dm: pci: Add a way to iterate through all PCI devices
authorSimon Glass <sjg@chromium.org>
Mon, 10 Aug 2015 13:05:04 +0000 (07:05 -0600)
committerSimon Glass <sjg@chromium.org>
Fri, 14 Aug 2015 09:24:21 +0000 (03:24 -0600)
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>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
drivers/pci/pci-uclass.c
include/pci.h

index b79927e453b4e48accd60032e4ba07959dc6d2aa..ad65427801f9cc4dd94fdf9a55615b4a165d237d 100644 (file)
@@ -775,6 +775,66 @@ 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;
+
+       /*
+        * Scan through all the PCI controllers. On x86 there will only be one
+        * but that is not necessarily true on other hardware.
+        */
+       do {
+               device_find_first_child(bus, &dev);
+               if (dev) {
+                       *devp = dev;
+                       return 0;
+               }
+               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",
index d1e2765cace61a1bbd3e8df8f19c4a4ace1537e4..488ff44c532805d1a5f4a6cc24ca0b29046dbafa 100644 (file)
@@ -909,6 +909,31 @@ int pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp);
 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
  *