aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2011-06-19 14:09:20 -0400
committerKevin O'Connor <kevin@koconnor.net>2011-06-20 23:49:47 -0400
commit096a9b10e68eb1b2087cc30e4fa6d333b6a03d72 (patch)
tree851e739237debfe5bf022e213536c0f143b3408a
parentbaac6b6e1a3fc2d5e662e685a6bbe196292c2522 (diff)
downloadseabios-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.c60
-rw-r--r--src/pci.h20
-rw-r--r--src/post.c1
3 files changed, 81 insertions, 0 deletions
diff --git a/src/pci.c b/src/pci.c
index c95baca..f0953e9 100644
--- 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)
diff --git a/src/pci.h b/src/pci.h
index 6e9cbf0..f1d84ed 100644
--- 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;
diff --git a/src/post.c b/src/post.c
index 70d98a6..d8f4acf 100644
--- a/src/post.c
+++ b/src/post.c
@@ -224,6 +224,7 @@ maininit(void)
// Initialize pci
pci_setup();
+ pci_probe();
pci_path_setup();
smm_init();