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 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 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 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 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 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 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 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 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 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 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 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 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 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 452 static void pnv_core_power8_class_init(ObjectClass *oc, 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 460 static void pnv_core_power9_class_init(ObjectClass *oc, 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 468 static void pnv_core_power10_class_init(ObjectClass *oc, 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 476 static void pnv_core_class_init(ObjectClass *oc, 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 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 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 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 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 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 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 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 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 703 static void pnv_quad_power9_class_init(ObjectClass *oc, 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 714 static void pnv_quad_power10_class_init(ObjectClass *oc, 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 728 static void pnv_quad_class_init(ObjectClass *oc, 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