Find all pci devices at startup and cache them for future use.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 19 Jun 2011 18:09:20 +0000 (14:09 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Tue, 21 Jun 2011 03:49:47 +0000 (23:49 -0400)
This adds 'struct pci_device' and pci_probe() which will locate and
store all found PCI devices in the system at startup.

src/pci.c
src/pci.h
src/post.c

index c95baca1c05123cee3fca151daa6b872f2d43c47..f0953e9688152f34eb2ae61d59306aacb493c201 100644 (file)
--- a/src/pci.c
+++ b/src/pci.c
@@ -103,6 +103,66 @@ pci_next(int bdf, int *pmax)
     return bdf;
 }
 
+struct pci_device *PCIDevices;
+int MaxPCIBus;
+
+void
+pci_probe(void)
+{
+    int rootbuses = 0;
+    struct pci_device *busdevs[256];
+    memset(busdevs, 0, sizeof(busdevs));
+
+    struct pci_device **pprev = &PCIDevices;
+    u8 lastbus = 0;
+    int bdf, max;
+    foreachbdf(bdf, max) {
+        // Create new pci_device struct and add to list.
+        struct pci_device *dev = malloc_tmp(sizeof(*dev));
+        if (!dev) {
+            warn_noalloc();
+            return;
+        }
+        memset(dev, 0, sizeof(*dev));
+        *pprev = dev;
+        pprev = &dev->next;
+
+        // Find parent device.
+        u8 bus = pci_bdf_to_bus(bdf), rootbus;
+        struct pci_device *parent = busdevs[bus];
+        if (!parent) {
+            if (bus != lastbus)
+                rootbuses++;
+            lastbus = bus;
+            rootbus = rootbuses;
+        } else {
+            rootbus = parent->rootbus;
+        }
+        if (bus > MaxPCIBus)
+            MaxPCIBus = bus;
+
+        // Populate pci_device info.
+        dev->bdf = bdf;
+        dev->parent = parent;
+        dev->rootbus = rootbus;
+        u32 vendev = pci_config_readl(bdf, PCI_VENDOR_ID);
+        dev->vendor = vendev & 0xffff;
+        dev->device = vendev >> 16;
+        u32 classrev = pci_config_readl(bdf, PCI_CLASS_REVISION);
+        dev->class = classrev >> 16;
+        dev->prog_if = classrev >> 8;
+        dev->revision = classrev & 0xff;
+        dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE);
+        u8 v = dev->header_type & 0x7f;
+        if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) {
+            u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS);
+            dev->secondary_bus = secbus;
+            if (secbus > bus && !busdevs[secbus])
+                busdevs[secbus] = dev;
+        }
+    }
+}
+
 // Find a vga device with legacy address decoding enabled.
 int
 pci_find_vga(void)
index 6e9cbf0fddb6f86029e274839925eec5b028c362..f1d84edc6ea1590699229c4e568475f5e6e2a633 100644 (file)
--- a/src/pci.h
+++ b/src/pci.h
@@ -47,6 +47,26 @@ int pci_find_vga(void);
 int pci_find_device(u16 vendid, u16 devid);
 int pci_find_class(u16 classid);
 
+struct pci_device {
+    u16 bdf;
+    u8 rootbus;
+    struct pci_device *next;
+    struct pci_device *parent;
+
+    // Configuration space device information
+    u16 vendor, device;
+    u16 class;
+    u8 prog_if, revision;
+    u8 header_type;
+    u8 secondary_bus;
+};
+extern struct pci_device *PCIDevices;
+extern int MaxPCIBus;
+void pci_probe(void);
+
+#define foreachpci(PCI)                         \
+    for (PCI=PCIDevices; PCI; PCI=PCI->next)
+
 #define PP_ROOT      (1<<17)
 #define PP_PCIBRIDGE (1<<18)
 extern int *PCIpaths;
index 70d98a67224b71d091d7ec69e74f9d4b47c0689a..d8f4acf1587b75529a5f29c84d534ef931ea9497 100644 (file)
@@ -224,6 +224,7 @@ maininit(void)
 
     // Initialize pci
     pci_setup();
+    pci_probe();
     pci_path_setup();
     smm_init();