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