]>
Commit | Line | Data |
---|---|---|
3b542549 BR |
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 | */ | |
71e8a915 | 9 | |
e9808d09 | 10 | #include "qemu/osdep.h" |
3b542549 BR |
11 | #include "hw/cpu/core.h" |
12 | #include "hw/ppc/spapr_cpu_core.h" | |
a27bd6c7 | 13 | #include "hw/qdev-properties.h" |
d6454270 | 14 | #include "migration/vmstate.h" |
fcf5ef2a | 15 | #include "target/ppc/cpu.h" |
3b542549 | 16 | #include "hw/ppc/spapr.h" |
3b542549 | 17 | #include "qapi/error.h" |
a9c94277 | 18 | #include "sysemu/cpus.h" |
e57ca75c | 19 | #include "sysemu/kvm.h" |
fcf5ef2a | 20 | #include "target/ppc/kvm_ppc.h" |
afd10a0f | 21 | #include "hw/ppc/ppc.h" |
fcf5ef2a | 22 | #include "target/ppc/mmu-hash64.h" |
a9c94277 | 23 | #include "sysemu/numa.h" |
71e8a915 | 24 | #include "sysemu/reset.h" |
1ec26c75 | 25 | #include "sysemu/hw_accel.h" |
e57ca75c | 26 | #include "qemu/error-report.h" |
afd10a0f | 27 | |
d1f2b469 | 28 | static void spapr_reset_vcpu(PowerPCCPU *cpu) |
afd10a0f | 29 | { |
afd10a0f BR |
30 | CPUState *cs = CPU(cpu); |
31 | CPUPPCState *env = &cpu->env; | |
d6322252 | 32 | PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); |
ce2918cb | 33 | SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); |
da20aed1 | 34 | target_ulong lpcr; |
d49e8a9b | 35 | SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); |
afd10a0f BR |
36 | |
37 | cpu_reset(cs); | |
38 | ||
39 | /* All CPUs start halted. CPU0 is unhalted from the machine level | |
40 | * reset code and the rest are explicitly started up by the guest | |
41 | * using an RTAS call */ | |
42 | cs->halted = 1; | |
43 | ||
44 | env->spr[SPR_HIOR] = 0; | |
d6322252 | 45 | |
da20aed1 DG |
46 | lpcr = env->spr[SPR_LPCR]; |
47 | ||
48 | /* Set emulated LPCR to not send interrupts to hypervisor. Note that | |
49 | * under KVM, the actual HW LPCR will be set differently by KVM itself, | |
50 | * the settings below ensure proper operations with TCG in absence of | |
51 | * a real hypervisor. | |
52 | * | |
47a9b551 DG |
53 | * Disable Power-saving mode Exit Cause exceptions for the CPU, so |
54 | * we don't get spurious wakups before an RTAS start-cpu call. | |
70de0967 | 55 | * For the same reason, set PSSCR_EC. |
da20aed1 | 56 | */ |
e8b1144e | 57 | lpcr &= ~(LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm); |
da20aed1 | 58 | lpcr |= LPCR_LPES0 | LPCR_LPES1; |
70de0967 | 59 | env->spr[SPR_PSSCR] |= PSSCR_EC; |
da20aed1 | 60 | |
da20aed1 DG |
61 | ppc_store_lpcr(cpu, lpcr); |
62 | ||
63 | /* Set a full AMOR so guest can use the AMR as it sees fit */ | |
64 | env->spr[SPR_AMOR] = 0xffffffffffffffffull; | |
7388efaf DG |
65 | |
66 | spapr_cpu->vpa_addr = 0; | |
67 | spapr_cpu->slb_shadow_addr = 0; | |
68 | spapr_cpu->slb_shadow_size = 0; | |
69 | spapr_cpu->dtl_addr = 0; | |
70 | spapr_cpu->dtl_size = 0; | |
e2e4f641 | 71 | |
d49e8a9b | 72 | spapr_caps_cpu_apply(spapr, cpu); |
e5ca28ec DG |
73 | |
74 | kvm_check_mmu(cpu, &error_fatal); | |
d49e8a9b CLG |
75 | |
76 | spapr_irq_cpu_intc_reset(spapr, cpu); | |
afd10a0f BR |
77 | } |
78 | ||
395a20d3 AK |
79 | void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, |
80 | target_ulong r1, target_ulong r3, | |
81 | target_ulong r4) | |
84369f63 | 82 | { |
47a9b551 | 83 | PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); |
84369f63 DG |
84 | CPUPPCState *env = &cpu->env; |
85 | ||
86 | env->nip = nip; | |
395a20d3 | 87 | env->gpr[1] = r1; |
84369f63 | 88 | env->gpr[3] = r3; |
395a20d3 | 89 | env->gpr[4] = r4; |
a84f7179 | 90 | kvmppc_set_reg_ppc_online(cpu, 1); |
84369f63 | 91 | CPU(cpu)->halted = 0; |
47a9b551 DG |
92 | /* Enable Power-saving mode Exit Cause exceptions */ |
93 | ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm); | |
84369f63 DG |
94 | } |
95 | ||
94a94e4c BR |
96 | /* |
97 | * Return the sPAPR CPU core type for @model which essentially is the CPU | |
98 | * model specified with -cpu cmdline option. | |
99 | */ | |
2e9c10eb | 100 | const char *spapr_get_cpu_core_type(const char *cpu_type) |
94a94e4c | 101 | { |
2e9c10eb IM |
102 | int len = strlen(cpu_type) - strlen(POWERPC_CPU_TYPE_SUFFIX); |
103 | char *core_type = g_strdup_printf(SPAPR_CPU_CORE_TYPE_NAME("%.*s"), | |
104 | len, cpu_type); | |
105 | ObjectClass *oc = object_class_by_name(core_type); | |
106 | ||
107 | g_free(core_type); | |
108 | if (!oc) { | |
109 | return NULL; | |
4babfaf0 TH |
110 | } |
111 | ||
2e9c10eb | 112 | return object_class_get_name(oc); |
94a94e4c BR |
113 | } |
114 | ||
7f9fe3f0 GK |
115 | static bool slb_shadow_needed(void *opaque) |
116 | { | |
ce2918cb | 117 | SpaprCpuState *spapr_cpu = opaque; |
7f9fe3f0 GK |
118 | |
119 | return spapr_cpu->slb_shadow_addr != 0; | |
120 | } | |
121 | ||
122 | static const VMStateDescription vmstate_spapr_cpu_slb_shadow = { | |
123 | .name = "spapr_cpu/vpa/slb_shadow", | |
124 | .version_id = 1, | |
125 | .minimum_version_id = 1, | |
126 | .needed = slb_shadow_needed, | |
127 | .fields = (VMStateField[]) { | |
ce2918cb DG |
128 | VMSTATE_UINT64(slb_shadow_addr, SpaprCpuState), |
129 | VMSTATE_UINT64(slb_shadow_size, SpaprCpuState), | |
7f9fe3f0 GK |
130 | VMSTATE_END_OF_LIST() |
131 | } | |
132 | }; | |
133 | ||
134 | static bool dtl_needed(void *opaque) | |
135 | { | |
ce2918cb | 136 | SpaprCpuState *spapr_cpu = opaque; |
7f9fe3f0 GK |
137 | |
138 | return spapr_cpu->dtl_addr != 0; | |
139 | } | |
140 | ||
141 | static const VMStateDescription vmstate_spapr_cpu_dtl = { | |
142 | .name = "spapr_cpu/vpa/dtl", | |
143 | .version_id = 1, | |
144 | .minimum_version_id = 1, | |
145 | .needed = dtl_needed, | |
146 | .fields = (VMStateField[]) { | |
ce2918cb DG |
147 | VMSTATE_UINT64(dtl_addr, SpaprCpuState), |
148 | VMSTATE_UINT64(dtl_size, SpaprCpuState), | |
7f9fe3f0 GK |
149 | VMSTATE_END_OF_LIST() |
150 | } | |
151 | }; | |
152 | ||
153 | static bool vpa_needed(void *opaque) | |
154 | { | |
ce2918cb | 155 | SpaprCpuState *spapr_cpu = opaque; |
7f9fe3f0 GK |
156 | |
157 | return spapr_cpu->vpa_addr != 0; | |
158 | } | |
159 | ||
160 | static const VMStateDescription vmstate_spapr_cpu_vpa = { | |
161 | .name = "spapr_cpu/vpa", | |
162 | .version_id = 1, | |
163 | .minimum_version_id = 1, | |
164 | .needed = vpa_needed, | |
165 | .fields = (VMStateField[]) { | |
ce2918cb | 166 | VMSTATE_UINT64(vpa_addr, SpaprCpuState), |
7f9fe3f0 GK |
167 | VMSTATE_END_OF_LIST() |
168 | }, | |
169 | .subsections = (const VMStateDescription * []) { | |
170 | &vmstate_spapr_cpu_slb_shadow, | |
171 | &vmstate_spapr_cpu_dtl, | |
172 | NULL | |
173 | } | |
174 | }; | |
175 | ||
b9402026 GK |
176 | static const VMStateDescription vmstate_spapr_cpu_state = { |
177 | .name = "spapr_cpu", | |
178 | .version_id = 1, | |
179 | .minimum_version_id = 1, | |
180 | .fields = (VMStateField[]) { | |
181 | VMSTATE_END_OF_LIST() | |
182 | }, | |
7f9fe3f0 GK |
183 | .subsections = (const VMStateDescription * []) { |
184 | &vmstate_spapr_cpu_vpa, | |
185 | NULL | |
186 | } | |
b9402026 GK |
187 | }; |
188 | ||
ce2918cb | 189 | static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc) |
cc71c776 BR |
190 | { |
191 | if (!sc->pre_3_0_migration) { | |
192 | vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data); | |
193 | } | |
0990ce6a | 194 | spapr_irq_cpu_intc_destroy(SPAPR_MACHINE(qdev_get_machine()), cpu); |
cc71c776 BR |
195 | cpu_remove_sync(CPU(cpu)); |
196 | object_unparent(OBJECT(cpu)); | |
197 | } | |
198 | ||
d1f2b469 GK |
199 | /* |
200 | * Called when CPUs are hot-plugged. | |
201 | */ | |
202 | static void spapr_cpu_core_reset(DeviceState *dev) | |
203 | { | |
204 | CPUCore *cc = CPU_CORE(dev); | |
205 | SpaprCpuCore *sc = SPAPR_CPU_CORE(dev); | |
206 | int i; | |
207 | ||
208 | for (i = 0; i < cc->nr_threads; i++) { | |
209 | spapr_reset_vcpu(sc->threads[i]); | |
210 | } | |
211 | } | |
212 | ||
213 | /* | |
214 | * Called by the machine reset. | |
215 | */ | |
216 | static void spapr_cpu_core_reset_handler(void *opaque) | |
217 | { | |
218 | spapr_cpu_core_reset(opaque); | |
219 | } | |
220 | ||
b69c3c21 | 221 | static void spapr_cpu_core_unrealize(DeviceState *dev) |
cc71c776 | 222 | { |
ce2918cb | 223 | SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); |
cc71c776 BR |
224 | CPUCore *cc = CPU_CORE(dev); |
225 | int i; | |
226 | ||
d1f2b469 GK |
227 | qemu_unregister_reset(spapr_cpu_core_reset_handler, sc); |
228 | ||
cc71c776 BR |
229 | for (i = 0; i < cc->nr_threads; i++) { |
230 | spapr_unrealize_vcpu(sc->threads[i], sc); | |
231 | } | |
232 | g_free(sc->threads); | |
233 | } | |
234 | ||
ce2918cb DG |
235 | static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr, |
236 | SpaprCpuCore *sc, Error **errp) | |
3b542549 | 237 | { |
b1d40d6e | 238 | CPUPPCState *env = &cpu->env; |
cc71c776 | 239 | CPUState *cs = CPU(cpu); |
7093645a | 240 | Error *local_err = NULL; |
5bc8d26d | 241 | |
118bfd76 | 242 | if (!qdev_realize(DEVICE(cpu), NULL, &local_err)) { |
c8a98293 | 243 | goto error; |
5bc8d26d | 244 | } |
3b542549 | 245 | |
b1d40d6e DG |
246 | /* Set time-base frequency to 512 MHz */ |
247 | cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); | |
248 | ||
249 | cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); | |
250 | kvmppc_set_papr(cpu); | |
3b542549 | 251 | |
ebd6be08 | 252 | if (spapr_irq_cpu_intc_create(spapr, cpu, &local_err) < 0) { |
90f8db52 | 253 | goto error_intc_create; |
3b542549 | 254 | } |
5bc8d26d | 255 | |
cc71c776 BR |
256 | if (!sc->pre_3_0_migration) { |
257 | vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state, | |
258 | cpu->machine_data); | |
259 | } | |
260 | ||
c8a98293 GK |
261 | return; |
262 | ||
90f8db52 | 263 | error_intc_create: |
9986ddec | 264 | cpu_remove_sync(CPU(cpu)); |
6595ab31 | 265 | error: |
c8a98293 | 266 | error_propagate(errp, local_err); |
3b542549 BR |
267 | } |
268 | ||
ce2918cb | 269 | static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp) |
d9f0e34c | 270 | { |
ce2918cb | 271 | SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc); |
d9f0e34c GK |
272 | CPUCore *cc = CPU_CORE(sc); |
273 | Object *obj; | |
274 | char *id; | |
275 | CPUState *cs; | |
276 | PowerPCCPU *cpu; | |
277 | Error *local_err = NULL; | |
278 | ||
279 | obj = object_new(scc->cpu_type); | |
280 | ||
281 | cs = CPU(obj); | |
282 | cpu = POWERPC_CPU(obj); | |
283 | cs->cpu_index = cc->core_id + i; | |
284 | spapr_set_vcpu_id(cpu, cs->cpu_index, &local_err); | |
285 | if (local_err) { | |
286 | goto err; | |
287 | } | |
288 | ||
289 | cpu->node_id = sc->node_id; | |
290 | ||
291 | id = g_strdup_printf("thread[%d]", i); | |
d2623129 | 292 | object_property_add_child(OBJECT(sc), id, obj); |
d9f0e34c | 293 | g_free(id); |
d9f0e34c | 294 | |
ce2918cb | 295 | cpu->machine_data = g_new0(SpaprCpuState, 1); |
7388efaf | 296 | |
d9f0e34c GK |
297 | object_unref(obj); |
298 | return cpu; | |
299 | ||
300 | err: | |
301 | object_unref(obj); | |
302 | error_propagate(errp, local_err); | |
303 | return NULL; | |
304 | } | |
305 | ||
ce2918cb | 306 | static void spapr_delete_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc) |
d9f0e34c | 307 | { |
ce2918cb | 308 | SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu); |
7388efaf DG |
309 | |
310 | cpu->machine_data = NULL; | |
311 | g_free(spapr_cpu); | |
d9f0e34c GK |
312 | object_unparent(OBJECT(cpu)); |
313 | } | |
314 | ||
3b542549 BR |
315 | static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) |
316 | { | |
e7cca3e9 GK |
317 | /* We don't use SPAPR_MACHINE() in order to exit gracefully if the user |
318 | * tries to add a sPAPR CPU core to a non-pseries machine. | |
319 | */ | |
ce2918cb DG |
320 | SpaprMachineState *spapr = |
321 | (SpaprMachineState *) object_dynamic_cast(qdev_get_machine(), | |
e7cca3e9 | 322 | TYPE_SPAPR_MACHINE); |
ce2918cb | 323 | SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); |
3b542549 | 324 | CPUCore *cc = CPU_CORE(OBJECT(dev)); |
3b542549 | 325 | Error *local_err = NULL; |
7093645a | 326 | int i, j; |
3b542549 | 327 | |
e7cca3e9 GK |
328 | if (!spapr) { |
329 | error_setg(errp, TYPE_SPAPR_CPU_CORE " needs a pseries machine"); | |
2363d5ee TH |
330 | return; |
331 | } | |
332 | ||
94ad93bd | 333 | sc->threads = g_new(PowerPCCPU *, cc->nr_threads); |
3b542549 | 334 | for (i = 0; i < cc->nr_threads; i++) { |
d9f0e34c | 335 | sc->threads[i] = spapr_create_vcpu(sc, i, &local_err); |
3b542549 BR |
336 | if (local_err) { |
337 | goto err; | |
338 | } | |
339 | } | |
7093645a BR |
340 | |
341 | for (j = 0; j < cc->nr_threads; j++) { | |
cc71c776 | 342 | spapr_realize_vcpu(sc->threads[j], spapr, sc, &local_err); |
7093645a | 343 | if (local_err) { |
9986ddec | 344 | goto err_unrealize; |
7093645a | 345 | } |
3b542549 | 346 | } |
d1f2b469 GK |
347 | |
348 | qemu_register_reset(spapr_cpu_core_reset_handler, sc); | |
7093645a | 349 | return; |
3b542549 | 350 | |
9986ddec GK |
351 | err_unrealize: |
352 | while (--j >= 0) { | |
cc71c776 | 353 | spapr_unrealize_vcpu(sc->threads[j], sc); |
9986ddec | 354 | } |
3b542549 | 355 | err: |
dde35bc9 | 356 | while (--i >= 0) { |
b9402026 | 357 | spapr_delete_vcpu(sc->threads[i], sc); |
3b542549 BR |
358 | } |
359 | g_free(sc->threads); | |
360 | error_propagate(errp, local_err); | |
361 | } | |
362 | ||
0b8497f0 | 363 | static Property spapr_cpu_core_properties[] = { |
ce2918cb DG |
364 | DEFINE_PROP_INT32("node-id", SpaprCpuCore, node_id, CPU_UNSET_NUMA_NODE_ID), |
365 | DEFINE_PROP_BOOL("pre-3.0-migration", SpaprCpuCore, pre_3_0_migration, | |
b9402026 | 366 | false), |
0b8497f0 IM |
367 | DEFINE_PROP_END_OF_LIST() |
368 | }; | |
369 | ||
5bbb2641 | 370 | static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) |
3b542549 | 371 | { |
7ebaf795 | 372 | DeviceClass *dc = DEVICE_CLASS(oc); |
ce2918cb | 373 | SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); |
7ebaf795 BR |
374 | |
375 | dc->realize = spapr_cpu_core_realize; | |
b1d40d6e | 376 | dc->unrealize = spapr_cpu_core_unrealize; |
d1f2b469 | 377 | dc->reset = spapr_cpu_core_reset; |
4f67d30b | 378 | device_class_set_props(dc, spapr_cpu_core_properties); |
b51d3c88 | 379 | scc->cpu_type = data; |
3b542549 BR |
380 | } |
381 | ||
44cd95e3 IM |
382 | #define DEFINE_SPAPR_CPU_CORE_TYPE(cpu_model) \ |
383 | { \ | |
384 | .parent = TYPE_SPAPR_CPU_CORE, \ | |
b51d3c88 | 385 | .class_data = (void *) POWERPC_CPU_TYPE_NAME(cpu_model), \ |
44cd95e3 IM |
386 | .class_init = spapr_cpu_core_class_init, \ |
387 | .name = SPAPR_CPU_CORE_TYPE_NAME(cpu_model), \ | |
3b542549 | 388 | } |
3b542549 | 389 | |
44cd95e3 IM |
390 | static const TypeInfo spapr_cpu_core_type_infos[] = { |
391 | { | |
392 | .name = TYPE_SPAPR_CPU_CORE, | |
393 | .parent = TYPE_CPU_CORE, | |
394 | .abstract = true, | |
ce2918cb DG |
395 | .instance_size = sizeof(SpaprCpuCore), |
396 | .class_size = sizeof(SpaprCpuCoreClass), | |
44cd95e3 IM |
397 | }, |
398 | DEFINE_SPAPR_CPU_CORE_TYPE("970_v2.2"), | |
399 | DEFINE_SPAPR_CPU_CORE_TYPE("970mp_v1.0"), | |
400 | DEFINE_SPAPR_CPU_CORE_TYPE("970mp_v1.1"), | |
401 | DEFINE_SPAPR_CPU_CORE_TYPE("power5+_v2.1"), | |
402 | DEFINE_SPAPR_CPU_CORE_TYPE("power7_v2.3"), | |
403 | DEFINE_SPAPR_CPU_CORE_TYPE("power7+_v2.1"), | |
404 | DEFINE_SPAPR_CPU_CORE_TYPE("power8_v2.0"), | |
405 | DEFINE_SPAPR_CPU_CORE_TYPE("power8e_v2.1"), | |
406 | DEFINE_SPAPR_CPU_CORE_TYPE("power8nvl_v1.0"), | |
407 | DEFINE_SPAPR_CPU_CORE_TYPE("power9_v1.0"), | |
408 | DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.0"), | |
0bbf14a0 | 409 | DEFINE_SPAPR_CPU_CORE_TYPE("power10_v1.0"), |
5bbb2641 IM |
410 | #ifdef CONFIG_KVM |
411 | DEFINE_SPAPR_CPU_CORE_TYPE("host"), | |
412 | #endif | |
44cd95e3 IM |
413 | }; |
414 | ||
415 | DEFINE_TYPES(spapr_cpu_core_type_infos) |