diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-01-21 02:08:24 -0800 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-02-14 08:44:54 -0800 |
commit | 19aa7ee432cec00b647443719eb5c055b69a5e8e (patch) | |
tree | 7d0175d80dba6171786886ddf388cb97e3d11dad /drivers/pci | |
parent | 9b03088f955552299f50a1f660372698b07ab339 (diff) |
PCI: make re-allocation try harder by reassigning ranges higher in the heirarchy
On a system with devices that support SRIOV connected to a pcie switch
to pcie root port:
+-[0000:80]-+-00.0-[81-8f]--
| +-01.0-[90-9f]--
| +-02.0-[a0-af]----00.0-[a1-a3]--+-02.0-[a2]--+-00.0 Oracle Corporation Device 207a
| | \-03.0-[a3]--+-00.0 Oracle Corporation Device 207a
| +-02.2-[b0-bf]----00.0-[b1-b3]--+-02.0-[b2]--+-00.0 Oracle Corporation Device 207a
| | \-03.0-[b3]--+-00.0 Oracle Corporation Device 207a
When the BIOS does not assign resources for SRIOV BARs, kernel pci
reallocation only goes up one bridge and then gives up, failing to to
get resources for all sSRIOV BARs, even though the range is large enough
in the peer root bus.
Specifically, only the bridge at the a1:02.0 level has its resources
cleared and reallocated. The kernel does not go up to clear the bridge
at the 80:02.0 level.
To make it go to upper levels, during retry, we need to treat "good to have"
resources as "must have".
Only on the last try will we treat good to have resources as optional.
At that time, parent bridge resources will already have been released so
we'll have a chance to get everything assigned with must_have plus
good_to_have for all child devices.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/setup-bus.c | 46 |
1 files changed, 28 insertions, 18 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index c09c67ab561..c79ce4ee634 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -943,7 +943,8 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, * Follow thru */ default: - pbus_size_io(bus, 0, additional_io_size, realloc_head); + pbus_size_io(bus, realloc_head ? 0 : additional_io_size, + additional_io_size, realloc_head); /* If the bridge supports prefetchable range, size it separately. If it doesn't, or its prefetchable window has already been allocated by arch code, try @@ -951,11 +952,15 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus, resources. */ mask = IORESOURCE_MEM; prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; - if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head)) + if (pbus_size_mem(bus, prefmask, prefmask, + realloc_head ? 0 : additional_mem_size, + additional_mem_size, realloc_head)) mask = prefmask; /* Success, size non-prefetch only. */ else additional_mem_size += additional_mem_size; - pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head); + pbus_size_mem(bus, mask, IORESOURCE_MEM, + realloc_head ? 0 : additional_mem_size, + additional_mem_size, realloc_head); break; } } @@ -1194,45 +1199,50 @@ pci_assign_unassigned_resources(void) struct pci_bus *bus; struct resource_list_x realloc_list; /* list of resources that want additional resources */ + struct resource_list_x *add_list = NULL; int tried_times = 0; enum release_type rel_type = leaf_only; struct resource_list_x head, *list; unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; unsigned long failed_type; - int max_depth = pci_get_max_depth(); - int pci_try_num; - + int pci_try_num = 1; head.next = NULL; realloc_list.next = NULL; - pci_try_num = max_depth + 1; - printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", - max_depth, pci_try_num); + /* don't realloc if asked to do so */ + if (pci_realloc_enabled()) { + int max_depth = pci_get_max_depth(); + + pci_try_num = max_depth + 1; + printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", + max_depth, pci_try_num); + } again: + /* + * last try will use add_list, otherwise will try good to have as + * must have, so can realloc parent bridge resource + */ + if (tried_times + 1 == pci_try_num) + add_list = &realloc_list; /* Depth first, calculate sizes and alignments of all subordinate buses. */ list_for_each_entry(bus, &pci_root_buses, node) - __pci_bus_size_bridges(bus, &realloc_list); + __pci_bus_size_bridges(bus, add_list); /* Depth last, allocate resources and update the hardware. */ list_for_each_entry(bus, &pci_root_buses, node) - __pci_bus_assign_resources(bus, &realloc_list, &head); - BUG_ON(realloc_list.next); + __pci_bus_assign_resources(bus, add_list, &head); + if (add_list) + BUG_ON(add_list->next); tried_times++; /* any device complain? */ if (!head.next) goto enable_and_dump; - /* don't realloc if asked to do so */ - if (!pci_realloc_enabled()) { - free_list(resource_list_x, &head); - goto enable_and_dump; - } - failed_type = 0; for (list = head.next; list;) { failed_type |= list->flags; |