linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: helgaas@kernel.org (Bjorn Helgaas)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller
Date: Thu, 4 Feb 2016 18:19:07 -0600	[thread overview]
Message-ID: <20160205001907.GJ7031@localhost> (raw)
In-Reply-To: <1454058340-7904-6-git-send-email-jchandra@broadcom.com>

Hi Jayachandran,

On Fri, Jan 29, 2016 at 02:35:40PM +0530, Jayachandran C wrote:
> Add a simple ACPI based PCI host controller under config option
> ACPI_PCI_HOST_GENERIC. This is done by providing an implementation
> of pci_acpi_scan_root().
> 
> The pci_mmcfg_list handling is done by the ACPI code, so we keep a
> reference to the pci_mmcfg_region in sysdata. The ECAM region will
> be already mapped, so map_bus can be implemented by using the
> virt pointer for the pci_mmcfg_region. pci_generic_config_read
> and pci_generic_config_write are used for config space read/write.
> 
> Also, we provide implementations of raw_pci_read and raw_pci_write
> hat are needed by ACPI based on the pci_mmcfg_list.
> 
> pci_acpi_set_companion() and acpi_pci_get_segment() are defined
> using sysdata of generic ACPI host controller so that PCI domain
> and ACPI companion are set in PCI code rather than platform code.
> 
> This code is currently enabled only for ARM64.
> 
> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
> ---
>  drivers/acpi/Kconfig         |   8 ++
>  drivers/acpi/Makefile        |   1 +
>  drivers/acpi/pci_host_acpi.c | 186 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci-acpi.h     |  17 ++++
>  4 files changed, 212 insertions(+)
>  create mode 100644 drivers/acpi/pci_host_acpi.c

I'm speaking a little bit out of turn here, because this is ACPI code,
but I'm confused about pci_host_acpi.c.  We already have pci_root.c,
which is *supposed* to be arch-independent.  I know pci_root.c is
crufty and could be improved, but it does work today on x86 and ia64,
and it handles some generic things that pci_host_acpi.c does not,
e.g., _OSC, NUMA, host bridge hotplug, etc.

I'd really like to see pci_root.c improved so it could work on x86,
ia64, and arm64.  I'm sure that was probably the first thing you
tried, so likely there are issues there.  Are they insurmountable?

Bjorn

> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 82b96ee..65fb483 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -294,6 +294,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 74976f1..346101c 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 <http://www.gnu.org/licenses/>.
> + *
> + * Copyright (c) 2015 Broadcom Corporation
> + *
> + * Based on drivers/pci/host/pci-host-generic.c
> + * Copyright (C) 2014 ARM Limited
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/acpi.h>
> +#include <linux/pci-acpi.h>
> +#include <linux/sfi_acpi.h>
> +#include <linux/slab.h>
> +
> +#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;
> +}
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index d410885..f8d62e3 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -143,6 +143,22 @@ static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
>  static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>  #endif	/* CONFIG_ACPI */
>  
> +#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_PCI_HOST_GENERIC)
> +static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
> +{
> +	struct pci_bus *b = bridge->bus;
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)b->sysdata;
> +
> +	ACPI_COMPANION_SET(&bridge->dev, ci->bridge);
> +}
> +
> +static inline u16 acpi_pci_get_segment(void *sysdata)
> +{
> +	struct acpi_pci_root_info *ci = (struct acpi_pci_root_info *)sysdata;
> +
> +	return ci->root->segment;
> +}
> +#else
>  static inline void pci_acpi_set_companion(struct pci_host_bridge *bridge)
>  {
>  	/* leave it to the platform for now */
> @@ -152,6 +168,7 @@ static inline u16 acpi_pci_get_segment(void *sysdata)
>  {
>  	return 0;
>  }
> +#endif
>  
>  #ifdef CONFIG_ACPI_APEI
>  extern bool aer_acpi_firmware_first(void);
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2016-02-05  0:19 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-29  9:05 [PATCH v7 0/5] ACPI based PCI support for arm64 Jayachandran C
2016-01-29  9:05 ` [PATCH v7 1/5] APCI: MCFG: Move mmcfg_list management to drivers/acpi Jayachandran C
2016-01-29  9:05 ` [PATCH v7 2/5] ACPI: PCI: Support platforms that need pci_remap_iospace Jayachandran C
2016-01-29  9:05 ` [PATCH v7 3/5] PCI: Handle ACPI companion and domain number Jayachandran C
2016-01-29  9:05 ` [PATCH v7 4/5] arm64: pci: Add ACPI support Jayachandran C
2016-01-29  9:05 ` [PATCH v7 5/5] PCI: ACPI: Add a generic ACPI based host controller Jayachandran C
2016-02-05  0:19   ` Bjorn Helgaas [this message]
2016-02-05  8:35     ` Jayachandran Chandrashekaran Nair
2016-02-05  9:47       ` Lorenzo Pieralisi
2016-02-05 23:26         ` Rafael J. Wysocki
2016-02-06  9:58           ` Jayachandran Chandrashekaran Nair
2016-02-08 11:27         ` Jayachandran Chandrashekaran Nair
2016-02-10 13:30           ` Lorenzo Pieralisi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160205001907.GJ7031@localhost \
    --to=helgaas@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).