xref: /openbmc/qemu/hw/ppc/pnv_core.c (revision 25de28220cedadac15021ec40047785f30e153fe)
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_spr = &env->spr_cb[SPR_PIR];
231     ppc_spr_t *tir_spr = &env->spr_cb[SPR_TIR];
232     uint32_t pir, tir;
233     Error *local_err = NULL;
234     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
235 
236     if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
237         return;
238     }
239 
240     pcc->intc_create(pc->chip, cpu, &local_err);
241     if (local_err) {
242         error_propagate(errp, local_err);
243         return;
244     }
245 
246     core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
247 
248     pcc->get_pir_tir(pc->chip, core_hwid, thread_index, &pir, &tir);
249     pir_spr->default_value = pir;
250     tir_spr->default_value = tir;
251 
252     /* Set time-base frequency to 512 MHz */
253     cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
254 }
255 
256 static void pnv_core_reset(void *dev)
257 {
258     CPUCore *cc = CPU_CORE(dev);
259     PnvCore *pc = PNV_CORE(dev);
260     int i;
261 
262     for (i = 0; i < cc->nr_threads; i++) {
263         pnv_core_cpu_reset(pc, pc->threads[i]);
264     }
265 }
266 
267 static void pnv_core_realize(DeviceState *dev, Error **errp)
268 {
269     PnvCore *pc = PNV_CORE(OBJECT(dev));
270     PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
271     CPUCore *cc = CPU_CORE(OBJECT(dev));
272     const char *typename = pnv_core_cpu_typename(pc);
273     Error *local_err = NULL;
274     void *obj;
275     int i, j;
276     char name[32];
277 
278     assert(pc->chip);
279 
280     pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
281     for (i = 0; i < cc->nr_threads; i++) {
282         PowerPCCPU *cpu;
283         PnvCPUState *pnv_cpu;
284 
285         obj = object_new(typename);
286         cpu = POWERPC_CPU(obj);
287 
288         pc->threads[i] = POWERPC_CPU(obj);
289 
290         snprintf(name, sizeof(name), "thread[%d]", i);
291         object_property_add_child(OBJECT(pc), name, obj);
292 
293         cpu->machine_data = g_new0(PnvCPUState, 1);
294         pnv_cpu = pnv_cpu_state(cpu);
295         pnv_cpu->pnv_core = pc;
296 
297         object_unref(obj);
298     }
299 
300     for (j = 0; j < cc->nr_threads; j++) {
301         pnv_core_cpu_realize(pc, pc->threads[j], &local_err, j);
302         if (local_err) {
303             goto err;
304         }
305     }
306 
307     snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
308     pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
309                           pc, name, pcc->xscom_size);
310 
311     qemu_register_reset(pnv_core_reset, pc);
312     return;
313 
314 err:
315     while (--i >= 0) {
316         obj = OBJECT(pc->threads[i]);
317         object_unparent(obj);
318     }
319     g_free(pc->threads);
320     error_propagate(errp, local_err);
321 }
322 
323 static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu)
324 {
325     PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
326     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
327 
328     pcc->intc_destroy(pc->chip, cpu);
329     cpu_remove_sync(CPU(cpu));
330     cpu->machine_data = NULL;
331     g_free(pnv_cpu);
332     object_unparent(OBJECT(cpu));
333 }
334 
335 static void pnv_core_unrealize(DeviceState *dev)
336 {
337     PnvCore *pc = PNV_CORE(dev);
338     CPUCore *cc = CPU_CORE(dev);
339     int i;
340 
341     qemu_unregister_reset(pnv_core_reset, pc);
342 
343     for (i = 0; i < cc->nr_threads; i++) {
344         pnv_core_cpu_unrealize(pc, pc->threads[i]);
345     }
346     g_free(pc->threads);
347 }
348 
349 static Property pnv_core_properties[] = {
350     DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
351     DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
352     DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
353     DEFINE_PROP_END_OF_LIST(),
354 };
355 
356 static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
357 {
358     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
359 
360     pcc->xscom_ops = &pnv_core_power8_xscom_ops;
361     pcc->xscom_size = PNV_XSCOM_EX_SIZE;
362 }
363 
364 static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
365 {
366     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
367 
368     pcc->xscom_ops = &pnv_core_power9_xscom_ops;
369     pcc->xscom_size = PNV_XSCOM_EX_SIZE;
370 }
371 
372 static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
373 {
374     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
375 
376     pcc->xscom_ops = &pnv_core_power10_xscom_ops;
377     pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
378 }
379 
380 static void pnv_core_class_init(ObjectClass *oc, void *data)
381 {
382     DeviceClass *dc = DEVICE_CLASS(oc);
383 
384     dc->realize = pnv_core_realize;
385     dc->unrealize = pnv_core_unrealize;
386     device_class_set_props(dc, pnv_core_properties);
387     dc->user_creatable = false;
388 }
389 
390 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
391     {                                           \
392         .parent = TYPE_PNV_CORE,                \
393         .name = PNV_CORE_TYPE_NAME(cpu_model),  \
394         .class_init = pnv_core_##family##_class_init, \
395     }
396 
397 static const TypeInfo pnv_core_infos[] = {
398     {
399         .name           = TYPE_PNV_CORE,
400         .parent         = TYPE_CPU_CORE,
401         .instance_size  = sizeof(PnvCore),
402         .class_size     = sizeof(PnvCoreClass),
403         .class_init = pnv_core_class_init,
404         .abstract       = true,
405     },
406     DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
407     DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
408     DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
409     DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"),
410     DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"),
411 };
412 
413 DEFINE_TYPES(pnv_core_infos)
414 
415 /*
416  * POWER9 Quads
417  */
418 
419 #define P9X_EX_NCU_SPEC_BAR                     0x11010
420 
421 static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
422                                            unsigned int width)
423 {
424     uint32_t offset = addr >> 3;
425     uint64_t val = -1;
426 
427     switch (offset) {
428     case P9X_EX_NCU_SPEC_BAR:
429     case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
430         val = 0;
431         break;
432     default:
433         qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
434                       offset);
435     }
436 
437     return val;
438 }
439 
440 static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
441                                         unsigned int width)
442 {
443     uint32_t offset = addr >> 3;
444 
445     switch (offset) {
446     case P9X_EX_NCU_SPEC_BAR:
447     case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
448         break;
449     default:
450         qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
451                   offset);
452     }
453 }
454 
455 static const MemoryRegionOps pnv_quad_power9_xscom_ops = {
456     .read = pnv_quad_power9_xscom_read,
457     .write = pnv_quad_power9_xscom_write,
458     .valid.min_access_size = 8,
459     .valid.max_access_size = 8,
460     .impl.min_access_size = 8,
461     .impl.max_access_size = 8,
462     .endianness = DEVICE_BIG_ENDIAN,
463 };
464 
465 /*
466  * POWER10 Quads
467  */
468 
469 static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
470                                             unsigned int width)
471 {
472     uint32_t offset = addr >> 3;
473     uint64_t val = -1;
474 
475     switch (offset) {
476     default:
477         qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
478                       offset);
479     }
480 
481     return val;
482 }
483 
484 static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
485                                          uint64_t val, unsigned int width)
486 {
487     uint32_t offset = addr >> 3;
488 
489     switch (offset) {
490     default:
491         qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
492                       offset);
493     }
494 }
495 
496 static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
497     .read = pnv_quad_power10_xscom_read,
498     .write = pnv_quad_power10_xscom_write,
499     .valid.min_access_size = 8,
500     .valid.max_access_size = 8,
501     .impl.min_access_size = 8,
502     .impl.max_access_size = 8,
503     .endianness = DEVICE_BIG_ENDIAN,
504 };
505 
506 #define P10_QME_SPWU_HYP 0x83c
507 #define P10_QME_SSH_HYP  0x82c
508 
509 static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
510                                             unsigned int width)
511 {
512     uint32_t offset = addr >> 3;
513     uint64_t val = -1;
514 
515     /*
516      * Forth nibble selects the core within a quad, mask it to process read
517      * for any core.
518      */
519     switch (offset & ~0xf000) {
520     case P10_QME_SPWU_HYP:
521     case P10_QME_SSH_HYP:
522         return 0;
523     default:
524         qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
525                       offset);
526     }
527 
528     return val;
529 }
530 
531 static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
532                                          uint64_t val, unsigned int width)
533 {
534     uint32_t offset = addr >> 3;
535 
536     switch (offset) {
537     default:
538         qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
539                       offset);
540     }
541 }
542 
543 static const MemoryRegionOps pnv_qme_power10_xscom_ops = {
544     .read = pnv_qme_power10_xscom_read,
545     .write = pnv_qme_power10_xscom_write,
546     .valid.min_access_size = 8,
547     .valid.max_access_size = 8,
548     .impl.min_access_size = 8,
549     .impl.max_access_size = 8,
550     .endianness = DEVICE_BIG_ENDIAN,
551 };
552 
553 static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
554 {
555     PnvQuad *eq = PNV_QUAD(dev);
556     PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
557     char name[32];
558 
559     snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
560     pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
561                           pqc->xscom_ops,
562                           eq, name,
563                           pqc->xscom_size);
564 }
565 
566 static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
567 {
568     PnvQuad *eq = PNV_QUAD(dev);
569     PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
570     char name[32];
571 
572     snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
573     pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
574                           pqc->xscom_ops,
575                           eq, name,
576                           pqc->xscom_size);
577 
578     snprintf(name, sizeof(name), "xscom-qme.%d", eq->quad_id);
579     pnv_xscom_region_init(&eq->xscom_qme_regs, OBJECT(dev),
580                           pqc->xscom_qme_ops,
581                           eq, name,
582                           pqc->xscom_qme_size);
583 }
584 
585 static Property pnv_quad_properties[] = {
586     DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
587     DEFINE_PROP_END_OF_LIST(),
588 };
589 
590 static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
591 {
592     PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
593     DeviceClass *dc = DEVICE_CLASS(oc);
594 
595     dc->realize = pnv_quad_power9_realize;
596 
597     pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
598     pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
599 }
600 
601 static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
602 {
603     PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
604     DeviceClass *dc = DEVICE_CLASS(oc);
605 
606     dc->realize = pnv_quad_power10_realize;
607 
608     pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
609     pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
610 
611     pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
612     pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
613 }
614 
615 static void pnv_quad_class_init(ObjectClass *oc, void *data)
616 {
617     DeviceClass *dc = DEVICE_CLASS(oc);
618 
619     device_class_set_props(dc, pnv_quad_properties);
620     dc->user_creatable = false;
621 }
622 
623 static const TypeInfo pnv_quad_infos[] = {
624     {
625         .name          = TYPE_PNV_QUAD,
626         .parent        = TYPE_DEVICE,
627         .instance_size = sizeof(PnvQuad),
628         .class_size    = sizeof(PnvQuadClass),
629         .class_init    = pnv_quad_class_init,
630         .abstract      = true,
631     },
632     {
633         .parent = TYPE_PNV_QUAD,
634         .name = PNV_QUAD_TYPE_NAME("power9"),
635         .class_init = pnv_quad_power9_class_init,
636     },
637     {
638         .parent = TYPE_PNV_QUAD,
639         .name = PNV_QUAD_TYPE_NAME("power10"),
640         .class_init = pnv_quad_power10_class_init,
641     },
642 };
643 
644 DEFINE_TYPES(pnv_quad_infos);
645