Patchwork [6/6] PCI, x86: change the way to add MMCFG region on x86

login
register
mail settings
Submitter Taku Izumi
Date April 26, 2012, 10:42 a.m.
Message ID <20120426194254.3679abe0.izumi.taku@jp.fujitsu.com>
Download mbox | patch
Permalink /patch/155241/
State Superseded
Headers show

Comments

Taku Izumi - April 26, 2012, 10:42 a.m.
This patch changes the way to add MMCFG region on x86.
MMCFG region information provided by ACPI MCFG table 
or _CBA method will be added at acpi_pci_root_add()
of pci_root driver.

Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
---
 arch/x86/include/asm/pci_x86.h |    2 +
 arch/x86/pci/acpi.c            |   45 +++++++++++++++++++++++++++++++++++++
 arch/x86/pci/mmconfig-shared.c |   49 ++++++++++++++++++++++++++++++-----------
 arch/x86/pci/mmconfig_32.c     |    2 -
 arch/x86/pci/mmconfig_64.c     |    2 -
 drivers/acpi/pci_root.c        |   15 ++++++++++++
 include/acpi/acnames.h         |    1 
 include/linux/pci-acpi.h       |    3 ++
 8 files changed, 105 insertions(+), 14 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jiang Liu - April 26, 2012, 3:04 p.m.
Hi Taku,
	Thanks for following this up. Please refer to inline comments below.
I feel there are still some concerns from Don about the change proposed by
Bjorn. And I haven't found a solution to address Don's concerns yet. So it
would be better for us to hold on this for a while.

	BTW, is it OK to split the task into two steps? 
1) enhance mmcfg to support host bridge hotplug.
2) refine the mmcfg setup logic.
Seems it's more realistic for us to reach an agreement for task 1 in a short time,
but there is still much work ahead for task 2.

On 04/26/2012 06:42 PM, Taku Izumi wrote:
> 
> This patch changes the way to add MMCFG region on x86.
> MMCFG region information provided by ACPI MCFG table 
> or _CBA method will be added at acpi_pci_root_add()
> of pci_root driver.
> 
> Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com>
> ---
>  arch/x86/include/asm/pci_x86.h |    2 +
>  arch/x86/pci/acpi.c            |   45 +++++++++++++++++++++++++++++++++++++
>  arch/x86/pci/mmconfig-shared.c |   49 ++++++++++++++++++++++++++++++-----------
>  arch/x86/pci/mmconfig_32.c     |    2 -
>  arch/x86/pci/mmconfig_64.c     |    2 -
>  drivers/acpi/pci_root.c        |   15 ++++++++++++
>  include/acpi/acnames.h         |    1 
>  include/linux/pci-acpi.h       |    3 ++
>  8 files changed, 105 insertions(+), 14 deletions(-)
> 
> Index: bjorn-next/arch/x86/include/asm/pci_x86.h
> ===================================================================
> --- bjorn-next.orig/arch/x86/include/asm/pci_x86.h
> +++ bjorn-next/arch/x86/include/asm/pci_x86.h
> @@ -100,6 +100,7 @@ struct pci_raw_ops {
>  extern const struct pci_raw_ops *raw_pci_ops;
>  extern const struct pci_raw_ops *raw_pci_ext_ops;
>  
> +extern const struct pci_raw_ops pci_mmcfg;
>  extern const struct pci_raw_ops pci_direct_conf1;
>  extern bool port_cf9_safe;
>  
> @@ -140,6 +141,7 @@ extern void pci_mmcfg_arch_unmap(struct 
>  extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
>  extern int __devinit pci_mmconfig_add(int seg, int start, int end, u64 addr);
>  extern int pci_mmconfig_delete(int seg, int start, int end);
> +extern u64 query_acpi_mcfg_table(int segment, int start);
>  extern struct list_head pci_mmcfg_list;
>  
>  #define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
> Index: bjorn-next/arch/x86/pci/acpi.c
> ===================================================================
> --- bjorn-next.orig/arch/x86/pci/acpi.c
> +++ bjorn-next/arch/x86/pci/acpi.c
> @@ -4,6 +4,7 @@
>  #include <linux/irq.h>
>  #include <linux/dmi.h>
>  #include <linux/slab.h>
> +#include <linux/pci-acpi.h>
>  #include <asm/numa.h>
>  #include <asm/pci_x86.h>
>  
> @@ -461,6 +462,50 @@ struct pci_bus * __devinit pci_acpi_scan
>  	return bus;
>  }
>  
> +
> +int __devinit arch_acpi_pci_root_add(struct acpi_pci_root *root)
> +{
> +	int result = 0;
> +	acpi_status status;
> +	unsigned long long base_addr = 0;
> +
> +	/* MMCFG not in use */
> +	if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
> +		return result;
> +
> +	/* Evaluate _CBA */
> +	status = acpi_evaluate_integer(root->device->handle, METHOD_NAME__CBA,
> +				       NULL, &base_addr);
> +	if (ACPI_FAILURE(status)) {
> +		/* search MCFG table */
> +		base_addr = query_acpi_mcfg_table(root->segment,
> +						  root->secondary.start);
> +
> +	}
> +
> +	/* add MMCFG region */
> +	if (base_addr) {
> +		if (pci_mmconfig_add(root->segment, root->secondary.start,
> +					root->secondary.end, base_addr)) {
> +			printk(KERN_ERR
> +				"can't add MMCFG information for Bus "
> +				"%04x:%02x\n",
> +				root->segment,
> +				(unsigned int)root->secondary.start);
Should set 'result' to suitable error code here.

> +		}
raw_pci_ext_ops should be set to &pci_mmcfg if raw_pci_ext_ops is still NULL
and pci_mmconfig_add succeeds.

> +	} else {
> +		result = -ENODEV;
> +	}
> +
> +	return result;
> +}
> +
> +void arch_acpi_pci_root_remove(struct acpi_pci_root *root)
> +{
> +	pci_mmconfig_delete(root->segment, root->secondary.start,
> +				root->secondary.end);
> +}
> +
>  int __init pci_acpi_init(void)
>  {
>  	struct pci_dev *dev = NULL;
> Index: bjorn-next/arch/x86/pci/mmconfig_32.c
> ===================================================================
> --- bjorn-next.orig/arch/x86/pci/mmconfig_32.c
> +++ bjorn-next/arch/x86/pci/mmconfig_32.c
> @@ -126,7 +126,7 @@ static int pci_mmcfg_write(unsigned int 
>  	return 0;
>  }
>  
> -static const struct pci_raw_ops pci_mmcfg = {
> +const struct pci_raw_ops pci_mmcfg = {
>  	.read =		pci_mmcfg_read,
>  	.write =	pci_mmcfg_write,
>  };
> Index: bjorn-next/arch/x86/pci/mmconfig_64.c
> ===================================================================
> --- bjorn-next.orig/arch/x86/pci/mmconfig_64.c
> +++ bjorn-next/arch/x86/pci/mmconfig_64.c
> @@ -90,7 +90,7 @@ static int pci_mmcfg_write(unsigned int 
>  	return 0;
>  }
>  
> -static const struct pci_raw_ops pci_mmcfg = {
> +const struct pci_raw_ops pci_mmcfg = {
>  	.read =		pci_mmcfg_read,
>  	.write =	pci_mmcfg_write,
>  };
> Index: bjorn-next/drivers/acpi/pci_root.c
> ===================================================================
> --- bjorn-next.orig/drivers/acpi/pci_root.c
> +++ bjorn-next/drivers/acpi/pci_root.c
> @@ -449,6 +449,15 @@ out:
>  }
>  EXPORT_SYMBOL(acpi_pci_osc_control_set);
>  
> +int __weak arch_acpi_pci_root_add(struct acpi_pci_root *root)
> +{
> +	return 0;
> +}
> +
> +void __weak arch_acpi_pci_root_remove(struct acpi_pci_root *root)
> +{
> +}
> +
>  static int __devinit acpi_pci_root_add(struct acpi_device *device)
>  {
>  	unsigned long long segment, bus;
> @@ -505,6 +514,11 @@ static int __devinit acpi_pci_root_add(s
>  	strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
>  	device->driver_data = root;
>  
> +	if (arch_acpi_pci_root_add(root)) {
> +		result = -ENODEV;
> +		goto end;
> +	}
> +
>  	/*
>  	 * All supported architectures that use ACPI have support for
>  	 * PCI domains, so we indicate this in _OSC support capabilities.
> @@ -627,6 +641,7 @@ static int __devinit acpi_pci_root_add(s
>  end:
>  	if (!list_empty(&root->node))
>  		list_del(&root->node);
> +	arch_acpi_pci_root_remove(root);
>  	kfree(root);
>  	return result;
>  }
> Index: bjorn-next/include/acpi/acnames.h
> ===================================================================
> --- bjorn-next.orig/include/acpi/acnames.h
> +++ bjorn-next/include/acpi/acnames.h
> @@ -62,6 +62,7 @@
>  #define METHOD_NAME__AEI        "_AEI"
>  #define METHOD_NAME__PRW        "_PRW"
>  #define METHOD_NAME__SRS        "_SRS"
> +#define METHOD_NAME__CBA	"_CBA"
>  
>  /* Method names - these methods must appear at the namespace root */
>  
> Index: bjorn-next/include/linux/pci-acpi.h
> ===================================================================
> --- bjorn-next.orig/include/linux/pci-acpi.h
> +++ bjorn-next/include/linux/pci-acpi.h
> @@ -18,6 +18,9 @@ extern acpi_status pci_acpi_add_pm_notif
>  					     struct pci_dev *pci_dev);
>  extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev);
>  
> +int arch_acpi_pci_root_add(struct acpi_pci_root *root);
> +void arch_acpi_pci_root_remove(struct acpi_pci_root *root);
> +
>  static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
>  {
>  	struct pci_bus *pbus = pdev->bus;
> Index: bjorn-next/arch/x86/pci/mmconfig-shared.c
> ===================================================================
> --- bjorn-next.orig/arch/x86/pci/mmconfig-shared.c
> +++ bjorn-next/arch/x86/pci/mmconfig-shared.c
> @@ -28,6 +28,9 @@
>  /* Indicate if the mmcfg resources have been placed into the resource table. */
>  static int __initdata pci_mmcfg_resources_inserted;
>  
> +static struct acpi_mcfg_allocation __initdata *mcfg_table;
> +static int __initdata mcfg_table_entry_size;
> +
Yinghai is working on PCI root host bridge hotplug. One of his work is to provide
online/offline support to non-hotplug-capable PCI host bridges. Here online/offline
means enable/disable PCI host bridge without physical hotplug operations.

With that change, query_acpi_mcfg_table() may be called at runtime for host bridges
without _CBA method, so mcfg_table shouldn't be __initdata.

Suggest to call acpi_sfi_table_parse() directly for simplicity in query_acpi_mcfg_table()
instead of cache MMCFG info in mcfg_table.

>  LIST_HEAD(pci_mmcfg_list);
>  
>  static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
> @@ -522,6 +525,25 @@ static int __init acpi_mcfg_check_entry(
>  	return -EINVAL;
>  }
>  
> +u64 query_acpi_mcfg_table(int segment, int start)
> +{
> +	u64 base_addr = 0;
> +	int i;
> +
> +	if (!mcfg_table)
> +		return 0;
> +
> +	for (i = 0; i < mcfg_table_entry_size; i++) {
> +		if (segment == mcfg_table[i].pci_segment &&
> +			start == mcfg_table[i].start_bus_number) {
> +			base_addr = mcfg_table[i].address;
> +			break;
> +		}
> +	}
> +
> +	return base_addr;
> +}
It should check the MMCFG item contains [(segment, start), (segment, end)]
instead of "start == mcfg_table[i].start_bus_number".
We have observed many systems which have several PCI host bridges in segment 0
and MMCFG table only reports one entry for bus 0-255 on segment 0.
The above code can't support such a system.

> +
>  static int __init pci_parse_mcfg(struct acpi_table_header *header)
>  {
>  	struct acpi_table_mcfg *mcfg;
> @@ -551,19 +573,19 @@ static int __init pci_parse_mcfg(struct 
>  	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) {
> -			printk(KERN_WARNING PREFIX
> -			       "no memory for MCFG entries\n");
> -			free_all_mmcfg();
> -			return -ENOMEM;
> -		}
>  	}
>  
> +	/* populate mcfg_table */
> +	mcfg_table = kzalloc(sizeof(struct acpi_mcfg_allocation) * entries,
> +			     GFP_KERNEL);
> +	if (!mcfg_table)
> +		return -ENOMEM;
> +	memcpy(mcfg_table, cfg_table,
> +	sizeof(struct acpi_mcfg_allocation) * entries);
> +	mcfg_table_entry_size = entries;
> +
The above change will break the pcibios_last_bus logic. The MMCFG initialization sequence
is something like:
1) pci_mmcfg_early_init()
	->__pci_mmcfg_init()
		->pci_parse_mcfg()
2) initialize ACPICA subsystem
3) pci_mmcfg_late_init()
	->__pci_mmcfg_init()
		->pci_parse_mcfg()
4) bind pci_root driver to pci host bridges
	pci_mmconfig_add()

If pci_parse_mcfg() doesn't call pci_mmconfig_add(), pci_mmcfg_list will always be
NULL until step 4. Then function __pci_mmcfg_init() can't set pcibios_last_bus to
the correct value. As Don has mentioned, it's high risky to cause compatibility issues
if pcibios_last_bus hasn't been setup correctly.

>  	return 0;
>  }
>  
> @@ -589,9 +611,6 @@ static void __init __pci_mmcfg_init(int 
>  	if (!known_bridge)
>  		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
>  
> -	if (list_empty(&pci_mmcfg_list))
> -		return;
> -
This change will always use MMCFG as the mechanism to access PCI extended configuration
space, then it will break some AMD platforms which should use pci_direct_conf1 to access
extend configuration space. Please refer to pci_direct_init() in arch/x86/pci/direct.c

>  	if (pcibios_last_bus < 0) {
>  		const struct pci_mmcfg_region *cfg;
>  
> @@ -641,6 +660,12 @@ static int __init pci_mmcfg_late_insert_
>  	 */
>  	pci_mmcfg_insert_resources();
>  
> +	/*
> +	 * MCFG table should not be reffered to any longer
> +	 */
> +	kfree(mcfg_table);
> +	mcfg_table = NULL;
> +
>  	return 0;
>  }
>  
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Taku Izumi - April 27, 2012, 6:17 a.m.
Hi Jian, Yinghai,

 Thank you your comment and review.

On Thu, 26 Apr 2012 23:04:33 +0800
Jiang Liu <liuj97@gmail.com> wrote:

> Hi Taku,
> 	Thanks for following this up. Please refer to inline comments below.
> I feel there are still some concerns from Don about the change proposed by
> Bjorn. And I haven't found a solution to address Don's concerns yet. So it
> would be better for us to hold on this for a while.
> 
> 	BTW, is it OK to split the task into two steps? 

   Sure.

> 1) enhance mmcfg to support host bridge hotplug.
> 2) refine the mmcfg setup logic.
> Seems it's more realistic for us to reach an agreement for task 1 in a short time,
> but there is still much work ahead for task 2.

  I agree with you.
  To achive task 1, your V4 should is good enough, but
  I found a problem in your patchset.

  When a hotpluggable hostbridge is found at boot time, its MCFG information should be 
  provided via _CBA method, and will added at the following timing:

         arch_acpi_pci_root_add()
            + pci_mmconfig_insert()
              + insert_resource()

  But at boot time, all entries in pci_mmcfg_list collection will added at the following timing:

        late_initcall
           + pci_mmcfg_late_insert_resources()
             + pci_mmcfg_insert_resources()
               + insert_resource()

  So, MCFG information of hotpluggable hostbridges which exist at boot time will fail to 
  add at this timing.

+int __devinit pci_mmconfig_insert(int segment, int start, int end, u64 addr)
+{
+	int rc = -EINVAL;
+	struct pci_mmcfg_region *cfg = NULL;
+
+	if (segment < 0 || segment > USHRT_MAX ||
+	    start < 0 || start > 255 || end < start || end > 255)
+		return rc;
+
+	mutex_lock(&pci_mmcfg_lock);
+	cfg = pci_mmconfig_lookup(segment, start);
+	if (cfg) {
+		if (cfg->start_bus <= start && cfg->end_bus >= end) {
+			rc = -EEXIST;
+		} else {
+			printk(KERN_WARNING PREFIX
+			       "MMCONFIG for domain %04x [bus %02x-%02x] "
+			       "conflicts with domain %04x [bus %02x-%02x]\n",
+			       segment, start, end,
+			       cfg->segment, cfg->start_bus, cfg->end_bus);
+		}
+		goto out;
+	}
+	if (!addr)
+		goto out;
+
+	cfg = pci_mmconfig_alloc(segment, start, end, addr);
+	if (cfg == NULL) {
+		rc = -ENOMEM;
+	} else if (!pci_mmcfg_check_reserved(cfg, 0)) {
+		printk(KERN_WARNING PREFIX
+		       "MMCONFIG for domain %04x [bus %02x-%02x] "
+		       "isn't reserved\n", segment, start, end);
+	} else if (insert_resource(&iomem_resource, &cfg->res)) {

          I think the following is better.

          else if (pci_mmcfg_resources_inserted &&
                   insert_resource(&iomem_resource, &cfg->res)) {


+		rc = -EBUSY;
+		printk(KERN_WARNING PREFIX
+		       "failed to insert resource for domain "
+		       "%04x [bus %02x-%02x]\n", segment, start, end);
+	} else if (pci_mmcfg_arch_map(cfg)) {
+		rc = -EBUSY;


  Could you please fix this?


Best regards,
Taku Izumi

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

Index: bjorn-next/arch/x86/include/asm/pci_x86.h
===================================================================
--- bjorn-next.orig/arch/x86/include/asm/pci_x86.h
+++ bjorn-next/arch/x86/include/asm/pci_x86.h
@@ -100,6 +100,7 @@  struct pci_raw_ops {
 extern const struct pci_raw_ops *raw_pci_ops;
 extern const struct pci_raw_ops *raw_pci_ext_ops;
 
+extern const struct pci_raw_ops pci_mmcfg;
 extern const struct pci_raw_ops pci_direct_conf1;
 extern bool port_cf9_safe;
 
@@ -140,6 +141,7 @@  extern void pci_mmcfg_arch_unmap(struct 
 extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
 extern int __devinit pci_mmconfig_add(int seg, int start, int end, u64 addr);
 extern int pci_mmconfig_delete(int seg, int start, int end);
+extern u64 query_acpi_mcfg_table(int segment, int start);
 extern struct list_head pci_mmcfg_list;
 
 #define PCI_MMCFG_BUS_OFFSET(bus)      ((bus) << 20)
Index: bjorn-next/arch/x86/pci/acpi.c
===================================================================
--- bjorn-next.orig/arch/x86/pci/acpi.c
+++ bjorn-next/arch/x86/pci/acpi.c
@@ -4,6 +4,7 @@ 
 #include <linux/irq.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <linux/pci-acpi.h>
 #include <asm/numa.h>
 #include <asm/pci_x86.h>
 
@@ -461,6 +462,50 @@  struct pci_bus * __devinit pci_acpi_scan
 	return bus;
 }
 
+
+int __devinit arch_acpi_pci_root_add(struct acpi_pci_root *root)
+{
+	int result = 0;
+	acpi_status status;
+	unsigned long long base_addr = 0;
+
+	/* MMCFG not in use */
+	if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
+		return result;
+
+	/* Evaluate _CBA */
+	status = acpi_evaluate_integer(root->device->handle, METHOD_NAME__CBA,
+				       NULL, &base_addr);
+	if (ACPI_FAILURE(status)) {
+		/* search MCFG table */
+		base_addr = query_acpi_mcfg_table(root->segment,
+						  root->secondary.start);
+
+	}
+
+	/* add MMCFG region */
+	if (base_addr) {
+		if (pci_mmconfig_add(root->segment, root->secondary.start,
+					root->secondary.end, base_addr)) {
+			printk(KERN_ERR
+				"can't add MMCFG information for Bus "
+				"%04x:%02x\n",
+				root->segment,
+				(unsigned int)root->secondary.start);
+		}
+	} else {
+		result = -ENODEV;
+	}
+
+	return result;
+}
+
+void arch_acpi_pci_root_remove(struct acpi_pci_root *root)
+{
+	pci_mmconfig_delete(root->segment, root->secondary.start,
+				root->secondary.end);
+}
+
 int __init pci_acpi_init(void)
 {
 	struct pci_dev *dev = NULL;
Index: bjorn-next/arch/x86/pci/mmconfig_32.c
===================================================================
--- bjorn-next.orig/arch/x86/pci/mmconfig_32.c
+++ bjorn-next/arch/x86/pci/mmconfig_32.c
@@ -126,7 +126,7 @@  static int pci_mmcfg_write(unsigned int 
 	return 0;
 }
 
-static const struct pci_raw_ops pci_mmcfg = {
+const struct pci_raw_ops pci_mmcfg = {
 	.read =		pci_mmcfg_read,
 	.write =	pci_mmcfg_write,
 };
Index: bjorn-next/arch/x86/pci/mmconfig_64.c
===================================================================
--- bjorn-next.orig/arch/x86/pci/mmconfig_64.c
+++ bjorn-next/arch/x86/pci/mmconfig_64.c
@@ -90,7 +90,7 @@  static int pci_mmcfg_write(unsigned int 
 	return 0;
 }
 
-static const struct pci_raw_ops pci_mmcfg = {
+const struct pci_raw_ops pci_mmcfg = {
 	.read =		pci_mmcfg_read,
 	.write =	pci_mmcfg_write,
 };
Index: bjorn-next/drivers/acpi/pci_root.c
===================================================================
--- bjorn-next.orig/drivers/acpi/pci_root.c
+++ bjorn-next/drivers/acpi/pci_root.c
@@ -449,6 +449,15 @@  out:
 }
 EXPORT_SYMBOL(acpi_pci_osc_control_set);
 
+int __weak arch_acpi_pci_root_add(struct acpi_pci_root *root)
+{
+	return 0;
+}
+
+void __weak arch_acpi_pci_root_remove(struct acpi_pci_root *root)
+{
+}
+
 static int __devinit acpi_pci_root_add(struct acpi_device *device)
 {
 	unsigned long long segment, bus;
@@ -505,6 +514,11 @@  static int __devinit acpi_pci_root_add(s
 	strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
 	device->driver_data = root;
 
+	if (arch_acpi_pci_root_add(root)) {
+		result = -ENODEV;
+		goto end;
+	}
+
 	/*
 	 * All supported architectures that use ACPI have support for
 	 * PCI domains, so we indicate this in _OSC support capabilities.
@@ -627,6 +641,7 @@  static int __devinit acpi_pci_root_add(s
 end:
 	if (!list_empty(&root->node))
 		list_del(&root->node);
+	arch_acpi_pci_root_remove(root);
 	kfree(root);
 	return result;
 }
Index: bjorn-next/include/acpi/acnames.h
===================================================================
--- bjorn-next.orig/include/acpi/acnames.h
+++ bjorn-next/include/acpi/acnames.h
@@ -62,6 +62,7 @@ 
 #define METHOD_NAME__AEI        "_AEI"
 #define METHOD_NAME__PRW        "_PRW"
 #define METHOD_NAME__SRS        "_SRS"
+#define METHOD_NAME__CBA	"_CBA"
 
 /* Method names - these methods must appear at the namespace root */
 
Index: bjorn-next/include/linux/pci-acpi.h
===================================================================
--- bjorn-next.orig/include/linux/pci-acpi.h
+++ bjorn-next/include/linux/pci-acpi.h
@@ -18,6 +18,9 @@  extern acpi_status pci_acpi_add_pm_notif
 					     struct pci_dev *pci_dev);
 extern acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev);
 
+int arch_acpi_pci_root_add(struct acpi_pci_root *root);
+void arch_acpi_pci_root_remove(struct acpi_pci_root *root);
+
 static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
 {
 	struct pci_bus *pbus = pdev->bus;
Index: bjorn-next/arch/x86/pci/mmconfig-shared.c
===================================================================
--- bjorn-next.orig/arch/x86/pci/mmconfig-shared.c
+++ bjorn-next/arch/x86/pci/mmconfig-shared.c
@@ -28,6 +28,9 @@ 
 /* Indicate if the mmcfg resources have been placed into the resource table. */
 static int __initdata pci_mmcfg_resources_inserted;
 
+static struct acpi_mcfg_allocation __initdata *mcfg_table;
+static int __initdata mcfg_table_entry_size;
+
 LIST_HEAD(pci_mmcfg_list);
 
 static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
@@ -522,6 +525,25 @@  static int __init acpi_mcfg_check_entry(
 	return -EINVAL;
 }
 
+u64 query_acpi_mcfg_table(int segment, int start)
+{
+	u64 base_addr = 0;
+	int i;
+
+	if (!mcfg_table)
+		return 0;
+
+	for (i = 0; i < mcfg_table_entry_size; i++) {
+		if (segment == mcfg_table[i].pci_segment &&
+			start == mcfg_table[i].start_bus_number) {
+			base_addr = mcfg_table[i].address;
+			break;
+		}
+	}
+
+	return base_addr;
+}
+
 static int __init pci_parse_mcfg(struct acpi_table_header *header)
 {
 	struct acpi_table_mcfg *mcfg;
@@ -551,19 +573,19 @@  static int __init pci_parse_mcfg(struct 
 	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) {
-			printk(KERN_WARNING PREFIX
-			       "no memory for MCFG entries\n");
-			free_all_mmcfg();
-			return -ENOMEM;
-		}
 	}
 
+	/* populate mcfg_table */
+	mcfg_table = kzalloc(sizeof(struct acpi_mcfg_allocation) * entries,
+			     GFP_KERNEL);
+	if (!mcfg_table)
+		return -ENOMEM;
+	memcpy(mcfg_table, cfg_table,
+	sizeof(struct acpi_mcfg_allocation) * entries);
+	mcfg_table_entry_size = entries;
+
 	return 0;
 }
 
@@ -589,9 +611,6 @@  static void __init __pci_mmcfg_init(int 
 	if (!known_bridge)
 		acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
 
-	if (list_empty(&pci_mmcfg_list))
-		return;
-
 	if (pcibios_last_bus < 0) {
 		const struct pci_mmcfg_region *cfg;
 
@@ -641,6 +660,12 @@  static int __init pci_mmcfg_late_insert_
 	 */
 	pci_mmcfg_insert_resources();
 
+	/*
+	 * MCFG table should not be reffered to any longer
+	 */
+	kfree(mcfg_table);
+	mcfg_table = NULL;
+
 	return 0;
 }