xref: /openbmc/qemu/hw/ppc/spapr_nvdimm.c (revision 64547a3b)
1 /*
2  * QEMU PAPR Storage Class Memory Interfaces
3  *
4  * Copyright (c) 2019-2020, IBM Corporation.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "qemu/osdep.h"
25 #include "qapi/error.h"
26 #include "hw/ppc/spapr_drc.h"
27 #include "hw/ppc/spapr_nvdimm.h"
28 #include "hw/mem/nvdimm.h"
29 #include "qemu/nvdimm-utils.h"
30 #include "hw/ppc/fdt.h"
31 #include "qemu/range.h"
32 
33 void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size,
34                                 Error **errp)
35 {
36     char *uuidstr = NULL;
37     QemuUUID uuid;
38     int ret;
39 
40     if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) {
41         error_setg(errp, "NVDIMM memory size excluding the label area"
42                    " must be a multiple of %" PRIu64 "MB",
43                    SPAPR_MINIMUM_SCM_BLOCK_SIZE / MiB);
44         return;
45     }
46 
47     uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP,
48                                       &error_abort);
49     ret = qemu_uuid_parse(uuidstr, &uuid);
50     g_assert(!ret);
51     g_free(uuidstr);
52 
53     if (qemu_uuid_is_null(&uuid)) {
54         error_setg(errp, "NVDIMM device requires the uuid to be set");
55         return;
56     }
57 }
58 
59 
60 void spapr_add_nvdimm(DeviceState *dev, uint64_t slot, Error **errp)
61 {
62     SpaprDrc *drc;
63     bool hotplugged = spapr_drc_hotplugged(dev);
64     Error *local_err = NULL;
65 
66     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PMEM, slot);
67     g_assert(drc);
68 
69     spapr_drc_attach(drc, dev, &local_err);
70     if (local_err) {
71         error_propagate(errp, local_err);
72         return;
73     }
74 
75     if (hotplugged) {
76         spapr_hotplug_req_add_by_index(drc);
77     }
78 }
79 
80 int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr,
81                            void *fdt, int *fdt_start_offset, Error **errp)
82 {
83     NVDIMMDevice *nvdimm = NVDIMM(drc->dev);
84 
85     *fdt_start_offset = spapr_dt_nvdimm(fdt, 0, nvdimm);
86 
87     return 0;
88 }
89 
90 void spapr_create_nvdimm_dr_connectors(SpaprMachineState *spapr)
91 {
92     MachineState *machine = MACHINE(spapr);
93     int i;
94 
95     for (i = 0; i < machine->ram_slots; i++) {
96         spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_PMEM, i);
97     }
98 }
99 
100 
101 int spapr_dt_nvdimm(void *fdt, int parent_offset,
102                            NVDIMMDevice *nvdimm)
103 {
104     int child_offset;
105     char *buf;
106     SpaprDrc *drc;
107     uint32_t drc_idx;
108     uint32_t node = object_property_get_uint(OBJECT(nvdimm), PC_DIMM_NODE_PROP,
109                                              &error_abort);
110     uint64_t slot = object_property_get_uint(OBJECT(nvdimm), PC_DIMM_SLOT_PROP,
111                                              &error_abort);
112     uint32_t associativity[] = {
113         cpu_to_be32(0x4), /* length */
114         cpu_to_be32(0x0), cpu_to_be32(0x0),
115         cpu_to_be32(0x0), cpu_to_be32(node)
116     };
117     uint64_t lsize = nvdimm->label_size;
118     uint64_t size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
119                                             NULL);
120 
121     drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PMEM, slot);
122     g_assert(drc);
123 
124     drc_idx = spapr_drc_index(drc);
125 
126     buf = g_strdup_printf("ibm,pmemory@%x", drc_idx);
127     child_offset = fdt_add_subnode(fdt, parent_offset, buf);
128     g_free(buf);
129 
130     _FDT(child_offset);
131 
132     _FDT((fdt_setprop_cell(fdt, child_offset, "reg", drc_idx)));
133     _FDT((fdt_setprop_string(fdt, child_offset, "compatible", "ibm,pmemory")));
134     _FDT((fdt_setprop_string(fdt, child_offset, "device_type", "ibm,pmemory")));
135 
136     _FDT((fdt_setprop(fdt, child_offset, "ibm,associativity", associativity,
137                       sizeof(associativity))));
138 
139     buf = qemu_uuid_unparse_strdup(&nvdimm->uuid);
140     _FDT((fdt_setprop_string(fdt, child_offset, "ibm,unit-guid", buf)));
141     g_free(buf);
142 
143     _FDT((fdt_setprop_cell(fdt, child_offset, "ibm,my-drc-index", drc_idx)));
144 
145     _FDT((fdt_setprop_u64(fdt, child_offset, "ibm,block-size",
146                           SPAPR_MINIMUM_SCM_BLOCK_SIZE)));
147     _FDT((fdt_setprop_u64(fdt, child_offset, "ibm,number-of-blocks",
148                           size / SPAPR_MINIMUM_SCM_BLOCK_SIZE)));
149     _FDT((fdt_setprop_cell(fdt, child_offset, "ibm,metadata-size", lsize)));
150 
151     _FDT((fdt_setprop_string(fdt, child_offset, "ibm,pmem-application",
152                              "operating-system")));
153     _FDT(fdt_setprop(fdt, child_offset, "ibm,cache-flush-required", NULL, 0));
154 
155     return child_offset;
156 }
157 
158 void spapr_dt_persistent_memory(void *fdt)
159 {
160     int offset = fdt_subnode_offset(fdt, 0, "persistent-memory");
161     GSList *iter, *nvdimms = nvdimm_get_device_list();
162 
163     if (offset < 0) {
164         offset = fdt_add_subnode(fdt, 0, "persistent-memory");
165         _FDT(offset);
166         _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1)));
167         _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0)));
168         _FDT((fdt_setprop_string(fdt, offset, "device_type",
169                                  "ibm,persistent-memory")));
170     }
171 
172     /* Create DT entries for cold plugged NVDIMM devices */
173     for (iter = nvdimms; iter; iter = iter->next) {
174         NVDIMMDevice *nvdimm = iter->data;
175 
176         spapr_dt_nvdimm(fdt, offset, nvdimm);
177     }
178     g_slist_free(nvdimms);
179 
180     return;
181 }
182 
183 static target_ulong h_scm_read_metadata(PowerPCCPU *cpu,
184                                         SpaprMachineState *spapr,
185                                         target_ulong opcode,
186                                         target_ulong *args)
187 {
188     uint32_t drc_index = args[0];
189     uint64_t offset = args[1];
190     uint64_t len = args[2];
191     SpaprDrc *drc = spapr_drc_by_index(drc_index);
192     NVDIMMDevice *nvdimm;
193     NVDIMMClass *ddc;
194     uint64_t data = 0;
195     uint8_t buf[8] = { 0 };
196 
197     if (!drc || !drc->dev ||
198         spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
199         return H_PARAMETER;
200     }
201 
202     if (len != 1 && len != 2 &&
203         len != 4 && len != 8) {
204         return H_P3;
205     }
206 
207     nvdimm = NVDIMM(drc->dev);
208     if ((offset + len < offset) ||
209         (nvdimm->label_size < len + offset)) {
210         return H_P2;
211     }
212 
213     ddc = NVDIMM_GET_CLASS(nvdimm);
214     ddc->read_label_data(nvdimm, buf, len, offset);
215 
216     switch (len) {
217     case 1:
218         data = ldub_p(buf);
219         break;
220     case 2:
221         data = lduw_be_p(buf);
222         break;
223     case 4:
224         data = ldl_be_p(buf);
225         break;
226     case 8:
227         data = ldq_be_p(buf);
228         break;
229     default:
230         g_assert_not_reached();
231     }
232 
233     args[0] = data;
234 
235     return H_SUCCESS;
236 }
237 
238 static target_ulong h_scm_write_metadata(PowerPCCPU *cpu,
239                                          SpaprMachineState *spapr,
240                                          target_ulong opcode,
241                                          target_ulong *args)
242 {
243     uint32_t drc_index = args[0];
244     uint64_t offset = args[1];
245     uint64_t data = args[2];
246     uint64_t len = args[3];
247     SpaprDrc *drc = spapr_drc_by_index(drc_index);
248     NVDIMMDevice *nvdimm;
249     NVDIMMClass *ddc;
250     uint8_t buf[8] = { 0 };
251 
252     if (!drc || !drc->dev ||
253         spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
254         return H_PARAMETER;
255     }
256 
257     if (len != 1 && len != 2 &&
258         len != 4 && len != 8) {
259         return H_P4;
260     }
261 
262     nvdimm = NVDIMM(drc->dev);
263     if ((offset + len < offset) ||
264         (nvdimm->label_size < len + offset)) {
265         return H_P2;
266     }
267 
268     switch (len) {
269     case 1:
270         if (data & 0xffffffffffffff00) {
271             return H_P2;
272         }
273         stb_p(buf, data);
274         break;
275     case 2:
276         if (data & 0xffffffffffff0000) {
277             return H_P2;
278         }
279         stw_be_p(buf, data);
280         break;
281     case 4:
282         if (data & 0xffffffff00000000) {
283             return H_P2;
284         }
285         stl_be_p(buf, data);
286         break;
287     case 8:
288         stq_be_p(buf, data);
289         break;
290     default:
291             g_assert_not_reached();
292     }
293 
294     ddc = NVDIMM_GET_CLASS(nvdimm);
295     ddc->write_label_data(nvdimm, buf, len, offset);
296 
297     return H_SUCCESS;
298 }
299 
300 static target_ulong h_scm_bind_mem(PowerPCCPU *cpu, SpaprMachineState *spapr,
301                                    target_ulong opcode, target_ulong *args)
302 {
303     uint32_t drc_index = args[0];
304     uint64_t starting_idx = args[1];
305     uint64_t no_of_scm_blocks_to_bind = args[2];
306     uint64_t target_logical_mem_addr = args[3];
307     uint64_t continue_token = args[4];
308     uint64_t size;
309     uint64_t total_no_of_scm_blocks;
310     SpaprDrc *drc = spapr_drc_by_index(drc_index);
311     hwaddr addr;
312     NVDIMMDevice *nvdimm;
313 
314     if (!drc || !drc->dev ||
315         spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
316         return H_PARAMETER;
317     }
318 
319     /*
320      * Currently continue token should be zero qemu has already bound
321      * everything and this hcall doesnt return H_BUSY.
322      */
323     if (continue_token > 0) {
324         return H_P5;
325     }
326 
327     /* Currently qemu assigns the address. */
328     if (target_logical_mem_addr != 0xffffffffffffffff) {
329         return H_OVERLAP;
330     }
331 
332     nvdimm = NVDIMM(drc->dev);
333 
334     size = object_property_get_uint(OBJECT(nvdimm),
335                                     PC_DIMM_SIZE_PROP, &error_abort);
336 
337     total_no_of_scm_blocks = size / SPAPR_MINIMUM_SCM_BLOCK_SIZE;
338 
339     if (starting_idx > total_no_of_scm_blocks) {
340         return H_P2;
341     }
342 
343     if (((starting_idx + no_of_scm_blocks_to_bind) < starting_idx) ||
344         ((starting_idx + no_of_scm_blocks_to_bind) > total_no_of_scm_blocks)) {
345         return H_P3;
346     }
347 
348     addr = object_property_get_uint(OBJECT(nvdimm),
349                                     PC_DIMM_ADDR_PROP, &error_abort);
350 
351     addr += starting_idx * SPAPR_MINIMUM_SCM_BLOCK_SIZE;
352 
353     /* Already bound, Return target logical address in R5 */
354     args[1] = addr;
355     args[2] = no_of_scm_blocks_to_bind;
356 
357     return H_SUCCESS;
358 }
359 
360 static target_ulong h_scm_unbind_mem(PowerPCCPU *cpu, SpaprMachineState *spapr,
361                                      target_ulong opcode, target_ulong *args)
362 {
363     uint32_t drc_index = args[0];
364     uint64_t starting_scm_logical_addr = args[1];
365     uint64_t no_of_scm_blocks_to_unbind = args[2];
366     uint64_t continue_token = args[3];
367     uint64_t size_to_unbind;
368     Range blockrange = range_empty;
369     Range nvdimmrange = range_empty;
370     SpaprDrc *drc = spapr_drc_by_index(drc_index);
371     NVDIMMDevice *nvdimm;
372     uint64_t size, addr;
373 
374     if (!drc || !drc->dev ||
375         spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
376         return H_PARAMETER;
377     }
378 
379     /* continue_token should be zero as this hcall doesn't return H_BUSY. */
380     if (continue_token > 0) {
381         return H_P4;
382     }
383 
384     /* Check if starting_scm_logical_addr is block aligned */
385     if (!QEMU_IS_ALIGNED(starting_scm_logical_addr,
386                          SPAPR_MINIMUM_SCM_BLOCK_SIZE)) {
387         return H_P2;
388     }
389 
390     size_to_unbind = no_of_scm_blocks_to_unbind * SPAPR_MINIMUM_SCM_BLOCK_SIZE;
391     if (no_of_scm_blocks_to_unbind == 0 || no_of_scm_blocks_to_unbind !=
392                                size_to_unbind / SPAPR_MINIMUM_SCM_BLOCK_SIZE) {
393         return H_P3;
394     }
395 
396     nvdimm = NVDIMM(drc->dev);
397     size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
398                                    &error_abort);
399     addr = object_property_get_int(OBJECT(nvdimm), PC_DIMM_ADDR_PROP,
400                                    &error_abort);
401 
402     range_init_nofail(&nvdimmrange, addr, size);
403     range_init_nofail(&blockrange, starting_scm_logical_addr, size_to_unbind);
404 
405     if (!range_contains_range(&nvdimmrange, &blockrange)) {
406         return H_P3;
407     }
408 
409     args[1] = no_of_scm_blocks_to_unbind;
410 
411     /* let unplug take care of actual unbind */
412     return H_SUCCESS;
413 }
414 
415 #define H_UNBIND_SCOPE_ALL 0x1
416 #define H_UNBIND_SCOPE_DRC 0x2
417 
418 static target_ulong h_scm_unbind_all(PowerPCCPU *cpu, SpaprMachineState *spapr,
419                                      target_ulong opcode, target_ulong *args)
420 {
421     uint64_t target_scope = args[0];
422     uint32_t drc_index = args[1];
423     uint64_t continue_token = args[2];
424     NVDIMMDevice *nvdimm;
425     uint64_t size;
426     uint64_t no_of_scm_blocks_unbound = 0;
427 
428     /* continue_token should be zero as this hcall doesn't return H_BUSY. */
429     if (continue_token > 0) {
430         return H_P4;
431     }
432 
433     if (target_scope == H_UNBIND_SCOPE_DRC) {
434         SpaprDrc *drc = spapr_drc_by_index(drc_index);
435 
436         if (!drc || !drc->dev ||
437             spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) {
438             return H_P2;
439         }
440 
441         nvdimm = NVDIMM(drc->dev);
442         size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
443                                        &error_abort);
444 
445         no_of_scm_blocks_unbound = size / SPAPR_MINIMUM_SCM_BLOCK_SIZE;
446     } else if (target_scope ==  H_UNBIND_SCOPE_ALL) {
447         GSList *list, *nvdimms;
448 
449         nvdimms = nvdimm_get_device_list();
450         for (list = nvdimms; list; list = list->next) {
451             nvdimm = list->data;
452             size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP,
453                                            &error_abort);
454 
455             no_of_scm_blocks_unbound += size / SPAPR_MINIMUM_SCM_BLOCK_SIZE;
456         }
457         g_slist_free(nvdimms);
458     } else {
459         return H_PARAMETER;
460     }
461 
462     args[1] = no_of_scm_blocks_unbound;
463 
464     /* let unplug take care of actual unbind */
465     return H_SUCCESS;
466 }
467 
468 static void spapr_scm_register_types(void)
469 {
470     /* qemu/scm specific hcalls */
471     spapr_register_hypercall(H_SCM_READ_METADATA, h_scm_read_metadata);
472     spapr_register_hypercall(H_SCM_WRITE_METADATA, h_scm_write_metadata);
473     spapr_register_hypercall(H_SCM_BIND_MEM, h_scm_bind_mem);
474     spapr_register_hypercall(H_SCM_UNBIND_MEM, h_scm_unbind_mem);
475     spapr_register_hypercall(H_SCM_UNBIND_ALL, h_scm_unbind_all);
476 }
477 
478 type_init(spapr_scm_register_types)
479