From a2ebb827958a4ab3577443f89037f229683c644a Mon Sep 17 00:00:00 2001
From: Bjorn Helgaas <bhelgaas@google.com>
Date: Fri, 28 Oct 2011 16:25:50 -0600
Subject: [PATCH] PCI: add pci_scan_root_bus() that accepts resource list

"Early" and "header" quirks often use incorrect bus resources because they
see the default resources assigned by pci_create_bus(), before the
architecture fixes them up (typically in pcibios_fixup_bus()).  Regions
reserved by these quirks end up with the wrong parents.

Here's the standard path for scanning a PCI root bus:

  pci_scan_bus or pci_scan_bus_parented
    pci_create_bus                     <-- A create with default resources
    pci_scan_child_bus
      pci_scan_slot
        pci_scan_single_device
          pci_scan_device
            pci_setup_device
              pci_fixup_device(early)  <-- B
          pci_device_add
            pci_fixup_device(header)   <-- C
      pcibios_fixup_bus                <-- D fill in correct resources

Early and header quirks at B and C use the default (incorrect) root bus
resources rather than those filled in at D.

This patch adds a new pci_scan_root_bus() function that sets the bus
resources correctly from a supplied list of resources.

I intend to remove pci_scan_bus() and pci_scan_bus_parented() after
fixing all callers.

Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/pci/probe.c | 15 +++++++++++++++
 include/linux/pci.h |  3 +++
 2 files changed, 18 insertions(+)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 89ecded0581b..7fc7e14118cc 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1608,6 +1608,21 @@ err_out:
 	return NULL;
 }
 
+struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
+		struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+	struct pci_bus *b;
+
+	b = pci_create_root_bus(parent, bus, ops, sysdata, resources);
+	if (!b)
+		return NULL;
+
+	b->subordinate = pci_scan_child_bus(b);
+	pci_bus_add_devices(b);
+	return b;
+}
+EXPORT_SYMBOL(pci_scan_root_bus);
+
 struct pci_bus *pci_create_bus(struct device *parent,
 		int bus, struct pci_ops *ops, void *sysdata)
 {
diff --git a/include/linux/pci.h b/include/linux/pci.h
index eacb1e51e11b..5102d74f6bfc 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -673,6 +673,9 @@ static inline struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *o
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 				    struct pci_ops *ops, void *sysdata,
 				    struct list_head *resources);
+struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus,
+					     struct pci_ops *ops, void *sysdata,
+					     struct list_head *resources);
 struct pci_bus *pci_create_bus(struct device *parent, int bus,
 			       struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
-- 
2.34.1