From patchwork Wed Nov 30 23:42:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Duc Dang X-Patchwork-Id: 9455159 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 A008C6071E for ; Wed, 30 Nov 2016 23:53:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 92433284BB for ; Wed, 30 Nov 2016 23:53:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 868C9284BD; Wed, 30 Nov 2016 23:53:11 +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=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EF6EC284BB for ; Wed, 30 Nov 2016 23:53:10 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1cCEeu-0001S0-Tp; Wed, 30 Nov 2016 23:51:28 +0000 Received: from mail-pg0-x232.google.com ([2607:f8b0:400e:c05::232]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1cCEen-0001At-Bf for linux-arm-kernel@lists.infradead.org; Wed, 30 Nov 2016 23:51:23 +0000 Received: by mail-pg0-x232.google.com with SMTP id p66so87391748pga.2 for ; Wed, 30 Nov 2016 15:50:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=apm.com; s=apm; h=from:to:cc:subject:date:message-id; bh=MMfiVomnNWK4CWwShYihrHiuqIuM+lEQaSd5JFHNcK4=; b=HC4rJVVFUDUV4j5MtIjBrtY4IHJQx3NnKkMF0VVc3ScP/niMb/TB77lSEtK2lN4EUQ U+WZO4v/EAbJIOP4yY5Tf8BLLJdbHvfvop3T0cU7LVXPeftAY++TBqpbg1fUJlBiIw3r 6FBAxoFx0T/xPDQV8cyfeU7z4hgRCvLxAe2fw= 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; bh=MMfiVomnNWK4CWwShYihrHiuqIuM+lEQaSd5JFHNcK4=; b=QqY/6tueJ431fsIeE8uBHDeGndySEZf8iubrI+FlfYbDeXJz/qKALd+aKxKowFX6jN aIZO8UOF4Q4zeNyid8ABJV46IYh+eA2Fz0otVcfnQs9uZX/Y63BzjA0G5N3BanMjKIxc Go7aIroDwy/tDXRT73OM7zgrqJe5uf7hJ0FkAbyZL5VGzI/8DAttkDXYbckVek0z81g+ pxCXaFIUKJyU2DmEKAl/VRpMt4Rx61qAXe63jTzwLQAdeoZwefbyn0/23n7zY925uGkJ p91KXOxMpEb4Upq89jOWyO+A4aK7nz/9W0uGRal1hWgGH5HWfPEWxmAVdSwlwfW1/OwL pXfg== X-Gm-Message-State: AKaTC01vWjt93A5MDAiopGhDx2F7qlNbxtROMEr2xGDPCtfVBg6D4dGtDEZVXbcEkDest/3C X-Received: by 10.84.128.65 with SMTP id 59mr78969280pla.109.1480549859053; Wed, 30 Nov 2016 15:50:59 -0800 (PST) Received: from dhdang-workstation-01.amcc.com ([206.80.4.98]) by smtp.gmail.com with ESMTPSA id a22sm105383811pfg.7.2016.11.30.15.50.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 30 Nov 2016 15:50:58 -0800 (PST) From: Duc Dang To: Bjorn Helgaas Subject: [PATCH v3] PCI/ACPI: xgene: Add ECAM quirk for X-Gene PCIe controller Date: Wed, 30 Nov 2016 15:42:53 -0800 Message-Id: <1480549373-2123-1-git-send-email-dhdang@apm.com> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161130_155121_531304_374144E3 X-CRM114-Status: GOOD ( 17.94 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Lorenzo Pieralisi , Jon Masters , Arnd Bergmann , Rafael Wysocki , linux-pci@vger.kernel.org, Duc Dang , patches , Linux Kernel Mailing List , Mark Salter , Tomasz Nowicki , linux-arm MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.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. 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). The quirk declares the X-Gene PCIe controller register space as 64KB fixed memory resource with name "PCIe CSR". This name will be showed next to the resource range in the output of "cat /proc/iomem". Signed-off-by: Duc Dang --- v3: - Rebase on top of pci/ecam-v6 tree. - Use DEFINE_RES_MEM_NAMED to declare controller register space with name "PCIe CSR" v2: RFC v2: https://patchwork.ozlabs.org/patch/686846/ v1: RFC v1: https://patchwork.kernel.org/patch/9337115/ drivers/acpi/pci_mcfg.c | 31 ++++++++ drivers/pci/host/pci-xgene.c | 165 ++++++++++++++++++++++++++++++++++++++++++- include/linux/pci-ecam.h | 7 ++ 3 files changed, 200 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index ac21db3..eb6125b 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -57,6 +57,37 @@ struct mcfg_fixup { { "QCOM ", "QDF2432 ", 1, 5, MCFG_BUS_ANY, &pci_32b_ops }, { "QCOM ", "QDF2432 ", 1, 6, MCFG_BUS_ANY, &pci_32b_ops }, { "QCOM ", "QDF2432 ", 1, 7, MCFG_BUS_ANY, &pci_32b_ops }, + +#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..43d7c69 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_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"), + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"), + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"), + [3] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"), + [4] = DEFINE_RES_MEM_NAMED(0x1f510000UL, SZ_64K, "PCIe CSR"), +}; + +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_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"), + [1] = DEFINE_RES_MEM_NAMED(0x1f2c0000UL, SZ_64K, "PCIe CSR"), +}; + +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_NAMED(0x1f2b0000UL, SZ_64K, "PCIe CSR"), + [1] = DEFINE_RES_MEM_NAMED(0x1f500000UL, SZ_64K, "PCIe CSR"), + [2] = DEFINE_RES_MEM_NAMED(0x1f2d0000UL, SZ_64K, "PCIe CSR"), +}; + +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 f5740b7..47ab947 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -62,6 +62,13 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, /* ops for buggy ECAM that supports only 32-bit accesses */ extern struct pci_ecam_ops pci_32b_ops; +/* ECAM ops for known quirks */ +#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 */ int pci_host_common_probe(struct platform_device *pdev,