From mboxrd@z Thu Jan 1 00:00:00 1970 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=-15.5 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_SANE_1 autolearn=ham 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 9EE01C433E0 for ; Thu, 14 Jan 2021 17:57:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 68F3123B4B for ; Thu, 14 Jan 2021 17:57:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728389AbhANR5A (ORCPT ); Thu, 14 Jan 2021 12:57:00 -0500 Received: from foss.arm.com ([217.140.110.172]:53928 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726428AbhANR47 (ORCPT ); Thu, 14 Jan 2021 12:56:59 -0500 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 B9605D6E; Thu, 14 Jan 2021 09:56:13 -0800 (PST) Received: from [192.168.122.166] (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0D7C63F70D; Thu, 14 Jan 2021 09:56:13 -0800 (PST) Subject: Re: [PATCH v2] arm64: PCI: Enable SMC conduit To: linux-arm-kernel@lists.infradead.org Cc: catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com, lorenzo.pieralisi@arm.com, sudeep.holla@arm.com, bhelgaas@google.com, robh@kernel.org, vidyas@nvidia.com, linux-kernel@vger.kernel.org References: <20210113224054.1769514-1-jeremy.linton@arm.com> From: Jeremy Linton Message-ID: <84072c8c-ec38-5d78-62d0-ba8524cffc8f@arm.com> Date: Thu, 14 Jan 2021 11:56:08 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.6.0 MIME-Version: 1.0 In-Reply-To: <20210113224054.1769514-1-jeremy.linton@arm.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi, Since I don't have a cover letter I forgot the changes list. V1->V2: Add SMC_PCI_FEATURES calls to verify _READ, _WRITE and _SEG_INFO functions exist. Add a _SEG_INFO bus start, end validation against the ACPI table. Adjust some function naming, and log messages. On 1/13/21 4:40 PM, Jeremy Linton wrote: > 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 ++++++++++++++++++++++++++++++++++++++ > include/linux/arm-smccc.h | 29 ++++++++++ > 2 files changed, 138 insertions(+) > > diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c > index 1006ed2d7c60..bcbca70ef219 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,112 @@ static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) > return status; > } > > +static int smccc_pcie_has_conduit(void) > +{ > + 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_FEATURES, > + SMCCC_PCI_WRITE, 0, 0, 0, 0, 0, 0, &res); > + if ((int)res.a0 < 0) > + return -EOPNOTSUPP; > + > + arm_smccc_smc(SMCCC_PCI_FEATURES, > + SMCCC_PCI_READ, 0, 0, 0, 0, 0, 0, &res); > + if ((int)res.a0 < 0) > + return -EOPNOTSUPP; > + > + arm_smccc_smc(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_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_ops = { > + .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 arm_smccc_res res; > + struct resource *bus_res = &root->secondary; > + struct pci_config_window *cfg; > + u16 seg = root->segment; > + > + arm_smccc_smc(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 = bus_res->start; > + cfg->busr.end = bus_res->end; > + 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. > @@ -125,6 +232,8 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) > > ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); > if (ret) { > + if (!smccc_pcie_has_conduit()) > + 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..a1a8fe0ea5aa 100644 > --- a/include/linux/arm-smccc.h > +++ b/include/linux/arm-smccc.h > @@ -89,6 +89,35 @@ > > #define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1 > > +/* PCI ECAM conduit (defined by ARM DEN0115A) */ > +#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) > + > +#define SMCCC_PCI_SEG_INFO_START_BUS GENMASK(7, 0) > +#define SMCCC_PCI_SEG_INFO_END_BUS GENMASK(15, 8) > + > /* Paravirtualised time calls (defined by ARM DEN0057A) */ > #define ARM_SMCCC_HV_PV_TIME_FEATURES \ > ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ >