From patchwork Fri Oct 2 22:37:56 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Daney X-Patchwork-Id: 525837 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 4D3F4140D6D for ; Sat, 3 Oct 2015 08:38:50 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=Y8vJjnJr; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751768AbbJBWiJ (ORCPT ); Fri, 2 Oct 2015 18:38:09 -0400 Received: from mail-io0-f182.google.com ([209.85.223.182]:34342 "EHLO mail-io0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751720AbbJBWiH (ORCPT ); Fri, 2 Oct 2015 18:38:07 -0400 Received: by iow1 with SMTP id 1so98311317iow.1; Fri, 02 Oct 2015 15:38:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=WB9mE3A0StMUyYsLHsoIP9v0+8/efcn1iXTxUs+jPtk=; b=Y8vJjnJrx7+Wl47bDt3sCyenIRYqIxI/Mj//EUzcaE+RZo9L9RBZBK5I4DDeQilT4l K5l61Z4khSQYAC7N7DJBMRibkQlNQ8ogDS+HyYbjHLliMtyphspPXxIDqFtfIgCaP53B AIUVi7375Bnjdcjsm0KL11u5qbGwRQHNCi6aRtfkXYyLLAMbX69qJcEnfva1Cat26BFm +np1JOqNZ0nsmVtukz64EFVmuHS/FddQYEPBHhQhkqTeC5ve9bnS4H84qK0xp8CaErC6 tdRczdYGZhvdCtGtrkFWdJr8cMdOxJL8It6rtyxLC48g5aU1/9wPjfNz2vPmiKC8mVyb jmLA== X-Received: by 10.107.168.39 with SMTP id r39mr21982828ioe.42.1443825486178; Fri, 02 Oct 2015 15:38:06 -0700 (PDT) Received: from dl.caveonetworks.com (64.2.3.194.ptr.us.xo.net. [64.2.3.194]) by smtp.gmail.com with ESMTPSA id 20sm5826601ioj.25.2015.10.02.15.38.00 (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 02 Oct 2015 15:38:04 -0700 (PDT) Received: from dl.caveonetworks.com (localhost.localdomain [127.0.0.1]) by dl.caveonetworks.com (8.14.5/8.14.5) with ESMTP id t92Mbx5H026939; Fri, 2 Oct 2015 15:37:59 -0700 Received: (from ddaney@localhost) by dl.caveonetworks.com (8.14.5/8.14.5/Submit) id t92MbxVc026938; Fri, 2 Oct 2015 15:37:59 -0700 From: David Daney To: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, Bjorn Helgaas , "Michael S. Tsirkin" , =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= , linux-api@vger.kernel.org, "Sean O. Stalley" , yinghai@kernel.org, rajatxjain@gmail.com, gong.chen@linux.intel.com Cc: David Daney Subject: [PATCH v4 5/5] PCI: Handle Enhanced Allocation (EA) capability for bridges Date: Fri, 2 Oct 2015 15:37:56 -0700 Message-Id: <1443825476-26880-6-git-send-email-ddaney.cavm@gmail.com> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1443825476-26880-1-git-send-email-ddaney.cavm@gmail.com> References: <1443825476-26880-1-git-send-email-ddaney.cavm@gmail.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org From: David Daney PCI bridges may have their properties be specified via EA entries. Extend the EA parser to extract the bridge resources, and modify pci_read_bridge_{io,mmio,mmio_pref}() to use resources previously obtained via EA. Save the offset to the EA capability in struct pci_dev, and use it to easily find the EA bridge subordinate and secondary bus numbers. When assigning the bridge resources a couple of changes are required so that the EA obtained IORESOURCE_PCI_FIXED are not resized, and correctly linked into the resource tree. 1) In pbus_size_mem() do not attempt to resize the bridge resources if they are marked as IORESOURCE_PCI_FIXED. 2) In pci_bus_alloc_from_region()for IORESOURCE_PCI_FIXED resources, just try to request the resource as is, without attempting to resize it. Signed-off-by: David Daney --- drivers/pci/bus.c | 7 +++++++ drivers/pci/pci.c | 13 +++++++++++++ drivers/pci/probe.c | 31 +++++++++++++++++++++++++++++-- drivers/pci/setup-bus.c | 3 +++ include/linux/pci.h | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 6fbd3f2..0556b33 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -153,6 +153,13 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res, !(res->flags & IORESOURCE_PREFETCH)) continue; + if (res->flags & IORESOURCE_PCI_FIXED) { + /* Cannot change it, just try to claim it. */ + if (request_resource(r, res)) + continue; + return 0; + } + avail = *r; pci_clip_resource_to_region(bus, &avail, region); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6750edf..c857632 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2183,6 +2183,17 @@ static struct resource *pci_ea_get_resource(struct pci_dev *dev, u8 bei, u8 prop (prop == PCI_EA_P_VIRT_MEM || prop == PCI_EA_P_VIRT_MEM_PREFETCH)) return &dev->resource[PCI_IOV_RESOURCES + bei - PCI_EA_BEI_VF_BAR0]; #endif + else if (bei == PCI_EA_BEI_BRIDGE) + switch (prop) { + case PCI_EA_P_BRIDGE_IO: + return &dev->resource[PCI_BRIDGE_RESOURCES + 0]; + case PCI_EA_P_BRIDGE_MEM: + return &dev->resource[PCI_BRIDGE_RESOURCES + 1]; + case PCI_EA_P_BRIDGE_MEM_PREFETCH: + return &dev->resource[PCI_BRIDGE_RESOURCES + 2]; + default: + return NULL; + } else if (bei == PCI_EA_BEI_ROM) return &dev->resource[PCI_ROM_RESOURCE]; else @@ -2321,6 +2332,8 @@ void pci_ea_init(struct pci_dev *dev) if (!ea) return; + dev->ea_cap = ea; + /* determine the number of entries */ pci_bus_read_config_byte(dev->bus, dev->devfn, ea + PCI_EA_NUM_ENT, &num_ent); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4293eec..e4bcb0b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -348,6 +348,10 @@ static void pci_read_bridge_io(struct pci_bus *child) } res = child->resource[0]; + if (res->flags & IORESOURCE_PCI_FIXED) { + dev_dbg(&dev->dev, " bridge window %pR (fixed)\n", res); + return; + } pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); base = (io_base_lo & io_mask) << 8; @@ -380,6 +384,10 @@ static void pci_read_bridge_mmio(struct pci_bus *child) struct resource *res; res = child->resource[1]; + if (res->flags & IORESOURCE_PCI_FIXED) { + dev_dbg(&dev->dev, " bridge window %pR (fixed)\n", res); + return; + } pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; @@ -403,6 +411,10 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child) struct resource *res; res = child->resource[2]; + if (res->flags & IORESOURCE_PCI_FIXED) { + dev_dbg(&dev->dev, " bridge window %pR (fixed)\n", res); + return; + } pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; @@ -801,8 +813,23 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); primary = buses & 0xFF; - secondary = (buses >> 8) & 0xFF; - subordinate = (buses >> 16) & 0xFF; + if (dev->ea_cap) { + u32 dw1; + + pci_read_config_dword(dev, dev->ea_cap + 4, &dw1); + if (dw1 & 0xFF) + secondary = dw1 & 0xFF; + else + secondary = (buses >> 8) & 0xFF; + + if ((dw1 >> 8) & 0xFF) + subordinate = (dw1 >> 8) & 0xFF; + else + subordinate = (buses >> 16) & 0xFF; + } else { + secondary = (buses >> 8) & 0xFF; + subordinate = (buses >> 16) & 0xFF; + } dev_dbg(&dev->dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n", secondary, subordinate, pass); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 8f9ed9b..8b8cc32 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -1086,6 +1086,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, } } + if (b_res->flags & IORESOURCE_PCI_FIXED) + return 0; + min_align = calculate_mem_align(aligns, max_order); min_align = max(min_align, window_alignment(bus, b_res->flags)); size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); diff --git a/include/linux/pci.h b/include/linux/pci.h index b505b50..a8a177c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -384,6 +384,7 @@ struct pci_dev { phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */ size_t romlen; /* Length of ROM if it's not from the BAR */ char *driver_override; /* Driver name to force a match */ + u8 ea_cap; /* Enhanced Allocation capability offset */ }; static inline struct pci_dev *pci_physfn(struct pci_dev *dev)