From patchwork Wed Oct 26 01:24:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Duc Dang X-Patchwork-Id: 9395785 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 B3AB060235 for ; Wed, 26 Oct 2016 01:31:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 50CA329768 for ; Wed, 26 Oct 2016 01:31:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 404A82976B; Wed, 26 Oct 2016 01:31:24 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID 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 0235529768 for ; Wed, 26 Oct 2016 01:31:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754103AbcJZBbU (ORCPT ); Tue, 25 Oct 2016 21:31:20 -0400 Received: from mail-pf0-f170.google.com ([209.85.192.170]:34586 "EHLO mail-pf0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753810AbcJZBbT (ORCPT ); Tue, 25 Oct 2016 21:31:19 -0400 Received: by mail-pf0-f170.google.com with SMTP id n85so12464093pfi.1 for ; Tue, 25 Oct 2016 18:31:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=apm.com; s=apm; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=R10Gyijlw8AZoJN9hojfuURXhtKLkKOfC22EjBeG+wY=; b=Z2lpPnQeMLmDb7zEbhWmrHVcILcbHiBbDHrcNngN0xwqgAY944wkXVnVIUCRcbTprg ni48ItfurpeHY1JhG9XHKgrLYU2A7iTGbfGEP9RcEba7K2yBSn9fTX1exuX/CDXWE2sE Wo5Q5ityHeFIJ2Nf7K0DkChJ7tCW2RLPanR5E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=R10Gyijlw8AZoJN9hojfuURXhtKLkKOfC22EjBeG+wY=; b=H/snHNeBOnIfkSuuYcWxJppmM5WiauyAuDfabwXA2/dzwvyJuC0/80uWVWoYh/KHV9 O8UfTTTjX3x1ND7QQLVYSrBYWbofBk1dSy7L5d6O86bXJ0j/l7DvuFXaUH5GjvG/hFBd qIJeeWgfY5Roz+f0gPQ0X2HqW2q8FRFGhj/cH9UHry0A4+WPhEqnUMqr3SvKzvSOdquO +sogMuQ6+TwI6KdIBsTly80cNL3/rFPU0Ps+rD/FFAtxN86PkTkgjJFXhd+as6xdn7/c Z0/8+EaYSGWdqvkOvVBOQLMVpIxAjKzcV7nIXHLvlpPx4C5++uilKfh9NuDiFZzKPHCG 7Vuw== X-Gm-Message-State: ABUngveMnzjvFEmGnUVUjxfH2lujqZBFmaKRc3f4hRLpuKPh94ycsXKUQe6BiarahIVjCB0P X-Received: by 10.98.26.205 with SMTP id a196mr45038877pfa.50.1477445478643; Tue, 25 Oct 2016 18:31:18 -0700 (PDT) Received: from dhdang-workstation-01.amcc.com ([206.80.4.98]) by smtp.gmail.com with ESMTPSA id f67sm36143510pfg.18.2016.10.25.18.31.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 25 Oct 2016 18:31:17 -0700 (PDT) From: Duc Dang To: Bjorn Helgaas Cc: Rafael Wysocki , Lorenzo Pieralisi , Arnd Bergmann , Mark Salter , linux-pci@vger.kernel.org, linux-arm , Linux Kernel Mailing List , Jon Masters , Tomasz Nowicki , patches , Duc Dang Subject: [RFC PATCH v2 1/1] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller Date: Tue, 25 Oct 2016 18:24:32 -0700 Message-Id: X-Mailer: git-send-email 1.9.1 In-Reply-To: <20160921212258.GE20006@localhost> References: <20160921212258.GE20006@localhost> 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 PCIe controllers in X-Gene SoCs is not ECAM compliant: software needs to configure additional controller's register to address device at bus:dev:function. This patch depends on "ECAM quirks handling for ARM64 platforms" series (http://www.spinics.net/lists/arm-kernel/msg530692.html, the series was also modified by Bjorn) to address the limitation above for X-Gene PCIe controller. The quirk will only be applied for X-Gene PCIe MCFG table with OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs). Signed-off-by: Duc Dang --- v2 changes: 1. Get rid of pci-xgene-ecam.c file and fold quirk code into pci-xgene.c 2. Redefine fixup array for X-Gene 3. Use devm_ioremap_resource to map csr_base drivers/acpi/pci_mcfg.c | 30 ++++++++ drivers/pci/host/pci-xgene.c | 165 ++++++++++++++++++++++++++++++++++++++++++- include/linux/pci-ecam.h | 5 ++ 3 files changed, 197 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index bb2c508..9dfc937 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -96,6 +96,36 @@ struct mcfg_fixup { THUNDER_ECAM_MCFG(2, 12), THUNDER_ECAM_MCFG(2, 13), #endif +#ifdef CONFIG_PCI_XGENE +#define XGENE_V1_ECAM_MCFG(rev, seg) \ + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ + &xgene_v1_pcie_ecam_ops } +#define XGENE_V2_1_ECAM_MCFG(rev, seg) \ + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ + &xgene_v2_1_pcie_ecam_ops } +#define XGENE_V2_2_ECAM_MCFG(rev, seg) \ + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ + &xgene_v2_2_pcie_ecam_ops } + + /* X-Gene SoC with v1 PCIe controller */ + XGENE_V1_ECAM_MCFG(1, 0), + XGENE_V1_ECAM_MCFG(1, 1), + XGENE_V1_ECAM_MCFG(1, 2), + XGENE_V1_ECAM_MCFG(1, 3), + XGENE_V1_ECAM_MCFG(1, 4), + XGENE_V1_ECAM_MCFG(2, 0), + XGENE_V1_ECAM_MCFG(2, 1), + XGENE_V1_ECAM_MCFG(2, 2), + XGENE_V1_ECAM_MCFG(2, 3), + XGENE_V1_ECAM_MCFG(2, 4), + /* X-Gene SoC with v2.1 PCIe controller */ + XGENE_V2_1_ECAM_MCFG(3, 0), + XGENE_V2_1_ECAM_MCFG(3, 1), + /* X-Gene SoC with v2.2 PCIe controller */ + XGENE_V2_2_ECAM_MCFG(4, 0), + XGENE_V2_2_ECAM_MCFG(4, 1), + XGENE_V2_2_ECAM_MCFG(4, 2), +#endif }; static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index 1de23d7..d6aa642 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -64,6 +66,7 @@ /* PCIe IP version */ #define XGENE_PCIE_IP_VER_UNKN 0 #define XGENE_PCIE_IP_VER_1 1 +#define XGENE_PCIE_IP_VER_2 2 struct xgene_pcie_port { struct device_node *node; @@ -97,7 +100,15 @@ static inline u32 pcie_bar_low_val(u32 addr, u32 flags) */ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) { - struct xgene_pcie_port *port = bus->sysdata; + struct pci_config_window *cfg; + struct xgene_pcie_port *port; + + if (acpi_disabled) + port = bus->sysdata; + else { + cfg = bus->sysdata; + port = cfg->priv; + } if (bus->number >= (bus->primary + 1)) return port->cfg_base + AXI_EP_CFG_ACCESS; @@ -111,10 +122,18 @@ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) */ static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn) { - struct xgene_pcie_port *port = bus->sysdata; + struct pci_config_window *cfg; + struct xgene_pcie_port *port; unsigned int b, d, f; u32 rtdid_val = 0; + if (acpi_disabled) + port = bus->sysdata; + else { + cfg = bus->sysdata; + port = cfg->priv; + } + b = bus->number; d = PCI_SLOT(devfn); f = PCI_FUNC(devfn); @@ -158,7 +177,15 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - struct xgene_pcie_port *port = bus->sysdata; + struct pci_config_window *cfg; + struct xgene_pcie_port *port; + + if (acpi_disabled) + port = bus->sysdata; + else { + cfg = bus->sysdata; + port = cfg->priv; + } if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) != PCIBIOS_SUCCESSFUL) @@ -189,6 +216,138 @@ static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, .write = pci_generic_config_write32, }; +#ifdef CONFIG_ACPI +static struct resource xgene_v1_csr_res[] = { + [0] = DEFINE_RES_MEM(0x1f2b0000UL, SZ_64K), + [1] = DEFINE_RES_MEM(0x1f2c0000UL, SZ_64K), + [2] = DEFINE_RES_MEM(0x1f2d0000UL, SZ_64K), + [3] = DEFINE_RES_MEM(0x1f500000UL, SZ_64K), + [4] = DEFINE_RES_MEM(0x1f510000UL, SZ_64K), +}; + +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg) +{ + struct acpi_device *adev = to_acpi_device(cfg->parent); + struct acpi_pci_root *root = acpi_driver_data(adev); + struct device *dev = cfg->parent; + struct xgene_pcie_port *port; + struct resource *csr; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + csr = &xgene_v1_csr_res[root->segment]; + port->csr_base = devm_ioremap_resource(dev, csr); + if (IS_ERR(port->csr_base)) { + kfree(port); + return -ENOMEM; + } + + port->cfg_base = cfg->win; + port->version = XGENE_PCIE_IP_VER_1; + + cfg->priv = port; + + return 0; +} + +struct pci_ecam_ops xgene_v1_pcie_ecam_ops = { + .bus_shift = 16, + .init = xgene_v1_pcie_ecam_init, + .pci_ops = { + .map_bus = xgene_pcie_map_bus, + .read = xgene_pcie_config_read32, + .write = pci_generic_config_write, + } +}; + +static struct resource xgene_v2_1_csr_res[] = { + [0] = DEFINE_RES_MEM(0x1f2b0000UL, SZ_64K), + [1] = DEFINE_RES_MEM(0x1f2c0000UL, SZ_64K), +}; + +static int xgene_v2_1_pcie_ecam_init(struct pci_config_window *cfg) +{ + struct acpi_device *adev = to_acpi_device(cfg->parent); + struct acpi_pci_root *root = acpi_driver_data(adev); + struct device *dev = cfg->parent; + struct xgene_pcie_port *port; + struct resource *csr; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + csr = &xgene_v2_1_csr_res[root->segment]; + port->csr_base = devm_ioremap_resource(dev, csr); + if (IS_ERR(port->csr_base)) { + kfree(port); + return -ENOMEM; + } + + port->cfg_base = cfg->win; + port->version = XGENE_PCIE_IP_VER_2; + + cfg->priv = port; + + return 0; +} + +struct pci_ecam_ops xgene_v2_1_pcie_ecam_ops = { + .bus_shift = 16, + .init = xgene_v2_1_pcie_ecam_init, + .pci_ops = { + .map_bus = xgene_pcie_map_bus, + .read = xgene_pcie_config_read32, + .write = pci_generic_config_write, + } +}; + +static struct resource xgene_v2_2_csr_res[] = { + [0] = DEFINE_RES_MEM(0x1f2b0000UL, SZ_64K), + [1] = DEFINE_RES_MEM(0x1f500000UL, SZ_64K), + [2] = DEFINE_RES_MEM(0x1f2d0000UL, SZ_64K), +}; + +static int xgene_v2_2_pcie_ecam_init(struct pci_config_window *cfg) +{ + struct acpi_device *adev = to_acpi_device(cfg->parent); + struct acpi_pci_root *root = acpi_driver_data(adev); + struct device *dev = cfg->parent; + struct xgene_pcie_port *port; + struct resource *csr; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + csr = &xgene_v2_2_csr_res[root->segment]; + port->csr_base = devm_ioremap_resource(dev, csr); + if (IS_ERR(port->csr_base)) { + kfree(port); + return -ENOMEM; + } + + port->cfg_base = cfg->win; + port->version = XGENE_PCIE_IP_VER_2; + + cfg->priv = port; + + return 0; +} + +struct pci_ecam_ops xgene_v2_2_pcie_ecam_ops = { + .bus_shift = 16, + .init = xgene_v2_2_pcie_ecam_init, + .pci_ops = { + .map_bus = xgene_pcie_map_bus, + .read = xgene_pcie_config_read32, + .write = pci_generic_config_write, + } +}; +#endif + static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr, u32 flags, u64 size) { diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 35f0e81..40da3e7 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -65,6 +65,11 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, #ifdef CONFIG_PCI_HOST_THUNDER_ECAM extern struct pci_ecam_ops pci_thunder_ecam_ops; #endif +#ifdef CONFIG_PCI_XGENE +extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; +extern struct pci_ecam_ops xgene_v2_1_pcie_ecam_ops; +extern struct pci_ecam_ops xgene_v2_2_pcie_ecam_ops; +#endif #ifdef CONFIG_PCI_HOST_GENERIC /* for DT-based PCI controllers that support ECAM */