PCI: Delay enabling bridges until they're needed
authorYinghai Lu <yinghai@kernel.org>
Mon, 22 Jul 2013 21:37:17 +0000 (14:37 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 25 Jul 2013 18:35:03 +0000 (12:35 -0600)
We currently enable PCI bridges after scanning a bus and assigning
resources.  This is often done in arch code.

This patch changes this so we don't enable a bridge until necessary, i.e.,
until we enable a PCI device behind the bridge.  We do this in the generic
pci_enable_device() path, so this also removes the arch-specific code to
enable bridges.

[bhelgaas: changelog]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
13 files changed:
arch/arm/kernel/bios32.c
arch/m68k/platform/coldfire/pci.c
arch/mips/pci/pci.c
arch/sh/drivers/pci/pci.c
drivers/acpi/pci_root.c
drivers/parisc/lba_pci.c
drivers/pci/bus.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/pci.c
drivers/pci/probe.c
drivers/pci/setup-bus.c
drivers/pcmcia/cardbus.c
include/linux/pci.h

index 261fcc8261698391937343d0f24ae4b72a93c0e7..88e14d74b6de8ae4cd21010e29e7ba421e80bdd0 100644 (file)
@@ -525,11 +525,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
                         * Assign resources.
                         */
                        pci_bus_assign_resources(bus);
-
-                       /*
-                        * Enable bridges
-                        */
-                       pci_enable_bridges(bus);
                }
 
                /*
index b33f97a13e6d11650db6f5a183511356884ae51e..df9679238b6d20f480487040abe882cc41ae4cba 100644 (file)
@@ -319,7 +319,6 @@ static int __init mcf_pci_init(void)
        pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
        pci_bus_size_bridges(rootbus);
        pci_bus_assign_resources(rootbus);
-       pci_enable_bridges(rootbus);
        return 0;
 }
 
index 594e60d6a43b256d5f65f04e751f624610b41b3d..33e7aa52d9c4451ca352221921e27c134246a52d 100644 (file)
@@ -113,7 +113,6 @@ static void pcibios_scanbus(struct pci_controller *hose)
                if (!pci_has_flag(PCI_PROBE_ONLY)) {
                        pci_bus_size_bridges(bus);
                        pci_bus_assign_resources(bus);
-                       pci_enable_bridges(bus);
                }
        }
 }
index 102f5d58b0371ac512af95a4d8994b91ad53a227..60ed3e1c4b753dd92ba4c58cc59def3079ef2050 100644 (file)
@@ -69,7 +69,6 @@ static void pcibios_scanbus(struct pci_channel *hose)
 
                pci_bus_size_bridges(bus);
                pci_bus_assign_resources(bus);
-               pci_enable_bridges(bus);
        } else {
                pci_free_resource_list(&resources);
        }
index 5917839321b8bb01254f57e0cde630f637ff76b2..faa1d29c0261a5255b223ff3f7e6ace32fb4386d 100644 (file)
@@ -527,9 +527,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
        if (system_state != SYSTEM_BOOTING) {
                pcibios_resource_survey_bus(root->bus);
                pci_assign_unassigned_bus_resources(root->bus);
-
-               /* need to after hot-added ioapic is registered */
-               pci_enable_bridges(root->bus);
        }
 
        pci_bus_add_devices(root->bus);
index 19f6f70c67d398f8d585618901de98797ebbfcef..37e71ff6408dca41ff5790417f549eead9ddea97 100644 (file)
@@ -1590,7 +1590,6 @@ lba_driver_probe(struct parisc_device *dev)
                lba_dump_res(&lba_dev->hba.lmmio_space, 2);
 #endif
        }
-       pci_enable_bridges(lba_bus);
 
        /*
        ** Once PCI register ops has walked the bus, access to config
index b1ff02ab4f131fbda7edd9971342b9ae91bf4149..fc1b740137430b703a348b03d1c9420d19d21d7a 100644 (file)
@@ -216,24 +216,6 @@ void pci_bus_add_devices(const struct pci_bus *bus)
        }
 }
 
-void pci_enable_bridges(struct pci_bus *bus)
-{
-       struct pci_dev *dev;
-       int retval;
-
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               if (dev->subordinate) {
-                       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_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
@@ -301,4 +283,3 @@ EXPORT_SYMBOL(pci_bus_put);
 EXPORT_SYMBOL(pci_bus_alloc_resource);
 EXPORT_SYMBOL_GPL(pci_bus_add_device);
 EXPORT_SYMBOL(pci_bus_add_devices);
-EXPORT_SYMBOL(pci_enable_bridges);
index 59df8575a48ce834fb48ea002689ed97ed9ca51a..52dee9d31e1cad6070b8e78b0eb507dc39a4f16f 100644 (file)
@@ -723,7 +723,6 @@ static int __ref enable_device(struct acpiphp_slot *slot)
        acpiphp_sanitize_bus(bus);
        acpiphp_set_hpp_values(bus);
        acpiphp_set_acpi_region(slot);
-       pci_enable_bridges(bus);
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                /* Assume that newly added devices are powered on already. */
index e37fea6e178d2dab00d3334848d231117d525013..44a1a8a0ad7b8a2289f4bd9f6ad168c74cc2bfd4 100644 (file)
@@ -1145,6 +1145,24 @@ int pci_reenable_device(struct pci_dev *dev)
        return 0;
 }
 
+static void pci_enable_bridge(struct pci_dev *dev)
+{
+       int retval;
+
+       if (!dev)
+               return;
+
+       pci_enable_bridge(dev->bus->self);
+
+       if (pci_is_enabled(dev))
+               return;
+       retval = pci_enable_device(dev);
+       if (retval)
+               dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n",
+                       retval);
+       pci_set_master(dev);
+}
+
 static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
 {
        int err;
@@ -1165,6 +1183,8 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
        if (atomic_inc_return(&dev->enable_cnt) > 1)
                return 0;               /* already enabled */
 
+       pci_enable_bridge(dev->bus->self);
+
        /* only skip sriov related */
        for (i = 0; i <= PCI_ROM_RESOURCE; i++)
                if (dev->resource[i].flags & flags)
index 46ada5c098ebed710f24a7deb426720149b219fd..85c114cd91cc512a5d399c45de2f14d6769fbdb9 100644 (file)
@@ -1979,7 +1979,6 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
 
        max = pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
-       pci_enable_bridges(bus);
        pci_bus_add_devices(bus);
 
        return max;
index 4d9ebb4ce015cdf4c4cdf8a582bb200c94743553..8f86be13678fd866cf700a4c74561a11ba6e8578 100644 (file)
@@ -1440,7 +1440,7 @@ again:
 
        /* any device complain? */
        if (list_empty(&fail_head))
-               goto enable_and_dump;
+               goto dump;
 
        if (tried_times >= pci_try_num) {
                if (enable_local == undefined)
@@ -1449,7 +1449,7 @@ again:
                        dev_info(&bus->dev, "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
 
                free_list(&fail_head);
-               goto enable_and_dump;
+               goto dump;
        }
 
        dev_printk(KERN_DEBUG, &bus->dev,
@@ -1482,10 +1482,7 @@ again:
 
        goto again;
 
-enable_and_dump:
-       /* Depth last, update the hardware. */
-       pci_enable_bridges(bus);
-
+dump:
        /* dump the resource on buses */
        pci_bus_dump_resources(bus);
 }
@@ -1556,7 +1553,6 @@ enable_all:
        if (retval)
                dev_err(&bridge->dev, "Error reenabling bridge (%d)\n", retval);
        pci_set_master(bridge);
-       pci_enable_bridges(parent);
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
 
index 9d3ac998fc1fac6bbfc35efb0ffac398613f6882..b2a98cdbd0d289dee032dfd71cd540ead129b8cc 100644 (file)
@@ -91,7 +91,6 @@ int __ref cb_alloc(struct pcmcia_socket *s)
        if (s->tune_bridge)
                s->tune_bridge(s, bus);
 
-       pci_enable_bridges(bus);
        pci_bus_add_devices(bus);
 
        return 0;
index 0fd1f1582fa1cdf359b33f3cddeaa60026f492ac..8cd1e6f30acd1a85ea5511162e2a060c9cf58a05 100644 (file)
@@ -1043,7 +1043,6 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
                                                  resource_size_t,
                                                  resource_size_t),
                        void *alignf_data);
-void pci_enable_bridges(struct pci_bus *bus);
 
 /* Proper probing supporting hot-pluggable devices */
 int __must_check __pci_register_driver(struct pci_driver *, struct module *,