1*ee3a71e3SShivaprasad G Bhat /* 2*ee3a71e3SShivaprasad G Bhat * QEMU PAPR Storage Class Memory Interfaces 3*ee3a71e3SShivaprasad G Bhat * 4*ee3a71e3SShivaprasad G Bhat * Copyright (c) 2019-2020, IBM Corporation. 5*ee3a71e3SShivaprasad G Bhat * 6*ee3a71e3SShivaprasad G Bhat * Permission is hereby granted, free of charge, to any person obtaining a copy 7*ee3a71e3SShivaprasad G Bhat * of this software and associated documentation files (the "Software"), to deal 8*ee3a71e3SShivaprasad G Bhat * in the Software without restriction, including without limitation the rights 9*ee3a71e3SShivaprasad G Bhat * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10*ee3a71e3SShivaprasad G Bhat * copies of the Software, and to permit persons to whom the Software is 11*ee3a71e3SShivaprasad G Bhat * furnished to do so, subject to the following conditions: 12*ee3a71e3SShivaprasad G Bhat * 13*ee3a71e3SShivaprasad G Bhat * The above copyright notice and this permission notice shall be included in 14*ee3a71e3SShivaprasad G Bhat * all copies or substantial portions of the Software. 15*ee3a71e3SShivaprasad G Bhat * 16*ee3a71e3SShivaprasad G Bhat * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17*ee3a71e3SShivaprasad G Bhat * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18*ee3a71e3SShivaprasad G Bhat * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19*ee3a71e3SShivaprasad G Bhat * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20*ee3a71e3SShivaprasad G Bhat * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21*ee3a71e3SShivaprasad G Bhat * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22*ee3a71e3SShivaprasad G Bhat * THE SOFTWARE. 23*ee3a71e3SShivaprasad G Bhat */ 24*ee3a71e3SShivaprasad G Bhat #include "qemu/osdep.h" 25*ee3a71e3SShivaprasad G Bhat #include "qapi/error.h" 26*ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_drc.h" 27*ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h" 28*ee3a71e3SShivaprasad G Bhat #include "hw/mem/nvdimm.h" 29*ee3a71e3SShivaprasad G Bhat #include "qemu/nvdimm-utils.h" 30*ee3a71e3SShivaprasad G Bhat #include "hw/ppc/fdt.h" 31*ee3a71e3SShivaprasad G Bhat 32*ee3a71e3SShivaprasad G Bhat void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size, 33*ee3a71e3SShivaprasad G Bhat Error **errp) 34*ee3a71e3SShivaprasad G Bhat { 35*ee3a71e3SShivaprasad G Bhat char *uuidstr = NULL; 36*ee3a71e3SShivaprasad G Bhat QemuUUID uuid; 37*ee3a71e3SShivaprasad G Bhat 38*ee3a71e3SShivaprasad G Bhat if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) { 39*ee3a71e3SShivaprasad G Bhat error_setg(errp, "NVDIMM memory size excluding the label area" 40*ee3a71e3SShivaprasad G Bhat " must be a multiple of %" PRIu64 "MB", 41*ee3a71e3SShivaprasad G Bhat SPAPR_MINIMUM_SCM_BLOCK_SIZE / MiB); 42*ee3a71e3SShivaprasad G Bhat return; 43*ee3a71e3SShivaprasad G Bhat } 44*ee3a71e3SShivaprasad G Bhat 45*ee3a71e3SShivaprasad G Bhat uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP, NULL); 46*ee3a71e3SShivaprasad G Bhat qemu_uuid_parse(uuidstr, &uuid); 47*ee3a71e3SShivaprasad G Bhat g_free(uuidstr); 48*ee3a71e3SShivaprasad G Bhat 49*ee3a71e3SShivaprasad G Bhat if (qemu_uuid_is_null(&uuid)) { 50*ee3a71e3SShivaprasad G Bhat error_setg(errp, "NVDIMM device requires the uuid to be set"); 51*ee3a71e3SShivaprasad G Bhat return; 52*ee3a71e3SShivaprasad G Bhat } 53*ee3a71e3SShivaprasad G Bhat } 54*ee3a71e3SShivaprasad G Bhat 55*ee3a71e3SShivaprasad G Bhat 56*ee3a71e3SShivaprasad G Bhat void spapr_add_nvdimm(DeviceState *dev, uint64_t slot, Error **errp) 57*ee3a71e3SShivaprasad G Bhat { 58*ee3a71e3SShivaprasad G Bhat SpaprDrc *drc; 59*ee3a71e3SShivaprasad G Bhat bool hotplugged = spapr_drc_hotplugged(dev); 60*ee3a71e3SShivaprasad G Bhat Error *local_err = NULL; 61*ee3a71e3SShivaprasad G Bhat 62*ee3a71e3SShivaprasad G Bhat drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PMEM, slot); 63*ee3a71e3SShivaprasad G Bhat g_assert(drc); 64*ee3a71e3SShivaprasad G Bhat 65*ee3a71e3SShivaprasad G Bhat spapr_drc_attach(drc, dev, &local_err); 66*ee3a71e3SShivaprasad G Bhat if (local_err) { 67*ee3a71e3SShivaprasad G Bhat error_propagate(errp, local_err); 68*ee3a71e3SShivaprasad G Bhat return; 69*ee3a71e3SShivaprasad G Bhat } 70*ee3a71e3SShivaprasad G Bhat 71*ee3a71e3SShivaprasad G Bhat if (hotplugged) { 72*ee3a71e3SShivaprasad G Bhat spapr_hotplug_req_add_by_index(drc); 73*ee3a71e3SShivaprasad G Bhat } 74*ee3a71e3SShivaprasad G Bhat } 75*ee3a71e3SShivaprasad G Bhat 76*ee3a71e3SShivaprasad G Bhat int spapr_pmem_dt_populate(SpaprDrc *drc, SpaprMachineState *spapr, 77*ee3a71e3SShivaprasad G Bhat void *fdt, int *fdt_start_offset, Error **errp) 78*ee3a71e3SShivaprasad G Bhat { 79*ee3a71e3SShivaprasad G Bhat NVDIMMDevice *nvdimm = NVDIMM(drc->dev); 80*ee3a71e3SShivaprasad G Bhat 81*ee3a71e3SShivaprasad G Bhat *fdt_start_offset = spapr_dt_nvdimm(fdt, 0, nvdimm); 82*ee3a71e3SShivaprasad G Bhat 83*ee3a71e3SShivaprasad G Bhat return 0; 84*ee3a71e3SShivaprasad G Bhat } 85*ee3a71e3SShivaprasad G Bhat 86*ee3a71e3SShivaprasad G Bhat void spapr_create_nvdimm_dr_connectors(SpaprMachineState *spapr) 87*ee3a71e3SShivaprasad G Bhat { 88*ee3a71e3SShivaprasad G Bhat MachineState *machine = MACHINE(spapr); 89*ee3a71e3SShivaprasad G Bhat int i; 90*ee3a71e3SShivaprasad G Bhat 91*ee3a71e3SShivaprasad G Bhat for (i = 0; i < machine->ram_slots; i++) { 92*ee3a71e3SShivaprasad G Bhat spapr_dr_connector_new(OBJECT(spapr), TYPE_SPAPR_DRC_PMEM, i); 93*ee3a71e3SShivaprasad G Bhat } 94*ee3a71e3SShivaprasad G Bhat } 95*ee3a71e3SShivaprasad G Bhat 96*ee3a71e3SShivaprasad G Bhat 97*ee3a71e3SShivaprasad G Bhat int spapr_dt_nvdimm(void *fdt, int parent_offset, 98*ee3a71e3SShivaprasad G Bhat NVDIMMDevice *nvdimm) 99*ee3a71e3SShivaprasad G Bhat { 100*ee3a71e3SShivaprasad G Bhat int child_offset; 101*ee3a71e3SShivaprasad G Bhat char *buf; 102*ee3a71e3SShivaprasad G Bhat SpaprDrc *drc; 103*ee3a71e3SShivaprasad G Bhat uint32_t drc_idx; 104*ee3a71e3SShivaprasad G Bhat uint32_t node = object_property_get_uint(OBJECT(nvdimm), PC_DIMM_NODE_PROP, 105*ee3a71e3SShivaprasad G Bhat &error_abort); 106*ee3a71e3SShivaprasad G Bhat uint64_t slot = object_property_get_uint(OBJECT(nvdimm), PC_DIMM_SLOT_PROP, 107*ee3a71e3SShivaprasad G Bhat &error_abort); 108*ee3a71e3SShivaprasad G Bhat uint32_t associativity[] = { 109*ee3a71e3SShivaprasad G Bhat cpu_to_be32(0x4), /* length */ 110*ee3a71e3SShivaprasad G Bhat cpu_to_be32(0x0), cpu_to_be32(0x0), 111*ee3a71e3SShivaprasad G Bhat cpu_to_be32(0x0), cpu_to_be32(node) 112*ee3a71e3SShivaprasad G Bhat }; 113*ee3a71e3SShivaprasad G Bhat uint64_t lsize = nvdimm->label_size; 114*ee3a71e3SShivaprasad G Bhat uint64_t size = object_property_get_int(OBJECT(nvdimm), PC_DIMM_SIZE_PROP, 115*ee3a71e3SShivaprasad G Bhat NULL); 116*ee3a71e3SShivaprasad G Bhat 117*ee3a71e3SShivaprasad G Bhat drc = spapr_drc_by_id(TYPE_SPAPR_DRC_PMEM, slot); 118*ee3a71e3SShivaprasad G Bhat g_assert(drc); 119*ee3a71e3SShivaprasad G Bhat 120*ee3a71e3SShivaprasad G Bhat drc_idx = spapr_drc_index(drc); 121*ee3a71e3SShivaprasad G Bhat 122*ee3a71e3SShivaprasad G Bhat buf = g_strdup_printf("ibm,pmemory@%x", drc_idx); 123*ee3a71e3SShivaprasad G Bhat child_offset = fdt_add_subnode(fdt, parent_offset, buf); 124*ee3a71e3SShivaprasad G Bhat g_free(buf); 125*ee3a71e3SShivaprasad G Bhat 126*ee3a71e3SShivaprasad G Bhat _FDT(child_offset); 127*ee3a71e3SShivaprasad G Bhat 128*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, child_offset, "reg", drc_idx))); 129*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "compatible", "ibm,pmemory"))); 130*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "device_type", "ibm,pmemory"))); 131*ee3a71e3SShivaprasad G Bhat 132*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop(fdt, child_offset, "ibm,associativity", associativity, 133*ee3a71e3SShivaprasad G Bhat sizeof(associativity)))); 134*ee3a71e3SShivaprasad G Bhat 135*ee3a71e3SShivaprasad G Bhat buf = qemu_uuid_unparse_strdup(&nvdimm->uuid); 136*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "ibm,unit-guid", buf))); 137*ee3a71e3SShivaprasad G Bhat g_free(buf); 138*ee3a71e3SShivaprasad G Bhat 139*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, child_offset, "ibm,my-drc-index", drc_idx))); 140*ee3a71e3SShivaprasad G Bhat 141*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_u64(fdt, child_offset, "ibm,block-size", 142*ee3a71e3SShivaprasad G Bhat SPAPR_MINIMUM_SCM_BLOCK_SIZE))); 143*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_u64(fdt, child_offset, "ibm,number-of-blocks", 144*ee3a71e3SShivaprasad G Bhat size / SPAPR_MINIMUM_SCM_BLOCK_SIZE))); 145*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, child_offset, "ibm,metadata-size", lsize))); 146*ee3a71e3SShivaprasad G Bhat 147*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, child_offset, "ibm,pmem-application", 148*ee3a71e3SShivaprasad G Bhat "operating-system"))); 149*ee3a71e3SShivaprasad G Bhat _FDT(fdt_setprop(fdt, child_offset, "ibm,cache-flush-required", NULL, 0)); 150*ee3a71e3SShivaprasad G Bhat 151*ee3a71e3SShivaprasad G Bhat return child_offset; 152*ee3a71e3SShivaprasad G Bhat } 153*ee3a71e3SShivaprasad G Bhat 154*ee3a71e3SShivaprasad G Bhat void spapr_dt_persistent_memory(void *fdt) 155*ee3a71e3SShivaprasad G Bhat { 156*ee3a71e3SShivaprasad G Bhat int offset = fdt_subnode_offset(fdt, 0, "persistent-memory"); 157*ee3a71e3SShivaprasad G Bhat GSList *iter, *nvdimms = nvdimm_get_device_list(); 158*ee3a71e3SShivaprasad G Bhat 159*ee3a71e3SShivaprasad G Bhat if (offset < 0) { 160*ee3a71e3SShivaprasad G Bhat offset = fdt_add_subnode(fdt, 0, "persistent-memory"); 161*ee3a71e3SShivaprasad G Bhat _FDT(offset); 162*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1))); 163*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0))); 164*ee3a71e3SShivaprasad G Bhat _FDT((fdt_setprop_string(fdt, offset, "device_type", 165*ee3a71e3SShivaprasad G Bhat "ibm,persistent-memory"))); 166*ee3a71e3SShivaprasad G Bhat } 167*ee3a71e3SShivaprasad G Bhat 168*ee3a71e3SShivaprasad G Bhat /* Create DT entries for cold plugged NVDIMM devices */ 169*ee3a71e3SShivaprasad G Bhat for (iter = nvdimms; iter; iter = iter->next) { 170*ee3a71e3SShivaprasad G Bhat NVDIMMDevice *nvdimm = iter->data; 171*ee3a71e3SShivaprasad G Bhat 172*ee3a71e3SShivaprasad G Bhat spapr_dt_nvdimm(fdt, offset, nvdimm); 173*ee3a71e3SShivaprasad G Bhat } 174*ee3a71e3SShivaprasad G Bhat g_slist_free(nvdimms); 175*ee3a71e3SShivaprasad G Bhat 176*ee3a71e3SShivaprasad G Bhat return; 177*ee3a71e3SShivaprasad G Bhat } 178