[PATCH 0/2] paravirt: load pci window data from host
This makes it possible to load pci window data from host, when running on qemu. 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. Michael S. Tsirkin (2): paravirt: init qemu cfg earlier pci: load memory window setup from host src/paravirt.c | 27 ++++++++++++++++++++++++++- src/pciinit.c | 54 ++++++++++++++++++++++++++++++++++++++++-------------- src/post.c | 1 - src/util.h | 8 +++++++- 4 files changed, 73 insertions(+), 17 deletions(-) -- MST
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> --- src/paravirt.c | 25 ++++++++++++++++++++++++- src/pciinit.c | 54 ++++++++++++++++++++++++++++++++++++++++-------------- src/util.h | 8 +++++++- 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/paravirt.c b/src/paravirt.c index 85aa423..067a4dc 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -91,14 +91,35 @@ qemu_preinit(void) dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G); } +struct pci_mem *qemu_get_pci_mem(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; +} + void qemu_platform_setup(void) { + struct pci_mem *mem; + if (!CONFIG_QEMU) return; qemu_cfg_init(); + mem = qemu_get_pci_mem(); + if (runningOnXen()) { pci_probe_devices(); xen_hypercall_setup(); @@ -107,7 +128,7 @@ qemu_platform_setup(void) } // Initialize pci - pci_setup(); + pci_setup(mem); smm_device_setup(); smm_setup(); @@ -120,6 +141,8 @@ qemu_platform_setup(void) mptable_setup(); smbios_setup(); acpi_setup(); + if (mem) + free(mem); } diff --git a/src/pciinit.c b/src/pciinit.c index bb9355f..f3bac02 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -361,6 +361,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 +385,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 +400,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 +765,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 +788,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; } @@ -807,7 +827,7 @@ static void pci_bios_map_devices(struct pci_bus *busses) ****************************************************************/ void -pci_setup(void) +pci_setup(struct pci_mem *mem) { if (!CONFIG_QEMU) return; @@ -823,8 +843,14 @@ pci_setup(void) dprintf(1, "=== PCI device probing ===\n"); pci_probe_devices(); - pcimem_start = RamSize; - pci_bios_init_platform(); + 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)); @@ -837,7 +863,7 @@ pci_setup(void) return; dprintf(1, "=== PCI new allocation pass #2 ===\n"); - pci_bios_map_devices(busses); + pci_bios_map_devices(busses, mem); pci_bios_init_devices(); diff --git a/src/util.h b/src/util.h index 7b50c38..03fe60c 100644 --- a/src/util.h +++ b/src/util.h @@ -311,7 +311,13 @@ void qemu_prep_reset(void); // pciinit.c extern const u8 pci_irqs[4]; -void pci_setup(void); +struct pci_mem { + u64 start32; + u64 end32; + u64 start64; + u64 end64; +}; +void pci_setup(struct pci_mem *); // smm.c void smm_device_setup(void); -- MST
This will make it possible to use fw config info for pci initialization. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> --- src/paravirt.c | 2 ++ src/post.c | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/paravirt.c b/src/paravirt.c index e5027d0..85aa423 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -97,6 +97,8 @@ qemu_platform_setup(void) if (!CONFIG_QEMU) return; + qemu_cfg_init(); + if (runningOnXen()) { pci_probe_devices(); xen_hypercall_setup(); diff --git a/src/post.c b/src/post.c index ff201fa..020959b 100644 --- a/src/post.c +++ b/src/post.c @@ -108,7 +108,6 @@ interface_init(void) malloc_init(); // Setup romfile items. - qemu_cfg_init(); coreboot_cbfs_init(); // Setup ivt/bda/ebda -- MST
participants (1)
-
Michael S. Tsirkin