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