Skip to content

Commit

Permalink
[PATCH] PCI: Add pci_walk_bus function to PCI core (nonrecursive)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paul Mackerras authored and Greg Kroah-Hartman committed Sep 8, 2005
1 parent 1d2450a commit cecf486
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
48 changes: 48 additions & 0 deletions drivers/pci/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,9 @@ const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);

void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
void *userdata);

/* kmem_cache style wrapper around pci_alloc_consistent() */

#include <linux/dmapool.h>
Expand Down

0 comments on commit cecf486

Please sign in to comment.