[SeaBIOS] [PATCH 5/6] Introduce PCI child device iterators and use in pciinit.c.
Kevin O'Connor
kevin at koconnor.net
Sat Oct 1 21:05:29 CEST 2011
Replace O(n^2) bus iterators with new a host iterator (for bus 0) and
a new pci bridge child bus iterator.
Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
src/pci.c | 2 +
src/pci.h | 12 +++++++
src/pciinit.c | 94 +++++++++++++++++++++++----------------------------------
3 files changed, 52 insertions(+), 56 deletions(-)
diff --git a/src/pci.c b/src/pci.c
index 6031c9f..7697583 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -137,6 +137,8 @@ pci_probe_devices(void)
MaxPCIBus = bus;
} else {
rootbus = parent->rootbus;
+ if (!parent->firstchild)
+ parent->firstchild = dev;
}
// Populate pci_device info.
diff --git a/src/pci.h b/src/pci.h
index a2a5a4c..b19b2e9 100644
--- a/src/pci.h
+++ b/src/pci.h
@@ -44,6 +44,7 @@ struct pci_device {
u8 rootbus;
struct pci_device *next;
struct pci_device *parent;
+ struct pci_device *firstchild;
// Configuration space device information
u16 vendor, device;
@@ -68,9 +69,20 @@ static inline u32 pci_classprog(struct pci_device *pci) {
return (pci->class << 8) | pci->prog_if;
}
+// Iterator for every PCI device in the system
#define foreachpci(PCI) \
for (PCI=PCIDevices; PCI; PCI=PCI->next)
+// Iterator for every PCI device on the main host bus (bus 0)
+#define foreachhostpci(PCI) \
+ for (PCI=PCIDevices; PCI && pci_bdf_to_bus(PCI->bdf) == 0; PCI=PCI->next)
+
+// Iterator for every PCI device hanging off a PCI bridge
+#define foreachchildpci(PCI, PARENT) \
+ for (PCI=PARENT->firstchild \
+ ; PCI && pci_bdf_to_bus(PCI->bdf) == pci_bdf_to_bus(PARENT->bdf) \
+ ; PCI=PCI->next)
+
int pci_next(int bdf, int bus);
#define foreachbdf(BDF, BUS) \
for (BDF=pci_next(pci_bus_devfn_to_bdf((BUS), 0)-1, (BUS)) \
diff --git a/src/pciinit.c b/src/pciinit.c
index e384a68..b87825d 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -236,17 +236,16 @@ static void pci_bios_init_device(struct pci_device *pci)
pci_init_device(pci_device_tbl, pci, NULL);
}
-static void pci_bios_init_device_in_bus(int bus)
+static void pci_bios_init_devices(void)
{
struct pci_device *pci;
- foreachpci(pci) {
- u8 pci_bus = pci_bdf_to_bus(pci->bdf);
- if (pci_bus < bus)
- continue;
- if (pci_bus > bus)
- break;
+ foreachhostpci(pci) {
pci_bios_init_device(pci);
}
+
+ foreachpci(pci) {
+ pci_init_device(pci_isa_bridge_tbl, pci, NULL);
+ }
}
@@ -369,10 +368,10 @@ static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size)
bus->r[type].max = size;
}
-static void pci_bios_check_device_in_bus(int bus);
-
-static void pci_bios_check_device(struct pci_bus *bus, struct pci_device *dev)
+static void pci_bios_check_device(struct pci_device *dev)
{
+ struct pci_bus *bus = &busses[pci_bdf_to_bus(dev->bdf)];
+
if (dev->class == PCI_CLASS_BRIDGE_PCI) {
if (dev->secondary_bus >= busses_count) {
/* should never trigger */
@@ -380,8 +379,13 @@ static void pci_bios_check_device(struct pci_bus *bus, struct pci_device *dev)
busses_count, dev->secondary_bus);
return;
}
- struct pci_bus *s = busses + dev->secondary_bus;
- pci_bios_check_device_in_bus(dev->secondary_bus);
+ dprintf(1, "PCI: check devices bus %d\n", dev->secondary_bus);
+ struct pci_device *pci;
+ foreachchildpci(pci, dev) {
+ pci_bios_check_device(pci);
+ }
+
+ struct pci_bus *s = &busses[dev->secondary_bus];
int type;
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
u32 limit = (type == PCI_REGION_TYPE_IO) ?
@@ -419,18 +423,6 @@ static void pci_bios_check_device(struct pci_bus *bus, struct pci_device *dev)
}
}
-static void pci_bios_check_device_in_bus(int bus)
-{
- struct pci_device *pci;
-
- dprintf(1, "PCI: check devices bus %d\n", bus);
- foreachpci(pci) {
- if (pci_bdf_to_bus(pci->bdf) != bus)
- continue;
- pci_bios_check_device(&busses[bus], pci);
- }
-}
-
#define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1)
// Setup region bases (given the regions' size and alignment)
@@ -496,17 +488,19 @@ static u32 pci_bios_bus_get_addr(struct pci_bus *bus, int type, u32 size)
#define PCI_MEMORY_SHIFT 16
#define PCI_PREF_MEMORY_SHIFT 16
-static void pci_bios_map_device_in_bus(int bus);
-
-static void pci_bios_map_device(struct pci_bus *bus, struct pci_device *dev)
+static void pci_bios_map_device(struct pci_device *dev)
{
+ struct pci_bus *bus = &busses[pci_bdf_to_bus(dev->bdf)];
+ u16 bdf = dev->bdf;
+
+ dprintf(1, "PCI: map device bdf=%02x:%02x.%x\n"
+ , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
+
if (dev->class == PCI_CLASS_BRIDGE_PCI) {
if (dev->secondary_bus >= busses_count) {
return;
}
- struct pci_bus *s = busses + dev->secondary_bus;
- u32 base, limit;
-
+ struct pci_bus *s = &busses[dev->secondary_bus];
int type;
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
s->r[type].base = pci_bios_bus_get_addr(bus, type, s->r[type].size);
@@ -514,9 +508,8 @@ static void pci_bios_map_device(struct pci_bus *bus, struct pci_device *dev)
dprintf(1, "PCI: init bases bus %d (secondary)\n", dev->secondary_bus);
pci_bios_init_bus_bases(s);
- base = s->r[PCI_REGION_TYPE_IO].base;
- limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
- u16 bdf = dev->bdf;
+ u32 base = s->r[PCI_REGION_TYPE_IO].base;
+ u32 limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
pci_config_writeb(bdf, PCI_IO_BASE, base >> PCI_IO_SHIFT);
pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT);
@@ -534,7 +527,10 @@ static void pci_bios_map_device(struct pci_bus *bus, struct pci_device *dev)
pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0);
pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0);
- pci_bios_map_device_in_bus(dev->secondary_bus);
+ struct pci_device *pci;
+ foreachchildpci(pci, dev) {
+ pci_bios_map_device(pci);
+ }
return;
}
@@ -558,20 +554,6 @@ static void pci_bios_map_device(struct pci_bus *bus, struct pci_device *dev)
}
}
-static void pci_bios_map_device_in_bus(int bus)
-{
- struct pci_device *pci;
-
- foreachpci(pci) {
- u16 bdf = pci->bdf;
- if (pci_bdf_to_bus(bdf) != bus)
- continue;
- dprintf(1, "PCI: map device bdf=%02x:%02x.%x\n"
- , pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf), pci_bdf_to_fn(bdf));
- pci_bios_map_device(&busses[bus], pci);
- }
-}
-
/****************************************************************
* Main setup code
@@ -603,7 +585,10 @@ pci_setup(void)
dprintf(1, "=== PCI new allocation pass #1 ===\n");
busses = malloc_tmp(sizeof(*busses) * busses_count);
memset(busses, 0, sizeof(*busses) * busses_count);
- pci_bios_check_device_in_bus(0 /* host bus */);
+ struct pci_device *pci;
+ foreachhostpci(pci) {
+ pci_bios_check_device(pci);
+ }
if (pci_bios_init_root_regions(start, end) != 0) {
panic("PCI: out of address space\n");
}
@@ -611,15 +596,12 @@ pci_setup(void)
dprintf(1, "=== PCI new allocation pass #2 ===\n");
dprintf(1, "PCI: init bases bus 0 (primary)\n");
pci_bios_init_bus_bases(&busses[0]);
- pci_bios_map_device_in_bus(0 /* host bus */);
-
- pci_bios_init_device_in_bus(0 /* host bus */);
-
- struct pci_device *pci;
- foreachpci(pci) {
- pci_init_device(pci_isa_bridge_tbl, pci, NULL);
+ foreachhostpci(pci) {
+ pci_bios_map_device(pci);
}
+ pci_bios_init_devices();
+
free(busses);
busses_count = 0;
}
--
1.7.6.2
More information about the SeaBIOS
mailing list