diff options
author | Yinghai Lu <yinghai@kernel.org> | 2010-01-22 04:02:27 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-02-22 19:17:25 -0500 |
commit | 32180e402f9ff1f3389c99edf3f393425e706080 (patch) | |
tree | 8bdc06675bdaf8dc79916e96e4ca666343bb1b23 /drivers/pci/setup-bus.c | |
parent | 9789ac979b6b6ae6cc09f7b29c88e95ecb14ec39 (diff) |
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: | |||
964 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) | 964 | void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) |
965 | { | 965 | { |
966 | struct pci_bus *parent = bridge->subordinate; | 966 | struct pci_bus *parent = bridge->subordinate; |
967 | int tried_times = 0; | ||
968 | struct resource_list_x head, *list; | ||
967 | int retval; | 969 | int retval; |
970 | unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | | ||
971 | IORESOURCE_PREFETCH; | ||
972 | |||
973 | head.next = NULL; | ||
968 | 974 | ||
975 | again: | ||
969 | pci_bus_size_bridges(parent); | 976 | pci_bus_size_bridges(parent); |
970 | __pci_bridge_assign_resources(bridge, NULL); | 977 | __pci_bridge_assign_resources(bridge, &head); |
971 | retval = pci_reenable_device(bridge); | 978 | retval = pci_reenable_device(bridge); |
972 | pci_set_master(bridge); | 979 | pci_set_master(bridge); |
973 | pci_enable_bridges(parent); | 980 | pci_enable_bridges(parent); |
981 | |||
982 | tried_times++; | ||
983 | |||
984 | if (!head.next) | ||
985 | return; | ||
986 | |||
987 | if (tried_times >= 2) { | ||
988 | /* still fail, don't need to try more */ | ||
989 | free_failed_list(&head); | ||
990 | return; | ||
991 | } | ||
992 | |||
993 | printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n", | ||
994 | tried_times + 1); | ||
995 | |||
996 | /* | ||
997 | * Try to release leaf bridge's resources that doesn't fit resource of | ||
998 | * child device under that bridge | ||
999 | */ | ||
1000 | for (list = head.next; list;) { | ||
1001 | struct pci_bus *bus = list->dev->bus; | ||
1002 | unsigned long flags = list->flags; | ||
1003 | |||
1004 | pci_bus_release_bridge_resources(bus, flags & type_mask, | ||
1005 | whole_subtree); | ||
1006 | list = list->next; | ||
1007 | } | ||
1008 | /* restore size and flags */ | ||
1009 | for (list = head.next; list;) { | ||
1010 | struct resource *res = list->res; | ||
1011 | |||
1012 | res->start = list->start; | ||
1013 | res->end = list->end; | ||
1014 | res->flags = list->flags; | ||
1015 | if (list->dev->subordinate) | ||
1016 | res->flags = 0; | ||
1017 | |||
1018 | list = list->next; | ||
1019 | } | ||
1020 | free_failed_list(&head); | ||
1021 | |||
1022 | goto again; | ||
974 | } | 1023 | } |
975 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); | 1024 | EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); |