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