Basically it looks good. Great work. I've wanted to see this kind of patch. Some comments below.
On Tue, May 24, 2011 at 11:05:32AM +0200, Gerd Hoffmann wrote: > This patch adds a second device scan to the pci initialization, which > counts the memory bars of the various sizes and types. Then it > calculates the sizes and the packing of the prefetchable and > non-prefetchable pci memory windows and prints the results. > > TODO: actually use the calculated stuff. > > Signed-off-by: Gerd Hoffmann <[email protected]> > --- > src/pciinit.c | 352 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 350 insertions(+), 2 deletions(-) > > diff --git a/src/pciinit.c b/src/pciinit.c > index 97df126..537eed0 100644 > --- a/src/pciinit.c > +++ b/src/pciinit.c > @@ -17,12 +17,77 @@ > #define PCI_ROM_SLOT 6 > #define PCI_NUM_REGIONS 7 > > -static void pci_bios_init_device_in_bus(int bus); > +#define PCI_IO_INDEX_SHIFT 2 > +#define PCI_MEM_INDEX_SHIFT 12 > + > +#define PCI_BRIDGE_IO_MIN 0x100 > +#define PCI_BRIDGE_MEM_MIN 0x100000 > > static struct pci_region pci_bios_io_region; > static struct pci_region pci_bios_mem_region; > static struct pci_region pci_bios_prefmem_region; > > +static struct pci_bus { > + /* pci region stats */ > + u32 io_count[16 - PCI_IO_INDEX_SHIFT]; > + u32 mem_count[32 - PCI_MEM_INDEX_SHIFT]; > + u32 prefmem_count[32 - PCI_MEM_INDEX_SHIFT]; > + u32 io_sum, io_max; > + u32 mem_sum, mem_max; > + u32 prefmem_sum, prefmem_max; > + /* seconday bus region sizes */ > + u32 io_size, mem_size, prefmem_size; > + /* pci region assignments */ > + u32 io_bases[16 - PCI_IO_INDEX_SHIFT]; > + u32 mem_bases[32 - PCI_MEM_INDEX_SHIFT]; > + u32 prefmem_bases[32 - PCI_MEM_INDEX_SHIFT]; > + u32 io_base, mem_base, prefmem_base; > +} busses[32]; Statically allocated? Should we be go for three pass by splitting the first pass into two? - 1.A pass: assign bus number and count the total number of pci buses. allocate busses by malloc_tmp() which will be freed later. - 1.B pass: calculate region size > + > +static void pci_bios_init_device_in_bus(int bus); > +static void pci_bios_check_device_in_bus(int bus); > +static void pci_bios_init_bus_bases(struct pci_bus *bus); > +static void pci_bios_map_device_in_bus(int bus); > + > +static int pci_size_to_index(u32 size, int shift) > +{ > + int index = 0; > + > + while (size > (1 << index)) { > + index++; > + } > + if (index < shift) > + index = shift; > + index -= shift; > + return index; > +} > + > +static u32 pci_size_roundup(u32 size) > +{ > + int index = pci_size_to_index(size, 0); > + return 1 << index; > +} > + > +static int pci_io_size_to_index(u32 size) > +{ > + return pci_size_to_index(size, PCI_IO_INDEX_SHIFT); > +} > + > +static u32 pci_io_index_to_size(int index) > +{ > + return 1 << (index + PCI_IO_INDEX_SHIFT); > +} > + > +static int pci_mem_size_to_index(u32 size) > +{ > + return pci_size_to_index(size, PCI_MEM_INDEX_SHIFT); > +} > + > +static u32 pci_mem_index_to_size(int index) > +{ > + return 1 << (index + PCI_MEM_INDEX_SHIFT); > +} > + > /* host irqs corresponding to PCI irqs A-D */ > const u8 pci_irqs[4] = { > 10, 10, 11, 11 > @@ -411,17 +476,296 @@ static const struct pci_device_id pci_mem_addr_tbl[] = > { > PCI_DEVICE_END, > }; > > +static void pci_bios_bus_get_bar(struct pci_bus *bus, int bdf, int bar, > + u32 *val, u32 *size) > +{ > + u32 ofs = pci_bar(bdf, bar); > + u32 old = pci_config_readl(bdf, ofs); > + u32 mask; > + > + if (bar == PCI_ROM_SLOT) { > + mask = PCI_ROM_ADDRESS_MASK; > + pci_config_writel(bdf, ofs, mask); > + } else { > + if (old & PCI_BASE_ADDRESS_SPACE_IO) > + mask = PCI_BASE_ADDRESS_IO_MASK; > + else > + mask = PCI_BASE_ADDRESS_MEM_MASK; > + pci_config_writel(bdf, ofs, ~0); > + } > + *val = pci_config_readl(bdf, ofs); > + pci_config_writel(bdf, ofs, old); > + *size = (~(*val & mask)) + 1; > +} > + > +static void pci_bios_bus_reserve(struct pci_bus *bus, u32 val, u32 size) > +{ > + u32 index; > + > + if (val & PCI_BASE_ADDRESS_SPACE_IO) { > + index = pci_io_size_to_index(size); > + size = pci_io_index_to_size(index); > + bus->io_count[index]++; > + bus->io_sum += size; > + if (bus->io_max < size) > + bus->io_max = size; > + } else { > + index = pci_mem_size_to_index(size); > + size = pci_mem_index_to_size(index); > + if (val & PCI_BASE_ADDRESS_MEM_PREFETCH) { > + bus->prefmem_count[index]++; > + bus->prefmem_sum += size; > + if (bus->prefmem_max < size) > + bus->prefmem_max = size; > + } else { > + bus->mem_count[index]++; > + bus->mem_sum += size; > + if (bus->mem_max < size) > + bus->mem_max = size; > + } > + } > +} > + > +static u32 pci_bios_bus_get_addr(struct pci_bus *bus, u32 val, u32 size) > +{ > + u32 index, addr; > + > + if (val & PCI_BASE_ADDRESS_SPACE_IO) { > + index = pci_io_size_to_index(size); > + addr = bus->io_bases[index]; > + bus->io_bases[index] += pci_io_index_to_size(index); > + } else { > + index = pci_mem_size_to_index(size); > + if (val & PCI_BASE_ADDRESS_MEM_PREFETCH) { > + addr = bus->prefmem_bases[index]; > + bus->prefmem_bases[index] += pci_mem_index_to_size(index); > + } else { > + addr = bus->mem_bases[index]; > + bus->mem_bases[index] += pci_mem_index_to_size(index); > + } > + } > + return addr; > +} > + > +static void pci_bios_check_device(struct pci_bus *bus, u16 bdf) > +{ > + u16 class; > + int i; > + > + class = pci_config_readw(bdf, PCI_CLASS_DEVICE); > + if (class == PCI_CLASS_BRIDGE_PCI) { > + u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS); > + if (secbus >= ARRAY_SIZE(busses)) { > + dprintf(1, "PCI: busses array too small, skipping bus %d\n", > secbus); > + return; > + } > + struct pci_bus *s = busses + secbus; > + pci_bios_check_device_in_bus(secbus); > + s->io_size = pci_size_roundup(s->io_sum); > + s->mem_size = pci_size_roundup(s->mem_sum); > + s->prefmem_size = pci_size_roundup(s->prefmem_sum); > + if (s->io_size < PCI_BRIDGE_IO_MIN) { > + s->io_size = PCI_BRIDGE_IO_MIN; > + } > + if (s->mem_size < PCI_BRIDGE_MEM_MIN) { > + s->mem_size = PCI_BRIDGE_MEM_MIN; > + } > + if (s->prefmem_size < PCI_BRIDGE_MEM_MIN) { > + s->prefmem_size = PCI_BRIDGE_MEM_MIN; > + } > + dprintf(1, "PCI: secondary bus %d sizes: io %x, mem %x, prefmem > %x\n", > + secbus, s->io_size, s->mem_size, s->prefmem_size); > + pci_bios_bus_reserve(bus, PCI_BASE_ADDRESS_SPACE_IO, s->io_size); > + pci_bios_bus_reserve(bus, 0, s->mem_size); > + pci_bios_bus_reserve(bus, PCI_BASE_ADDRESS_MEM_PREFETCH, > s->prefmem_size); > + return; > + } > + > + for (i = 0; i < PCI_NUM_REGIONS; i++) { > + u32 val, size; > + pci_bios_bus_get_bar(bus, bdf, i, &val, &size); > + if (val == 0) { > + continue; > + } > + pci_bios_bus_reserve(bus, val, size); > + > + if (!(val & PCI_BASE_ADDRESS_SPACE_IO) && > + (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == > PCI_BASE_ADDRESS_MEM_TYPE_64) { > + i++; > + } > + } > +} > + > +static void pci_bios_map_device(struct pci_bus *bus, u16 bdf) > +{ > + u16 class; > + int i; > + > + class = pci_config_readw(bdf, PCI_CLASS_DEVICE); > + if (class == PCI_CLASS_BRIDGE_PCI) { > + u8 secbus = pci_config_readb(bdf, PCI_SECONDARY_BUS); > + if (secbus >= ARRAY_SIZE(busses)) { > + return; > + } > + struct pci_bus *s = busses + secbus; > + s->io_base = pci_bios_bus_get_addr > + (bus, PCI_BASE_ADDRESS_SPACE_IO, s->io_size); > + s->mem_base = pci_bios_bus_get_addr > + (bus, 0, s->mem_size); > + s->prefmem_base = pci_bios_bus_get_addr > + (bus, PCI_BASE_ADDRESS_MEM_PREFETCH, s->prefmem_size); > + dprintf(1, "PCI: init bases bus %d (secondary)\n", secbus); > + pci_bios_init_bus_bases(s); > + /* TODO: commit assignments */ > + pci_bios_map_device_in_bus(secbus); > + return; > + } > + > + for (i = 0; i < PCI_NUM_REGIONS; i++) { > + u32 val, size, addr; > + pci_bios_bus_get_bar(bus, bdf, i, &val, &size); > + if (val == 0) { > + continue; > + } > + > + addr = pci_bios_bus_get_addr(bus, val, size); > + dprintf(1, " bar %d, addr %x, size %x [%s]\n", > + i, addr, size, > + val & PCI_BASE_ADDRESS_SPACE_IO ? "io" : "mem"); > + /* TODO: commit assignments */ > + > + if (!(val & PCI_BASE_ADDRESS_SPACE_IO) && > + (val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == > PCI_BASE_ADDRESS_MEM_TYPE_64) { > + i++; > + } > + } > +} > + > +static void pci_bios_check_device_in_bus(int bus) > +{ > + int bdf, max; > + > + dprintf(1, "PCI: check devices bus %d\n", bus); > + foreachpci_in_bus(bdf, max, bus) { > + pci_bios_check_device(&busses[bus], bdf); > + } > +} > + > +static void pci_bios_map_device_in_bus(int bus) > +{ > + int bdf, max; > + > + foreachpci_in_bus(bdf, max, bus) { > + dprintf(1, "PCI: map device bus %d, bfd 0x%x\n", bus, bdf); > + pci_bios_map_device(&busses[bus], bdf); > + } > +} > + > +static void pci_bios_init_bus_bases(struct pci_bus *bus) > +{ > + u32 base, newbase, size; > + int i; > + > + /* assign prefetchable memory regions */ > + dprintf(1, " prefmem max %x sum %x base %x\n", > + bus->prefmem_max, bus->prefmem_sum, bus->prefmem_base); > + base = bus->prefmem_base; > + for (i = ARRAY_SIZE(bus->prefmem_count)-1; i >= 0; i--) { > + size = pci_mem_index_to_size(i); > + if (!bus->prefmem_count[i]) > + continue; > + newbase = base + size * bus->prefmem_count[i]; > + dprintf(1, " size %8x: %d bar(s), %8x -> %8x\n", > + size, bus->prefmem_count[i], base, newbase - 1); > + bus->prefmem_bases[i] = base; > + base = newbase; > + } > + > + /* assign memory regions */ > + dprintf(1, " mem max %x sum %x base %x\n", > + bus->mem_max, bus->mem_sum, bus->mem_base); > + base = bus->mem_base; > + for (i = ARRAY_SIZE(bus->mem_count)-1; i >= 0; i--) { > + size = pci_mem_index_to_size(i); > + if (!bus->mem_count[i]) > + continue; > + newbase = base + size * bus->mem_count[i]; > + dprintf(1, " mem size %8x: %d bar(s), %8x -> %8x\n", > + size, bus->mem_count[i], base, newbase - 1); > + bus->mem_bases[i] = base; > + base = newbase; > + } > + > + /* assign io regions */ > + dprintf(1, " io max %x sum %x base %x\n", > + bus->io_max, bus->io_sum, bus->io_base); > + base = bus->io_base; > + for (i = ARRAY_SIZE(bus->io_count)-1; i >= 0; i--) { > + size = pci_io_index_to_size(i); > + if (!bus->io_count[i]) > + continue; > + newbase = base + size * bus->io_count[i]; > + dprintf(1, " io size %4x: %d bar(s), %4x -> %4x\n", > + size, bus->io_count[i], base, newbase - 1); > + bus->io_bases[i] = base; > + base = newbase; > + } > +} > + > +static void pci_bios_init_root_regions(void) > +{ > + struct pci_bus *bus = &busses[0]; > + u32 reserved = 0xffffffff - 0xfec00000 + 1; > + > + /* calculate memory windows */ > + if (bus->mem_sum) { > + u32 window = bus->mem_max; > + while (bus->mem_sum + reserved > window) { > + window += bus->mem_max; > + } > + bus->mem_base = 0xffffffff - window + 1; > + reserved = 0xffffffff - bus->mem_base + 1; > + } > + > + if (bus->prefmem_sum) { > + u32 window = bus->prefmem_max; > + while (bus->prefmem_sum + reserved > window) { > + window += bus->prefmem_max; > + } > + bus->prefmem_base = 0xffffffff - window + 1; > + reserved = 0xffffffff - bus->prefmem_base + 1; > + } > + > + bus->io_base = 0xc000; > + > + /* simple sanity check */ > + /* TODO: check e820 table */ > + if (bus->mem_base < RamSize) { > + dprintf(1, "PCI: out of space for memory bars\n"); > + /* Hmm, what to do now? */ > + } > + > + dprintf(1, "PCI: init bases bus 0 (primary)\n"); > + pci_bios_init_bus_bases(bus); > +} > + > void > pci_setup(void) > { > + int bdf, max; > + > if (CONFIG_COREBOOT) > // Already done by coreboot. > return; > > dprintf(3, "pci setup\n"); > > + dprintf(1, "=== PCI bus & bridge init ===\n"); > pci_bios_init_bus(); > > + dprintf(1, "=== PCI new allocation pass #1 ===\n"); > + pci_bios_check_device_in_bus(0 /* host bus */); > + > pci_region_init(&pci_bios_io_region, 0xc000, 64 * 1024 - 1); > struct pci_mem_addr addr = { > .pci_bios_mem_region = &pci_bios_mem_region, > @@ -429,7 +773,11 @@ pci_setup(void) > }; > pci_find_init_device(pci_mem_addr_tbl, &addr); > > - int bdf, max; > + dprintf(1, "=== PCI new allocation pass #2 ===\n"); > + pci_bios_init_root_regions(); > + pci_bios_map_device_in_bus(0 /* host bus */); > + > + dprintf(1, "=== PCI old allocation pass ===\n"); > foreachpci(bdf, max) { > pci_init_device(pci_isa_bridge_tbl, bdf, NULL); > } > -- > 1.7.1 > > > _______________________________________________ > SeaBIOS mailing list > [email protected] > http://www.seabios.org/mailman/listinfo/seabios > -- yamahata _______________________________________________ SeaBIOS mailing list [email protected] http://www.seabios.org/mailman/listinfo/seabios
