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
