From patchwork Tue Nov 15 09:14:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 694918 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 3tJ1yB1jqNz9t26 for ; Tue, 15 Nov 2016 20:17:54 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=semihalf-com.20150623.gappssmtp.com header.i=@semihalf-com.20150623.gappssmtp.com header.b="IiRuUdKl"; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966389AbcKOJRc (ORCPT ); Tue, 15 Nov 2016 04:17:32 -0500 Received: from mail-qt0-f176.google.com ([209.85.216.176]:33232 "EHLO mail-qt0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965934AbcKOJRC (ORCPT ); Tue, 15 Nov 2016 04:17:02 -0500 Received: by mail-qt0-f176.google.com with SMTP id p16so64440701qta.0 for ; Tue, 15 Nov 2016 01:17:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=semihalf-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=9ixGCf40ReYyt98uqq+UHNTMRQKkMlifGRgWMMtbDNU=; b=IiRuUdKlvr8zL9hwseuS9+Se3AdIIvHFR/J+p6D3DJsGTaE0c62Zca//WNXLJcB+Px 6ukWVztQwjnixdwdXzPsoCTV+4jOYkzyjzzONJUkXgzSLOnljCTrAlrWNizrBqfeYB31 78J1hOdLgpzhbgilRhNJkv9vadXisyrZGYxgjO4ltGsqKbFbGCOSjB35cn9OjfF0LmDD lTtcLOQfLuDQ1JD/3/eGXfXS39YMw8TxeQny9Edm8Q94XRm0DGPMatUhuSJN6Ms0ftvv drDWaAnbILGh2zO0eMTPDHmDP7dfwxOyPxAD+isNoWrgkPcNSjmH78iVprsTLvfNTVuO zbGQ== 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=9ixGCf40ReYyt98uqq+UHNTMRQKkMlifGRgWMMtbDNU=; b=HZrk9Dz7YO36bwvn+/zAMB/n7dEhhHDYg5VCNc3yZrvTPgp0tjvWOGGq1KW98cld62 PepS/IcK5hI2RUKrclY95arwm0vOpr/kJExZ2T7IhQbAb6xw7ER2UlGXHuSkJYpv8vRP RuSfqwJGNNxF1uHVhDKwwV+5SHQ5PtpK/qIGOC8h2HkZYGGuOMI8iSDcrwH0bvNNOriL K4TdPr7AuLc71XdUhpxjJ6+VKN8W0MqApxrYIGs3CVABSpFfcTFCzkSiowjVI0t7cNQv I/rD55kGaf3NloIEwoJoZ6kOWT6PwHQ9uZxgYS+ZhtQaBg+Cvlo6O09QzV+cNPf75dV2 W1qA== X-Gm-Message-State: ABUngvc1rtUb8vI5Nz9s7RU7nEgp8Yk8HWxeyvJc4fqXlgKqGsAVlQxQamD8SsrsBBisjQ== X-Received: by 10.25.208.14 with SMTP id h14mr10100213lfg.73.1479201420888; Tue, 15 Nov 2016 01:17:00 -0800 (PST) Received: from tn-desktop.semihalf.local (31-172-191-173.noc.fibertech.net.pl. [31.172.191.173]) by smtp.gmail.com with ESMTPSA id 31sm6128287lfv.21.2016.11.15.01.16.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 15 Nov 2016 01:17:00 -0800 (PST) From: Tomasz Nowicki To: helgaas@kernel.org, will.deacon@arm.com, catalin.marinas@arm.com, rafael@kernel.org, Lorenzo.Pieralisi@arm.com Cc: arnd@arndb.de, jchandra@broadcom.com, ard.biesheuvel@linaro.org, robert.richter@caviumnetworks.com, mw@semihalf.com, ddaney@caviumnetworks.com, linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linaro-acpi@lists.linaro.org, andrea.gallo@linaro.org, jeremy.linton@arm.com, liudongdong3@huawei.com, gabriele.paoloni@huawei.com, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, jcm@redhat.com, msalter@redhat.com, Tomasz Nowicki Subject: [PATCH V1 1/2] PCI: thunder: Enable ACPI PCI controller for ThunderX pass2.x silicon version Date: Tue, 15 Nov 2016 10:14:57 +0100 Message-Id: <1479201298-25494-2-git-send-email-tn@semihalf.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1479201298-25494-1-git-send-email-tn@semihalf.com> References: <1479201298-25494-1-git-send-email-tn@semihalf.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org ThunderX PCIe controller to off-chip devices (so-called PEM) is not fully compliant with ECAM standard. It uses non-standard configuration space accessors (see pci_thunder_pem_ops) and custom configuration space granulation (see bus_shift = 24). In order to access configuration space and probe PEM as ACPI based PCI host controller we need to add MCFG quirk infrastructure. This involves: 1. thunder_pem_init() ACPI extension so that we can probe PEM-specific register ranges analogously to DT 2. Export PEM pci_thunder_pem_ops structure so it is visible to MCFG quirk code. 3. New quirk entries for each PEM segment. Each contains platform IDs, mentioned pci_thunder_pem_ops and CFG resources. Quirk is considered for ThunderX silicon pass2.x only which is identified via MCFG revision 1. Signed-off-by: Tomasz Nowicki --- drivers/acpi/pci_mcfg.c | 20 +++++++ drivers/pci/host/pci-thunder-pem.c | 107 ++++++++++++++++++++++++++++++++----- include/linux/pci-ecam.h | 4 ++ 3 files changed, 117 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index ac21db3..e4e2b9b 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -57,6 +57,26 @@ static struct mcfg_fixup mcfg_quirks[] = { { "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_HOST_THUNDER_PEM +#define THUNDER_MCFG_RES(addr, node) \ + DEFINE_RES_MEM(addr + (node << 44), 0x39 * SZ_16M) +#define THUNDER_MCFG_QUIRK(rev, node) \ + { "CAVIUM", "THUNDERX", rev, 4 + (10 * node), MCFG_BUS_ANY, \ + &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x88001f000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 5 + (10 * node), MCFG_BUS_ANY, \ + &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x884057000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 6 + (10 * node), MCFG_BUS_ANY, \ + &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x88808f000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 7 + (10 * node), MCFG_BUS_ANY, \ + &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x89001f000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 8 + (10 * node), MCFG_BUS_ANY, \ + &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x894057000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 9 + (10 * node), MCFG_BUS_ANY, \ + &pci_thunder_pem_ops, THUNDER_MCFG_RES(0x89808f000000UL, node) } + /* SoC pass2.x */ + THUNDER_MCFG_QUIRK(1, 0UL), + THUNDER_MCFG_QUIRK(1, 1UL), +#endif }; static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index 6abaf80..7bdc4cd 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -284,6 +285,84 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn, return pci_generic_config_write(bus, devfn, where, size, val); } +#ifdef CONFIG_ACPI + +/* + * Retrieve PEM bridge register base and size from PNP0C02 sub-device under + * the RC. + * + * Device (RES0) + * { + * Name (_HID, "THRX0002") + * Name (_CID, "PNP0C02") + * Name (_CRS, ResourceTemplate () { + * // Device specific registers range + * QWordMemory(ResourceConsumer, PosDecode, MinFixed, + * MaxFixed, Cacheable, ReadWrite, 0, + * 0x87e0c2000000, 0x87E0C2FFFFFF, 0, 0x1000000) + * }) + * } + */ + +static const struct acpi_device_id thunder_pem_reg_ids[] = { + {"THRX0002", 0}, + {"", 0}, +}; + +static struct resource *thunder_pem_acpi_res(struct pci_config_window *cfg) +{ + struct device *dev = cfg->parent; + struct acpi_device *adev = to_acpi_device(dev); + struct acpi_device *child_adev; + struct resource *res_pem; + + res_pem = devm_kzalloc(dev, sizeof(*res_pem), GFP_KERNEL); + if (!res_pem) { + dev_err(dev, "failed to allocate PEM resource\n"); + return NULL; + } + + list_for_each_entry(child_adev, &adev->children, node) { + struct resource_entry *entry; + struct list_head list; + unsigned long flags; + int ret; + + ret = acpi_match_device_ids(child_adev, thunder_pem_reg_ids); + if (ret) + continue; + + INIT_LIST_HEAD(&list); + flags = IORESOURCE_MEM; + ret = acpi_dev_get_resources(child_adev, &list, + acpi_dev_filter_resource_type_cb, + (void *)flags); + if (ret < 0) { + dev_err(&child_adev->dev, + "failed to parse _CRS method, error code %d\n", + ret); + return NULL; + } else if (ret == 0) { + dev_err(&child_adev->dev, + "no memory resources present in _CRS\n"); + return NULL; + } + + entry = list_first_entry(&list, struct resource_entry, node); + *res_pem = *entry->res; + acpi_dev_free_resource_list(&list); + return res_pem; + } + + return NULL; +} +#else +static struct resource *thunder_pem_acpi_res(struct pci_config_window *cfg) +{ + return NULL; +} +#endif + static int thunder_pem_init(struct pci_config_window *cfg) { struct device *dev = cfg->parent; @@ -292,24 +371,24 @@ static int thunder_pem_init(struct pci_config_window *cfg) struct thunder_pem_pci *pem_pci; struct platform_device *pdev; - /* Only OF support for now */ - if (!dev->of_node) - return -EINVAL; - pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL); if (!pem_pci) return -ENOMEM; - pdev = to_platform_device(dev); - - /* - * The second register range is the PEM bridge to the PCIe - * bus. It has a different config access method than those - * devices behind the bridge. - */ - res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (acpi_disabled) { + pdev = to_platform_device(dev); + + /* + * The second register range is the PEM bridge to the PCIe + * bus. It has a different config access method than those + * devices behind the bridge. + */ + res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + } else { + res_pem = thunder_pem_acpi_res(cfg); + } if (!res_pem) { - dev_err(dev, "missing \"reg[1]\"property\n"); + dev_err(dev, "missing configuration region\n"); return -EINVAL; } @@ -332,7 +411,7 @@ static int thunder_pem_init(struct pci_config_window *cfg) return 0; } -static struct pci_ecam_ops pci_thunder_pem_ops = { +struct pci_ecam_ops pci_thunder_pem_ops = { .bus_shift = 24, .init = thunder_pem_init, .pci_ops = { diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index f5740b7..3f2a98f 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -58,6 +58,10 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, int where); /* default ECAM ops */ extern struct pci_ecam_ops pci_generic_ecam_ops; +/* ECAM ops for known quirks */ +#ifdef CONFIG_PCI_HOST_THUNDER_PEM +extern struct pci_ecam_ops pci_thunder_pem_ops; +#endif /* ops for buggy ECAM that supports only 32-bit accesses */ extern struct pci_ecam_ops pci_32b_ops;