From patchwork Sat Jan 16 02:41:55 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yinghai Lu X-Patchwork-Id: 73273 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.2) with ESMTP id o0G2iYOI007281 for ; Sat, 16 Jan 2010 02:44:35 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758372Ab0APCoL (ORCPT ); Fri, 15 Jan 2010 21:44:11 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1758199Ab0APCna (ORCPT ); Fri, 15 Jan 2010 21:43:30 -0500 Received: from sca-es-mail-1.Sun.COM ([192.18.43.132]:57729 "EHLO sca-es-mail-1.sun.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758201Ab0APCnZ (ORCPT ); Fri, 15 Jan 2010 21:43:25 -0500 Received: from fe-sfbay-10.sun.com ([192.18.43.129]) by sca-es-mail-1.sun.com (8.13.7+Sun/8.12.9) with ESMTP id o0G2hED8009762; Fri, 15 Jan 2010 18:43:24 -0800 (PST) MIME-version: 1.0 Content-transfer-encoding: 7BIT Content-type: TEXT/PLAIN Received: from conversion-daemon.fe-sfbay-10.sun.com by fe-sfbay-10.sun.com (Sun Java(tm) System Messaging Server 7u2-7.04 64bit (built Jul 2 2009)) id <0KWB00500J6JYC00@fe-sfbay-10.sun.com>; Fri, 15 Jan 2010 18:43:15 -0800 (PST) Received: from localhost.localdomain ([unknown] [10.6.76.26]) by fe-sfbay-10.sun.com (Sun Java(tm) System Messaging Server 7u2-7.04 64bit (built Jul 2 2009)) with ESMTPSA id <0KWB00EKPJJTDA60@fe-sfbay-10.sun.com>; Fri, 15 Jan 2010 18:43:15 -0800 (PST) Date: Fri, 15 Jan 2010 18:41:55 -0800 From: Yinghai Lu Subject: [PATCH 05/11] pci: update bridge res to get more big range in pci assign unssign In-reply-to: <1263609721-3921-1-git-send-email-yinghai@kernel.org> To: Jesse Barnes , Ingo Molnar , Linus Torvalds , Ivan Kokshaysky , Kenji Kaneshige , Alex Chiang , Bjorn Helgaas Cc: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, Yinghai Lu Message-id: <1263609721-3921-6-git-send-email-yinghai@kernel.org> X-Mailer: git-send-email 1.6.4.2 References: <1263609721-3921-1-git-send-email-yinghai@kernel.org> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d62a5de..9dc358d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2951,6 +2951,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 < 16) + 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)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4eb10f4..f6582c4 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -212,6 +212,8 @@ static inline int pci_ari_enabled(struct pci_bus *bus) 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); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 5eebec8..8ad515e 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -798,11 +798,69 @@ static void pci_bus_dump_resources(struct pci_bus *bus) } } +static int __init pci_bus_get_depth(struct pci_bus *bus) +{ + int depth = 0; + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + int ret; + struct pci_bus *b = dev->subordinate; + if (!b) + continue; + + ret = pci_bus_get_depth(b); + if (ret + 1 > depth) + depth = ret + 1; + } + + return depth; +} +static int __init pci_get_max_depth(void) +{ + int depth = 0; + struct pci_bus *bus; + + list_for_each_entry(bus, &pci_root_buses, node) { + int ret; + + ret = pci_bus_get_depth(bus); + if (ret > depth) + depth = ret; + } + + return depth; +} + +/* + * first try will not touch pci bridge res + * second try will clear small leaf bridge res + * third try will clear related bridge: some aggressive + */ +int pci_try_num = 1; void __init pci_assign_unassigned_resources(void) { struct pci_bus *bus; + 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(); + + head.next = NULL; + + if (pci_try_num > 1) { + if (max_depth + 1 > pci_try_num) + pci_try_num = max_depth + 1; + } + + printk(KERN_DEBUG "PCI: max depth: %d pci_try_num: %d\n", + max_depth, pci_try_num); +again: /* Depth first, calculate sizes and alignments of all subordinate buses. */ list_for_each_entry(bus, &pci_root_buses, node) { @@ -810,7 +868,64 @@ 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;) { + failed_type |= list->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) + rel_type = whole_subtree; + + /* + * Try to release leaf bridge's resources that doesn't fit resource of + * child device under that bridge + */ + for (list = head.next; list;) { + bus = list->dev->bus; + pci_bus_release_bridge_resources(bus, list->flags & type_mask, + rel_type); + 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); }