On Linux, the kernel first checks E820_SOFT_RESERVED ranges, and when
multiple CXL Type 3 devices share a contiguous HPA range those ranges
tend to be merged into a single region. In that case, the CXL driver
cannot reliably initialize per‑device regions based on E820 alone.

To let the OS distinguish CXL Type 3 memory from normal RAM and associate
it with the “memory only” NUMA nodes created earlier, SRAT needs entries
for the host physical address ranges assigned to CXL Type 3 devices.

This patch adds a helper that walks CXL Type 3 devices, obtains their HPA
ranges via `ct3_type3_get_hpm_range()`, and emits SRAT memory affinity
entries using the NUMA node IDs stored on each device. This runs only when
CXL is enabled and `program_hdm_decoder` is set.

Signed-off-by: Yukiya Takaki <[email protected]>
---
 hw/acpi/cxl_type3.c        | 30 ++++++++++++++++++++++++++++++
 hw/acpi/meson.build        |  1 +
 hw/i386/acpi-build.c       |  7 +++++++
 include/hw/mem/cxl_type3.h |  8 ++++++++
 4 files changed, 46 insertions(+)
 create mode 100644 hw/acpi/cxl_type3.c
 create mode 100644 include/hw/mem/cxl_type3.h

diff --git a/hw/acpi/cxl_type3.c b/hw/acpi/cxl_type3.c
new file mode 100644
index 0000000000..4cad270257
--- /dev/null
+++ b/hw/acpi/cxl_type3.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "qemu/osdep.h"
+
+#include "hw/acpi/aml-build.h"
+#include "hw/cxl/cxl_device.h"
+#include "hw/mem/cxl_type3.h"
+
+int cxl_type3_build_srat(Object *obj, void *opaque)
+{
+    GArray *table_data = opaque;
+    DeviceState *dev;
+    CXLType3Dev *c3d;
+    uint64_t addr, size;
+    if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) {
+        return 0;
+    }
+    dev = DEVICE(obj);
+    c3d = CXL_TYPE3(dev);
+
+    if (!c3d->program_hdm_decoder) {
+        return 0;
+    }
+
+    ct3_type3_get_hpm_range(c3d, &addr, &size);
+
+    build_srat_memory(table_data, addr, size, c3d->node,
+                      MEM_AFFINITY_ENABLED | MEM_AFFINITY_HOTPLUGGABLE);
+    return 0;
+}
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index 09ad488a04..b1def538bd 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -13,6 +13,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_NVDIMM', if_true: 
files('nvdimm.c'))
 stub_ss.add(files('acpi-nvdimm-stub.c'))
 acpi_ss.add(when: 'CONFIG_ACPI_PCI', if_true: files('pci.c'))
 acpi_ss.add(when: 'CONFIG_ACPI_CXL', if_true: files('cxl.c'))
+acpi_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c'))
 stub_ss.add(files('cxl-stub.c'))
 acpi_ss.add(when: 'CONFIG_ACPI_VMGENID', if_true: files('vmgenid.c'))
 acpi_ss.add(when: 'CONFIG_ACPI_VMCLOCK', if_true: files('vmclock.c'))
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 6d7308b4e4..2f607f3ec9 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -51,6 +51,7 @@
 #include "hw/rtc/mc146818rtc_regs.h"
 #include "migration/vmstate.h"
 #include "hw/mem/memory-device.h"
+#include "hw/mem/cxl_type3.h"
 #include "hw/mem/nvdimm.h"
 #include "hw/mem/sp-mem.h"
 #include "system/numa.h"
@@ -1460,6 +1461,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
     uint64_t mem_len, mem_base, next_base;
     MachineClass *mc = MACHINE_GET_CLASS(machine);
     X86MachineState *x86ms = X86_MACHINE(machine);
+    PCMachineState *pcms = PC_MACHINE(machine);
     const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(machine);
     int nb_numa_nodes = machine->numa_state->num_nodes;
     NodeInfo *numa_info = machine->numa_state->nodes;
@@ -1584,6 +1586,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
         build_srat_device_memory(table_data, machine);
     }
 
+    if (pcms->cxl_devices_state.is_enabled) {
+        object_child_foreach_recursive(object_get_root(),
+                                       cxl_type3_build_srat, table_data);
+    }
+
     acpi_table_end(linker, &table);
 }
 
diff --git a/include/hw/mem/cxl_type3.h b/include/hw/mem/cxl_type3.h
new file mode 100644
index 0000000000..15a204d66a
--- /dev/null
+++ b/include/hw/mem/cxl_type3.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef QEMU_CXL_TYPE3_H
+#define QEMU_CXL_TYPE3_H
+
+int cxl_type3_build_srat(Object *obj, void *opaque);
+
+#endif
-- 
2.52.0


Reply via email to