qemu/hw/ppc/pnv_core.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC PowerNV CPU Core model
   3 *
   4 * Copyright (c) 2016, IBM Corporation.
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public License
   8 * as published by the Free Software Foundation; either version 2 of
   9 * the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include "qemu/osdep.h"
  20#include "sysemu/sysemu.h"
  21#include "qapi/error.h"
  22#include "qemu/log.h"
  23#include "target-ppc/cpu.h"
  24#include "hw/ppc/ppc.h"
  25#include "hw/ppc/pnv.h"
  26#include "hw/ppc/pnv_core.h"
  27#include "hw/ppc/pnv_xscom.h"
  28
  29static void powernv_cpu_reset(void *opaque)
  30{
  31    PowerPCCPU *cpu = opaque;
  32    CPUState *cs = CPU(cpu);
  33    CPUPPCState *env = &cpu->env;
  34
  35    cpu_reset(cs);
  36
  37    /*
  38     * the skiboot firmware elects a primary thread to initialize the
  39     * system and it can be any.
  40     */
  41    env->gpr[3] = PNV_FDT_ADDR;
  42    env->nip = 0x10;
  43    env->msr |= MSR_HVB; /* Hypervisor mode */
  44}
  45
  46static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp)
  47{
  48    CPUPPCState *env = &cpu->env;
  49    int core_pir;
  50    int thread_index = 0; /* TODO: TCG supports only one thread */
  51    ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
  52
  53    core_pir = object_property_get_int(OBJECT(cpu), "core-pir", &error_abort);
  54
  55    /*
  56     * The PIR of a thread is the core PIR + the thread index. We will
  57     * need to find a way to get the thread index when TCG supports
  58     * more than 1. We could use the object name ?
  59     */
  60    pir->default_value = core_pir + thread_index;
  61
  62    /* Set time-base frequency to 512 MHz */
  63    cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
  64
  65    qemu_register_reset(powernv_cpu_reset, cpu);
  66}
  67
  68/*
  69 * These values are read by the PowerNV HW monitors under Linux
  70 */
  71#define PNV_XSCOM_EX_DTS_RESULT0     0x50000
  72#define PNV_XSCOM_EX_DTS_RESULT1     0x50001
  73
  74static uint64_t pnv_core_xscom_read(void *opaque, hwaddr addr,
  75                                    unsigned int width)
  76{
  77    uint32_t offset = addr >> 3;
  78    uint64_t val = 0;
  79
  80    /* The result should be 38 C */
  81    switch (offset) {
  82    case PNV_XSCOM_EX_DTS_RESULT0:
  83        val = 0x26f024f023f0000ull;
  84        break;
  85    case PNV_XSCOM_EX_DTS_RESULT1:
  86        val = 0x24f000000000000ull;
  87        break;
  88    default:
  89        qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx,
  90                  addr);
  91    }
  92
  93    return val;
  94}
  95
  96static void pnv_core_xscom_write(void *opaque, hwaddr addr, uint64_t val,
  97                                 unsigned int width)
  98{
  99    qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx,
 100                  addr);
 101}
 102
 103static const MemoryRegionOps pnv_core_xscom_ops = {
 104    .read = pnv_core_xscom_read,
 105    .write = pnv_core_xscom_write,
 106    .valid.min_access_size = 8,
 107    .valid.max_access_size = 8,
 108    .impl.min_access_size = 8,
 109    .impl.max_access_size = 8,
 110    .endianness = DEVICE_BIG_ENDIAN,
 111};
 112
 113static void pnv_core_realize_child(Object *child, Error **errp)
 114{
 115    Error *local_err = NULL;
 116    CPUState *cs = CPU(child);
 117    PowerPCCPU *cpu = POWERPC_CPU(cs);
 118
 119    object_property_set_bool(child, true, "realized", &local_err);
 120    if (local_err) {
 121        error_propagate(errp, local_err);
 122        return;
 123    }
 124
 125    powernv_cpu_init(cpu, &local_err);
 126    if (local_err) {
 127        error_propagate(errp, local_err);
 128        return;
 129    }
 130}
 131
 132static void pnv_core_realize(DeviceState *dev, Error **errp)
 133{
 134    PnvCore *pc = PNV_CORE(OBJECT(dev));
 135    CPUCore *cc = CPU_CORE(OBJECT(dev));
 136    PnvCoreClass *pcc = PNV_CORE_GET_CLASS(OBJECT(dev));
 137    const char *typename = object_class_get_name(pcc->cpu_oc);
 138    size_t size = object_type_get_instance_size(typename);
 139    Error *local_err = NULL;
 140    void *obj;
 141    int i, j;
 142    char name[32];
 143
 144    pc->threads = g_malloc0(size * cc->nr_threads);
 145    for (i = 0; i < cc->nr_threads; i++) {
 146        obj = pc->threads + i * size;
 147
 148        object_initialize(obj, size, typename);
 149
 150        snprintf(name, sizeof(name), "thread[%d]", i);
 151        object_property_add_child(OBJECT(pc), name, obj, &local_err);
 152        object_property_add_alias(obj, "core-pir", OBJECT(pc),
 153                                  "pir", &local_err);
 154        if (local_err) {
 155            goto err;
 156        }
 157        object_unref(obj);
 158    }
 159
 160    for (j = 0; j < cc->nr_threads; j++) {
 161        obj = pc->threads + j * size;
 162
 163        pnv_core_realize_child(obj, &local_err);
 164        if (local_err) {
 165            goto err;
 166        }
 167    }
 168
 169    snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
 170    pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), &pnv_core_xscom_ops,
 171                          pc, name, PNV_XSCOM_EX_CORE_SIZE);
 172    return;
 173
 174err:
 175    while (--i >= 0) {
 176        obj = pc->threads + i * size;
 177        object_unparent(obj);
 178    }
 179    g_free(pc->threads);
 180    error_propagate(errp, local_err);
 181}
 182
 183static Property pnv_core_properties[] = {
 184    DEFINE_PROP_UINT32("pir", PnvCore, pir, 0),
 185    DEFINE_PROP_END_OF_LIST(),
 186};
 187
 188static void pnv_core_class_init(ObjectClass *oc, void *data)
 189{
 190    DeviceClass *dc = DEVICE_CLASS(oc);
 191    PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
 192
 193    dc->realize = pnv_core_realize;
 194    dc->props = pnv_core_properties;
 195    pcc->cpu_oc = cpu_class_by_name(TYPE_POWERPC_CPU, data);
 196}
 197
 198static const TypeInfo pnv_core_info = {
 199    .name           = TYPE_PNV_CORE,
 200    .parent         = TYPE_CPU_CORE,
 201    .instance_size  = sizeof(PnvCore),
 202    .class_size     = sizeof(PnvCoreClass),
 203    .abstract       = true,
 204};
 205
 206static const char *pnv_core_models[] = {
 207    "POWER8E", "POWER8", "POWER8NVL", "POWER9"
 208};
 209
 210static void pnv_core_register_types(void)
 211{
 212    int i ;
 213
 214    type_register_static(&pnv_core_info);
 215    for (i = 0; i < ARRAY_SIZE(pnv_core_models); ++i) {
 216        TypeInfo ti = {
 217            .parent = TYPE_PNV_CORE,
 218            .instance_size = sizeof(PnvCore),
 219            .class_init = pnv_core_class_init,
 220            .class_data = (void *) pnv_core_models[i],
 221        };
 222        ti.name = pnv_core_typename(pnv_core_models[i]);
 223        type_register(&ti);
 224        g_free((void *)ti.name);
 225    }
 226}
 227
 228type_init(pnv_core_register_types)
 229
 230char *pnv_core_typename(const char *model)
 231{
 232    return g_strdup_printf(TYPE_PNV_CORE "-%s", model);
 233}
 234