migration/ram: Fix compilation with -Wshadow=local
[qemu/ar7.git] / hw / ppc / pnv_core.c
blob8c7afe037f00bf13426baf6c928aa34325f999e5
1 /*
2 * QEMU PowerPC PowerNV CPU Core model
4 * Copyright (c) 2016, IBM Corporation.
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.1 of
9 * the License, or (at your option) any later version.
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.
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/>.
20 #include "qemu/osdep.h"
21 #include "sysemu/reset.h"
22 #include "qapi/error.h"
23 #include "qemu/log.h"
24 #include "qemu/module.h"
25 #include "target/ppc/cpu.h"
26 #include "hw/ppc/ppc.h"
27 #include "hw/ppc/pnv.h"
28 #include "hw/ppc/pnv_chip.h"
29 #include "hw/ppc/pnv_core.h"
30 #include "hw/ppc/pnv_xscom.h"
31 #include "hw/ppc/xics.h"
32 #include "hw/qdev-properties.h"
33 #include "helper_regs.h"
35 static const char *pnv_core_cpu_typename(PnvCore *pc)
37 const char *core_type = object_class_get_name(object_get_class(OBJECT(pc)));
38 int len = strlen(core_type) - strlen(PNV_CORE_TYPE_SUFFIX);
39 char *s = g_strdup_printf(POWERPC_CPU_TYPE_NAME("%.*s"), len, core_type);
40 const char *cpu_type = object_class_get_name(object_class_by_name(s));
41 g_free(s);
42 return cpu_type;
45 static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
47 CPUState *cs = CPU(cpu);
48 CPUPPCState *env = &cpu->env;
49 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
51 cpu_reset(cs);
54 * the skiboot firmware elects a primary thread to initialize the
55 * system and it can be any.
57 env->gpr[3] = PNV_FDT_ADDR;
58 env->nip = 0x10;
59 env->msr |= MSR_HVB; /* Hypervisor mode */
60 env->spr[SPR_HRMOR] = pc->hrmor;
61 hreg_compute_hflags(env);
62 ppc_maybe_interrupt(env);
64 cpu_ppc_tb_reset(env);
66 pcc->intc_reset(pc->chip, cpu);
70 * These values are read by the PowerNV HW monitors under Linux
72 #define PNV_XSCOM_EX_DTS_RESULT0 0x50000
73 #define PNV_XSCOM_EX_DTS_RESULT1 0x50001
75 static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
76 unsigned int width)
78 uint32_t offset = addr >> 3;
79 uint64_t val = 0;
81 /* The result should be 38 C */
82 switch (offset) {
83 case PNV_XSCOM_EX_DTS_RESULT0:
84 val = 0x26f024f023f0000ull;
85 break;
86 case PNV_XSCOM_EX_DTS_RESULT1:
87 val = 0x24f000000000000ull;
88 break;
89 default:
90 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
91 offset);
94 return val;
97 static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
98 unsigned int width)
100 uint32_t offset = addr >> 3;
102 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
103 offset);
106 static const MemoryRegionOps pnv_core_power8_xscom_ops = {
107 .read = pnv_core_power8_xscom_read,
108 .write = pnv_core_power8_xscom_write,
109 .valid.min_access_size = 8,
110 .valid.max_access_size = 8,
111 .impl.min_access_size = 8,
112 .impl.max_access_size = 8,
113 .endianness = DEVICE_BIG_ENDIAN,
118 * POWER9 core controls
120 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
121 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
123 #define PNV9_XSCOM_EC_CORE_THREAD_STATE 0x10ab3
125 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
126 unsigned int width)
128 uint32_t offset = addr >> 3;
129 uint64_t val = 0;
131 /* The result should be 38 C */
132 switch (offset) {
133 case PNV_XSCOM_EX_DTS_RESULT0:
134 val = 0x26f024f023f0000ull;
135 break;
136 case PNV_XSCOM_EX_DTS_RESULT1:
137 val = 0x24f000000000000ull;
138 break;
139 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
140 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
141 val = 0x0;
142 break;
143 case PNV9_XSCOM_EC_CORE_THREAD_STATE:
144 val = 0;
145 break;
146 default:
147 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
148 offset);
151 return val;
154 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
155 unsigned int width)
157 uint32_t offset = addr >> 3;
159 switch (offset) {
160 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
161 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
162 break;
163 default:
164 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
165 offset);
169 static const MemoryRegionOps pnv_core_power9_xscom_ops = {
170 .read = pnv_core_power9_xscom_read,
171 .write = pnv_core_power9_xscom_write,
172 .valid.min_access_size = 8,
173 .valid.max_access_size = 8,
174 .impl.min_access_size = 8,
175 .impl.max_access_size = 8,
176 .endianness = DEVICE_BIG_ENDIAN,
180 * POWER10 core controls
183 #define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412
185 static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
186 unsigned int width)
188 uint32_t offset = addr >> 3;
189 uint64_t val = 0;
191 switch (offset) {
192 case PNV10_XSCOM_EC_CORE_THREAD_STATE:
193 val = 0;
194 break;
195 default:
196 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
197 offset);
200 return val;
203 static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
204 uint64_t val, unsigned int width)
206 uint32_t offset = addr >> 3;
208 switch (offset) {
209 default:
210 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
211 offset);
215 static const MemoryRegionOps pnv_core_power10_xscom_ops = {
216 .read = pnv_core_power10_xscom_read,
217 .write = pnv_core_power10_xscom_write,
218 .valid.min_access_size = 8,
219 .valid.max_access_size = 8,
220 .impl.min_access_size = 8,
221 .impl.max_access_size = 8,
222 .endianness = DEVICE_BIG_ENDIAN,
225 static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
226 int thread_index)
228 CPUPPCState *env = &cpu->env;
229 int core_pir;
230 ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
231 ppc_spr_t *tir = &env->spr_cb[SPR_TIR];
232 Error *local_err = NULL;
233 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
235 if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
236 return;
239 pcc->intc_create(pc->chip, cpu, &local_err);
240 if (local_err) {
241 error_propagate(errp, local_err);
242 return;
245 core_pir = object_property_get_uint(OBJECT(pc), "pir", &error_abort);
247 tir->default_value = thread_index;
248 pir->default_value = core_pir + thread_index;
250 /* Set time-base frequency to 512 MHz */
251 cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
254 static void pnv_core_reset(void *dev)
256 CPUCore *cc = CPU_CORE(dev);
257 PnvCore *pc = PNV_CORE(dev);
258 int i;
260 for (i = 0; i < cc->nr_threads; i++) {
261 pnv_core_cpu_reset(pc, pc->threads[i]);
265 static void pnv_core_realize(DeviceState *dev, Error **errp)
267 PnvCore *pc = PNV_CORE(OBJECT(dev));
268 PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
269 CPUCore *cc = CPU_CORE(OBJECT(dev));
270 const char *typename = pnv_core_cpu_typename(pc);
271 Error *local_err = NULL;
272 void *obj;
273 int i, j;
274 char name[32];
276 assert(pc->chip);
278 pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
279 for (i = 0; i < cc->nr_threads; i++) {
280 PowerPCCPU *cpu;
282 obj = object_new(typename);
283 cpu = POWERPC_CPU(obj);
285 pc->threads[i] = POWERPC_CPU(obj);
287 snprintf(name, sizeof(name), "thread[%d]", i);
288 object_property_add_child(OBJECT(pc), name, obj);
290 cpu->machine_data = g_new0(PnvCPUState, 1);
292 object_unref(obj);
295 for (j = 0; j < cc->nr_threads; j++) {
296 pnv_core_cpu_realize(pc, pc->threads[j], &local_err, j);
297 if (local_err) {
298 goto err;
302 snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
303 pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
304 pc, name, pcc->xscom_size);
306 qemu_register_reset(pnv_core_reset, pc);
307 return;
309 err:
310 while (--i >= 0) {
311 obj = OBJECT(pc->threads[i]);
312 object_unparent(obj);
314 g_free(pc->threads);
315 error_propagate(errp, local_err);
318 static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu)
320 PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
321 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
323 pcc->intc_destroy(pc->chip, cpu);
324 cpu_remove_sync(CPU(cpu));
325 cpu->machine_data = NULL;
326 g_free(pnv_cpu);
327 object_unparent(OBJECT(cpu));
330 static void pnv_core_unrealize(DeviceState *dev)
332 PnvCore *pc = PNV_CORE(dev);
333 CPUCore *cc = CPU_CORE(dev);
334 int i;
336 qemu_unregister_reset(pnv_core_reset, pc);
338 for (i = 0; i < cc->nr_threads; i++) {
339 pnv_core_cpu_unrealize(pc, pc->threads[i]);
341 g_free(pc->threads);
344 static Property pnv_core_properties[] = {
345 DEFINE_PROP_UINT32("pir", PnvCore, pir, 0),
346 DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
347 DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
348 DEFINE_PROP_END_OF_LIST(),
351 static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
353 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
355 pcc->xscom_ops = &pnv_core_power8_xscom_ops;
356 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
359 static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
361 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
363 pcc->xscom_ops = &pnv_core_power9_xscom_ops;
364 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
367 static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
369 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
371 pcc->xscom_ops = &pnv_core_power10_xscom_ops;
372 pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
375 static void pnv_core_class_init(ObjectClass *oc, void *data)
377 DeviceClass *dc = DEVICE_CLASS(oc);
379 dc->realize = pnv_core_realize;
380 dc->unrealize = pnv_core_unrealize;
381 device_class_set_props(dc, pnv_core_properties);
382 dc->user_creatable = false;
385 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
387 .parent = TYPE_PNV_CORE, \
388 .name = PNV_CORE_TYPE_NAME(cpu_model), \
389 .class_init = pnv_core_##family##_class_init, \
392 static const TypeInfo pnv_core_infos[] = {
394 .name = TYPE_PNV_CORE,
395 .parent = TYPE_CPU_CORE,
396 .instance_size = sizeof(PnvCore),
397 .class_size = sizeof(PnvCoreClass),
398 .class_init = pnv_core_class_init,
399 .abstract = true,
401 DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
402 DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
403 DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
404 DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"),
405 DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"),
408 DEFINE_TYPES(pnv_core_infos)
411 * POWER9 Quads
414 #define P9X_EX_NCU_SPEC_BAR 0x11010
416 static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
417 unsigned int width)
419 uint32_t offset = addr >> 3;
420 uint64_t val = -1;
422 switch (offset) {
423 case P9X_EX_NCU_SPEC_BAR:
424 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
425 val = 0;
426 break;
427 default:
428 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
429 offset);
432 return val;
435 static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
436 unsigned int width)
438 uint32_t offset = addr >> 3;
440 switch (offset) {
441 case P9X_EX_NCU_SPEC_BAR:
442 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
443 break;
444 default:
445 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
446 offset);
450 static const MemoryRegionOps pnv_quad_power9_xscom_ops = {
451 .read = pnv_quad_power9_xscom_read,
452 .write = pnv_quad_power9_xscom_write,
453 .valid.min_access_size = 8,
454 .valid.max_access_size = 8,
455 .impl.min_access_size = 8,
456 .impl.max_access_size = 8,
457 .endianness = DEVICE_BIG_ENDIAN,
461 * POWER10 Quads
464 static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
465 unsigned int width)
467 uint32_t offset = addr >> 3;
468 uint64_t val = -1;
470 switch (offset) {
471 default:
472 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
473 offset);
476 return val;
479 static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
480 uint64_t val, unsigned int width)
482 uint32_t offset = addr >> 3;
484 switch (offset) {
485 default:
486 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
487 offset);
491 static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
492 .read = pnv_quad_power10_xscom_read,
493 .write = pnv_quad_power10_xscom_write,
494 .valid.min_access_size = 8,
495 .valid.max_access_size = 8,
496 .impl.min_access_size = 8,
497 .impl.max_access_size = 8,
498 .endianness = DEVICE_BIG_ENDIAN,
501 #define P10_QME_SPWU_HYP 0x83c
502 #define P10_QME_SSH_HYP 0x82c
504 static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
505 unsigned int width)
507 uint32_t offset = addr >> 3;
508 uint64_t val = -1;
511 * Forth nibble selects the core within a quad, mask it to process read
512 * for any core.
514 switch (offset & ~0xf000) {
515 case P10_QME_SPWU_HYP:
516 case P10_QME_SSH_HYP:
517 return 0;
518 default:
519 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
520 offset);
523 return val;
526 static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
527 uint64_t val, unsigned int width)
529 uint32_t offset = addr >> 3;
531 switch (offset) {
532 default:
533 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
534 offset);
538 static const MemoryRegionOps pnv_qme_power10_xscom_ops = {
539 .read = pnv_qme_power10_xscom_read,
540 .write = pnv_qme_power10_xscom_write,
541 .valid.min_access_size = 8,
542 .valid.max_access_size = 8,
543 .impl.min_access_size = 8,
544 .impl.max_access_size = 8,
545 .endianness = DEVICE_BIG_ENDIAN,
548 static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
550 PnvQuad *eq = PNV_QUAD(dev);
551 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
552 char name[32];
554 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
555 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
556 pqc->xscom_ops,
557 eq, name,
558 pqc->xscom_size);
561 static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
563 PnvQuad *eq = PNV_QUAD(dev);
564 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
565 char name[32];
567 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
568 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
569 pqc->xscom_ops,
570 eq, name,
571 pqc->xscom_size);
573 snprintf(name, sizeof(name), "xscom-qme.%d", eq->quad_id);
574 pnv_xscom_region_init(&eq->xscom_qme_regs, OBJECT(dev),
575 pqc->xscom_qme_ops,
576 eq, name,
577 pqc->xscom_qme_size);
580 static Property pnv_quad_properties[] = {
581 DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
582 DEFINE_PROP_END_OF_LIST(),
585 static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
587 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
588 DeviceClass *dc = DEVICE_CLASS(oc);
590 dc->realize = pnv_quad_power9_realize;
592 pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
593 pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
596 static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
598 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
599 DeviceClass *dc = DEVICE_CLASS(oc);
601 dc->realize = pnv_quad_power10_realize;
603 pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
604 pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
606 pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
607 pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
610 static void pnv_quad_class_init(ObjectClass *oc, void *data)
612 DeviceClass *dc = DEVICE_CLASS(oc);
614 device_class_set_props(dc, pnv_quad_properties);
615 dc->user_creatable = false;
618 static const TypeInfo pnv_quad_infos[] = {
620 .name = TYPE_PNV_QUAD,
621 .parent = TYPE_DEVICE,
622 .instance_size = sizeof(PnvQuad),
623 .class_size = sizeof(PnvQuadClass),
624 .class_init = pnv_quad_class_init,
625 .abstract = true,
628 .parent = TYPE_PNV_QUAD,
629 .name = PNV_QUAD_TYPE_NAME("power9"),
630 .class_init = pnv_quad_power9_class_init,
633 .parent = TYPE_PNV_QUAD,
634 .name = PNV_QUAD_TYPE_NAME("power10"),
635 .class_init = pnv_quad_power10_class_init,
639 DEFINE_TYPES(pnv_quad_infos);