master
c 128 lines 3.74 KB
Raw
1 /*
2 * Specific Purpose Memory (SPM) device
3 *
4 * Copyright (c) 2026 Advanced Micro Devices, Inc.
5 *
6 * Authors:
7 * FangSheng Huang <FangSheng.Huang@amd.com>
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "qemu/osdep.h"
13 #include "qemu/module.h"
14 #include "qapi/error.h"
15 #include "hw/core/qdev-properties.h"
16 #include "hw/core/qdev.h"
17 #include "hw/mem/sp-mem.h"
18 #include "hw/mem/memory-device.h"
19 #include "system/hostmem.h"
20
21 #define SP_MEM_MEMDEV_PROP "memdev"
22 #define SP_MEM_NODE_PROP "node"
23 #define SP_MEM_ADDR_PROP "addr"
24
25 static const Property sp_mem_properties[] = {
26 DEFINE_PROP_LINK(SP_MEM_MEMDEV_PROP, SpMemDevice, hostmem,
27 TYPE_MEMORY_BACKEND, HostMemoryBackend *),
28 DEFINE_PROP_UINT32(SP_MEM_NODE_PROP, SpMemDevice, node, 0),
29 DEFINE_PROP_UINT64(SP_MEM_ADDR_PROP, SpMemDevice, addr, 0),
30 };
31
32 static uint64_t sp_mem_get_addr(const MemoryDeviceState *md)
33 {
34 return object_property_get_uint(OBJECT(md), SP_MEM_ADDR_PROP,
35 &error_abort);
36 }
37
38 static void sp_mem_set_addr(MemoryDeviceState *md, uint64_t addr,
39 Error **errp)
40 {
41 object_property_set_uint(OBJECT(md), SP_MEM_ADDR_PROP, addr, errp);
42 }
43
44 static MemoryRegion *sp_mem_get_memory_region(MemoryDeviceState *md,
45 Error **errp)
46 {
47 SpMemDevice *spm = SP_MEM(md);
48
49 if (!spm->hostmem) {
50 error_setg(errp, "'%s' property must be set", SP_MEM_MEMDEV_PROP);
51 return NULL;
52 }
53 return host_memory_backend_get_memory(spm->hostmem);
54 }
55
56 static void sp_mem_fill_device_info(const MemoryDeviceState *md,
57 MemoryDeviceInfo *info)
58 {
59 SpMemDeviceInfo *di = g_new0(SpMemDeviceInfo, 1);
60 SpMemDevice *spm = SP_MEM(md);
61 DeviceState *dev = DEVICE(md);
62
63 di->id = dev->id ? g_strdup(dev->id) : NULL;
64 di->addr = spm->addr;
65 di->size = memory_region_size(
66 host_memory_backend_get_memory(spm->hostmem));
67 di->node = spm->node;
68 di->memdev = object_get_canonical_path(OBJECT(spm->hostmem));
69
70 info->u.sp_mem.data = di;
71 info->type = MEMORY_DEVICE_INFO_KIND_SP_MEM;
72 }
73
74 static void sp_mem_realize(DeviceState *dev, Error **errp)
75 {
76 SpMemDevice *spm = SP_MEM(dev);
77
78 if (!spm->hostmem) {
79 error_setg(errp, "'%s' property is required", SP_MEM_MEMDEV_PROP);
80 return;
81 }
82 if (host_memory_backend_is_mapped(spm->hostmem)) {
83 error_setg(errp, "memory backend '%s' is already in use",
84 object_get_canonical_path_component(OBJECT(spm->hostmem)));
85 return;
86 }
87 host_memory_backend_set_mapped(spm->hostmem, true);
88 }
89
90 static void sp_mem_unrealize(DeviceState *dev)
91 {
92 SpMemDevice *spm = SP_MEM(dev);
93
94 host_memory_backend_set_mapped(spm->hostmem, false);
95 }
96
97 static void sp_mem_class_init(ObjectClass *oc, const void *data)
98 {
99 DeviceClass *dc = DEVICE_CLASS(oc);
100 MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
101
102 dc->desc = "SPM (Specific Purpose Memory) device";
103 dc->hotpluggable = false;
104 dc->realize = sp_mem_realize;
105 dc->unrealize = sp_mem_unrealize;
106 device_class_set_props(dc, sp_mem_properties);
107
108 mdc->get_addr = sp_mem_get_addr;
109 mdc->set_addr = sp_mem_set_addr;
110 mdc->get_memory_region = sp_mem_get_memory_region;
111 mdc->get_plugged_size = memory_device_get_region_size;
112 mdc->fill_device_info = sp_mem_fill_device_info;
113 }
114
115 static const TypeInfo sp_mem_types[] = {
116 {
117 .name = TYPE_SP_MEM,
118 .parent = TYPE_DEVICE,
119 .class_init = sp_mem_class_init,
120 .instance_size = sizeof(SpMemDevice),
121 .interfaces = (InterfaceInfo[]) {
122 { TYPE_MEMORY_DEVICE },
123 { }
124 },
125 },
126 };
127
128 DEFINE_TYPES(sp_mem_types)