PCI: Convert __pci_walk_bus() to be recursive
authorKeith Busch <kbusch@kernel.org>
Tue, 22 Oct 2024 22:48:50 +0000 (15:48 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Mon, 11 Nov 2024 19:06:02 +0000 (13:06 -0600)
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>
drivers/pci/bus.c

index 7c07a141e87728ecd9dd76afc13aeed37fe31afd..8491e9c7f05869d7bccc5fce9e5705c2da72e449 100644 (file)
@@ -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;
 }
 
 /**