diff mbox

[U-Boot,05/15] dm: pci: Add a way to iterate through all PCI devices

Message ID 1438033652-30435-6-git-send-email-sjg@chromium.org
State Superseded
Delegated to: Simon Glass
Headers show

Commit Message

Simon Glass July 27, 2015, 9:47 p.m. UTC
These functions allow iteration through all PCI devices including bridges.
The children of each PCI bus are returned in turn. This can be useful for
configuring, checking or enumerating all the devices.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/pci/pci-uclass.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/pci.h            | 25 +++++++++++++++++++++
 2 files changed, 83 insertions(+)

Comments

Bin Meng July 28, 2015, 7:48 a.m. UTC | #1
Hi Simon,

On Tue, Jul 28, 2015 at 5:47 AM, Simon Glass <sjg@chromium.org> wrote:
> These functions allow iteration through all PCI devices including bridges.
> The children of each PCI bus are returned in turn. This can be useful for
> configuring, checking or enumerating all the devices.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
>  drivers/pci/pci-uclass.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/pci.h            | 25 +++++++++++++++++++++
>  2 files changed, 83 insertions(+)
>
> diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
> index 8d3536c..da724ca 100644
> --- a/drivers/pci/pci-uclass.c
> +++ b/drivers/pci/pci-uclass.c
> @@ -779,6 +779,64 @@ static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf,
>         return pci_bus_write_config(hose->ctlr, bdf, offset, value, size);
>  }
>
> +static int skip_to_next_device(struct udevice *bus, struct udevice **devp)
> +{
> +       struct udevice *dev;
> +       int ret = 0;
> +
> +       do {
> +               do {
> +                       device_find_first_child(bus, &dev);
> +                       if (dev) {
> +                               *devp = dev;
> +                               return 0;
> +                       }
> +               } while (dev);

There is no need to do a 'do..while' here.

> +               ret = uclass_next_device(&bus);

I don't understand. If there is no child device of the root pci bus,
why do we bother doing this uclass_next_device()? No child device of
the root pci bus means there will not be another bus device which is
attached to the root pci bus.

> +               if (ret)
> +                       return ret;
> +       } while (bus);
> +
> +       return 0;
> +}
> +
> +int pci_find_next_device(struct udevice **devp)
> +{
> +       struct udevice *child = *devp;
> +       struct udevice *bus = child->parent;
> +       int ret;
> +
> +       /* First try all the siblings */
> +       *devp = NULL;
> +       while (child) {
> +               device_find_next_child(&child);
> +               if (child) {
> +                       *devp = child;
> +                       return 0;
> +               }
> +       }
> +
> +       /* We ran out of siblings. Try the next bus */
> +       ret = uclass_next_device(&bus);
> +       if (ret)
> +               return ret;
> +
> +       return bus ? skip_to_next_device(bus, devp) : 0;
> +}
> +
> +int pci_find_first_device(struct udevice **devp)
> +{
> +       struct udevice *bus;
> +       int ret;
> +
> +       *devp = NULL;
> +       ret = uclass_first_device(UCLASS_PCI, &bus);
> +       if (ret)
> +               return ret;
> +
> +       return skip_to_next_device(bus, devp);
> +}
> +
>  UCLASS_DRIVER(pci) = {
>         .id             = UCLASS_PCI,
>         .name           = "pci",
> diff --git a/include/pci.h b/include/pci.h
> index 0bb3090..c842f78 100644
> --- a/include/pci.h
> +++ b/include/pci.h
> @@ -869,6 +869,31 @@ int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn,
>                        struct udevice **devp);
>
>  /**
> + * pci_find_first_device() - return the first available PCI device
> + *
> + * This function and pci_find_first_device() allow iteration through all
> + * available PCI devices on all buses. Assuming there are any, this will
> + * return the first one.
> + *
> + * @devp:      Set to the first available device, or NULL if no more are left
> + *             or we got an error
> + * @return 0 if all is OK, -ve on error (e.g. a bus/bridge failed to probe)
> + */
> +int pci_find_first_device(struct udevice **devp);
> +
> +/**
> + * pci_find_next_device() - return the next available PCI device
> + *
> + * Finds the next available PCI device after the one supplied, or sets @devp
> + * to NULL if there are no more.
> + *
> + * @devp:      On entry, the last device returned. Set to the next available
> + *             device, or NULL if no more are left or we got an error
> + * @return 0 if all is OK, -ve on error (e.g. a bus/bridge failed to probe)
> + */
> +int pci_find_next_device(struct udevice **devp);
> +
> +/**
>   * pci_get_ff() - Returns a mask for the given access size
>   *
>   * @size:      Access size
> --

Regards,
Bin
Simon Glass Aug. 7, 2015, 2:28 a.m. UTC | #2
Hi Bin,

On 28 July 2015 at 01:48, Bin Meng <bmeng.cn@gmail.com> wrote:
> Hi Simon,
>
> On Tue, Jul 28, 2015 at 5:47 AM, Simon Glass <sjg@chromium.org> wrote:
>> These functions allow iteration through all PCI devices including bridges.
>> The children of each PCI bus are returned in turn. This can be useful for
>> configuring, checking or enumerating all the devices.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> ---
>>
>>  drivers/pci/pci-uclass.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/pci.h            | 25 +++++++++++++++++++++
>>  2 files changed, 83 insertions(+)
>>
>> diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
>> index 8d3536c..da724ca 100644
>> --- a/drivers/pci/pci-uclass.c
>> +++ b/drivers/pci/pci-uclass.c
>> @@ -779,6 +779,64 @@ static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf,
>>         return pci_bus_write_config(hose->ctlr, bdf, offset, value, size);
>>  }
>>
>> +static int skip_to_next_device(struct udevice *bus, struct udevice **devp)
>> +{
>> +       struct udevice *dev;
>> +       int ret = 0;
>> +
>> +       do {
>> +               do {
>> +                       device_find_first_child(bus, &dev);
>> +                       if (dev) {
>> +                               *devp = dev;
>> +                               return 0;
>> +                       }
>> +               } while (dev);
>
> There is no need to do a 'do..while' here.
>
>> +               ret = uclass_next_device(&bus);
>
> I don't understand. If there is no child device of the root pci bus,
> why do we bother doing this uclass_next_device()? No child device of
> the root pci bus means there will not be another bus device which is
> attached to the root pci bus.

That's true on x86, but other hardware may have multiple PCI
controllers. I will add a comment.

[snip]

Regards,
Simon
diff mbox

Patch

diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 8d3536c..da724ca 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -779,6 +779,64 @@  static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf,
 	return pci_bus_write_config(hose->ctlr, bdf, offset, value, size);
 }
 
+static int skip_to_next_device(struct udevice *bus, struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret = 0;
+
+	do {
+		do {
+			device_find_first_child(bus, &dev);
+			if (dev) {
+				*devp = dev;
+				return 0;
+			}
+		} while (dev);
+		ret = uclass_next_device(&bus);
+		if (ret)
+			return ret;
+	} while (bus);
+
+	return 0;
+}
+
+int pci_find_next_device(struct udevice **devp)
+{
+	struct udevice *child = *devp;
+	struct udevice *bus = child->parent;
+	int ret;
+
+	/* First try all the siblings */
+	*devp = NULL;
+	while (child) {
+		device_find_next_child(&child);
+		if (child) {
+			*devp = child;
+			return 0;
+		}
+	}
+
+	/* We ran out of siblings. Try the next bus */
+	ret = uclass_next_device(&bus);
+	if (ret)
+		return ret;
+
+	return bus ? skip_to_next_device(bus, devp) : 0;
+}
+
+int pci_find_first_device(struct udevice **devp)
+{
+	struct udevice *bus;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_first_device(UCLASS_PCI, &bus);
+	if (ret)
+		return ret;
+
+	return skip_to_next_device(bus, devp);
+}
+
 UCLASS_DRIVER(pci) = {
 	.id		= UCLASS_PCI,
 	.name		= "pci",
diff --git a/include/pci.h b/include/pci.h
index 0bb3090..c842f78 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -869,6 +869,31 @@  int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn,
 		       struct udevice **devp);
 
 /**
+ * pci_find_first_device() - return the first available PCI device
+ *
+ * This function and pci_find_first_device() allow iteration through all
+ * available PCI devices on all buses. Assuming there are any, this will
+ * return the first one.
+ *
+ * @devp:	Set to the first available device, or NULL if no more are left
+ *		or we got an error
+ * @return 0 if all is OK, -ve on error (e.g. a bus/bridge failed to probe)
+ */
+int pci_find_first_device(struct udevice **devp);
+
+/**
+ * pci_find_next_device() - return the next available PCI device
+ *
+ * Finds the next available PCI device after the one supplied, or sets @devp
+ * to NULL if there are no more.
+ *
+ * @devp:	On entry, the last device returned. Set to the next available
+ *		device, or NULL if no more are left or we got an error
+ * @return 0 if all is OK, -ve on error (e.g. a bus/bridge failed to probe)
+ */
+int pci_find_next_device(struct udevice **devp);
+
+/**
  * pci_get_ff() - Returns a mask for the given access size
  *
  * @size:	Access size