* [PATCH v10 0/4] hw/mem: add sp-mem device for Specific Purpose Memory
@ 2026-06-05 10:46 fanhuang
2026-06-05 10:46 ` [PATCH v10 1/4] " fanhuang
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: fanhuang @ 2026-06-05 10:46 UTC (permalink / raw)
To: qemu-devel, david, imammedo, gourry, philmd
Cc: Zhigang.Luo, Lianjie.Shi, fanhuang
This series adds a TYPE_MEMORY_DEVICE subclass `sp-mem` for boot-time
SOFT_RESERVED guest memory, following the direction from the v7
thread [1] and the v8 / v9 reviews [2][3].
Background
----------
This series targets coherent CPU + accelerator shared-address-space
systems, where the accelerator's HBM is not a device-private
framebuffer behind a PCIe BAR but a tier of host system memory:
visible to the CPU in the platform physical address space, shared
coherently with the accelerator over the platform fabric, and bound
to a NUMA proximity domain set by platform firmware at boot fabric
training.
For such a region to function correctly in the guest, two things
must hold simultaneously: the CPU memory subsystem has to see it in
the system memory map (so the CPU side can address it), and it has
to be reserved exclusively for the accelerator's driver (so the
kernel's general allocator does not hand SPM pages to unrelated
workloads). The SOFT_RESERVED memory type in E820 plus a matching
SRAT memory-affinity entry is the mechanism that delivers both: a
firmware-produced topology that the CPU memory subsystem honors and
the accelerator's driver consumes for its own range.
Approach
--------
The series introduces a new TYPE_MEMORY_DEVICE subclass `sp-mem`.
Each instance binds one host memory backend to a single NUMA
proximity domain and is boot-time only; placement, mapped-state
enforcement, and QMP introspection come from the existing
memory-device framework.
Testing
-------
Verified end-to-end on q35 + KVM, with both SeaBIOS and OVMF, for:
- single sp-mem instance
- two sp-mem instances on different NUMA nodes
Guest observations: /proc/iomem shows one SOFT_RESERVED entry per
sp-mem device, dmesg SRAT parsing reports the matching
memory_affinity entries with correct PXM, and the umbrella
HOTPLUGGABLE entry covers the remaining hotplug-memory window
without overlapping the sp-mem ranges.
Changes since v9
----------------
- Rename `spm-memory` to `sp-mem` throughout (cmdline, file,
TYPE_, QAPI enum, Kconfig, struct).
- Drop the redundant `_md_` infix from local memory-device
methods.
- Drop the empty `SpmDeviceClass` struct and switch to
`OBJECT_DECLARE_SIMPLE_TYPE`.
- Drop the `/*< private >*/` / `/*< public >*/` markers in the
header.
- Use `DEFINE_TYPES()` instead of `type_register_static`.
- Comment why `.unmigratable = 1`.
- Validate the `node` property in pc_sp_mem_pre_plug().
- Move the `select SP_MEM` Kconfig hunks for i440fx and Q35 from
patch 1/4 into patch 3/4.
- MAINTAINERS: add an `R:` line for myself under Memory devices.
Keep MAINTAINERS as a separate patch.
Previous versions
-----------------
v1: https://lore.kernel.org/qemu-devel/20250924103324.2074819-1-FangSheng.Huang@amd.com/
v2: https://lore.kernel.org/qemu-devel/20251020090701.4036748-1-FangSheng.Huang@amd.com/
v3: https://lore.kernel.org/qemu-devel/20251208105137.2058928-1-FangSheng.Huang@amd.com/
v4: https://lore.kernel.org/qemu-devel/20251209093841.2250527-1-FangSheng.Huang@amd.com/
v5: https://lore.kernel.org/qemu-devel/20260123024312.1601732-1-FangSheng.Huang@amd.com/
v6: https://lore.kernel.org/qemu-devel/20260226105023.256568-1-FangSheng.Huang@amd.com/
v7: https://lore.kernel.org/qemu-devel/20260306082735.1106690-1-FangSheng.Huang@amd.com/
v8: https://lore.kernel.org/qemu-devel/20260527074215.229119-1-FangSheng.Huang@amd.com/
v9: https://lore.kernel.org/qemu-devel/20260602084447.1100554-1-FangSheng.Huang@amd.com/
[1] v7 thread closeout:
https://lore.kernel.org/qemu-devel/666a7ba1-5d3a-4732-b872-0d9fb2fe8461@amd.com/
[2] v8 review:
https://lore.kernel.org/qemu-devel/20260601105057.2d764e55@imammedo/
[3] v9 review:
https://lore.kernel.org/qemu-devel/20260602084447.1100554-1-FangSheng.Huang@amd.com/T/
fanhuang (4):
hw/mem: add sp-mem device for Specific Purpose Memory
i386/acpi-build: partition device_memory SRAT umbrella for sp-mem
hw/i386: hook sp-mem into the pc machine plug path
MAINTAINERS: cover sp-mem under Memory devices, add R: tag
MAINTAINERS | 3 +
qapi/machine.json | 43 +++++++++++-
hw/i386/e820_memory_layout.h | 11 +--
include/hw/mem/sp-mem.h | 35 ++++++++++
hw/i386/acpi-build.c | 98 ++++++++++++++++++++++++--
hw/i386/pc.c | 42 +++++++++++
hw/mem/sp-mem.c | 130 +++++++++++++++++++++++++++++++++++
hw/i386/Kconfig | 2 +
hw/mem/Kconfig | 4 ++
hw/mem/meson.build | 1 +
10 files changed, 356 insertions(+), 13 deletions(-)
create mode 100644 include/hw/mem/sp-mem.h
create mode 100644 hw/mem/sp-mem.c
base-commit: 405c32d2b18a683ba36301351af75125d9afda08
--
2.34.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v10 1/4] hw/mem: add sp-mem device for Specific Purpose Memory
2026-06-05 10:46 [PATCH v10 0/4] hw/mem: add sp-mem device for Specific Purpose Memory fanhuang
@ 2026-06-05 10:46 ` fanhuang
2026-06-05 15:10 ` David Hildenbrand (Arm)
` (2 more replies)
2026-06-05 10:46 ` [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem fanhuang
` (2 subsequent siblings)
3 siblings, 3 replies; 14+ messages in thread
From: fanhuang @ 2026-06-05 10:46 UTC (permalink / raw)
To: qemu-devel, david, imammedo, gourry, philmd
Cc: Zhigang.Luo, Lianjie.Shi, fanhuang
Introduce a TYPE_MEMORY_DEVICE subclass `sp-mem` for boot-time
SOFT_RESERVED memory exposed to the guest with a per-device NUMA
proximity domain.
The device targets accelerator memory (HBM and similar) that the
firmware hands to the guest OS as SOFT_RESERVED memory, so a driver
in the guest -- rather than the kernel's general allocator -- owns
the range.
Usage:
-object memory-backend-ram,id=spm0,size=$SIZE
-numa node,nodeid=$N
-device sp-mem,id=dev0,memdev=spm0,node=$N[,addr=$GPA]
The device is boot-time only (no hotplug).
Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
---
qapi/machine.json | 43 ++++++++++++-
include/hw/mem/sp-mem.h | 35 +++++++++++
hw/mem/sp-mem.c | 130 ++++++++++++++++++++++++++++++++++++++++
hw/mem/Kconfig | 4 ++
hw/mem/meson.build | 1 +
5 files changed, 211 insertions(+), 2 deletions(-)
create mode 100644 include/hw/mem/sp-mem.h
create mode 100644 hw/mem/sp-mem.c
diff --git a/qapi/machine.json b/qapi/machine.json
index 685e4e29b8..41cc3a188a 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1413,6 +1413,32 @@
}
}
+##
+# @SpMemDeviceInfo:
+#
+# sp-mem device state information
+#
+# @id: device's ID
+#
+# @memaddr: physical address in memory, where device is mapped
+#
+# @size: size of memory that the device provides
+#
+# @node: NUMA proximity domain to which the device is assigned
+#
+# @memdev: memory backend linked with device
+#
+# Since: 11.1
+##
+{ 'struct': 'SpMemDeviceInfo',
+ 'data': { '*id': 'str',
+ 'memaddr': 'size',
+ 'size': 'size',
+ 'node': 'int',
+ 'memdev': 'str'
+ }
+}
+
##
# @MemoryDeviceInfoKind:
#
@@ -1426,11 +1452,13 @@
#
# @hv-balloon: since 8.2.
#
+# @sp-mem: since 11.1.
+#
# Since: 2.1
##
{ 'enum': 'MemoryDeviceInfoKind',
'data': [ 'dimm', 'nvdimm', 'virtio-pmem', 'virtio-mem', 'sgx-epc',
- 'hv-balloon' ] }
+ 'hv-balloon', 'sp-mem' ] }
##
# @PCDIMMDeviceInfoWrapper:
@@ -1482,6 +1510,16 @@
{ 'struct': 'HvBalloonDeviceInfoWrapper',
'data': { 'data': 'HvBalloonDeviceInfo' } }
+##
+# @SpMemDeviceInfoWrapper:
+#
+# @data: sp-mem device state information
+#
+# Since: 11.1
+##
+{ 'struct': 'SpMemDeviceInfoWrapper',
+ 'data': { 'data': 'SpMemDeviceInfo' } }
+
##
# @MemoryDeviceInfo:
#
@@ -1499,7 +1537,8 @@
'virtio-pmem': 'VirtioPMEMDeviceInfoWrapper',
'virtio-mem': 'VirtioMEMDeviceInfoWrapper',
'sgx-epc': 'SgxEPCDeviceInfoWrapper',
- 'hv-balloon': 'HvBalloonDeviceInfoWrapper'
+ 'hv-balloon': 'HvBalloonDeviceInfoWrapper',
+ 'sp-mem': 'SpMemDeviceInfoWrapper'
}
}
diff --git a/include/hw/mem/sp-mem.h b/include/hw/mem/sp-mem.h
new file mode 100644
index 0000000000..5c0b6ec4f8
--- /dev/null
+++ b/include/hw/mem/sp-mem.h
@@ -0,0 +1,35 @@
+/*
+ * Specific Purpose Memory (SPM) device
+ *
+ * TYPE_MEMORY_DEVICE subclass for boot-time-only memory exposed to the
+ * guest as an E820 SOFT_RESERVED range with a SRAT memory-affinity entry.
+ *
+ * Copyright (c) 2026 Advanced Micro Devices, Inc.
+ *
+ * Authors:
+ * FangSheng Huang <FangSheng.Huang@amd.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_SP_MEM_H
+#define QEMU_SP_MEM_H
+
+#include "hw/mem/memory-device.h"
+#include "hw/core/qdev.h"
+#include "qom/object.h"
+#include "system/hostmem.h"
+
+#define TYPE_SP_MEM "sp-mem"
+
+OBJECT_DECLARE_SIMPLE_TYPE(SpMemDevice, SP_MEM)
+
+struct SpMemDevice {
+ DeviceState parent_obj;
+
+ HostMemoryBackend *hostmem;
+ uint32_t node;
+ uint64_t addr;
+};
+
+#endif /* QEMU_SP_MEM_H */
diff --git a/hw/mem/sp-mem.c b/hw/mem/sp-mem.c
new file mode 100644
index 0000000000..f6ba9a6d7c
--- /dev/null
+++ b/hw/mem/sp-mem.c
@@ -0,0 +1,130 @@
+/*
+ * Specific Purpose Memory (SPM) device
+ *
+ * Copyright (c) 2026 Advanced Micro Devices, Inc.
+ *
+ * Authors:
+ * FangSheng Huang <FangSheng.Huang@amd.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/qdev.h"
+#include "hw/mem/sp-mem.h"
+#include "hw/mem/memory-device.h"
+#include "migration/vmstate.h"
+#include "system/hostmem.h"
+
+#define SP_MEM_MEMDEV_PROP "memdev"
+#define SP_MEM_NODE_PROP "node"
+#define SP_MEM_ADDR_PROP "addr"
+
+static const Property sp_mem_properties[] = {
+ DEFINE_PROP_LINK(SP_MEM_MEMDEV_PROP, SpMemDevice, hostmem,
+ TYPE_MEMORY_BACKEND, HostMemoryBackend *),
+ DEFINE_PROP_UINT32(SP_MEM_NODE_PROP, SpMemDevice, node, 0),
+ DEFINE_PROP_UINT64(SP_MEM_ADDR_PROP, SpMemDevice, addr, 0),
+};
+
+static uint64_t sp_mem_get_addr(const MemoryDeviceState *md)
+{
+ return SP_MEM(md)->addr;
+}
+
+static void sp_mem_set_addr(MemoryDeviceState *md, uint64_t addr,
+ Error **errp)
+{
+ SP_MEM(md)->addr = addr;
+}
+
+static MemoryRegion *sp_mem_get_memory_region(MemoryDeviceState *md,
+ Error **errp)
+{
+ SpMemDevice *spm = SP_MEM(md);
+
+ if (!spm->hostmem) {
+ error_setg(errp, "'memdev' property must be set");
+ return NULL;
+ }
+ return host_memory_backend_get_memory(spm->hostmem);
+}
+
+static uint64_t sp_mem_get_plugged_size(const MemoryDeviceState *md,
+ Error **errp)
+{
+ SpMemDevice *spm = SP_MEM(md);
+ return spm->hostmem ?
+ memory_region_size(host_memory_backend_get_memory(spm->hostmem)) : 0;
+}
+
+static void sp_mem_fill_device_info(const MemoryDeviceState *md,
+ MemoryDeviceInfo *info)
+{
+ SpMemDeviceInfo *di = g_new0(SpMemDeviceInfo, 1);
+ SpMemDevice *spm = SP_MEM(md);
+ DeviceState *dev = DEVICE(md);
+
+ di->id = dev->id ? g_strdup(dev->id) : NULL;
+ di->memaddr = spm->addr;
+ di->size = spm->hostmem ? memory_region_size(
+ host_memory_backend_get_memory(spm->hostmem)) : 0;
+ di->node = spm->node;
+ di->memdev = spm->hostmem ?
+ object_get_canonical_path(OBJECT(spm->hostmem)) : NULL;
+
+ info->u.sp_mem.data = di;
+ info->type = MEMORY_DEVICE_INFO_KIND_SP_MEM;
+}
+
+static void sp_mem_realize(DeviceState *dev, Error **errp)
+{
+ SpMemDevice *spm = SP_MEM(dev);
+
+ if (!spm->hostmem) {
+ error_setg(errp, "'%s' property is required", SP_MEM_MEMDEV_PROP);
+ return;
+ }
+}
+
+/* boot-time only; no plug/unplug state to migrate */
+static const VMStateDescription vmstate_sp_mem = {
+ .name = TYPE_SP_MEM,
+ .unmigratable = 1,
+};
+
+static void sp_mem_class_init(ObjectClass *oc, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
+
+ dc->desc = "SPM (Specific Purpose Memory) device";
+ dc->hotpluggable = false;
+ dc->realize = sp_mem_realize;
+ dc->vmsd = &vmstate_sp_mem;
+ device_class_set_props(dc, sp_mem_properties);
+
+ mdc->get_addr = sp_mem_get_addr;
+ mdc->set_addr = sp_mem_set_addr;
+ mdc->get_memory_region = sp_mem_get_memory_region;
+ mdc->get_plugged_size = sp_mem_get_plugged_size;
+ mdc->fill_device_info = sp_mem_fill_device_info;
+}
+
+static const TypeInfo sp_mem_types[] = {
+ {
+ .name = TYPE_SP_MEM,
+ .parent = TYPE_DEVICE,
+ .class_init = sp_mem_class_init,
+ .instance_size = sizeof(SpMemDevice),
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_MEMORY_DEVICE },
+ { }
+ },
+ },
+};
+
+DEFINE_TYPES(sp_mem_types)
diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig
index 73c5ae8ad9..39ddb36710 100644
--- a/hw/mem/Kconfig
+++ b/hw/mem/Kconfig
@@ -16,3 +16,7 @@ config CXL_MEM_DEVICE
bool
default y if CXL
select MEM_DEVICE
+
+config SP_MEM
+ bool
+ select MEM_DEVICE
diff --git a/hw/mem/meson.build b/hw/mem/meson.build
index 8c2beeb7d4..f410d75475 100644
--- a/hw/mem/meson.build
+++ b/hw/mem/meson.build
@@ -4,6 +4,7 @@ mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c'))
mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c'))
mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c'))
mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c'))
+mem_ss.add(when: 'CONFIG_SP_MEM', if_true: files('sp-mem.c'))
stub_ss.add(files('cxl_type3_stubs.c'))
stub_ss.add(files('memory-device-stubs.c'))
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem
2026-06-05 10:46 [PATCH v10 0/4] hw/mem: add sp-mem device for Specific Purpose Memory fanhuang
2026-06-05 10:46 ` [PATCH v10 1/4] " fanhuang
@ 2026-06-05 10:46 ` fanhuang
2026-06-05 21:27 ` Gregory Price
2026-06-09 11:14 ` Igor Mammedov
2026-06-05 10:46 ` [PATCH v10 3/4] hw/i386: hook sp-mem into the pc machine plug path fanhuang
2026-06-05 10:46 ` [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag fanhuang
3 siblings, 2 replies; 14+ messages in thread
From: fanhuang @ 2026-06-05 10:46 UTC (permalink / raw)
To: qemu-devel, david, imammedo, gourry, philmd
Cc: Zhigang.Luo, Lianjie.Shi, fanhuang
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>
---
hw/i386/acpi-build.c | 98 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 92 insertions(+), 6 deletions(-)
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 0d7c83d5e9..76efa83808 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 collect_sp_mem_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));
+ uint64_t cursor, end;
+ int nb_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0;
+ uint32_t hotplug_pxm = nb_nodes > 0 ? nb_nodes - 1 : 0;
+ guint i;
+
+ if (!ms->device_memory) {
+ return;
+ }
+
+ cursor = ms->device_memory->base;
+ end = cursor + memory_region_size(&ms->device_memory->mr);
+
+ object_child_foreach_recursive(qdev_get_machine(),
+ collect_sp_mem_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 (cursor < r->addr) {
+ build_srat_memory(table_data, cursor, r->addr - cursor,
+ hotplug_pxm,
+ MEM_AFFINITY_HOTPLUGGABLE |
+ MEM_AFFINITY_ENABLED);
+ }
+ build_srat_memory(table_data, r->addr, r->size, r->node,
+ MEM_AFFINITY_ENABLED);
+ cursor = r->addr + r->size;
+ }
+
+ if (cursor < end) {
+ build_srat_memory(table_data, cursor, end - cursor,
+ hotplug_pxm,
+ MEM_AFFINITY_HOTPLUGGABLE |
+ MEM_AFFINITY_ENABLED);
+ }
+}
+
#define HOLE_640K_START (640 * KiB)
#define HOLE_640K_END (1 * MiB)
@@ -1481,12 +1572,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
* Memory devices may override proximity set by this entry,
* 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);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 3/4] hw/i386: hook sp-mem into the pc machine plug path
2026-06-05 10:46 [PATCH v10 0/4] hw/mem: add sp-mem device for Specific Purpose Memory fanhuang
2026-06-05 10:46 ` [PATCH v10 1/4] " fanhuang
2026-06-05 10:46 ` [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem fanhuang
@ 2026-06-05 10:46 ` fanhuang
2026-06-09 11:52 ` Igor Mammedov
2026-06-05 10:46 ` [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag fanhuang
3 siblings, 1 reply; 14+ messages in thread
From: fanhuang @ 2026-06-05 10:46 UTC (permalink / raw)
To: qemu-devel, david, imammedo, gourry, philmd
Cc: Zhigang.Luo, Lianjie.Shi, fanhuang
Add the pc machine hookup for TYPE_SP_MEM so each sp-mem instance is
placed by the memory-device framework and reported to the guest as
E820_SOFT_RESERVED.
Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
---
hw/i386/e820_memory_layout.h | 11 +++++-----
hw/i386/pc.c | 42 ++++++++++++++++++++++++++++++++++++
hw/i386/Kconfig | 2 ++
3 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/hw/i386/e820_memory_layout.h b/hw/i386/e820_memory_layout.h
index b50acfa201..6ef169db9c 100644
--- a/hw/i386/e820_memory_layout.h
+++ b/hw/i386/e820_memory_layout.h
@@ -10,11 +10,12 @@
#define HW_I386_E820_MEMORY_LAYOUT_H
/* e820 types */
-#define E820_RAM 1
-#define E820_RESERVED 2
-#define E820_ACPI 3
-#define E820_NVS 4
-#define E820_UNUSABLE 5
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_UNUSABLE 5
+#define E820_SOFT_RESERVED 0xefffffff
struct e820_entry {
uint64_t address;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 2ecad3c503..b538f49f23 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -63,6 +63,7 @@
#include "hw/i386/kvm/xen_gnttab.h"
#include "hw/i386/kvm/xen_xenstore.h"
#include "hw/mem/memory-device.h"
+#include "hw/mem/sp-mem.h"
#include "e820_memory_layout.h"
#include "trace.h"
#include "sev.h"
@@ -1283,11 +1284,49 @@ static void pc_hv_balloon_plug(HotplugHandler *hotplug_dev,
memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
}
+static void pc_sp_mem_pre_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ MachineState *ms = MACHINE(hotplug_dev);
+ SpMemDevice *spm = SP_MEM(dev);
+
+ if (host_memory_backend_is_mapped(spm->hostmem)) {
+ error_setg(errp, "memory backend '%s' is already in use",
+ object_get_canonical_path_component(OBJECT(spm->hostmem)));
+ return;
+ }
+ if (ms->numa_state && spm->node >= ms->numa_state->num_nodes) {
+ error_setg(errp,
+ "'node' property value %" PRIu32
+ " exceeds the number of NUMA nodes (%d)",
+ spm->node, ms->numa_state->num_nodes);
+ return;
+ }
+ memory_device_pre_plug(MEMORY_DEVICE(dev), ms, errp);
+}
+
+static void pc_sp_mem_plug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ SpMemDevice *spm = SP_MEM(dev);
+ MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(MEMORY_DEVICE(dev));
+ uint64_t addr, size;
+
+ host_memory_backend_set_mapped(spm->hostmem, true);
+ memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
+
+ addr = mdc->get_addr(MEMORY_DEVICE(dev));
+ size = memory_region_size(host_memory_backend_get_memory(spm->hostmem));
+ e820_add_entry(addr, size, E820_SOFT_RESERVED);
+}
+
static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
pc_memory_pre_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SP_MEM)) {
+ pc_sp_mem_pre_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
x86_cpu_pre_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
@@ -1324,6 +1363,8 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
pc_memory_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SP_MEM)) {
+ pc_sp_mem_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
x86_cpu_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
@@ -1368,6 +1409,7 @@ static HotplugHandler *pc_get_hotplug_handler(MachineState *machine,
DeviceState *dev)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_SP_MEM) ||
object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI) ||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index 12473acaa7..e27d8816e5 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -84,6 +84,7 @@ config I440FX
select PCI_I440FX
select PIIX
select DIMM
+ select SP_MEM
select SMBIOS
select SMBIOS_LEGACY
select FW_CFG_DMA
@@ -113,6 +114,7 @@ config Q35
select LPC_ICH9
select AHCI_ICH9
select DIMM
+ select SP_MEM
select SMBIOS
select FW_CFG_DMA
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag
2026-06-05 10:46 [PATCH v10 0/4] hw/mem: add sp-mem device for Specific Purpose Memory fanhuang
` (2 preceding siblings ...)
2026-06-05 10:46 ` [PATCH v10 3/4] hw/i386: hook sp-mem into the pc machine plug path fanhuang
@ 2026-06-05 10:46 ` fanhuang
2026-06-09 11:53 ` Igor Mammedov
2026-06-09 12:51 ` David Hildenbrand (Arm)
3 siblings, 2 replies; 14+ messages in thread
From: fanhuang @ 2026-06-05 10:46 UTC (permalink / raw)
To: qemu-devel, david, imammedo, gourry, philmd
Cc: Zhigang.Luo, Lianjie.Shi, fanhuang
Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
---
MAINTAINERS | 3 +++
1 file changed, 3 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7752917d8c..db34f6cf17 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3361,13 +3361,16 @@ F: scripts/coccinelle/memory-region-housekeeping.cocci
Memory devices
M: David Hildenbrand <david@kernel.org>
M: Igor Mammedov <imammedo@redhat.com>
+R: FangSheng Huang <FangSheng.Huang@amd.com>
S: Supported
F: hw/mem/memory-device*.c
F: hw/mem/nvdimm.c
F: hw/mem/pc-dimm.c
+F: hw/mem/sp-mem.c
F: include/hw/mem/memory-device.h
F: include/hw/mem/nvdimm.h
F: include/hw/mem/pc-dimm.h
+F: include/hw/mem/sp-mem.h
F: docs/nvdimm.txt
SPICE
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v10 1/4] hw/mem: add sp-mem device for Specific Purpose Memory
2026-06-05 10:46 ` [PATCH v10 1/4] " fanhuang
@ 2026-06-05 15:10 ` David Hildenbrand (Arm)
2026-06-05 21:22 ` Gregory Price
2026-06-09 9:03 ` Igor Mammedov
2 siblings, 0 replies; 14+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-05 15:10 UTC (permalink / raw)
To: fanhuang, qemu-devel, imammedo, gourry, philmd; +Cc: Zhigang.Luo, Lianjie.Shi
On 6/5/26 12:46, fanhuang wrote:
> Introduce a TYPE_MEMORY_DEVICE subclass `sp-mem` for boot-time
> SOFT_RESERVED memory exposed to the guest with a per-device NUMA
> proximity domain.
>
> The device targets accelerator memory (HBM and similar) that the
> firmware hands to the guest OS as SOFT_RESERVED memory, so a driver
> in the guest -- rather than the kernel's general allocator -- owns
> the range.
>
> Usage:
>
> -object memory-backend-ram,id=spm0,size=$SIZE
> -numa node,nodeid=$N
> -device sp-mem,id=dev0,memdev=spm0,node=$N[,addr=$GPA]
>
> The device is boot-time only (no hotplug).
>
> Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
> ---
Reviewed-by: David Hildenbrand <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 1/4] hw/mem: add sp-mem device for Specific Purpose Memory
2026-06-05 10:46 ` [PATCH v10 1/4] " fanhuang
2026-06-05 15:10 ` David Hildenbrand (Arm)
@ 2026-06-05 21:22 ` Gregory Price
2026-06-09 9:03 ` Igor Mammedov
2 siblings, 0 replies; 14+ messages in thread
From: Gregory Price @ 2026-06-05 21:22 UTC (permalink / raw)
To: fanhuang; +Cc: qemu-devel, david, imammedo, philmd, Zhigang.Luo, Lianjie.Shi
On Fri, Jun 05, 2026 at 06:46:06PM +0800, fanhuang wrote:
> Introduce a TYPE_MEMORY_DEVICE subclass `sp-mem` for boot-time
> SOFT_RESERVED memory exposed to the guest with a per-device NUMA
> proximity domain.
>
> The device targets accelerator memory (HBM and similar) that the
> firmware hands to the guest OS as SOFT_RESERVED memory, so a driver
> in the guest -- rather than the kernel's general allocator -- owns
> the range.
>
> Usage:
>
> -object memory-backend-ram,id=spm0,size=$SIZE
> -numa node,nodeid=$N
> -device sp-mem,id=dev0,memdev=spm0,node=$N[,addr=$GPA]
>
> The device is boot-time only (no hotplug).
>
> Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
Reviewed-by: Gregory Price <gourry@gourry.net>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem
2026-06-05 10:46 ` [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem fanhuang
@ 2026-06-05 21:27 ` Gregory Price
2026-06-09 3:53 ` Huang, FangSheng (Jerry)
2026-06-09 11:14 ` Igor Mammedov
1 sibling, 1 reply; 14+ messages in thread
From: Gregory Price @ 2026-06-05 21:27 UTC (permalink / raw)
To: fanhuang; +Cc: qemu-devel, david, imammedo, philmd, Zhigang.Luo, Lianjie.Shi
On Fri, Jun 05, 2026 at 06:46:07PM +0800, fanhuang 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 <FangSheng.Huang@amd.com>
> ---
> hw/i386/acpi-build.c | 98 +++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 92 insertions(+), 6 deletions(-)
>
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 0d7c83d5e9..76efa83808 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 collect_sp_mem_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));
> + uint64_t cursor, end;
> + int nb_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0;
> + uint32_t hotplug_pxm = nb_nodes > 0 ? nb_nodes - 1 : 0;
> + guint i;
> +
> + if (!ms->device_memory) {
> + return;
> + }
> +
> + cursor = ms->device_memory->base;
> + end = cursor + memory_region_size(&ms->device_memory->mr);
> +
> + object_child_foreach_recursive(qdev_get_machine(),
> + collect_sp_mem_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 (cursor < r->addr) {
> + build_srat_memory(table_data, cursor, r->addr - cursor,
> + hotplug_pxm,
> + MEM_AFFINITY_HOTPLUGGABLE |
> + MEM_AFFINITY_ENABLED);
> + }
> + build_srat_memory(table_data, r->addr, r->size, r->node,
> + MEM_AFFINITY_ENABLED);
> + cursor = r->addr + r->size;
> + }
> +
Should we expect (cursor == end) here and fire a warning if there wasn't
a full range to cover the region? If not - why set it all as
hotpluggable anyway?
(Maybe just worth a comment here what the last block is actually doing)
> + if (cursor < end) {
> + build_srat_memory(table_data, cursor, end - cursor,
> + hotplug_pxm,
> + MEM_AFFINITY_HOTPLUGGABLE |
> + MEM_AFFINITY_ENABLED);
> + }
> +}
> +
> #define HOLE_640K_START (640 * KiB)
> #define HOLE_640K_END (1 * MiB)
>
> @@ -1481,12 +1572,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
> * Memory devices may override proximity set by this entry,
> * 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);
> }
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem
2026-06-05 21:27 ` Gregory Price
@ 2026-06-09 3:53 ` Huang, FangSheng (Jerry)
0 siblings, 0 replies; 14+ messages in thread
From: Huang, FangSheng (Jerry) @ 2026-06-09 3:53 UTC (permalink / raw)
To: Gregory Price
Cc: qemu-devel, david, imammedo, philmd, Zhigang.Luo, Lianjie.Shi
On 6/6/2026 5:27 AM, Gregory Price wrote:
> On Fri, Jun 05, 2026 at 06:46:07PM +0800, fanhuang 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 <FangSheng.Huang@amd.com>
>> ---
>> hw/i386/acpi-build.c | 98 +++++++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 92 insertions(+), 6 deletions(-)
>>
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 0d7c83d5e9..76efa83808 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 collect_sp_mem_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));
>> + uint64_t cursor, end;
>> + int nb_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0;
>> + uint32_t hotplug_pxm = nb_nodes > 0 ? nb_nodes - 1 : 0;
>> + guint i;
>> +
>> + if (!ms->device_memory) {
>> + return;
>> + }
>> +
>> + cursor = ms->device_memory->base;
>> + end = cursor + memory_region_size(&ms->device_memory->mr);
>> +
>> + object_child_foreach_recursive(qdev_get_machine(),
>> + collect_sp_mem_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 (cursor < r->addr) {
>> + build_srat_memory(table_data, cursor, r->addr - cursor,
>> + hotplug_pxm,
>> + MEM_AFFINITY_HOTPLUGGABLE |
>> + MEM_AFFINITY_ENABLED);
>> + }
>> + build_srat_memory(table_data, r->addr, r->size, r->node,
>> + MEM_AFFINITY_ENABLED);
>> + cursor = r->addr + r->size;
>> + }
>> +
>
> Should we expect (cursor == end) here and fire a warning if there wasn't
> a full range to cover the region? If not - why set it all as
> hotpluggable anyway?
>
> (Maybe just worth a comment here what the last block is actually doing)
>
Thanks, Gregory.
(cursor == end) is not an invariant — ms->device_memory is sized
for the maxmem cap, so sp-mem typically leaves the rest of the
window unused. The trailing HOTPLUGGABLE | ENABLED entry covers
that remainder so future pc-dimm / virtio-mem hot-add into the same
window still sees a properly-flagged SRAT range, preserving the
prior umbrella behaviour.
Agreed on the inline comment; will include if/when we respin.
>> + if (cursor < end) {
>> + build_srat_memory(table_data, cursor, end - cursor,
>> + hotplug_pxm,
>> + MEM_AFFINITY_HOTPLUGGABLE |
>> + MEM_AFFINITY_ENABLED);
>> + }
>> +}
>> +
>> #define HOLE_640K_START (640 * KiB)
>> #define HOLE_640K_END (1 * MiB)
>>
>> @@ -1481,12 +1572,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
>> * Memory devices may override proximity set by this entry,
>> * 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);
>> }
>> --
>> 2.34.1
>>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 1/4] hw/mem: add sp-mem device for Specific Purpose Memory
2026-06-05 10:46 ` [PATCH v10 1/4] " fanhuang
2026-06-05 15:10 ` David Hildenbrand (Arm)
2026-06-05 21:22 ` Gregory Price
@ 2026-06-09 9:03 ` Igor Mammedov
2 siblings, 0 replies; 14+ messages in thread
From: Igor Mammedov @ 2026-06-09 9:03 UTC (permalink / raw)
To: fanhuang; +Cc: qemu-devel, david, gourry, philmd, Zhigang.Luo, Lianjie.Shi
On Fri, 5 Jun 2026 18:46:06 +0800
fanhuang <FangSheng.Huang@amd.com> wrote:
> Introduce a TYPE_MEMORY_DEVICE subclass `sp-mem` for boot-time
> SOFT_RESERVED memory exposed to the guest with a per-device NUMA
> proximity domain.
>
> The device targets accelerator memory (HBM and similar) that the
> firmware hands to the guest OS as SOFT_RESERVED memory, so a driver
> in the guest -- rather than the kernel's general allocator -- owns
> the range.
>
> Usage:
>
> -object memory-backend-ram,id=spm0,size=$SIZE
> -numa node,nodeid=$N
> -device sp-mem,id=dev0,memdev=spm0,node=$N[,addr=$GPA]
>
> The device is boot-time only (no hotplug).
>
> Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
> ---
> qapi/machine.json | 43 ++++++++++++-
> include/hw/mem/sp-mem.h | 35 +++++++++++
> hw/mem/sp-mem.c | 130 ++++++++++++++++++++++++++++++++++++++++
> hw/mem/Kconfig | 4 ++
> hw/mem/meson.build | 1 +
> 5 files changed, 211 insertions(+), 2 deletions(-)
> create mode 100644 include/hw/mem/sp-mem.h
> create mode 100644 hw/mem/sp-mem.c
>
> diff --git a/qapi/machine.json b/qapi/machine.json
> index 685e4e29b8..41cc3a188a 100644
> --- a/qapi/machine.json
> +++ b/qapi/machine.json
> @@ -1413,6 +1413,32 @@
> }
> }
>
> +##
> +# @SpMemDeviceInfo:
> +#
> +# sp-mem device state information
> +#
> +# @id: device's ID
> +#
> +# @memaddr: physical address in memory, where device is mapped
> +#
> +# @size: size of memory that the device provides
> +#
> +# @node: NUMA proximity domain to which the device is assigned
> +#
> +# @memdev: memory backend linked with device
> +#
> +# Since: 11.1
> +##
> +{ 'struct': 'SpMemDeviceInfo',
> + 'data': { '*id': 'str',
> + 'memaddr': 'size',
why not 'addr', like DIMM?
> + 'size': 'size',
> + 'node': 'int',
> + 'memdev': 'str'
> + }
> +}
> +
> ##
> # @MemoryDeviceInfoKind:
> #
> @@ -1426,11 +1452,13 @@
> #
> # @hv-balloon: since 8.2.
> #
> +# @sp-mem: since 11.1.
> +#
> # Since: 2.1
> ##
> { 'enum': 'MemoryDeviceInfoKind',
> 'data': [ 'dimm', 'nvdimm', 'virtio-pmem', 'virtio-mem', 'sgx-epc',
> - 'hv-balloon' ] }
> + 'hv-balloon', 'sp-mem' ] }
>
> ##
> # @PCDIMMDeviceInfoWrapper:
> @@ -1482,6 +1510,16 @@
> { 'struct': 'HvBalloonDeviceInfoWrapper',
> 'data': { 'data': 'HvBalloonDeviceInfo' } }
>
> +##
> +# @SpMemDeviceInfoWrapper:
> +#
> +# @data: sp-mem device state information
> +#
> +# Since: 11.1
> +##
> +{ 'struct': 'SpMemDeviceInfoWrapper',
> + 'data': { 'data': 'SpMemDeviceInfo' } }
> +
> ##
> # @MemoryDeviceInfo:
> #
> @@ -1499,7 +1537,8 @@
> 'virtio-pmem': 'VirtioPMEMDeviceInfoWrapper',
> 'virtio-mem': 'VirtioMEMDeviceInfoWrapper',
> 'sgx-epc': 'SgxEPCDeviceInfoWrapper',
> - 'hv-balloon': 'HvBalloonDeviceInfoWrapper'
> + 'hv-balloon': 'HvBalloonDeviceInfoWrapper',
> + 'sp-mem': 'SpMemDeviceInfoWrapper'
> }
> }
>
> diff --git a/include/hw/mem/sp-mem.h b/include/hw/mem/sp-mem.h
> new file mode 100644
> index 0000000000..5c0b6ec4f8
> --- /dev/null
> +++ b/include/hw/mem/sp-mem.h
> @@ -0,0 +1,35 @@
> +/*
> + * Specific Purpose Memory (SPM) device
> + *
> + * TYPE_MEMORY_DEVICE subclass for boot-time-only memory exposed to the
> + * guest as an E820 SOFT_RESERVED range with a SRAT memory-affinity entry.
> + *
> + * Copyright (c) 2026 Advanced Micro Devices, Inc.
> + *
> + * Authors:
> + * FangSheng Huang <FangSheng.Huang@amd.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef QEMU_SP_MEM_H
> +#define QEMU_SP_MEM_H
> +
> +#include "hw/mem/memory-device.h"
> +#include "hw/core/qdev.h"
> +#include "qom/object.h"
> +#include "system/hostmem.h"
> +
> +#define TYPE_SP_MEM "sp-mem"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(SpMemDevice, SP_MEM)
> +
> +struct SpMemDevice {
> + DeviceState parent_obj;
> +
> + HostMemoryBackend *hostmem;
> + uint32_t node;
> + uint64_t addr;
> +};
> +
> +#endif /* QEMU_SP_MEM_H */
> diff --git a/hw/mem/sp-mem.c b/hw/mem/sp-mem.c
> new file mode 100644
> index 0000000000..f6ba9a6d7c
> --- /dev/null
> +++ b/hw/mem/sp-mem.c
> @@ -0,0 +1,130 @@
> +/*
> + * Specific Purpose Memory (SPM) device
> + *
> + * Copyright (c) 2026 Advanced Micro Devices, Inc.
> + *
> + * Authors:
> + * FangSheng Huang <FangSheng.Huang@amd.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/module.h"
> +#include "qapi/error.h"
> +#include "hw/core/qdev-properties.h"
> +#include "hw/core/qdev.h"
> +#include "hw/mem/sp-mem.h"
> +#include "hw/mem/memory-device.h"
> +#include "migration/vmstate.h"
> +#include "system/hostmem.h"
> +
> +#define SP_MEM_MEMDEV_PROP "memdev"
> +#define SP_MEM_NODE_PROP "node"
> +#define SP_MEM_ADDR_PROP "addr"
> +
> +static const Property sp_mem_properties[] = {
> + DEFINE_PROP_LINK(SP_MEM_MEMDEV_PROP, SpMemDevice, hostmem,
> + TYPE_MEMORY_BACKEND, HostMemoryBackend *),
> + DEFINE_PROP_UINT32(SP_MEM_NODE_PROP, SpMemDevice, node, 0),
> + DEFINE_PROP_UINT64(SP_MEM_ADDR_PROP, SpMemDevice, addr, 0),
> +};
> +
> +static uint64_t sp_mem_get_addr(const MemoryDeviceState *md)
> +{
> + return SP_MEM(md)->addr;
device cast + deref, should be separate. or even better look at
pc_dimm_md_get_addr()
> +}
> +
> +static void sp_mem_set_addr(MemoryDeviceState *md, uint64_t addr,
> + Error **errp)
> +{
> + SP_MEM(md)->addr = addr;
> +}
ditto
> +
> +static MemoryRegion *sp_mem_get_memory_region(MemoryDeviceState *md,
> + Error **errp)
> +{
> + SpMemDevice *spm = SP_MEM(md);
> +
> + if (!spm->hostmem) {
> + error_setg(errp, "'memdev' property must be set");
> + return NULL;
> + }
> + return host_memory_backend_get_memory(spm->hostmem);
> +}
> +
> +static uint64_t sp_mem_get_plugged_size(const MemoryDeviceState *md,
> + Error **errp)
> +{
> + SpMemDevice *spm = SP_MEM(md);
> + return spm->hostmem ?
> + memory_region_size(host_memory_backend_get_memory(spm->hostmem)) : 0;
> +}
> +
> +static void sp_mem_fill_device_info(const MemoryDeviceState *md,
> + MemoryDeviceInfo *info)
> +{
> + SpMemDeviceInfo *di = g_new0(SpMemDeviceInfo, 1);
> + SpMemDevice *spm = SP_MEM(md);
> + DeviceState *dev = DEVICE(md);
> +
> + di->id = dev->id ? g_strdup(dev->id) : NULL;
> + di->memaddr = spm->addr;
> + di->size = spm->hostmem ? memory_region_size(
> + host_memory_backend_get_memory(spm->hostmem)) : 0;
why conditional?
> + di->node = spm->node;
> + di->memdev = spm->hostmem ?
> + object_get_canonical_path(OBJECT(spm->hostmem)) : NULL;
ditto
> +
> + info->u.sp_mem.data = di;
> + info->type = MEMORY_DEVICE_INFO_KIND_SP_MEM;
> +}
> +
> +static void sp_mem_realize(DeviceState *dev, Error **errp)
> +{
> + SpMemDevice *spm = SP_MEM(dev);
> +
> + if (!spm->hostmem) {
> + error_setg(errp, "'%s' property is required", SP_MEM_MEMDEV_PROP);
> + return;
> + }
> +}
> +
> +/* boot-time only; no plug/unplug state to migrate */
> +static const VMStateDescription vmstate_sp_mem = {
> + .name = TYPE_SP_MEM,
> + .unmigratable = 1,
> +};
> +
> +static void sp_mem_class_init(ObjectClass *oc, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(oc);
> + MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
> +
> + dc->desc = "SPM (Specific Purpose Memory) device";
> + dc->hotpluggable = false;
> + dc->realize = sp_mem_realize;
> + dc->vmsd = &vmstate_sp_mem;
> + device_class_set_props(dc, sp_mem_properties);
> +
> + mdc->get_addr = sp_mem_get_addr;
> + mdc->set_addr = sp_mem_set_addr;
> + mdc->get_memory_region = sp_mem_get_memory_region;
> + mdc->get_plugged_size = sp_mem_get_plugged_size;
^^^^
wouldn't memory_device_get_region_size() do here?
> + mdc->fill_device_info = sp_mem_fill_device_info;
> +}
> +
> +static const TypeInfo sp_mem_types[] = {
> + {
> + .name = TYPE_SP_MEM,
> + .parent = TYPE_DEVICE,
> + .class_init = sp_mem_class_init,
> + .instance_size = sizeof(SpMemDevice),
> + .interfaces = (InterfaceInfo[]) {
> + { TYPE_MEMORY_DEVICE },
> + { }
> + },
> + },
> +};
> +
> +DEFINE_TYPES(sp_mem_types)
> diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig
> index 73c5ae8ad9..39ddb36710 100644
> --- a/hw/mem/Kconfig
> +++ b/hw/mem/Kconfig
> @@ -16,3 +16,7 @@ config CXL_MEM_DEVICE
> bool
> default y if CXL
> select MEM_DEVICE
> +
> +config SP_MEM
> + bool
> + select MEM_DEVICE
> diff --git a/hw/mem/meson.build b/hw/mem/meson.build
> index 8c2beeb7d4..f410d75475 100644
> --- a/hw/mem/meson.build
> +++ b/hw/mem/meson.build
> @@ -4,6 +4,7 @@ mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c'))
> mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c'))
> mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c'))
> mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c'))
> +mem_ss.add(when: 'CONFIG_SP_MEM', if_true: files('sp-mem.c'))
> stub_ss.add(files('cxl_type3_stubs.c'))
>
> stub_ss.add(files('memory-device-stubs.c'))
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem
2026-06-05 10:46 ` [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem fanhuang
2026-06-05 21:27 ` Gregory Price
@ 2026-06-09 11:14 ` Igor Mammedov
1 sibling, 0 replies; 14+ messages in thread
From: Igor Mammedov @ 2026-06-09 11:14 UTC (permalink / raw)
To: fanhuang; +Cc: qemu-devel, david, gourry, philmd, Zhigang.Luo, Lianjie.Shi
On Fri, 5 Jun 2026 18:46:07 +0800
fanhuang <FangSheng.Huang@amd.com> 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 <FangSheng.Huang@amd.com>
> ---
> hw/i386/acpi-build.c | 98 +++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 92 insertions(+), 6 deletions(-)
>
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 0d7c83d5e9..76efa83808 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 collect_sp_mem_ranges_cb(Object *obj, void *opaque)
sp_mem_collect... maybe
> +{
> + 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));
> + uint64_t cursor, end;
region_start, region_end
> + int nb_nodes = ms->numa_state ? ms->numa_state->num_nodes : 0;
> + uint32_t hotplug_pxm = nb_nodes > 0 ? nb_nodes - 1 : 0;
when function is called ms->numa_state->num_nodes is always > 0, isn't it?
> + guint i;
> +
> + if (!ms->device_memory) {
> + return;
> + }
> +
> + cursor = ms->device_memory->base;
> + end = cursor + memory_region_size(&ms->device_memory->mr);
> +
> + object_child_foreach_recursive(qdev_get_machine(),
> + collect_sp_mem_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 (cursor < r->addr) {
> + build_srat_memory(table_data, cursor, r->addr - cursor,
> + hotplug_pxm,
> + MEM_AFFINITY_HOTPLUGGABLE |
> + MEM_AFFINITY_ENABLED);
> + }
> + build_srat_memory(table_data, r->addr, r->size, r->node,
> + MEM_AFFINITY_ENABLED);
> + cursor = r->addr + r->size;
> + }
> +
> + if (cursor < end) {
> + build_srat_memory(table_data, cursor, end - cursor,
> + hotplug_pxm,
> + MEM_AFFINITY_HOTPLUGGABLE |
> + MEM_AFFINITY_ENABLED);
> + }
> +}
> +
> #define HOLE_640K_START (640 * KiB)
> #define HOLE_640K_END (1 * MiB)
>
> @@ -1481,12 +1572,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
> * Memory devices may override proximity set by this entry,
> * providing _PXM method if necessary.
> */
> - if (machine->device_memory) {
keep it here, and drop one in build_srat_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);
> }
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 3/4] hw/i386: hook sp-mem into the pc machine plug path
2026-06-05 10:46 ` [PATCH v10 3/4] hw/i386: hook sp-mem into the pc machine plug path fanhuang
@ 2026-06-09 11:52 ` Igor Mammedov
0 siblings, 0 replies; 14+ messages in thread
From: Igor Mammedov @ 2026-06-09 11:52 UTC (permalink / raw)
To: fanhuang; +Cc: qemu-devel, david, gourry, philmd, Zhigang.Luo, Lianjie.Shi
On Fri, 5 Jun 2026 18:46:08 +0800
fanhuang <FangSheng.Huang@amd.com> wrote:
> Add the pc machine hookup for TYPE_SP_MEM so each sp-mem instance is
> placed by the memory-device framework and reported to the guest as
> E820_SOFT_RESERVED.
>
> Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
> ---
> hw/i386/e820_memory_layout.h | 11 +++++-----
> hw/i386/pc.c | 42 ++++++++++++++++++++++++++++++++++++
> hw/i386/Kconfig | 2 ++
> 3 files changed, 50 insertions(+), 5 deletions(-)
>
> diff --git a/hw/i386/e820_memory_layout.h b/hw/i386/e820_memory_layout.h
> index b50acfa201..6ef169db9c 100644
> --- a/hw/i386/e820_memory_layout.h
> +++ b/hw/i386/e820_memory_layout.h
> @@ -10,11 +10,12 @@
> #define HW_I386_E820_MEMORY_LAYOUT_H
>
> /* e820 types */
> -#define E820_RAM 1
> -#define E820_RESERVED 2
> -#define E820_ACPI 3
> -#define E820_NVS 4
> -#define E820_UNUSABLE 5
> +#define E820_RAM 1
> +#define E820_RESERVED 2
> +#define E820_ACPI 3
> +#define E820_NVS 4
> +#define E820_UNUSABLE 5
> +#define E820_SOFT_RESERVED 0xefffffff
>
> struct e820_entry {
> uint64_t address;
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index 2ecad3c503..b538f49f23 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -63,6 +63,7 @@
> #include "hw/i386/kvm/xen_gnttab.h"
> #include "hw/i386/kvm/xen_xenstore.h"
> #include "hw/mem/memory-device.h"
> +#include "hw/mem/sp-mem.h"
> #include "e820_memory_layout.h"
> #include "trace.h"
> #include "sev.h"
> @@ -1283,11 +1284,49 @@ static void pc_hv_balloon_plug(HotplugHandler *hotplug_dev,
> memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
> }
>
> +static void pc_sp_mem_pre_plug(HotplugHandler *hotplug_dev,
> + DeviceState *dev, Error **errp)
> +{
> + MachineState *ms = MACHINE(hotplug_dev);
> + SpMemDevice *spm = SP_MEM(dev);
> +
> + if (host_memory_backend_is_mapped(spm->hostmem)) {
> + error_setg(errp, "memory backend '%s' is already in use",
> + object_get_canonical_path_component(OBJECT(spm->hostmem)));
> + return;
> + }
this belongs to sp_mem realize
> + if (ms->numa_state && spm->node >= ms->numa_state->num_nodes) {
> + error_setg(errp,
> + "'node' property value %" PRIu32
> + " exceeds the number of NUMA nodes (%d)",
> + spm->node, ms->numa_state->num_nodes);
> + return;
> + }
I think this the right place for this, despite what other mems do.
Perhaps it is worth to consolidate/cleanup 1st.
I'd put it in memory_device_pre_plug():
if has_node_prop:
.....
> + memory_device_pre_plug(MEMORY_DEVICE(dev), ms, errp);
> +}
> +
> +static void pc_sp_mem_plug(HotplugHandler *hotplug_dev,
> + DeviceState *dev, Error **errp)
> +{
> + SpMemDevice *spm = SP_MEM(dev);
> + MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(MEMORY_DEVICE(dev));
> + uint64_t addr, size;
> +
> + host_memory_backend_set_mapped(spm->hostmem, true);
dup? see above.
> + memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
> +
> + addr = mdc->get_addr(MEMORY_DEVICE(dev));
> + size = memory_region_size(host_memory_backend_get_memory(spm->hostmem));
> + e820_add_entry(addr, size, E820_SOFT_RESERVED);
> +}
> +
> static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
> DeviceState *dev, Error **errp)
> {
> if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
> pc_memory_pre_plug(hotplug_dev, dev, errp);
> + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SP_MEM)) {
> + pc_sp_mem_pre_plug(hotplug_dev, dev, errp);
> } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
> x86_cpu_pre_plug(hotplug_dev, dev, errp);
> } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
> @@ -1324,6 +1363,8 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
> {
> if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
> pc_memory_plug(hotplug_dev, dev, errp);
> + } else if (object_dynamic_cast(OBJECT(dev), TYPE_SP_MEM)) {
> + pc_sp_mem_plug(hotplug_dev, dev, errp);
> } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
> x86_cpu_plug(hotplug_dev, dev, errp);
> } else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
> @@ -1368,6 +1409,7 @@ static HotplugHandler *pc_get_hotplug_handler(MachineState *machine,
> DeviceState *dev)
> {
> if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
> + object_dynamic_cast(OBJECT(dev), TYPE_SP_MEM) ||
> object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
> object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI) ||
> object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
> diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
> index 12473acaa7..e27d8816e5 100644
> --- a/hw/i386/Kconfig
> +++ b/hw/i386/Kconfig
> @@ -84,6 +84,7 @@ config I440FX
> select PCI_I440FX
> select PIIX
> select DIMM
> + select SP_MEM
> select SMBIOS
> select SMBIOS_LEGACY
> select FW_CFG_DMA
> @@ -113,6 +114,7 @@ config Q35
> select LPC_ICH9
> select AHCI_ICH9
> select DIMM
> + select SP_MEM
> select SMBIOS
> select FW_CFG_DMA
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag
2026-06-05 10:46 ` [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag fanhuang
@ 2026-06-09 11:53 ` Igor Mammedov
2026-06-09 12:51 ` David Hildenbrand (Arm)
1 sibling, 0 replies; 14+ messages in thread
From: Igor Mammedov @ 2026-06-09 11:53 UTC (permalink / raw)
To: fanhuang; +Cc: qemu-devel, david, gourry, philmd, Zhigang.Luo, Lianjie.Shi
On Fri, 5 Jun 2026 18:46:09 +0800
fanhuang <FangSheng.Huang@amd.com> wrote:
> Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
> ---
> MAINTAINERS | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7752917d8c..db34f6cf17 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3361,13 +3361,16 @@ F: scripts/coccinelle/memory-region-housekeeping.cocci
> Memory devices
> M: David Hildenbrand <david@kernel.org>
> M: Igor Mammedov <imammedo@redhat.com>
> +R: FangSheng Huang <FangSheng.Huang@amd.com>
> S: Supported
> F: hw/mem/memory-device*.c
> F: hw/mem/nvdimm.c
> F: hw/mem/pc-dimm.c
> +F: hw/mem/sp-mem.c
> F: include/hw/mem/memory-device.h
> F: include/hw/mem/nvdimm.h
> F: include/hw/mem/pc-dimm.h
> +F: include/hw/mem/sp-mem.h
> F: docs/nvdimm.txt
>
> SPICE
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag
2026-06-05 10:46 ` [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag fanhuang
2026-06-09 11:53 ` Igor Mammedov
@ 2026-06-09 12:51 ` David Hildenbrand (Arm)
1 sibling, 0 replies; 14+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-09 12:51 UTC (permalink / raw)
To: fanhuang, qemu-devel, imammedo, gourry, philmd; +Cc: Zhigang.Luo, Lianjie.Shi
On 6/5/26 12:46, fanhuang wrote:
/insert text here
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
--
Cheers,
David
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-06-09 12:51 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-05 10:46 [PATCH v10 0/4] hw/mem: add sp-mem device for Specific Purpose Memory fanhuang
2026-06-05 10:46 ` [PATCH v10 1/4] " fanhuang
2026-06-05 15:10 ` David Hildenbrand (Arm)
2026-06-05 21:22 ` Gregory Price
2026-06-09 9:03 ` Igor Mammedov
2026-06-05 10:46 ` [PATCH v10 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem fanhuang
2026-06-05 21:27 ` Gregory Price
2026-06-09 3:53 ` Huang, FangSheng (Jerry)
2026-06-09 11:14 ` Igor Mammedov
2026-06-05 10:46 ` [PATCH v10 3/4] hw/i386: hook sp-mem into the pc machine plug path fanhuang
2026-06-09 11:52 ` Igor Mammedov
2026-06-05 10:46 ` [PATCH v10 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag fanhuang
2026-06-09 11:53 ` Igor Mammedov
2026-06-09 12:51 ` David Hildenbrand (Arm)
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.