@@ -185,19 +185,20 @@ int pci_bus_add_device(struct pci_dev *dev)
*/
int pci_bus_add_child(struct pci_bus *bus)
{
- int retval;
-
- if (bus->bridge)
- bus->dev.parent = bus->bridge;
-
- retval = device_add(&bus->dev);
- if (retval)
- return retval;
-
- bus->is_added = 1;
-
- /* Create legacy_io and legacy_mem files for this bus */
- pci_create_legacy_files(bus);
+ int retval = -EBUSY;
+
+ if (pci_bus_get_state(bus) == PCI_BUS_STATE_INITIALIZED) {
+ if (bus->bridge)
+ bus->dev.parent = bus->bridge;
+ retval = device_add(&bus->dev);
+ if (retval == 0) {
+ /* Create legacy_io and legacy_mem files for this bus */
+ pci_create_legacy_files(bus);
+ pci_bus_change_state(bus, PCI_BUS_STATE_INITIALIZED,
+ PCI_BUS_STATE_WORKING, false);
+ bus->is_added = 1;
+ }
+ }
return retval;
}
@@ -232,13 +233,14 @@ void pci_bus_add_devices(const struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
BUG_ON(!dev->is_added);
- child = dev->subordinate;
+ child = pci_lock_subordinate(dev, PCI_BUS_STATE_STOPPING - 1);
+ if (!child)
+ continue;
+
/*
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/
- if (!child)
- continue;
if (list_empty(&child->node)) {
down_write(&pci_bus_sem);
list_add_tail(&child->node, &dev->bus->children);
@@ -250,28 +252,34 @@ void pci_bus_add_devices(const struct pci_bus *bus)
* register the bus with sysfs as the parent is now
* properly registered.
*/
- if (child->is_added)
- continue;
- retval = pci_bus_add_child(child);
- if (retval)
- dev_err(&dev->dev, "Error adding bus, continuing\n");
+ if (pci_bus_get_state(child) == PCI_BUS_STATE_INITIALIZED) {
+ retval = pci_bus_add_child(child);
+ if (retval)
+ dev_err(&dev->dev,
+ "Error adding bus, continuing\n");
+ }
+
+ pci_bus_unlock(child);
}
}
void pci_enable_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
+ struct pci_bus *child;
int retval;
list_for_each_entry(dev, &bus->devices, bus_list) {
- if (dev->subordinate) {
+ child = pci_lock_subordinate(dev, PCI_BUS_STATE_STOPPING - 1);
+ if (child) {
if (!pci_is_enabled(dev)) {
retval = pci_enable_device(dev);
if (retval)
dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", retval);
pci_set_master(dev);
}
- pci_enable_bridges(dev->subordinate);
+ pci_enable_bridges(child);
+ pci_bus_unlock(child);
}
}
}
This patch enhances PCI bus specific logic to support PCI bus lock mechanism. Signed-off-by: Jiang Liu <liuj97@gmail.com> --- drivers/pci/bus.c | 54 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 23 deletions(-)