From: "liudongdong (C)" <liudongdong3@huawei.com>
To: Tomasz Nowicki <tn@semihalf.com>, <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>,
<jiang.liu@linux.intel.com>, <jchandra@broadcom.com>,
<Stefano.Stabellini@eu.citrix.com>
Cc: <jcm@redhat.com>, <linaro-acpi@lists.linaro.org>,
<linux-pci@vger.kernel.org>, <Liviu.Dudau@arm.com>,
<ddaney@caviumnetworks.com>, <linux-kernel@vger.kernel.org>,
<linux-acpi@vger.kernel.org>, <robert.richter@caviumnetworks.com>,
<wangyijing@huawei.com>, <mw@semihalf.com>,
<linux-arm-kernel@lists.infradead.org>
Subject: Re: [Linaro-acpi] [PATCH V5 01/15] ACPI: MCFG: Move mmcfg_list management to drivers/acpi
Date: Thu, 18 Feb 2016 20:25:35 +0800 [thread overview]
Message-ID: <56C5B83F.4010602@huawei.com> (raw)
In-Reply-To: <1455630825-27253-2-git-send-email-tn@semihalf.com>
Hi Tomasz
在 2016/2/16 21:53, Tomasz Nowicki 写道:
> From: Jayachandran C <jchandra@broadcom.com>
>
> Move pci_mmcfg_list handling to a drivers/acpi/pci_mcfg.c. This is
> to share the API and code with ARM64 later. The corresponding
> declarations are moved from asm/pci_x86.h to linux/pci-acpi.h
>
> As a part of this we introduce three functions that can be
> implemented by the arch code: pci_mmconfig_map_resource() to map a
> mcfg entry, pci_mmconfig_unmap_resource to do the corresponding
> unmap and pci_mmconfig_enabled to see if the arch setup of
> mcfg entries was successful. We also provide weak implementations
> of these, which will be used from ARM64. On x86, we retain the
> old logic by providing platform specific implementation.
>
> This patch is purely rearranging code, it should not have any
> impact on the logic of MCFG parsing or list handling.
>
> Signed-off-by: Jayachandran C <jchandra@broadcom.com>
> [Xen parts:]
> Acked-by: David Vrabel <david.vrabel@citrix.com>
> ---
> arch/x86/include/asm/pci_x86.h | 24 +---
> arch/x86/pci/mmconfig-shared.c | 269 +++++------------------------------
> arch/x86/pci/mmconfig_32.c | 1 +
> arch/x86/pci/mmconfig_64.c | 1 +
> arch/x86/pci/numachip.c | 1 +
> drivers/acpi/Makefile | 1 +
> drivers/acpi/pci_mcfg.c | 312 +++++++++++++++++++++++++++++++++++++++++
> drivers/xen/pci.c | 5 +-
> include/linux/pci-acpi.h | 33 +++++
> 9 files changed, 386 insertions(+), 261 deletions(-)
> create mode 100644 drivers/acpi/pci_mcfg.c
>
> diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
> index 46873fb..7824626 100644
> --- a/arch/x86/include/asm/pci_x86.h
> +++ b/arch/x86/include/asm/pci_x86.h
> @@ -122,33 +122,11 @@ extern int pci_legacy_init(void);
> extern void pcibios_fixup_irqs(void);
>
> /* pci-mmconfig.c */
> -
> -/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
> -#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
> -
> -struct pci_mmcfg_region {
> - struct list_head list;
> - struct resource res;
> - u64 address;
> - char __iomem *virt;
> - u16 segment;
> - u8 start_bus;
> - u8 end_bus;
> - char name[PCI_MMCFG_RESOURCE_NAME_LEN];
> -};
> -
> +struct pci_mmcfg_region;
> extern int __init pci_mmcfg_arch_init(void);
> extern void __init pci_mmcfg_arch_free(void);
> extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
> extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
> -extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
> - phys_addr_t addr);
> -extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
> -extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
> -
> -extern struct list_head pci_mmcfg_list;
> -
> -#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)
>
> /*
> * On AMD Fam10h CPUs, all PCI MMIO configuration space accesses must use
> diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
> index dd30b7e..626710b 100644
> --- a/arch/x86/pci/mmconfig-shared.c
> +++ b/arch/x86/pci/mmconfig-shared.c
> @@ -12,13 +12,12 @@
>
> #include <linux/pci.h>
> #include <linux/init.h>
> -#include <linux/sfi_acpi.h>
> #include <linux/bitmap.h>
> -#include <linux/dmi.h>
> #include <linux/slab.h>
> #include <linux/mutex.h>
> #include <linux/rculist.h>
> #include <asm/e820.h>
> +#include <linux/pci-acpi.h>
> #include <asm/pci_x86.h>
> #include <asm/acpi.h>
>
> @@ -27,9 +26,6 @@
> /* Indicate if the mmcfg resources have been placed into the resource table. */
> static bool pci_mmcfg_running_state;
> static bool pci_mmcfg_arch_init_failed;
> -static DEFINE_MUTEX(pci_mmcfg_lock);
> -
> -LIST_HEAD(pci_mmcfg_list);
>
> static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
> {
> @@ -48,83 +44,6 @@ static void __init free_all_mmcfg(void)
> pci_mmconfig_remove(cfg);
> }
>
> -static void list_add_sorted(struct pci_mmcfg_region *new)
> -{
> - struct pci_mmcfg_region *cfg;
> -
> - /* keep list sorted by segment and starting bus number */
> - list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
> - if (cfg->segment > new->segment ||
> - (cfg->segment == new->segment &&
> - cfg->start_bus >= new->start_bus)) {
> - list_add_tail_rcu(&new->list, &cfg->list);
> - return;
> - }
> - }
> - list_add_tail_rcu(&new->list, &pci_mmcfg_list);
> -}
> -
> -static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
> - int end, u64 addr)
> -{
> - struct pci_mmcfg_region *new;
> - struct resource *res;
> -
> - if (addr == 0)
> - return NULL;
> -
> - new = kzalloc(sizeof(*new), GFP_KERNEL);
> - if (!new)
> - return NULL;
> -
> - new->address = addr;
> - new->segment = segment;
> - new->start_bus = start;
> - new->end_bus = end;
> -
> - res = &new->res;
> - res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
> - res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
> - res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
> - snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
> - "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
> - res->name = new->name;
> -
> - return new;
> -}
> -
> -static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
> - int end, u64 addr)
> -{
> - struct pci_mmcfg_region *new;
> -
> - new = pci_mmconfig_alloc(segment, start, end, addr);
> - if (new) {
> - mutex_lock(&pci_mmcfg_lock);
> - list_add_sorted(new);
> - mutex_unlock(&pci_mmcfg_lock);
> -
> - pr_info(PREFIX
> - "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
> - "(base %#lx)\n",
> - segment, start, end, &new->res, (unsigned long)addr);
> - }
> -
> - return new;
> -}
> -
> -struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
> -{
> - struct pci_mmcfg_region *cfg;
> -
> - list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
> - if (cfg->segment == segment &&
> - cfg->start_bus <= bus && bus <= cfg->end_bus)
> - return cfg;
> -
> - return NULL;
> -}
> -
> static const char *__init pci_mmcfg_e7520(void)
> {
> u32 win;
> @@ -543,73 +462,6 @@ static void __init pci_mmcfg_reject_broken(int early)
> }
> }
>
> -static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
> - struct acpi_mcfg_allocation *cfg)
> -{
> - int year;
> -
> - if (cfg->address < 0xFFFFFFFF)
> - return 0;
> -
> - if (!strncmp(mcfg->header.oem_id, "SGI", 3))
> - return 0;
> -
> - if (mcfg->header.revision >= 1) {
> - if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
> - year >= 2010)
> - return 0;
> - }
> -
> - pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
> - "is above 4GB, ignored\n", cfg->pci_segment,
> - cfg->start_bus_number, cfg->end_bus_number, cfg->address);
> - return -EINVAL;
> -}
> -
> -static int __init pci_parse_mcfg(struct acpi_table_header *header)
> -{
> - struct acpi_table_mcfg *mcfg;
> - struct acpi_mcfg_allocation *cfg_table, *cfg;
> - unsigned long i;
> - int entries;
> -
> - if (!header)
> - return -EINVAL;
> -
> - mcfg = (struct acpi_table_mcfg *)header;
> -
> - /* how many config structures do we have */
> - free_all_mmcfg();
> - entries = 0;
> - i = header->length - sizeof(struct acpi_table_mcfg);
> - while (i >= sizeof(struct acpi_mcfg_allocation)) {
> - entries++;
> - i -= sizeof(struct acpi_mcfg_allocation);
> - }
> - if (entries == 0) {
> - pr_err(PREFIX "MMCONFIG has no entries\n");
> - return -ENODEV;
> - }
> -
> - cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
> - for (i = 0; i < entries; i++) {
> - cfg = &cfg_table[i];
> - if (acpi_mcfg_check_entry(mcfg, cfg)) {
> - free_all_mmcfg();
> - return -ENODEV;
> - }
> -
> - if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
> - cfg->end_bus_number, cfg->address) == NULL) {
> - pr_warn(PREFIX "no memory for MCFG entries\n");
> - free_all_mmcfg();
> - return -ENOMEM;
> - }
> - }
> -
> - return 0;
> -}
> -
> #ifdef CONFIG_ACPI_APEI
> extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
> void *data), void *data);
> @@ -662,13 +514,20 @@ static void __init __pci_mmcfg_init(int early)
>
> static int __initdata known_bridge;
>
> +static void __init pci_mmcfg_list_setup(void)
> +{
> + free_all_mmcfg();
> + if (pci_mmconfig_parse_table())
> + free_all_mmcfg();
> +}
> +
> void __init pci_mmcfg_early_init(void)
> {
> if (pci_probe & PCI_PROBE_MMCONF) {
> if (pci_mmcfg_check_hostbridge())
> known_bridge = 1;
> else
> - acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
> + pci_mmcfg_list_setup();
> __pci_mmcfg_init(1);
>
> set_apei_filter();
> @@ -686,7 +545,7 @@ void __init pci_mmcfg_late_init(void)
>
> /* MMCONFIG hasn't been enabled yet, try again */
> if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
> - acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
> + pci_mmcfg_list_setup();
> __pci_mmcfg_init(0);
> }
> }
> @@ -720,99 +579,41 @@ static int __init pci_mmcfg_late_insert_resources(void)
> */
> late_initcall(pci_mmcfg_late_insert_resources);
>
> -/* Add MMCFG information for host bridges */
> -int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
> - phys_addr_t addr)
> +int pci_mmconfig_map_resource(struct device *dev, struct pci_mmcfg_region *cfg)
> {
> - int rc;
> - struct resource *tmp = NULL;
> - struct pci_mmcfg_region *cfg;
> + struct resource *tmp;
>
> - if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
> - return -ENODEV;
> -
> - if (start > end)
> - return -EINVAL;
> -
> - mutex_lock(&pci_mmcfg_lock);
> - cfg = pci_mmconfig_lookup(seg, start);
> - if (cfg) {
> - if (cfg->end_bus < end)
> - dev_info(dev, FW_INFO
> - "MMCONFIG for "
> - "domain %04x [bus %02x-%02x] "
> - "only partially covers this bridge\n",
> - cfg->segment, cfg->start_bus, cfg->end_bus);
> - mutex_unlock(&pci_mmcfg_lock);
> - return -EEXIST;
> - }
> -
> - if (!addr) {
> - mutex_unlock(&pci_mmcfg_lock);
> - return -EINVAL;
> - }
> -
> - rc = -EBUSY;
> - cfg = pci_mmconfig_alloc(seg, start, end, addr);
> - if (cfg == NULL) {
> - dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
> - rc = -ENOMEM;
> - } else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
> + if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
> dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
> &cfg->res);
> - } else {
> - /* Insert resource if it's not in boot stage */
> - if (pci_mmcfg_running_state)
> - tmp = insert_resource_conflict(&iomem_resource,
> - &cfg->res);
> -
> + return -EBUSY;
> + }
> + /* Insert resource if it's not in boot stage */
> + if (pci_mmcfg_running_state) {
> + tmp = insert_resource_conflict(&iomem_resource,
> + &cfg->res);
> if (tmp) {
> - dev_warn(dev,
> - "MMCONFIG %pR conflicts with "
> - "%s %pR\n",
> - &cfg->res, tmp->name, tmp);
> - } else if (pci_mmcfg_arch_map(cfg)) {
> - dev_warn(dev, "fail to map MMCONFIG %pR.\n",
> - &cfg->res);
> - } else {
> - list_add_sorted(cfg);
> - dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
> - &cfg->res, (unsigned long)addr);
> - cfg = NULL;
> - rc = 0;
> + dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
> + &cfg->res, tmp->name, tmp);
> + return -EBUSY;
> }
> }
> -
> - if (cfg) {
> - if (cfg->res.parent)
> - release_resource(&cfg->res);
> - kfree(cfg);
> + if (pci_mmcfg_arch_map(cfg)) {
> + dev_warn(dev, "fail to map MMCONFIG %pR.\n", &cfg->res);
> + return -EBUSY;
> }
> -
> - mutex_unlock(&pci_mmcfg_lock);
> -
> - return rc;
> + return 0;
> }
>
> -/* Delete MMCFG information for host bridges */
> -int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
> +void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *cfg)
> {
> - struct pci_mmcfg_region *cfg;
> -
> - mutex_lock(&pci_mmcfg_lock);
> - list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
> - if (cfg->segment == seg && cfg->start_bus == start &&
> - cfg->end_bus == end) {
> - list_del_rcu(&cfg->list);
> - synchronize_rcu();
> - pci_mmcfg_arch_unmap(cfg);
> - if (cfg->res.parent)
> - release_resource(&cfg->res);
> - mutex_unlock(&pci_mmcfg_lock);
> - kfree(cfg);
> - return 0;
> - }
> - mutex_unlock(&pci_mmcfg_lock);
> + pci_mmcfg_arch_unmap(cfg);
> + if (cfg->res.parent)
> + release_resource(&cfg->res);
> + cfg->res.parent = NULL;
> +}
>
> - return -ENOENT;
> +int pci_mmconfig_enabled(void)
> +{
> + return (pci_probe & PCI_PROBE_MMCONF) && !pci_mmcfg_arch_init_failed;
> }
> diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
> index 43984bc..38a37f8 100644
> --- a/arch/x86/pci/mmconfig_32.c
> +++ b/arch/x86/pci/mmconfig_32.c
> @@ -12,6 +12,7 @@
> #include <linux/pci.h>
> #include <linux/init.h>
> #include <linux/rcupdate.h>
> +#include <linux/pci-acpi.h>
> #include <asm/e820.h>
> #include <asm/pci_x86.h>
>
> diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
> index bea5249..29253ec 100644
> --- a/arch/x86/pci/mmconfig_64.c
> +++ b/arch/x86/pci/mmconfig_64.c
> @@ -10,6 +10,7 @@
> #include <linux/acpi.h>
> #include <linux/bitmap.h>
> #include <linux/rcupdate.h>
> +#include <linux/pci-acpi.h>
> #include <asm/e820.h>
> #include <asm/pci_x86.h>
>
> diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c
> index 2e565e6..c181eeb 100644
> --- a/arch/x86/pci/numachip.c
> +++ b/arch/x86/pci/numachip.c
> @@ -14,6 +14,7 @@
> */
>
> #include <linux/pci.h>
> +#include <linux/pci-acpi.h>
> #include <asm/pci_x86.h>
>
> static u8 limit __read_mostly;
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 7ea903d..e5e4393 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -40,6 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
> 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-y += acpi_lpss.o acpi_apd.o
> acpi-y += acpi_platform.o
> acpi-y += acpi_pnp.o
> diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
> new file mode 100644
> index 0000000..ea84365
> --- /dev/null
> +++ b/drivers/acpi/pci_mcfg.c
> @@ -0,0 +1,312 @@
> +/*
> + * pci_mcfg.c
> + *
> + * Common code to maintain the MCFG areas and mappings
> + *
> + * This has been extracted from arch/x86/pci/mmconfig-shared.c
> + * and moved here so that other architectures can use this code.
> + */
> +
> +#include <linux/pci.h>
> +#include <linux/init.h>
> +#include <linux/dmi.h>
> +#include <linux/pci-acpi.h>
> +#include <linux/sfi_acpi.h>
> +#include <linux/slab.h>
> +#include <linux/mutex.h>
> +#include <linux/rculist.h>
> +
> +#define PREFIX "ACPI: "
> +
> +static DEFINE_MUTEX(pci_mmcfg_lock);
> +LIST_HEAD(pci_mmcfg_list);
> +
> +static void list_add_sorted(struct pci_mmcfg_region *new)
> +{
> + struct pci_mmcfg_region *cfg;
> +
> + /* keep list sorted by segment and starting bus number */
> + list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list) {
> + if (cfg->segment > new->segment ||
> + (cfg->segment == new->segment &&
> + cfg->start_bus >= new->start_bus)) {
> + list_add_tail_rcu(&new->list, &cfg->list);
> + return;
> + }
> + }
> + list_add_tail_rcu(&new->list, &pci_mmcfg_list);
> +}
> +
> +static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
> + int end, u64 addr)
> +{
> + struct pci_mmcfg_region *new;
> + struct resource *res;
> +
> + if (addr == 0)
> + return NULL;
> +
> + new = kzalloc(sizeof(*new), GFP_KERNEL);
> + if (!new)
> + return NULL;
> +
> + new->address = addr;
> + new->segment = segment;
> + new->start_bus = start;
> + new->end_bus = end;
> +
> + res = &new->res;
> + res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
> + res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
> + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
> + snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
> + "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
> + res->name = new->name;
> +
> + return new;
> +}
> +
> +struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
> + int end, u64 addr)
> +{
> + struct pci_mmcfg_region *new;
> +
> + new = pci_mmconfig_alloc(segment, start, end, addr);
> + if (new) {
> + mutex_lock(&pci_mmcfg_lock);
> + list_add_sorted(new);
> + mutex_unlock(&pci_mmcfg_lock);
> +
> + pr_info(PREFIX
> + "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
> + "(base %#lx)\n",
> + segment, start, end, &new->res, (unsigned long)addr);
> + }
> +
> + return new;
> +}
> +
> +struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
> +{
> + struct pci_mmcfg_region *cfg;
> +
> + list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
> + if (cfg->segment == segment &&
> + cfg->start_bus <= bus && bus <= cfg->end_bus)
> + return cfg;
> +
> + return NULL;
> +}
> +
> +/*
> + * Map a pci_mmcfg_region, can be overrriden by arch
> + */
> +int __weak pci_mmconfig_map_resource(struct device *dev,
> + struct pci_mmcfg_region *mcfg)
> +{
> + struct resource *tmp;
> + void __iomem *vaddr;
> +
> + tmp = insert_resource_conflict(&iomem_resource, &mcfg->res);
> + if (tmp) {
> + dev_warn(dev, "MMCONFIG %pR conflicts with %s %pR\n",
> + &mcfg->res, tmp->name, tmp);
> + return -EBUSY;
> + }
> +
> + vaddr = ioremap(mcfg->res.start, resource_size(&mcfg->res));
> + if (!vaddr) {
> + release_resource(&mcfg->res);
> + return -ENOMEM;
> + }
> +
> + mcfg->virt = vaddr;
Here should be changed to
mcfg->virt = vaddr - PCI_MMCFG_BUS_OFFSET(mcfg->start_bus);
or when pcie host "start_bus" is not 0, the configuraion access will be wrong.
See v3 or v4 patchset "addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);"
static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
{
void __iomem *addr;
u64 start, size;
int num_buses;
start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
num_buses = cfg->end_bus - cfg->start_bus + 1;
size = PCI_MMCFG_BUS_OFFSET(num_buses);
addr = ioremap_nocache(start, size);
if (addr)
addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
return addr;
}
Dongdong
Thanks
> + return 0;
> +}
> +
> +/*
> + * Unmap a pci_mmcfg_region, can be overrriden by arch
> + */
> +void __weak pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg)
> +{
> + if (mcfg->virt) {
> + iounmap(mcfg->virt);
> + mcfg->virt = NULL;
> + }
> + if (mcfg->res.parent) {
> + release_resource(&mcfg->res);
> + mcfg->res.parent = NULL;
> + }
> +}
> +
> +/*
> + * check if the mmconfig is enabled and configured
> + */
> +int __weak pci_mmconfig_enabled(void)
> +{
> + return 1;
> +}
> +
> +/* Add MMCFG information for host bridges */
> +int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
> + phys_addr_t addr)
> +{
> + struct pci_mmcfg_region *cfg;
> + int rc;
> +
> + if (!pci_mmconfig_enabled())
> + return -ENODEV;
> + if (start > end)
> + return -EINVAL;
> +
> + mutex_lock(&pci_mmcfg_lock);
> + cfg = pci_mmconfig_lookup(seg, start);
> + if (cfg) {
> + if (cfg->end_bus < end)
> + dev_info(dev, FW_INFO
> + "MMCONFIG for "
> + "domain %04x [bus %02x-%02x] "
> + "only partially covers this bridge\n",
> + cfg->segment, cfg->start_bus, cfg->end_bus);
> + rc = -EEXIST;
> + goto err;
> + }
> +
> + if (!addr) {
> + rc = -EINVAL;
> + goto err;
> + }
> +
> + cfg = pci_mmconfig_alloc(seg, start, end, addr);
> + if (cfg == NULL) {
> + dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
> + rc = -ENOMEM;
> + goto err;
> + }
> + rc = pci_mmconfig_map_resource(dev, cfg);
> + if (!rc) {
> + list_add_sorted(cfg);
> + dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
> + &cfg->res, (unsigned long)addr);
> + return 0;
> + } else {
> + if (cfg->res.parent)
> + release_resource(&cfg->res);
> + kfree(cfg);
> + }
> +
> +err:
> + mutex_unlock(&pci_mmcfg_lock);
> + return rc;
> +}
> +
> +/* Delete MMCFG information for host bridges */
> +int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
> +{
> + struct pci_mmcfg_region *cfg;
> +
> + mutex_lock(&pci_mmcfg_lock);
> + list_for_each_entry_rcu(cfg, &pci_mmcfg_list, list)
> + if (cfg->segment == seg && cfg->start_bus == start &&
> + cfg->end_bus == end) {
> + list_del_rcu(&cfg->list);
> + synchronize_rcu();
> + pci_mmconfig_unmap_resource(cfg);
> + mutex_unlock(&pci_mmcfg_lock);
> + kfree(cfg);
> + return 0;
> + }
> + mutex_unlock(&pci_mmcfg_lock);
> +
> + return -ENOENT;
> +}
> +
> +static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
> + struct acpi_mcfg_allocation *cfg)
> +{
> + int year;
> +
> + if (!config_enabled(CONFIG_X86))
> + return 0;
> +
> + if (cfg->address < 0xFFFFFFFF)
> + return 0;
> +
> + if (!strncmp(mcfg->header.oem_id, "SGI", 3))
> + return 0;
> +
> + if (mcfg->header.revision >= 1) {
> + if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
> + year >= 2010)
> + return 0;
> + }
> +
> + pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
> + "is above 4GB, ignored\n", cfg->pci_segment,
> + cfg->start_bus_number, cfg->end_bus_number, cfg->address);
> + return -EINVAL;
> +}
> +
> +static int __init pci_parse_mcfg(struct acpi_table_header *header)
> +{
> + struct acpi_table_mcfg *mcfg;
> + struct acpi_mcfg_allocation *cfg_table, *cfg;
> + unsigned long i;
> + int entries;
> +
> + if (!header)
> + return -EINVAL;
> +
> + mcfg = (struct acpi_table_mcfg *)header;
> +
> + /* how many config structures do we have */
> + entries = 0;
> + i = header->length - sizeof(struct acpi_table_mcfg);
> + while (i >= sizeof(struct acpi_mcfg_allocation)) {
> + entries++;
> + i -= sizeof(struct acpi_mcfg_allocation);
> + }
> + if (entries == 0) {
> + pr_err(PREFIX "MMCONFIG has no entries\n");
> + return -ENODEV;
> + }
> +
> + cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
> + for (i = 0; i < entries; i++) {
> + cfg = &cfg_table[i];
> + if (acpi_mcfg_check_entry(mcfg, cfg))
> + return -ENODEV;
> +
> + if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
> + cfg->end_bus_number, cfg->address) == NULL) {
> + pr_warn(PREFIX "no memory for MCFG entries\n");
> + return -ENOMEM;
> + }
> + }
> +
> + return 0;
> +}
> +
> +int __init pci_mmconfig_parse_table(void)
> +{
> + return acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
> +}
> +
> +void __weak __init pci_mmcfg_late_init(void)
> +{
> + int err, n = 0;
> + struct pci_mmcfg_region *cfg;
> +
> + err = pci_mmconfig_parse_table();
> + if (err) {
> + pr_err(PREFIX " Failed to parse MCFG (%d)\n", err);
> + return;
> + }
> +
> + list_for_each_entry(cfg, &pci_mmcfg_list, list) {
> + pci_mmconfig_map_resource(NULL, cfg);
> + n++;
> + }
> +
> + pr_info(PREFIX " MCFG table loaded %d entries\n", n);
> +}
> diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c
> index 7494dbe..97aa9d3 100644
> --- a/drivers/xen/pci.c
> +++ b/drivers/xen/pci.c
> @@ -27,9 +27,6 @@
> #include <asm/xen/hypervisor.h>
> #include <asm/xen/hypercall.h>
> #include "../pci/pci.h"
> -#ifdef CONFIG_PCI_MMCONFIG
> -#include <asm/pci_x86.h>
> -#endif
>
> static bool __read_mostly pci_seg_supported = true;
>
> @@ -221,7 +218,7 @@ static int __init xen_mcfg_late(void)
> if (!xen_initial_domain())
> return 0;
>
> - if ((pci_probe & PCI_PROBE_MMCONF) == 0)
> + if (!pci_mmconfig_enabled())
> return 0;
>
> if (list_empty(&pci_mmcfg_list))
> diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
> index 89ab057..e9450ef 100644
> --- a/include/linux/pci-acpi.h
> +++ b/include/linux/pci-acpi.h
> @@ -106,6 +106,39 @@ extern const u8 pci_acpi_dsm_uuid[];
> #define RESET_DELAY_DSM 0x08
> #define FUNCTION_DELAY_DSM 0x09
>
> +/* common API to maintain list of MCFG regions */
> +/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
> +#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
> +
> +struct pci_mmcfg_region {
> + struct list_head list;
> + struct resource res;
> + u64 address;
> + char __iomem *virt;
> + u16 segment;
> + u8 start_bus;
> + u8 end_bus;
> + char name[PCI_MMCFG_RESOURCE_NAME_LEN];
> +};
> +
> +extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
> + phys_addr_t addr);
> +extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
> +
> +extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
> +extern struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
> + int end, u64 addr);
> +extern int pci_mmconfig_map_resource(struct device *dev,
> + struct pci_mmcfg_region *mcfg);
> +extern void pci_mmconfig_unmap_resource(struct pci_mmcfg_region *mcfg);
> +extern int pci_mmconfig_enabled(void);
> +extern int __init pci_mmconfig_parse_table(void);
> +
> +extern struct list_head pci_mmcfg_list;
> +
> +#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)
> +#define PCI_MMCFG_OFFSET(bus, devfn) ((bus) << 20 | (devfn) << 12)
> +
> #else /* CONFIG_ACPI */
> static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
> static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
>
next prev parent reply other threads:[~2016-02-18 12:34 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-16 13:53 [PATCH V5 00/15] MMCONFIG refactoring and support for ARM64 PCI hostbridge init based on ACPI Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 01/15] ACPI: MCFG: Move mmcfg_list management to drivers/acpi Tomasz Nowicki
2016-02-17 11:00 ` Lorenzo Pieralisi
2016-02-18 12:25 ` liudongdong (C) [this message]
2016-02-18 13:20 ` [Linaro-acpi] " Lorenzo Pieralisi
2016-03-03 22:51 ` Bjorn Helgaas
2016-03-04 8:35 ` Jayachandran Chandrashekaran Nair
2016-03-05 4:14 ` Bjorn Helgaas
2016-03-09 9:13 ` Tomasz Nowicki
2016-03-09 9:14 ` Tomasz Nowicki
2016-03-09 10:10 ` Jayachandran Chandrashekaran Nair
2016-03-09 10:50 ` Tomasz Nowicki
2016-03-10 13:08 ` Jayachandran Chandrashekaran Nair
2016-03-17 20:18 ` [RFC PATCH 0/4] ACPI based PCI host driver with generic ECAM Jayachandran C
2016-03-18 17:47 ` Jayachandran C
2016-03-23 10:22 ` Gabriele Paoloni
2016-03-28 13:42 ` Sinan Kaya
2016-03-28 18:01 ` Jayachandran C
2016-03-17 20:18 ` [RFC PATCH 1/4] PCI: Provide generic ECAM mapping functions Jayachandran C
2016-03-17 20:18 ` [RFC PATCH 2/4] PCI: generic,thunder: Use generic config functions Jayachandran C
2016-03-17 20:18 ` [RFC PATCH 3/4] ACPI: PCI: Add generic PCI host controller Jayachandran C
2016-03-17 20:18 ` [RFC PATCH 4/4] ACPI: PCI: Add raw_pci_read/write operations Jayachandran C
2016-04-05 14:11 ` [PATCH V5 01/15] ACPI: MCFG: Move mmcfg_list management to drivers/acpi Tomasz Nowicki
2016-04-05 16:41 ` Bjorn Helgaas
2016-04-05 18:07 ` Tomasz Nowicki
2016-04-05 18:50 ` Jayachandran C
2016-03-04 9:27 ` Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 02/15] acpi, pci, mcfg: Provide default RAW ACPI PCI config space accessors Tomasz Nowicki
2016-02-17 12:39 ` Lorenzo Pieralisi
2016-02-16 13:53 ` [PATCH V5 03/15] arm64, acpi: Use MCFG library and empty PCI config space accessors from pci_mcfg.c file Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 04/15] pci, acpi, ecam: Add flag to indicate whether ECAM region was hot added or not Tomasz Nowicki
2016-02-18 12:32 ` Lorenzo Pieralisi
2016-02-16 13:53 ` [PATCH V5 05/15] x86, pci: Cleanup platform specific MCFG data by using ECAM hot_added flag Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 06/15] pci, acpi, x86, ia64: Move ACPI host bridge device companion assignment to core code Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 07/15] pci, acpi: Provide generic way to assign bus domain number Tomasz Nowicki
2016-02-17 13:44 ` Jayachandran Chandrashekaran Nair
2016-02-17 14:07 ` Tomasz Nowicki
2016-02-17 14:21 ` Jayachandran Chandrashekaran Nair
2016-02-17 15:05 ` Tomasz Nowicki
2016-02-17 15:21 ` Jayachandran Chandrashekaran Nair
2016-02-17 15:35 ` Tomasz Nowicki
2016-02-17 17:45 ` Lorenzo Pieralisi
2016-02-16 13:53 ` [PATCH V5 08/15] x86, ia64: Include acpi_pci_{add|remove}_bus to the default pcibios_{add|remove}_bus implementation Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 09/15] acpi, mcfg: Add default PCI config accessors implementation and initial support for related quirks Tomasz Nowicki
2016-02-17 18:39 ` Lorenzo Pieralisi
2016-02-16 13:53 ` [PATCH V5 10/15] pci, of: Move the PCI I/O space management to PCI core code Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 11/15] drivers: pci: add generic code to claim bus resources Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 12/15] pci, acpi: Support for ACPI based generic PCI host controller initialization Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 13/15] pci, acpi: Match PCI config space accessors against platfrom specific quirks Tomasz Nowicki
2016-03-18 15:49 ` Mark Salter
2016-03-22 10:26 ` Tomasz Nowicki
2016-02-16 13:53 ` [PATCH V5 14/15] arm64, pci, acpi: Assign legacy IRQs once device is enable Tomasz Nowicki
2016-02-17 18:18 ` Lorenzo Pieralisi
2016-02-16 13:53 ` [PATCH V5 15/15] arm64, pci, acpi: Start using ACPI based PCI host bridge driver for ARM64 Tomasz Nowicki
2016-02-18 12:59 ` [PATCH V5 00/15] MMCONFIG refactoring and support for ARM64 PCI hostbridge init based on ACPI Lorenzo Pieralisi
2016-02-29 19:03 ` Sinan Kaya
2016-03-03 11:23 ` Lorenzo Pieralisi
2016-03-03 14:24 ` Sinan Kaya
2016-03-04 10:55 ` Lorenzo Pieralisi
2016-03-04 12:01 ` Tomasz Nowicki
2016-03-04 14:52 ` Sinan Kaya
2016-03-04 17:37 ` 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=56C5B83F.4010602@huawei.com \
--to=liudongdong3@huawei.com \
--cc=Liviu.Dudau@arm.com \
--cc=Lorenzo.Pieralisi@arm.com \
--cc=Stefano.Stabellini@eu.citrix.com \
--cc=arnd@arndb.de \
--cc=catalin.marinas@arm.com \
--cc=ddaney@caviumnetworks.com \
--cc=hanjun.guo@linaro.org \
--cc=helgaas@kernel.org \
--cc=jchandra@broadcom.com \
--cc=jcm@redhat.com \
--cc=jiang.liu@linux.intel.com \
--cc=linaro-acpi@lists.linaro.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=mw@semihalf.com \
--cc=okaya@codeaurora.org \
--cc=rafael@kernel.org \
--cc=robert.richter@caviumnetworks.com \
--cc=tn@semihalf.com \
--cc=wangyijing@huawei.com \
--cc=will.deacon@arm.com \
/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).