X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fpciinit.c;h=9f3fdd49f0776f519ae1d943f84939ca5c951828;hb=139d5ac037de828f89c36e39c6dd15610650cede;hp=baafa5bb722e618cced0c6332da05726ad327933;hpb=2c4c2115a72afd66d2cc861bdb25fe12347a22b0;p=seabios.git diff --git a/src/pciinit.c b/src/pciinit.c index baafa5b..9f3fdd4 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -31,7 +31,7 @@ static const char *region_type_name[] = { [ PCI_REGION_TYPE_PREFMEM ] = "prefmem", }; -static struct pci_bus { +struct pci_bus { struct { /* pci region stats */ u32 count[32 - PCI_MEM_INDEX_SHIFT]; @@ -43,7 +43,7 @@ static struct pci_bus { 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) { @@ -230,17 +230,19 @@ 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) + 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); + } } @@ -362,7 +364,7 @@ static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size) 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"); @@ -420,38 +422,24 @@ static void pci_bios_check_devices(void) #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; } @@ -495,8 +483,12 @@ 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_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++) { @@ -553,8 +545,10 @@ static void pci_bios_map_devices(void) i, addr, pci->bars[i].size, region_type_name[type]); pci_set_io_region_addr(pci, i, addr); - if (pci->bars[i].is64) + if (pci->bars[i].is64) { i++; + pci_set_io_region_addr(pci, i, 0); + } } } } @@ -588,28 +582,21 @@ pci_setup(void) 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); }