1ee3a71e3SShivaprasad G Bhat /*
2ee3a71e3SShivaprasad G Bhat * QEMU PAPR Storage Class Memory Interfaces
3ee3a71e3SShivaprasad G Bhat *
4ee3a71e3SShivaprasad G Bhat * Copyright (c) 2019-2020, IBM Corporation.
5ee3a71e3SShivaprasad G Bhat *
6ee3a71e3SShivaprasad G Bhat * Permission is hereby granted, free of charge, to any person obtaining a copy
7ee3a71e3SShivaprasad G Bhat * of this software and associated documentation files (the "Software"), to deal
8ee3a71e3SShivaprasad G Bhat * in the Software without restriction, including without limitation the rights
9ee3a71e3SShivaprasad G Bhat * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10ee3a71e3SShivaprasad G Bhat * copies of the Software, and to permit persons to whom the Software is
11ee3a71e3SShivaprasad G Bhat * furnished to do so, subject to the following conditions:
12ee3a71e3SShivaprasad G Bhat *
13ee3a71e3SShivaprasad G Bhat * The above copyright notice and this permission notice shall be included in
14ee3a71e3SShivaprasad G Bhat * all copies or substantial portions of the Software.
15ee3a71e3SShivaprasad G Bhat *
16ee3a71e3SShivaprasad G Bhat * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17ee3a71e3SShivaprasad G Bhat * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18ee3a71e3SShivaprasad G Bhat * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19ee3a71e3SShivaprasad G Bhat * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20ee3a71e3SShivaprasad G Bhat * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21ee3a71e3SShivaprasad G Bhat * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22ee3a71e3SShivaprasad G Bhat * THE SOFTWARE.
23ee3a71e3SShivaprasad G Bhat */
24ee3a71e3SShivaprasad G Bhat #include "qemu/osdep.h"
25b5513584SShivaprasad G Bhat #include "qemu/cutils.h"
26ee3a71e3SShivaprasad G Bhat #include "qapi/error.h"
27ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_drc.h"
28ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h"
29ee3a71e3SShivaprasad G Bhat #include "hw/mem/nvdimm.h"
30ee3a71e3SShivaprasad G Bhat #include "qemu/nvdimm-utils.h"
31ee3a71e3SShivaprasad G Bhat #include "hw/ppc/fdt.h"
32b5fca656SShivaprasad G Bhat #include "qemu/range.h"
33f1aa45ffSDaniel Henrique Barboza #include "hw/ppc/spapr_numa.h"
34b5513584SShivaprasad G Bhat #include "block/thread-pool.h"
35b5513584SShivaprasad G Bhat #include "migration/vmstate.h"
36b5513584SShivaprasad G Bhat #include "qemu/pmem.h"
378601b4f1SShivaprasad G Bhat #include "hw/qdev-properties.h"
38ee3a71e3SShivaprasad G Bhat
3953d7d7e2SVaibhav Jain /* DIMM health bitmap bitmap indicators. Taken from kernel's papr_scm.c */
4053d7d7e2SVaibhav Jain /* SCM device is unable to persist memory contents */
4153d7d7e2SVaibhav Jain #define PAPR_PMEM_UNARMED PPC_BIT(0)
4253d7d7e2SVaibhav Jain
43f93c8f14SShivaprasad G Bhat /*
44f93c8f14SShivaprasad G Bhat * The nvdimm size should be aligned to SCM block size.
45f93c8f14SShivaprasad G Bhat * The SCM block size should be aligned to SPAPR_MEMORY_BLOCK_SIZE
46f93c8f14SShivaprasad G Bhat * in order to have SCM regions not to overlap with dimm memory regions.
47f93c8f14SShivaprasad G Bhat * The SCM devices can have variable block sizes. For now, fixing the
48f93c8f14SShivaprasad G Bhat * block size to the minimum value.
49f93c8f14SShivaprasad G Bhat */
50f93c8f14SShivaprasad G Bhat #define SPAPR_MINIMUM_SCM_BLOCK_SIZE SPAPR_MEMORY_BLOCK_SIZE
51f93c8f14SShivaprasad G Bhat
52f93c8f14SShivaprasad G Bhat /* Have an explicit check for alignment */
53f93c8f14SShivaprasad G Bhat QEMU_BUILD_BUG_ON(SPAPR_MINIMUM_SCM_BLOCK_SIZE % SPAPR_MEMORY_BLOCK_SIZE);
54f93c8f14SShivaprasad G Bhat
55b5513584SShivaprasad G Bhat #define TYPE_SPAPR_NVDIMM "spapr-nvdimm"
56b5513584SShivaprasad G Bhat OBJECT_DECLARE_TYPE(SpaprNVDIMMDevice, SPAPRNVDIMMClass, SPAPR_NVDIMM)
57b5513584SShivaprasad G Bhat
58b5513584SShivaprasad G Bhat struct SPAPRNVDIMMClass {
59b5513584SShivaprasad G Bhat /* private */
60b5513584SShivaprasad G Bhat NVDIMMClass parent_class;
618601b4f1SShivaprasad G Bhat
628601b4f1SShivaprasad G Bhat /* public */
638601b4f1SShivaprasad G Bhat void (*realize)(NVDIMMDevice *dimm, Error **errp);
648601b4f1SShivaprasad G Bhat void (*unrealize)(NVDIMMDevice *dimm, Error **errp);
65b5513584SShivaprasad G Bhat };
66b5513584SShivaprasad G Bhat
spapr_nvdimm_validate(HotplugHandler * hotplug_dev,NVDIMMDevice * nvdimm,uint64_t size,Error ** errp)67451c6905SGreg Kurz bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm,
68beb6073fSDaniel Henrique Barboza uint64_t size, Error **errp)
69ee3a71e3SShivaprasad G Bhat {
70beb6073fSDaniel Henrique Barboza const MachineClass *mc = MACHINE_GET_CLASS(hotplug_dev);
7128f5a716SDaniel Henrique Barboza const MachineState *ms = MACHINE(hotplug_dev);
728601b4f1SShivaprasad G Bhat PCDIMMDevice *dimm = PC_DIMM(nvdimm);
738601b4f1SShivaprasad G Bhat MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem);
7490d282d0SDaniel Henrique Barboza g_autofree char *uuidstr = NULL;
75ee3a71e3SShivaprasad G Bhat QemuUUID uuid;
76af7084e7SShivaprasad G Bhat int ret;
77ee3a71e3SShivaprasad G Bhat
78beb6073fSDaniel Henrique Barboza if (!mc->nvdimm_supported) {
79beb6073fSDaniel Henrique Barboza error_setg(errp, "NVDIMM hotplug not supported for this machine");
80451c6905SGreg Kurz return false;
81beb6073fSDaniel Henrique Barboza }
82beb6073fSDaniel Henrique Barboza
8355810e90SIgor Mammedov if (!ms->nvdimms_state->is_enabled) {
8428f5a716SDaniel Henrique Barboza error_setg(errp, "nvdimm device found but 'nvdimm=off' was set");
85451c6905SGreg Kurz return false;
8628f5a716SDaniel Henrique Barboza }
8728f5a716SDaniel Henrique Barboza
8870fc9cb0SDaniel Henrique Barboza if (object_property_get_int(OBJECT(nvdimm), NVDIMM_LABEL_SIZE_PROP,
8970fc9cb0SDaniel Henrique Barboza &error_abort) == 0) {
906c0f0cb3SDavid Gibson error_setg(errp, "PAPR requires NVDIMM devices to have label-size set");
91451c6905SGreg Kurz return false;
9270fc9cb0SDaniel Henrique Barboza }
9370fc9cb0SDaniel Henrique Barboza
94ee3a71e3SShivaprasad G Bhat if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) {
956c0f0cb3SDavid Gibson error_setg(errp, "PAPR requires NVDIMM memory size (excluding label)"
966c0f0cb3SDavid Gibson " to be a multiple of %" PRIu64 "MB",
97ee3a71e3SShivaprasad G Bhat SPAPR_MINIMUM_SCM_BLOCK_SIZE / MiB);
98451c6905SGreg Kurz return false;
99ee3a71e3SShivaprasad G Bhat }
100ee3a71e3SShivaprasad G Bhat
101af7084e7SShivaprasad G Bhat uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP,
102af7084e7SShivaprasad G Bhat &error_abort);
103af7084e7SShivaprasad G Bhat ret = qemu_uuid_parse(uuidstr, &uuid);
104af7084e7SShivaprasad G Bhat g_assert(!ret);
105ee3a71e3SShivaprasad G Bhat
106ee3a71e3SShivaprasad G Bhat if (qemu_uuid_is_null(&uuid)) {
107ee3a71e3SShivaprasad G Bhat error_setg(errp, "NVDIMM device requires the uuid to be set");
108451c6905SGreg Kurz return false;
109ee3a71e3SShivaprasad G Bhat }
110451c6905SGreg Kurz
1118601b4f1SShivaprasad G Bhat if (object_dynamic_cast(OBJECT(nvdimm), TYPE_SPAPR_NVDIMM) &&
1128601b4f1SShivaprasad G Bhat (memory_region_get_fd(mr) < 0)) {
1138601b4f1SShivaprasad G Bhat error_setg(errp, "spapr-nvdimm device requires the "
1148601b4f1SShivaprasad G Bhat "memdev %s to be of memory-backend-file type",
1158601b4f1SShivaprasad G Bhat object_get_canonical_path_component(OBJECT(dimm->hostmem)));
1168601b4f1SShivaprasad G Bhat return false;
1178601b4f1SShivaprasad G Bhat }
1188601b4f1SShivaprasad G Bhat
119451c6905SGreg Kurz return true;
120ee3a71e3SShivaprasad G Bhat }
121ee3a71e3SShivaprasad G Bhat
122ee3a71e3SShivaprasad G Bhat
spapr_add_nvdimm(DeviceState * dev,uint64_t slot)123ea042c53SGreg Kurz void spapr_add_nvdimm(DeviceState *dev, uint64_t slot)
124ee3a71e3SShivaprasad G Bhat {
125ee3a71e3SShivaprasad G Bhat SpaprDrc *drc;
126ee3a71e3SShivaprasad G Bhat bool hotplugged = spapr_drc_hotplugged(dev);
127ee3a71e3SShivaprasad G Bhat
128ee3a71e3SShivaprasad G Bhat drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PMEM, slot);
129ee3a71e3SShivaprasad G Bhat g_assert(drc);
130ee3a71e3SShivaprasad G Bhat
131ea042c53SGreg Kurz /*
132ea042c53SGreg Kurz * pc_dimm_get_free_slot() provided a free slot at pre-plug. The
133ea042c53SGreg Kurz * corresponding DRC is thus assumed to be attachable.
134ea042c53SGreg Kurz */
135bc370a65SGreg Kurz spapr_drc_attach(drc, dev);
136ee3a71e3SShivaprasad G Bhat
137ee3a71e3SShivaprasad G Bhat if (hotplugged) {
138ee3a71e3SShivaprasad G Bhat spapr_hotplug_req_add_by_index(drc);
139ee3a71e3SShivaprasad G Bhat }
140ee3a71e3SShivaprasad G Bhat }
141ee3a71e3SShivaprasad G Bhat
spapr_dt_nvdimm(SpaprMachineState * spapr,void * fdt,int parent_offset,NVDIMMDevice * nvdimm)142f1aa45ffSDaniel Henrique Barboza static int spapr_dt_nvdimm(SpaprMachineState *spapr, void *fdt,
143f1aa45ffSDaniel Henrique Barboza int parent_offset, NVDIMMDevice *nvdimm)
144ee3a71e3SShivaprasad G Bhat {
145ee3a71e3SShivaprasad G Bhat int child_offset;
146ee3a71e3SShivaprasad G Bhat char *buf;
147ee3a71e3SShivaprasad G Bhat SpaprDrc *drc;
148ee3a71e3SShivaprasad G Bhat uint32_t drc_idx;
149ee3a71e3SShivaprasad G Bhat uint32_t node = object_property_get_uint(OBJECT(nvdimm), PC_DIMM_NODE_PROP,
150ee3a71e3SShivaprasad G Bhat &error_abort);
151ee3a71e3SShivaprasad G Bhat uint64_t slot = object_property_get_uint(OBJECT(nvdimm), PC_DIMM_SLOT_PROP,
152ee3a71e3SShivaprasad G Bhat &error_abort);
153ee3a71e3SShivaprasad G Bhat uint64_t lsize = nvdimm->label_size;
154ee3a71e3SShivaprasad G Bhat uint64_t size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
155ee3a71e3SShivaprasad G Bhat NULL);
156ee3a71e3SShivaprasad G Bhat
157ee3a71e3SShivaprasad G Bhat drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PMEM, slot);
158ee3a71e3SShivaprasad G Bhat g_assert(drc);
159ee3a71e3SShivaprasad G Bhat
160ee3a71e3SShivaprasad G Bhat drc_idx = spapr_drc_index(drc);
161ee3a71e3SShivaprasad G Bhat
162ee3a71e3SShivaprasad G Bhat buf = g_strdup_printf("ibm,pmemory@%x", drc_idx);
163ee3a71e3SShivaprasad G Bhat child_offset = fdt_add_subnode(fdt, parent_offset, buf);
164ee3a71e3SShivaprasad G Bhat g_free(buf);
165ee3a71e3SShivaprasad G Bhat
166ee3a71e3SShivaprasad G Bhat _FDT(child_offset);
167ee3a71e3SShivaprasad G Bhat
168ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, child_offset, "reg", drc_idx)));
169ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "compatible", "ibm,pmemory")));
170ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "device_type", "ibm,pmemory")));
171ee3a71e3SShivaprasad G Bhat
172f1aa45ffSDaniel Henrique Barboza spapr_numa_write_associativity_dt(spapr, fdt, child_offset, node);
173ee3a71e3SShivaprasad G Bhat
174ee3a71e3SShivaprasad G Bhat buf = qemu_uuid_unparse_strdup(&nvdimm->uuid);
175ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "ibm,unit-guid", buf)));
176ee3a71e3SShivaprasad G Bhat g_free(buf);
177ee3a71e3SShivaprasad G Bhat
178ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, child_offset, "ibm,my-drc-index", drc_idx)));
179ee3a71e3SShivaprasad G Bhat
180ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_u64(fdt, child_offset, "ibm,block-size",
181ee3a71e3SShivaprasad G Bhat SPAPR_MINIMUM_SCM_BLOCK_SIZE)));
182ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_u64(fdt, child_offset, "ibm,number-of-blocks",
183ee3a71e3SShivaprasad G Bhat size / SPAPR_MINIMUM_SCM_BLOCK_SIZE)));
184ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, child_offset, "ibm,metadata-size", lsize)));
185ee3a71e3SShivaprasad G Bhat
186ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "ibm,pmem-application",
187ee3a71e3SShivaprasad G Bhat "operating-system")));
188ee3a71e3SShivaprasad G Bhat _FDT(fdt_setprop(fdt, child_offset, "ibm,cache-flush-required", NULL, 0));
189ee3a71e3SShivaprasad G Bhat
1908601b4f1SShivaprasad G Bhat if (object_dynamic_cast(OBJECT(nvdimm), TYPE_SPAPR_NVDIMM)) {
1918601b4f1SShivaprasad G Bhat bool is_pmem = false, pmem_override = false;
1928601b4f1SShivaprasad G Bhat PCDIMMDevice *dimm = PC_DIMM(nvdimm);
1938601b4f1SShivaprasad G Bhat HostMemoryBackend *hostmem = dimm->hostmem;
1948601b4f1SShivaprasad G Bhat
1958601b4f1SShivaprasad G Bhat is_pmem = object_property_get_bool(OBJECT(hostmem), "pmem", NULL);
1968601b4f1SShivaprasad G Bhat pmem_override = object_property_get_bool(OBJECT(nvdimm),
1978601b4f1SShivaprasad G Bhat "pmem-override", NULL);
1988601b4f1SShivaprasad G Bhat if (!is_pmem || pmem_override) {
1998601b4f1SShivaprasad G Bhat _FDT(fdt_setprop(fdt, child_offset, "ibm,hcall-flush-required",
2008601b4f1SShivaprasad G Bhat NULL, 0));
2018601b4f1SShivaprasad G Bhat }
2028601b4f1SShivaprasad G Bhat }
2038601b4f1SShivaprasad G Bhat
204ee3a71e3SShivaprasad G Bhat return child_offset;
205ee3a71e3SShivaprasad G Bhat }
206ee3a71e3SShivaprasad G Bhat
spapr_pmem_dt_populate(SpaprDrc * drc,SpaprMachineState * spapr,void * fdt,int * fdt_start_offset,Error ** errp)2076ee1d62eSDaniel Henrique Barboza int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
2086ee1d62eSDaniel Henrique Barboza void *fdt, int *fdt_start_offset, Error **errp)
2096ee1d62eSDaniel Henrique Barboza {
2106ee1d62eSDaniel Henrique Barboza NVDIMMDevice *nvdimm = NVDIMM(drc->dev);
2116ee1d62eSDaniel Henrique Barboza
212f1aa45ffSDaniel Henrique Barboza *fdt_start_offset = spapr_dt_nvdimm(spapr, fdt, 0, nvdimm);
2136ee1d62eSDaniel Henrique Barboza
2146ee1d62eSDaniel Henrique Barboza return 0;
2156ee1d62eSDaniel Henrique Barboza }
2166ee1d62eSDaniel Henrique Barboza
spapr_dt_persistent_memory(SpaprMachineState * spapr,void * fdt)217f1aa45ffSDaniel Henrique Barboza void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt)
218ee3a71e3SShivaprasad G Bhat {
2199f9f82daSShivaprasad G Bhat int offset = fdt_subnode_offset(fdt, 0, "ibm,persistent-memory");
220ee3a71e3SShivaprasad G Bhat GSList *iter, *nvdimms = nvdimm_get_device_list();
221ee3a71e3SShivaprasad G Bhat
222ee3a71e3SShivaprasad G Bhat if (offset < 0) {
2239f9f82daSShivaprasad G Bhat offset = fdt_add_subnode(fdt, 0, "ibm,persistent-memory");
224ee3a71e3SShivaprasad G Bhat _FDT(offset);
225ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1)));
226ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0)));
227ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, offset, "device_type",
228ee3a71e3SShivaprasad G Bhat "ibm,persistent-memory")));
229ee3a71e3SShivaprasad G Bhat }
230ee3a71e3SShivaprasad G Bhat
231ee3a71e3SShivaprasad G Bhat /* Create DT entries for cold plugged NVDIMM devices */
232ee3a71e3SShivaprasad G Bhat for (iter = nvdimms; iter; iter = iter->next) {
233ee3a71e3SShivaprasad G Bhat NVDIMMDevice *nvdimm = iter->data;
234ee3a71e3SShivaprasad G Bhat
235f1aa45ffSDaniel Henrique Barboza spapr_dt_nvdimm(spapr, fdt, offset, nvdimm);
236ee3a71e3SShivaprasad G Bhat }
237ee3a71e3SShivaprasad G Bhat g_slist_free(nvdimms);
238ee3a71e3SShivaprasad G Bhat
239ee3a71e3SShivaprasad G Bhat return;
240ee3a71e3SShivaprasad G Bhat }
241b5fca656SShivaprasad G Bhat
h_scm_read_metadata(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)242b5fca656SShivaprasad G Bhat static target_ulong h_scm_read_metadata(PowerPCCPU *cpu,
243b5fca656SShivaprasad G Bhat SpaprMachineState *spapr,
244b5fca656SShivaprasad G Bhat target_ulong opcode,
245b5fca656SShivaprasad G Bhat target_ulong *args)
246b5fca656SShivaprasad G Bhat {
247b5fca656SShivaprasad G Bhat uint32_t drc_index = args[0];
248b5fca656SShivaprasad G Bhat uint64_t offset = args[1];
249b5fca656SShivaprasad G Bhat uint64_t len = args[2];
250b5fca656SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(drc_index);
251b5fca656SShivaprasad G Bhat NVDIMMDevice *nvdimm;
252b5fca656SShivaprasad G Bhat NVDIMMClass *ddc;
253b5fca656SShivaprasad G Bhat uint64_t data = 0;
254b5fca656SShivaprasad G Bhat uint8_t buf[8] = { 0 };
255b5fca656SShivaprasad G Bhat
256b5fca656SShivaprasad G Bhat if (!drc || !drc->dev ||
257b5fca656SShivaprasad G Bhat spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
258b5fca656SShivaprasad G Bhat return H_PARAMETER;
259b5fca656SShivaprasad G Bhat }
260b5fca656SShivaprasad G Bhat
261b5fca656SShivaprasad G Bhat if (len != 1 && len != 2 &&
262b5fca656SShivaprasad G Bhat len != 4 && len != 8) {
263b5fca656SShivaprasad G Bhat return H_P3;
264b5fca656SShivaprasad G Bhat }
265b5fca656SShivaprasad G Bhat
266b5fca656SShivaprasad G Bhat nvdimm = NVDIMM(drc->dev);
267b5fca656SShivaprasad G Bhat if ((offset + len < offset) ||
268b5fca656SShivaprasad G Bhat (nvdimm->label_size < len + offset)) {
269b5fca656SShivaprasad G Bhat return H_P2;
270b5fca656SShivaprasad G Bhat }
271b5fca656SShivaprasad G Bhat
272b5fca656SShivaprasad G Bhat ddc = NVDIMM_GET_CLASS(nvdimm);
273b5fca656SShivaprasad G Bhat ddc->read_label_data(nvdimm, buf, len, offset);
274b5fca656SShivaprasad G Bhat
275b5fca656SShivaprasad G Bhat switch (len) {
276b5fca656SShivaprasad G Bhat case 1:
277b5fca656SShivaprasad G Bhat data = ldub_p(buf);
278b5fca656SShivaprasad G Bhat break;
279b5fca656SShivaprasad G Bhat case 2:
280b5fca656SShivaprasad G Bhat data = lduw_be_p(buf);
281b5fca656SShivaprasad G Bhat break;
282b5fca656SShivaprasad G Bhat case 4:
283b5fca656SShivaprasad G Bhat data = ldl_be_p(buf);
284b5fca656SShivaprasad G Bhat break;
285b5fca656SShivaprasad G Bhat case 8:
286b5fca656SShivaprasad G Bhat data = ldq_be_p(buf);
287b5fca656SShivaprasad G Bhat break;
288b5fca656SShivaprasad G Bhat default:
289b5fca656SShivaprasad G Bhat g_assert_not_reached();
290b5fca656SShivaprasad G Bhat }
291b5fca656SShivaprasad G Bhat
292b5fca656SShivaprasad G Bhat args[0] = data;
293b5fca656SShivaprasad G Bhat
294b5fca656SShivaprasad G Bhat return H_SUCCESS;
295b5fca656SShivaprasad G Bhat }
296b5fca656SShivaprasad G Bhat
h_scm_write_metadata(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)297b5fca656SShivaprasad G Bhat static target_ulong h_scm_write_metadata(PowerPCCPU *cpu,
298b5fca656SShivaprasad G Bhat SpaprMachineState *spapr,
299b5fca656SShivaprasad G Bhat target_ulong opcode,
300b5fca656SShivaprasad G Bhat target_ulong *args)
301b5fca656SShivaprasad G Bhat {
302b5fca656SShivaprasad G Bhat uint32_t drc_index = args[0];
303b5fca656SShivaprasad G Bhat uint64_t offset = args[1];
304b5fca656SShivaprasad G Bhat uint64_t data = args[2];
305b5fca656SShivaprasad G Bhat uint64_t len = args[3];
306b5fca656SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(drc_index);
307b5fca656SShivaprasad G Bhat NVDIMMDevice *nvdimm;
308b5fca656SShivaprasad G Bhat NVDIMMClass *ddc;
309b5fca656SShivaprasad G Bhat uint8_t buf[8] = { 0 };
310b5fca656SShivaprasad G Bhat
311b5fca656SShivaprasad G Bhat if (!drc || !drc->dev ||
312b5fca656SShivaprasad G Bhat spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
313b5fca656SShivaprasad G Bhat return H_PARAMETER;
314b5fca656SShivaprasad G Bhat }
315b5fca656SShivaprasad G Bhat
316b5fca656SShivaprasad G Bhat if (len != 1 && len != 2 &&
317b5fca656SShivaprasad G Bhat len != 4 && len != 8) {
318b5fca656SShivaprasad G Bhat return H_P4;
319b5fca656SShivaprasad G Bhat }
320b5fca656SShivaprasad G Bhat
321b5fca656SShivaprasad G Bhat nvdimm = NVDIMM(drc->dev);
322b5fca656SShivaprasad G Bhat if ((offset + len < offset) ||
3233a125839SDavid Hildenbrand (nvdimm->label_size < len + offset) ||
3243a125839SDavid Hildenbrand nvdimm->readonly) {
325b5fca656SShivaprasad G Bhat return H_P2;
326b5fca656SShivaprasad G Bhat }
327b5fca656SShivaprasad G Bhat
328b5fca656SShivaprasad G Bhat switch (len) {
329b5fca656SShivaprasad G Bhat case 1:
330b5fca656SShivaprasad G Bhat if (data & 0xffffffffffffff00) {
331b5fca656SShivaprasad G Bhat return H_P2;
332b5fca656SShivaprasad G Bhat }
333b5fca656SShivaprasad G Bhat stb_p(buf, data);
334b5fca656SShivaprasad G Bhat break;
335b5fca656SShivaprasad G Bhat case 2:
336b5fca656SShivaprasad G Bhat if (data & 0xffffffffffff0000) {
337b5fca656SShivaprasad G Bhat return H_P2;
338b5fca656SShivaprasad G Bhat }
339b5fca656SShivaprasad G Bhat stw_be_p(buf, data);
340b5fca656SShivaprasad G Bhat break;
341b5fca656SShivaprasad G Bhat case 4:
342b5fca656SShivaprasad G Bhat if (data & 0xffffffff00000000) {
343b5fca656SShivaprasad G Bhat return H_P2;
344b5fca656SShivaprasad G Bhat }
345b5fca656SShivaprasad G Bhat stl_be_p(buf, data);
346b5fca656SShivaprasad G Bhat break;
347b5fca656SShivaprasad G Bhat case 8:
348b5fca656SShivaprasad G Bhat stq_be_p(buf, data);
349b5fca656SShivaprasad G Bhat break;
350b5fca656SShivaprasad G Bhat default:
351b5fca656SShivaprasad G Bhat g_assert_not_reached();
352b5fca656SShivaprasad G Bhat }
353b5fca656SShivaprasad G Bhat
354b5fca656SShivaprasad G Bhat ddc = NVDIMM_GET_CLASS(nvdimm);
355b5fca656SShivaprasad G Bhat ddc->write_label_data(nvdimm, buf, len, offset);
356b5fca656SShivaprasad G Bhat
357b5fca656SShivaprasad G Bhat return H_SUCCESS;
358b5fca656SShivaprasad G Bhat }
359b5fca656SShivaprasad G Bhat
h_scm_bind_mem(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)360b5fca656SShivaprasad G Bhat static target_ulong h_scm_bind_mem(PowerPCCPU *cpu, SpaprMachineState *spapr,
361b5fca656SShivaprasad G Bhat target_ulong opcode, target_ulong *args)
362b5fca656SShivaprasad G Bhat {
363b5fca656SShivaprasad G Bhat uint32_t drc_index = args[0];
364b5fca656SShivaprasad G Bhat uint64_t starting_idx = args[1];
365b5fca656SShivaprasad G Bhat uint64_t no_of_scm_blocks_to_bind = args[2];
366b5fca656SShivaprasad G Bhat uint64_t target_logical_mem_addr = args[3];
367b5fca656SShivaprasad G Bhat uint64_t continue_token = args[4];
368b5fca656SShivaprasad G Bhat uint64_t size;
369b5fca656SShivaprasad G Bhat uint64_t total_no_of_scm_blocks;
370b5fca656SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(drc_index);
371b5fca656SShivaprasad G Bhat hwaddr addr;
372b5fca656SShivaprasad G Bhat NVDIMMDevice *nvdimm;
373b5fca656SShivaprasad G Bhat
374b5fca656SShivaprasad G Bhat if (!drc || !drc->dev ||
375b5fca656SShivaprasad G Bhat spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
376b5fca656SShivaprasad G Bhat return H_PARAMETER;
377b5fca656SShivaprasad G Bhat }
378b5fca656SShivaprasad G Bhat
379b5fca656SShivaprasad G Bhat /*
380b5fca656SShivaprasad G Bhat * Currently continue token should be zero qemu has already bound
381e6a19a64SMichael Tokarev * everything and this hcall doesn't return H_BUSY.
382b5fca656SShivaprasad G Bhat */
383b5fca656SShivaprasad G Bhat if (continue_token > 0) {
384b5fca656SShivaprasad G Bhat return H_P5;
385b5fca656SShivaprasad G Bhat }
386b5fca656SShivaprasad G Bhat
387b5fca656SShivaprasad G Bhat /* Currently qemu assigns the address. */
388b5fca656SShivaprasad G Bhat if (target_logical_mem_addr != 0xffffffffffffffff) {
389b5fca656SShivaprasad G Bhat return H_OVERLAP;
390b5fca656SShivaprasad G Bhat }
391b5fca656SShivaprasad G Bhat
392b5fca656SShivaprasad G Bhat nvdimm = NVDIMM(drc->dev);
393b5fca656SShivaprasad G Bhat
394b5fca656SShivaprasad G Bhat size = object_property_get_uint(OBJECT(nvdimm),
395b5fca656SShivaprasad G Bhat PC_DIMM_SIZE_PROP, &error_abort);
396b5fca656SShivaprasad G Bhat
397b5fca656SShivaprasad G Bhat total_no_of_scm_blocks = size / SPAPR_MINIMUM_SCM_BLOCK_SIZE;
398b5fca656SShivaprasad G Bhat
399b5fca656SShivaprasad G Bhat if (starting_idx > total_no_of_scm_blocks) {
400b5fca656SShivaprasad G Bhat return H_P2;
401b5fca656SShivaprasad G Bhat }
402b5fca656SShivaprasad G Bhat
403b5fca656SShivaprasad G Bhat if (((starting_idx + no_of_scm_blocks_to_bind) < starting_idx) ||
404b5fca656SShivaprasad G Bhat ((starting_idx + no_of_scm_blocks_to_bind) > total_no_of_scm_blocks)) {
405b5fca656SShivaprasad G Bhat return H_P3;
406b5fca656SShivaprasad G Bhat }
407b5fca656SShivaprasad G Bhat
408b5fca656SShivaprasad G Bhat addr = object_property_get_uint(OBJECT(nvdimm),
409b5fca656SShivaprasad G Bhat PC_DIMM_ADDR_PROP, &error_abort);
410b5fca656SShivaprasad G Bhat
411b5fca656SShivaprasad G Bhat addr += starting_idx * SPAPR_MINIMUM_SCM_BLOCK_SIZE;
412b5fca656SShivaprasad G Bhat
413b5fca656SShivaprasad G Bhat /* Already bound, Return target logical address in R5 */
414b5fca656SShivaprasad G Bhat args[1] = addr;
415b5fca656SShivaprasad G Bhat args[2] = no_of_scm_blocks_to_bind;
416b5fca656SShivaprasad G Bhat
417b5fca656SShivaprasad G Bhat return H_SUCCESS;
418b5fca656SShivaprasad G Bhat }
419b5fca656SShivaprasad G Bhat
420b5513584SShivaprasad G Bhat typedef struct SpaprNVDIMMDeviceFlushState {
421b5513584SShivaprasad G Bhat uint64_t continue_token;
422b5513584SShivaprasad G Bhat int64_t hcall_ret;
423b5513584SShivaprasad G Bhat uint32_t drcidx;
424b5513584SShivaprasad G Bhat
425b5513584SShivaprasad G Bhat QLIST_ENTRY(SpaprNVDIMMDeviceFlushState) node;
426b5513584SShivaprasad G Bhat } SpaprNVDIMMDeviceFlushState;
427b5513584SShivaprasad G Bhat
428b5513584SShivaprasad G Bhat typedef struct SpaprNVDIMMDevice SpaprNVDIMMDevice;
429b5513584SShivaprasad G Bhat struct SpaprNVDIMMDevice {
4308601b4f1SShivaprasad G Bhat /* private */
431b5513584SShivaprasad G Bhat NVDIMMDevice parent_obj;
432b5513584SShivaprasad G Bhat
4338601b4f1SShivaprasad G Bhat bool hcall_flush_required;
434b5513584SShivaprasad G Bhat uint64_t nvdimm_flush_token;
435b5513584SShivaprasad G Bhat QLIST_HEAD(, SpaprNVDIMMDeviceFlushState) pending_nvdimm_flush_states;
436b5513584SShivaprasad G Bhat QLIST_HEAD(, SpaprNVDIMMDeviceFlushState) completed_nvdimm_flush_states;
4378601b4f1SShivaprasad G Bhat
4388601b4f1SShivaprasad G Bhat /* public */
4398601b4f1SShivaprasad G Bhat
4408601b4f1SShivaprasad G Bhat /*
4418601b4f1SShivaprasad G Bhat * The 'on' value for this property forced the qemu to enable the hcall
4428601b4f1SShivaprasad G Bhat * flush for the nvdimm device even if the backend is a pmem
4438601b4f1SShivaprasad G Bhat */
4448601b4f1SShivaprasad G Bhat bool pmem_override;
445b5513584SShivaprasad G Bhat };
446b5513584SShivaprasad G Bhat
flush_worker_cb(void * opaque)447b5513584SShivaprasad G Bhat static int flush_worker_cb(void *opaque)
448b5513584SShivaprasad G Bhat {
449b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState *state = opaque;
450b5513584SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(state->drcidx);
451edccf661SDaniel Henrique Barboza PCDIMMDevice *dimm;
452edccf661SDaniel Henrique Barboza HostMemoryBackend *backend;
453edccf661SDaniel Henrique Barboza int backend_fd;
454edccf661SDaniel Henrique Barboza
455edccf661SDaniel Henrique Barboza g_assert(drc != NULL);
456edccf661SDaniel Henrique Barboza
457edccf661SDaniel Henrique Barboza dimm = PC_DIMM(drc->dev);
458edccf661SDaniel Henrique Barboza backend = MEMORY_BACKEND(dimm->hostmem);
459edccf661SDaniel Henrique Barboza backend_fd = memory_region_get_fd(&backend->mr);
460b5513584SShivaprasad G Bhat
461b5513584SShivaprasad G Bhat if (object_property_get_bool(OBJECT(backend), "pmem", NULL)) {
462b5513584SShivaprasad G Bhat MemoryRegion *mr = host_memory_backend_get_memory(dimm->hostmem);
463b5513584SShivaprasad G Bhat void *ptr = memory_region_get_ram_ptr(mr);
464b5513584SShivaprasad G Bhat size_t size = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP,
465b5513584SShivaprasad G Bhat NULL);
466b5513584SShivaprasad G Bhat
467b5513584SShivaprasad G Bhat /* flush pmem backend */
468b5513584SShivaprasad G Bhat pmem_persist(ptr, size);
469b5513584SShivaprasad G Bhat } else {
470b5513584SShivaprasad G Bhat /* flush raw backing image */
471b5513584SShivaprasad G Bhat if (qemu_fdatasync(backend_fd) < 0) {
472b5513584SShivaprasad G Bhat error_report("papr_scm: Could not sync nvdimm to backend file: %s",
473b5513584SShivaprasad G Bhat strerror(errno));
474b5513584SShivaprasad G Bhat return H_HARDWARE;
475b5513584SShivaprasad G Bhat }
476b5513584SShivaprasad G Bhat }
477b5513584SShivaprasad G Bhat
478b5513584SShivaprasad G Bhat return H_SUCCESS;
479b5513584SShivaprasad G Bhat }
480b5513584SShivaprasad G Bhat
spapr_nvdimm_flush_completion_cb(void * opaque,int hcall_ret)481b5513584SShivaprasad G Bhat static void spapr_nvdimm_flush_completion_cb(void *opaque, int hcall_ret)
482b5513584SShivaprasad G Bhat {
483b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState *state = opaque;
484b5513584SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(state->drcidx);
485edccf661SDaniel Henrique Barboza SpaprNVDIMMDevice *s_nvdimm;
486edccf661SDaniel Henrique Barboza
487edccf661SDaniel Henrique Barboza g_assert(drc != NULL);
488edccf661SDaniel Henrique Barboza
489edccf661SDaniel Henrique Barboza s_nvdimm = SPAPR_NVDIMM(drc->dev);
490b5513584SShivaprasad G Bhat
491b5513584SShivaprasad G Bhat state->hcall_ret = hcall_ret;
492b5513584SShivaprasad G Bhat QLIST_REMOVE(state, node);
493b5513584SShivaprasad G Bhat QLIST_INSERT_HEAD(&s_nvdimm->completed_nvdimm_flush_states, state, node);
494b5513584SShivaprasad G Bhat }
495b5513584SShivaprasad G Bhat
spapr_nvdimm_flush_post_load(void * opaque,int version_id)496b5513584SShivaprasad G Bhat static int spapr_nvdimm_flush_post_load(void *opaque, int version_id)
497b5513584SShivaprasad G Bhat {
498b5513584SShivaprasad G Bhat SpaprNVDIMMDevice *s_nvdimm = (SpaprNVDIMMDevice *)opaque;
499b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState *state;
5008601b4f1SShivaprasad G Bhat HostMemoryBackend *backend = MEMORY_BACKEND(PC_DIMM(s_nvdimm)->hostmem);
5018601b4f1SShivaprasad G Bhat bool is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL);
5028601b4f1SShivaprasad G Bhat bool pmem_override = object_property_get_bool(OBJECT(s_nvdimm),
5038601b4f1SShivaprasad G Bhat "pmem-override", NULL);
5048601b4f1SShivaprasad G Bhat bool dest_hcall_flush_required = pmem_override || !is_pmem;
5058601b4f1SShivaprasad G Bhat
5068601b4f1SShivaprasad G Bhat if (!s_nvdimm->hcall_flush_required && dest_hcall_flush_required) {
5078601b4f1SShivaprasad G Bhat error_report("The file backend for the spapr-nvdimm device %s at "
5088601b4f1SShivaprasad G Bhat "source is a pmem, use pmem=on and pmem-override=off to "
5098601b4f1SShivaprasad G Bhat "continue.", DEVICE(s_nvdimm)->id);
5108601b4f1SShivaprasad G Bhat return -EINVAL;
5118601b4f1SShivaprasad G Bhat }
5128601b4f1SShivaprasad G Bhat if (s_nvdimm->hcall_flush_required && !dest_hcall_flush_required) {
5138601b4f1SShivaprasad G Bhat error_report("The guest expects hcall-flush support for the "
5148601b4f1SShivaprasad G Bhat "spapr-nvdimm device %s, use pmem_override=on to "
5158601b4f1SShivaprasad G Bhat "continue.", DEVICE(s_nvdimm)->id);
5168601b4f1SShivaprasad G Bhat return -EINVAL;
5178601b4f1SShivaprasad G Bhat }
518b5513584SShivaprasad G Bhat
519b5513584SShivaprasad G Bhat QLIST_FOREACH(state, &s_nvdimm->pending_nvdimm_flush_states, node) {
520aef04fc7SEmanuele Giuseppe Esposito thread_pool_submit_aio(flush_worker_cb, state,
521b5513584SShivaprasad G Bhat spapr_nvdimm_flush_completion_cb, state);
522b5513584SShivaprasad G Bhat }
523b5513584SShivaprasad G Bhat
524b5513584SShivaprasad G Bhat return 0;
525b5513584SShivaprasad G Bhat }
526b5513584SShivaprasad G Bhat
527b5513584SShivaprasad G Bhat static const VMStateDescription vmstate_spapr_nvdimm_flush_state = {
528b5513584SShivaprasad G Bhat .name = "spapr_nvdimm_flush_state",
529b5513584SShivaprasad G Bhat .version_id = 1,
530b5513584SShivaprasad G Bhat .minimum_version_id = 1,
531b5513584SShivaprasad G Bhat .fields = (VMStateField[]) {
532b5513584SShivaprasad G Bhat VMSTATE_UINT64(continue_token, SpaprNVDIMMDeviceFlushState),
533b5513584SShivaprasad G Bhat VMSTATE_INT64(hcall_ret, SpaprNVDIMMDeviceFlushState),
534b5513584SShivaprasad G Bhat VMSTATE_UINT32(drcidx, SpaprNVDIMMDeviceFlushState),
535b5513584SShivaprasad G Bhat VMSTATE_END_OF_LIST()
536b5513584SShivaprasad G Bhat },
537b5513584SShivaprasad G Bhat };
538b5513584SShivaprasad G Bhat
539b5513584SShivaprasad G Bhat const VMStateDescription vmstate_spapr_nvdimm_states = {
540b5513584SShivaprasad G Bhat .name = "spapr_nvdimm_states",
541b5513584SShivaprasad G Bhat .version_id = 1,
542b5513584SShivaprasad G Bhat .minimum_version_id = 1,
543b5513584SShivaprasad G Bhat .post_load = spapr_nvdimm_flush_post_load,
544b5513584SShivaprasad G Bhat .fields = (VMStateField[]) {
5458601b4f1SShivaprasad G Bhat VMSTATE_BOOL(hcall_flush_required, SpaprNVDIMMDevice),
546b5513584SShivaprasad G Bhat VMSTATE_UINT64(nvdimm_flush_token, SpaprNVDIMMDevice),
547b5513584SShivaprasad G Bhat VMSTATE_QLIST_V(completed_nvdimm_flush_states, SpaprNVDIMMDevice, 1,
548b5513584SShivaprasad G Bhat vmstate_spapr_nvdimm_flush_state,
549b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState, node),
550b5513584SShivaprasad G Bhat VMSTATE_QLIST_V(pending_nvdimm_flush_states, SpaprNVDIMMDevice, 1,
551b5513584SShivaprasad G Bhat vmstate_spapr_nvdimm_flush_state,
552b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState, node),
553b5513584SShivaprasad G Bhat VMSTATE_END_OF_LIST()
554b5513584SShivaprasad G Bhat },
555b5513584SShivaprasad G Bhat };
556b5513584SShivaprasad G Bhat
557b5513584SShivaprasad G Bhat /*
558b5513584SShivaprasad G Bhat * Assign a token and reserve it for the new flush state.
559b5513584SShivaprasad G Bhat */
spapr_nvdimm_init_new_flush_state(SpaprNVDIMMDevice * spapr_nvdimm)560b5513584SShivaprasad G Bhat static SpaprNVDIMMDeviceFlushState *spapr_nvdimm_init_new_flush_state(
561b5513584SShivaprasad G Bhat SpaprNVDIMMDevice *spapr_nvdimm)
562b5513584SShivaprasad G Bhat {
563b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState *state;
564b5513584SShivaprasad G Bhat
565b5513584SShivaprasad G Bhat state = g_malloc0(sizeof(*state));
566b5513584SShivaprasad G Bhat
567b5513584SShivaprasad G Bhat spapr_nvdimm->nvdimm_flush_token++;
568b5513584SShivaprasad G Bhat /* Token zero is presumed as no job pending. Assert on overflow to zero */
569b5513584SShivaprasad G Bhat g_assert(spapr_nvdimm->nvdimm_flush_token != 0);
570b5513584SShivaprasad G Bhat
571b5513584SShivaprasad G Bhat state->continue_token = spapr_nvdimm->nvdimm_flush_token;
572b5513584SShivaprasad G Bhat
573b5513584SShivaprasad G Bhat QLIST_INSERT_HEAD(&spapr_nvdimm->pending_nvdimm_flush_states, state, node);
574b5513584SShivaprasad G Bhat
575b5513584SShivaprasad G Bhat return state;
576b5513584SShivaprasad G Bhat }
577b5513584SShivaprasad G Bhat
578b5513584SShivaprasad G Bhat /*
579b5513584SShivaprasad G Bhat * spapr_nvdimm_finish_flushes
580b5513584SShivaprasad G Bhat * Waits for all pending flush requests to complete
581b5513584SShivaprasad G Bhat * their execution and free the states
582b5513584SShivaprasad G Bhat */
spapr_nvdimm_finish_flushes(void)583b5513584SShivaprasad G Bhat void spapr_nvdimm_finish_flushes(void)
584b5513584SShivaprasad G Bhat {
585b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState *state, *next;
586b5513584SShivaprasad G Bhat GSList *list, *nvdimms;
587b5513584SShivaprasad G Bhat
588b5513584SShivaprasad G Bhat /*
589b5513584SShivaprasad G Bhat * Called on reset path, the main loop thread which calls
590b5513584SShivaprasad G Bhat * the pending BHs has gotten out running in the reset path,
591b5513584SShivaprasad G Bhat * finally reaching here. Other code path being guest
592e6a19a64SMichael Tokarev * h_client_architecture_support, that's early boot up.
593b5513584SShivaprasad G Bhat */
594b5513584SShivaprasad G Bhat nvdimms = nvdimm_get_device_list();
595b5513584SShivaprasad G Bhat for (list = nvdimms; list; list = list->next) {
596b5513584SShivaprasad G Bhat NVDIMMDevice *nvdimm = list->data;
597b5513584SShivaprasad G Bhat if (object_dynamic_cast(OBJECT(nvdimm), TYPE_SPAPR_NVDIMM)) {
598b5513584SShivaprasad G Bhat SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(nvdimm);
599b5513584SShivaprasad G Bhat while (!QLIST_EMPTY(&s_nvdimm->pending_nvdimm_flush_states)) {
600b5513584SShivaprasad G Bhat aio_poll(qemu_get_aio_context(), true);
601b5513584SShivaprasad G Bhat }
602b5513584SShivaprasad G Bhat
603b5513584SShivaprasad G Bhat QLIST_FOREACH_SAFE(state, &s_nvdimm->completed_nvdimm_flush_states,
604b5513584SShivaprasad G Bhat node, next) {
605b5513584SShivaprasad G Bhat QLIST_REMOVE(state, node);
606b5513584SShivaprasad G Bhat g_free(state);
607b5513584SShivaprasad G Bhat }
608b5513584SShivaprasad G Bhat }
609b5513584SShivaprasad G Bhat }
610b5513584SShivaprasad G Bhat g_slist_free(nvdimms);
611b5513584SShivaprasad G Bhat }
612b5513584SShivaprasad G Bhat
613b5513584SShivaprasad G Bhat /*
614b5513584SShivaprasad G Bhat * spapr_nvdimm_get_flush_status
615b5513584SShivaprasad G Bhat * Fetches the status of the hcall worker and returns
616b5513584SShivaprasad G Bhat * H_LONG_BUSY_ORDER_10_MSEC if the worker is still running.
617b5513584SShivaprasad G Bhat */
spapr_nvdimm_get_flush_status(SpaprNVDIMMDevice * s_nvdimm,uint64_t token)618b5513584SShivaprasad G Bhat static int spapr_nvdimm_get_flush_status(SpaprNVDIMMDevice *s_nvdimm,
619b5513584SShivaprasad G Bhat uint64_t token)
620b5513584SShivaprasad G Bhat {
621b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState *state, *node;
622b5513584SShivaprasad G Bhat
623b5513584SShivaprasad G Bhat QLIST_FOREACH(state, &s_nvdimm->pending_nvdimm_flush_states, node) {
624b5513584SShivaprasad G Bhat if (state->continue_token == token) {
625b5513584SShivaprasad G Bhat return H_LONG_BUSY_ORDER_10_MSEC;
626b5513584SShivaprasad G Bhat }
627b5513584SShivaprasad G Bhat }
628b5513584SShivaprasad G Bhat
629b5513584SShivaprasad G Bhat QLIST_FOREACH_SAFE(state, &s_nvdimm->completed_nvdimm_flush_states,
630b5513584SShivaprasad G Bhat node, node) {
631b5513584SShivaprasad G Bhat if (state->continue_token == token) {
632b5513584SShivaprasad G Bhat int ret = state->hcall_ret;
633b5513584SShivaprasad G Bhat QLIST_REMOVE(state, node);
634b5513584SShivaprasad G Bhat g_free(state);
635b5513584SShivaprasad G Bhat return ret;
636b5513584SShivaprasad G Bhat }
637b5513584SShivaprasad G Bhat }
638b5513584SShivaprasad G Bhat
639b5513584SShivaprasad G Bhat /* If not found in complete list too, invalid token */
640b5513584SShivaprasad G Bhat return H_P2;
641b5513584SShivaprasad G Bhat }
642b5513584SShivaprasad G Bhat
643b5513584SShivaprasad G Bhat /*
644b5513584SShivaprasad G Bhat * H_SCM_FLUSH
645b5513584SShivaprasad G Bhat * Input: drc_index, continue-token
646b5513584SShivaprasad G Bhat * Out: continue-token
647b5513584SShivaprasad G Bhat * Return Value: H_SUCCESS, H_Parameter, H_P2, H_LONG_BUSY_ORDER_10_MSEC,
648b5513584SShivaprasad G Bhat * H_UNSUPPORTED
649b5513584SShivaprasad G Bhat *
650b5513584SShivaprasad G Bhat * Given a DRC Index Flush the data to backend NVDIMM device. The hcall returns
651b5513584SShivaprasad G Bhat * H_LONG_BUSY_ORDER_10_MSEC when the flush takes longer time and the hcall
652b5513584SShivaprasad G Bhat * needs to be issued multiple times in order to be completely serviced. The
653b5513584SShivaprasad G Bhat * continue-token from the output to be passed in the argument list of
654b5513584SShivaprasad G Bhat * subsequent hcalls until the hcall is completely serviced at which point
655b5513584SShivaprasad G Bhat * H_SUCCESS or other error is returned.
656b5513584SShivaprasad G Bhat */
h_scm_flush(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)657b5513584SShivaprasad G Bhat static target_ulong h_scm_flush(PowerPCCPU *cpu, SpaprMachineState *spapr,
658b5513584SShivaprasad G Bhat target_ulong opcode, target_ulong *args)
659b5513584SShivaprasad G Bhat {
660b5513584SShivaprasad G Bhat int ret;
661b5513584SShivaprasad G Bhat uint32_t drc_index = args[0];
662b5513584SShivaprasad G Bhat uint64_t continue_token = args[1];
663b5513584SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(drc_index);
664b5513584SShivaprasad G Bhat PCDIMMDevice *dimm;
665b5513584SShivaprasad G Bhat HostMemoryBackend *backend = NULL;
666b5513584SShivaprasad G Bhat SpaprNVDIMMDeviceFlushState *state;
667b5513584SShivaprasad G Bhat int fd;
668b5513584SShivaprasad G Bhat
669b5513584SShivaprasad G Bhat if (!drc || !drc->dev ||
670b5513584SShivaprasad G Bhat spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
671b5513584SShivaprasad G Bhat return H_PARAMETER;
672b5513584SShivaprasad G Bhat }
673b5513584SShivaprasad G Bhat
674b5513584SShivaprasad G Bhat dimm = PC_DIMM(drc->dev);
6758601b4f1SShivaprasad G Bhat if (!object_dynamic_cast(OBJECT(dimm), TYPE_SPAPR_NVDIMM)) {
6768601b4f1SShivaprasad G Bhat return H_PARAMETER;
6778601b4f1SShivaprasad G Bhat }
678b5513584SShivaprasad G Bhat if (continue_token == 0) {
6798601b4f1SShivaprasad G Bhat bool is_pmem = false, pmem_override = false;
680b5513584SShivaprasad G Bhat backend = MEMORY_BACKEND(dimm->hostmem);
681b5513584SShivaprasad G Bhat fd = memory_region_get_fd(&backend->mr);
682b5513584SShivaprasad G Bhat
683b5513584SShivaprasad G Bhat if (fd < 0) {
684b5513584SShivaprasad G Bhat return H_UNSUPPORTED;
685b5513584SShivaprasad G Bhat }
686b5513584SShivaprasad G Bhat
6878601b4f1SShivaprasad G Bhat is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL);
6888601b4f1SShivaprasad G Bhat pmem_override = object_property_get_bool(OBJECT(dimm),
6898601b4f1SShivaprasad G Bhat "pmem-override", NULL);
6908601b4f1SShivaprasad G Bhat if (is_pmem && !pmem_override) {
6918601b4f1SShivaprasad G Bhat return H_UNSUPPORTED;
6928601b4f1SShivaprasad G Bhat }
6938601b4f1SShivaprasad G Bhat
694b5513584SShivaprasad G Bhat state = spapr_nvdimm_init_new_flush_state(SPAPR_NVDIMM(dimm));
695b5513584SShivaprasad G Bhat if (!state) {
696b5513584SShivaprasad G Bhat return H_HARDWARE;
697b5513584SShivaprasad G Bhat }
698b5513584SShivaprasad G Bhat
699b5513584SShivaprasad G Bhat state->drcidx = drc_index;
700b5513584SShivaprasad G Bhat
701aef04fc7SEmanuele Giuseppe Esposito thread_pool_submit_aio(flush_worker_cb, state,
702b5513584SShivaprasad G Bhat spapr_nvdimm_flush_completion_cb, state);
703b5513584SShivaprasad G Bhat
704b5513584SShivaprasad G Bhat continue_token = state->continue_token;
705b5513584SShivaprasad G Bhat }
706b5513584SShivaprasad G Bhat
707b5513584SShivaprasad G Bhat ret = spapr_nvdimm_get_flush_status(SPAPR_NVDIMM(dimm), continue_token);
708b5513584SShivaprasad G Bhat if (H_IS_LONG_BUSY(ret)) {
709b5513584SShivaprasad G Bhat args[0] = continue_token;
710b5513584SShivaprasad G Bhat }
711b5513584SShivaprasad G Bhat
712b5513584SShivaprasad G Bhat return ret;
713b5513584SShivaprasad G Bhat }
714b5513584SShivaprasad G Bhat
h_scm_unbind_mem(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)715b5fca656SShivaprasad G Bhat static target_ulong h_scm_unbind_mem(PowerPCCPU *cpu, SpaprMachineState *spapr,
716b5fca656SShivaprasad G Bhat target_ulong opcode, target_ulong *args)
717b5fca656SShivaprasad G Bhat {
718b5fca656SShivaprasad G Bhat uint32_t drc_index = args[0];
719b5fca656SShivaprasad G Bhat uint64_t starting_scm_logical_addr = args[1];
720b5fca656SShivaprasad G Bhat uint64_t no_of_scm_blocks_to_unbind = args[2];
721b5fca656SShivaprasad G Bhat uint64_t continue_token = args[3];
722b5fca656SShivaprasad G Bhat uint64_t size_to_unbind;
723b5fca656SShivaprasad G Bhat Range blockrange = range_empty;
724b5fca656SShivaprasad G Bhat Range nvdimmrange = range_empty;
725b5fca656SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(drc_index);
726b5fca656SShivaprasad G Bhat NVDIMMDevice *nvdimm;
727b5fca656SShivaprasad G Bhat uint64_t size, addr;
728b5fca656SShivaprasad G Bhat
729b5fca656SShivaprasad G Bhat if (!drc || !drc->dev ||
730b5fca656SShivaprasad G Bhat spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
731b5fca656SShivaprasad G Bhat return H_PARAMETER;
732b5fca656SShivaprasad G Bhat }
733b5fca656SShivaprasad G Bhat
734b5fca656SShivaprasad G Bhat /* continue_token should be zero as this hcall doesn't return H_BUSY. */
735b5fca656SShivaprasad G Bhat if (continue_token > 0) {
736b5fca656SShivaprasad G Bhat return H_P4;
737b5fca656SShivaprasad G Bhat }
738b5fca656SShivaprasad G Bhat
739b5fca656SShivaprasad G Bhat /* Check if starting_scm_logical_addr is block aligned */
740b5fca656SShivaprasad G Bhat if (!QEMU_IS_ALIGNED(starting_scm_logical_addr,
741b5fca656SShivaprasad G Bhat SPAPR_MINIMUM_SCM_BLOCK_SIZE)) {
742b5fca656SShivaprasad G Bhat return H_P2;
743b5fca656SShivaprasad G Bhat }
744b5fca656SShivaprasad G Bhat
745b5fca656SShivaprasad G Bhat size_to_unbind = no_of_scm_blocks_to_unbind * SPAPR_MINIMUM_SCM_BLOCK_SIZE;
746b5fca656SShivaprasad G Bhat if (no_of_scm_blocks_to_unbind == 0 || no_of_scm_blocks_to_unbind !=
747b5fca656SShivaprasad G Bhat size_to_unbind / SPAPR_MINIMUM_SCM_BLOCK_SIZE) {
748b5fca656SShivaprasad G Bhat return H_P3;
749b5fca656SShivaprasad G Bhat }
750b5fca656SShivaprasad G Bhat
751b5fca656SShivaprasad G Bhat nvdimm = NVDIMM(drc->dev);
752b5fca656SShivaprasad G Bhat size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
753b5fca656SShivaprasad G Bhat &error_abort);
754b5fca656SShivaprasad G Bhat addr = object_property_get_int(OBJECT(nvdimm), PC_DIMM_ADDR_PROP,
755b5fca656SShivaprasad G Bhat &error_abort);
756b5fca656SShivaprasad G Bhat
757b5fca656SShivaprasad G Bhat range_init_nofail(&nvdimmrange, addr, size);
758b5fca656SShivaprasad G Bhat range_init_nofail(&blockrange, starting_scm_logical_addr, size_to_unbind);
759b5fca656SShivaprasad G Bhat
760b5fca656SShivaprasad G Bhat if (!range_contains_range(&nvdimmrange, &blockrange)) {
761b5fca656SShivaprasad G Bhat return H_P3;
762b5fca656SShivaprasad G Bhat }
763b5fca656SShivaprasad G Bhat
764b5fca656SShivaprasad G Bhat args[1] = no_of_scm_blocks_to_unbind;
765b5fca656SShivaprasad G Bhat
766b5fca656SShivaprasad G Bhat /* let unplug take care of actual unbind */
767b5fca656SShivaprasad G Bhat return H_SUCCESS;
768b5fca656SShivaprasad G Bhat }
769b5fca656SShivaprasad G Bhat
770b5fca656SShivaprasad G Bhat #define H_UNBIND_SCOPE_ALL 0x1
771b5fca656SShivaprasad G Bhat #define H_UNBIND_SCOPE_DRC 0x2
772b5fca656SShivaprasad G Bhat
h_scm_unbind_all(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)773b5fca656SShivaprasad G Bhat static target_ulong h_scm_unbind_all(PowerPCCPU *cpu, SpaprMachineState *spapr,
774b5fca656SShivaprasad G Bhat target_ulong opcode, target_ulong *args)
775b5fca656SShivaprasad G Bhat {
776b5fca656SShivaprasad G Bhat uint64_t target_scope = args[0];
777b5fca656SShivaprasad G Bhat uint32_t drc_index = args[1];
778b5fca656SShivaprasad G Bhat uint64_t continue_token = args[2];
779b5fca656SShivaprasad G Bhat NVDIMMDevice *nvdimm;
780b5fca656SShivaprasad G Bhat uint64_t size;
781b5fca656SShivaprasad G Bhat uint64_t no_of_scm_blocks_unbound = 0;
782b5fca656SShivaprasad G Bhat
783b5fca656SShivaprasad G Bhat /* continue_token should be zero as this hcall doesn't return H_BUSY. */
784b5fca656SShivaprasad G Bhat if (continue_token > 0) {
785b5fca656SShivaprasad G Bhat return H_P4;
786b5fca656SShivaprasad G Bhat }
787b5fca656SShivaprasad G Bhat
788b5fca656SShivaprasad G Bhat if (target_scope == H_UNBIND_SCOPE_DRC) {
789b5fca656SShivaprasad G Bhat SpaprDrc *drc = spapr_drc_by_index(drc_index);
790b5fca656SShivaprasad G Bhat
791b5fca656SShivaprasad G Bhat if (!drc || !drc->dev ||
792b5fca656SShivaprasad G Bhat spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
793b5fca656SShivaprasad G Bhat return H_P2;
794b5fca656SShivaprasad G Bhat }
795b5fca656SShivaprasad G Bhat
796b5fca656SShivaprasad G Bhat nvdimm = NVDIMM(drc->dev);
797b5fca656SShivaprasad G Bhat size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
798b5fca656SShivaprasad G Bhat &error_abort);
799b5fca656SShivaprasad G Bhat
800b5fca656SShivaprasad G Bhat no_of_scm_blocks_unbound = size / SPAPR_MINIMUM_SCM_BLOCK_SIZE;
801b5fca656SShivaprasad G Bhat } else if (target_scope == H_UNBIND_SCOPE_ALL) {
802b5fca656SShivaprasad G Bhat GSList *list, *nvdimms;
803b5fca656SShivaprasad G Bhat
804b5fca656SShivaprasad G Bhat nvdimms = nvdimm_get_device_list();
805b5fca656SShivaprasad G Bhat for (list = nvdimms; list; list = list->next) {
806b5fca656SShivaprasad G Bhat nvdimm = list->data;
807b5fca656SShivaprasad G Bhat size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
808b5fca656SShivaprasad G Bhat &error_abort);
809b5fca656SShivaprasad G Bhat
810b5fca656SShivaprasad G Bhat no_of_scm_blocks_unbound += size / SPAPR_MINIMUM_SCM_BLOCK_SIZE;
811b5fca656SShivaprasad G Bhat }
812b5fca656SShivaprasad G Bhat g_slist_free(nvdimms);
813b5fca656SShivaprasad G Bhat } else {
814b5fca656SShivaprasad G Bhat return H_PARAMETER;
815b5fca656SShivaprasad G Bhat }
816b5fca656SShivaprasad G Bhat
817b5fca656SShivaprasad G Bhat args[1] = no_of_scm_blocks_unbound;
818b5fca656SShivaprasad G Bhat
819b5fca656SShivaprasad G Bhat /* let unplug take care of actual unbind */
820b5fca656SShivaprasad G Bhat return H_SUCCESS;
821b5fca656SShivaprasad G Bhat }
822b5fca656SShivaprasad G Bhat
h_scm_health(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)82353d7d7e2SVaibhav Jain static target_ulong h_scm_health(PowerPCCPU *cpu, SpaprMachineState *spapr,
82453d7d7e2SVaibhav Jain target_ulong opcode, target_ulong *args)
82553d7d7e2SVaibhav Jain {
82653d7d7e2SVaibhav Jain
82753d7d7e2SVaibhav Jain NVDIMMDevice *nvdimm;
82853d7d7e2SVaibhav Jain uint64_t hbitmap = 0;
82953d7d7e2SVaibhav Jain uint32_t drc_index = args[0];
83053d7d7e2SVaibhav Jain SpaprDrc *drc = spapr_drc_by_index(drc_index);
83153d7d7e2SVaibhav Jain const uint64_t hbitmap_mask = PAPR_PMEM_UNARMED;
83253d7d7e2SVaibhav Jain
83353d7d7e2SVaibhav Jain
83453d7d7e2SVaibhav Jain /* Ensure that the drc is valid & is valid PMEM dimm and is plugged in */
83553d7d7e2SVaibhav Jain if (!drc || !drc->dev ||
83653d7d7e2SVaibhav Jain spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
83753d7d7e2SVaibhav Jain return H_PARAMETER;
83853d7d7e2SVaibhav Jain }
83953d7d7e2SVaibhav Jain
84053d7d7e2SVaibhav Jain nvdimm = NVDIMM(drc->dev);
84153d7d7e2SVaibhav Jain
84253d7d7e2SVaibhav Jain /* Update if the nvdimm is unarmed and send its status via health bitmaps */
84353d7d7e2SVaibhav Jain if (object_property_get_bool(OBJECT(nvdimm), NVDIMM_UNARMED_PROP, NULL)) {
84453d7d7e2SVaibhav Jain hbitmap |= PAPR_PMEM_UNARMED;
84553d7d7e2SVaibhav Jain }
84653d7d7e2SVaibhav Jain
84753d7d7e2SVaibhav Jain /* Update the out args with health bitmap/mask */
84853d7d7e2SVaibhav Jain args[0] = hbitmap;
84953d7d7e2SVaibhav Jain args[1] = hbitmap_mask;
85053d7d7e2SVaibhav Jain
85153d7d7e2SVaibhav Jain return H_SUCCESS;
85253d7d7e2SVaibhav Jain }
85353d7d7e2SVaibhav Jain
spapr_scm_register_types(void)854b5fca656SShivaprasad G Bhat static void spapr_scm_register_types(void)
855b5fca656SShivaprasad G Bhat {
856b5fca656SShivaprasad G Bhat /* qemu/scm specific hcalls */
857b5fca656SShivaprasad G Bhat spapr_register_hypercall(H_SCM_READ_METADATA, h_scm_read_metadata);
858b5fca656SShivaprasad G Bhat spapr_register_hypercall(H_SCM_WRITE_METADATA, h_scm_write_metadata);
859b5fca656SShivaprasad G Bhat spapr_register_hypercall(H_SCM_BIND_MEM, h_scm_bind_mem);
860b5fca656SShivaprasad G Bhat spapr_register_hypercall(H_SCM_UNBIND_MEM, h_scm_unbind_mem);
861b5fca656SShivaprasad G Bhat spapr_register_hypercall(H_SCM_UNBIND_ALL, h_scm_unbind_all);
86253d7d7e2SVaibhav Jain spapr_register_hypercall(H_SCM_HEALTH, h_scm_health);
863b5513584SShivaprasad G Bhat spapr_register_hypercall(H_SCM_FLUSH, h_scm_flush);
864b5fca656SShivaprasad G Bhat }
865b5fca656SShivaprasad G Bhat
type_init(spapr_scm_register_types)866b5fca656SShivaprasad G Bhat type_init(spapr_scm_register_types)
8678601b4f1SShivaprasad G Bhat
8688601b4f1SShivaprasad G Bhat static void spapr_nvdimm_realize(NVDIMMDevice *dimm, Error **errp)
8698601b4f1SShivaprasad G Bhat {
8708601b4f1SShivaprasad G Bhat SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(dimm);
8718601b4f1SShivaprasad G Bhat HostMemoryBackend *backend = MEMORY_BACKEND(PC_DIMM(dimm)->hostmem);
8728601b4f1SShivaprasad G Bhat bool is_pmem = object_property_get_bool(OBJECT(backend), "pmem", NULL);
8738601b4f1SShivaprasad G Bhat bool pmem_override = object_property_get_bool(OBJECT(dimm), "pmem-override",
8748601b4f1SShivaprasad G Bhat NULL);
8758601b4f1SShivaprasad G Bhat if (!is_pmem || pmem_override) {
8768601b4f1SShivaprasad G Bhat s_nvdimm->hcall_flush_required = true;
8778601b4f1SShivaprasad G Bhat }
8788601b4f1SShivaprasad G Bhat
879*99b16e8eSJuan Quintela vmstate_register_any(NULL, &vmstate_spapr_nvdimm_states, dimm);
8808601b4f1SShivaprasad G Bhat }
8818601b4f1SShivaprasad G Bhat
spapr_nvdimm_unrealize(NVDIMMDevice * dimm)8828601b4f1SShivaprasad G Bhat static void spapr_nvdimm_unrealize(NVDIMMDevice *dimm)
8838601b4f1SShivaprasad G Bhat {
8848601b4f1SShivaprasad G Bhat vmstate_unregister(NULL, &vmstate_spapr_nvdimm_states, dimm);
8858601b4f1SShivaprasad G Bhat }
8868601b4f1SShivaprasad G Bhat
8878601b4f1SShivaprasad G Bhat static Property spapr_nvdimm_properties[] = {
8888601b4f1SShivaprasad G Bhat #ifdef CONFIG_LIBPMEM
8898601b4f1SShivaprasad G Bhat DEFINE_PROP_BOOL("pmem-override", SpaprNVDIMMDevice, pmem_override, false),
8908601b4f1SShivaprasad G Bhat #endif
8918601b4f1SShivaprasad G Bhat DEFINE_PROP_END_OF_LIST(),
8928601b4f1SShivaprasad G Bhat };
8938601b4f1SShivaprasad G Bhat
spapr_nvdimm_class_init(ObjectClass * oc,void * data)8948601b4f1SShivaprasad G Bhat static void spapr_nvdimm_class_init(ObjectClass *oc, void *data)
8958601b4f1SShivaprasad G Bhat {
8968601b4f1SShivaprasad G Bhat DeviceClass *dc = DEVICE_CLASS(oc);
8978601b4f1SShivaprasad G Bhat NVDIMMClass *nvc = NVDIMM_CLASS(oc);
8988601b4f1SShivaprasad G Bhat
8998601b4f1SShivaprasad G Bhat nvc->realize = spapr_nvdimm_realize;
9008601b4f1SShivaprasad G Bhat nvc->unrealize = spapr_nvdimm_unrealize;
9018601b4f1SShivaprasad G Bhat
9028601b4f1SShivaprasad G Bhat device_class_set_props(dc, spapr_nvdimm_properties);
9038601b4f1SShivaprasad G Bhat }
9048601b4f1SShivaprasad G Bhat
spapr_nvdimm_init(Object * obj)9058601b4f1SShivaprasad G Bhat static void spapr_nvdimm_init(Object *obj)
9068601b4f1SShivaprasad G Bhat {
9078601b4f1SShivaprasad G Bhat SpaprNVDIMMDevice *s_nvdimm = SPAPR_NVDIMM(obj);
9088601b4f1SShivaprasad G Bhat
9098601b4f1SShivaprasad G Bhat s_nvdimm->hcall_flush_required = false;
9108601b4f1SShivaprasad G Bhat QLIST_INIT(&s_nvdimm->pending_nvdimm_flush_states);
9118601b4f1SShivaprasad G Bhat QLIST_INIT(&s_nvdimm->completed_nvdimm_flush_states);
9128601b4f1SShivaprasad G Bhat }
9138601b4f1SShivaprasad G Bhat
9148601b4f1SShivaprasad G Bhat static TypeInfo spapr_nvdimm_info = {
9158601b4f1SShivaprasad G Bhat .name = TYPE_SPAPR_NVDIMM,
9168601b4f1SShivaprasad G Bhat .parent = TYPE_NVDIMM,
9178601b4f1SShivaprasad G Bhat .class_init = spapr_nvdimm_class_init,
9188601b4f1SShivaprasad G Bhat .class_size = sizeof(SPAPRNVDIMMClass),
9198601b4f1SShivaprasad G Bhat .instance_size = sizeof(SpaprNVDIMMDevice),
9208601b4f1SShivaprasad G Bhat .instance_init = spapr_nvdimm_init,
9218601b4f1SShivaprasad G Bhat };
9228601b4f1SShivaprasad G Bhat
spapr_nvdimm_register_types(void)9238601b4f1SShivaprasad G Bhat static void spapr_nvdimm_register_types(void)
9248601b4f1SShivaprasad G Bhat {
9258601b4f1SShivaprasad G Bhat type_register_static(&spapr_nvdimm_info);
9268601b4f1SShivaprasad G Bhat }
9278601b4f1SShivaprasad G Bhat
9288601b4f1SShivaprasad G Bhat type_init(spapr_nvdimm_register_types)
929