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@1fe0,0/pci@1,1. Is there a better way?
Other comments?
Signed-off-by: Blue Swirl blauwirbel@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
On Sat, Feb 6, 2010 at 7:49 PM, Blue Swirl blauwirbel@gmail.com wrote:
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@1fe0,0/pci@1,1. Is there a better way?
Lookup using "pci" as node name would stop at first node with matching "name" property value. When we assign "reg" property this can break lookup if there are multiple nodes with the same "name" property value. To resolve path to correct node the node path must be reloaded after "reg" property is assigned. "get-package-path" should work.
On Sun, Feb 7, 2010 at 10:05 AM, Igor Kovalenko igor.v.kovalenko@gmail.com wrote:
On Sat, Feb 6, 2010 at 7:49 PM, Blue Swirl blauwirbel@gmail.com wrote:
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@1fe0,0/pci@1,1. Is there a better way?
Lookup using "pci" as node name would stop at first node with matching "name" property value. When we assign "reg" property this can break lookup if there are multiple nodes with the same "name" property value. To resolve path to correct node the node path must be reloaded after "reg" property is assigned. "get-package-path" should work.
Nice. With this change I got rid of one class of problems. There are still some bugs: OpenBIOS for Sparc64 Initializing PCI devices... 0:0.0 - 108e:a000 - //pci - 0:1.0 - 108e:5000 - /pci@1fe,0/pci - 1:0.0 - 108e:5000 - /pci@1fe,0/pci@1/pci - 2:0.0 - 1011:26 - /pci@1fe,0/pci@1/pci@0/pci-bridge - 2:1.0 - 1095:646 - /pci@1fe,0/pci@1/pci@0/pci-ata - 1:1.0 - 108e:1000 - /pci@1fe,0/pci@1/ebus - 0:2.0 - 1234:1111 - /pci@1fe,0/QEMU,VGA - 0:3.0 - 10ec:8029 - /pci@1fe,0/NE2000 - Configuration device id QEMU version 1 machine id 0 kernel addr 404000 size 404d61 kernel cmdline root=/dev/ram -p console=prom init=/sbin/init of_debug=3 ofpci_debug=1 CPUs: 1 x SUNW,UltraSPARC-II UUID: 00000000-0000-0000-0000-000000000000 Welcome to OpenBIOS v1.0 built on Jan 29 2010 18:24 Type 'help' for detailed information
0 > show-devs ffe1d2a0 / ffe1d478 /aliases ffe1d5a0 /openprom (BootROM) ffe28268 /openprom/client-services ffe1d858 /options ffe1d938 /chosen ffe1dad8 /builtin ffe1dc00 /builtin/console ffe27d30 /packages ffe29a08 /packages/disk-label ffe2a108 /packages/cmdline ffe2b420 /packages/deblocker ffe2ba78 /packages/misc-files ffe2c0a0 /packages/sun-parts ffe2c360 /packages/elf-loader ffe2a708 /memory@0,0 (memory) ffe2a868 /virtual-memory ffe2c4c0 /pci@1fe,0 (pci) ffe2cd60 /pci@1fe,0/pci@1 (pci) ffe2d408 /pci@1fe,0/pci@1/pci@0 (pci) ffe2da90 /pci@1fe,0/pci@1/pci@0 ffe2db70 /pci@1fe,0/pci@1/pci@0/pci-bridge@20000 (pci) ffe2e1e8 /pci@1fe,0/pci@1/pci@0 ffe2e2c8 /pci@1fe,0/pci@1/pci@0/pci-ata@20800 (pci-ide) ffe2e900 /pci@1fe,0/pci@1/pci@0 ffe2e9e0 /pci@1fe,0/pci@1/pci@0/pci-ata ffe2eac0 /pci@1fe,0/pci@1/pci@0/pci-ata/ide0@0 (ide) ffe2ee40 /pci@1fe,0/pci@1/pci@0 ffe2ef20 /pci@1fe,0/pci@1/pci@0/pci-ata ffe2f000 /pci@1fe,0/pci@1/pci@0/pci-ata/ide0@0 ffe2f0e0 /pci@1fe,0/pci@1/pci@0/pci-ata/ide0@0/disk@0 (block) ffe2f838 /pci@1fe,0/pci@1/pci@0 ffe2f918 /pci@1fe,0/pci@1/pci@0/pci-ata ffe2f9f8 /pci@1fe,0/pci@1/pci@0/pci-ata/ide1@0 (ide) ffe2fd78 /pci@1fe,0/pci@1/pci@0 ffe2fe58 /pci@1fe,0/pci@1/pci@0/pci-ata ffe2ff38 /pci@1fe,0/pci@1/pci@0/pci-ata/ide1@0 ffe30018 /pci@1fe,0/pci@1/pci@0/pci-ata/ide1@0/cdrom@0 (block) ffe30770 /pci@1fe,0/pci@1/ebus@1 (pci) ffe30df0 /pci@1fe,0/pci@1/ebus@1/fdthree@0 (block) ffe312f0 /pci@1fe,0/pci@1/ebus@1/su@1fe (serial) ffe315f8 /pci@1fe,0/pci@1/ebus@1/kb_ps2 (keyboard) ffe318f8 /pci@1fe,0/QEMU,VGA@2 (display) ffe320b0 /pci@1fe,0/NE2000@3 (network) ffe32690 /SUNW,UltraSPARC-II (cpu) ffe32a78 /SUNW,UltraSPARC-II/mmu ok 0 > QEMU 0.12.50 monitor - type 'help' for more information (qemu) info pci Bus 0, device 0, function 0: Host bridge: PCI device 108e:a000 BUS 0. secondary bus 1. subordinate bus 255. IO range [0x0000, 0x0fff] memory range [0x0f100000, 0x000fffff] prefetchable memory range [0x0f200000, 0x001fffff] id "" Bus 1, device 0, function 0: PCI bridge: PCI device 108e:5000 BUS 1. secondary bus 2. subordinate bus 4. IO range [0x0000, 0x0fff] memory range [0x00000000, 0x000fffff] prefetchable memory range [0x00000000, 0x000fffff] id "" Bus 2, device 0, function 0: PCI bridge: PCI device 1011:0026 BUS 2. secondary bus 3. subordinate bus 3. IO range [0x0000, 0x0fff] memory range [0x00000000, 0x000fffff] prefetchable memory range [0x00000000, 0x000fffff] id "" Bus 2, device 1, function 0: IDE controller: PCI device 1095:0646 IRQ 1. BAR0: I/O at 0x0400 [0x0407]. BAR1: I/O at 0x0480 [0x0483]. BAR2: I/O at 0x0500 [0x0507]. BAR3: I/O at 0x0580 [0x0583]. BAR4: I/O at 0x0600 [0x060f]. id "" Bus 1, device 1, function 0: Bridge: PCI device 108e:1000 BAR0: 32 bit memory at 0xffffffffffffffff [0x00fffffe]. BAR1: 32 bit memory at 0xffffffffffffffff [0x007ffffe]. id "" Bus 0, device 1, function 0: PCI bridge: PCI device 108e:5000 BUS 0. secondary bus 1. subordinate bus 5. IO range [0x0000, 0x0fff] memory range [0x00000000, 0x000fffff] prefetchable memory range [0x00000000, 0x000fffff] id "" Bus 1, device 0, function 0: PCI bridge: PCI device 108e:5000 BUS 1. secondary bus 2. subordinate bus 4. IO range [0x0000, 0x0fff] memory range [0x00000000, 0x000fffff] prefetchable memory range [0x00000000, 0x000fffff] id "" Bus 2, device 0, function 0: PCI bridge: PCI device 1011:0026 BUS 2. secondary bus 3. subordinate bus 3. IO range [0x0000, 0x0fff] memory range [0x00000000, 0x000fffff] prefetchable memory range [0x00000000, 0x000fffff] id "" Bus 2, device 1, function 0: IDE controller: PCI device 1095:0646 IRQ 1. BAR0: I/O at 0x0400 [0x0407]. BAR1: I/O at 0x0480 [0x0483]. BAR2: I/O at 0x0500 [0x0507]. BAR3: I/O at 0x0580 [0x0583]. BAR4: I/O at 0x0600 [0x060f]. id "" Bus 1, device 1, function 0: Bridge: PCI device 108e:1000 BAR0: 32 bit memory at 0xffffffffffffffff [0x00fffffe]. BAR1: 32 bit memory at 0xffffffffffffffff [0x007ffffe]. id "" Bus 0, device 2, function 0: VGA controller: PCI device 1234:1111 BAR0: 32 bit prefetchable memory at 0x02800000 [0x02ffffff]. id "" Bus 0, device 3, function 0: Ethernet controller: PCI device 10ec:8029 IRQ 3. BAR0: I/O at 0x0700 [0x07ff]. id ""
Output from OpenBIOS's PCI probe looks OK, "show-devs" output looks strange and "info pci" output is schizophrenic.
[...]
ffe30770 /pci@1fe,0/pci@1/ebus@1 (pci) [...] Output from OpenBIOS's PCI probe looks OK, "show-devs" output looks strange and "info pci" output is schizophrenic.
Ebus shouldn't be showing up as a "pci"; the addressing under it definitely does not use PCI semantics.
ffe315f8 /pci@1fe,0/pci@1/ebus@1/kb_ps2 (keyboard)
The unit address is missing here, which is a little wierd.
On Sun, Feb 7, 2010 at 8:24 PM, Tarl Neustaedter Tarl.Neustaedter@sun.com wrote:
[...]
ffe30770 /pci@1fe,0/pci@1/ebus@1 (pci) [...] Output from OpenBIOS's PCI probe looks OK, "show-devs" output looks strange and "info pci" output is schizophrenic.
Ebus shouldn't be showing up as a "pci"; the addressing under it definitely does not use PCI semantics.
Fixed, there was a bug in the PCI database.
ffe315f8 /pci@1fe,0/pci@1/ebus@1/kb_ps2 (keyboard)
The unit address is missing here, which is a little wierd.
I added the "reg" property, now it shows up: ffe2f088 /pci@1fe,0/pci@1/pci@1,1/ebus@3/kb_ps2@0 (serial)