Update the pci i/o windows at runtime, depending on the amount memory the machine has. The 32bit window starts above low memory and ends at the ioapic map address, the 64bit window is placed above high memory.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/pciinit.c | 33 +++++++++++++++++++++++++++++---- 1 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c index dc33f83..dd74963 100644 --- a/src/pciinit.c +++ b/src/pciinit.c @@ -592,6 +592,20 @@ static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r)
static void pci_bios_map_devices(struct pci_bus *busses) { + /* + * Try smaller 64bit windows first, sized to be half of the + * maximum physical address space of common cpus. + * Your cpu: try 'grep "address sizes" /proc/cpuinfo' + */ + static const u64 sizes[] = { + (1LL << 35), // 36 bits physical (64 GB, every PAE-capable cpu can do this) + (1LL << 39), // 40 bits physical (1 TB) + }; + u64 pcimem64_size; + int i; + + pcimem_start = RamSize; + if (pci_bios_init_root_regions(busses)) { struct pci_region r64_mem, r64_pref; r64_mem.list = NULL; @@ -604,14 +618,25 @@ static void pci_bios_map_devices(struct pci_bus *busses) if (pci_bios_init_root_regions(busses)) panic("PCI: out of 32bit address space\n");
- r64_mem.base = pcimem64_start; - u64 sum = pci_region_sum(&r64_mem); - u64 align = pci_region_align(&r64_pref); - r64_pref.base = ALIGN(r64_mem.base + sum, align); + for (i = 0; i < ARRAY_SIZE(sizes); i++) { + pcimem64_size = sizes[i]; + pcimem64_start = ALIGN(0x100000000LL + RamSizeOver4G, pcimem64_size); + pcimem64_end = pcimem64_start + pcimem64_size; + + r64_mem.base = pcimem64_start; + u64 sum = pci_region_sum(&r64_mem); + u64 align = pci_region_align(&r64_pref); + r64_pref.base = ALIGN(r64_mem.base + sum, align); + if (r64_pref.base + pci_region_sum(&r64_pref) <= pcimem64_end) + break; + } if (r64_pref.base + pci_region_sum(&r64_pref) > pcimem64_end) panic("PCI: out of 64bit address space\n"); pci_region_map_entries(busses, &r64_mem); pci_region_map_entries(busses, &r64_pref); + } else { + // no bars mapped high -> drop 64bit window (see dsdt) + pcimem64_start = 0; } // Map regions on each device. int bus;