From patchwork Mon Jan 4 05:13:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Jayachandran C." X-Patchwork-Id: 7945571 Return-Path: X-Original-To: patchwork-linux-arm@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 2A48BBEEE5 for ; Mon, 4 Jan 2016 04:52:45 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1AF942022A for ; Mon, 4 Jan 2016 04:52:44 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F1FAD201FE for ; Mon, 4 Jan 2016 04:52:42 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aFx71-0001hL-Qc; Mon, 04 Jan 2016 04:51:19 +0000 Received: from mail-gw1-out.broadcom.com ([216.31.210.62]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aFx68-0001Au-QG for linux-arm-kernel@lists.infradead.org; Mon, 04 Jan 2016 04:50:27 +0000 X-IronPort-AV: E=Sophos;i="5.20,519,1444719600"; d="scan'208";a="84710138" Received: from irvexchcas08.broadcom.com (HELO IRVEXCHCAS08.corp.ad.broadcom.com) ([10.9.208.57]) by mail-gw1-out.broadcom.com with ESMTP; 03 Jan 2016 23:24:28 -0800 Received: from IRVEXCHSMTP1.corp.ad.broadcom.com (10.9.207.51) by IRVEXCHCAS08.corp.ad.broadcom.com (10.9.208.57) with Microsoft SMTP Server (TLS) id 14.3.235.1; Sun, 3 Jan 2016 20:50:07 -0800 Received: from mail-irva-13.broadcom.com (10.10.10.20) by IRVEXCHSMTP1.corp.ad.broadcom.com (10.9.207.51) with Microsoft SMTP Server id 14.3.235.1; Sun, 3 Jan 2016 20:50:07 -0800 Received: from netl-snoppy.ban.broadcom.com (unknown [10.132.128.129]) by mail-irva-13.broadcom.com (Postfix) with ESMTP id 4780B40FE9; Sun, 3 Jan 2016 20:46:20 -0800 (PST) From: Jayachandran C To: , Bjorn Helgaas , , Arnd Bergmann , , "Rafael J. Wysocki" Subject: [PATCH v5 5/5] PCI: ACPI: Add a generic ACPI based host controller Date: Mon, 4 Jan 2016 10:43:23 +0530 Message-ID: <1451884403-21437-6-git-send-email-jchandra@broadcom.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1451884403-21437-1-git-send-email-jchandra@broadcom.com> References: <1451884403-21437-1-git-send-email-jchandra@broadcom.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160103_205024_972847_0995B326 X-CRM114-Status: GOOD ( 19.36 ) X-Spam-Score: -4.2 (----) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Tomasz Nowicki , Lorenzo Pieralisi , Jayachandran C Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, 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 Add a simple ACPI based PCI host controller. This is done by providing a simple implementation for pci_acpi_scan_root(). The pci_mmcfg_list handling is done by the ACPI code, we keep a reference to the pci_mmcfg_region which is already mapped. Provide implementations of raw_pci_read and raw_pci_write based on the pci_mmcfg_list This is enabled only for ARM64 now. Signed-off-by: Jayachandran C --- drivers/acpi/Kconfig | 8 ++ drivers/acpi/Makefile | 1 + drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 drivers/acpi/pci_host_acpi.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 25dbb76..dceb871 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -283,6 +283,14 @@ config ACPI_NUMA depends on (X86 || IA64) default y if IA64_GENERIC || IA64_SGI_SN2 +config ACPI_PCI_HOST_GENERIC + bool "Generic ACPI PCI host controller" + depends on ARM64 && ACPI + help + Say Y here if you want to support a simple generic ACPI PCI host + controller. + + config ACPI_CUSTOM_DSDT_FILE string "Custom DSDT Table file to include" default "" diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 0780ced..52eb38f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -41,6 +41,7 @@ acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o acpi-$(CONFIG_PCI_MMCONFIG) += pci_mcfg.o +acpi-$(CONFIG_ACPI_PCI_HOST_GENERIC) += pci_host_acpi.o acpi-y += acpi_lpss.o acpi_apd.o acpi-y += acpi_platform.o acpi-y += acpi_pnp.o diff --git a/drivers/acpi/pci_host_acpi.c b/drivers/acpi/pci_host_acpi.c new file mode 100644 index 0000000..9dbdd81 --- /dev/null +++ b/drivers/acpi/pci_host_acpi.c @@ -0,0 +1,186 @@ +/* + * Generic PCI host controller driver for ACPI based systems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Copyright (c) 2015 Broadcom Corporation + * + * Based on drivers/pci/host/pci-host-generic.c + * Copyright (C) 2014 ARM Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PREFIX "pci-host-acpi:" + +/* sysdata pointer is ->root_info */ +struct gen_acpi_root_info { + struct acpi_pci_root_info common; + struct pci_mmcfg_region *mcfg; + bool mcfg_added; +}; + +/* find mapping of a MCFG area */ +static void __iomem *gen_acpi_map_cfg_bus(struct pci_bus *bus, + unsigned int devfn, int where) +{ + struct gen_acpi_root_info *pci = bus->sysdata; + struct pci_mmcfg_region *mcfg = pci->mcfg; + + if (bus->number < mcfg->start_bus || bus->number > mcfg->end_bus) + return NULL; + + return mcfg->virt + + PCI_MMCFG_OFFSET(bus->number - mcfg->start_bus, devfn) + + where; +} + +static struct pci_ops gen_acpi_pci_ops = { + .map_bus = gen_acpi_map_cfg_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, +}; + +/* Insert the ECFG area for a root bus */ +static int pci_acpi_root_init_info(struct acpi_pci_root_info *ci) +{ + struct gen_acpi_root_info *info; + struct acpi_pci_root *root = ci->root; + struct device *dev = &ci->bridge->dev; + int err; + + info = container_of(ci, struct gen_acpi_root_info, common); + err = pci_mmconfig_insert(dev, root->segment, root->secondary.start, + root->secondary.end, root->mcfg_addr); + if (err && err != -EEXIST) + return err; + + info->mcfg = pci_mmconfig_lookup(root->segment, root->secondary.start); + WARN_ON(info->mcfg == NULL); + info->mcfg_added = (err == -EEXIST); + return 0; +} + +static void pci_acpi_root_release_info(struct acpi_pci_root_info *ci) +{ + struct gen_acpi_root_info *info; + struct acpi_pci_root *root = ci->root; + + info = container_of(ci, struct gen_acpi_root_info, common); + if (info->mcfg_added) + pci_mmconfig_delete(root->segment, root->secondary.start, + root->secondary.end); + info->mcfg = NULL; +} + +static struct acpi_pci_root_ops pci_acpi_root_ops = { + .pci_ops = &gen_acpi_pci_ops, + .init_info = pci_acpi_root_init_info, + .release_info = pci_acpi_root_release_info, +}; + +struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) +{ + struct acpi_device *device = root->device; + struct gen_acpi_root_info *ri; + struct pci_bus *bus, *child; + + /* allocate acpi_info/sysdata */ + ri = devm_kzalloc(&device->dev, sizeof(*ri), GFP_KERNEL); + if (!ri) { + dev_err(&device->dev, + "pci_bus %04x:%02x: ignored (out of memory)\n", + root->segment, (int)root->secondary.start); + return NULL; + } + + bus = acpi_pci_root_create(root, &pci_acpi_root_ops, + &ri->common, ri); + if (!bus) { + dev_err(&device->dev, "Scanning rootbus failed"); + 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; +} + +int raw_pci_read(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 *val) +{ + struct pci_mmcfg_region *mcfg; + void __iomem *addr; + int err = -EINVAL; + + rcu_read_lock(); + mcfg = pci_mmconfig_lookup(seg, bus); + if (!mcfg || !mcfg->virt) + goto err; + + addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn); + switch (len) { + case 1: + *val = readb(addr + reg); + break; + case 2: + *val = readw(addr + reg); + break; + case 4: + *val = readl(addr + reg); + break; + } + err = 0; +err: + rcu_read_unlock(); + return err; +} + +int raw_pci_write(unsigned int seg, unsigned int bus, + unsigned int devfn, int reg, int len, u32 val) +{ + struct pci_mmcfg_region *mcfg; + void __iomem *addr; + int err = -EINVAL; + + rcu_read_lock(); + mcfg = pci_mmconfig_lookup(seg, bus); + if (!mcfg || !mcfg->virt) + goto err; + + addr = mcfg->virt + PCI_MMCFG_OFFSET(bus, devfn); + switch (len) { + case 1: + writeb(val, addr + reg); + break; + case 2: + writew(val, addr + reg); + break; + case 4: + writel(val, addr + reg); + break; + } + err = 0; +err: + rcu_read_unlock(); + return err; +}