From patchwork Wed Dec 20 20:36:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thierry Reding X-Patchwork-Id: 10126549 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DEAF06019C for ; Wed, 20 Dec 2017 20:36:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C77D229225 for ; Wed, 20 Dec 2017 20:36:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B971629237; Wed, 20 Dec 2017 20:36:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EEE2629225 for ; Wed, 20 Dec 2017 20:36:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755557AbdLTUgL (ORCPT ); Wed, 20 Dec 2017 15:36:11 -0500 Received: from mail-qk0-f194.google.com ([209.85.220.194]:42609 "EHLO mail-qk0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754428AbdLTUgL (ORCPT ); Wed, 20 Dec 2017 15:36:11 -0500 Received: by mail-qk0-f194.google.com with SMTP id d202so3793624qkc.9; Wed, 20 Dec 2017 12:36:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=r2GHUiBvPa/UlPfeqPDmiIboCSS+FHb+NouMVSI8JVU=; b=E0feRYiPjuLcclVo3b7S66PeNpW1oPAwWurEP7plhLf6bUD9oRXjzoVZVehfRW7Xf+ XdnSsAOXtokxqdoN0IKSVAI32rkRoSdk3G3lPrN8T+qCXSIVJC/HWEoTidXaErxGW9di xFjbi6jUkuQnfHuYjscLVpYGBMX2tI175WprNOTUxn9n9XcHKOEy6N4rlqKQDcW5yM44 6jZH3kqAceeai28dV7kU8sHCQgHFRFF/OgK/TdtHWgyw1YxXZY7wl+fw5jRDQXvd3hUm +YjJyDvxiLGrJu6oO1yCnVO8JZOMsAGG7momI995L1yEIdA4VQBlYS80Ltpa2wHa5+4m 2Fww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=r2GHUiBvPa/UlPfeqPDmiIboCSS+FHb+NouMVSI8JVU=; b=LbrXl+ozQicqEcnYXF+VIdYk7BAy18SygsqRfcwVegMw0UIHj80w0Vr5dloLyku4lR QDEAIRLOYY7jle2qjha49IVkIVrzqB1nToUt9rQDmehwJCLz/OCvHnD/oyWYIeFMToOW ENpQG8h23REaXCUeeSH1+sBPUU0rM26AkV3iSFN0gJCWRfXral8nl8koavep5/6v9YL4 0J6rDY6hRxjgmsrywqQtKAXYk6vuH2LEoUTmYu/RD0ehdiRN7OL3629Y6zCCGRXRnwUq N3T9HaQlQKdgjj2m7jWA8oPh61/PEjkXpacrQUx3SSSwQKT3BJnNtVSAXMcnpkZQ3u2w Fk9Q== X-Gm-Message-State: AKGB3mJ57RNLrvfeOpvw+BbGb8A1EG8jSeoqmyZIE1ZjLvmT6lzikOJh kxz+CuERUVFALQ1Dj7CuWYI= X-Google-Smtp-Source: ACJfBou4nY7xWmSDq3iw1J1OY5ZlZLOsdJ5Cj0TE46WSU+Oba45lPD/eqhNOMnvr7o18dgIOs2gx1g== X-Received: by 10.55.126.198 with SMTP id z189mr12069097qkc.100.1513802170016; Wed, 20 Dec 2017 12:36:10 -0800 (PST) Received: from localhost (p200300E41F200F003F65F430A8AE2E44.dip0.t-ipconnect.de. [2003:e4:1f20:f00:3f65:f430:a8ae:2e44]) by smtp.gmail.com with ESMTPSA id u26sm11778846qtb.1.2017.12.20.12.36.09 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Dec 2017 12:36:09 -0800 (PST) From: Thierry Reding To: Lorenzo Pieralisi , Bjorn Helgaas Cc: Jonathan Hunter , Vidya Saga , Manikanta Maddireddy , linux-pci@vger.kernel.org, linux-tegra@vger.kernel.org Subject: [PATCH v4] PCI: tegra: Refactor configuration space mapping code Date: Wed, 20 Dec 2017 21:36:07 +0100 Message-Id: <20171220203607.18288-1-thierry.reding@gmail.com> X-Mailer: git-send-email 2.15.1 Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Vidya Sagar Use only 4 KiB space from the available 1 GiB PCIe aperture to access endpoint configuration space by dynamically moving the AFI_FPCI_BAR base address. This frees more space for mapping endpoint device BARs on some Tegra platforms. The ->add_bus() and ->remove_bus() callbacks are now no longer needed, so they can be removed. Signed-off-by: Vidya Sagar [treding@nvidia.com: various cleanups, update commit message] Signed-off-by: Thierry Reding --- drivers/pci/host/pci-tegra.c | 148 +++++++++---------------------------------- 1 file changed, 30 insertions(+), 118 deletions(-) diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index f2214ca1ad17..56434aa44b60 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -269,11 +269,10 @@ struct tegra_pcie { void __iomem *pads; void __iomem *afi; + void __iomem *cfg; int irq; - struct list_head buses; - struct resource *cs; - + struct resource cs; struct resource io; struct resource pio; struct resource mem; @@ -322,7 +321,6 @@ struct tegra_pcie_port { }; struct tegra_pcie_bus { - struct vm_struct *area; struct list_head list; unsigned int nr; }; @@ -362,100 +360,19 @@ static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset) * * Mapping the whole extended configuration space would require 256 MiB of * virtual address space, only a small part of which will actually be used. - * To work around this, a 1 MiB of virtual addresses are allocated per bus - * when the bus is first accessed. When the physical range is mapped, the - * the bus number bits are hidden so that the extended register number bits - * appear as bits [19:16]. Therefore the virtual mapping looks like this: - * - * [19:16] extended register number - * [15:11] device number - * [10: 8] function number - * [ 7: 0] register number * - * This is achieved by stitching together 16 chunks of 64 KiB of physical - * address space via the MMU. + * To work around this, a 4 KiB region is used to generate the required + * configuration transaction with relevant B:D:F and register offset values. + * This is achieved by dynamically programming base address and size of + * AFI_AXI_BAR used for end point config space mapping to make sure that the + * address (access to which generates correct config transaction) falls in + * this 4 KiB region. */ -static unsigned long tegra_pcie_conf_offset(unsigned int devfn, int where) -{ - return ((where & 0xf00) << 8) | (PCI_SLOT(devfn) << 11) | - (PCI_FUNC(devfn) << 8) | (where & 0xfc); -} - -static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie, - unsigned int busnr) +static unsigned int tegra_pcie_conf_offset(u8 bus, unsigned int devfn, + unsigned int where) { - struct device *dev = pcie->dev; - pgprot_t prot = pgprot_noncached(PAGE_KERNEL); - phys_addr_t cs = pcie->cs->start; - struct tegra_pcie_bus *bus; - unsigned int i; - int err; - - bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (!bus) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&bus->list); - bus->nr = busnr; - - /* allocate 1 MiB of virtual addresses */ - bus->area = get_vm_area(SZ_1M, VM_IOREMAP); - if (!bus->area) { - err = -ENOMEM; - goto free; - } - - /* map each of the 16 chunks of 64 KiB each */ - for (i = 0; i < 16; i++) { - unsigned long virt = (unsigned long)bus->area->addr + - i * SZ_64K; - phys_addr_t phys = cs + i * SZ_16M + busnr * SZ_64K; - - err = ioremap_page_range(virt, virt + SZ_64K, phys, prot); - if (err < 0) { - dev_err(dev, "ioremap_page_range() failed: %d\n", err); - goto unmap; - } - } - - return bus; - -unmap: - vunmap(bus->area->addr); -free: - kfree(bus); - return ERR_PTR(err); -} - -static int tegra_pcie_add_bus(struct pci_bus *bus) -{ - struct pci_host_bridge *host = pci_find_host_bridge(bus); - struct tegra_pcie *pcie = pci_host_bridge_priv(host); - struct tegra_pcie_bus *b; - - b = tegra_pcie_bus_alloc(pcie, bus->number); - if (IS_ERR(b)) - return PTR_ERR(b); - - list_add_tail(&b->list, &pcie->buses); - - return 0; -} - -static void tegra_pcie_remove_bus(struct pci_bus *child) -{ - struct pci_host_bridge *host = pci_find_host_bridge(child); - struct tegra_pcie *pcie = pci_host_bridge_priv(host); - struct tegra_pcie_bus *bus, *tmp; - - list_for_each_entry_safe(bus, tmp, &pcie->buses, list) { - if (bus->nr == child->number) { - vunmap(bus->area->addr); - list_del(&bus->list); - kfree(bus); - break; - } - } + return ((where & 0xf00) << 16) | (bus << 16) | (PCI_SLOT(devfn) << 11) | + (PCI_FUNC(devfn) << 8) | (where & 0xff); } static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, @@ -464,7 +381,6 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, { struct pci_host_bridge *host = pci_find_host_bridge(bus); struct tegra_pcie *pcie = pci_host_bridge_priv(host); - struct device *dev = pcie->dev; void __iomem *addr = NULL; if (bus->number == 0) { @@ -478,19 +394,17 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, } } } else { - struct tegra_pcie_bus *b; + unsigned int offset; + u32 base; - list_for_each_entry(b, &pcie->buses, list) - if (b->nr == bus->number) - addr = (void __iomem *)b->area->addr; + offset = tegra_pcie_conf_offset(bus->number, devfn, where); - if (!addr) { - dev_err(dev, "failed to map cfg. space for bus %u\n", - bus->number); - return NULL; - } + /* move 4 KiB window to offset within the FPCI region */ + base = 0xfe100000 + ((offset & ~(SZ_4K - 1)) >> 8); + afi_writel(pcie, base, AFI_FPCI_BAR0); - addr += tegra_pcie_conf_offset(devfn, where); + /* move to correct offset within the 4 KiB page */ + addr = pcie->cfg + (offset & (SZ_4K - 1)); } return addr; @@ -517,8 +431,6 @@ static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops tegra_pcie_ops = { - .add_bus = tegra_pcie_add_bus, - .remove_bus = tegra_pcie_remove_bus, .map_bus = tegra_pcie_map_bus, .read = tegra_pcie_config_read, .write = tegra_pcie_config_write, @@ -743,12 +655,9 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) u32 fpci_bar, size, axi_address; /* Bar 0: type 1 extended configuration space */ - fpci_bar = 0xfe100000; - size = resource_size(pcie->cs); - axi_address = pcie->cs->start; - afi_writel(pcie, axi_address, AFI_AXI_BAR0_START); + size = resource_size(&pcie->cs); + afi_writel(pcie, pcie->cs.start, AFI_AXI_BAR0_START); afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ); - afi_writel(pcie, fpci_bar, AFI_FPCI_BAR0); /* Bar 1: downstream IO bar */ fpci_bar = 0xfdfc0000; @@ -1353,10 +1262,14 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) goto poweroff; } - pcie->cs = devm_request_mem_region(dev, res->start, - resource_size(res), res->name); - if (!pcie->cs) { - err = -EADDRNOTAVAIL; + pcie->cs = *res; + + /* constrain configuration space to 4 KiB */ + pcie->cs.end = pcie->cs.start + SZ_4K - 1; + + pcie->cfg = devm_ioremap_resource(dev, &pcie->cs); + if (IS_ERR(pcie->cfg)) { + err = PTR_ERR(pcie->cfg); goto poweroff; } @@ -2376,7 +2289,6 @@ static int tegra_pcie_probe(struct platform_device *pdev) pcie = pci_host_bridge_priv(host); pcie->soc = of_device_get_match_data(dev); - INIT_LIST_HEAD(&pcie->buses); INIT_LIST_HEAD(&pcie->ports); pcie->dev = dev;