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@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;
} memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1)); if (pci_bios_check_devices(busses))goto done;
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