[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