diff options
author | Yinghai Lu <yinghai@kernel.org> | 2013-07-22 17:37:17 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-07-25 14:35:03 -0400 |
commit | 928bea964827d7824b548c1f8e06eccbbc4d0d7d (patch) | |
tree | 13110a5f05a65aa487cee8be5bd58017986f4929 /drivers/pci | |
parent | 55ed83a615730c2578da155bc99b68f4417ffe20 (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.c | 19 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 1 | ||||
-rw-r--r-- | drivers/pci/pci.c | 20 | ||||
-rw-r--r-- | drivers/pci/probe.c | 1 | ||||
-rw-r--r-- | drivers/pci/setup-bus.c | 10 |
5 files changed, 23 insertions, 28 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index b1ff02ab4f13..fc1b74013743 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) | |||
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | void pci_enable_bridges(struct pci_bus *bus) | ||
220 | { | ||
221 | struct pci_dev *dev; | ||
222 | int retval; | ||
223 | |||
224 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
225 | if (dev->subordinate) { | ||
226 | if (!pci_is_enabled(dev)) { | ||
227 | retval = pci_enable_device(dev); | ||
228 | if (retval) | ||
229 | dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", retval); | ||
230 | pci_set_master(dev); | ||
231 | } | ||
232 | pci_enable_bridges(dev->subordinate); | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | /** pci_walk_bus - walk devices on/under bus, calling callback. | 219 | /** pci_walk_bus - walk devices on/under bus, calling callback. |
238 | * @top bus whose devices should be walked | 220 | * @top bus whose devices should be walked |
239 | * @cb callback to be called for each device found | 221 | * @cb callback to be called for each device found |
@@ -301,4 +283,3 @@ EXPORT_SYMBOL(pci_bus_put); | |||
301 | EXPORT_SYMBOL(pci_bus_alloc_resource); | 283 | EXPORT_SYMBOL(pci_bus_alloc_resource); |
302 | EXPORT_SYMBOL_GPL(pci_bus_add_device); | 284 | EXPORT_SYMBOL_GPL(pci_bus_add_device); |
303 | EXPORT_SYMBOL(pci_bus_add_devices); | 285 | EXPORT_SYMBOL(pci_bus_add_devices); |
304 | EXPORT_SYMBOL(pci_enable_bridges); | ||
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 59df8575a48c..52dee9d31e1c 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) | |||
723 | acpiphp_sanitize_bus(bus); | 723 | acpiphp_sanitize_bus(bus); |
724 | acpiphp_set_hpp_values(bus); | 724 | acpiphp_set_hpp_values(bus); |
725 | acpiphp_set_acpi_region(slot); | 725 | acpiphp_set_acpi_region(slot); |
726 | pci_enable_bridges(bus); | ||
727 | 726 | ||
728 | list_for_each_entry(dev, &bus->devices, bus_list) { | 727 | list_for_each_entry(dev, &bus->devices, bus_list) { |
729 | /* Assume that newly added devices are powered on already. */ | 728 | /* Assume that newly added devices are powered on already. */ |
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e37fea6e178d..44a1a8a0ad7b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1145,6 +1145,24 @@ int pci_reenable_device(struct pci_dev *dev) | |||
1145 | return 0; | 1145 | return 0; |
1146 | } | 1146 | } |
1147 | 1147 | ||
1148 | static void pci_enable_bridge(struct pci_dev *dev) | ||
1149 | { | ||
1150 | int retval; | ||
1151 | |||
1152 | if (!dev) | ||
1153 | return; | ||
1154 | |||
1155 | pci_enable_bridge(dev->bus->self); | ||
1156 | |||
1157 | if (pci_is_enabled(dev)) | ||
1158 | return; | ||
1159 | retval = pci_enable_device(dev); | ||
1160 | if (retval) | ||
1161 | dev_err(&dev->dev, "Error enabling bridge (%d), continuing\n", | ||
1162 | retval); | ||
1163 | pci_set_master(dev); | ||
1164 | } | ||
1165 | |||
1148 | static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) | 1166 | static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) |
1149 | { | 1167 | { |
1150 | int err; | 1168 | int err; |
@@ -1165,6 +1183,8 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) | |||
1165 | if (atomic_inc_return(&dev->enable_cnt) > 1) | 1183 | if (atomic_inc_return(&dev->enable_cnt) > 1) |
1166 | return 0; /* already enabled */ | 1184 | return 0; /* already enabled */ |
1167 | 1185 | ||
1186 | pci_enable_bridge(dev->bus->self); | ||
1187 | |||
1168 | /* only skip sriov related */ | 1188 | /* only skip sriov related */ |
1169 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) | 1189 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) |
1170 | if (dev->resource[i].flags & flags) | 1190 | if (dev->resource[i].flags & flags) |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 46ada5c098eb..85c114cd91cc 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) | |||
1979 | 1979 | ||
1980 | max = pci_scan_child_bus(bus); | 1980 | max = pci_scan_child_bus(bus); |
1981 | pci_assign_unassigned_bus_resources(bus); | 1981 | pci_assign_unassigned_bus_resources(bus); |
1982 | pci_enable_bridges(bus); | ||
1983 | pci_bus_add_devices(bus); | 1982 | pci_bus_add_devices(bus); |
1984 | 1983 | ||
1985 | return max; | 1984 | return max; |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 4d9ebb4ce015..8f86be13678f 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -1440,7 +1440,7 @@ again: | |||
1440 | 1440 | ||
1441 | /* any device complain? */ | 1441 | /* any device complain? */ |
1442 | if (list_empty(&fail_head)) | 1442 | if (list_empty(&fail_head)) |
1443 | goto enable_and_dump; | 1443 | goto dump; |
1444 | 1444 | ||
1445 | if (tried_times >= pci_try_num) { | 1445 | if (tried_times >= pci_try_num) { |
1446 | if (enable_local == undefined) | 1446 | if (enable_local == undefined) |
@@ -1449,7 +1449,7 @@ again: | |||
1449 | dev_info(&bus->dev, "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n"); | 1449 | dev_info(&bus->dev, "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n"); |
1450 | 1450 | ||
1451 | free_list(&fail_head); | 1451 | free_list(&fail_head); |
1452 | goto enable_and_dump; | 1452 | goto dump; |
1453 | } | 1453 | } |
1454 | 1454 | ||
1455 | dev_printk(KERN_DEBUG, &bus->dev, | 1455 | dev_printk(KERN_DEBUG, &bus->dev, |
@@ -1482,10 +1482,7 @@ again: | |||
1482 | 1482 | ||
1483 | goto again; | 1483 | goto again; |
1484 | 1484 | ||
1485 | enable_and_dump: | 1485 | dump: |
1486 | /* Depth last, update the hardware. */ | ||
1487 | pci_enable_bridges(bus); | ||
1488 | |||
1489 | /* dump the resource on buses */ | 1486 | /* dump the resource on buses */ |
1490 | pci_bus_dump_resources(bus); | 1487 | pci_bus_dump_resources(bus); |
1491 | } | 1488 | } |
@@ -1556,7 +1553,6 @@ enable_all: | |||
1556 | if (retval) | 1553 | if (retval) |
1557 | dev_err(&bridge->dev, "Error reenabling bridge (%d)\n", retval); | 1554 | dev_err(&bridge->dev, "Error reenabling bridge (%d)\n", retval); |
1558 | pci_set_master(bridge); | 1555 | pci_set_master(bridge); |
1559 | pci_enable_bridges(parent); | ||
1560 | } | 1556 | } |
1561 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); | 1557 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); |
1562 | 1558 | ||