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 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_core.h" 29 #include "hw/ppc/pnv_xscom.h" 30 #include "hw/ppc/xics.h" 31 #include "hw/qdev-properties.h" 32 33 static const char *pnv_core_cpu_typename(PnvCore *pc) 34 { 35 const char *core_type = object_class_get_name(object_get_class(OBJECT(pc))); 36 int len = strlen(core_type) - strlen(PNV_CORE_TYPE_SUFFIX); 37 char *s = g_strdup_printf(POWERPC_CPU_TYPE_NAME("%.*s"), len, core_type); 38 const char *cpu_type = object_class_get_name(object_class_by_name(s)); 39 g_free(s); 40 return cpu_type; 41 } 42 43 static void pnv_core_cpu_reset(PowerPCCPU *cpu) 44 { 45 CPUState *cs = CPU(cpu); 46 CPUPPCState *env = &cpu->env; 47 48 cpu_reset(cs); 49 50 /* 51 * the skiboot firmware elects a primary thread to initialize the 52 * system and it can be any. 53 */ 54 env->gpr[3] = PNV_FDT_ADDR; 55 env->nip = 0x10; 56 env->msr |= MSR_HVB; /* Hypervisor mode */ 57 } 58 59 /* 60 * These values are read by the PowerNV HW monitors under Linux 61 */ 62 #define PNV_XSCOM_EX_DTS_RESULT0 0x50000 63 #define PNV_XSCOM_EX_DTS_RESULT1 0x50001 64 65 static uint64_t pnv_core_power8_xscom_read(void *opaque, hwaddr addr, 66 unsigned int width) 67 { 68 uint32_t offset = addr >> 3; 69 uint64_t val = 0; 70 71 /* The result should be 38 C */ 72 switch (offset) { 73 case PNV_XSCOM_EX_DTS_RESULT0: 74 val = 0x26f024f023f0000ull; 75 break; 76 case PNV_XSCOM_EX_DTS_RESULT1: 77 val = 0x24f000000000000ull; 78 break; 79 default: 80 qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n", 81 addr); 82 } 83 84 return val; 85 } 86 87 static void pnv_core_power8_xscom_write(void *opaque, hwaddr addr, uint64_t val, 88 unsigned int width) 89 { 90 qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n", 91 addr); 92 } 93 94 static const MemoryRegionOps pnv_core_power8_xscom_ops = { 95 .read = pnv_core_power8_xscom_read, 96 .write = pnv_core_power8_xscom_write, 97 .valid.min_access_size = 8, 98 .valid.max_access_size = 8, 99 .impl.min_access_size = 8, 100 .impl.max_access_size = 8, 101 .endianness = DEVICE_BIG_ENDIAN, 102 }; 103 104 105 /* 106 * POWER9 core controls 107 */ 108 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP 0xf010d 109 #define PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR 0xf010a 110 111 static uint64_t pnv_core_power9_xscom_read(void *opaque, hwaddr addr, 112 unsigned int width) 113 { 114 uint32_t offset = addr >> 3; 115 uint64_t val = 0; 116 117 /* The result should be 38 C */ 118 switch (offset) { 119 case PNV_XSCOM_EX_DTS_RESULT0: 120 val = 0x26f024f023f0000ull; 121 break; 122 case PNV_XSCOM_EX_DTS_RESULT1: 123 val = 0x24f000000000000ull; 124 break; 125 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP: 126 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR: 127 val = 0x0; 128 break; 129 default: 130 qemu_log_mask(LOG_UNIMP, "Warning: reading reg=0x%" HWADDR_PRIx "\n", 131 addr); 132 } 133 134 return val; 135 } 136 137 static void pnv_core_power9_xscom_write(void *opaque, hwaddr addr, uint64_t val, 138 unsigned int width) 139 { 140 uint32_t offset = addr >> 3; 141 142 switch (offset) { 143 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_HYP: 144 case PNV9_XSCOM_EC_PPM_SPECIAL_WKUP_OTR: 145 break; 146 default: 147 qemu_log_mask(LOG_UNIMP, "Warning: writing to reg=0x%" HWADDR_PRIx "\n", 148 addr); 149 } 150 } 151 152 static const MemoryRegionOps pnv_core_power9_xscom_ops = { 153 .read = pnv_core_power9_xscom_read, 154 .write = pnv_core_power9_xscom_write, 155 .valid.min_access_size = 8, 156 .valid.max_access_size = 8, 157 .impl.min_access_size = 8, 158 .impl.max_access_size = 8, 159 .endianness = DEVICE_BIG_ENDIAN, 160 }; 161 162 static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp) 163 { 164 CPUPPCState *env = &cpu->env; 165 int core_pir; 166 int thread_index = 0; /* TODO: TCG supports only one thread */ 167 ppc_spr_t *pir = &env->spr_cb[SPR_PIR]; 168 Error *local_err = NULL; 169 PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip); 170 171 object_property_set_bool(OBJECT(cpu), true, "realized", &local_err); 172 if (local_err) { 173 error_propagate(errp, local_err); 174 return; 175 } 176 177 pcc->intc_create(chip, cpu, &local_err); 178 if (local_err) { 179 error_propagate(errp, local_err); 180 return; 181 } 182 183 core_pir = object_property_get_uint(OBJECT(cpu), "core-pir", &error_abort); 184 185 /* 186 * The PIR of a thread is the core PIR + the thread index. We will 187 * need to find a way to get the thread index when TCG supports 188 * more than 1. We could use the object name ? 189 */ 190 pir->default_value = core_pir + thread_index; 191 192 /* Set time-base frequency to 512 MHz */ 193 cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ); 194 } 195 196 static void pnv_core_reset(void *dev) 197 { 198 CPUCore *cc = CPU_CORE(dev); 199 PnvCore *pc = PNV_CORE(dev); 200 int i; 201 202 for (i = 0; i < cc->nr_threads; i++) { 203 pnv_core_cpu_reset(pc->threads[i]); 204 } 205 } 206 207 static void pnv_core_realize(DeviceState *dev, Error **errp) 208 { 209 PnvCore *pc = PNV_CORE(OBJECT(dev)); 210 PnvCoreClass *pcc = PNV_CORE_GET_CLASS(pc); 211 CPUCore *cc = CPU_CORE(OBJECT(dev)); 212 const char *typename = pnv_core_cpu_typename(pc); 213 Error *local_err = NULL; 214 void *obj; 215 int i, j; 216 char name[32]; 217 Object *chip; 218 219 chip = object_property_get_link(OBJECT(dev), "chip", &local_err); 220 if (!chip) { 221 error_propagate_prepend(errp, local_err, 222 "required link 'chip' not found: "); 223 return; 224 } 225 pc->chip = PNV_CHIP(chip); 226 227 pc->threads = g_new(PowerPCCPU *, cc->nr_threads); 228 for (i = 0; i < cc->nr_threads; i++) { 229 PowerPCCPU *cpu; 230 231 obj = object_new(typename); 232 cpu = POWERPC_CPU(obj); 233 234 pc->threads[i] = POWERPC_CPU(obj); 235 236 snprintf(name, sizeof(name), "thread[%d]", i); 237 object_property_add_child(OBJECT(pc), name, obj, &error_abort); 238 object_property_add_alias(obj, "core-pir", OBJECT(pc), 239 "pir", &error_abort); 240 241 cpu->machine_data = g_new0(PnvCPUState, 1); 242 243 object_unref(obj); 244 } 245 246 for (j = 0; j < cc->nr_threads; j++) { 247 pnv_realize_vcpu(pc->threads[j], pc->chip, &local_err); 248 if (local_err) { 249 goto err; 250 } 251 } 252 253 snprintf(name, sizeof(name), "xscom-core.%d", cc->core_id); 254 pnv_xscom_region_init(&pc->xscom_regs, OBJECT(dev), pcc->xscom_ops, 255 pc, name, PNV_XSCOM_EX_SIZE); 256 257 qemu_register_reset(pnv_core_reset, pc); 258 return; 259 260 err: 261 while (--i >= 0) { 262 obj = OBJECT(pc->threads[i]); 263 object_unparent(obj); 264 } 265 g_free(pc->threads); 266 error_propagate(errp, local_err); 267 } 268 269 static void pnv_unrealize_vcpu(PowerPCCPU *cpu) 270 { 271 PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); 272 273 object_unparent(OBJECT(pnv_cpu_state(cpu)->intc)); 274 cpu_remove_sync(CPU(cpu)); 275 cpu->machine_data = NULL; 276 g_free(pnv_cpu); 277 object_unparent(OBJECT(cpu)); 278 } 279 280 static void pnv_core_unrealize(DeviceState *dev, Error **errp) 281 { 282 PnvCore *pc = PNV_CORE(dev); 283 CPUCore *cc = CPU_CORE(dev); 284 int i; 285 286 qemu_unregister_reset(pnv_core_reset, pc); 287 288 for (i = 0; i < cc->nr_threads; i++) { 289 pnv_unrealize_vcpu(pc->threads[i]); 290 } 291 g_free(pc->threads); 292 } 293 294 static Property pnv_core_properties[] = { 295 DEFINE_PROP_UINT32("pir", PnvCore, pir, 0), 296 DEFINE_PROP_END_OF_LIST(), 297 }; 298 299 static void pnv_core_power8_class_init(ObjectClass *oc, void *data) 300 { 301 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 302 303 pcc->xscom_ops = &pnv_core_power8_xscom_ops; 304 } 305 306 static void pnv_core_power9_class_init(ObjectClass *oc, void *data) 307 { 308 PnvCoreClass *pcc = PNV_CORE_CLASS(oc); 309 310 pcc->xscom_ops = &pnv_core_power9_xscom_ops; 311 } 312 313 static void pnv_core_class_init(ObjectClass *oc, void *data) 314 { 315 DeviceClass *dc = DEVICE_CLASS(oc); 316 317 dc->realize = pnv_core_realize; 318 dc->unrealize = pnv_core_unrealize; 319 dc->props = pnv_core_properties; 320 } 321 322 #define DEFINE_PNV_CORE_TYPE(family, cpu_model) \ 323 { \ 324 .parent = TYPE_PNV_CORE, \ 325 .name = PNV_CORE_TYPE_NAME(cpu_model), \ 326 .class_init = pnv_core_##family##_class_init, \ 327 } 328 329 static const TypeInfo pnv_core_infos[] = { 330 { 331 .name = TYPE_PNV_CORE, 332 .parent = TYPE_CPU_CORE, 333 .instance_size = sizeof(PnvCore), 334 .class_size = sizeof(PnvCoreClass), 335 .class_init = pnv_core_class_init, 336 .abstract = true, 337 }, 338 DEFINE_PNV_CORE_TYPE(power8, "power8e_v2.1"), 339 DEFINE_PNV_CORE_TYPE(power8, "power8_v2.0"), 340 DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"), 341 DEFINE_PNV_CORE_TYPE(power9, "power9_v2.0"), 342 }; 343 344 DEFINE_TYPES(pnv_core_infos) 345 346 /* 347 * POWER9 Quads 348 */ 349 350 #define P9X_EX_NCU_SPEC_BAR 0x11010 351 352 static uint64_t pnv_quad_xscom_read(void *opaque, hwaddr addr, 353 unsigned int width) 354 { 355 uint32_t offset = addr >> 3; 356 uint64_t val = -1; 357 358 switch (offset) { 359 case P9X_EX_NCU_SPEC_BAR: 360 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ 361 val = 0; 362 break; 363 default: 364 qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__, 365 offset); 366 } 367 368 return val; 369 } 370 371 static void pnv_quad_xscom_write(void *opaque, hwaddr addr, uint64_t val, 372 unsigned int width) 373 { 374 uint32_t offset = addr >> 3; 375 376 switch (offset) { 377 case P9X_EX_NCU_SPEC_BAR: 378 case P9X_EX_NCU_SPEC_BAR + 0x400: /* Second EX */ 379 break; 380 default: 381 qemu_log_mask(LOG_UNIMP, "%s: writing @0x%08x\n", __func__, 382 offset); 383 } 384 } 385 386 static const MemoryRegionOps pnv_quad_xscom_ops = { 387 .read = pnv_quad_xscom_read, 388 .write = pnv_quad_xscom_write, 389 .valid.min_access_size = 8, 390 .valid.max_access_size = 8, 391 .impl.min_access_size = 8, 392 .impl.max_access_size = 8, 393 .endianness = DEVICE_BIG_ENDIAN, 394 }; 395 396 static void pnv_quad_realize(DeviceState *dev, Error **errp) 397 { 398 PnvQuad *eq = PNV_QUAD(dev); 399 char name[32]; 400 401 snprintf(name, sizeof(name), "xscom-quad.%d", eq->id); 402 pnv_xscom_region_init(&eq->xscom_regs, OBJECT(dev), &pnv_quad_xscom_ops, 403 eq, name, PNV9_XSCOM_EQ_SIZE); 404 } 405 406 static Property pnv_quad_properties[] = { 407 DEFINE_PROP_UINT32("id", PnvQuad, id, 0), 408 DEFINE_PROP_END_OF_LIST(), 409 }; 410 411 static void pnv_quad_class_init(ObjectClass *oc, void *data) 412 { 413 DeviceClass *dc = DEVICE_CLASS(oc); 414 415 dc->realize = pnv_quad_realize; 416 dc->props = pnv_quad_properties; 417 } 418 419 static const TypeInfo pnv_quad_info = { 420 .name = TYPE_PNV_QUAD, 421 .parent = TYPE_DEVICE, 422 .instance_size = sizeof(PnvQuad), 423 .class_init = pnv_quad_class_init, 424 }; 425 426 static void pnv_core_register_types(void) 427 { 428 type_register_static(&pnv_quad_info); 429 } 430 431 type_init(pnv_core_register_types) 432