Commit ee061da7 authored by Keith Busch's avatar Keith Busch Committed by Bjorn Helgaas
Browse files

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: default avatarKeith Busch <kbusch@kernel.org>
[bhelgaas: commit log]
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
parent 4d6dcd6c
Loading
Loading
Loading
Loading
+11 −25
Original line number Diff line number Diff line
@@ -389,38 +389,24 @@ 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 *),
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;
			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)
			ret = __pci_walk_bus(dev->subordinate, cb, userdata);
			if (ret)
				break;
		}
	}
	return ret;
}

/**
 *  pci_walk_bus - walk devices on/under bus, calling callback.