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 "system/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
pnv_core_cpu_typename(PnvCore * pc)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
pnv_core_cpu_reset(PnvCore * pc,PowerPCCPU * cpu)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 if (pc->big_core) {
62 /* Clear "small core" bit on Power9/10 (this is set in default PVR) */
63 env->spr[SPR_PVR] &= ~PPC_BIT(51);
64 }
65 hreg_compute_hflags(env);
66 ppc_maybe_interrupt(env);
67
68 cpu_ppc_tb_reset(env);
69
70 pcc->intc_reset(pc->chip, cpu);
71 }
72
73 /*
74 * These values are read by the PowerNV HW monitors under Linux
75 */
76 #define PNV_XSCOM_EX_DTS_RESULT0 0x50000
77 #define PNV_XSCOM_EX_DTS_RESULT1 0x50001
78
pnv_core_power8_xscom_read(void * opaque,hwaddr addr,unsigned int width)79 static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr,
80 unsigned int width)
81 {
82 uint32_t offset = addr >> 3;
83 uint64_t val = 0;
84
85 /* The result should be 38 C */
86 switch (offset) {
87 case PNV_XSCOM_EX_DTS_RESULT0:
88 val = 0x26f024f023f0000ull;
89 break;
90 case PNV_XSCOM_EX_DTS_RESULT1:
91 val = 0x24f000000000000ull;
92 break;
93 default:
94 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
95 offset);
96 }
97
98 return val;
99 }
100
pnv_core_power8_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)101 static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val,
102 unsigned int width)
103 {
104 uint32_t offset = addr >> 3;
105
106 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
107 offset);
108 }
109
110 static const MemoryRegionOps pnv_core_power8_xscom_ops = {
111 .read = pnv_core_power8_xscom_read,
112 .write = pnv_core_power8_xscom_write,
113 .valid.min_access_size = 8,
114 .valid.max_access_size = 8,
115 .impl.min_access_size = 8,
116 .impl.max_access_size = 8,
117 .endianness = DEVICE_BIG_ENDIAN,
118 };
119
120
121 /*
122 * POWER9 core controls
123 */
124 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d
125 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a
126
127 #define PNV9_XSCOM_EC_CORE_THREAD_STATE 0x10ab3
128
pnv_core_power9_xscom_read(void * opaque,hwaddr addr,unsigned int width)129 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr,
130 unsigned int width)
131 {
132 uint32_t offset = addr >> 3;
133 uint64_t val = 0;
134
135 /* The result should be 38 C */
136 switch (offset) {
137 case PNV_XSCOM_EX_DTS_RESULT0:
138 val = 0x26f024f023f0000ull;
139 break;
140 case PNV_XSCOM_EX_DTS_RESULT1:
141 val = 0x24f000000000000ull;
142 break;
143 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
144 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
145 val = 0x0;
146 break;
147 case PNV9_XSCOM_EC_CORE_THREAD_STATE:
148 val = 0;
149 break;
150 default:
151 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
152 offset);
153 }
154
155 return val;
156 }
157
pnv_core_power9_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)158 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
159 unsigned int width)
160 {
161 uint32_t offset = addr >> 3;
162
163 switch (offset) {
164 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP:
165 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR:
166 break;
167 default:
168 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
169 offset);
170 }
171 }
172
173 static const MemoryRegionOps pnv_core_power9_xscom_ops = {
174 .read = pnv_core_power9_xscom_read,
175 .write = pnv_core_power9_xscom_write,
176 .valid.min_access_size = 8,
177 .valid.max_access_size = 8,
178 .impl.min_access_size = 8,
179 .impl.max_access_size = 8,
180 .endianness = DEVICE_BIG_ENDIAN,
181 };
182
183 /*
184 * POWER10 core controls
185 */
186
187 #define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412
188 #define PNV10_XSCOM_EC_CORE_THREAD_INFO 0x413
189 #define PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS 0x449
190 #define PNV10_XSCOM_EC_CORE_RAS_STATUS 0x454
191
pnv_core_power10_xscom_read(void * opaque,hwaddr addr,unsigned int width)192 static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
193 unsigned int width)
194 {
195 PnvCore *pc = PNV_CORE(opaque);
196 int nr_threads = CPU_CORE(pc)->nr_threads;
197 int i;
198 uint32_t offset = addr >> 3;
199 uint64_t val = 0;
200
201 switch (offset) {
202 case PNV10_XSCOM_EC_CORE_THREAD_STATE:
203 for (i = 0; i < nr_threads; i++) {
204 PowerPCCPU *cpu = pc->threads[i];
205 CPUState *cs = CPU(cpu);
206
207 if (cs->halted) {
208 val |= PPC_BIT(56 + i);
209 }
210 }
211 if (pc->lpar_per_core) {
212 val |= PPC_BIT(62);
213 }
214 break;
215 case PNV10_XSCOM_EC_CORE_THREAD_INFO:
216 break;
217 case PNV10_XSCOM_EC_CORE_RAS_STATUS:
218 for (i = 0; i < nr_threads; i++) {
219 PowerPCCPU *cpu = pc->threads[i];
220 CPUPPCState *env = &cpu->env;
221 if (env->quiesced) {
222 val |= PPC_BIT(0 + 8 * i) | PPC_BIT(1 + 8 * i);
223 }
224 }
225 break;
226 default:
227 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
228 offset);
229 }
230
231 return val;
232 }
233
pnv_core_power10_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)234 static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
235 uint64_t val, unsigned int width)
236 {
237 PnvCore *pc = PNV_CORE(opaque);
238 int nr_threads = CPU_CORE(pc)->nr_threads;
239 int i;
240 uint32_t offset = addr >> 3;
241
242 switch (offset) {
243 case PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS:
244 for (i = 0; i < nr_threads; i++) {
245 PowerPCCPU *cpu = pc->threads[i];
246 CPUState *cs = CPU(cpu);
247 CPUPPCState *env = &cpu->env;
248
249 if (val & PPC_BIT(7 + 8 * i)) { /* stop */
250 val &= ~PPC_BIT(7 + 8 * i);
251 env->quiesced = true;
252 ppc_maybe_interrupt(env);
253 cpu_pause(cs);
254 }
255 if (val & PPC_BIT(6 + 8 * i)) { /* start */
256 val &= ~PPC_BIT(6 + 8 * i);
257 env->quiesced = false;
258 ppc_maybe_interrupt(env);
259 cpu_resume(cs);
260 }
261 if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
262 val &= ~PPC_BIT(4 + 8 * i);
263 env->quiesced = false;
264 ppc_maybe_interrupt(env);
265 pnv_cpu_do_nmi_resume(cs);
266 }
267 if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
268 env->quiesced = false;
269 ppc_maybe_interrupt(env);
270 /*
271 * Hardware has very particular cases for where clear maint
272 * must be used and where start must be used to resume a
273 * thread. These are not modelled exactly, just treat
274 * this and start the same.
275 */
276 val &= ~PPC_BIT(3 + 8 * i);
277 cpu_resume(cs);
278 }
279 }
280 if (val) {
281 qemu_log_mask(LOG_UNIMP, "%s: unimp bits in DIRECT_CONTROLS "
282 "0x%016" PRIx64 "\n", __func__, val);
283 }
284 break;
285
286 default:
287 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
288 offset);
289 }
290 }
291
292 static const MemoryRegionOps pnv_core_power10_xscom_ops = {
293 .read = pnv_core_power10_xscom_read,
294 .write = pnv_core_power10_xscom_write,
295 .valid.min_access_size = 8,
296 .valid.max_access_size = 8,
297 .impl.min_access_size = 8,
298 .impl.max_access_size = 8,
299 .endianness = DEVICE_BIG_ENDIAN,
300 };
301
pnv_core_cpu_realize(PnvCore * pc,PowerPCCPU * cpu,Error ** errp,int thread_index)302 static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
303 int thread_index)
304 {
305 CPUPPCState *env = &cpu->env;
306 int core_hwid;
307 ppc_spr_t *pir_spr = &env->spr_cb[SPR_PIR];
308 ppc_spr_t *tir_spr = &env->spr_cb[SPR_TIR];
309 uint32_t pir, tir;
310 Error *local_err = NULL;
311 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
312
313 if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
314 return;
315 }
316
317 pcc->intc_create(pc->chip, cpu, &local_err);
318 if (local_err) {
319 error_propagate(errp, local_err);
320 return;
321 }
322
323 core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
324
325 pcc->get_pir_tir(pc->chip, core_hwid, thread_index, &pir, &tir);
326 pir_spr->default_value = pir;
327 tir_spr->default_value = tir;
328
329 env->chip_index = pc->chip->chip_id;
330
331 if (pc->big_core) {
332 /* 2 "small cores" get the same core index for SMT operations */
333 env->core_index = core_hwid >> 1;
334 } else {
335 env->core_index = core_hwid;
336 }
337
338 if (pc->lpar_per_core) {
339 cpu_ppc_set_1lpar(cpu);
340 }
341
342 /* Set time-base frequency to 512 MHz */
343 cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
344 }
345
pnv_core_reset(void * dev)346 static void pnv_core_reset(void *dev)
347 {
348 CPUCore *cc = CPU_CORE(dev);
349 PnvCore *pc = PNV_CORE(dev);
350 int i;
351
352 for (i = 0; i < cc->nr_threads; i++) {
353 pnv_core_cpu_reset(pc, pc->threads[i]);
354 }
355 }
356
pnv_core_realize(DeviceState * dev,Error ** errp)357 static void pnv_core_realize(DeviceState *dev, Error **errp)
358 {
359 PnvCore *pc = PNV_CORE(OBJECT(dev));
360 PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
361 CPUCore *cc = CPU_CORE(OBJECT(dev));
362 const char *typename = pnv_core_cpu_typename(pc);
363 Error *local_err = NULL;
364 void *obj;
365 int i, j;
366 char name[32];
367
368 assert(pc->chip);
369
370 pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
371 for (i = 0; i < cc->nr_threads; i++) {
372 PowerPCCPU *cpu;
373 PnvCPUState *pnv_cpu;
374
375 obj = object_new(typename);
376 cpu = POWERPC_CPU(obj);
377
378 pc->threads[i] = POWERPC_CPU(obj);
379 if (cc->nr_threads > 1) {
380 cpu->env.has_smt_siblings = true;
381 }
382
383 snprintf(name, sizeof(name), "thread[%d]", i);
384 object_property_add_child(OBJECT(pc), name, obj);
385
386 cpu->machine_data = g_new0(PnvCPUState, 1);
387 pnv_cpu = pnv_cpu_state(cpu);
388 pnv_cpu->pnv_core = pc;
389
390 object_unref(obj);
391 }
392
393 for (j = 0; j < cc->nr_threads; j++) {
394 pnv_core_cpu_realize(pc, pc->threads[j], &local_err, j);
395 if (local_err) {
396 goto err;
397 }
398 }
399
400 snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
401 pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
402 pc, name, pcc->xscom_size);
403
404 qemu_register_reset(pnv_core_reset, pc);
405 return;
406
407 err:
408 while (--i >= 0) {
409 obj = OBJECT(pc->threads[i]);
410 object_unparent(obj);
411 }
412 g_free(pc->threads);
413 error_propagate(errp, local_err);
414 }
415
pnv_core_cpu_unrealize(PnvCore * pc,PowerPCCPU * cpu)416 static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu)
417 {
418 PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
419 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
420
421 pcc->intc_destroy(pc->chip, cpu);
422 cpu_remove_sync(CPU(cpu));
423 cpu->machine_data = NULL;
424 g_free(pnv_cpu);
425 object_unparent(OBJECT(cpu));
426 }
427
pnv_core_unrealize(DeviceState * dev)428 static void pnv_core_unrealize(DeviceState *dev)
429 {
430 PnvCore *pc = PNV_CORE(dev);
431 CPUCore *cc = CPU_CORE(dev);
432 int i;
433
434 qemu_unregister_reset(pnv_core_reset, pc);
435
436 for (i = 0; i < cc->nr_threads; i++) {
437 pnv_core_cpu_unrealize(pc, pc->threads[i]);
438 }
439 g_free(pc->threads);
440 }
441
442 static const Property pnv_core_properties[] = {
443 DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
444 DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
445 DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
446 DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
447 false),
448 DEFINE_PROP_BOOL("lpar-per-core", PnvCore, lpar_per_core, false),
449 DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
450 };
451
pnv_core_power8_class_init(ObjectClass * oc,const void * data)452 static void pnv_core_power8_class_init(ObjectClass *oc, const void *data)
453 {
454 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
455
456 pcc->xscom_ops = &pnv_core_power8_xscom_ops;
457 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
458 }
459
pnv_core_power9_class_init(ObjectClass * oc,const void * data)460 static void pnv_core_power9_class_init(ObjectClass *oc, const void *data)
461 {
462 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
463
464 pcc->xscom_ops = &pnv_core_power9_xscom_ops;
465 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
466 }
467
pnv_core_power10_class_init(ObjectClass * oc,const void * data)468 static void pnv_core_power10_class_init(ObjectClass *oc, const void *data)
469 {
470 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
471
472 pcc->xscom_ops = &pnv_core_power10_xscom_ops;
473 pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
474 }
475
pnv_core_class_init(ObjectClass * oc,const void * data)476 static void pnv_core_class_init(ObjectClass *oc, const void *data)
477 {
478 DeviceClass *dc = DEVICE_CLASS(oc);
479
480 dc->realize = pnv_core_realize;
481 dc->unrealize = pnv_core_unrealize;
482 device_class_set_props(dc, pnv_core_properties);
483 dc->user_creatable = false;
484 }
485
486 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
487 { \
488 .parent = TYPE_PNV_CORE, \
489 .name = PNV_CORE_TYPE_NAME(cpu_model), \
490 .class_init = pnv_core_##family##_class_init, \
491 }
492
493 static const TypeInfo pnv_core_infos[] = {
494 {
495 .name = TYPE_PNV_CORE,
496 .parent = TYPE_CPU_CORE,
497 .instance_size = sizeof(PnvCore),
498 .class_size = sizeof(PnvCoreClass),
499 .class_init = pnv_core_class_init,
500 .abstract = true,
501 },
502 DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
503 DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
504 DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
505 DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"),
506 DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"),
507 };
508
DEFINE_TYPES(pnv_core_infos)509 DEFINE_TYPES(pnv_core_infos)
510
511 /*
512 * POWER9 Quads
513 */
514
515 #define P9X_EX_NCU_SPEC_BAR 0x11010
516
517 static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
518 unsigned int width)
519 {
520 uint32_t offset = addr >> 3;
521 uint64_t val = -1;
522
523 switch (offset) {
524 case P9X_EX_NCU_SPEC_BAR:
525 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
526 val = 0;
527 break;
528 default:
529 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
530 offset);
531 }
532
533 return val;
534 }
535
pnv_quad_power9_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)536 static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
537 unsigned int width)
538 {
539 uint32_t offset = addr >> 3;
540
541 switch (offset) {
542 case P9X_EX_NCU_SPEC_BAR:
543 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
544 break;
545 default:
546 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
547 offset);
548 }
549 }
550
551 static const MemoryRegionOps pnv_quad_power9_xscom_ops = {
552 .read = pnv_quad_power9_xscom_read,
553 .write = pnv_quad_power9_xscom_write,
554 .valid.min_access_size = 8,
555 .valid.max_access_size = 8,
556 .impl.min_access_size = 8,
557 .impl.max_access_size = 8,
558 .endianness = DEVICE_BIG_ENDIAN,
559 };
560
561 /*
562 * POWER10 Quads
563 */
564
pnv_quad_power10_xscom_read(void * opaque,hwaddr addr,unsigned int width)565 static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
566 unsigned int width)
567 {
568 uint32_t offset = addr >> 3;
569 uint64_t val = -1;
570
571 switch (offset) {
572 default:
573 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
574 offset);
575 }
576
577 return val;
578 }
579
pnv_quad_power10_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)580 static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
581 uint64_t val, unsigned int width)
582 {
583 uint32_t offset = addr >> 3;
584
585 switch (offset) {
586 default:
587 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
588 offset);
589 }
590 }
591
592 static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
593 .read = pnv_quad_power10_xscom_read,
594 .write = pnv_quad_power10_xscom_write,
595 .valid.min_access_size = 8,
596 .valid.max_access_size = 8,
597 .impl.min_access_size = 8,
598 .impl.max_access_size = 8,
599 .endianness = DEVICE_BIG_ENDIAN,
600 };
601
602 #define P10_QME_SPWU_HYP 0x83c
603 #define P10_QME_SSH_HYP 0x82c
604
pnv_qme_power10_xscom_read(void * opaque,hwaddr addr,unsigned int width)605 static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
606 unsigned int width)
607 {
608 PnvQuad *eq = PNV_QUAD(opaque);
609 uint32_t offset = addr >> 3;
610 uint64_t val = -1;
611
612 /*
613 * Forth nibble selects the core within a quad, mask it to process read
614 * for any core.
615 */
616 switch (offset & ~PPC_BITMASK32(16, 19)) {
617 case P10_QME_SSH_HYP:
618 val = 0;
619 if (eq->special_wakeup_done) {
620 val |= PPC_BIT(1); /* SPWU DONE */
621 val |= PPC_BIT(4); /* SSH SPWU DONE */
622 }
623 break;
624 default:
625 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
626 offset);
627 }
628
629 return val;
630 }
631
pnv_qme_power10_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)632 static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
633 uint64_t val, unsigned int width)
634 {
635 PnvQuad *eq = PNV_QUAD(opaque);
636 uint32_t offset = addr >> 3;
637 bool set;
638 int i;
639
640 switch (offset & ~PPC_BITMASK32(16, 19)) {
641 case P10_QME_SPWU_HYP:
642 set = !!(val & PPC_BIT(0));
643 eq->special_wakeup_done = set;
644 for (i = 0; i < 4; i++) {
645 /* These bits select cores in the quad */
646 if (offset & PPC_BIT32(16 + i)) {
647 eq->special_wakeup[i] = set;
648 }
649 }
650 break;
651 default:
652 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
653 offset);
654 }
655 }
656
657 static const MemoryRegionOps pnv_qme_power10_xscom_ops = {
658 .read = pnv_qme_power10_xscom_read,
659 .write = pnv_qme_power10_xscom_write,
660 .valid.min_access_size = 8,
661 .valid.max_access_size = 8,
662 .impl.min_access_size = 8,
663 .impl.max_access_size = 8,
664 .endianness = DEVICE_BIG_ENDIAN,
665 };
666
pnv_quad_power9_realize(DeviceState * dev,Error ** errp)667 static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
668 {
669 PnvQuad *eq = PNV_QUAD(dev);
670 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
671 char name[32];
672
673 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
674 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
675 pqc->xscom_ops,
676 eq, name,
677 pqc->xscom_size);
678 }
679
pnv_quad_power10_realize(DeviceState * dev,Error ** errp)680 static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
681 {
682 PnvQuad *eq = PNV_QUAD(dev);
683 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
684 char name[32];
685
686 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
687 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
688 pqc->xscom_ops,
689 eq, name,
690 pqc->xscom_size);
691
692 snprintf(name, sizeof(name), "xscom-qme.%d", eq->quad_id);
693 pnv_xscom_region_init(&eq->xscom_qme_regs, OBJECT(dev),
694 pqc->xscom_qme_ops,
695 eq, name,
696 pqc->xscom_qme_size);
697 }
698
699 static const Property pnv_quad_properties[] = {
700 DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
701 };
702
pnv_quad_power9_class_init(ObjectClass * oc,const void * data)703 static void pnv_quad_power9_class_init(ObjectClass *oc, const void *data)
704 {
705 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
706 DeviceClass *dc = DEVICE_CLASS(oc);
707
708 dc->realize = pnv_quad_power9_realize;
709
710 pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
711 pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
712 }
713
pnv_quad_power10_class_init(ObjectClass * oc,const void * data)714 static void pnv_quad_power10_class_init(ObjectClass *oc, const void *data)
715 {
716 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
717 DeviceClass *dc = DEVICE_CLASS(oc);
718
719 dc->realize = pnv_quad_power10_realize;
720
721 pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
722 pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
723
724 pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
725 pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
726 }
727
pnv_quad_class_init(ObjectClass * oc,const void * data)728 static void pnv_quad_class_init(ObjectClass *oc, const void *data)
729 {
730 DeviceClass *dc = DEVICE_CLASS(oc);
731
732 device_class_set_props(dc, pnv_quad_properties);
733 dc->user_creatable = false;
734 }
735
736 static const TypeInfo pnv_quad_infos[] = {
737 {
738 .name = TYPE_PNV_QUAD,
739 .parent = TYPE_DEVICE,
740 .instance_size = sizeof(PnvQuad),
741 .class_size = sizeof(PnvQuadClass),
742 .class_init = pnv_quad_class_init,
743 .abstract = true,
744 },
745 {
746 .parent = TYPE_PNV_QUAD,
747 .name = PNV_QUAD_TYPE_NAME("power9"),
748 .class_init = pnv_quad_power9_class_init,
749 },
750 {
751 .parent = TYPE_PNV_QUAD,
752 .name = PNV_QUAD_TYPE_NAME("power10"),
753 .class_init = pnv_quad_power10_class_init,
754 },
755 };
756
757 DEFINE_TYPES(pnv_quad_infos);
758