BIOS separate IO range between several IOHs, and on some slots, BIOS assign the resource to the bridge, but stop assigning resource to the device under that bridge, because the device need big resource. 1. pci assign unassign and record the failed device resource. 2. clear the BIOS assigned resource of the parent bridge of fail device 3. go back and call pci assign unsigned 4. if it still fail, will go up more bridges. and clear and try again. use pci_try_num to control back track bridge levels. -v2: update it with resource_list_x Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> --- drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 2 + drivers/pci/setup-bus.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) Index: linux-2.6/drivers/pci/setup-bus.c =================================================================== --- linux-2.6.orig/drivers/pci/setup-bus.c +++ linux-2.6/drivers/pci/setup-bus.c @@ -810,11 +810,27 @@ static void pci_bus_dump_resources(struc } } +/* + * first try will not touch pci bridge res + * second try will clear small leaf bridge res + * third try will clear related bridge: some aggressive + */ +/* assume we only have 4 level bridges, so only try 5 times */ +int pci_try_num = 5; void __init pci_assign_unassigned_resources(void) { struct pci_bus *bus; + int tried_times = 0; + int check_leaf = 1; + struct resource_list_x head, *list; + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | + IORESOURCE_PREFETCH; + unsigned long failed_type; + head.next = NULL; + +again: /* Depth first, calculate sizes and alignments of all subordinate buses. */ list_for_each_entry(bus, &pci_root_buses, node) { @@ -822,7 +838,68 @@ pci_assign_unassigned_resources(void) } /* Depth last, allocate resources and update the hardware. */ list_for_each_entry(bus, &pci_root_buses, node) { - pci_bus_assign_resources(bus); + __pci_bus_assign_resources(bus, &head); + } + tried_times++; + + /* any device complain? */ + if (!head.next) + goto enable_and_dump; + failed_type = 0; + for (list = head.next; list;) { + unsigned long flags = list->flags; + + failed_type |= flags; + list = list->next; + } + /* + * io port are tight, don't try extra + * or if reach the limit, don't want to try more + */ + failed_type &= type_mask; + if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) { + free_failed_list(&head); + goto enable_and_dump; + } + + printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n", + tried_times + 1); + + /* third times and later will not check if it is leaf */ + if ((tried_times + 1) > 2) + check_leaf = 0; + + /* + * Try to release leaf bridge's resources that doesn't fit resource of + * child device under that bridge + */ + for (list = head.next; list;) { + unsigned long flags = list->flags; + + bus = list->dev->bus; + pci_bus_release_unused_bridge_res(bus, flags & type_mask, + check_leaf); + list = list->next; + } + /* retore 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; + +enable_and_dump: + /* Depth last, update the hardware. */ + list_for_each_entry(bus, &pci_root_buses, node) { pci_enable_bridges(bus); } Index: linux-2.6/drivers/pci/pci.c =================================================================== --- linux-2.6.orig/drivers/pci/pci.c +++ linux-2.6/drivers/pci/pci.c @@ -2777,6 +2777,11 @@ static int __init pci_setup(char *str) pci_no_aer(); } else if (!strcmp(str, "nodomains")) { pci_no_domains(); + } else if (!strncmp(str, "try=", 4)) { + int try_num = memparse(str + 4, &str); + + if (try_num > 0 && try_num < 10) + pci_try_num = try_num; } else if (!strncmp(str, "cbiosize=", 9)) { pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { Index: linux-2.6/drivers/pci/pci.h =================================================================== --- linux-2.6.orig/drivers/pci/pci.h +++ linux-2.6/drivers/pci/pci.h @@ -203,6 +203,8 @@ static inline int pci_ari_enabled(struct return bus->self && bus->self->ari_enabled; } +extern int pci_try_num; + #ifdef CONFIG_PCI_QUIRKS extern int pci_is_reassigndev(struct pci_dev *dev); resource_size_t pci_specified_resource_alignment(struct pci_dev *dev); -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html