From patchwork Tue Jan 5 04:57:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeremy Linton X-Patchwork-Id: 11998131 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4AE4BC433E0 for ; Tue, 5 Jan 2021 05:01:06 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 00FFC227C3 for ; Tue, 5 Jan 2021 05:01:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 00FFC227C3 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:To:From: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner; bh=XLZPPJ12ZGxhWkCnv2x4y24fGGSlaUNgKMRCXXl9IH8=; b=Xz+xKpguSGaWoKtcXq3q1vqy7t CSUn693GFyAnrvBxzU5vgegPghMye7+GpRj0/HdAa2Y3qF0btbrlbRj7sjL6iFLgPVmpH3HaXnL4s 1wyfJaO4ZYvGBvvW/j//wxASPViEv6qtYXPFEdhgkN+F0lmyme50awcDF9o3+RT3vHDaVsv7avjCL pK3cipsnTzCCZbPrzIIhjVKYqC+Ig9hfjLbqvOB+jO33U/H7iDpVdaGVsL2DnvI75sAtNOkH82Qdz jy/ccKn3ov8qkE8SLohZ+8mHRReH8p/WOoVj/cjZ8Sv8HG9amRCzSxe1+kAyNbp1tlq+ND/b39tke A1KV9TMw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kwePr-0008Pc-Ko; Tue, 05 Jan 2021 04:57:55 +0000 Received: from foss.arm.com ([217.140.110.172]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kwePo-0008Mn-Vh for linux-arm-kernel@lists.infradead.org; Tue, 05 Jan 2021 04:57:54 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id CA0FC101E; Mon, 4 Jan 2021 20:57:44 -0800 (PST) Received: from mammon-tx2.austin.arm.com (mammon-tx2.austin.arm.com [10.118.28.62]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id B38243F66E; Mon, 4 Jan 2021 20:57:44 -0800 (PST) From: Jeremy Linton To: linux-arm-kernel@lists.infradead.org, linux-pci@vger.kernel.org Subject: [PATCH] arm64: PCI: Enable SMC conduit Date: Mon, 4 Jan 2021 22:57:35 -0600 Message-Id: <20210105045735.1709825-1-jeremy.linton@arm.com> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210104_235753_122617_E7169806 X-CRM114-Status: GOOD ( 18.65 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mark.rutland@arm.com, lorenzo.pieralisi@arm.com, catalin.marinas@arm.com, linux-kernel@vger.kernel.org, Jeremy Linton , sudeep.holla@arm.com, bhelgaas@google.com, will@kernel.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Given that most arm64 platform's PCI implementations needs quirks to deal with problematic config accesses, this is a good place to apply a firmware abstraction. The ARM PCI SMMCCC spec details a standard SMC conduit designed to provide a simple PCI config accessor. This specification enhances the existing ACPI/PCI abstraction and expects power, config, etc functionality is handled by the platform. It also is very explicit that the resulting config space registers must behave as is specified by the pci specification. Lets hook the normal ACPI/PCI config path, and when we detect missing MADT data, attempt to probe the SMC conduit. If the conduit exists and responds for the requested segment number (provided by the ACPI namespace) attach a custom pci_ecam_ops which redirects all config read/write requests to the firmware. This patch is based on the Arm PCI Config space access document @ https://developer.arm.com/documentation/den0115/latest Signed-off-by: Jeremy Linton --- arch/arm64/kernel/pci.c | 87 +++++++++++++++++++++++++++++++++++++++ include/linux/arm-smccc.h | 26 ++++++++++++ 2 files changed, 113 insertions(+) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 1006ed2d7c60..56d3773aaa25 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -107,6 +108,90 @@ static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) return status; } +static int smccc_pcie_check_conduit(u16 seg) +{ + struct arm_smccc_res res; + + if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) + return -EOPNOTSUPP; + + arm_smccc_smc(SMCCC_PCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + if ((int)res.a0 < 0) + return -EOPNOTSUPP; + + arm_smccc_smc(SMCCC_PCI_SEG_INFO, seg, 0, 0, 0, 0, 0, 0, &res); + if ((int)res.a0 < 0) + return -EOPNOTSUPP; + + pr_info("PCI: SMC conduit attached to segment %d\n", seg); + + return 0; +} + +static int smccc_pcie_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct arm_smccc_res res; + + devfn |= bus->number << 8; + devfn |= bus->domain_nr << 16; + + arm_smccc_smc(SMCCC_PCI_READ, devfn, where, size, 0, 0, 0, 0, &res); + if (res.a0) { + *val = ~0; + return -PCIBIOS_BAD_REGISTER_NUMBER; + } + + *val = res.a1; + return PCIBIOS_SUCCESSFUL; +} + +static int smccc_pcie_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + struct arm_smccc_res res; + + devfn |= bus->number << 8; + devfn |= bus->domain_nr << 16; + + arm_smccc_smc(SMCCC_PCI_WRITE, devfn, where, size, val, 0, 0, 0, &res); + if (res.a0) + return -PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + +static const struct pci_ecam_ops smccc_pcie_ecam_ops = { + .bus_shift = 8, + .pci_ops = { + .read = smccc_pcie_config_read, + .write = smccc_pcie_config_write, + } +}; + +static struct pci_config_window * +pci_acpi_setup_smccc_mapping(struct acpi_pci_root *root) +{ + struct device *dev = &root->device->dev; + struct resource *bus_res = &root->secondary; + struct pci_config_window *cfg; + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return ERR_PTR(-ENOMEM); + + cfg->parent = dev; + cfg->ops = &smccc_pcie_ecam_ops; + cfg->busr.start = bus_res->start; + cfg->busr.end = bus_res->end; + cfg->busr.flags = IORESOURCE_BUS; + + cfg->res.name = "PCI SMCCC"; + if (cfg->ops->init) + cfg->ops->init(cfg); + return cfg; +} + /* * Lookup the bus range for the domain in MCFG, and set up config space * mapping. @@ -125,6 +210,8 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); if (ret) { + if (!smccc_pcie_check_conduit(seg)) + return pci_acpi_setup_smccc_mapping(root); dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res); return NULL; } diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index f860645f6512..327f52533c71 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -89,6 +89,32 @@ #define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1 +/* PCI ECAM conduit */ +#define SMCCC_PCI_VERSION \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, 0x0130) + +#define SMCCC_PCI_FEATURES \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, 0x0131) + +#define SMCCC_PCI_READ \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, 0x0132) + +#define SMCCC_PCI_WRITE \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, 0x0133) + +#define SMCCC_PCI_SEG_INFO \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + ARM_SMCCC_OWNER_STANDARD, 0x0134) + /* Paravirtualised time calls (defined by ARM DEN0057A) */ #define ARM_SMCCC_HV_PV_TIME_FEATURES \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \