Relax the lower bound of the HighMem MMIO region size to make it more
likely that the region fits in the PA space.

The lower bound was especially problematic on Apple M2. The current
lower bound, 512 GiB, is too big to fit in the limited PA space on the
hardware. That makes the HighMem MMIO region unavailable and limits the
PCIe MMIO space to the base MMIO region. The base MMIO region is not big
enough to contain a large hostmem window configured for virtio-gpu-gl-pci
with DRM native context, for example.

Relax the lower bound to 64 KiB, matching the memory map comment that
says "devices should generally be placed at multiples of 0x10000, to
accommodate guests using 64K pages." Also, automatically lower the
default HighMem MMIO region size to fit in the PA space for the latest
machine version; the older machine versions retain the previous default
HighMem MMIO region size for compatibility.

Signed-off-by: Akihiko Odaki <[email protected]>
---
 docs/system/arm/virt.rst |  2 +-
 include/hw/arm/virt.h    |  1 +
 hw/arm/virt.c            | 22 ++++++++++++++--------
 3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index f811e662d68d..c8284ce2fa0e 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -149,7 +149,7 @@ highmem-mmio
 
 highmem-mmio-size
   Set the high memory region size for PCI MMIO. Must be a power of 2 and
-  greater than or equal to the default size (512G).
+  greater than or equal to 64 KiB.
 
 gic-version
   Specify the version of the Generic Interrupt Controller (GIC) to provide.
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 6c8ba8f3185b..7aa289d3936f 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -143,6 +143,7 @@ typedef enum VirtGICType {
 struct VirtMachineClass {
     MachineClass parent;
     hwaddr min_highmem_base;
+    hwaddr high_pcie_mmio_size;
     bool no_tcg_its;
     bool no_highmem_compact;
     bool no_kvm_steal_time;
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 78a85a966ad7..dd97b0dd6a42 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -222,8 +222,7 @@ static const MemMapEntry base_memmap[] = {
 };
 
 /* Update the docs for highmem-mmio-size when changing this default */
-#define DEFAULT_HIGH_PCIE_MMIO_SIZE_GB 512
-#define DEFAULT_HIGH_PCIE_MMIO_SIZE (DEFAULT_HIGH_PCIE_MMIO_SIZE_GB * GiB)
+#define MAX_DEFAULT_HIGH_PCIE_MMIO_SIZE (512 * GiB)
 
 /*
  * Highmem IO Regions: This memory map is floating, located after the RAM.
@@ -249,7 +248,7 @@ static MemMapEntry extended_memmap[] = {
     [VIRT_CXL_HOST] =           { 0x0, 64 * KiB * 16 }, /* 16 UID */
     [VIRT_HIGH_PCIE_ECAM] =     { 0x0, 256 * MiB },
     /* Second PCIe window */
-    [VIRT_HIGH_PCIE_MMIO] =     { 0x0, DEFAULT_HIGH_PCIE_MMIO_SIZE },
+    [VIRT_HIGH_PCIE_MMIO] =     { 0x0, 0 },
     /* Any CXL Fixed memory windows come here */
 };
 
@@ -2448,9 +2447,14 @@ static void virt_set_high_memmap(VirtMachineState *vms,
 
     for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) {
         region_enabled = virt_get_high_memmap_enabled(vms, i);
-        region_base = ROUND_UP(base, extended_memmap[i].size);
         region_size = extended_memmap[i].size;
 
+        if (i == VIRT_HIGH_PCIE_MMIO && !region_size) {
+            region_size = CLAMP(pow2floor(BIT_ULL(pa_bits) - base),
+                                64 * KiB, MAX_DEFAULT_HIGH_PCIE_MMIO_SIZE);
+        }
+
+        region_base = ROUND_UP(base, region_size);
         vms->memmap[i].base = region_base;
         vms->memmap[i].size = region_size;
 
@@ -3340,11 +3344,9 @@ static void virt_set_highmem_mmio_size(Object *obj, 
Visitor *v,
         return;
     }
 
-    if (size < DEFAULT_HIGH_PCIE_MMIO_SIZE) {
-        char *sz = size_to_str(DEFAULT_HIGH_PCIE_MMIO_SIZE);
+    if (size < 64 * KiB) {
         error_setg(errp, "highmem-mmio-size cannot be set to a lower value "
-                         "than the default (%s)", sz);
-        g_free(sz);
+                         "than 64 KiB");
         return;
     }
 
@@ -4271,6 +4273,8 @@ static void virt_instance_init(Object *obj)
     VirtMachineState *vms = VIRT_MACHINE(obj);
     VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
 
+    extended_memmap[VIRT_HIGH_PCIE_MMIO].size = vmc->high_pcie_mmio_size;
+
     /* EL3 is disabled by default on virt: this makes us consistent
      * between KVM and TCG for this board, and it also allows us to
      * boot UEFI blobs which assume no TrustZone support.
@@ -4372,6 +4376,8 @@ static void virt_machine_11_0_options(MachineClass *mc)
      * < 255GiB we keep the legacy memory map.
      */
     vmc->min_highmem_base = base_memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES;
+
+    vmc->high_pcie_mmio_size = MAX_DEFAULT_HIGH_PCIE_MMIO_SIZE;
 }
 DEFINE_VIRT_MACHINE(11, 0)
 

-- 
2.54.0


Reply via email to