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 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr, 120 unsigned int width) 121 { 122 uint32_t offset = addr >> 3; 123 uint64_t val = 0; 124 125 /* The result should be 38 C */ 126 switch (offset) { 127 case PNV_XSCOM_EX_DTS_RESULT0: 128 val = 0x26f024f023f0000ull; 129 break; 130 case PNV_XSCOM_EX_DTS_RESULT1: 131 val = 0x24f000000000000ull; 132 break; 133 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP: 134 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR: 135 val = 0x0; 136 break; 137 default: 138 qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n", 139 addr); 140 } 141 142 return val; 143 } 144 145 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val, 146 unsigned int width) 147 { 148 uint32_t offset = addr >> 3; 149 150 switch (offset) { 151 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP: 152 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR: 153 break; 154 default: 155 qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n", 156 addr); 157 } 158 } 159 160 static const MemoryRegionOps pnv_core_power9_xscom_ops = { 161 .read = pnv_core_power9_xscom_read, 162 .write = pnv_core_power9_xscom_write, 163 .valid.min_access_size = 8, 164 .valid.max_access_size = 8, 165 .impl.min_access_size = 8, 166 .impl.max_access_size = 8, 167 .endianness = DEVICE_BIG_ENDIAN, 168 }; 169 170 static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp) 171 { 172 CPUPPCState *env = &cpu->env; 173 int core_pir; 174 int thread_index = 0; /* TODO: TCG supports only one thread */ 175 ppc_spr_t *pir = &env->spr_cb[SPR_PIR]; 176 Error *local_err = NULL; 177 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip); 178 179 if (!qdev_realize(DEVICE(cpu), NULL, errp)) { 180 return; 181 } 182 183 pcc->intc_create(pc->chip, cpu, &local_err); 184 if (local_err) { 185 error_propagate(errp, local_err); 186 return; 187 } 188 189 core_pir = object_property_get_uint(OBJECT(pc), "pir", &error_abort); 190 191 /* 192 * The PIR of a thread is the core PIR + the thread index. We will 193 * need to find a way to get the thread index when TCG supports 194 * more than 1. We could use the object name ? 195 */ 196 pir->default_value = core_pir + thread_index; 197 198 /* Set time-base frequency to 512 MHz */ 199 cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ); 200 } 201 202 static void pnv_core_reset(void *dev) 203 { 204 CPUCore *cc = CPU_CORE(dev); 205 PnvCore *pc = PNV_CORE(dev); 206 int i; 207 208 for (i = 0; i < cc->nr_threads; i++) { 209 pnv_core_cpu_reset(pc, pc->threads[i]); 210 } 211 } 212 213 static void pnv_core_realize(DeviceState *dev, Error **errp) 214 { 215 PnvCore *pc = PNV_CORE(OBJECT(dev)); 216 PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc); 217 CPUCore *cc = CPU_CORE(OBJECT(dev)); 218 const char *typename = pnv_core_cpu_typename(pc); 219 Error *local_err = NULL; 220 void *obj; 221 int i, j; 222 char name[32]; 223 224 assert(pc->chip); 225 226 pc->threads = g_new(PowerPCCPU *, cc->nr_threads); 227 for (i = 0; i < cc->nr_threads; i++) { 228 PowerPCCPU *cpu; 229 230 obj = object_new(typename); 231 cpu = POWERPC_CPU(obj); 232 233 pc->threads[i] = POWERPC_CPU(obj); 234 235 snprintf(name, sizeof(name), "thread[%d]", i); 236 object_property_add_child(OBJECT(pc), name, obj); 237 238 cpu->machine_data = g_new0(PnvCPUState, 1); 239 240 object_unref(obj); 241 } 242 243 for (j = 0; j < cc->nr_threads; j++) { 244 pnv_core_cpu_realize(pc, pc->threads[j], &local_err); 245 if (local_err) { 246 goto err; 247 } 248 } 249 250 snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id); 251 /* TODO: check PNV_XSCOM_EX_SIZE for p10 */ 252 pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops, 253 pc, name, PNV_XSCOM_EX_SIZE); 254 255 qemu_register_reset(pnv_core_reset, pc); 256 return; 257 258 err: 259 while (--i >= 0) { 260 obj = OBJECT(pc->threads[i]); 261 object_unparent(obj); 262 } 263 g_free(pc->threads); 264 error_propagate(errp, local_err); 265 } 266 267 static void pnv_core_cpu_unrealize(PnvCore *pc, PowerPCCPU *cpu) 268 { 269 PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); 270 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip); 271 272 pcc->intc_destroy(pc->chip, cpu); 273 cpu_remove_sync(CPU(cpu)); 274 cpu->machine_data = NULL; 275 g_free(pnv_cpu); 276 object_unparent(OBJECT(cpu)); 277 } 278 279 static void pnv_core_unrealize(DeviceState *dev) 280 { 281 PnvCore *pc = PNV_CORE(dev); 282 CPUCore *cc = CPU_CORE(dev); 283 int i; 284 285 qemu_unregister_reset(pnv_core_reset, pc); 286 287 for (i = 0; i < cc->nr_threads; i++) { 288 pnv_core_cpu_unrealize(pc, pc->threads[i]); 289 } 290 g_free(pc->threads); 291 } 292 293 static Property pnv_core_properties[] = { 294 DEFINE_PROP_UINT32("pir", PnvCore, pir, 0), 295 DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0), 296 DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *), 297 DEFINE_PROP_END_OF_LIST(), 298 }; 299 300 static void pnv_core_power8_class_init(ObjectClass *oc, void *data) 301 { 302 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 303 304 pcc->xscom_ops = &pnv_core_power8_xscom_ops; 305 } 306 307 static void pnv_core_power9_class_init(ObjectClass *oc, void *data) 308 { 309 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 310 311 pcc->xscom_ops = &pnv_core_power9_xscom_ops; 312 } 313 314 static void pnv_core_power10_class_init(ObjectClass *oc, void *data) 315 { 316 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 317 318 /* TODO: Use the P9 XSCOMs for now on P10 */ 319 pcc->xscom_ops = &pnv_core_power9_xscom_ops; 320 } 321 322 static void pnv_core_class_init(ObjectClass *oc, void *data) 323 { 324 DeviceClass *dc = DEVICE_CLASS(oc); 325 326 dc->realize = pnv_core_realize; 327 dc->unrealize = pnv_core_unrealize; 328 device_class_set_props(dc, pnv_core_properties); 329 dc->user_creatable = false; 330 } 331 332 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \ 333 { \ 334 .parent = TYPE_PNV_CORE, \ 335 .name = PNV_CORE_TYPE_NAME(cpu_model), \ 336 .class_init = pnv_core_##family##_class_init, \ 337 } 338 339 static const TypeInfo pnv_core_infos[] = { 340 { 341 .name = TYPE_PNV_CORE, 342 .parent = TYPE_CPU_CORE, 343 .instance_size = sizeof(PnvCore), 344 .class_size = sizeof(PnvCoreClass), 345 .class_init = pnv_core_class_init, 346 .abstract = true, 347 }, 348 DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"), 349 DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"), 350 DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"), 351 DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"), 352 DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"), 353 }; 354 355 DEFINE_TYPES(pnv_core_infos) 356 357 /* 358 * POWER9 Quads 359 */ 360 361 #define P9X_EX_NCU_SPEC_BAR 0x11010 362 363 static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr, 364 unsigned int width) 365 { 366 uint32_t offset = addr >> 3; 367 uint64_t val = -1; 368 369 switch (offset) { 370 case P9X_EX_NCU_SPEC_BAR: 371 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ 372 val = 0; 373 break; 374 default: 375 qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__, 376 offset); 377 } 378 379 return val; 380 } 381 382 static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val, 383 unsigned int width) 384 { 385 uint32_t offset = addr >> 3; 386 387 switch (offset) { 388 case P9X_EX_NCU_SPEC_BAR: 389 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ 390 break; 391 default: 392 qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__, 393 offset); 394 } 395 } 396 397 static const MemoryRegionOps pnv_quad_xscom_ops = { 398 .read = pnv_quad_xscom_read, 399 .write = pnv_quad_xscom_write, 400 .valid.min_access_size = 8, 401 .valid.max_access_size = 8, 402 .impl.min_access_size = 8, 403 .impl.max_access_size = 8, 404 .endianness = DEVICE_BIG_ENDIAN, 405 }; 406 407 static void pnv_quad_realize(DeviceState *dev, Error **errp) 408 { 409 PnvQuad *eq = PNV_QUAD(dev); 410 char name[32]; 411 412 snprintf(name, sizeof(name), "xscom-quad.%d", eq->quad_id); 413 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops, 414 eq, name, PNV9_XSCOM_EQ_SIZE); 415 } 416 417 static Property pnv_quad_properties[] = { 418 DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0), 419 DEFINE_PROP_END_OF_LIST(), 420 }; 421 422 static void pnv_quad_class_init(ObjectClass *oc, void *data) 423 { 424 DeviceClass *dc = DEVICE_CLASS(oc); 425 426 dc->realize = pnv_quad_realize; 427 device_class_set_props(dc, pnv_quad_properties); 428 dc->user_creatable = false; 429 } 430 431 static const TypeInfo pnv_quad_info = { 432 .name = TYPE_PNV_QUAD, 433 .parent = TYPE_DEVICE, 434 .instance_size = sizeof(PnvQuad), 435 .class_init = pnv_quad_class_init, 436 }; 437 438 static void pnv_core_register_types(void) 439 { 440 type_register_static(&pnv_quad_info); 441 } 442 443 type_init(pnv_core_register_types) 444