]> git.proxmox.com Git - mirror_qemu.git/blob - hw/ppc/pnv_core.c
Merge tag 'pull-maintainer-may24-160524-2' of https://gitlab.com/stsquad/qemu into...
[mirror_qemu.git] / hw / ppc / pnv_core.c
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.1 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
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"
34
35 static const char *pnv_core_cpu_typename(PnvCore *pc)
36 {
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;
43 }
44
45 static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
46 {
47 CPUState *cs = CPU(cpu);
48 CPUPPCState *env = &cpu->env;
49 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
50
51 cpu_reset(cs);
52
53 /*
54 * the skiboot firmware elects a primary thread to initialize the
55 * system and it can be any.
56 */
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);
63
64 cpu_ppc_tb_reset(env);
65
66 pcc->intc_reset(pc->chip, cpu);
67 }
68
69 /*
70 * These values are read by the PowerNV HW monitors under Linux
71 */
72 #define PNV_XSCOM_EX_DTS_RESULT0 0x50000
73 #define PNV_XSCOM_EX_DTS_RESULT1 0x50001
74
75 static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
76 unsigned int width)
77 {
78 uint32_t offset = addr >> 3;
79 uint64_t val = 0;
80
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);
92 }
93
94 return val;
95 }
96
97 static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
98 unsigned int width)
99 {
100 uint32_t offset = addr >> 3;
101
102 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
103 offset);
104 }
105
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,
114 };
115
116
117 /*
118 * POWER9 core controls
119 */
120 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
121 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
122
123 #define PNV9_XSCOM_EC_CORE_THREAD_STATE 0x10ab3
124
125 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
126 unsigned int width)
127 {
128 uint32_t offset = addr >> 3;
129 uint64_t val = 0;
130
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);
149 }
150
151 return val;
152 }
153
154 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
155 unsigned int width)
156 {
157 uint32_t offset = addr >> 3;
158
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);
166 }
167 }
168
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,
177 };
178
179 /*
180 * POWER10 core controls
181 */
182
183 #define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412
184
185 static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
186 unsigned int width)
187 {
188 uint32_t offset = addr >> 3;
189 uint64_t val = 0;
190
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);
198 }
199
200 return val;
201 }
202
203 static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
204 uint64_t val, unsigned int width)
205 {
206 uint32_t offset = addr >> 3;
207
208 switch (offset) {
209 default:
210 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
211 offset);
212 }
213 }
214
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,
223 };
224
225 static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
226 int thread_index)
227 {
228 CPUPPCState *env = &cpu->env;
229 int core_hwid;
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);
234
235 if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
236 return;
237 }
238
239 pcc->intc_create(pc->chip, cpu, &local_err);
240 if (local_err) {
241 error_propagate(errp, local_err);
242 return;
243 }
244
245 core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
246
247 tir->default_value = thread_index;
248 pir->default_value = pcc->chip_pir(pc->chip, core_hwid, thread_index);
249
250 /* Set time-base frequency to 512 MHz */
251 cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
252 }
253
254 static void pnv_core_reset(void *dev)
255 {
256 CPUCore *cc = CPU_CORE(dev);
257 PnvCore *pc = PNV_CORE(dev);
258 int i;
259
260 for (i = 0; i < cc->nr_threads; i++) {
261 pnv_core_cpu_reset(pc, pc->threads[i]);
262 }
263 }
264
265 static void pnv_core_realize(DeviceState *dev, Error **errp)
266 {
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];
275
276 assert(pc->chip);
277
278 pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
279 for (i = 0; i < cc->nr_threads; i++) {
280 PowerPCCPU *cpu;
281
282 obj = object_new(typename);
283 cpu = POWERPC_CPU(obj);
284
285 pc->threads[i] = POWERPC_CPU(obj);
286
287 snprintf(name, sizeof(name), "thread[%d]", i);
288 object_property_add_child(OBJECT(pc), name, obj);
289
290 cpu->machine_data = g_new0(PnvCPUState, 1);
291
292 object_unref(obj);
293 }
294
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;
299 }
300 }
301
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);
305
306 qemu_register_reset(pnv_core_reset, pc);
307 return;
308
309 err:
310 while (--i >= 0) {
311 obj = OBJECT(pc->threads[i]);
312 object_unparent(obj);
313 }
314 g_free(pc->threads);
315 error_propagate(errp, local_err);
316 }
317
318 static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu)
319 {
320 PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
321 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
322
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));
328 }
329
330 static void pnv_core_unrealize(DeviceState *dev)
331 {
332 PnvCore *pc = PNV_CORE(dev);
333 CPUCore *cc = CPU_CORE(dev);
334 int i;
335
336 qemu_unregister_reset(pnv_core_reset, pc);
337
338 for (i = 0; i < cc->nr_threads; i++) {
339 pnv_core_cpu_unrealize(pc, pc->threads[i]);
340 }
341 g_free(pc->threads);
342 }
343
344 static Property pnv_core_properties[] = {
345 DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 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(),
349 };
350
351 static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
352 {
353 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
354
355 pcc->xscom_ops = &pnv_core_power8_xscom_ops;
356 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
357 }
358
359 static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
360 {
361 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
362
363 pcc->xscom_ops = &pnv_core_power9_xscom_ops;
364 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
365 }
366
367 static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
368 {
369 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
370
371 pcc->xscom_ops = &pnv_core_power10_xscom_ops;
372 pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
373 }
374
375 static void pnv_core_class_init(ObjectClass *oc, void *data)
376 {
377 DeviceClass *dc = DEVICE_CLASS(oc);
378
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;
383 }
384
385 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
386 { \
387 .parent = TYPE_PNV_CORE, \
388 .name = PNV_CORE_TYPE_NAME(cpu_model), \
389 .class_init = pnv_core_##family##_class_init, \
390 }
391
392 static const TypeInfo pnv_core_infos[] = {
393 {
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,
400 },
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"),
406 };
407
408 DEFINE_TYPES(pnv_core_infos)
409
410 /*
411 * POWER9 Quads
412 */
413
414 #define P9X_EX_NCU_SPEC_BAR 0x11010
415
416 static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
417 unsigned int width)
418 {
419 uint32_t offset = addr >> 3;
420 uint64_t val = -1;
421
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);
430 }
431
432 return val;
433 }
434
435 static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
436 unsigned int width)
437 {
438 uint32_t offset = addr >> 3;
439
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);
447 }
448 }
449
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,
458 };
459
460 /*
461 * POWER10 Quads
462 */
463
464 static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
465 unsigned int width)
466 {
467 uint32_t offset = addr >> 3;
468 uint64_t val = -1;
469
470 switch (offset) {
471 default:
472 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
473 offset);
474 }
475
476 return val;
477 }
478
479 static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
480 uint64_t val, unsigned int width)
481 {
482 uint32_t offset = addr >> 3;
483
484 switch (offset) {
485 default:
486 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
487 offset);
488 }
489 }
490
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,
499 };
500
501 #define P10_QME_SPWU_HYP 0x83c
502 #define P10_QME_SSH_HYP 0x82c
503
504 static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
505 unsigned int width)
506 {
507 uint32_t offset = addr >> 3;
508 uint64_t val = -1;
509
510 /*
511 * Forth nibble selects the core within a quad, mask it to process read
512 * for any core.
513 */
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);
521 }
522
523 return val;
524 }
525
526 static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
527 uint64_t val, unsigned int width)
528 {
529 uint32_t offset = addr >> 3;
530
531 switch (offset) {
532 default:
533 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
534 offset);
535 }
536 }
537
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,
546 };
547
548 static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
549 {
550 PnvQuad *eq = PNV_QUAD(dev);
551 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
552 char name[32];
553
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);
559 }
560
561 static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
562 {
563 PnvQuad *eq = PNV_QUAD(dev);
564 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
565 char name[32];
566
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);
572
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);
578 }
579
580 static Property pnv_quad_properties[] = {
581 DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
582 DEFINE_PROP_END_OF_LIST(),
583 };
584
585 static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
586 {
587 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
588 DeviceClass *dc = DEVICE_CLASS(oc);
589
590 dc->realize = pnv_quad_power9_realize;
591
592 pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
593 pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
594 }
595
596 static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
597 {
598 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
599 DeviceClass *dc = DEVICE_CLASS(oc);
600
601 dc->realize = pnv_quad_power10_realize;
602
603 pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
604 pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
605
606 pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
607 pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
608 }
609
610 static void pnv_quad_class_init(ObjectClass *oc, void *data)
611 {
612 DeviceClass *dc = DEVICE_CLASS(oc);
613
614 device_class_set_props(dc, pnv_quad_properties);
615 dc->user_creatable = false;
616 }
617
618 static const TypeInfo pnv_quad_infos[] = {
619 {
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,
626 },
627 {
628 .parent = TYPE_PNV_QUAD,
629 .name = PNV_QUAD_TYPE_NAME("power9"),
630 .class_init = pnv_quad_power9_class_init,
631 },
632 {
633 .parent = TYPE_PNV_QUAD,
634 .name = PNV_QUAD_TYPE_NAME("power10"),
635 .class_init = pnv_quad_power10_class_init,
636 },
637 };
638
639 DEFINE_TYPES(pnv_quad_infos);