]>
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 <[email protected]> | |
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" | |
fcf5ef2a | 11 | #include "target/ppc/cpu.h" |
3b542549 BR |
12 | #include "hw/ppc/spapr.h" |
13 | #include "hw/boards.h" | |
14 | #include "qapi/error.h" | |
a9c94277 | 15 | #include "sysemu/cpus.h" |
e57ca75c | 16 | #include "sysemu/kvm.h" |
fcf5ef2a | 17 | #include "target/ppc/kvm_ppc.h" |
afd10a0f | 18 | #include "hw/ppc/ppc.h" |
fcf5ef2a | 19 | #include "target/ppc/mmu-hash64.h" |
a9c94277 | 20 | #include "sysemu/numa.h" |
e57ca75c | 21 | #include "qemu/error-report.h" |
afd10a0f | 22 | |
7843c0d6 DG |
23 | void spapr_cpu_parse_features(sPAPRMachineState *spapr) |
24 | { | |
25 | /* | |
26 | * Backwards compatibility hack: | |
27 | * | |
28 | * CPUs had a "compat=" property which didn't make sense for | |
29 | * anything except pseries. It was replaced by "max-cpu-compat" | |
30 | * machine option. This supports old command lines like | |
31 | * -cpu POWER8,compat=power7 | |
32 | * By stripping the compat option and applying it to the machine | |
33 | * before passing it on to the cpu level parser. | |
34 | */ | |
35 | gchar **inpieces; | |
36 | int i, j; | |
37 | gchar *compat_str = NULL; | |
38 | ||
39 | inpieces = g_strsplit(MACHINE(spapr)->cpu_model, ",", 0); | |
40 | ||
41 | /* inpieces[0] is the actual model string */ | |
42 | i = 1; | |
43 | j = 1; | |
44 | while (inpieces[i]) { | |
45 | if (g_str_has_prefix(inpieces[i], "compat=")) { | |
46 | /* in case of multiple compat= options */ | |
47 | g_free(compat_str); | |
48 | compat_str = inpieces[i]; | |
49 | } else { | |
50 | j++; | |
51 | } | |
52 | ||
53 | i++; | |
54 | /* Excise compat options from list */ | |
55 | inpieces[j] = inpieces[i]; | |
56 | } | |
57 | ||
58 | if (compat_str) { | |
59 | char *val = compat_str + strlen("compat="); | |
60 | gchar *newprops = g_strjoinv(",", inpieces); | |
61 | ||
62 | object_property_set_str(OBJECT(spapr), val, "max-cpu-compat", | |
63 | &error_fatal); | |
64 | ||
65 | ppc_cpu_parse_features(newprops); | |
66 | g_free(newprops); | |
67 | } else { | |
68 | ppc_cpu_parse_features(MACHINE(spapr)->cpu_model); | |
69 | } | |
70 | ||
71 | g_strfreev(inpieces); | |
72 | } | |
73 | ||
afd10a0f BR |
74 | static void spapr_cpu_reset(void *opaque) |
75 | { | |
76 | sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); | |
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 | ||
e57ca75c DG |
90 | /* |
91 | * This is a hack for the benefit of KVM PR - it abuses the SDR1 | |
92 | * slot in kvm_sregs to communicate the userspace address of the | |
93 | * HPT | |
94 | */ | |
95 | if (kvm_enabled()) { | |
96 | env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | |
97 | | (spapr->htab_shift - 18); | |
98 | if (kvmppc_put_books_sregs(cpu) < 0) { | |
99 | error_report("Unable to update SDR1 in KVM"); | |
100 | exit(1); | |
101 | } | |
102 | } | |
afd10a0f BR |
103 | } |
104 | ||
6f4b5c3e BR |
105 | static void spapr_cpu_destroy(PowerPCCPU *cpu) |
106 | { | |
6f4b5c3e BR |
107 | qemu_unregister_reset(spapr_cpu_reset, cpu); |
108 | } | |
109 | ||
0c86d0fd DG |
110 | static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, |
111 | Error **errp) | |
afd10a0f BR |
112 | { |
113 | CPUPPCState *env = &cpu->env; | |
114 | ||
115 | /* Set time-base frequency to 512 MHz */ | |
116 | cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); | |
117 | ||
118 | /* Enable PAPR mode in TCG or KVM */ | |
b7b0b1f1 | 119 | cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); |
afd10a0f | 120 | |
afd10a0f | 121 | qemu_register_reset(spapr_cpu_reset, cpu); |
af81cf32 | 122 | spapr_cpu_reset(cpu); |
afd10a0f | 123 | } |
3b542549 | 124 | |
94a94e4c BR |
125 | /* |
126 | * Return the sPAPR CPU core type for @model which essentially is the CPU | |
127 | * model specified with -cpu cmdline option. | |
128 | */ | |
129 | char *spapr_get_cpu_core_type(const char *model) | |
130 | { | |
131 | char *core_type; | |
132 | gchar **model_pieces = g_strsplit(model, ",", 2); | |
133 | ||
134 | core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); | |
4babfaf0 TH |
135 | |
136 | /* Check whether it exists or whether we have to look up an alias name */ | |
137 | if (!object_class_by_name(core_type)) { | |
138 | const char *realmodel; | |
139 | ||
140 | g_free(core_type); | |
e17a8779 GK |
141 | core_type = NULL; |
142 | realmodel = ppc_cpu_lookup_alias(model_pieces[0]); | |
4babfaf0 | 143 | if (realmodel) { |
e17a8779 | 144 | core_type = spapr_get_cpu_core_type(realmodel); |
4babfaf0 | 145 | } |
4babfaf0 TH |
146 | } |
147 | ||
e17a8779 | 148 | g_strfreev(model_pieces); |
94a94e4c BR |
149 | return core_type; |
150 | } | |
151 | ||
f844616b | 152 | static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) |
6f4b5c3e BR |
153 | { |
154 | sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); | |
7ebaf795 BR |
155 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); |
156 | const char *typename = object_class_get_name(scc->cpu_class); | |
6f4b5c3e | 157 | size_t size = object_type_get_instance_size(typename); |
6f4b5c3e | 158 | CPUCore *cc = CPU_CORE(dev); |
6f4b5c3e BR |
159 | int i; |
160 | ||
161 | for (i = 0; i < cc->nr_threads; i++) { | |
162 | void *obj = sc->threads + i * size; | |
163 | DeviceState *dev = DEVICE(obj); | |
164 | CPUState *cs = CPU(dev); | |
165 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
166 | ||
167 | spapr_cpu_destroy(cpu); | |
8f37e54e | 168 | object_unparent(cpu->intc); |
6f4b5c3e BR |
169 | cpu_remove_sync(cs); |
170 | object_unparent(obj); | |
171 | } | |
8a1eb71b | 172 | g_free(sc->threads); |
6f4b5c3e BR |
173 | } |
174 | ||
7093645a | 175 | static void spapr_cpu_core_realize_child(Object *child, Error **errp) |
3b542549 | 176 | { |
7093645a | 177 | Error *local_err = NULL; |
3b542549 BR |
178 | sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); |
179 | CPUState *cs = CPU(child); | |
180 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
6595ab31 | 181 | Object *obj; |
5bc8d26d | 182 | |
9ed65663 | 183 | object_property_set_bool(child, true, "realized", &local_err); |
5bc8d26d | 184 | if (local_err) { |
c8a98293 | 185 | goto error; |
5bc8d26d | 186 | } |
3b542549 | 187 | |
9ed65663 | 188 | spapr_cpu_init(spapr, cpu, &local_err); |
f11235b9 | 189 | if (local_err) { |
c8a98293 | 190 | goto error; |
3b542549 BR |
191 | } |
192 | ||
9ed65663 GK |
193 | obj = object_new(spapr->icp_type); |
194 | object_property_add_child(child, "icp", obj, &error_abort); | |
195 | object_unref(obj); | |
196 | object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(spapr), | |
197 | &error_abort); | |
198 | object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort); | |
199 | object_property_set_bool(obj, true, "realized", &local_err); | |
f11235b9 | 200 | if (local_err) { |
6595ab31 | 201 | goto free_icp; |
3b542549 | 202 | } |
5bc8d26d | 203 | |
c8a98293 GK |
204 | return; |
205 | ||
6595ab31 | 206 | free_icp: |
c8a98293 | 207 | object_unparent(obj); |
6595ab31 | 208 | error: |
c8a98293 | 209 | error_propagate(errp, local_err); |
3b542549 BR |
210 | } |
211 | ||
212 | static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) | |
213 | { | |
214 | sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); | |
7ebaf795 | 215 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); |
3b542549 | 216 | CPUCore *cc = CPU_CORE(OBJECT(dev)); |
7ebaf795 | 217 | const char *typename = object_class_get_name(scc->cpu_class); |
3b542549 BR |
218 | size_t size = object_type_get_instance_size(typename); |
219 | Error *local_err = NULL; | |
7093645a BR |
220 | void *obj; |
221 | int i, j; | |
3b542549 BR |
222 | |
223 | sc->threads = g_malloc0(size * cc->nr_threads); | |
224 | for (i = 0; i < cc->nr_threads; i++) { | |
225 | char id[32]; | |
b63578bd | 226 | CPUState *cs; |
15f8b142 | 227 | PowerPCCPU *cpu; |
b63578bd | 228 | |
7093645a | 229 | obj = sc->threads + i * size; |
3b542549 BR |
230 | |
231 | object_initialize(obj, size, typename); | |
b63578bd | 232 | cs = CPU(obj); |
15f8b142 | 233 | cpu = POWERPC_CPU(cs); |
b63578bd | 234 | cs->cpu_index = cc->core_id + i; |
17b7c39e | 235 | |
722387e7 | 236 | /* Set NUMA node for the threads belonged to core */ |
15f8b142 | 237 | cpu->node_id = sc->node_id; |
17b7c39e | 238 | |
3b542549 BR |
239 | snprintf(id, sizeof(id), "thread[%d]", i); |
240 | object_property_add_child(OBJECT(sc), id, obj, &local_err); | |
241 | if (local_err) { | |
242 | goto err; | |
243 | } | |
8e758dee | 244 | object_unref(obj); |
3b542549 | 245 | } |
7093645a BR |
246 | |
247 | for (j = 0; j < cc->nr_threads; j++) { | |
248 | obj = sc->threads + j * size; | |
249 | ||
250 | spapr_cpu_core_realize_child(obj, &local_err); | |
251 | if (local_err) { | |
252 | goto err; | |
253 | } | |
3b542549 | 254 | } |
7093645a | 255 | return; |
3b542549 BR |
256 | |
257 | err: | |
dde35bc9 | 258 | while (--i >= 0) { |
3b542549 BR |
259 | obj = sc->threads + i * size; |
260 | object_unparent(obj); | |
3b542549 BR |
261 | } |
262 | g_free(sc->threads); | |
263 | error_propagate(errp, local_err); | |
264 | } | |
265 | ||
7ebaf795 | 266 | static const char *spapr_core_models[] = { |
4babfaf0 | 267 | /* 970 */ |
7ebaf795 | 268 | "970_v2.2", |
ff461b8d | 269 | |
4babfaf0 | 270 | /* 970MP variants */ |
7ebaf795 BR |
271 | "970MP_v1.0", |
272 | "970mp_v1.0", | |
273 | "970MP_v1.1", | |
274 | "970mp_v1.1", | |
470f2157 | 275 | |
4babfaf0 | 276 | /* POWER5+ */ |
7ebaf795 | 277 | "POWER5+_v2.1", |
ff461b8d | 278 | |
4babfaf0 | 279 | /* POWER7 */ |
7ebaf795 | 280 | "POWER7_v2.3", |
3b542549 | 281 | |
4babfaf0 | 282 | /* POWER7+ */ |
7ebaf795 | 283 | "POWER7+_v2.1", |
3b542549 | 284 | |
4babfaf0 | 285 | /* POWER8 */ |
7ebaf795 | 286 | "POWER8_v2.0", |
3b542549 | 287 | |
4babfaf0 | 288 | /* POWER8E */ |
7ebaf795 | 289 | "POWER8E_v2.1", |
3b542549 | 290 | |
4babfaf0 | 291 | /* POWER8NVL */ |
7ebaf795 | 292 | "POWER8NVL_v1.0", |
24d8e565 SJS |
293 | |
294 | /* POWER9 */ | |
295 | "POWER9_v1.0", | |
3b542549 BR |
296 | }; |
297 | ||
0b8497f0 IM |
298 | static Property spapr_cpu_core_properties[] = { |
299 | DEFINE_PROP_INT32("node-id", sPAPRCPUCore, node_id, CPU_UNSET_NUMA_NODE_ID), | |
300 | DEFINE_PROP_END_OF_LIST() | |
301 | }; | |
302 | ||
7ebaf795 | 303 | void spapr_cpu_core_class_init(ObjectClass *oc, void *data) |
3b542549 | 304 | { |
7ebaf795 BR |
305 | DeviceClass *dc = DEVICE_CLASS(oc); |
306 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); | |
307 | ||
308 | dc->realize = spapr_cpu_core_realize; | |
f844616b | 309 | dc->unrealize = spapr_cpu_core_unrealizefn; |
0b8497f0 | 310 | dc->props = spapr_cpu_core_properties; |
7ebaf795 BR |
311 | scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data); |
312 | g_assert(scc->cpu_class); | |
3b542549 BR |
313 | } |
314 | ||
315 | static const TypeInfo spapr_cpu_core_type_info = { | |
316 | .name = TYPE_SPAPR_CPU_CORE, | |
317 | .parent = TYPE_CPU_CORE, | |
318 | .abstract = true, | |
319 | .instance_size = sizeof(sPAPRCPUCore), | |
7ebaf795 | 320 | .class_size = sizeof(sPAPRCPUCoreClass), |
3b542549 BR |
321 | }; |
322 | ||
323 | static void spapr_cpu_core_register_types(void) | |
324 | { | |
7ebaf795 | 325 | int i; |
3b542549 BR |
326 | |
327 | type_register_static(&spapr_cpu_core_type_info); | |
7ebaf795 BR |
328 | |
329 | for (i = 0; i < ARRAY_SIZE(spapr_core_models); i++) { | |
330 | TypeInfo type_info = { | |
331 | .parent = TYPE_SPAPR_CPU_CORE, | |
332 | .instance_size = sizeof(sPAPRCPUCore), | |
333 | .class_init = spapr_cpu_core_class_init, | |
334 | .class_data = (void *) spapr_core_models[i], | |
335 | }; | |
336 | ||
337 | type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, | |
338 | spapr_core_models[i]); | |
339 | type_register(&type_info); | |
340 | g_free((void *)type_info.name); | |
3b542549 BR |
341 | } |
342 | } | |
343 | ||
344 | type_init(spapr_cpu_core_register_types) |