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