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 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 hreg_compute_hflags(env); 62 ppc_maybe_interrupt(env); 63 64 pcc->intc_reset(pc->chip, cpu); 65 } 66 67 /* 68 * These values are read by the PowerNV HW monitors under Linux 69 */ 70 #define PNV_XSCOM_EX_DTS_RESULT0 0x50000 71 #define PNV_XSCOM_EX_DTS_RESULT1 0x50001 72 73 static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr, 74 unsigned int width) 75 { 76 uint32_t offset = addr >> 3; 77 uint64_t val = 0; 78 79 /* The result should be 38 C */ 80 switch (offset) { 81 case PNV_XSCOM_EX_DTS_RESULT0: 82 val = 0x26f024f023f0000ull; 83 break; 84 case PNV_XSCOM_EX_DTS_RESULT1: 85 val = 0x24f000000000000ull; 86 break; 87 default: 88 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__, 89 offset); 90 } 91 92 return val; 93 } 94 95 static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val, 96 unsigned int width) 97 { 98 uint32_t offset = addr >> 3; 99 100 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__, 101 offset); 102 } 103 104 static const MemoryRegionOps pnv_core_power8_xscom_ops = { 105 .read = pnv_core_power8_xscom_read, 106 .write = pnv_core_power8_xscom_write, 107 .valid.min_access_size = 8, 108 .valid.max_access_size = 8, 109 .impl.min_access_size = 8, 110 .impl.max_access_size = 8, 111 .endianness = DEVICE_BIG_ENDIAN, 112 }; 113 114 115 /* 116 * POWER9 core controls 117 */ 118 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d 119 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a 120 121 #define PNV9_XSCOM_EC_CORE_THREAD_STATE 0x10ab3 122 123 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr, 124 unsigned int width) 125 { 126 uint32_t offset = addr >> 3; 127 uint64_t val = 0; 128 129 /* The result should be 38 C */ 130 switch (offset) { 131 case PNV_XSCOM_EX_DTS_RESULT0: 132 val = 0x26f024f023f0000ull; 133 break; 134 case PNV_XSCOM_EX_DTS_RESULT1: 135 val = 0x24f000000000000ull; 136 break; 137 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP: 138 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR: 139 val = 0x0; 140 break; 141 case PNV9_XSCOM_EC_CORE_THREAD_STATE: 142 val = 0; 143 break; 144 default: 145 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__, 146 offset); 147 } 148 149 return val; 150 } 151 152 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val, 153 unsigned int width) 154 { 155 uint32_t offset = addr >> 3; 156 157 switch (offset) { 158 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP: 159 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR: 160 break; 161 default: 162 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__, 163 offset); 164 } 165 } 166 167 static const MemoryRegionOps pnv_core_power9_xscom_ops = { 168 .read = pnv_core_power9_xscom_read, 169 .write = pnv_core_power9_xscom_write, 170 .valid.min_access_size = 8, 171 .valid.max_access_size = 8, 172 .impl.min_access_size = 8, 173 .impl.max_access_size = 8, 174 .endianness = DEVICE_BIG_ENDIAN, 175 }; 176 177 /* 178 * POWER10 core controls 179 */ 180 181 #define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412 182 183 static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr, 184 unsigned int width) 185 { 186 uint32_t offset = addr >> 3; 187 uint64_t val = 0; 188 189 switch (offset) { 190 case PNV10_XSCOM_EC_CORE_THREAD_STATE: 191 val = 0; 192 break; 193 default: 194 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__, 195 offset); 196 } 197 198 return val; 199 } 200 201 static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr, 202 uint64_t val, unsigned int width) 203 { 204 uint32_t offset = addr >> 3; 205 206 switch (offset) { 207 default: 208 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__, 209 offset); 210 } 211 } 212 213 static const MemoryRegionOps pnv_core_power10_xscom_ops = { 214 .read = pnv_core_power10_xscom_read, 215 .write = pnv_core_power10_xscom_write, 216 .valid.min_access_size = 8, 217 .valid.max_access_size = 8, 218 .impl.min_access_size = 8, 219 .impl.max_access_size = 8, 220 .endianness = DEVICE_BIG_ENDIAN, 221 }; 222 223 static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp, 224 int thread_index) 225 { 226 CPUPPCState *env = &cpu->env; 227 int core_pir; 228 ppc_spr_t *pir = &env->spr_cb[SPR_PIR]; 229 ppc_spr_t *tir = &env->spr_cb[SPR_TIR]; 230 Error *local_err = NULL; 231 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip); 232 233 if (!qdev_realize(DEVICE(cpu), NULL, errp)) { 234 return; 235 } 236 237 pcc->intc_create(pc->chip, cpu, &local_err); 238 if (local_err) { 239 error_propagate(errp, local_err); 240 return; 241 } 242 243 core_pir = object_property_get_uint(OBJECT(pc), "pir", &error_abort); 244 245 tir->default_value = thread_index; 246 pir->default_value = core_pir + thread_index; 247 248 /* Set time-base frequency to 512 MHz */ 249 cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ); 250 } 251 252 static void pnv_core_reset(void *dev) 253 { 254 CPUCore *cc = CPU_CORE(dev); 255 PnvCore *pc = PNV_CORE(dev); 256 int i; 257 258 for (i = 0; i < cc->nr_threads; i++) { 259 pnv_core_cpu_reset(pc, pc->threads[i]); 260 } 261 } 262 263 static void pnv_core_realize(DeviceState *dev, Error **errp) 264 { 265 PnvCore *pc = PNV_CORE(OBJECT(dev)); 266 PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc); 267 CPUCore *cc = CPU_CORE(OBJECT(dev)); 268 const char *typename = pnv_core_cpu_typename(pc); 269 Error *local_err = NULL; 270 void *obj; 271 int i, j; 272 char name[32]; 273 274 assert(pc->chip); 275 276 pc->threads = g_new(PowerPCCPU *, cc->nr_threads); 277 for (i = 0; i < cc->nr_threads; i++) { 278 PowerPCCPU *cpu; 279 280 obj = object_new(typename); 281 cpu = POWERPC_CPU(obj); 282 283 pc->threads[i] = POWERPC_CPU(obj); 284 285 snprintf(name, sizeof(name), "thread[%d]", i); 286 object_property_add_child(OBJECT(pc), name, obj); 287 288 cpu->machine_data = g_new0(PnvCPUState, 1); 289 290 object_unref(obj); 291 } 292 293 for (j = 0; j < cc->nr_threads; j++) { 294 pnv_core_cpu_realize(pc, pc->threads[j], &local_err, j); 295 if (local_err) { 296 goto err; 297 } 298 } 299 300 snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id); 301 /* TODO: check PNV_XSCOM_EX_SIZE for p10 */ 302 pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops, 303 pc, name, PNV_XSCOM_EX_SIZE); 304 305 qemu_register_reset(pnv_core_reset, pc); 306 return; 307 308 err: 309 while (--i >= 0) { 310 obj = OBJECT(pc->threads[i]); 311 object_unparent(obj); 312 } 313 g_free(pc->threads); 314 error_propagate(errp, local_err); 315 } 316 317 static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu) 318 { 319 PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); 320 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip); 321 322 pcc->intc_destroy(pc->chip, cpu); 323 cpu_remove_sync(CPU(cpu)); 324 cpu->machine_data = NULL; 325 g_free(pnv_cpu); 326 object_unparent(OBJECT(cpu)); 327 } 328 329 static void pnv_core_unrealize(DeviceState *dev) 330 { 331 PnvCore *pc = PNV_CORE(dev); 332 CPUCore *cc = CPU_CORE(dev); 333 int i; 334 335 qemu_unregister_reset(pnv_core_reset, pc); 336 337 for (i = 0; i < cc->nr_threads; i++) { 338 pnv_core_cpu_unrealize(pc, pc->threads[i]); 339 } 340 g_free(pc->threads); 341 } 342 343 static Property pnv_core_properties[] = { 344 DEFINE_PROP_UINT32("pir", PnvCore, pir, 0), 345 DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0), 346 DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *), 347 DEFINE_PROP_END_OF_LIST(), 348 }; 349 350 static void pnv_core_power8_class_init(ObjectClass *oc, void *data) 351 { 352 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 353 354 pcc->xscom_ops = &pnv_core_power8_xscom_ops; 355 } 356 357 static void pnv_core_power9_class_init(ObjectClass *oc, void *data) 358 { 359 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 360 361 pcc->xscom_ops = &pnv_core_power9_xscom_ops; 362 } 363 364 static void pnv_core_power10_class_init(ObjectClass *oc, void *data) 365 { 366 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 367 368 pcc->xscom_ops = &pnv_core_power10_xscom_ops; 369 } 370 371 static void pnv_core_class_init(ObjectClass *oc, void *data) 372 { 373 DeviceClass *dc = DEVICE_CLASS(oc); 374 375 dc->realize = pnv_core_realize; 376 dc->unrealize = pnv_core_unrealize; 377 device_class_set_props(dc, pnv_core_properties); 378 dc->user_creatable = false; 379 } 380 381 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \ 382 { \ 383 .parent = TYPE_PNV_CORE, \ 384 .name = PNV_CORE_TYPE_NAME(cpu_model), \ 385 .class_init = pnv_core_##family##_class_init, \ 386 } 387 388 static const TypeInfo pnv_core_infos[] = { 389 { 390 .name = TYPE_PNV_CORE, 391 .parent = TYPE_CPU_CORE, 392 .instance_size = sizeof(PnvCore), 393 .class_size = sizeof(PnvCoreClass), 394 .class_init = pnv_core_class_init, 395 .abstract = true, 396 }, 397 DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"), 398 DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"), 399 DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"), 400 DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"), 401 DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"), 402 }; 403 404 DEFINE_TYPES(pnv_core_infos) 405 406 /* 407 * POWER9 Quads 408 */ 409 410 #define P9X_EX_NCU_SPEC_BAR 0x11010 411 412 static uint64_t pnv_quad_power9_xscom_read(void *opaque, hwaddr addr, 413 unsigned int width) 414 { 415 uint32_t offset = addr >> 3; 416 uint64_t val = -1; 417 418 switch (offset) { 419 case P9X_EX_NCU_SPEC_BAR: 420 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ 421 val = 0; 422 break; 423 default: 424 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__, 425 offset); 426 } 427 428 return val; 429 } 430 431 static void pnv_quad_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val, 432 unsigned int width) 433 { 434 uint32_t offset = addr >> 3; 435 436 switch (offset) { 437 case P9X_EX_NCU_SPEC_BAR: 438 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ 439 break; 440 default: 441 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__, 442 offset); 443 } 444 } 445 446 static const MemoryRegionOps pnv_quad_power9_xscom_ops = { 447 .read = pnv_quad_power9_xscom_read, 448 .write = pnv_quad_power9_xscom_write, 449 .valid.min_access_size = 8, 450 .valid.max_access_size = 8, 451 .impl.min_access_size = 8, 452 .impl.max_access_size = 8, 453 .endianness = DEVICE_BIG_ENDIAN, 454 }; 455 456 /* 457 * POWER10 Quads 458 */ 459 460 static uint64_t pnv_quad_power10_xscom_read(void *opaque, hwaddr addr, 461 unsigned int width) 462 { 463 uint32_t offset = addr >> 3; 464 uint64_t val = -1; 465 466 switch (offset) { 467 default: 468 qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__, 469 offset); 470 } 471 472 return val; 473 } 474 475 static void pnv_quad_power10_xscom_write(void *opaque, hwaddr addr, 476 uint64_t val, unsigned int width) 477 { 478 uint32_t offset = addr >> 3; 479 480 switch (offset) { 481 default: 482 qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__, 483 offset); 484 } 485 } 486 487 static const MemoryRegionOps pnv_quad_power10_xscom_ops = { 488 .read = pnv_quad_power10_xscom_read, 489 .write = pnv_quad_power10_xscom_write, 490 .valid.min_access_size = 8, 491 .valid.max_access_size = 8, 492 .impl.min_access_size = 8, 493 .impl.max_access_size = 8, 494 .endianness = DEVICE_BIG_ENDIAN, 495 }; 496 497 static void pnv_quad_realize(DeviceState *dev, Error **errp) 498 { 499 PnvQuad *eq = PNV_QUAD(dev); 500 PnvQuadClass *pqc = PNV_QUAD_GET_CLASS(eq); 501 char name[32]; 502 503 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id); 504 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), 505 pqc->xscom_ops, 506 eq, name, 507 pqc->xscom_size); 508 } 509 510 static Property pnv_quad_properties[] = { 511 DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0), 512 DEFINE_PROP_END_OF_LIST(), 513 }; 514 515 static void pnv_quad_power9_class_init(ObjectClass *oc, void *data) 516 { 517 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc); 518 519 pqc->xscom_ops = &pnv_quad_power9_xscom_ops; 520 pqc->xscom_size = PNV9_XSCOM_EQ_SIZE; 521 } 522 523 static void pnv_quad_power10_class_init(ObjectClass *oc, void *data) 524 { 525 PnvQuadClass *pqc = PNV_QUAD_CLASS(oc); 526 527 pqc->xscom_ops = &pnv_quad_power10_xscom_ops; 528 pqc->xscom_size = PNV10_XSCOM_EQ_SIZE; 529 } 530 531 static void pnv_quad_class_init(ObjectClass *oc, void *data) 532 { 533 DeviceClass *dc = DEVICE_CLASS(oc); 534 535 dc->realize = pnv_quad_realize; 536 device_class_set_props(dc, pnv_quad_properties); 537 dc->user_creatable = false; 538 } 539 540 static const TypeInfo pnv_quad_infos[] = { 541 { 542 .name = TYPE_PNV_QUAD, 543 .parent = TYPE_DEVICE, 544 .instance_size = sizeof(PnvQuad), 545 .class_size = sizeof(PnvQuadClass), 546 .class_init = pnv_quad_class_init, 547 .abstract = true, 548 }, 549 { 550 .parent = TYPE_PNV_QUAD, 551 .name = PNV_QUAD_TYPE_NAME("power9"), 552 .class_init = pnv_quad_power9_class_init, 553 }, 554 { 555 .parent = TYPE_PNV_QUAD, 556 .name = PNV_QUAD_TYPE_NAME("power10"), 557 .class_init = pnv_quad_power10_class_init, 558 }, 559 }; 560 561 DEFINE_TYPES(pnv_quad_infos); 562