aboutsummaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2013-07-22 14:37:17 -0700
committerBjorn Helgaas <bhelgaas@google.com>2013-07-25 12:35:03 -0600
commit928bea964827d7824b548c1f8e06eccbbc4d0d7d (patch)
tree13110a5f05a65aa487cee8be5bd58017986f4929 /drivers/pci
parent55ed83a615730c2578da155bc99b68f4417ffe20 (diff)
PCI: Delay enabling bridges until they're needed
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>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/bus.c19
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c1
-rw-r--r--drivers/pci/pci.c20
-rw-r--r--drivers/pci/probe.c1
-rw-r--r--drivers/pci/setup-bus.c10
5 files changed, 23 insertions, 28 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index b1ff02ab4f1..fc1b7401374 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -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);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 59df8575a48..52dee9d31e1 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -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. */
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e37fea6e178..44a1a8a0ad7 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -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)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 46ada5c098e..85c114cd91c 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -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;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 4d9ebb4ce01..8f86be13678 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -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);