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
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 cpu_pause(cs);
252 env->quiesced = true;
253 }
254 if (val & PPC_BIT(6 + 8 * i)) { /* start */
255 val &= ~PPC_BIT(6 + 8 * i);
256 env->quiesced = false;
257 cpu_resume(cs);
258 }
259 if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
260 val &= ~PPC_BIT(4 + 8 * i);
261 env->quiesced = false;
262 pnv_cpu_do_nmi_resume(cs);
263 }
264 if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
265 env->quiesced = false;
266 /*
267 * Hardware has very particular cases for where clear maint
268 * must be used and where start must be used to resume a
269 * thread. These are not modelled exactly, just treat
270 * this and start the same.
271 */
272 val &= ~PPC_BIT(3 + 8 * i);
273 cpu_resume(cs);
274 }
275 }
276 if (val) {
277 qemu_log_mask(LOG_UNIMP, "%s: unimp bits in DIRECT_CONTROLS "
278 "0x%016" PRIx64 "\n", __func__, val);
279 }
280 break;
281
282 default:
283 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
284 offset);
285 }
286 }
287
288 static const MemoryRegionOps pnv_core_power10_xscom_ops = {
289 .read = pnv_core_power10_xscom_read,
290 .write = pnv_core_power10_xscom_write,
291 .valid.min_access_size = 8,
292 .valid.max_access_size = 8,
293 .impl.min_access_size = 8,
294 .impl.max_access_size = 8,
295 .endianness = DEVICE_BIG_ENDIAN,
296 };
297
pnv_core_cpu_realize(PnvCore * pc,PowerPCCPU * cpu,Error ** errp,int thread_index)298 static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
299 int thread_index)
300 {
301 CPUPPCState *env = &cpu->env;
302 int core_hwid;
303 ppc_spr_t *pir_spr = &env->spr_cb[SPR_PIR];
304 ppc_spr_t *tir_spr = &env->spr_cb[SPR_TIR];
305 uint32_t pir, tir;
306 Error *local_err = NULL;
307 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
308
309 if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
310 return;
311 }
312
313 pcc->intc_create(pc->chip, cpu, &local_err);
314 if (local_err) {
315 error_propagate(errp, local_err);
316 return;
317 }
318
319 core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
320
321 pcc->get_pir_tir(pc->chip, core_hwid, thread_index, &pir, &tir);
322 pir_spr->default_value = pir;
323 tir_spr->default_value = tir;
324
325 env->chip_index = pc->chip->chip_id;
326
327 if (pc->big_core) {
328 /* 2 "small cores" get the same core index for SMT operations */
329 env->core_index = core_hwid >> 1;
330 } else {
331 env->core_index = core_hwid;
332 }
333
334 if (pc->lpar_per_core) {
335 cpu_ppc_set_1lpar(cpu);
336 }
337
338 /* Set time-base frequency to 512 MHz */
339 cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
340 }
341
pnv_core_reset(void * dev)342 static void pnv_core_reset(void *dev)
343 {
344 CPUCore *cc = CPU_CORE(dev);
345 PnvCore *pc = PNV_CORE(dev);
346 int i;
347
348 for (i = 0; i < cc->nr_threads; i++) {
349 pnv_core_cpu_reset(pc, pc->threads[i]);
350 }
351 }
352
pnv_core_realize(DeviceState * dev,Error ** errp)353 static void pnv_core_realize(DeviceState *dev, Error **errp)
354 {
355 PnvCore *pc = PNV_CORE(OBJECT(dev));
356 PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc);
357 CPUCore *cc = CPU_CORE(OBJECT(dev));
358 const char *typename = pnv_core_cpu_typename(pc);
359 Error *local_err = NULL;
360 void *obj;
361 int i, j;
362 char name[32];
363
364 assert(pc->chip);
365
366 pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
367 for (i = 0; i < cc->nr_threads; i++) {
368 PowerPCCPU *cpu;
369 PnvCPUState *pnv_cpu;
370
371 obj = object_new(typename);
372 cpu = POWERPC_CPU(obj);
373
374 pc->threads[i] = POWERPC_CPU(obj);
375 if (cc->nr_threads > 1) {
376 cpu->env.has_smt_siblings = true;
377 }
378
379 snprintf(name, sizeof(name), "thread[%d]", i);
380 object_property_add_child(OBJECT(pc), name, obj);
381
382 cpu->machine_data = g_new0(PnvCPUState, 1);
383 pnv_cpu = pnv_cpu_state(cpu);
384 pnv_cpu->pnv_core = pc;
385
386 object_unref(obj);
387 }
388
389 for (j = 0; j < cc->nr_threads; j++) {
390 pnv_core_cpu_realize(pc, pc->threads[j], &local_err, j);
391 if (local_err) {
392 goto err;
393 }
394 }
395
396 snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id);
397 pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops,
398 pc, name, pcc->xscom_size);
399
400 qemu_register_reset(pnv_core_reset, pc);
401 return;
402
403 err:
404 while (--i >= 0) {
405 obj = OBJECT(pc->threads[i]);
406 object_unparent(obj);
407 }
408 g_free(pc->threads);
409 error_propagate(errp, local_err);
410 }
411
pnv_core_cpu_unrealize(PnvCore * pc,PowerPCCPU * cpu)412 static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu)
413 {
414 PnvCPUState *pnv_cpu = pnv_cpu_state(cpu);
415 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
416
417 pcc->intc_destroy(pc->chip, cpu);
418 cpu_remove_sync(CPU(cpu));
419 cpu->machine_data = NULL;
420 g_free(pnv_cpu);
421 object_unparent(OBJECT(cpu));
422 }
423
pnv_core_unrealize(DeviceState * dev)424 static void pnv_core_unrealize(DeviceState *dev)
425 {
426 PnvCore *pc = PNV_CORE(dev);
427 CPUCore *cc = CPU_CORE(dev);
428 int i;
429
430 qemu_unregister_reset(pnv_core_reset, pc);
431
432 for (i = 0; i < cc->nr_threads; i++) {
433 pnv_core_cpu_unrealize(pc, pc->threads[i]);
434 }
435 g_free(pc->threads);
436 }
437
438 static Property pnv_core_properties[] = {
439 DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
440 DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
441 DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
442 DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
443 false),
444 DEFINE_PROP_BOOL("lpar-per-core", PnvCore, lpar_per_core, false),
445 DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
446 DEFINE_PROP_END_OF_LIST(),
447 };
448
pnv_core_power8_class_init(ObjectClass * oc,void * data)449 static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
450 {
451 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
452
453 pcc->xscom_ops = &pnv_core_power8_xscom_ops;
454 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
455 }
456
pnv_core_power9_class_init(ObjectClass * oc,void * data)457 static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
458 {
459 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
460
461 pcc->xscom_ops = &pnv_core_power9_xscom_ops;
462 pcc->xscom_size = PNV_XSCOM_EX_SIZE;
463 }
464
pnv_core_power10_class_init(ObjectClass * oc,void * data)465 static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
466 {
467 PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
468
469 pcc->xscom_ops = &pnv_core_power10_xscom_ops;
470 pcc->xscom_size = PNV10_XSCOM_EC_SIZE;
471 }
472
pnv_core_class_init(ObjectClass * oc,void * data)473 static void pnv_core_class_init(ObjectClass *oc, void *data)
474 {
475 DeviceClass *dc = DEVICE_CLASS(oc);
476
477 dc->realize = pnv_core_realize;
478 dc->unrealize = pnv_core_unrealize;
479 device_class_set_props(dc, pnv_core_properties);
480 dc->user_creatable = false;
481 }
482
483 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
484 { \
485 .parent = TYPE_PNV_CORE, \
486 .name = PNV_CORE_TYPE_NAME(cpu_model), \
487 .class_init = pnv_core_##family##_class_init, \
488 }
489
490 static const TypeInfo pnv_core_infos[] = {
491 {
492 .name = TYPE_PNV_CORE,
493 .parent = TYPE_CPU_CORE,
494 .instance_size = sizeof(PnvCore),
495 .class_size = sizeof(PnvCoreClass),
496 .class_init = pnv_core_class_init,
497 .abstract = true,
498 },
499 DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"),
500 DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"),
501 DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"),
502 DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"),
503 DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"),
504 };
505
DEFINE_TYPES(pnv_core_infos)506 DEFINE_TYPES(pnv_core_infos)
507
508 /*
509 * POWER9 Quads
510 */
511
512 #define P9X_EX_NCU_SPEC_BAR 0x11010
513
514 static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr,
515 unsigned int width)
516 {
517 uint32_t offset = addr >> 3;
518 uint64_t val = -1;
519
520 switch (offset) {
521 case P9X_EX_NCU_SPEC_BAR:
522 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
523 val = 0;
524 break;
525 default:
526 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
527 offset);
528 }
529
530 return val;
531 }
532
pnv_quad_power9_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)533 static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val,
534 unsigned int width)
535 {
536 uint32_t offset = addr >> 3;
537
538 switch (offset) {
539 case P9X_EX_NCU_SPEC_BAR:
540 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */
541 break;
542 default:
543 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
544 offset);
545 }
546 }
547
548 static const MemoryRegionOps pnv_quad_power9_xscom_ops = {
549 .read = pnv_quad_power9_xscom_read,
550 .write = pnv_quad_power9_xscom_write,
551 .valid.min_access_size = 8,
552 .valid.max_access_size = 8,
553 .impl.min_access_size = 8,
554 .impl.max_access_size = 8,
555 .endianness = DEVICE_BIG_ENDIAN,
556 };
557
558 /*
559 * POWER10 Quads
560 */
561
pnv_quad_power10_xscom_read(void * opaque,hwaddr addr,unsigned int width)562 static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr,
563 unsigned int width)
564 {
565 uint32_t offset = addr >> 3;
566 uint64_t val = -1;
567
568 switch (offset) {
569 default:
570 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
571 offset);
572 }
573
574 return val;
575 }
576
pnv_quad_power10_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)577 static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr,
578 uint64_t val, unsigned int width)
579 {
580 uint32_t offset = addr >> 3;
581
582 switch (offset) {
583 default:
584 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
585 offset);
586 }
587 }
588
589 static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
590 .read = pnv_quad_power10_xscom_read,
591 .write = pnv_quad_power10_xscom_write,
592 .valid.min_access_size = 8,
593 .valid.max_access_size = 8,
594 .impl.min_access_size = 8,
595 .impl.max_access_size = 8,
596 .endianness = DEVICE_BIG_ENDIAN,
597 };
598
599 #define P10_QME_SPWU_HYP 0x83c
600 #define P10_QME_SSH_HYP 0x82c
601
pnv_qme_power10_xscom_read(void * opaque,hwaddr addr,unsigned int width)602 static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
603 unsigned int width)
604 {
605 PnvQuad *eq = PNV_QUAD(opaque);
606 uint32_t offset = addr >> 3;
607 uint64_t val = -1;
608
609 /*
610 * Forth nibble selects the core within a quad, mask it to process read
611 * for any core.
612 */
613 switch (offset & ~PPC_BITMASK32(16, 19)) {
614 case P10_QME_SSH_HYP:
615 val = 0;
616 if (eq->special_wakeup_done) {
617 val |= PPC_BIT(1); /* SPWU DONE */
618 val |= PPC_BIT(4); /* SSH SPWU DONE */
619 }
620 break;
621 default:
622 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
623 offset);
624 }
625
626 return val;
627 }
628
pnv_qme_power10_xscom_write(void * opaque,hwaddr addr,uint64_t val,unsigned int width)629 static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
630 uint64_t val, unsigned int width)
631 {
632 PnvQuad *eq = PNV_QUAD(opaque);
633 uint32_t offset = addr >> 3;
634 bool set;
635 int i;
636
637 switch (offset & ~PPC_BITMASK32(16, 19)) {
638 case P10_QME_SPWU_HYP:
639 set = !!(val & PPC_BIT(0));
640 eq->special_wakeup_done = set;
641 for (i = 0; i < 4; i++) {
642 /* These bits select cores in the quad */
643 if (offset & PPC_BIT32(16 + i)) {
644 eq->special_wakeup[i] = set;
645 }
646 }
647 break;
648 default:
649 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
650 offset);
651 }
652 }
653
654 static const MemoryRegionOps pnv_qme_power10_xscom_ops = {
655 .read = pnv_qme_power10_xscom_read,
656 .write = pnv_qme_power10_xscom_write,
657 .valid.min_access_size = 8,
658 .valid.max_access_size = 8,
659 .impl.min_access_size = 8,
660 .impl.max_access_size = 8,
661 .endianness = DEVICE_BIG_ENDIAN,
662 };
663
pnv_quad_power9_realize(DeviceState * dev,Error ** errp)664 static void pnv_quad_power9_realize(DeviceState *dev, Error **errp)
665 {
666 PnvQuad *eq = PNV_QUAD(dev);
667 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
668 char name[32];
669
670 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
671 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
672 pqc->xscom_ops,
673 eq, name,
674 pqc->xscom_size);
675 }
676
pnv_quad_power10_realize(DeviceState * dev,Error ** errp)677 static void pnv_quad_power10_realize(DeviceState *dev, Error **errp)
678 {
679 PnvQuad *eq = PNV_QUAD(dev);
680 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq);
681 char name[32];
682
683 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id);
684 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev),
685 pqc->xscom_ops,
686 eq, name,
687 pqc->xscom_size);
688
689 snprintf(name, sizeof(name), "xscom-qme.%d", eq->quad_id);
690 pnv_xscom_region_init(&eq->xscom_qme_regs, OBJECT(dev),
691 pqc->xscom_qme_ops,
692 eq, name,
693 pqc->xscom_qme_size);
694 }
695
696 static Property pnv_quad_properties[] = {
697 DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0),
698 DEFINE_PROP_END_OF_LIST(),
699 };
700
pnv_quad_power9_class_init(ObjectClass * oc,void * data)701 static void pnv_quad_power9_class_init(ObjectClass *oc, void *data)
702 {
703 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
704 DeviceClass *dc = DEVICE_CLASS(oc);
705
706 dc->realize = pnv_quad_power9_realize;
707
708 pqc->xscom_ops = &pnv_quad_power9_xscom_ops;
709 pqc->xscom_size = PNV9_XSCOM_EQ_SIZE;
710 }
711
pnv_quad_power10_class_init(ObjectClass * oc,void * data)712 static void pnv_quad_power10_class_init(ObjectClass *oc, void *data)
713 {
714 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc);
715 DeviceClass *dc = DEVICE_CLASS(oc);
716
717 dc->realize = pnv_quad_power10_realize;
718
719 pqc->xscom_ops = &pnv_quad_power10_xscom_ops;
720 pqc->xscom_size = PNV10_XSCOM_EQ_SIZE;
721
722 pqc->xscom_qme_ops = &pnv_qme_power10_xscom_ops;
723 pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE;
724 }
725
pnv_quad_class_init(ObjectClass * oc,void * data)726 static void pnv_quad_class_init(ObjectClass *oc, void *data)
727 {
728 DeviceClass *dc = DEVICE_CLASS(oc);
729
730 device_class_set_props(dc, pnv_quad_properties);
731 dc->user_creatable = false;
732 }
733
734 static const TypeInfo pnv_quad_infos[] = {
735 {
736 .name = TYPE_PNV_QUAD,
737 .parent = TYPE_DEVICE,
738 .instance_size = sizeof(PnvQuad),
739 .class_size = sizeof(PnvQuadClass),
740 .class_init = pnv_quad_class_init,
741 .abstract = true,
742 },
743 {
744 .parent = TYPE_PNV_QUAD,
745 .name = PNV_QUAD_TYPE_NAME("power9"),
746 .class_init = pnv_quad_power9_class_init,
747 },
748 {
749 .parent = TYPE_PNV_QUAD,
750 .name = PNV_QUAD_TYPE_NAME("power10"),
751 .class_init = pnv_quad_power10_class_init,
752 },
753 };
754
755 DEFINE_TYPES(pnv_quad_infos);
756