From patchwork Mon May 30 15:14:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 9141637 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2307960777 for ; Mon, 30 May 2016 15:15:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 12FC028185 for ; Mon, 30 May 2016 15:15:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0738928222; Mon, 30 May 2016 15:15:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7A47B28185 for ; Mon, 30 May 2016 15:15:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933484AbcE3PPl (ORCPT ); Mon, 30 May 2016 11:15:41 -0400 Received: from mail-lf0-f52.google.com ([209.85.215.52]:36720 "EHLO mail-lf0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933158AbcE3PPj (ORCPT ); Mon, 30 May 2016 11:15:39 -0400 Received: by mail-lf0-f52.google.com with SMTP id b73so51436546lfb.3 for ; Mon, 30 May 2016 08:15:33 -0700 (PDT) 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=fXQyUqrbZGJpPLJPvBqK7ijV/Mxs3Z0F6BNNHOvYf44=; b=hd5Nj8gDJhwFREA5e5aPOKv+TVLz5ARRS56lsUTSeEcMfVcPClEAG9094WCRfyjB4S hd+ae2zE0Gq80FOdhV9NexiWNVsYf8qBrSQl9XhmePbwwoISHZ//xLA0Gbbs4H1WqU0R Wp9ySvL75mEnoc+QQEfAJxtdRRWXwCzlPD38QSJ2Ew/vcsPL/KQpUzZf53Y/E3dxZEDe vnsme+VF/pW3B1novWeBC1c63GeC8VBZ8WFGR8rrQ+pirK/ZIaszpEgNWMY3F98JCZji ymaDjpjdhd7PT9/bqLCD85xCGkQ5A8iimnVB3AOOnqWaP3YEkgNbA3DG/CBPFbn4xp+b V/aw== 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=fXQyUqrbZGJpPLJPvBqK7ijV/Mxs3Z0F6BNNHOvYf44=; b=WnKpiXNfFyyZ+n13O257HgkN8HL/S99NigKH5zn2zmHB8RV1l26AUg77EFKcC9Ap0E T/ygyx6hrB+RtlvuEdQiH75ozJvZCGth5Q96SmZnHlIu0XpWMCQznkqpvK+ex1g0MHpW ykBJTg8xUlWMn1dW5uMMaUBygIa6gteGZZg1fw/MNk7japSwxhHa1PU32wnIYvHuI74H wk5Wh+klwwf7PBz0FhVq/H/OTg+4U/kCP/zzK6/W7ZQVx6huq3m9nx/RW3JI7G6czCVY a/ZFm9+2IFc9ShAK8lqxJxUPuNX+7kHWRCgnbcazxvJsSmffZ6EhhEIBybzHcN1qR/1p RvEA== X-Gm-Message-State: ALyK8tLJuMia+1ovlzsaCVsrRpIoK/LcviYxj2fQs1AKfJDnVgrYFHQtPxmOfQkFME+ztQ== X-Received: by 10.25.40.144 with SMTP id o138mr7320906lfo.160.1464621316926; Mon, 30 May 2016 08:15:16 -0700 (PDT) Received: from tn-HP-4.semihalf.local (31-172-191-173.noc.fibertech.net.pl. [31.172.191.173]) by smtp.gmail.com with ESMTPSA id n13sm1392264lfb.33.2016.05.30.08.15.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 30 May 2016 08:15:16 -0700 (PDT) From: Tomasz Nowicki To: helgaas@kernel.org, arnd@arndb.de, will.deacon@arm.com, catalin.marinas@arm.com, rafael@kernel.org, hanjun.guo@linaro.org, Lorenzo.Pieralisi@arm.com, okaya@codeaurora.org, jchandra@broadcom.com Cc: robert.richter@caviumnetworks.com, mw@semihalf.com, Liviu.Dudau@arm.com, ddaney@caviumnetworks.com, wangyijing@huawei.com, Suravee.Suthikulpanit@amd.com, msalter@redhat.com, linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org, linaro-acpi@lists.linaro.org, jcm@redhat.com, andrea.gallo@linaro.org, dhdang@apm.com, jeremy.linton@arm.com, liudongdong3@huawei.com, cov@codeaurora.org, Tomasz Nowicki Subject: [PATCH V8 9/9] pci, acpi: ARM64 support for ACPI based generic PCI host controller Date: Mon, 30 May 2016 17:14:22 +0200 Message-Id: <1464621262-26770-10-git-send-email-tn@semihalf.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1464621262-26770-1-git-send-email-tn@semihalf.com> References: <1464621262-26770-1-git-send-email-tn@semihalf.com> Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch implements pci_acpi_scan_root call so that ARM64 can start using ACPI to setup and enumerate PCI buses. The implementation of pci_acpi_scan_root() looks up config space regions through MCFG interface. Then ECAM library is doing a new mapping and attach generic ECAM ops which are used for accessing config space. On ARM64, ACPI and DT can be enabled together, and in that case we need to use generic domains. In order to do that we implement ARM64 specific way of retrieving domain number from pci_config_window structure. Since we enable PCI for ACPI we need to implement raw_pci_{read|write} at the same time. ARM64 provides RAW accessors as long as there is correlated valid pci_bus structure, but not before. Signed-off-by: Tomasz Nowicki Signed-off-by: Jayachandran C Reviewed-by: Lorenzo Pieralisi --- arch/arm64/Kconfig | 2 + arch/arm64/kernel/pci.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++-- include/linux/pci.h | 5 ++ 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 76747d9..87c48ad 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -3,6 +3,7 @@ config ARM64 select ACPI_CCA_REQUIRED if ACPI select ACPI_GENERIC_GSI if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI + select ACPI_MCFG if ACPI select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ELF_RANDOMIZE @@ -96,6 +97,7 @@ config ARM64 select OF_EARLY_FLATTREE select OF_NUMA if NUMA && OF select OF_RESERVED_MEM + select PCI_ECAM if ACPI select PERF_USE_VMALLOC select POWER_RESET select POWER_SUPPLY diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 3663be1..39f2a40 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #include /* @@ -71,13 +73,21 @@ int pcibios_alloc_irq(struct pci_dev *dev) int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 *val) { - return -ENXIO; + struct pci_bus *b = pci_find_bus(domain, bus); + + if (!b) + return PCIBIOS_DEVICE_NOT_FOUND; + return b->ops->read(b, devfn, reg, len, val); } int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 val) { - return -ENXIO; + struct pci_bus *b = pci_find_bus(domain, bus); + + if (!b) + return PCIBIOS_DEVICE_NOT_FOUND; + return b->ops->write(b, devfn, reg, len, val); } #ifdef CONFIG_NUMA @@ -91,11 +101,111 @@ EXPORT_SYMBOL(pcibus_to_node); #endif #ifdef CONFIG_ACPI -/* Root bridge scanning */ + +struct acpi_pci_generic_root_info { + struct acpi_pci_root_info common; + struct pci_config_window *cfg; /* config space mapping */ +}; + +int acpi_pci_bus_domain_nr(struct pci_bus *bus) +{ + struct pci_config_window *cfg = bus->sysdata; + struct acpi_device *adev = to_acpi_device(cfg->parent); + struct acpi_pci_root *root = acpi_driver_data(adev); + + return root->segment; +} + +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) +{ + if (!acpi_disabled) { + struct pci_config_window *cfg = bridge->bus->sysdata; + struct acpi_device *adev = to_acpi_device(cfg->parent); + ACPI_COMPANION_SET(&bridge->dev, adev); + } + + return 0; +} + +/* + * Lookup the bus range for the domain in MCFG, and set up config space + * mapping. + */ +static int pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root, + struct acpi_pci_generic_root_info *ri) +{ + struct resource *bus_res = &root->secondary; + u16 seg = root->segment; + struct pci_config_window *cfg; + struct resource cfgres; + unsigned int bsz; + int err; + + err = pci_mcfg_lookup(root); + if (err) { + pr_err("%04x:%pR MCFG region not found\n", seg, bus_res); + return err; + } + + bsz = 1 << pci_generic_ecam_ops.bus_shift; + cfgres.start = root->mcfg_addr + bus_res->start * bsz; + cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1; + cfgres.flags = IORESOURCE_MEM; + cfg = pci_ecam_create(&root->device->dev, &cfgres, bus_res, + &pci_generic_ecam_ops); + if (IS_ERR(cfg)) { + pr_err("%04x:%pR error %ld mapping CAM\n", seg, bus_res, + PTR_ERR(cfg)); + return PTR_ERR(cfg); + } + + ri->cfg = cfg; + return 0; +} + +/* release_info: free resrouces allocated by init_info */ +static void pci_acpi_generic_release_info(struct acpi_pci_root_info *ci) +{ + struct acpi_pci_generic_root_info *ri; + + ri = container_of(ci, struct acpi_pci_generic_root_info, common); + pci_ecam_free(ri->cfg); + kfree(ri); +} + +static struct acpi_pci_root_ops acpi_pci_root_ops = { + .release_info = pci_acpi_generic_release_info, +}; + +/* Interface called from ACPI code to setup PCI host controller */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) { - /* TODO: Should be revisited when implementing PCI on ACPI */ - return NULL; + int node = acpi_get_node(root->device->handle); + struct acpi_pci_generic_root_info *ri; + struct pci_bus *bus, *child; + int err; + + ri = kzalloc_node(sizeof(*ri), GFP_KERNEL, node); + if (!ri) + return NULL; + + err = pci_acpi_setup_ecam_mapping(root, ri); + if (err) + return NULL; + + acpi_pci_root_ops.pci_ops = &ri->cfg->ops->pci_ops; + bus = acpi_pci_root_create(root, &acpi_pci_root_ops, &ri->common, + ri->cfg); + if (!bus) + return NULL; + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + + return bus; } void pcibios_add_bus(struct pci_bus *bus) diff --git a/include/linux/pci.h b/include/linux/pci.h index 9661c85..f66d188 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1390,7 +1390,12 @@ static inline int pci_domain_nr(struct pci_bus *bus) { return bus->domain_nr; } +/* Arch specific ACPI hook to set-up domain number */ +#ifdef CONFIG_ACPI +int acpi_pci_bus_domain_nr(struct pci_bus *bus); +#else static inline int acpi_pci_bus_domain_nr(struct pci_bus *bus) { return -1; } +#endif void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent); #else static inline void pci_bus_assign_domain_nr(struct pci_bus *bus,