xref: /openbmc/qemu/hw/ppc/spapr_nvdimm.c (revision 99b16e8e)
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