diff options
author | Keith Busch <kbusch@kernel.org> | 2024-10-22 15:48:50 -0700 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2024-11-11 13:06:02 -0600 |
commit | ee061da777f704976c6d3fdc1707788d11a052c5 (patch) | |
tree | 7cb56a23fe60b2c73dbd475540b61a66303c4102 /drivers/pci | |
parent | 4d6dcd6c2fa3a80898651d323c150e5ebc03881d (diff) | |
download | linux-ee061da777f704976c6d3fdc1707788d11a052c5.tar.gz linux-ee061da777f704976c6d3fdc1707788d11a052c5.tar.bz2 linux-ee061da777f704976c6d3fdc1707788d11a052c5.zip |
PCI: Convert __pci_walk_bus() to be recursive
The original implementation of __pci_walk_bus() chose a non-recursive walk,
presumably as a precaution on stack use. We do recursive bus walking in
other places though. For example:
pci_bus_resettable()
pci_stop_bus_device()
pci_remove_bus_device()
pci_bus_allocate_dev_resources()
So recursive pci bus walking is well tested and safe, and is easier to
follow.
Convert __pci_walk_bus() to be recursive to make it easier to introduce
finer grain locking in the future.
Link: https://lore.kernel.org/r/20241022224851.340648-5-kbusch@meta.com
Signed-off-by: Keith Busch <kbusch@kernel.org>
[bhelgaas: commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/bus.c | 36 |
1 files changed, 11 insertions, 25 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 7c07a141e877..8491e9c7f058 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -389,37 +389,23 @@ void pci_bus_add_devices(const struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_add_devices); -static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), - void *userdata) +static int __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), + void *userdata) { struct pci_dev *dev; - struct pci_bus *bus; - struct list_head *next; - int retval; + int ret = 0; - bus = top; - next = top->devices.next; - for (;;) { - if (next == &bus->devices) { - /* end of this bus, go up or finish */ - if (bus == top) + list_for_each_entry(dev, &top->devices, bus_list) { + ret = cb(dev, userdata); + if (ret) + break; + if (dev->subordinate) { + ret = __pci_walk_bus(dev->subordinate, cb, userdata); + if (ret) break; - next = bus->self->bus_list.next; - bus = bus->self->bus; - continue; } - dev = list_entry(next, struct pci_dev, bus_list); - 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; - - retval = cb(dev, userdata); - if (retval) - break; } + return ret; } /** |