xref: /openbmc/qemu/hw/ppc/pnv_core.c (revision 053075097a053f7f9d8ce01f40ae1b1ad1845fea)
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     pcc->intc_reset(pc->chip, cpu);
65 }
66 
67 /*
68  * These values are read by the PowerNV HW monitors under Linux
69  */
70 #define PNV_XSCOM_EX_DTS_RESULT0     0x50000
71 #define PNV_XSCOM_EX_DTS_RESULT1     0x50001
72 
73 static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
74                                            unsigned int width)
75 {
76     uint32_t offset = addr >> 3;
77     uint64_t val = 0;
78 
79     /* The result should be 38 C */
80     switch (offset) {
81     case PNV_XSCOM_EX_DTS_RESULT0:
82         val = 0x26f024f023f0000ull;
83         break;
84     case PNV_XSCOM_EX_DTS_RESULT1:
85         val = 0x24f000000000000ull;
86         break;
87     default:
88         qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
89                   addr);
90     }
91 
92     return val;
93 }
94 
95 static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
96                                         unsigned int width)
97 {
98     qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
99                   addr);
100 }
101 
102 static const MemoryRegionOps pnv_core_power8_xscom_ops = {
103     .read = pnv_core_power8_xscom_read,
104     .write = pnv_core_power8_xscom_write,
105     .valid.min_access_size = 8,
106     .valid.max_access_size = 8,
107     .impl.min_access_size = 8,
108     .impl.max_access_size = 8,
109     .endianness = DEVICE_BIG_ENDIAN,
110 };
111 
112 
113 /*
114  * POWER9 core controls
115  */
116 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
117 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
118 
119 #define PNV9_XSCOM_EC_CORE_THREAD_STATE    0x10ab3
120 
121 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
122                                            unsigned int width)
123 {
124     uint32_t offset = addr >> 3;
125     uint64_t val = 0;
126 
127     /* The result should be 38 C */
128     switch (offset) {
129     case PNV_XSCOM_EX_DTS_RESULT0:
130         val = 0x26f024f023f0000ull;
131         break;
132     case PNV_XSCOM_EX_DTS_RESULT1:
133         val = 0x24f000000000000ull;
134         break;
135     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
136     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
137         val = 0x0;
138         break;
139     case PNV9_XSCOM_EC_CORE_THREAD_STATE:
140         val = 0;
141         break;
142     default:
143         qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
144                   addr);
145     }
146 
147     return val;
148 }
149 
150 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
151                                         unsigned int width)
152 {
153     uint32_t offset = addr >> 3;
154 
155     switch (offset) {
156     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
157     case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
158         break;
159     default:
160         qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
161                       addr);
162     }
163 }
164 
165 static const MemoryRegionOps pnv_core_power9_xscom_ops = {
166     .read = pnv_core_power9_xscom_read,
167     .write = pnv_core_power9_xscom_write,
168     .valid.min_access_size = 8,
169     .valid.max_access_size = 8,
170     .impl.min_access_size = 8,
171     .impl.max_access_size = 8,
172     .endianness = DEVICE_BIG_ENDIAN,
173 };
174 
175 /*
176  * POWER10 core controls
177  */
178 
179 #define PNV10_XSCOM_EC_CORE_THREAD_STATE    0x412
180 
181 static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
182                                            unsigned int width)
183 {
184     uint32_t offset = addr >> 3;
185     uint64_t val = 0;
186 
187     switch (offset) {
188     case PNV10_XSCOM_EC_CORE_THREAD_STATE:
189         val = 0;
190         break;
191     default:
192         qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n",
193                   addr);
194     }
195 
196     return val;
197 }
198 
199 static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
200                                          uint64_t val, unsigned int width)
201 {
202     uint32_t offset = addr >> 3;
203 
204     switch (offset) {
205     default:
206         qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n",
207                       addr);
208     }
209 }
210 
211 static const MemoryRegionOps pnv_core_power10_xscom_ops = {
212     .read = pnv_core_power10_xscom_read,
213     .write = pnv_core_power10_xscom_write,
214     .valid.min_access_size = 8,
215     .valid.max_access_size = 8,
216     .impl.min_access_size = 8,
217     .impl.max_access_size = 8,
218     .endianness = DEVICE_BIG_ENDIAN,
219 };
220 
221 static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp)
222 {
223     CPUPPCState *env = &cpu->env;
224     int core_pir;
225     int thread_index = 0; /* TODO: TCG supports only one thread */
226     ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
227     Error *local_err = NULL;
228     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
229 
230     if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
231         return;
232     }
233 
234     pcc->intc_create(pc->chip, cpu, &local_err);
235     if (local_err) {
236         error_propagate(errp, local_err);
237         return;
238     }
239 
240     core_pir = object_property_get_uint(OBJECT(pc), "pir", &error_abort);
241 
242     /*
243      * The PIR of a thread is the core PIR + the thread index. We will
244      * need to find a way to get the thread index when TCG supports
245      * more than 1. We could use the object name ?
246      */
247     pir->default_value = core_pir + thread_index;
248 
249     /* Set time-base frequency to 512 MHz */
250     cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
251 }
252 
253 static void pnv_core_reset(void *dev)
254 {
255     CPUCore *cc = CPU_CORE(dev);
256     PnvCore *pc = PNV_CORE(dev);
257     int i;
258 
259     for (i = 0; i < cc->nr_threads; i++) {
260         pnv_core_cpu_reset(pc, pc->threads[i]);
261     }
262 }
263 
264 static void pnv_core_realize(DeviceState *dev, Error **errp)
265 {
266     PnvCore *pc = PNV_CORE(OBJECT(dev));
267     PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
268     CPUCore *cc = CPU_CORE(OBJECT(dev));
269     const char *typename = pnv_core_cpu_typename(pc);
270     Error *local_err = NULL;
271     void *obj;
272     int i, j;
273     char name[32];
274 
275     assert(pc->chip);
276 
277     pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
278     for (i = 0; i < cc->nr_threads; i++) {
279         PowerPCCPU *cpu;
280 
281         obj = object_new(typename);
282         cpu = POWERPC_CPU(obj);
283 
284         pc->threads[i] = POWERPC_CPU(obj);
285 
286         snprintf(name, sizeof(name), "thread[%d]", i);
287         object_property_add_child(OBJECT(pc), name, obj);
288 
289         cpu->machine_data = g_new0(PnvCPUState, 1);
290 
291         object_unref(obj);
292     }
293 
294     for (j = 0; j < cc->nr_threads; j++) {
295         pnv_core_cpu_realize(pc, pc->threads[j], &local_err);
296         if (local_err) {
297             goto err;
298         }
299     }
300 
301     snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
302     /* TODO: check PNV_XSCOM_EX_SIZE for p10 */
303     pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
304                           pc, name, PNV_XSCOM_EX_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("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(),
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 }
357 
358 static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
359 {
360     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
361 
362     pcc->xscom_ops = &pnv_core_power9_xscom_ops;
363 }
364 
365 static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
366 {
367     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
368 
369     pcc->xscom_ops = &pnv_core_power10_xscom_ops;
370 }
371 
372 static void pnv_core_class_init(ObjectClass *oc, void *data)
373 {
374     DeviceClass *dc = DEVICE_CLASS(oc);
375 
376     dc->realize = pnv_core_realize;
377     dc->unrealize = pnv_core_unrealize;
378     device_class_set_props(dc, pnv_core_properties);
379     dc->user_creatable = false;
380 }
381 
382 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
383     {                                           \
384         .parent = TYPE_PNV_CORE,                \
385         .name = PNV_CORE_TYPE_NAME(cpu_model),  \
386         .class_init = pnv_core_##family##_class_init, \
387     }
388 
389 static const TypeInfo pnv_core_infos[] = {
390     {
391         .name           = TYPE_PNV_CORE,
392         .parent         = TYPE_CPU_CORE,
393         .instance_size  = sizeof(PnvCore),
394         .class_size     = sizeof(PnvCoreClass),
395         .class_init = pnv_core_class_init,
396         .abstract       = true,
397     },
398     DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
399     DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
400     DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
401     DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"),
402     DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"),
403 };
404 
405 DEFINE_TYPES(pnv_core_infos)
406 
407 /*
408  * POWER9 Quads
409  */
410 
411 #define P9X_EX_NCU_SPEC_BAR                     0x11010
412 
413 static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
414                                            unsigned int width)
415 {
416     uint32_t offset = addr >> 3;
417     uint64_t val = -1;
418 
419     switch (offset) {
420     case P9X_EX_NCU_SPEC_BAR:
421     case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
422         val = 0;
423         break;
424     default:
425         qemu_log_mask(LOG_UNIMP, "%s: reading @0x%08x\n", __func__,
426                       offset);
427     }
428 
429     return val;
430 }
431 
432 static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
433                                         unsigned int width)
434 {
435     uint32_t offset = addr >> 3;
436 
437     switch (offset) {
438     case P9X_EX_NCU_SPEC_BAR:
439     case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
440         break;
441     default:
442         qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
443                   offset);
444     }
445 }
446 
447 static const MemoryRegionOps pnv_quad_power9_xscom_ops = {
448     .read = pnv_quad_power9_xscom_read,
449     .write = pnv_quad_power9_xscom_write,
450     .valid.min_access_size = 8,
451     .valid.max_access_size = 8,
452     .impl.min_access_size = 8,
453     .impl.max_access_size = 8,
454     .endianness = DEVICE_BIG_ENDIAN,
455 };
456 
457 /*
458  * POWER10 Quads
459  */
460 
461 static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
462                                             unsigned int width)
463 {
464     uint32_t offset = addr >> 3;
465     uint64_t val = -1;
466 
467     switch (offset) {
468     default:
469         qemu_log_mask(LOG_UNIMP, "%s: reading @0x%08x\n", __func__,
470                       offset);
471     }
472 
473     return val;
474 }
475 
476 static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
477                                          uint64_t val, unsigned int width)
478 {
479     uint32_t offset = addr >> 3;
480 
481     switch (offset) {
482     default:
483         qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__,
484                       offset);
485     }
486 }
487 
488 static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
489     .read = pnv_quad_power10_xscom_read,
490     .write = pnv_quad_power10_xscom_write,
491     .valid.min_access_size = 8,
492     .valid.max_access_size = 8,
493     .impl.min_access_size = 8,
494     .impl.max_access_size = 8,
495     .endianness = DEVICE_BIG_ENDIAN,
496 };
497 
498 static void pnv_quad_realize(DeviceState *dev, Error **errp)
499 {
500     PnvQuad *eq = PNV_QUAD(dev);
501     PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
502     char name[32];
503 
504     snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
505     pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
506                           pqc->xscom_ops,
507                           eq, name,
508                           pqc->xscom_size);
509 }
510 
511 static Property pnv_quad_properties[] = {
512     DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
513     DEFINE_PROP_END_OF_LIST(),
514 };
515 
516 static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
517 {
518     PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
519 
520     pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
521     pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
522 }
523 
524 static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
525 {
526     PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
527 
528     pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
529     pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
530 }
531 
532 static void pnv_quad_class_init(ObjectClass *oc, void *data)
533 {
534     DeviceClass *dc = DEVICE_CLASS(oc);
535 
536     dc->realize = pnv_quad_realize;
537     device_class_set_props(dc, pnv_quad_properties);
538     dc->user_creatable = false;
539 }
540 
541 static const TypeInfo pnv_quad_infos[] = {
542     {
543         .name          = TYPE_PNV_QUAD,
544         .parent        = TYPE_DEVICE,
545         .instance_size = sizeof(PnvQuad),
546         .class_size    = sizeof(PnvQuadClass),
547         .class_init    = pnv_quad_class_init,
548         .abstract      = true,
549     },
550     {
551         .parent = TYPE_PNV_QUAD,
552         .name = PNV_QUAD_TYPE_NAME("power9"),
553         .class_init = pnv_quad_power9_class_init,
554     },
555     {
556         .parent = TYPE_PNV_QUAD,
557         .name = PNV_QUAD_TYPE_NAME("power10"),
558         .class_init = pnv_quad_power10_class_init,
559     },
560 };
561 
562 DEFINE_TYPES(pnv_quad_infos);
563