]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/pci/bus.c
[PATCH] PCI: Add pci_walk_bus function to PCI core (nonrecursive)
[karo-tx-linux.git] / drivers / pci / bus.c
index a83ee0b8539473a0723842589b1b3a846e848538..eed67d9e73bcd6e3e9ac684342d460a1ac77c62b 100644 (file)
@@ -151,6 +151,54 @@ void pci_enable_bridges(struct pci_bus *bus)
        }
 }
 
+/** pci_walk_bus - walk devices on/under bus, calling callback.
+ *  @top      bus whose devices should be walked
+ *  @cb       callback to be called for each device found
+ *  @userdata arbitrary pointer to be passed to callback.
+ *
+ *  Walk the given bus, including any bridged devices
+ *  on buses under this bus.  Call the provided callback
+ *  on each device found.
+ */
+void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
+                 void *userdata)
+{
+       struct pci_dev *dev;
+       struct pci_bus *bus;
+       struct list_head *next;
+
+       bus = top;
+       spin_lock(&pci_bus_lock);
+       next = top->devices.next;
+       for (;;) {
+               if (next == &bus->devices) {
+                       /* end of this bus, go up or finish */
+                       if (bus == top)
+                               break;
+                       next = bus->self->bus_list.next;
+                       bus = bus->self->bus;
+                       continue;
+               }
+               dev = list_entry(next, struct pci_dev, bus_list);
+               pci_dev_get(dev);
+               if (dev->subordinate) {
+                       /* this is a pci-pci bridge, do its devices next */
+                       next = dev->subordinate->devices.next;
+                       bus = dev->subordinate;
+               } else
+                       next = dev->bus_list.next;
+               spin_unlock(&pci_bus_lock);
+
+               /* Run device routines with the bus unlocked */
+               cb(dev, userdata);
+
+               spin_lock(&pci_bus_lock);
+               pci_dev_put(dev);
+       }
+       spin_unlock(&pci_bus_lock);
+}
+EXPORT_SYMBOL_GPL(pci_walk_bus);
+
 EXPORT_SYMBOL(pci_bus_alloc_resource);
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
 EXPORT_SYMBOL(pci_bus_add_devices);