2 * Non-Volatile Dual In-line Memory Module Virtualization Implementation
4 * Copyright(C) 2015 Intel Corporation.
7 * Xiao Guangrong <guangrong.xiao@linux.intel.com>
9 * Currently, it only supports PMEM Virtualization.
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, see <http://www.gnu.org/licenses/>
25 #include "qemu/osdep.h"
26 #include "qapi/error.h"
27 #include "qapi/visitor.h"
28 #include "qapi-visit.h"
29 #include "hw/mem/nvdimm.h"
31 static void nvdimm_get_label_size(Object
*obj
, Visitor
*v
, const char *name
,
32 void *opaque
, Error
**errp
)
34 NVDIMMDevice
*nvdimm
= NVDIMM(obj
);
35 uint64_t value
= nvdimm
->label_size
;
37 visit_type_size(v
, name
, &value
, errp
);
40 static void nvdimm_set_label_size(Object
*obj
, Visitor
*v
, const char *name
,
41 void *opaque
, Error
**errp
)
43 NVDIMMDevice
*nvdimm
= NVDIMM(obj
);
44 Error
*local_err
= NULL
;
47 if (memory_region_size(&nvdimm
->nvdimm_mr
)) {
48 error_setg(&local_err
, "cannot change property value");
52 visit_type_size(v
, name
, &value
, &local_err
);
56 if (value
< MIN_NAMESPACE_LABEL_SIZE
) {
57 error_setg(&local_err
, "Property '%s.%s' (0x%" PRIx64
") is required"
58 " at least 0x%lx", object_get_typename(obj
),
59 name
, value
, MIN_NAMESPACE_LABEL_SIZE
);
63 nvdimm
->label_size
= value
;
65 error_propagate(errp
, local_err
);
68 static bool nvdimm_get_unarmed(Object
*obj
, Error
**errp
)
70 NVDIMMDevice
*nvdimm
= NVDIMM(obj
);
72 return nvdimm
->unarmed
;
75 static void nvdimm_set_unarmed(Object
*obj
, bool value
, Error
**errp
)
77 NVDIMMDevice
*nvdimm
= NVDIMM(obj
);
78 Error
*local_err
= NULL
;
80 if (memory_region_size(&nvdimm
->nvdimm_mr
)) {
81 error_setg(&local_err
, "cannot change property value");
85 nvdimm
->unarmed
= value
;
88 error_propagate(errp
, local_err
);
91 static void nvdimm_init(Object
*obj
)
93 object_property_add(obj
, NVDIMM_LABLE_SIZE_PROP
, "int",
94 nvdimm_get_label_size
, nvdimm_set_label_size
, NULL
,
96 object_property_add_bool(obj
, NVDIMM_UNARMED_PROP
,
97 nvdimm_get_unarmed
, nvdimm_set_unarmed
, NULL
);
100 static MemoryRegion
*nvdimm_get_memory_region(PCDIMMDevice
*dimm
, Error
**errp
)
102 NVDIMMDevice
*nvdimm
= NVDIMM(dimm
);
104 return &nvdimm
->nvdimm_mr
;
107 static void nvdimm_realize(PCDIMMDevice
*dimm
, Error
**errp
)
109 MemoryRegion
*mr
= host_memory_backend_get_memory(dimm
->hostmem
, errp
);
110 NVDIMMDevice
*nvdimm
= NVDIMM(dimm
);
111 uint64_t align
, pmem_size
, size
= memory_region_size(mr
);
113 align
= memory_region_get_alignment(mr
);
115 pmem_size
= size
- nvdimm
->label_size
;
116 nvdimm
->label_data
= memory_region_get_ram_ptr(mr
) + pmem_size
;
117 pmem_size
= QEMU_ALIGN_DOWN(pmem_size
, align
);
119 if (size
<= nvdimm
->label_size
|| !pmem_size
) {
120 HostMemoryBackend
*hostmem
= dimm
->hostmem
;
121 char *path
= object_get_canonical_path_component(OBJECT(hostmem
));
123 error_setg(errp
, "the size of memdev %s (0x%" PRIx64
") is too "
124 "small to contain nvdimm label (0x%" PRIx64
") and "
125 "aligned PMEM (0x%" PRIx64
")",
126 path
, memory_region_size(mr
), nvdimm
->label_size
, align
);
131 memory_region_init_alias(&nvdimm
->nvdimm_mr
, OBJECT(dimm
),
132 "nvdimm-memory", mr
, 0, pmem_size
);
133 nvdimm
->nvdimm_mr
.align
= align
;
137 * the caller should check the input parameters before calling
138 * label read/write functions.
140 static void nvdimm_validate_rw_label_data(NVDIMMDevice
*nvdimm
, uint64_t size
,
143 assert((nvdimm
->label_size
>= size
+ offset
) && (offset
+ size
> offset
));
146 static void nvdimm_read_label_data(NVDIMMDevice
*nvdimm
, void *buf
,
147 uint64_t size
, uint64_t offset
)
149 nvdimm_validate_rw_label_data(nvdimm
, size
, offset
);
151 memcpy(buf
, nvdimm
->label_data
+ offset
, size
);
154 static void nvdimm_write_label_data(NVDIMMDevice
*nvdimm
, const void *buf
,
155 uint64_t size
, uint64_t offset
)
158 PCDIMMDevice
*dimm
= PC_DIMM(nvdimm
);
159 uint64_t backend_offset
;
161 nvdimm_validate_rw_label_data(nvdimm
, size
, offset
);
163 memcpy(nvdimm
->label_data
+ offset
, buf
, size
);
165 mr
= host_memory_backend_get_memory(dimm
->hostmem
, &error_abort
);
166 backend_offset
= memory_region_size(mr
) - nvdimm
->label_size
+ offset
;
167 memory_region_set_dirty(mr
, backend_offset
, size
);
170 static MemoryRegion
*nvdimm_get_vmstate_memory_region(PCDIMMDevice
*dimm
)
172 return host_memory_backend_get_memory(dimm
->hostmem
, &error_abort
);
175 static void nvdimm_class_init(ObjectClass
*oc
, void *data
)
177 PCDIMMDeviceClass
*ddc
= PC_DIMM_CLASS(oc
);
178 NVDIMMClass
*nvc
= NVDIMM_CLASS(oc
);
180 ddc
->realize
= nvdimm_realize
;
181 ddc
->get_memory_region
= nvdimm_get_memory_region
;
182 ddc
->get_vmstate_memory_region
= nvdimm_get_vmstate_memory_region
;
184 nvc
->read_label_data
= nvdimm_read_label_data
;
185 nvc
->write_label_data
= nvdimm_write_label_data
;
188 static TypeInfo nvdimm_info
= {
190 .parent
= TYPE_PC_DIMM
,
191 .class_size
= sizeof(NVDIMMClass
),
192 .class_init
= nvdimm_class_init
,
193 .instance_size
= sizeof(NVDIMMDevice
),
194 .instance_init
= nvdimm_init
,
197 static void nvdimm_register_types(void)
199 type_register_static(&nvdimm_info
);
202 type_init(nvdimm_register_types
)