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