diff options
| author | Paul Mackerras <paulus@samba.org> | 2005-08-18 00:33:01 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-09-08 18:04:30 -0400 |
| commit | cecf4864cf52a4a243a62b2856a6a155edbb55e8 (patch) | |
| tree | ffbf170ed0208e81e9561dca3ad7786c362a7024 | |
| parent | 1d2450a4a6eb656798c6282b5ffc8e5f9f52ac14 (diff) | |
[PATCH] PCI: Add pci_walk_bus function to PCI core (nonrecursive)
The PCI error recovery infrastructure needs to be able to contact all
the drivers affected by a PCI error event, which may mean traversing
all the devices under a given PCI-PCI bridge. This patch adds a
function to the PCI core that traverses all the PCI devices on a PCI
bus and under any PCI-PCI bridges on that bus (and so on), calling a
given function for each device. This provides a way for the error
recovery code to iterate through all devices that are affected by an
error event.
This version is not implemented as a recursive function. Instead,
when we reach a PCI-PCI bridge, we set the pointers to start doing the
devices on the bus under the bridge, and when we reach the end of a
bus's devices, we use the bus->self pointer to go back up to the next
higher bus and continue doing its devices.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -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> |
