From patchwork Wed Nov 10 17:26:07 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bjorn Helgaas X-Patchwork-Id: 314812 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oAAHQOZA010242 for ; Wed, 10 Nov 2010 17:26:24 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932084Ab0KJR0N (ORCPT ); Wed, 10 Nov 2010 12:26:13 -0500 Received: from g1t0028.austin.hp.com ([15.216.28.35]:3436 "EHLO g1t0028.austin.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932074Ab0KJR0M (ORCPT ); Wed, 10 Nov 2010 12:26:12 -0500 Received: from g1t0038.austin.hp.com (g1t0038.austin.hp.com [16.236.32.44]) by g1t0028.austin.hp.com (Postfix) with ESMTP id DFAF91C362; Wed, 10 Nov 2010 17:26:09 +0000 (UTC) Received: from ldl (ldl.usa.hp.com [16.125.112.222]) by g1t0038.austin.hp.com (Postfix) with ESMTP id 454F830177; Wed, 10 Nov 2010 17:26:08 +0000 (UTC) Received: from localhost (ldl.fc.hp.com [127.0.0.1]) by ldl (Postfix) with ESMTP id 00740CF0018; Wed, 10 Nov 2010 10:26:08 -0700 (MST) Received: from ldl ([127.0.0.1]) by localhost (ldl.fc.hp.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zeOyZQYT8bIG; Wed, 10 Nov 2010 10:26:07 -0700 (MST) Received: from eh.fc.hp.com (bob.lnx.usa.hp.com [16.125.112.218]) by ldl (Postfix) with ESMTP id D553ECF0009; Wed, 10 Nov 2010 10:26:07 -0700 (MST) Received: from bob.kio (localhost [127.0.0.1]) by eh.fc.hp.com (Postfix) with ESMTP id 814AF26196; Wed, 10 Nov 2010 10:26:07 -0700 (MST) Subject: [PATCH v2] PCI: fix pci_bus_alloc_resource() hang, prefer positive decode To: Jesse Barnes From: Bjorn Helgaas Cc: Bob Picco , Brian Bloniarz , Charles Butterfield , Denys Vlasenko , Ingo Molnar , linux-pci@vger.kernel.org, "Horst H. von Brand" , "H. Peter Anvin" , linux-kernel@vger.kernel.org, Borislav Petkov , Stefan Becker , Chuck Ebbert , Fabrice Bellet , Yinghai Lu , Leann Ogasawara , Linus Torvalds , Thomas Gleixner Date: Wed, 10 Nov 2010 10:26:07 -0700 Message-ID: <20101110172607.2537.10985.stgit@bob.kio> User-Agent: StGit/0.15 MIME-Version: 1.0 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Wed, 10 Nov 2010 17:26:24 +0000 (UTC) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 5624db8..003170e 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -64,17 +64,57 @@ void pci_bus_remove_resources(struct pci_bus *bus) } } +static bool pci_bus_resource_better(struct resource *res1, bool pos1, + struct resource *res2, bool pos2) +{ + /* If exactly one is positive decode, always prefer that one */ + if (pos1 != pos2) + return pos1 ? true : false; + + /* Prefer the one that contains the highest address */ + if (res1->end != res2->end) + return (res1->end > res2->end) ? true : false; + + /* Otherwise, prefer the one with highest "center of gravity" */ + if (res1->start != res2->start) + return (res1->start > res2->start) ? true : false; + + /* Otherwise, choose one arbitrarily (but consistently) */ + return (res1 > res2) ? true : false; +} + +static bool pci_bus_resource_positive(struct pci_bus *bus, struct resource *res) +{ + struct pci_bus_resource *bus_res; + + /* + * This relies on the fact that pci_bus.resource[] refers to P2P or + * CardBus bridge base/limit registers, which are always positively + * decoded. The pci_bus.resources list contains host bridge or + * subtractively decoded resources. + */ + list_for_each_entry(bus_res, &bus->resources, list) { + if (bus_res->res == res) + return (bus_res->flags & PCI_SUBTRACTIVE_DECODE) ? + false : true; + } + return true; +} + /* - * Find the highest-address bus resource below the cursor "res". If the - * cursor is NULL, return the highest resource. + * Find the next-best bus resource after the cursor "res". If the cursor is + * NULL, return the best resource. "Best" means that we prefer positive + * decode regions over subtractive decode, then those at higher addresses. */ static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, unsigned int type, struct resource *res) { + bool res_pos, r_pos, prev_pos = false; struct resource *r, *prev = NULL; int i; + res_pos = pci_bus_resource_positive(bus, res); pci_bus_for_each_resource(bus, r, i) { if (!r) continue; @@ -82,26 +122,14 @@ static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, if ((r->flags & IORESOURCE_TYPE_BITS) != type) continue; - /* If this resource is at or past the cursor, skip it */ - if (res) { - if (r == res) - continue; - if (r->end > res->end) - continue; - if (r->end == res->end && r->start > res->start) - continue; + r_pos = pci_bus_resource_positive(bus, r); + if (!res || pci_bus_resource_better(res, res_pos, r, r_pos)) { + if (!prev || pci_bus_resource_better(r, r_pos, + prev, prev_pos)) { + prev = r; + prev_pos = r_pos; + } } - - if (!prev) - prev = r; - - /* - * A small resource is higher than a large one that ends at - * the same address. - */ - if (r->end > prev->end || - (r->end == prev->end && r->start > prev->start)) - prev = r; } return prev;