1 /* 2 * sPAPR CPU core device, acts as container of CPU thread devices. 3 * 4 * Copyright (C) 2016 Bharata B Rao <bharata@linux.vnet.ibm.com> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 #include "hw/cpu/core.h" 10 #include "hw/ppc/spapr_cpu_core.h" 11 #include "target/ppc/cpu.h" 12 #include "hw/ppc/spapr.h" 13 #include "hw/boards.h" 14 #include "qapi/error.h" 15 #include "sysemu/cpus.h" 16 #include "sysemu/kvm.h" 17 #include "target/ppc/kvm_ppc.h" 18 #include "hw/ppc/ppc.h" 19 #include "target/ppc/mmu-hash64.h" 20 #include "sysemu/numa.h" 21 #include "sysemu/hw_accel.h" 22 #include "qemu/error-report.h" 23 24 void spapr_cpu_parse_features(sPAPRMachineState *spapr) 25 { 26 /* 27 * Backwards compatibility hack: 28 * 29 * CPUs had a "compat=" property which didn't make sense for 30 * anything except pseries. It was replaced by "max-cpu-compat" 31 * machine option. This supports old command lines like 32 * -cpu POWER8,compat=power7 33 * By stripping the compat option and applying it to the machine 34 * before passing it on to the cpu level parser. 35 */ 36 gchar **inpieces; 37 int i, j; 38 gchar *compat_str = NULL; 39 40 inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0); 41 42 /* inpieces[0] is the actual model string */ 43 i = 1; 44 j = 1; 45 while (inpieces[i]) { 46 if (g_str_has_prefix(inpieces[i], "compat=")) { 47 /* in case of multiple compat= options */ 48 g_free(compat_str); 49 compat_str = inpieces[i]; 50 } else { 51 j++; 52 } 53 54 i++; 55 /* Excise compat options from list */ 56 inpieces[j] = inpieces[i]; 57 } 58 59 if (compat_str) { 60 char *val = compat_str + strlen("compat="); 61 gchar *newprops = g_strjoinv(",", inpieces); 62 63 object_property_set_str(OBJECT(spapr), val, "max-cpu-compat", 64 &error_fatal); 65 66 ppc_cpu_parse_features(newprops); 67 g_free(newprops); 68 } else { 69 ppc_cpu_parse_features(MACHINE(spapr)->cpu_model); 70 } 71 72 g_strfreev(inpieces); 73 } 74 75 static void spapr_cpu_reset(void *opaque) 76 { 77 PowerPCCPU *cpu = opaque; 78 CPUState *cs = CPU(cpu); 79 CPUPPCState *env = &cpu->env; 80 81 cpu_reset(cs); 82 83 /* All CPUs start halted. CPU0 is unhalted from the machine level 84 * reset code and the rest are explicitly started up by the guest 85 * using an RTAS call */ 86 cs->halted = 1; 87 88 env->spr[SPR_HIOR] = 0; 89 } 90 91 static void spapr_cpu_destroy(PowerPCCPU *cpu) 92 { 93 qemu_unregister_reset(spapr_cpu_reset, cpu); 94 } 95 96 static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, 97 Error **errp) 98 { 99 CPUPPCState *env = &cpu->env; 100 101 /* Set time-base frequency to 512 MHz */ 102 cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); 103 104 /* Enable PAPR mode in TCG or KVM */ 105 cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); 106 107 qemu_register_reset(spapr_cpu_reset, cpu); 108 spapr_cpu_reset(cpu); 109 } 110 111 /* 112 * Return the sPAPR CPU core type for @model which essentially is the CPU 113 * model specified with -cpu cmdline option. 114 */ 115 char *spapr_get_cpu_core_type(const char *model) 116 { 117 char *core_type; 118 gchar **model_pieces = g_strsplit(model, ",", 2); 119 gchar *cpu_model = g_ascii_strdown(model_pieces[0], -1); 120 g_strfreev(model_pieces); 121 122 core_type = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, cpu_model); 123 124 /* Check whether it exists or whether we have to look up an alias name */ 125 if (!object_class_by_name(core_type)) { 126 const char *realmodel; 127 128 g_free(core_type); 129 core_type = NULL; 130 realmodel = ppc_cpu_lookup_alias(cpu_model); 131 if (realmodel) { 132 core_type = spapr_get_cpu_core_type(realmodel); 133 } 134 } 135 g_free(cpu_model); 136 137 return core_type; 138 } 139 140 static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) 141 { 142 sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); 143 sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); 144 const char *typename = object_class_get_name(scc->cpu_class); 145 size_t size = object_type_get_instance_size(typename); 146 CPUCore *cc = CPU_CORE(dev); 147 int i; 148 149 for (i = 0; i < cc->nr_threads; i++) { 150 void *obj = sc->threads + i * size; 151 DeviceState *dev = DEVICE(obj); 152 CPUState *cs = CPU(dev); 153 PowerPCCPU *cpu = POWERPC_CPU(cs); 154 155 spapr_cpu_destroy(cpu); 156 object_unparent(cpu->intc); 157 cpu_remove_sync(cs); 158 object_unparent(obj); 159 } 160 g_free(sc->threads); 161 } 162 163 static void spapr_cpu_core_realize_child(Object *child, 164 sPAPRMachineState *spapr, Error **errp) 165 { 166 Error *local_err = NULL; 167 CPUState *cs = CPU(child); 168 PowerPCCPU *cpu = POWERPC_CPU(cs); 169 Object *obj; 170 171 object_property_set_bool(child, true, "realized", &local_err); 172 if (local_err) { 173 goto error; 174 } 175 176 spapr_cpu_init(spapr, cpu, &local_err); 177 if (local_err) { 178 goto error; 179 } 180 181 obj = object_new(spapr->icp_type); 182 object_property_add_child(child, "icp", obj, &error_abort); 183 object_unref(obj); 184 object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(spapr), 185 &error_abort); 186 object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort); 187 object_property_set_bool(obj, true, "realized", &local_err); 188 if (local_err) { 189 goto free_icp; 190 } 191 192 return; 193 194 free_icp: 195 object_unparent(obj); 196 error: 197 error_propagate(errp, local_err); 198 } 199 200 static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) 201 { 202 sPAPRMachineState *spapr; 203 sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); 204 sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); 205 CPUCore *cc = CPU_CORE(OBJECT(dev)); 206 const char *typename = object_class_get_name(scc->cpu_class); 207 size_t size = object_type_get_instance_size(typename); 208 Error *local_err = NULL; 209 void *obj; 210 int i, j; 211 212 spapr = (sPAPRMachineState *) qdev_get_machine(); 213 if (!object_dynamic_cast((Object *) spapr, TYPE_SPAPR_MACHINE)) { 214 error_setg(errp, "spapr-cpu-core needs a pseries machine"); 215 return; 216 } 217 218 sc->threads = g_malloc0(size * cc->nr_threads); 219 for (i = 0; i < cc->nr_threads; i++) { 220 char id[32]; 221 CPUState *cs; 222 PowerPCCPU *cpu; 223 224 obj = sc->threads + i * size; 225 226 object_initialize(obj, size, typename); 227 cs = CPU(obj); 228 cpu = POWERPC_CPU(cs); 229 cs->cpu_index = cc->core_id + i; 230 cpu->vcpu_id = (cc->core_id * spapr->vsmt / smp_threads) + i; 231 if (kvm_enabled() && !kvm_vcpu_id_is_valid(cpu->vcpu_id)) { 232 error_setg(&local_err, "Can't create CPU with id %d in KVM", 233 cpu->vcpu_id); 234 error_append_hint(&local_err, "Adjust the number of cpus to %d " 235 "or try to raise the number of threads per core\n", 236 cpu->vcpu_id * smp_threads / spapr->vsmt); 237 goto err; 238 } 239 240 241 /* Set NUMA node for the threads belonged to core */ 242 cpu->node_id = sc->node_id; 243 244 snprintf(id, sizeof(id), "thread[%d]", i); 245 object_property_add_child(OBJECT(sc), id, obj, &local_err); 246 if (local_err) { 247 goto err; 248 } 249 object_unref(obj); 250 } 251 252 for (j = 0; j < cc->nr_threads; j++) { 253 obj = sc->threads + j * size; 254 255 spapr_cpu_core_realize_child(obj, spapr, &local_err); 256 if (local_err) { 257 goto err; 258 } 259 } 260 return; 261 262 err: 263 while (--i >= 0) { 264 obj = sc->threads + i * size; 265 object_unparent(obj); 266 } 267 g_free(sc->threads); 268 error_propagate(errp, local_err); 269 } 270 271 static const char *spapr_core_models[] = { 272 /* 970 */ 273 "970_v2.2", 274 275 /* 970MP variants */ 276 "970mp_v1.0", 277 "970mp_v1.1", 278 279 /* POWER5+ */ 280 "power5+_v2.1", 281 282 /* POWER7 */ 283 "power7_v2.3", 284 285 /* POWER7+ */ 286 "power7+_v2.1", 287 288 /* POWER8 */ 289 "power8_v2.0", 290 291 /* POWER8E */ 292 "power8e_v2.1", 293 294 /* POWER8NVL */ 295 "power8nvl_v1.0", 296 297 /* POWER9 */ 298 "power9_v1.0", 299 }; 300 301 static Property spapr_cpu_core_properties[] = { 302 DEFINE_PROP_INT32("node-id", sPAPRCPUCore, node_id, CPU_UNSET_NUMA_NODE_ID), 303 DEFINE_PROP_END_OF_LIST() 304 }; 305 306 void spapr_cpu_core_class_init(ObjectClass *oc, void *data) 307 { 308 DeviceClass *dc = DEVICE_CLASS(oc); 309 sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); 310 311 dc->realize = spapr_cpu_core_realize; 312 dc->unrealize = spapr_cpu_core_unrealizefn; 313 dc->props = spapr_cpu_core_properties; 314 scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data); 315 g_assert(scc->cpu_class); 316 } 317 318 static const TypeInfo spapr_cpu_core_type_info = { 319 .name = TYPE_SPAPR_CPU_CORE, 320 .parent = TYPE_CPU_CORE, 321 .abstract = true, 322 .instance_size = sizeof(sPAPRCPUCore), 323 .class_size = sizeof(sPAPRCPUCoreClass), 324 }; 325 326 static void spapr_cpu_core_register_types(void) 327 { 328 int i; 329 330 type_register_static(&spapr_cpu_core_type_info); 331 332 for (i = 0; i < ARRAY_SIZE(spapr_core_models); i++) { 333 TypeInfo type_info = { 334 .parent = TYPE_SPAPR_CPU_CORE, 335 .instance_size = sizeof(sPAPRCPUCore), 336 .class_init = spapr_cpu_core_class_init, 337 .class_data = (void *) spapr_core_models[i], 338 }; 339 340 type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, 341 spapr_core_models[i]); 342 type_register(&type_info); 343 g_free((void *)type_info.name); 344 } 345 } 346 347 type_init(spapr_cpu_core_register_types) 348