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