Introduce a TYPE_MEMORY_DEVICE subclass `spm-memory` 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.  Per-device NUMA placement matches the natural shape of
multiple HBM blocks (one block == one driver claim == one PXM).

Usage:

    -object memory-backend-ram,id=spm0,size=8G
    -numa node,nodeid=N
    -device spm-memory,id=dev0,memdev=spm0,node=N[,addr=GPA]

The device:

- inherits TYPE_DEVICE and implements TYPE_MEMORY_DEVICE; placement
  in machine->device_memory goes through the standard memory-device
  framework (memory_device_pre_plug + memory_device_plug)
- is boot-time only: dc->hotpluggable = false, and realize rejects
  attempts past PHASE_MACHINE_READY
- emits one E820 SOFT_RESERVED entry per instance at machine_done
- emits one SRAT memory_affinity entry per instance at acpi-build,
  ENABLED-only (no HOTPLUGGABLE flag)
- rejects mixed-memory configurations on the target NUMA node at
  realize-time
- is reported by QMP query-memory-devices as a dedicated kind,
  MEMORY_DEVICE_INFO_KIND_SPM_MEMORY

The device_memory SRAT umbrella entry in hw/i386/acpi-build.c is
restructured to partition the region into per-kind chunks rather
than emitting a single HOTPLUGGABLE entry covering everything.
For each plugged TYPE_SPM_MEMORY device the partition emits an
ENABLED entry at the device's proximity_domain; the remaining
sub-ranges (gaps between SPM devices, leading and trailing
padding, and ranges occupied by non-SPM memory devices) are
emitted as HOTPLUGGABLE | ENABLED entries at the placeholder
PXM (nb_numa_nodes - 1), preserving the upstream convention.

E820_SOFT_RESERVED is added to hw/i386/e820_memory_layout.h
alongside the other type codes.

CONFIG_SPM_MEMORY is selected by the i386 PC and Q35 machines
(same as DIMM).

MAINTAINERS gets new file entries under the existing "Memory devices"
stanza.

Signed-off-by: FangSheng Huang <[email protected]>
---
 MAINTAINERS                  |   2 +
 hw/i386/Kconfig              |   2 +
 hw/i386/acpi-build.c         | 105 ++++++++++++--
 hw/i386/e820_memory_layout.h |  11 +-
 hw/mem/Kconfig               |   4 +
 hw/mem/meson.build           |   1 +
 hw/mem/spm-memory.c          | 269 +++++++++++++++++++++++++++++++++++
 include/hw/mem/spm-memory.h  |  43 ++++++
 qapi/machine.json            |  43 +++++-
 9 files changed, 459 insertions(+), 21 deletions(-)
 create mode 100644 hw/mem/spm-memory.c
 create mode 100644 include/hw/mem/spm-memory.h

diff --git a/MAINTAINERS b/MAINTAINERS
index cd5c4831e2..2a06515fc8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3361,9 +3361,11 @@ S: Supported
 F: hw/mem/memory-device*.c
 F: hw/mem/nvdimm.c
 F: hw/mem/pc-dimm.c
+F: hw/mem/spm-memory.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/spm-memory.h
 F: docs/nvdimm.txt
 
 SPICE
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index 12473acaa7..e31a25b634 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -84,6 +84,7 @@ config I440FX
     select PCI_I440FX
     select PIIX
     select DIMM
+    select SPM_MEMORY
     select SMBIOS
     select SMBIOS_LEGACY
     select FW_CFG_DMA
@@ -113,6 +114,7 @@ config Q35
     select LPC_ICH9
     select AHCI_ICH9
     select DIMM
+    select SPM_MEMORY
     select SMBIOS
     select FW_CFG_DMA
 
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 0d7c83d5e9..865ab5fa4f 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/spm-memory.h"
 #include "system/numa.h"
 #include "system/reset.h"
 #include "hw/hyperv/vmbus-bridge.h"
@@ -1346,6 +1347,95 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, 
GArray *tcpalog,
 }
 #endif
 
+typedef struct {
+    uint64_t addr;
+    uint64_t size;
+    uint32_t node;
+} SpmRange;
+
+static int collect_spm_ranges_cb(Object *obj, void *opaque)
+{
+    GArray *ranges = opaque;
+    SpmMemoryDevice *spm;
+    MemoryDeviceClass *mdc;
+    SpmRange r;
+
+    if (!object_dynamic_cast(obj, TYPE_SPM_MEMORY)) {
+        return 0;
+    }
+    spm = SPM_MEMORY(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 spm_range_compare(gconstpointer a, gconstpointer b)
+{
+    const SpmRange *range_a = a;
+    const SpmRange *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:
+ *   - ENABLED entry at the device's proximity_domain for each plugged
+ *     TYPE_SPM_MEMORY instance.
+ *   - HOTPLUGGABLE | ENABLED entry with PXM = nb_numa_nodes - 1 for
+ *     every remaining sub-range (gaps, leading/trailing padding, and
+ *     ranges occupied by non-SPM memory devices).
+ */
+static void build_srat_device_memory(GArray *table_data, MachineState *ms)
+{
+    g_autoptr(GArray) ranges = g_array_new(FALSE, TRUE, sizeof(SpmRange));
+    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_spm_ranges_cb, ranges);
+    g_array_sort(ranges, spm_range_compare);
+
+    for (i = 0; i < ranges->len; i++) {
+        SpmRange *r = &g_array_index(ranges, SpmRange, 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)
 
@@ -1473,20 +1563,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 
     build_srat_generic_affinity_structures(table_data);
 
-    /*
-     * Entry is required for Windows to enable memory hotplug in OS
-     * and for Linux to enable SWIOTLB when booted with less than
-     * 4G of RAM. Windows works better if the entry sets proximity
-     * to the highest NUMA node in the 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);
 }
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/mem/Kconfig b/hw/mem/Kconfig
index 73c5ae8ad9..4145870881 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 SPM_MEMORY
+    bool
+    select MEM_DEVICE
diff --git a/hw/mem/meson.build b/hw/mem/meson.build
index 8c2beeb7d4..2c28104282 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_SPM_MEMORY', if_true: files('spm-memory.c'))
 stub_ss.add(files('cxl_type3_stubs.c'))
 
 stub_ss.add(files('memory-device-stubs.c'))
diff --git a/hw/mem/spm-memory.c b/hw/mem/spm-memory.c
new file mode 100644
index 0000000000..85887b2479
--- /dev/null
+++ b/hw/mem/spm-memory.c
@@ -0,0 +1,269 @@
+/*
+ * Specific Purpose Memory (SPM) device
+ *
+ * Copyright (c) 2026 Advanced Micro Devices, Inc.
+ *
+ * Authors:
+ *  FangSheng Huang <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qapi/error.h"
+#include "hw/core/boards.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/core/qdev.h"
+#include "hw/mem/spm-memory.h"
+#include "hw/mem/memory-device.h"
+#include "hw/i386/e820_memory_layout.h"
+#include "migration/vmstate.h"
+#include "system/hostmem.h"
+#include "system/numa.h"
+#include "system/system.h"
+
+static QLIST_HEAD(, SpmMemoryDevice) spm_memory_list =
+    QLIST_HEAD_INITIALIZER(spm_memory_list);
+static Notifier spm_machine_done_notifier;
+static bool spm_machine_done_registered;
+
+#define SPM_MEMORY_MEMDEV_PROP    "memdev"
+#define SPM_MEMORY_NODE_PROP      "node"
+#define SPM_MEMORY_ADDR_PROP      "addr"
+
+static const Property spm_memory_properties[] = {
+    DEFINE_PROP_LINK(SPM_MEMORY_MEMDEV_PROP, SpmMemoryDevice, hostmem,
+                     TYPE_MEMORY_BACKEND, HostMemoryBackend *),
+    DEFINE_PROP_UINT32(SPM_MEMORY_NODE_PROP, SpmMemoryDevice, node, 0),
+    DEFINE_PROP_UINT64(SPM_MEMORY_ADDR_PROP, SpmMemoryDevice, addr, 0),
+};
+
+static uint64_t spm_memory_md_get_addr(const MemoryDeviceState *md)
+{
+    return SPM_MEMORY(md)->addr;
+}
+
+static void spm_memory_md_set_addr(MemoryDeviceState *md, uint64_t addr,
+                                   Error **errp)
+{
+    SPM_MEMORY(md)->addr = addr;
+}
+
+static MemoryRegion *spm_memory_md_get_memory_region(MemoryDeviceState *md,
+                                                    Error **errp)
+{
+    SpmMemoryDevice *spm = SPM_MEMORY(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 spm_memory_md_get_plugged_size(const MemoryDeviceState *md,
+                                               Error **errp)
+{
+    SpmMemoryDevice *spm = SPM_MEMORY(md);
+    return spm->hostmem ?
+        memory_region_size(host_memory_backend_get_memory(spm->hostmem)) : 0;
+}
+
+static void spm_memory_md_fill_device_info(const MemoryDeviceState *md,
+                                           MemoryDeviceInfo *info)
+{
+    SpmMemoryDeviceInfo *di = g_new0(SpmMemoryDeviceInfo, 1);
+    SpmMemoryDevice *spm = SPM_MEMORY(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.spm_memory.data = di;
+    info->type = MEMORY_DEVICE_INFO_KIND_SPM_MEMORY;
+}
+
+typedef struct {
+    uint32_t node_id;
+    const SpmMemoryDevice *self;  /* exclude self when walking */
+    bool conflict;
+} SpmNodeCheckCtx;
+
+static int spm_check_node_collision_cb(Object *obj, void *opaque)
+{
+    SpmNodeCheckCtx *ctx = opaque;
+    uint32_t other_node;
+
+    if (!object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) {
+        return 0;
+    }
+    /*
+     * Skip self.  Compare canonical Object* pointers, not interface-cast
+     * MemoryDeviceState* (different address under INTERFACE_CHECK).
+     */
+    if (obj == OBJECT(ctx->self)) {
+        return 0;
+    }
+
+    /*
+     * Not all memory-device subclasses have a "node" property; skip
+     * those silently rather than asserting.
+     */
+    if (!object_property_find(obj, "node")) {
+        return 0;
+    }
+    other_node = (uint32_t)object_property_get_uint(obj, "node", NULL);
+    if (other_node == ctx->node_id) {
+        ctx->conflict = true;
+        return 1; /* stop walk */
+    }
+    return 0;
+}
+
+/*
+ * Require the target NUMA node to be SPM-only: driver-side discovery
+ * uses proximity_domain as the key, so a node mixing SPM with other
+ * memory yields ambiguous discovery.
+ */
+static void spm_memory_check_node_exclusive(SpmMemoryDevice *spm,
+                                            MachineState *ms, Error **errp)
+{
+    ERRP_GUARD();
+    SpmNodeCheckCtx ctx = { spm->node, spm, false };
+
+    /* Bounds check: spm->node must be a valid NUMA node id */
+    if (!ms->numa_state || spm->node >= ms->numa_state->num_nodes) {
+        error_setg(errp,
+                   "spm-memory: node %u out of range "
+                   "(numa_state has %d nodes)", spm->node,
+                   ms->numa_state ? ms->numa_state->num_nodes : 0);
+        return;
+    }
+
+    /* Check 1: target node must not have memory from -numa node,memdev= */
+    if (ms->numa_state->nodes[spm->node].node_mem > 0) {
+        error_setg(errp,
+                   "spm-memory: NUMA node %u already has memory attached "
+                   "via -numa node,memdev=; SPM nodes must be SPM-only",
+                   spm->node);
+        return;
+    }
+
+    /* Check 2: target node must not already have another memory device */
+    object_child_foreach_recursive(qdev_get_machine(),
+                                   spm_check_node_collision_cb, &ctx);
+    if (ctx.conflict) {
+        error_setg(errp,
+                   "spm-memory: NUMA node %u already has another memory "
+                   "device plugged; SPM nodes must be SPM-only", spm->node);
+        return;
+    }
+}
+
+static void spm_memory_machine_done(Notifier *n, void *opaque)
+{
+    SpmMemoryDevice *spm;
+    MemoryDeviceClass *mdc;
+    uint64_t addr, size;
+
+    QLIST_FOREACH(spm, &spm_memory_list, next) {
+        g_assert(spm->hostmem);
+        mdc = MEMORY_DEVICE_GET_CLASS(MEMORY_DEVICE(spm));
+        addr = mdc->get_addr(MEMORY_DEVICE(spm));
+        size = memory_region_size(
+                   host_memory_backend_get_memory(spm->hostmem));
+        e820_add_entry(addr, size, E820_SOFT_RESERVED);
+    }
+}
+
+static void spm_memory_realize(DeviceState *dev, Error **errp)
+{
+    ERRP_GUARD();
+    SpmMemoryDevice *spm = SPM_MEMORY(dev);
+    MachineState *ms = MACHINE(qdev_get_machine());
+
+    if (phase_check(PHASE_MACHINE_READY)) {
+        error_setg(errp, "spm-memory: hotplug is not supported "
+                         "(boot-time-only device)");
+        return;
+    }
+
+    if (!spm->hostmem) {
+        error_setg(errp, "'%s' property is required", SPM_MEMORY_MEMDEV_PROP);
+        return;
+    }
+    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;
+    }
+
+    spm_memory_check_node_exclusive(spm, ms, errp);
+    if (*errp) {
+        return;
+    }
+
+    memory_device_pre_plug(MEMORY_DEVICE(spm), ms, errp);
+    if (*errp) {
+        return;
+    }
+
+    host_memory_backend_set_mapped(spm->hostmem, true);
+    memory_device_plug(MEMORY_DEVICE(spm), ms);
+
+    QLIST_INSERT_HEAD(&spm_memory_list, spm, next);
+
+    if (!spm_machine_done_registered) {
+        spm_machine_done_notifier.notify = spm_memory_machine_done;
+        qemu_add_machine_init_done_notifier(&spm_machine_done_notifier);
+        spm_machine_done_registered = true;
+    }
+}
+
+static const VMStateDescription vmstate_spm_memory = {
+    .name = TYPE_SPM_MEMORY,
+    .unmigratable = 1,
+};
+
+static void spm_memory_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 = spm_memory_realize;
+    dc->vmsd = &vmstate_spm_memory;
+    device_class_set_props(dc, spm_memory_properties);
+
+    mdc->get_addr            = spm_memory_md_get_addr;
+    mdc->set_addr            = spm_memory_md_set_addr;
+    mdc->get_memory_region   = spm_memory_md_get_memory_region;
+    mdc->get_plugged_size    = spm_memory_md_get_plugged_size;
+    mdc->fill_device_info    = spm_memory_md_fill_device_info;
+}
+
+static const TypeInfo spm_memory_info = {
+    .name          = TYPE_SPM_MEMORY,
+    .parent        = TYPE_DEVICE,
+    .class_size    = sizeof(SpmMemoryDeviceClass),
+    .class_init    = spm_memory_class_init,
+    .instance_size = sizeof(SpmMemoryDevice),
+    .interfaces    = (InterfaceInfo[]) {
+        { TYPE_MEMORY_DEVICE },
+        { }
+    },
+};
+
+static void spm_memory_register_types(void)
+{
+    type_register_static(&spm_memory_info);
+}
+
+type_init(spm_memory_register_types)
diff --git a/include/hw/mem/spm-memory.h b/include/hw/mem/spm-memory.h
new file mode 100644
index 0000000000..c662864b29
--- /dev/null
+++ b/include/hw/mem/spm-memory.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_SPM_MEMORY_H
+#define QEMU_SPM_MEMORY_H
+
+#include "hw/mem/memory-device.h"
+#include "hw/core/qdev.h"
+#include "qom/object.h"
+#include "system/hostmem.h"
+
+#define TYPE_SPM_MEMORY "spm-memory"
+
+OBJECT_DECLARE_TYPE(SpmMemoryDevice, SpmMemoryDeviceClass, SPM_MEMORY)
+
+struct SpmMemoryDevice {
+    /*< private >*/
+    DeviceState parent_obj;
+    QLIST_ENTRY(SpmMemoryDevice) next;
+
+    /*< public >*/
+    HostMemoryBackend *hostmem;    /* memdev= backend */
+    uint32_t node;                 /* NUMA proximity domain (node=) */
+    uint64_t addr;                 /* GPA (from addr= or framework-assigned) */
+};
+
+struct SpmMemoryDeviceClass {
+    /*< private >*/
+    DeviceClass parent_class;
+};
+
+#endif /* QEMU_SPM_MEMORY_H */
diff --git a/qapi/machine.json b/qapi/machine.json
index 685e4e29b8..51b06d7cba 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1413,6 +1413,32 @@
           }
 }
 
+##
+# @SpmMemoryDeviceInfo:
+#
+# spm-memory 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': 'SpmMemoryDeviceInfo',
+  'data': { '*id': 'str',
+            'memaddr': 'size',
+            'size': 'size',
+            'node': 'int',
+            'memdev': 'str'
+          }
+}
+
 ##
 # @MemoryDeviceInfoKind:
 #
@@ -1426,11 +1452,13 @@
 #
 # @hv-balloon: since 8.2.
 #
+# @spm-memory: since 11.1.
+#
 # Since: 2.1
 ##
 { 'enum': 'MemoryDeviceInfoKind',
   'data': [ 'dimm', 'nvdimm', 'virtio-pmem', 'virtio-mem', 'sgx-epc',
-            'hv-balloon' ] }
+            'hv-balloon', 'spm-memory' ] }
 
 ##
 # @PCDIMMDeviceInfoWrapper:
@@ -1482,6 +1510,16 @@
 { 'struct': 'HvBalloonDeviceInfoWrapper',
   'data': { 'data': 'HvBalloonDeviceInfo' } }
 
+##
+# @SpmMemoryDeviceInfoWrapper:
+#
+# @data: spm-memory device state information
+#
+# Since: 11.1
+##
+{ 'struct': 'SpmMemoryDeviceInfoWrapper',
+  'data': { 'data': 'SpmMemoryDeviceInfo' } }
+
 ##
 # @MemoryDeviceInfo:
 #
@@ -1499,7 +1537,8 @@
             'virtio-pmem': 'VirtioPMEMDeviceInfoWrapper',
             'virtio-mem': 'VirtioMEMDeviceInfoWrapper',
             'sgx-epc': 'SgxEPCDeviceInfoWrapper',
-            'hv-balloon': 'HvBalloonDeviceInfoWrapper'
+            'hv-balloon': 'HvBalloonDeviceInfoWrapper',
+            'spm-memory': 'SpmMemoryDeviceInfoWrapper'
           }
 }
 
-- 
2.34.1


Reply via email to