Only touch PCI functions > 0 on multi-function devices; rescan max pci each time.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 30 Nov 2008 01:31:49 +0000 (20:31 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 30 Nov 2008 01:31:49 +0000 (20:31 -0500)
Some single-function devices will respond to all sub-functions - and
    this confuses things.  So, when scanning the PCI bus make sure to
    only touch function 0 on single-function devices.
Since the bus scanning code is necessarily complex now, we might as
    well implement max bus detection inline with all pci scans.  So,
    there is no need to scan for the max bus at startup.

src/optionroms.c
src/pci.c
src/pci.h
src/pcibios.c
src/pciinit.c
src/post.c

index 1c1b7911392464af76c7f4b9d37aada305eac85b..0d5f34b4443f33285a36b1cda66ab7602019a5ff 100644 (file)
@@ -271,9 +271,8 @@ optionrom_setup()
         }
     } else {
         // Find and deploy PCI roms.
         }
     } else {
         // Find and deploy PCI roms.
-        int max = GET_VAR(CS, MaxBDF);
-        int bdf;
-        for (bdf=0; bdf < max; bdf++) {
+        int bdf, max;
+        foreachpci(bdf, max, 0) {
             u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
             if (v == 0x0000 || v == 0xffff || v == PCI_CLASS_DISPLAY_VGA)
                 continue;
             u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
             if (v == 0x0000 || v == 0xffff || v == PCI_CLASS_DISPLAY_VGA)
                 continue;
index 91a7ca5f3d73047fdef29b0182a8dc2070d5c212..20838bffba66d2f1811d5808b10bd6126f6520d8 100644 (file)
--- a/src/pci.c
+++ b/src/pci.c
@@ -5,7 +5,7 @@
 //
 // This file may be distributed under the terms of the GNU GPLv3 license.
 
 //
 // This file may be distributed under the terms of the GNU GPLv3 license.
 
-#include "pci.h" // MaxBDF
+#include "pci.h" // pci_config_writel
 #include "ioport.h" // outl
 #include "util.h" // dprintf
 #include "config.h" // CONFIG_*
 #include "ioport.h" // outl
 #include "util.h" // dprintf
 #include "config.h" // CONFIG_*
@@ -48,37 +48,42 @@ u8 pci_config_readb(u16 bdf, u32 addr)
     return inb(PORT_PCI_DATA + (addr & 3));
 }
 
     return inb(PORT_PCI_DATA + (addr & 3));
 }
 
-#if MODE16
-int MaxBDF VISIBLE16 = 0x0100;
-#endif
-
-// Find the maximum bus number.
-void
-pci_bus_setup()
+int
+pci_next(int bdf, int *pmax)
 {
 {
-    dprintf(3, "Scan for max PCI bus\n");
+    if (pci_bdf_to_fn(bdf) == 1
+        && (pci_config_readb(bdf-1, PCI_HEADER_TYPE) & 0x80) == 0)
+        // Last found device wasn't a multi-function device - skip to
+        // the next device.
+        bdf += 7;
 
 
-    int max = 0x0100;
-    int bdf;
-    for (bdf=0; bdf < max; bdf++) {
-        u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
-        if (v == 0xffffffff || v == 0x00000000
-            || v == 0x0000ffff || v == 0xffff0000)
-            // No device present.
-            continue;
-        v = pci_config_readb(bdf, PCI_HEADER_TYPE);
-        v &= 0x7f;
-        if (v != PCI_HEADER_TYPE_BRIDGE && v != PCI_HEADER_TYPE_CARDBUS)
-            // Not a bridge
-            continue;
+    int max = *pmax;
+    for (;;) {
+        if (bdf >= max)
+            return -1;
+
+        u16 v = pci_config_readw(bdf, PCI_VENDOR_ID);
+        if (v != 0x0000 && v != 0xffff)
+            // Device is present.
+            break;
+
+        if (pci_bdf_to_fn(bdf) == 0)
+            bdf += 8;
+        else
+            bdf += 1;
+    }
+
+    // Check if found device is a bridge.
+    u32 v = pci_config_readb(bdf, PCI_HEADER_TYPE);
+    v &= 0x7f;
+    if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
         v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
         int newmax = (v & 0xff00) + 0x0100;
         if (newmax > max)
         v = pci_config_readl(bdf, PCI_PRIMARY_BUS);
         int newmax = (v & 0xff00) + 0x0100;
         if (newmax > max)
-            max = newmax;
+            *pmax = newmax;
     }
     }
-    SET_VAR(CS, MaxBDF, max);
 
 
-    dprintf(1, "Found %d PCI buses\n", pci_bdf_to_bus(max));
+    return bdf;
 }
 
 // Search for a device with the specified vendor and device ids.
 }
 
 // Search for a device with the specified vendor and device ids.
@@ -86,9 +91,8 @@ int
 pci_find_device(u16 vendid, u16 devid, int start_bdf)
 {
     u32 id = (devid << 16) | vendid;
 pci_find_device(u16 vendid, u16 devid, int start_bdf)
 {
     u32 id = (devid << 16) | vendid;
-    int max = GET_VAR(CS, MaxBDF);
-    int bdf;
-    for (bdf=start_bdf; bdf < max; bdf++) {
+    int bdf, max;
+    foreachpci(bdf, max, start_bdf) {
         u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
         if (v != id)
             continue;
         u32 v = pci_config_readl(bdf, PCI_VENDOR_ID);
         if (v != id)
             continue;
@@ -102,9 +106,8 @@ pci_find_device(u16 vendid, u16 devid, int start_bdf)
 int
 pci_find_classprog(u32 classprog, int start_bdf)
 {
 int
 pci_find_classprog(u32 classprog, int start_bdf)
 {
-    int max = GET_VAR(CS, MaxBDF);
-    int bdf;
-    for (bdf=start_bdf; bdf < max; bdf++) {
+    int bdf, max;
+    foreachpci(bdf, max, start_bdf) {
         u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
         if ((v>>8) != classprog)
             continue;
         u32 v = pci_config_readl(bdf, PCI_CLASS_REVISION);
         if ((v>>8) != classprog)
             continue;
@@ -118,9 +121,8 @@ pci_find_classprog(u32 classprog, int start_bdf)
 int
 pci_find_class(u16 classid, int start_bdf)
 {
 int
 pci_find_class(u16 classid, int start_bdf)
 {
-    int max = GET_VAR(CS, MaxBDF);
-    int bdf;
-    for (bdf=start_bdf; bdf < max; bdf++) {
+    int bdf, max;
+    foreachpci(bdf, max, start_bdf) {
         u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
         if (v != classid)
             continue;
         u16 v = pci_config_readw(bdf, PCI_CLASS_DEVICE);
         if (v != classid)
             continue;
index a18cfb7e217ee231d924f584aaea16bd44e08eb9..fc39fa0fed3dc249d9fd1244448db18cf2d94e3d 100644 (file)
--- a/src/pci.h
+++ b/src/pci.h
@@ -23,12 +23,15 @@ u32 pci_config_readl(u16 bdf, u32 addr);
 u16 pci_config_readw(u16 bdf, u32 addr);
 u8 pci_config_readb(u16 bdf, u32 addr);
 
 u16 pci_config_readw(u16 bdf, u32 addr);
 u8 pci_config_readb(u16 bdf, u32 addr);
 
-void pci_bus_setup();
 int pci_find_device(u16 vendid, u16 devid, int start_bdf);
 int pci_find_classprog(u32 classprog, int start_bdf);
 int pci_find_class(u16 classid, int start_bdf);
 
 int pci_find_device(u16 vendid, u16 devid, int start_bdf);
 int pci_find_classprog(u32 classprog, int start_bdf);
 int pci_find_class(u16 classid, int start_bdf);
 
-extern int MaxBDF;
+int pci_next(int bdf, int *pmax);
+#define foreachpci(BDF, MAX, START)                     \
+    for (MAX=0x0100, BDF=pci_next((START), &MAX)        \
+         ; BDF >= 0                                     \
+         ; BDF=pci_next(BDF+1, &MAX))
 
 // pirtable.c
 void create_pirtable();
 
 // pirtable.c
 void create_pirtable();
index 65e4a18c0607ea7422fd7b5a64fce57af48dd21a..93cdc46238e98de5fc316776752fc853d132a7d9 100644 (file)
 static void
 handle_1ab101(struct bregs *regs)
 {
 static void
 handle_1ab101(struct bregs *regs)
 {
+    // Find max bus.
+    int bdf, max;
+    foreachpci(bdf, max, 0) {
+    }
+
     regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
     regs->bx = 0x0210; // PCI version 2.10
     regs->al = 0x01; // Flags - "Config Mechanism #1" supported.
     regs->bx = 0x0210; // PCI version 2.10
-    regs->cl = pci_bdf_to_bus(GET_VAR(CS, MaxBDF) - 1);
+    regs->cl = pci_bdf_to_bus(max - 1);
     regs->edx = 0x20494350; // "PCI "
     // XXX - bochs bios code sets edi to point to 32bit code - but no
     // reference to this in spec.
     regs->edx = 0x20494350; // "PCI "
     // XXX - bochs bios code sets edi to point to 32bit code - but no
     // reference to this in spec.
index 9b6e9f64fca58adb825dd9f08d207bdb590cac11..28bee74ff6ddef5aff77acaded9d528278f8173e 100644 (file)
@@ -189,18 +189,6 @@ static void pci_bios_init_device(u16 bdf)
     }
 }
 
     }
 }
 
-static void pci_for_each_device(void (*init_func)(u16 bdf))
-{
-    int max = GET_VAR(CS, MaxBDF);
-    int bdf;
-    for (bdf = 0; bdf < max; bdf++) {
-        u16 vendor_id = pci_config_readw(bdf, PCI_VENDOR_ID);
-        u16 device_id = pci_config_readw(bdf, PCI_DEVICE_ID);
-        if (vendor_id != 0xffff || device_id != 0xffff)
-            init_func(bdf);
-    }
-}
-
 void
 pci_bios_setup(void)
 {
 void
 pci_bios_setup(void)
 {
@@ -214,7 +202,11 @@ pci_bios_setup(void)
     if (pci_bios_bigmem_addr < 0x90000000)
         pci_bios_bigmem_addr = 0x90000000;
 
     if (pci_bios_bigmem_addr < 0x90000000)
         pci_bios_bigmem_addr = 0x90000000;
 
-    pci_for_each_device(pci_bios_init_bridges);
-
-    pci_for_each_device(pci_bios_init_device);
+    int bdf, max;
+    foreachpci(bdf, max, 0) {
+        pci_bios_init_bridges(bdf);
+    }
+    foreachpci(bdf, max, 0) {
+        pci_bios_init_device(bdf);
+    }
 }
 }
index 68a473ce7e1469f5b82dec0c38e16a5aa0473442..3aec90b918a6daa8071134bc7038f02ea4204d27 100644 (file)
@@ -195,7 +195,6 @@ post()
     timer_setup();
     mathcp_setup();
 
     timer_setup();
     mathcp_setup();
 
-    pci_bus_setup();
     smp_probe_setup();
 
     memmap_setup();
     smp_probe_setup();
 
     memmap_setup();