diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2011-06-19 14:09:20 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2011-06-20 23:49:47 -0400 |
commit | 096a9b10e68eb1b2087cc30e4fa6d333b6a03d72 (patch) | |
tree | 851e739237debfe5bf022e213536c0f143b3408a | |
parent | baac6b6e1a3fc2d5e662e685a6bbe196292c2522 (diff) | |
download | seabios-096a9b10e68eb1b2087cc30e4fa6d333b6a03d72.zip seabios-096a9b10e68eb1b2087cc30e4fa6d333b6a03d72.tar.gz seabios-096a9b10e68eb1b2087cc30e4fa6d333b6a03d72.tar.bz2 |
Find all pci devices at startup and cache them for future use.
This adds 'struct pci_device' and pci_probe() which will locate and
store all found PCI devices in the system at startup.
-rw-r--r-- | src/pci.c | 60 | ||||
-rw-r--r-- | src/pci.h | 20 | ||||
-rw-r--r-- | src/post.c | 1 |
3 files changed, 81 insertions, 0 deletions
@@ -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) @@ -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; @@ -224,6 +224,7 @@ maininit(void) // Initialize pci pci_setup(); + pci_probe(); pci_path_setup(); smm_init(); |