[ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
};
-static struct pci_bus {
+struct pci_bus {
struct {
/* pci region stats */
u32 count[32 - PCI_MEM_INDEX_SHIFT];
u32 base;
} r[PCI_REGION_TYPE_COUNT];
struct pci_device *bus_dev;
-} *busses;
+};
static int pci_size_to_index(u32 size, enum pci_region_type type)
{
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)
+ if (pci_bdf_to_bus(pci->bdf) != 0)
+ // Only init devices on host bus.
break;
pci_bios_init_device(pci);
}
+
+ foreachpci(pci) {
+ pci_init_device(pci_isa_bridge_tbl, pci, NULL);
+ }
}
bus->r[type].max = size;
}
-static void pci_bios_check_devices(void)
+static void pci_bios_check_devices(struct pci_bus *busses)
{
dprintf(1, "PCI: check devices\n");
#define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1)
-static int pci_bios_init_root_regions(u32 start, u32 end)
+// Setup region bases (given the regions' size and alignment)
+static int pci_bios_init_root_regions(struct pci_bus *bus, u32 start, u32 end)
{
- struct pci_bus *bus = &busses[0];
-
bus->r[PCI_REGION_TYPE_IO].base = 0xc000;
- if (bus->r[PCI_REGION_TYPE_MEM].sum < bus->r[PCI_REGION_TYPE_PREFMEM].sum) {
- bus->r[PCI_REGION_TYPE_MEM].base =
- ROOT_BASE(end,
- bus->r[PCI_REGION_TYPE_MEM].sum,
- bus->r[PCI_REGION_TYPE_MEM].max);
- bus->r[PCI_REGION_TYPE_PREFMEM].base =
- ROOT_BASE(bus->r[PCI_REGION_TYPE_MEM].base,
- bus->r[PCI_REGION_TYPE_PREFMEM].sum,
- bus->r[PCI_REGION_TYPE_PREFMEM].max);
- if (bus->r[PCI_REGION_TYPE_PREFMEM].base >= start) {
- return 0;
- }
- } else {
- bus->r[PCI_REGION_TYPE_PREFMEM].base =
- ROOT_BASE(end,
- bus->r[PCI_REGION_TYPE_PREFMEM].sum,
- bus->r[PCI_REGION_TYPE_PREFMEM].max);
- bus->r[PCI_REGION_TYPE_MEM].base =
- ROOT_BASE(bus->r[PCI_REGION_TYPE_PREFMEM].base,
- bus->r[PCI_REGION_TYPE_MEM].sum,
- bus->r[PCI_REGION_TYPE_MEM].max);
- if (bus->r[PCI_REGION_TYPE_MEM].base >= start) {
- return 0;
- }
+ int reg1 = PCI_REGION_TYPE_PREFMEM, reg2 = PCI_REGION_TYPE_MEM;
+ if (bus->r[reg1].sum < bus->r[reg2].sum) {
+ // Swap regions so larger area is more likely to align well.
+ reg1 = PCI_REGION_TYPE_MEM;
+ reg2 = PCI_REGION_TYPE_PREFMEM;
}
- return -1;
+ bus->r[reg2].base = ROOT_BASE(end, bus->r[reg2].sum, bus->r[reg2].max);
+ bus->r[reg1].base = ROOT_BASE(bus->r[reg2].base, bus->r[reg1].sum
+ , bus->r[reg1].max);
+ if (bus->r[reg1].base < start)
+ // Memory range requested is larger than available.
+ return -1;
+ return 0;
}
#define PCI_MEMORY_SHIFT 16
#define PCI_PREF_MEMORY_SHIFT 16
-static void pci_bios_map_devices(void)
+static void pci_bios_map_devices(struct pci_bus *busses)
{
+ // Setup bases for root bus.
+ dprintf(1, "PCI: init bases bus 0 (primary)\n");
+ pci_bios_init_bus_bases(&busses[0]);
+
// Map regions on each secondary bus.
int secondary_bus;
for (secondary_bus=1; secondary_bus<=MaxPCIBus; secondary_bus++) {
pci_probe_devices();
dprintf(1, "=== PCI new allocation pass #1 ===\n");
- busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1));
+ struct pci_bus *busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1));
if (!busses) {
warn_noalloc();
return;
}
memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1));
- pci_bios_check_devices();
- if (pci_bios_init_root_regions(start, end) != 0) {
+ pci_bios_check_devices(busses);
+ if (pci_bios_init_root_regions(&busses[0], start, end) != 0) {
panic("PCI: out of address space\n");
}
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_devices();
+ pci_bios_map_devices(busses);
- pci_bios_init_device_in_bus(0 /* host bus */);
-
- struct pci_device *pci;
- foreachpci(pci) {
- pci_init_device(pci_isa_bridge_tbl, pci, NULL);
- }
+ pci_bios_init_devices();
free(busses);
}