From patchwork Wed Feb 10 01:49:44 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Duc Dang X-Patchwork-Id: 8267911 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 5E0ED9F1C1 for ; Wed, 10 Feb 2016 01:57:52 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5A8DB20270 for ; Wed, 10 Feb 2016 01:57:51 +0000 (UTC) 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.kernel.org (Postfix) with ESMTPS id 5973820263 for ; Wed, 10 Feb 2016 01:57:50 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aTK19-0004w6-GC; Wed, 10 Feb 2016 01:56:31 +0000 Received: from mail-pf0-x234.google.com ([2607:f8b0:400e:c00::234]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1aTK12-0004Qo-Qj for linux-arm-kernel@lists.infradead.org; Wed, 10 Feb 2016 01:56:27 +0000 Received: by mail-pf0-x234.google.com with SMTP id c10so3522629pfc.2 for ; Tue, 09 Feb 2016 17:56:04 -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=X4jMt/pMLcPMEs0as35ny93x14PvLvIcNVikjRBoFl0=; b=Ex0BLlE2McqZExtfPWevC2hd0jE6ZJnAsvJOvH7lHrfyqk5BXO7/a5kylGH4U/qS6f vjBaHbNqR8lU+TQ8WfNyCPrObYU61tPl++6xGacncZq9kHWAPTzdUxQNB3zcrgZ4JKV3 iqPPwGLxumr5r67cQP2sgjBQcLEzRcbvt17ic= 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=X4jMt/pMLcPMEs0as35ny93x14PvLvIcNVikjRBoFl0=; b=MGf7TUlZ0gK5Io32CbTY2SKpDbzNE/IS05Zzlq0P+CTfkOrVXqzVNZZievmyUrLuHZ xEx6GeCjYzwtW+MFaKB4Ge+YkydPAtVY/yzDXUdyy6wiSyfyb0bKkhU63dOMfTuCvF2R n/OAv0Clb+FFiM0mPj8oGHKCWNUWk/vVxw7PnZ+4cTwLbCzbs6DbNC1ou4V/kMUfHC/u 5HnvGhGogRrrBVxlQhIT70XzbiIwBHMjv8SD5J99LctZ6HCF+2zQF0CD5s9nr4rJdvwU /bYpIRIKmE8amJ44iFUCoR4LziG2QdygIF8GmHoZ4vok39Enq6/30raLNACs2RuL9ZG7 XSTQ== X-Gm-Message-State: AG10YOSA+PKZgNPfqNSw0LnYvlqHLMovDIrvD+Q/cjsD94sFthMVrAiakLhBHU+4LN0dVtV8 X-Received: by 10.98.72.202 with SMTP id q71mr54724009pfi.69.1455069363891; Tue, 09 Feb 2016 17:56:03 -0800 (PST) Received: from dhdang-Precision-WorkStation-T3400.amcc.com (70-35-53-82.static.wiline.com. [70.35.53.82]) by smtp.gmail.com with ESMTPSA id e20sm682973pfd.4.2016.02.09.17.56.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 09 Feb 2016 17:56:03 -0800 (PST) From: Duc Dang To: Bjorn Helgaas , Tomasz Nowicki Subject: [PATCH] pci: xgene: Add ECAM fixups Date: Tue, 9 Feb 2016 17:49:44 -0800 Message-Id: <1455068984-22210-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-20160209_175625_049479_1FA087A0 X-CRM114-Status: GOOD ( 16.02 ) X-Spam-Score: -2.7 (--) 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: Feng Kan , linux-pci@vger.kernel.org, Duc Dang , patches@apm.com, linux-kernel@vger.kernel.org, Loc Ho , Mark Salter , linux-arm-kernel@lists.infradead.org, Tanmay Inamdar MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP X-Gene PCIe controller does not fully support ECAM. This patch adds required ECAM fixup to allow X-Gene PCIe controller to be functional in ACPI boot mode. This patch is based on the original work of Mark Salter and depends on Tomasz's PCIe ACPI series: https://lkml.org/lkml/2016/2/4/646 Signed-off-by: Duc Dang --- drivers/pci/host/pci-xgene.c | 130 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 3 deletions(-) diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index ae00ce2..5d3f74e 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -29,6 +29,11 @@ #include #include #include +#ifdef CONFIG_ACPI +#include +#include +#include +#endif #define PCIECORE_CTLANDSTATUS 0x50 #define PIM1_1L 0x80 @@ -76,6 +81,13 @@ struct xgene_pcie_port { u32 version; }; +static struct xgene_pcie_port *(*xgene_pcie_bus_to_port)(struct pci_bus *bus); + +static struct xgene_pcie_port *xgene_pcie_dt_bus_to_port(struct pci_bus *bus) +{ + return bus->sysdata; +} + static inline u32 pcie_bar_low_val(u32 addr, u32 flags) { return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags; @@ -87,7 +99,7 @@ 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 xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); if (bus->number >= (bus->primary + 1)) return port->cfg_base + AXI_EP_CFG_ACCESS; @@ -101,7 +113,7 @@ 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 xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); unsigned int b, d, f; u32 rtdid_val = 0; @@ -148,7 +160,7 @@ 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 xgene_pcie_port *port = xgene_pcie_bus_to_port(bus); if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) != PCIBIOS_SUCCESSFUL) @@ -509,6 +521,116 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port, return 0; } +#ifdef CONFIG_ACPI +#define APM_OEM_ID "APM " +#define APM_XGENE_TABLE_ID "XGENE " +static LIST_HEAD(xgene_acpi_pcie_roots); + +struct xgene_pcie_acpi_root { + struct list_head list; + struct acpi_pci_root *root; + struct xgene_pcie_port port; +}; + +static struct xgene_pcie_port *xgene_pcie_acpi_bus_to_port(struct pci_bus *bus) +{ + struct acpi_pci_root *root = bus->sysdata; + struct xgene_pcie_acpi_root *xgene_root; + + list_for_each_entry(xgene_root, &xgene_acpi_pcie_roots, list) { + if (xgene_root->root == root) + return &xgene_root->port; + } + + return NULL; +} + +static acpi_status xgene_pcie_find_csr_base(struct acpi_resource *acpi_res, + void *data) +{ + struct xgene_pcie_acpi_root *root = data; + struct acpi_resource_fixed_memory32 *fixed32; + + if (acpi_res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { + fixed32 = &acpi_res->data.fixed_memory32; + root->port.csr_base = ioremap(fixed32->address, + fixed32->address_length); + return AE_CTRL_TERMINATE; + } + return AE_OK; +} + +static int xgene_pcie_mcfg_fixup(struct acpi_pci_root *root) +{ + struct pci_mmcfg_region *cfg; + struct acpi_device *device = root->device; + struct xgene_pcie_acpi_root *acpi_root; + + acpi_root = kzalloc(sizeof(*acpi_root), GFP_KERNEL); + if (acpi_root == NULL) + return -ENOMEM; + + INIT_LIST_HEAD(&acpi_root->list); + acpi_root->root = root; + + cfg = pci_mmconfig_lookup(root->segment, root->secondary.start); + if (cfg) + acpi_root->port.cfg_base = cfg->virt; + else { + dev_err(&device->dev, "Failed to get CFG virt base\n"); + return -ENODEV; + } + + acpi_walk_resources(device->handle, METHOD_NAME__CRS, + xgene_pcie_find_csr_base, acpi_root); + + if (!acpi_root->port.csr_base) { + kfree(acpi_root); + return -ENODEV; + } + + /* Update bus_to_port method */ + xgene_pcie_bus_to_port = xgene_pcie_acpi_bus_to_port; + + /* Set to IP version 1 to disable Configuration-Request Retry Status */ + acpi_root->port.version = XGENE_PCIE_IP_VER_1; + + list_add(&acpi_root->list, &xgene_acpi_pcie_roots); + + return 0; +} + +static int xgene_pcie_acpi_match(struct pci_mcfg_fixup *fixup, + struct acpi_pci_root *root) +{ + struct acpi_table_header table_header; + + if (acpi_get_table_header(ACPI_SIG_MCFG, 0, &table_header)) + return 0; + + if (strncmp(APM_OEM_ID, table_header.oem_id, ACPI_OEM_ID_SIZE)) + return 0; + + if (strncmp(APM_XGENE_TABLE_ID, table_header.oem_table_id, + ACPI_OEM_TABLE_ID_SIZE)) + return 0; + + /* + * MCFG table matches with X-Gene PCIe MCFG table. + * Now perform additional fix-up actions to prepare for + * X-Gene PCIe private data. + */ + if (xgene_pcie_mcfg_fixup(root)) + return 0; + + return 1; +} + +DECLARE_ACPI_MCFG_FIXUP(NULL, xgene_pcie_acpi_match, &xgene_pcie_ops, + PCI_MCFG_DOMAIN_ANY, PCI_MCFG_BUS_ANY); + +#endif /* CONFIG_ACPI */ + static int xgene_pcie_probe_bridge(struct platform_device *pdev) { struct device_node *dn = pdev->dev.of_node; @@ -518,6 +640,8 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev) int ret; LIST_HEAD(res); + xgene_pcie_bus_to_port = xgene_pcie_dt_bus_to_port; + port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM;