diff options
author | Yinghai Lu <yinghai@kernel.org> | 2010-01-22 12:02:27 +0300 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-02-23 03:17:25 +0300 |
commit | 32180e402f9ff1f3389c99edf3f393425e706080 (patch) | |
tree | 8bdc06675bdaf8dc79916e96e4ca666343bb1b23 /drivers/pci/setup-bus.c | |
parent | 9789ac979b6b6ae6cc09f7b29c88e95ecb14ec39 (diff) | |
download | linux-32180e402f9ff1f3389c99edf3f393425e706080.tar.xz |
PCI: pciehp: second try to get big range for pcie devices
Handle the case where the slot bridge that doesn't get a pre-allocated
resource big enough to handle its child resources.. For example pcie
devices need 256M, but the bridge only gets 2M preallocated.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index b19a56b8b17a..ed545f669459 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -964,12 +964,61 @@ enable_and_dump: void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) { struct pci_bus *parent = bridge->subordinate; + int tried_times = 0; + struct resource_list_x head, *list; int retval; + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | + IORESOURCE_PREFETCH; + + head.next = NULL; +again: pci_bus_size_bridges(parent); - __pci_bridge_assign_resources(bridge, NULL); + __pci_bridge_assign_resources(bridge, &head); retval = pci_reenable_device(bridge); pci_set_master(bridge); pci_enable_bridges(parent); + + tried_times++; + + if (!head.next) + return; + + if (tried_times >= 2) { + /* still fail, don't need to try more */ + free_failed_list(&head); + return; + } + + printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n", + tried_times + 1); + + /* + * Try to release leaf bridge's resources that doesn't fit resource of + * child device under that bridge + */ + for (list = head.next; list;) { + struct pci_bus *bus = list->dev->bus; + unsigned long flags = list->flags; + + pci_bus_release_bridge_resources(bus, flags & type_mask, + whole_subtree); + list = list->next; + } + /* restore size and flags */ + for (list = head.next; list;) { + struct resource *res = list->res; + + res->start = list->start; + res->end = list->end; + res->flags = list->flags; + if (list->dev->subordinate) + res->flags = 0; + + list = list->next; + } + free_failed_list(&head); + + goto again; } EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); |