From patchwork Wed Jan 13 13:21:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Nowicki X-Patchwork-Id: 566917 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id C883C14076E for ; Thu, 14 Jan 2016 00:23:16 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=semihalf-com.20150623.gappssmtp.com header.i=@semihalf-com.20150623.gappssmtp.com header.b=zg3ViCBm; dkim-atps=neutral Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752157AbcAMNXH (ORCPT ); Wed, 13 Jan 2016 08:23:07 -0500 Received: from mail-wm0-f48.google.com ([74.125.82.48]:36398 "EHLO mail-wm0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933381AbcAMNVz (ORCPT ); Wed, 13 Jan 2016 08:21:55 -0500 Received: by mail-wm0-f48.google.com with SMTP id l65so293172167wmf.1 for ; Wed, 13 Jan 2016 05:21:55 -0800 (PST) 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=j1yxHcEnL7qT15ngk+iTS8wvPODMUPzAhSfkTkyK9QA=; b=zg3ViCBmu/FoF53XgRE6pWEP43wPZbKtw5ogP0wIB9sbQAtFvjTc9gxflQ8kIpoNbd sKiVcPKPhteIUT2DEWIuPrs2nZq5ZF4dzO726mTW+kYiCtcc4YSSFwLr2cu9op6rV23O qrd9pg4ba90CC3bKRKfLLUR6rNyJSEXz9U96JtMjYzceLHVNV4KsUtED5+Jeffc4YmSh fvE+Wcl9gRDESUezvI8+olehC1q51LukrmaldK81mgxHHxt5aTXCvDhsT/3eVKtVPP/P IZDDV9i6iuLgNPo7lI/Tl9iwTCK7u0DhzALbADesQVuXxNjlB15wmmsLmcHUdmjDmI04 Um5Q== 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=j1yxHcEnL7qT15ngk+iTS8wvPODMUPzAhSfkTkyK9QA=; b=Xi97rgy6lMw7q0BiCuvCnT9QtwvfpudxRkiBUwj7Egk7jHcbWbz0yRPlxUEP96BiHd dNaERzxZHaKv7MFXwglRLw804En1WmhZpym9K9XQp+o5IRLW0LOGa4iRqChL1qbI6MPF ZWpmp4uo8sFS9ZHHgiLQWCk/iMdkft0Pxo7IeNBLXH/WWF2UBisrapiNFmjcHIMcVqKC kd6PpGM0RBlatkG6g69eErZmUQSmDvupf5YJ8QyasFhw1ShDWYe5/XIOra8qNja3b2Ue fJ1j8eCQT7qWyv/emqWiqXx7RArVZmHCipzkwV/RWMW/i6fNu07bu1m6SRLutyW+dU09 6sgA== X-Gm-Message-State: ALoCoQk0eYN661lLCguKEXtsXDd3CWPRf28yVVf/rTJFIFPhHIehHkwT5zXOmD6XzNceFGzZKb2KQlgsTKM+Jr9dZg//OTG5kQ== X-Received: by 10.194.103.234 with SMTP id fz10mr102413646wjb.31.1452691314519; Wed, 13 Jan 2016 05:21:54 -0800 (PST) Received: from tn-HP-4.semihalf.local (cardhu.semihalf.com. [213.17.239.108]) by smtp.gmail.com with ESMTPSA id y124sm8858741wmg.3.2016.01.13.05.21.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 13 Jan 2016 05:21:53 -0800 (PST) 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, okaya@codeaurora.org, jiang.liu@linux.intel.com, Stefano.Stabellini@eu.citrix.com Cc: robert.richter@caviumnetworks.com, mw@semihalf.com, Liviu.Dudau@arm.com, ddaney@caviumnetworks.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, jchandra@broadcom.com, jcm@redhat.com, Tomasz Nowicki Subject: [PATCH V3 19/21] pci, acpi: Support for ACPI based generic PCI host controller init Date: Wed, 13 Jan 2016 14:21:05 +0100 Message-Id: <1452691267-32240-20-git-send-email-tn@semihalf.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1452691267-32240-1-git-send-email-tn@semihalf.com> References: <1452691267-32240-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 Because of two patch series: 1. Jiang Liu's common interface to support PCI host controller init 2. MMCONFIG refactoring (part of this patch set) now we can think about generic ACPI based PCI host controller init implementation out of arch/ directory. These calls use information from MCFG table (PCI config space regions) and _CRS method (IO/irq resources) to initialize PCI hostbridge. TBD: We are still not sure whether we should reassign resources after PCI bus enumeration or trust firmware to do all that work for us properly. 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 Tested-by: Suravee Suthikulpanit Tested-by: Jeremy Linton --- drivers/acpi/Kconfig | 5 ++ drivers/acpi/pci_root.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index c3664be..e315061 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -335,6 +335,11 @@ config ACPI_PCI_SLOT i.e., segment/bus/device/function tuples, with physical slots in the system. If you are unsure, say N. +config ACPI_PCI_HOST_GENERIC + bool "Generic ACPI PCI host controller" + help + Say Y here if you want to support generic ACPI PCI host controller. + config X86_PM_TIMER bool "Power Management Timer Support" if EXPERT depends on X86 diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index a65c8c2..d483e2a 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -514,6 +515,136 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) } } +#ifdef CONFIG_ACPI_PCI_HOST_GENERIC +static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (pci_dev_msi_enabled(dev)) + return 0; + + acpi_pci_irq_enable(dev); + return dev->irq; +} + +static void pci_mcfg_release_info(struct acpi_pci_root_info *ci) +{ + pci_mmcfg_teardown_map(ci); + kfree(ci); +} + +static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci) +{ + struct list_head *list = &ci->resources; + struct acpi_device *device = ci->bridge; + struct resource_entry *entry, *tmp; + unsigned long flags; + int ret; + + flags = IORESOURCE_IO | IORESOURCE_MEM; + ret = acpi_dev_get_resources(device, list, + acpi_dev_filter_resource_type_cb, + (void *)flags); + if (ret < 0) { + dev_warn(&device->dev, + "failed to parse _CRS method, error code %d\n", ret); + return ret; + } else if (ret == 0) + dev_dbg(&device->dev, + "no IO and memory resources present in _CRS\n"); + + resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { + resource_size_t cpu_addr, length; + struct resource *res = entry->res; + + if (entry->res->flags & IORESOURCE_DISABLED) + resource_list_destroy_entry(entry); + else + res->name = ci->name; + + /* PCI -> CPU space translation */ + cpu_addr = res->start + entry->offset; + length = res->end - res->start + 1; + + if (res->flags & IORESOURCE_MEM) { + res->start = cpu_addr; + res->end = cpu_addr + length - 1; + } else if (res->flags & IORESOURCE_IO) { + resource_size_t pci_addr = res->start; + unsigned long port; + + if (pci_register_io_range(cpu_addr, length)) { + resource_list_destroy_entry(entry); + continue; + } + + port = pci_address_to_pio(cpu_addr); + if (port == (unsigned long)-1) { + resource_list_destroy_entry(entry); + continue; + } + + res->start = port; + res->end = port + length - 1; + entry->offset = port - pci_addr; + + if (pci_remap_iospace(res, cpu_addr) < 0) + resource_list_destroy_entry(entry); + } + } + return ret; +} + +static struct acpi_pci_root_ops acpi_pci_root_ops = { + .init_info = pci_mmcfg_setup_map, + .release_info = pci_mcfg_release_info, + .prepare_resources = pci_acpi_root_prepare_resources, +}; + +/* Root bridge scanning */ +struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) +{ + 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_host_bridge *bridge; + struct pci_bus *bus, *child; + + 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; + } + + acpi_pci_root_ops.pci_ops = pci_mcfg_get_ops(root); + bus = acpi_pci_root_create(root, &acpi_pci_root_ops, info, root); + if (!bus) + return NULL; + + bridge = pci_find_host_bridge(bus); + bridge->map_irq = pcibios_map_irq; + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + + /* + * After the PCI-E bus has been walked and all devices discovered, + * configure any settings of the fabric that might be necessary. + */ + list_for_each_entry(child, &bus->children, node) + pcie_bus_configure_settings(child); + + return bus; +} +#endif /* CONFIG_ARCH_PCI_HOST_GENERIC_ACPI */ + static int acpi_pci_root_add(struct acpi_device *device, const struct acpi_device_id *not_used) {