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
On a related note: end is currently one after last byte of the region. Would it be cleaner to rework code to have the address of the last byte there, as the name implies, and change the interface to qemu appropriately?
src/pciinit.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 16 deletions(-)
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