qemu/hw/ppc/spapr_cpu_core.c
<<
>>
Prefs
   1/*
   2 * sPAPR CPU core device, acts as container of CPU thread devices.
   3 *
   4 * Copyright (C) 2016 Bharata B Rao <bharata@linux.vnet.ibm.com>
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9#include "hw/cpu/core.h"
  10#include "hw/ppc/spapr_cpu_core.h"
  11#include "target/ppc/cpu.h"
  12#include "hw/ppc/spapr.h"
  13#include "hw/boards.h"
  14#include "qapi/error.h"
  15#include "sysemu/cpus.h"
  16#include "sysemu/kvm.h"
  17#include "target/ppc/kvm_ppc.h"
  18#include "hw/ppc/ppc.h"
  19#include "target/ppc/mmu-hash64.h"
  20#include "sysemu/numa.h"
  21#include "qemu/error-report.h"
  22
  23static void spapr_cpu_reset(void *opaque)
  24{
  25    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
  26    PowerPCCPU *cpu = opaque;
  27    CPUState *cs = CPU(cpu);
  28    CPUPPCState *env = &cpu->env;
  29
  30    cpu_reset(cs);
  31
  32    /* All CPUs start halted.  CPU0 is unhalted from the machine level
  33     * reset code and the rest are explicitly started up by the guest
  34     * using an RTAS call */
  35    cs->halted = 1;
  36
  37    env->spr[SPR_HIOR] = 0;
  38
  39    /*
  40     * This is a hack for the benefit of KVM PR - it abuses the SDR1
  41     * slot in kvm_sregs to communicate the userspace address of the
  42     * HPT
  43     */
  44    if (kvm_enabled()) {
  45        env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab
  46            | (spapr->htab_shift - 18);
  47        if (kvmppc_put_books_sregs(cpu) < 0) {
  48            error_report("Unable to update SDR1 in KVM");
  49            exit(1);
  50        }
  51    }
  52}
  53
  54static void spapr_cpu_destroy(PowerPCCPU *cpu)
  55{
  56    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
  57
  58    xics_cpu_destroy(XICS_FABRIC(spapr), cpu);
  59    qemu_unregister_reset(spapr_cpu_reset, cpu);
  60}
  61
  62static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu,
  63                           Error **errp)
  64{
  65    CPUPPCState *env = &cpu->env;
  66
  67    /* Set time-base frequency to 512 MHz */
  68    cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ);
  69
  70    /* Enable PAPR mode in TCG or KVM */
  71    cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
  72
  73    if (cpu->max_compat) {
  74        Error *local_err = NULL;
  75
  76        ppc_set_compat(cpu, cpu->max_compat, &local_err);
  77        if (local_err) {
  78            error_propagate(errp, local_err);
  79            return;
  80        }
  81    }
  82
  83    xics_cpu_setup(XICS_FABRIC(spapr), cpu);
  84
  85    qemu_register_reset(spapr_cpu_reset, cpu);
  86    spapr_cpu_reset(cpu);
  87}
  88
  89/*
  90 * Return the sPAPR CPU core type for @model which essentially is the CPU
  91 * model specified with -cpu cmdline option.
  92 */
  93char *spapr_get_cpu_core_type(const char *model)
  94{
  95    char *core_type;
  96    gchar **model_pieces = g_strsplit(model, ",", 2);
  97
  98    core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE);
  99
 100    /* Check whether it exists or whether we have to look up an alias name */
 101    if (!object_class_by_name(core_type)) {
 102        const char *realmodel;
 103
 104        g_free(core_type);
 105        core_type = NULL;
 106        realmodel = ppc_cpu_lookup_alias(model_pieces[0]);
 107        if (realmodel) {
 108            core_type = spapr_get_cpu_core_type(realmodel);
 109        }
 110    }
 111
 112    g_strfreev(model_pieces);
 113    return core_type;
 114}
 115
 116static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp)
 117{
 118    sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
 119    sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
 120    const char *typename = object_class_get_name(scc->cpu_class);
 121    size_t size = object_type_get_instance_size(typename);
 122    CPUCore *cc = CPU_CORE(dev);
 123    int i;
 124
 125    for (i = 0; i < cc->nr_threads; i++) {
 126        void *obj = sc->threads + i * size;
 127        DeviceState *dev = DEVICE(obj);
 128        CPUState *cs = CPU(dev);
 129        PowerPCCPU *cpu = POWERPC_CPU(cs);
 130
 131        spapr_cpu_destroy(cpu);
 132        cpu_remove_sync(cs);
 133        object_unparent(obj);
 134    }
 135    g_free(sc->threads);
 136}
 137
 138static void spapr_cpu_core_realize_child(Object *child, Error **errp)
 139{
 140    Error *local_err = NULL;
 141    sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
 142    CPUState *cs = CPU(child);
 143    PowerPCCPU *cpu = POWERPC_CPU(cs);
 144
 145    object_property_set_bool(child, true, "realized", &local_err);
 146    if (local_err) {
 147        error_propagate(errp, local_err);
 148        return;
 149    }
 150
 151    spapr_cpu_init(spapr, cpu, &local_err);
 152    if (local_err) {
 153        error_propagate(errp, local_err);
 154        return;
 155    }
 156}
 157
 158static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
 159{
 160    sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
 161    sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev));
 162    CPUCore *cc = CPU_CORE(OBJECT(dev));
 163    const char *typename = object_class_get_name(scc->cpu_class);
 164    size_t size = object_type_get_instance_size(typename);
 165    Error *local_err = NULL;
 166    int core_node_id = numa_get_node_for_cpu(cc->core_id);;
 167    void *obj;
 168    int i, j;
 169
 170    sc->threads = g_malloc0(size * cc->nr_threads);
 171    for (i = 0; i < cc->nr_threads; i++) {
 172        int node_id;
 173        char id[32];
 174        CPUState *cs;
 175
 176        obj = sc->threads + i * size;
 177
 178        object_initialize(obj, size, typename);
 179        cs = CPU(obj);
 180        cs->cpu_index = cc->core_id + i;
 181
 182        /* Set NUMA node for the added CPUs  */
 183        node_id = numa_get_node_for_cpu(cs->cpu_index);
 184        if (node_id != core_node_id) {
 185            error_setg(&local_err, "Invalid node-id=%d of thread[cpu-index: %d]"
 186                " on CPU[core-id: %d, node-id: %d], node-id must be the same",
 187                 node_id, cs->cpu_index, cc->core_id, core_node_id);
 188            goto err;
 189        }
 190        if (node_id < nb_numa_nodes) {
 191            cs->numa_node = node_id;
 192        }
 193
 194        snprintf(id, sizeof(id), "thread[%d]", i);
 195        object_property_add_child(OBJECT(sc), id, obj, &local_err);
 196        if (local_err) {
 197            goto err;
 198        }
 199        object_unref(obj);
 200    }
 201
 202    for (j = 0; j < cc->nr_threads; j++) {
 203        obj = sc->threads + j * size;
 204
 205        spapr_cpu_core_realize_child(obj, &local_err);
 206        if (local_err) {
 207            goto err;
 208        }
 209    }
 210    return;
 211
 212err:
 213    while (--i >= 0) {
 214        obj = sc->threads + i * size;
 215        object_unparent(obj);
 216    }
 217    g_free(sc->threads);
 218    error_propagate(errp, local_err);
 219}
 220
 221static const char *spapr_core_models[] = {
 222    /* 970 */
 223    "970_v2.2",
 224
 225    /* 970MP variants */
 226    "970MP_v1.0",
 227    "970mp_v1.0",
 228    "970MP_v1.1",
 229    "970mp_v1.1",
 230
 231    /* POWER5+ */
 232    "POWER5+_v2.1",
 233
 234    /* POWER7 */
 235    "POWER7_v2.3",
 236
 237    /* POWER7+ */
 238    "POWER7+_v2.1",
 239
 240    /* POWER8 */
 241    "POWER8_v2.0",
 242
 243    /* POWER8E */
 244    "POWER8E_v2.1",
 245
 246    /* POWER8NVL */
 247    "POWER8NVL_v1.0",
 248
 249    /* POWER9 */
 250    "POWER9_v1.0",
 251};
 252
 253void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
 254{
 255    DeviceClass *dc = DEVICE_CLASS(oc);
 256    sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
 257
 258    dc->realize = spapr_cpu_core_realize;
 259    dc->unrealize = spapr_cpu_core_unrealizefn;
 260    scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data);
 261    g_assert(scc->cpu_class);
 262}
 263
 264static const TypeInfo spapr_cpu_core_type_info = {
 265    .name = TYPE_SPAPR_CPU_CORE,
 266    .parent = TYPE_CPU_CORE,
 267    .abstract = true,
 268    .instance_size = sizeof(sPAPRCPUCore),
 269    .class_size = sizeof(sPAPRCPUCoreClass),
 270};
 271
 272static void spapr_cpu_core_register_types(void)
 273{
 274    int i;
 275
 276    type_register_static(&spapr_cpu_core_type_info);
 277
 278    for (i = 0; i < ARRAY_SIZE(spapr_core_models); i++) {
 279        TypeInfo type_info = {
 280            .parent = TYPE_SPAPR_CPU_CORE,
 281            .instance_size = sizeof(sPAPRCPUCore),
 282            .class_init = spapr_cpu_core_class_init,
 283            .class_data = (void *) spapr_core_models[i],
 284        };
 285
 286        type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE,
 287                                         spapr_core_models[i]);
 288        type_register(&type_info);
 289        g_free((void *)type_info.name);
 290    }
 291}
 292
 293type_init(spapr_cpu_core_register_types)
 294