[SeaBIOS] [RfC PATCH 1/2] pci: move to two-pass pci initialization
Alon Levy
alevy at redhat.com
Tue May 24 11:29:23 CEST 2011
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 <kraxel at redhat.com>
> ---
> 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];
16, 32 - are these numbers worth defines? (same below)
Suppressing any coding style comments (not sure they are worth for RfC).
> + 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];
> +
> +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
> SeaBIOS at seabios.org
> http://www.seabios.org/mailman/listinfo/seabios
More information about the SeaBIOS
mailing list