commit 49c92c2d55b3032703b54d81fbffb55b9a865e60
Author: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>
Date:   Thu May 27 00:25:28 2010 +0400

    pci: scan for primary host bridge
    
    - mac99 has pci host bridge at non-zero device address, need to scan for it
    - factor out ob_pci_read_identification to check if pci device is present
    
    Signed-off-by: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>

diff --git a/drivers/pci.c b/drivers/pci.c
index f8d0b41..56ac047 100644
--- a/drivers/pci.c
+++ b/drivers/pci.c
@@ -1074,6 +1074,47 @@ static void ob_configure_pci_bridge(pci_addr addr,
     pci_set_bus_range(config);
 }
 
+static int ob_pci_read_identification(int bus, int devnum, int fn,
+                                 int *p_vid, int *p_did,
+                                 uint8_t *p_class, uint8_t *p_subclass)
+{
+    int vid, did;
+    uint32_t ccode;
+    pci_addr addr;
+
+#ifdef CONFIG_XBOX
+    if (pci_xbox_blacklisted (bus, devnum, fn))
+        return;
+#endif
+    addr = PCI_ADDR(bus, devnum, fn);
+    vid = pci_config_read16(addr, PCI_VENDOR_ID);
+    did = pci_config_read16(addr, PCI_DEVICE_ID);
+
+    if (vid==0xffff || vid==0) {
+        return 0;
+    }
+
+    if (p_vid) {
+        *p_vid = vid;
+    }
+
+    if (p_did) {
+        *p_did = did;
+    }
+
+    ccode = pci_config_read16(addr, PCI_CLASS_DEVICE);
+
+    if (p_class) {
+        *p_class = ccode >> 8;
+    }
+
+    if (p_subclass) {
+        *p_subclass = ccode;
+    }
+
+    return 1;
+}
+
 static void ob_configure_pci_device(const char* parent_path,
         int *bus_num, unsigned long *mem_base, unsigned long *io_base,
         int bus, int devnum, int fn, int *p_is_multi)
@@ -1083,28 +1124,17 @@ static void ob_configure_pci_device(const char* parent_path,
     pci_addr addr;
     pci_config_t config = {};
         const pci_dev_t *pci_dev;
-    uint32_t ccode;
     uint8_t class, subclass, iface;
     int num_bars, rom_bar;
 
     phandle_t phandle = 0;
     int is_host_bridge = 0;
 
-#ifdef CONFIG_XBOX
-    if (pci_xbox_blacklisted (bus, devnum, fn))
-        return;
-#endif
-    addr = PCI_ADDR(bus, devnum, fn);
-    vid = pci_config_read16(addr, PCI_VENDOR_ID);
-    did = pci_config_read16(addr, PCI_DEVICE_ID);
-
-    if (vid==0xffff || vid==0)
+    if (!ob_pci_read_identification(bus, devnum, fn, &vid, &did, &class, &subclass)) {
         return;
+    }
 
-    ccode = pci_config_read16(addr, PCI_CLASS_DEVICE);
-    class = ccode >> 8;
-    subclass = ccode;
-
+    addr = PCI_ADDR(bus, devnum, fn);
     iface = pci_config_read8(addr, PCI_CLASS_PROG);
 
     pci_dev = pci_find_device(class, subclass, iface,
@@ -1212,7 +1242,8 @@ static void ob_configure_pci_device(const char* parent_path,
 
 int ob_pci_init(void)
 {
-    int bus;
+    int bus, devnum, fn;
+    uint8_t class, subclass;
     unsigned long mem_base, io_base;
 
     pci_config_t config = {}; /* host bridge */
@@ -1231,21 +1262,39 @@ int ob_pci_init(void)
 
     bus = 0;
 
-    /* create root node for host PCI bridge */
+    for (devnum = 0; devnum < 32; devnum++) {
+        /* scan only fn 0 */
+        fn = 0;
+
+        if (!ob_pci_read_identification(bus, devnum, fn,
+                                        0, 0, &class, &subclass)) {
+            continue;
+        }
+
+        if (class != PCI_BASE_CLASS_BRIDGE || subclass != PCI_SUBCLASS_BRIDGE_HOST) {
+            continue;
+        }
+
+        /* create root node for host PCI bridge */
 
-    /* configure  */
-    snprintf(config.path, sizeof(config.path), "/pci");
+        /* configure  */
+        snprintf(config.path, sizeof(config.path), "/pci");
 
-    REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle_host);
+        REGISTER_NAMED_NODE_PHANDLE(ob_pci_bus_node, config.path, phandle_host);
 
-    pci_host_set_reg(phandle_host);
+        pci_host_set_reg(phandle_host);
 
-    /* update device path after changing "reg" property */
-    ob_pci_reload_device_path(phandle_host, &config);
+        /* update device path after changing "reg" property */
+        ob_pci_reload_device_path(phandle_host, &config);
 
-    /* we expect host PCI bridge at pci0:0:0 but this may be machine-specific */
+        ob_configure_pci_device(config.path, &bus, &mem_base, &io_base,
+                bus, devnum, fn, 0);
+
+        /* we expect single host PCI bridge
+           but this may be machine-specific */
+        break;
+    }
 
-    ob_configure_pci_device(config.path, &bus, &mem_base, &io_base, 0, 0, 0, 0);
 
     device_end();
 
