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