On Tue, 16 Jun 2026 17:08:06 +0800
fanhuang <[email protected]> wrote:

> Restructure the device_memory SRAT umbrella entry into a per-kind
> partition: each TYPE_SP_MEM device gets an ENABLED entry at its own
> proximity_domain; the remaining sub-ranges get HOTPLUGGABLE | ENABLED
> placeholders at the highest PXM, preserving the existing umbrella
> convention.
> 
> Signed-off-by: FangSheng Huang <[email protected]>

LGTM, but i haven't really tested it.
please add test case for this, see tests/qtest/bios-tables-test.c
for examples and process.

With condition adding test to cover it:
Reviewed-by: Igor Mammedov <[email protected]>

> ---
>  hw/i386/acpi-build.c | 96 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 92 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 0d7c83d5e9..db144b5706 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -52,6 +52,7 @@
>  #include "migration/vmstate.h"
>  #include "hw/mem/memory-device.h"
>  #include "hw/mem/nvdimm.h"
> +#include "hw/mem/sp-mem.h"
>  #include "system/numa.h"
>  #include "system/reset.h"
>  #include "hw/hyperv/vmbus-bridge.h"
> @@ -1346,6 +1347,96 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, 
> GArray *tcpalog,
>  }
>  #endif
>  
> +typedef struct {
> +    uint64_t addr;
> +    uint64_t size;
> +    uint32_t node;
> +} SpMemRange;
> +
> +static int sp_mem_collect_ranges_cb(Object *obj, void *opaque)
> +{
> +    GArray *ranges = opaque;
> +    SpMemDevice *spm;
> +    MemoryDeviceClass *mdc;
> +    SpMemRange r;
> +
> +    if (!object_dynamic_cast(obj, TYPE_SP_MEM)) {
> +        return 0;
> +    }
> +    spm = SP_MEM(obj);
> +    mdc = MEMORY_DEVICE_GET_CLASS(MEMORY_DEVICE(spm));
> +    r.addr = mdc->get_addr(MEMORY_DEVICE(spm));
> +    r.size = memory_region_size(
> +                 host_memory_backend_get_memory(spm->hostmem));
> +    r.node = spm->node;
> +    g_array_append_val(ranges, r);
> +    return 0;
> +}
> +
> +static gint sp_mem_range_compare(gconstpointer a, gconstpointer b)
> +{
> +    const SpMemRange *range_a = a;
> +    const SpMemRange *range_b = b;
> +
> +    if (range_a->addr < range_b->addr) {
> +        return -1;
> +    }
> +    if (range_a->addr > range_b->addr) {
> +        return 1;
> +    }
> +    return 0;
> +}
> +
> +/*
> + * Emit SRAT memory-affinity entries covering the device_memory region.
> + *
> + * For each plugged TYPE_SP_MEM device, emit an ENABLED entry at the
> + * device's own proximity_domain.  All remaining sub-ranges (gaps
> + * between sp-mem devices, leading and trailing padding, and ranges
> + * occupied by other memory devices) are covered by HOTPLUGGABLE |
> + * ENABLED placeholder entries at PXM = nb_numa_nodes - 1.
> + */
> +static void build_srat_device_memory(GArray *table_data, MachineState *ms)
> +{
> +    g_autoptr(GArray) ranges = g_array_new(FALSE, TRUE, sizeof(SpMemRange));
> +    uint32_t hotplug_pxm = ms->numa_state->num_nodes - 1;
> +    uint64_t region_start, region_end;
> +    guint i;
> +
> +    region_start = ms->device_memory->base;
> +    region_end = region_start + memory_region_size(&ms->device_memory->mr);
> +
> +    object_child_foreach_recursive(qdev_get_machine(),
> +                                   sp_mem_collect_ranges_cb, ranges);
> +    g_array_sort(ranges, sp_mem_range_compare);
> +
> +    for (i = 0; i < ranges->len; i++) {
> +        SpMemRange *r = &g_array_index(ranges, SpMemRange, i);
> +
> +        if (region_start < r->addr) {
> +            build_srat_memory(table_data, region_start, r->addr - 
> region_start,
> +                              hotplug_pxm,
> +                              MEM_AFFINITY_HOTPLUGGABLE |
> +                              MEM_AFFINITY_ENABLED);
> +        }
> +        build_srat_memory(table_data, r->addr, r->size, r->node,
> +                          MEM_AFFINITY_ENABLED);
> +        region_start = r->addr + r->size;
> +    }
> +
> +    /*
> +     * Cover the rest of the device_memory window that no sp-mem device
> +     * occupies. Keeping it HOTPLUGGABLE preserves the umbrella entry's
> +     * role for future pc-dimm / virtio-mem hot-add into this window.
> +     */
> +    if (region_start < region_end) {
> +        build_srat_memory(table_data, region_start, region_end - 
> region_start,
> +                          hotplug_pxm,
> +                          MEM_AFFINITY_HOTPLUGGABLE |
> +                          MEM_AFFINITY_ENABLED);
> +    }
> +}
> +
>  #define HOLE_640K_START  (640 * KiB)
>  #define HOLE_640K_END   (1 * MiB)
>  
> @@ -1482,10 +1573,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
> MachineState *machine)
>       * providing _PXM method if necessary.
>       */
>      if (machine->device_memory) {
> -        build_srat_memory(table_data, machine->device_memory->base,
> -                          memory_region_size(&machine->device_memory->mr),
> -                          nb_numa_nodes - 1,
> -                          MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
> +        build_srat_device_memory(table_data, machine);
>      }
>  
>      acpi_table_end(linker, &table);


Reply via email to