[OpenBIOS] [PATCH] Probe PCI buses recursively

Blue Swirl blauwirbel at gmail.com
Sat Feb 6 17:49:04 CET 2010


I tried to get PCI probing work in cases where the devices are behind
multiple bridges. This patch works in many cases (especially current
QEMU PPC/Sparc64 setup), but not if I make some arbitrary changes to
the bridging setup.

The mysterious "?active-package get-package-path" piece resolves the
simple /pci/pci path (which would be identical to any other bridge
found) to /pci at 1fe0,0/pci at 1,1. Is there a better way?

Other comments?

Signed-off-by: Blue Swirl <blauwirbel at gmail.com>
---
 drivers/pci.c |   72 +++++++++++++++++++++++++++++++++++++++++++-------------
 drivers/pci.h |    2 +
 2 files changed, 57 insertions(+), 17 deletions(-)

diff --git a/drivers/pci.c b/drivers/pci.c
index 7d681f1..293509b 100644
--- a/drivers/pci.c
+++ b/drivers/pci.c
@@ -877,8 +877,15 @@ ob_pci_configure(pci_addr addr, pci_config_t
*config, int num_regs, int rom_bar,
         pci_config_write16(addr, PCI_COMMAND, cmd);
 }

-static void ob_scan_pci_bus(int bus, unsigned long *mem_base,
-                            unsigned long *io_base, char **path)
+static struct ob_buses{
+        char *path;
+        pci_addr addr;
+} ob_buses[256];
+
+static int buses, found_host;
+
+static int ob_scan_pci_bus(int bus, unsigned long *mem_base,
+                           unsigned long *io_base)
 {
 	int devnum, fn, is_multi, vid, did;
 	unsigned int htype;
@@ -887,8 +894,9 @@ static void ob_scan_pci_bus(int bus, unsigned long
*mem_base,
         const pci_dev_t *pci_dev;
 	uint32_t ccode;
 	uint8_t class, subclass, iface, rev;
-	int num_bars, rom_bar;
+        int num_bars, rom_bar, child_buses;

+        child_buses = 0;
 	activate_device("/");
 	for (devnum = 0; devnum < 32; devnum++) {
 		is_multi = 0;
@@ -923,10 +931,10 @@ static void ob_scan_pci_bus(int bus, unsigned
long *mem_base,

 			if (pci_dev == NULL || pci_dev->name == NULL)
                             snprintf(config.path, sizeof(config.path),
-				     "%s/pci%x,%x", *path, vid, did);
+				     "%s/pci%x,%x", ob_buses[bus].path, vid, did);
 			else
                             snprintf(config.path, sizeof(config.path),
-				     "%s/%s", *path, pci_dev->name);
+				     "%s/%s", ob_buses[bus].path, pci_dev->name);
 #ifdef CONFIG_DEBUG_PCI
 			printk("%s - ", config.path);
 #endif
@@ -957,37 +965,67 @@ static void ob_scan_pci_bus(int bus, unsigned
long *mem_base,
                             (subclass == PCI_SUBCLASS_BRIDGE_HOST ||
                              subclass == PCI_SUBCLASS_BRIDGE_PCI)) {
 				/* host or bridge */
-				free(*path);
-				*path = strdup(config.path);
+                                fword("?active-package");
+                                fword("get-package-path");
+                                ob_buses[buses].path = pop_fstr_copy();
+                                ob_buses[buses].addr = addr;
+                                pci_config_write8(addr, PCI_PRIMARY_BUS, bus);
+                                pci_config_write8(addr, PCI_SUBORDINATE_BUS,
+                                                  255);
+                                /* we assume the first device found is
+                                   the host */
+                                if (!found_host) {
+                                        pci_config_write8(addr,
+                                                          PCI_SECONDARY_BUS,
+                                                          buses + 1);
+                                } else {
+                                        pci_config_write8(addr,
+                                                          PCI_SECONDARY_BUS,
+                                                          buses);
+                                }
+                                buses++;
+                                child_buses++;
+                                if (!found_host) {
+                                        found_host = 1;
+                                } else {
+                                        int ret;
+
+                                        ret = ob_scan_pci_bus(buses - 1,
+                                                              mem_base,
+                                                              io_base);
+                                        pci_config_write8(addr,
+                                                          PCI_SUBORDINATE_BUS,
+                                                          buses - 1 + ret);
+                                        child_buses += ret;
+                                }
 			}

 		}
 	}
 	device_end();
+        return child_buses;
 }

+/* Recursively scan PCI bus, starting from host bus */
 int ob_pci_init(void)
 {
         int bus;
         unsigned long mem_base, io_base;
-	char *path;

 #ifdef CONFIG_DEBUG_PCI
 	printk("Initializing PCI devices...\n");
 #endif

-	/* brute force bus scan */
-
-	/* Find all PCI bridges */
-
 	mem_base = arch->mem_base;
         /* I/O ports under 0x400 are used by devices mapped at fixed
            location. */
         io_base = arch->io_base + 0x400;
-	path = strdup("");
-	for (bus = 0; bus<0x100; bus++) {
-		ob_scan_pci_bus(bus, &mem_base, &io_base, &path);
-	}
-	free(path);
+
+        ob_buses[0].path = strdup("");
+        ob_scan_pci_bus(0, &mem_base, &io_base);
+
+        for (bus = 0; bus < buses; bus++) {
+                free(ob_buses[bus].path);
+        }
 	return 0;
 }
diff --git a/drivers/pci.h b/drivers/pci.h
index 3ca71f3..fc8968f 100644
--- a/drivers/pci.h
+++ b/drivers/pci.h
@@ -34,7 +34,9 @@
 #define  PCI_HEADER_TYPE_NORMAL 0x00
 #define  PCI_HEADER_TYPE_BRIDGE 0x01
 #define  PCI_HEADER_TYPE_CARDBUS 0x02
+#define PCI_PRIMARY_BUS		0x18
 #define PCI_SECONDARY_BUS	0x19
+#define PCI_SUBORDINATE_BUS	0x1a
 #define PCI_BASE_ADDR_0		0x10
 #define PCI_BASE_ADDR_1		0x14
 #define PCI_BASE_ADDR_2		0x18
-- 
1.6.2.4



More information about the OpenBIOS mailing list