From patchwork Tue Oct 27 16:38:42 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 7497951 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 70039BEEA4 for ; Tue, 27 Oct 2015 16:40:17 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 47FE72087A for ; Tue, 27 Oct 2015 16:40:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0888420638 for ; Tue, 27 Oct 2015 16:40:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965019AbbJ0Qjy (ORCPT ); Tue, 27 Oct 2015 12:39:54 -0400 Received: from mail-lb0-f172.google.com ([209.85.217.172]:34381 "EHLO mail-lb0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965191AbbJ0Qjf (ORCPT ); Tue, 27 Oct 2015 12:39:35 -0400 Received: by lbbwb3 with SMTP id wb3so68107346lbb.1 for ; Tue, 27 Oct 2015 09:39: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=i9vJ5zfyU/0b76NHolaWGSHR7c8HIOUOHAwlvSM3GR0=; b=otDuuHiA5dVQ+g8ihlDwUJ5BS3k4ULnWEqyLDrGWj46Y/IeY3yJO/8W5PrzhFqnmAX r9F4dsDW1X3J+I6g9QpxUtw43WdStWIlr31y0q6ZNUkcpa3+GYeFHG/vWki0ZLoxCbZz TWSBbC3yhowSZO2wL6kmyOiHtET2PWnDd3u7lrSvLjufWtxhPKkjIXLDbUI+l/zoBwqk 0DBzuc4gJE4+krbLgXksOINkWD6OVpYhu8BDQ0Ga4YvObfEiJv3jhtz4MxhUfZlvMUaa gyNO/+yPVHKBzMyEIaMxE3R18POXngWrte8ksQbcVd/wC8uRmRDXEspbu28mTQA6DmKJ ROgA== 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=i9vJ5zfyU/0b76NHolaWGSHR7c8HIOUOHAwlvSM3GR0=; b=MXecO+lM8V7DgFnkvCEmx/+xb6Xc83vNAJlfuxuDAKnV7LGl8vwfsOU/AaIWwpMgN4 MderdedoqM5r4PRtyAUEndTOsxwJoZUFmPHvXoRnmBj1ROENVot0wtILEWDNyqK6ShMM H/vt+LQQANT0UCopnbGOLe+aZ5lJn4Te4XUK7Ee3oZWfztxmc0rXwPpn2CHWs/m36NAd F4ijRMxET2psPqvPrPYJe9aJvZQauaaOt83wfOJbhU45sq8VPTgdeAY3SyjI7w3sNkQj +RjDj3m2x9u/Nv28uU2tSVUUMhhRIZ3Er9wi0qf+PLIa3+wONsWocEYEHaiWZRP6NlKo Xm+w== X-Gm-Message-State: ALoCoQl/W2vsiVaIYCe605CPdpBG+5bcZ/ZzWYOuIK+lNBnacvjISm3wHdsDl+fu//hizgC4s+Eo X-Received: by 10.112.146.104 with SMTP id tb8mr20977915lbb.35.1445963973829; Tue, 27 Oct 2015 09:39:33 -0700 (PDT) Received: from tn-HP-4.semihalf.local ([80.82.22.190]) by smtp.gmail.com with ESMTPSA id kk6sm6988609lbc.48.2015.10.27.09.39.32 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 27 Oct 2015 09:39:33 -0700 (PDT) From: Tomasz Nowicki To: bhelgaas@google.com, arnd@arndb.de, will.deacon@arm.com, catalin.marinas@arm.com, rjw@rjwysocki.net, hanjun.guo@linaro.org, Lorenzo.Pieralisi@arm.com Cc: jiang.liu@linux.intel.com, robert.richter@caviumnetworks.com, Narinder.Dhillon@caviumnetworks.com, ddaney@caviumnetworks.com, Liviu.Dudau@arm.com, tglx@linutronix.de, 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, Tomasz Nowicki Subject: [PATCH V1 11/11] arm64, pci, acpi: Support for ACPI based PCI hostbridge init Date: Tue, 27 Oct 2015 17:38:42 +0100 Message-Id: <1445963922-22711-12-git-send-email-tn@semihalf.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1445963922-22711-1-git-send-email-tn@semihalf.com> References: <1445963922-22711-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 X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Because of two patch series: 1. Jiang Liu's common interface to support PCI host bridge init 2. Refactoring of MMCONFIG, part of this patch set now we can think about PCI buses enumeration for ARM64 and ACPI tables. This patch introduce ACPI based PCI hostbridge init calls which use information from MCFG table (PCI config space regions) and _CRS (IO/irq resources) to initialize PCI hostbridge. Signed-off-by: Tomasz Nowicki Signed-off-by: Hanjun Guo Signed-off-by: Suravee Suthikulpanit CC: Arnd Bergmann CC: Catalin Marinas CC: Liviu Dudau CC: Lorenzo Pieralisi CC: Will Deacon --- arch/arm64/Kconfig | 6 ++ arch/arm64/kernel/pci.c | 208 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 202 insertions(+), 12 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 07d1811..bbcc6b1 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -89,6 +89,7 @@ config ARM64 select SPARSE_IRQ select SYSCTL_EXCEPTION_TRACE select HAVE_CONTEXT_TRACKING + select HAVE_PCI_ECAM help ARM 64-bit (AArch64) Linux support. @@ -202,6 +203,11 @@ source "drivers/pci/Kconfig" source "drivers/pci/pcie/Kconfig" source "drivers/pci/hotplug/Kconfig" +config PCI_MMCONFIG + def_bool y + select PCI_ECAM + depends on ACPI + endmenu menu "Kernel Features" diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index b3d098b..66cc1ae 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -11,12 +11,15 @@ */ #include +#include #include #include #include #include +#include #include #include +#include #include #include @@ -52,35 +55,216 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) } /* - * Try to assign the IRQ number from DT when adding a new device + * Try to assign the IRQ number from DT/ACPI when adding a new device */ int pcibios_add_device(struct pci_dev *dev) { - dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); + if (acpi_disabled) + dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); +#ifdef CONFIG_ACPI + else + acpi_pci_irq_enable(dev); +#endif return 0; } +#ifdef CONFIG_ACPI +int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) +{ + struct acpi_pci_root *root = bridge->bus->sysdata; + + ACPI_COMPANION_SET(&bridge->dev, root->device); + return 0; +} + +void pcibios_add_bus(struct pci_bus *bus) +{ + acpi_pci_add_bus(bus); +} + +void pcibios_remove_bus(struct pci_bus *bus) +{ + acpi_pci_remove_bus(bus); +} + +static int __init pcibios_assign_resources(void) +{ + if (acpi_disabled) + return 0; + + pci_assign_unassigned_resources(); + return 0; +} /* - * raw_pci_read/write - Platform-specific PCI config space access. + * rootfs_initcall comes after subsys_initcall and fs_initcall_sync, + * so we know acpi scan and PCI_FIXUP_FINAL quirks have both run. */ -int raw_pci_read(unsigned int domain, unsigned int bus, - unsigned int devfn, int reg, int len, u32 *val) +rootfs_initcall(pcibios_assign_resources); + +static void __iomem * +pci_mcfg_dev_base(struct pci_bus *bus, unsigned int devfn, int offset) { - return -ENXIO; + struct pci_mmcfg_region *cfg; + + cfg = pci_mmconfig_lookup(pci_domain_nr(bus), bus->number); + if (cfg && cfg->virt) + return cfg->virt + + (PCI_MMCFG_BUS_OFFSET(bus->number) | (devfn << 12)) + + offset; + return NULL; } -int raw_pci_write(unsigned int domain, unsigned int bus, - unsigned int devfn, int reg, int len, u32 val) +struct pci_ops pci_root_ops = { + .map_bus = pci_mcfg_dev_base, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; + +#ifdef CONFIG_PCI_MMCONFIG +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci) { - return -ENXIO; + struct pci_mmcfg_region *cfg; + struct acpi_pci_root *root; + int seg, start, end, err; + + root = ci->root; + seg = root->segment; + start = root->secondary.start; + end = root->secondary.end; + + cfg = pci_mmconfig_lookup(seg, start); + if (cfg) + return 0; + + cfg = pci_mmconfig_alloc(seg, start, end, root->mcfg_addr); + if (!cfg) + return -ENOMEM; + + err = pci_mmconfig_inject(cfg); + return err; } -#ifdef CONFIG_ACPI +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci) +{ + struct acpi_pci_root *root = ci->root; + struct pci_mmcfg_region *cfg; + + cfg = pci_mmconfig_lookup(root->segment, root->secondary.start); + if (cfg) + return; + + if (cfg->hot_added) + pci_mmconfig_delete(root->segment, root->secondary.start, + root->secondary.end); +} +#else +static int pci_add_mmconfig_region(struct acpi_pci_root_info *ci) +{ + return 0; +} + +static void pci_remove_mmconfig_region(struct acpi_pci_root_info *ci) { } +#endif + +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci) +{ + return pci_add_mmconfig_region(ci); +} + +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci) +{ + pci_remove_mmconfig_region(ci); + kfree(ci); +} + +static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) +{ + struct resource_entry *entry, *tmp; + int ret; + + ret = acpi_pci_probe_root_resources(ci); + if (ret < 0) + return ret; + + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { + struct resource *res = entry->res; + + /* + * Special handling for ARM IO range + * TODO: need to move pci_register_io_range() function out + * of drivers/of/address.c for both used by DT and ACPI + */ + if (res->flags & IORESOURCE_IO) { + unsigned long port; + int err; + resource_size_t length = res->end - res->start; + + err = pci_register_io_range(res->start, length); + if (err) { + resource_list_destroy_entry(entry); + continue; + } + + port = pci_address_to_pio(res->start); + if (port == (unsigned long)-1) { + resource_list_destroy_entry(entry); + continue; + } + + res->start = port; + res->end = res->start + length - 1; + + if (pci_remap_iospace(res, res->start) < 0) + resource_list_destroy_entry(entry); + } + } + + return 0; +} + +static struct acpi_pci_root_ops acpi_pci_root_ops = { + .pci_ops = &pci_root_ops, + .init_info = pci_acpi_root_init_info, + .release_info = pci_acpi_root_release_info, + .prepare_resources = pci_acpi_root_prepare_resources, +}; + /* Root bridge scanning */ 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); + int domain = root->segment; + int busnum = root->secondary.start; + struct acpi_pci_root_info *info; + struct pci_bus *bus; + + if (domain && !pci_domains_supported) { + pr_warn("PCI %04x:%02x: multiple domains not supported.\n", + domain, busnum); + return NULL; + } + + info = kzalloc_node(sizeof(*info), GFP_KERNEL, node); + if (!info) { + dev_err(&root->device->dev, + "pci_bus %04x:%02x: ignored (out of memory)\n", + domain, busnum); + return NULL; + } + + bus = acpi_pci_root_create(root, &acpi_pci_root_ops, info, root); + + /* After the PCI-E bus has been walked and all devices discovered, + * configure any settings of the fabric that might be necessary. + */ + if (bus) { + struct pci_bus *child; + + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + } + + return bus; } #endif