[SeaBIOS] [PATCHv2] pci: load memory window setup from host

Michael S. Tsirkin mst at redhat.com
Sun Jul 14 16:11:44 CEST 2013


On Tue, Apr 30, 2013 at 09:34:55AM +0300, Michael S. Tsirkin wrote:
> Load memory window setup for pci from host.
> This makes it possible for host to make sure
> setup matches hardware exactly: especially important
> for when ACPI tables are loaded from host.
> This will also make it easier to add more chipsets
> down the road.
> 
> Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
> ---
> 
> Changes from v1:
> 	- fix bug in 64 bit range check
> 	- address Kevin's comments:
> 		move file load into pciinit.c
> 		dont reorder initialization
> 		sizeof style fix
> 
>  src/pciinit.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 75 insertions(+), 16 deletions(-)

QEMU now includes these interfaces - could the bios side be
merged please?


> diff --git a/src/pciinit.c b/src/pciinit.c
> index bb9355f..a4a5bf5 100644
> --- a/src/pciinit.c
> +++ b/src/pciinit.c
> @@ -13,6 +13,7 @@
>  #include "config.h" // CONFIG_*
>  #include "memmap.h" // add_e820
>  #include "paravirt.h" // RamSize
> +#include "byteorder.h" // le64_to_cpu
>  #include "dev-q35.h"
>  
>  /* PM Timer ticks per second (HZ) */
> @@ -61,6 +62,13 @@ struct pci_bus {
>      struct pci_device *bus_dev;
>  };
>  
> +struct pci_mem {
> +	u64 start32;
> +	u64 end32;
> +	u64 start64;
> +	u64 end64;
> +};
> +
>  static u32 pci_bar(struct pci_device *pci, int region_num)
>  {
>      if (region_num != PCI_ROM_SLOT) {
> @@ -361,6 +369,8 @@ static void pci_enable_default_vga(void)
>  
>  void i440fx_mem_addr_setup(struct pci_device *dev, void *arg)
>  {
> +    if (arg)
> +	/* use supplied memory */;
>      if (RamSize <= 0x80000000)
>          pcimem_start = 0x80000000;
>      else if (RamSize <= 0xc0000000)
> @@ -383,8 +393,9 @@ void mch_mem_addr_setup(struct pci_device *dev, void *arg)
>      pci_config_writel(bdf, Q35_HOST_BRIDGE_PCIEXBAR, lower);
>      add_e820(addr, size, E820_RESERVED);
>  
> -    /* setup pci i/o window (above mmconfig) */
> -    pcimem_start = addr + size;
> +    /* unless done already, setup pci i/o window (above mmconfig) */
> +    if (!arg)
> +    	pcimem_start = addr + size;
>  
>      pci_slot_get_irq = mch_pci_slot_get_irq;
>  }
> @@ -397,11 +408,11 @@ static const struct pci_device_id pci_platform_tbl[] = {
>      PCI_DEVICE_END
>  };
>  
> -static void pci_bios_init_platform(void)
> +static void pci_bios_init_platform(struct pci_mem *mem)
>  {
>      struct pci_device *pci;
>      foreachpci(pci) {
> -        pci_init_device(pci_platform_tbl, pci, NULL);
> +        pci_init_device(pci_platform_tbl, pci, mem);
>      }
>  }
>  
> @@ -762,10 +773,14 @@ static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
>      }
>  }
>  
> -static void pci_bios_map_devices(struct pci_bus *busses)
> +static void pci_bios_map_devices(struct pci_bus *busses, struct pci_mem *mem)
>  {
>      if (pci_bios_init_root_regions(busses)) {
>          struct pci_region r64_mem, r64_pref;
> +
> +        if (mem && mem->start64 >= mem->end64)
> +            panic("PCI: out of 32bit address space\n");
> +
>          r64_mem.list = NULL;
>          r64_pref.list = NULL;
>          pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_MEM],
> @@ -781,14 +796,27 @@ static void pci_bios_map_devices(struct pci_bus *busses)
>          u64 align_mem = pci_region_align(&r64_mem);
>          u64 align_pref = pci_region_align(&r64_pref);
>  
> -        r64_mem.base = ALIGN(0x100000000LL + RamSizeOver4G, align_mem);
> -        r64_pref.base = ALIGN(r64_mem.base + sum_mem, align_pref);
> -        pcimem64_start = r64_mem.base;
> -        pcimem64_end = r64_pref.base + sum_pref;
> +        if (mem) {
> +            /*
> +             * Non prefetcheable memory at start of the window,
> +             * prefetcheable memory at the end.
> +             * This way OS has the maximum flexibility for
> +             * allocating the rest of the memory.
> +             */
> +            r64_mem.base = ALIGN(mem->start64, align_mem);
> +            r64_pref.base = ALIGN_DOWN(mem->end64 - sum_pref + 1, align_pref);
> +            if (sum_pref && r64_pref.base < r64_mem.base + sum_mem)
> +                panic("PCI: out of 64bit address space\n");
> +        } else {
> +            r64_mem.base = ALIGN(0x100000000LL + RamSizeOver4G, align_mem);
> +            r64_pref.base = ALIGN(r64_mem.base + sum_mem, align_pref);
> +            pcimem64_start = r64_mem.base;
> +            pcimem64_end = r64_pref.base + sum_pref;
> +        }
>  
>          pci_region_map_entries(busses, &r64_mem);
>          pci_region_map_entries(busses, &r64_pref);
> -    } else {
> +    } else if (!mem) {
>          // no bars mapped high -> drop 64bit window (see dsdt)
>          pcimem64_start = 0;
>      }
> @@ -801,11 +829,28 @@ static void pci_bios_map_devices(struct pci_bus *busses)
>      }
>  }
>  
> +static
> +struct pci_mem *pci_mem_get(void)
> +{
> +    int psize;
> +    struct pci_mem *mem = romfile_loadfile("etc/pci-info", &psize);
> +    if (!mem)
> +        return NULL;
> +    if (psize < sizeof(*mem)) {
> +        free(mem);
> +        return NULL;
> +    }
> +    mem->start32 = le64_to_cpu(mem->start32);
> +    mem->end32 = le64_to_cpu(mem->end32);
> +    mem->start64 = le64_to_cpu(mem->start64);
> +    mem->end64 = le64_to_cpu(mem->end64);
> +    return mem;
> +}
> +
>  
>  /****************************************************************
>   * Main setup code
>   ****************************************************************/
> -
>  void
>  pci_setup(void)
>  {
> @@ -823,25 +868,39 @@ pci_setup(void)
>      dprintf(1, "=== PCI device probing ===\n");
>      pci_probe_devices();
>  
> -    pcimem_start = RamSize;
> -    pci_bios_init_platform();
> +    struct pci_mem *mem = pci_mem_get();
> +
> +    if (mem) {
> +        pcimem_start = mem->start32;
> +        pcimem_end = mem->end32;
> +        pcimem64_start = mem->start64;
> +        pcimem64_end = mem->end64;
> +    } else {
> +        pcimem_start = RamSize;
> +    }
> +
> +    pci_bios_init_platform(mem);
>  
>      dprintf(1, "=== PCI new allocation pass #1 ===\n");
>      struct pci_bus *busses = malloc_tmp(sizeof(*busses) * (MaxPCIBus + 1));
>      if (!busses) {
>          warn_noalloc();
> -        return;
> +        goto done;
>      }
>      memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1));
>      if (pci_bios_check_devices(busses))
> -        return;
> +        goto done;
>  
>      dprintf(1, "=== PCI new allocation pass #2 ===\n");
> -    pci_bios_map_devices(busses);
> +    pci_bios_map_devices(busses, mem);
>  
>      pci_bios_init_devices();
>  
>      free(busses);
>  
>      pci_enable_default_vga();
> +
> +done:
> +    if (mem)
> +        free(mem);
>  }
> -- 
> MST



More information about the SeaBIOS mailing list