i386/acpi-build: partition device_memory SRAT umbrella for sp-mem
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 <FangSheng.Huang@amd.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260623075051.3797975-4-FangSheng.Huang@amd.com>
fanhuang committed
Jun 23, 2026 at 15:50 UTC
78f08a0f47e787921d8beb78a5bade9a8a64400b
1 file changed
+92
-4
hw/i386/acpi-build.c
+92
-4
@@ -52,6 +52,7 @@
52
#include "migration/vmstate.h"
53
#include "hw/mem/memory-device.h"
54
#include "hw/mem/nvdimm.h"
55
+#include "hw/mem/sp-mem.h"
56
#include "system/numa.h"
57
#include "system/reset.h"
58
#include "hw/hyperv/vmbus-bridge.h"
@@ -1351,6 +1352,96 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
1352
}
1353
#endif
1354
1355
+typedef struct {
1356
+ uint64_t addr;
1357
+ uint64_t size;
1358
+ uint32_t node;
1359
+} SpMemRange;
1360
+
1361
+static int sp_mem_collect_ranges_cb(Object *obj, void *opaque)
1362
+{
1363
+ GArray *ranges = opaque;
1364
+ SpMemDevice *spm;
1365
+ MemoryDeviceClass *mdc;
1366
+ SpMemRange r;
1367
+
1368
+ if (!object_dynamic_cast(obj, TYPE_SP_MEM)) {
1369
+ return 0;
1370
+ }
1371
+ spm = SP_MEM(obj);
1372
+ mdc = MEMORY_DEVICE_GET_CLASS(MEMORY_DEVICE(spm));
1373
+ r.addr = mdc->get_addr(MEMORY_DEVICE(spm));
1374
+ r.size = memory_region_size(
1375
+ host_memory_backend_get_memory(spm->hostmem));
1376
+ r.node = spm->node;
1377
+ g_array_append_val(ranges, r);
1378
+ return 0;
1379
+}
1380
+
1381
+static gint sp_mem_range_compare(gconstpointer a, gconstpointer b)
1382
+{
1383
+ const SpMemRange *range_a = a;
1384
+ const SpMemRange *range_b = b;
1385
+
1386
+ if (range_a->addr < range_b->addr) {
1387
+ return -1;
1388
+ }
1389
+ if (range_a->addr > range_b->addr) {
1390
+ return 1;
1391
+ }
1392
+ return 0;
1393
+}
1394
+
1395
+/*
1396
+ * Emit SRAT memory-affinity entries covering the device_memory region.
1397
+ *
1398
+ * For each plugged TYPE_SP_MEM device, emit an ENABLED entry at the
1399
+ * device's own proximity_domain. All remaining sub-ranges (gaps
1400
+ * between sp-mem devices, leading and trailing padding, and ranges
1401
+ * occupied by other memory devices) are covered by HOTPLUGGABLE |
1402
+ * ENABLED placeholder entries at PXM = nb_numa_nodes - 1.
1403
+ */
1404
+static void build_srat_device_memory(GArray *table_data, MachineState *ms)
1405
+{
1406
+ g_autoptr(GArray) ranges = g_array_new(FALSE, TRUE, sizeof(SpMemRange));
1407
+ uint32_t hotplug_pxm = ms->numa_state->num_nodes - 1;
1408
+ uint64_t region_start, region_end;
1409
+ guint i;
1410
+
1411
+ region_start = ms->device_memory->base;
1412
+ region_end = region_start + memory_region_size(&ms->device_memory->mr);
1413
+
1414
+ object_child_foreach_recursive(qdev_get_machine(),
1415
+ sp_mem_collect_ranges_cb, ranges);
1416
+ g_array_sort(ranges, sp_mem_range_compare);
1417
+
1418
+ for (i = 0; i < ranges->len; i++) {
1419
+ SpMemRange *r = &g_array_index(ranges, SpMemRange, i);
1420
+
1421
+ if (region_start < r->addr) {
1422
+ build_srat_memory(table_data, region_start, r->addr - region_start,
1423
+ hotplug_pxm,
1424
+ MEM_AFFINITY_HOTPLUGGABLE |
1425
+ MEM_AFFINITY_ENABLED);
1426
+ }
1427
+ build_srat_memory(table_data, r->addr, r->size, r->node,
1428
+ MEM_AFFINITY_ENABLED);
1429
+ region_start = r->addr + r->size;
1430
+ }
1431
+
1432
+ /*
1433
+ * Cover the rest of the device_memory window that no sp-mem device
1434
+ * occupies. Keeping it HOTPLUGGABLE preserves the umbrella entry's
1435
+ * role for future pc-dimm / virtio-mem hot-add into this window.
1436
+ */
1437
+ if (region_start < region_end) {
1438
+ build_srat_memory(table_data, region_start, region_end - region_start,
1439
+ hotplug_pxm,
1440
+ MEM_AFFINITY_HOTPLUGGABLE |
1441
+ MEM_AFFINITY_ENABLED);
1442
+ }
1443
+}
1444
+
1445
#define HOLE_640K_START (640 * KiB)
1446
#define HOLE_640K_END (1 * MiB)
1447
@@ -1487,10 +1578,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
1578
* providing _PXM method if necessary.
1579
*/
1580
if (machine->device_memory) {
1490
- build_srat_memory(table_data, machine->device_memory->base,
1491
- memory_region_size(&machine->device_memory->mr),
1492
- nb_numa_nodes - 1,
1493
- MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
1581
+ build_srat_device_memory(table_data, machine);
1582
}
1583
1584
acpi_table_end(linker, &table);