From patchwork Mon Jul 25 16:39:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeremy Linton X-Patchwork-Id: 12928277 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3F2A7C43334 for ; Mon, 25 Jul 2022 16:40:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=frBGMoYCPYc6BH427dvZ2Wgl8ZfZxqihUjFBoFbwNHc=; b=2ggKGIJ4CSu5i+ Tysi/mmdg1xI8z8BSYeQgH6zcMpSxie3VtGfQX5/fyiPi+949vDjJpv5g0aeLgU6gZcy0JkEL0mUG XEGArx8lK6bKLEqTAngmrJJS67kx5yORgBJ6RfuuJRXGCSs/XGgikDWb63auxzMjPxIPsKGu0UUhi QxrczzFW+TT9f0vsNcx0DShBeVQiHyicEPuOd5O5+imybDYYi8HitLBbDhU4gixNzwXrnLUaqi6GP nGOaToIDRoxyOmNmIhAwj1XF1DYobcw0gCKNBleo6XBgII71n6masoFU5oQ0emLFI/sefj62TPZLW 697k2Ib7V9fvAZ4BIurQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oG17Q-00FiG0-M6; Mon, 25 Jul 2022 16:39:44 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1oG16x-00Fi2d-5J for linux-arm-kernel@lists.infradead.org; Mon, 25 Jul 2022 16:39:19 +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 E1666139F; Mon, 25 Jul 2022 09:39:13 -0700 (PDT) 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 2424C3F73D; Mon, 25 Jul 2022 09:39:13 -0700 (PDT) From: Jeremy Linton To: linux-pci@vger.kernel.org Cc: will@kernel.org, bhelgaas@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, lpieralisi@kernel.org, kw@linux.com, mark.rutland@arm.com, sudeep.holla@arm.com, boqun.feng@gmail.com, catalin.marinas@arm.com, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Jeremy Linton Subject: [PATCH 2/4] arm64: PCI: Enable SMC conduit Date: Mon, 25 Jul 2022 11:39:03 -0500 Message-Id: <20220725163905.2024437-3-jeremy.linton@arm.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20220725163905.2024437-1-jeremy.linton@arm.com> References: <20220725163905.2024437-1-jeremy.linton@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220725_093915_330250_0141EF80 X-CRM114-Status: GOOD ( 15.38 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Given that most arm64 platforms' PCI implementations need quirks to deal with problematic config accesses, this is a good place to apply a firmware abstraction. The ARM PCI Configuration Space Access Firmware Interface specification 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., 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. Hook the ACPI/PCI config path, and when missing MCFG data is detected, attempt to probe the SMC conduit. If the conduit exists and responds to the requested segment, provided by the ACPI namespace, attach a custom pci_ecam_ops which redirects all config read/write requests to the firmware. The Arm PCI Configuration Space Access Firmware Interface: https://developer.arm.com/documentation/den0115/latest Signed-off-by: Jeremy Linton --- arch/arm64/kernel/pci.c | 109 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 2276689b5411..beb4289a7471 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -122,6 +123,112 @@ static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) return status; } +int pcie_has_fw_conduit(void) +{ + struct arm_smccc_res res; + + if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) + return -EOPNOTSUPP; + + arm_smccc_1_1_invoke(SMCCC_PCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + if ((int)res.a0 < 0) + return -EOPNOTSUPP; + + arm_smccc_1_1_invoke(SMCCC_PCI_FEATURES, + SMCCC_PCI_WRITE, 0, 0, 0, 0, 0, 0, &res); + if ((int)res.a0 < 0) + return -EOPNOTSUPP; + + arm_smccc_1_1_invoke(SMCCC_PCI_FEATURES, + SMCCC_PCI_READ, 0, 0, 0, 0, 0, 0, &res); + if ((int)res.a0 < 0) + return -EOPNOTSUPP; + + arm_smccc_1_1_invoke(SMCCC_PCI_FEATURES, + SMCCC_PCI_SEG_INFO, 0, 0, 0, 0, 0, 0, &res); + if ((int)res.a0 < 0) + return -EOPNOTSUPP; + + 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_1_1_invoke(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_1_1_invoke(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_ops = { + .pci_ops = { + .read = smccc_pcie_config_read, + .write = smccc_pcie_config_write, + } +}; + + +struct pci_config_window * +pci_setup_fw_mapping(struct device *dev, u16 seg, struct resource *bus_res) +{ + struct arm_smccc_res res; + struct pci_config_window *cfg; + + arm_smccc_1_1_invoke(SMCCC_PCI_SEG_INFO, seg, 0, 0, 0, 0, 0, 0, &res); + if ((int)res.a0 < 0) { + pr_warn("PCI: SMC segment %d doesn't exist\n", seg); + return NULL; + } + + if (FIELD_GET(SMCCC_PCI_SEG_INFO_START_BUS, res.a1) != bus_res->start || + FIELD_GET(SMCCC_PCI_SEG_INFO_END_BUS, res.a1) != bus_res->end) { + pr_warn("PCI: SMC segment %d doesn't match ACPI description\n", seg); + return NULL; + } + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return NULL; + + cfg->parent = dev; + cfg->ops = &smccc_pcie_ops; + cfg->busr.start = FIELD_GET(SMCCC_PCI_SEG_INFO_START_BUS, res.a1); + cfg->busr.end = FIELD_GET(SMCCC_PCI_SEG_INFO_END_BUS, res.a1); + cfg->busr.flags = IORESOURCE_BUS; + cfg->res.name = "PCI SMCCC"; + + pr_info("PCI: SMC conduit attached to segment %d\n", seg); + + return cfg; +} + /* * Lookup the bus range for the domain in MCFG, and set up config space * mapping. @@ -140,6 +247,8 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); if (ret) { + if (!pcie_has_fw_conduit()) + return pci_setup_fw_mapping(dev, seg, bus_res); dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res); return NULL; }