diff options
-rw-r--r-- | drivers/pci/bus.c | 48 | ||||
-rw-r--r-- | include/linux/pci.h | 3 |
2 files changed, 51 insertions, 0 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index a83ee0b85394..eed67d9e73bc 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
@@ -151,6 +151,54 @@ void pci_enable_bridges(struct pci_bus *bus) | |||
151 | } | 151 | } |
152 | } | 152 | } |
153 | 153 | ||
154 | /** pci_walk_bus - walk devices on/under bus, calling callback. | ||
155 | * @top bus whose devices should be walked | ||
156 | * @cb callback to be called for each device found | ||
157 | * @userdata arbitrary pointer to be passed to callback. | ||
158 | * | ||
159 | * Walk the given bus, including any bridged devices | ||
160 | * on buses under this bus. Call the provided callback | ||
161 | * on each device found. | ||
162 | */ | ||
163 | void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | ||
164 | void *userdata) | ||
165 | { | ||
166 | struct pci_dev *dev; | ||
167 | struct pci_bus *bus; | ||
168 | struct list_head *next; | ||
169 | |||
170 | bus = top; | ||
171 | spin_lock(&pci_bus_lock); | ||
172 | next = top->devices.next; | ||
173 | for (;;) { | ||
174 | if (next == &bus->devices) { | ||
175 | /* end of this bus, go up or finish */ | ||
176 | if (bus == top) | ||
177 | break; | ||
178 | next = bus->self->bus_list.next; | ||
179 | bus = bus->self->bus; | ||
180 | continue; | ||
181 | } | ||
182 | dev = list_entry(next, struct pci_dev, bus_list); | ||
183 | pci_dev_get(dev); | ||
184 | if (dev->subordinate) { | ||
185 | /* this is a pci-pci bridge, do its devices next */ | ||
186 | next = dev->subordinate->devices.next; | ||
187 | bus = dev->subordinate; | ||
188 | } else | ||
189 | next = dev->bus_list.next; | ||
190 | spin_unlock(&pci_bus_lock); | ||
191 | |||
192 | /* Run device routines with the bus unlocked */ | ||
193 | cb(dev, userdata); | ||
194 | |||
195 | spin_lock(&pci_bus_lock); | ||
196 | pci_dev_put(dev); | ||
197 | } | ||
198 | spin_unlock(&pci_bus_lock); | ||
199 | } | ||
200 | EXPORT_SYMBOL_GPL(pci_walk_bus); | ||
201 | |||
154 | EXPORT_SYMBOL(pci_bus_alloc_resource); | 202 | EXPORT_SYMBOL(pci_bus_alloc_resource); |
155 | EXPORT_SYMBOL_GPL(pci_bus_add_device); | 203 | EXPORT_SYMBOL_GPL(pci_bus_add_device); |
156 | EXPORT_SYMBOL(pci_bus_add_devices); | 204 | EXPORT_SYMBOL(pci_bus_add_devices); |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 8878ccff9e3c..b0e244713281 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -434,6 +434,9 @@ const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_ | |||
434 | const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev); | 434 | const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev); |
435 | int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); | 435 | int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); |
436 | 436 | ||
437 | void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | ||
438 | void *userdata); | ||
439 | |||
437 | /* kmem_cache style wrapper around pci_alloc_consistent() */ | 440 | /* kmem_cache style wrapper around pci_alloc_consistent() */ |
438 | 441 | ||
439 | #include <linux/dmapool.h> | 442 | #include <linux/dmapool.h> |