]>
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 BR |
22 | |
23 | static void spapr_cpu_reset(void *opaque) | |
24 | { | |
25 | sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); | |
26 | PowerPCCPU *cpu = opaque; | |
27 | CPUState *cs = CPU(cpu); | |
28 | CPUPPCState *env = &cpu->env; | |
29 | ||
30 | cpu_reset(cs); | |
31 | ||
32 | /* All CPUs start halted. CPU0 is unhalted from the machine level | |
33 | * reset code and the rest are explicitly started up by the guest | |
34 | * using an RTAS call */ | |
35 | cs->halted = 1; | |
36 | ||
37 | env->spr[SPR_HIOR] = 0; | |
38 | ||
e57ca75c DG |
39 | /* |
40 | * This is a hack for the benefit of KVM PR - it abuses the SDR1 | |
41 | * slot in kvm_sregs to communicate the userspace address of the | |
42 | * HPT | |
43 | */ | |
44 | if (kvm_enabled()) { | |
45 | env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | |
46 | | (spapr->htab_shift - 18); | |
47 | if (kvmppc_put_books_sregs(cpu) < 0) { | |
48 | error_report("Unable to update SDR1 in KVM"); | |
49 | exit(1); | |
50 | } | |
51 | } | |
afd10a0f BR |
52 | } |
53 | ||
6f4b5c3e BR |
54 | static void spapr_cpu_destroy(PowerPCCPU *cpu) |
55 | { | |
56 | sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); | |
57 | ||
b4f27d71 | 58 | xics_cpu_destroy(XICS_FABRIC(spapr), cpu); |
6f4b5c3e BR |
59 | qemu_unregister_reset(spapr_cpu_reset, cpu); |
60 | } | |
61 | ||
0c86d0fd DG |
62 | static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu, |
63 | Error **errp) | |
afd10a0f BR |
64 | { |
65 | CPUPPCState *env = &cpu->env; | |
66 | ||
67 | /* Set time-base frequency to 512 MHz */ | |
68 | cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); | |
69 | ||
70 | /* Enable PAPR mode in TCG or KVM */ | |
b7b0b1f1 | 71 | cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); |
afd10a0f BR |
72 | |
73 | if (cpu->max_compat) { | |
74 | Error *local_err = NULL; | |
75 | ||
76 | ppc_set_compat(cpu, cpu->max_compat, &local_err); | |
77 | if (local_err) { | |
78 | error_propagate(errp, local_err); | |
79 | return; | |
80 | } | |
81 | } | |
82 | ||
afd10a0f | 83 | qemu_register_reset(spapr_cpu_reset, cpu); |
af81cf32 | 84 | spapr_cpu_reset(cpu); |
afd10a0f | 85 | } |
3b542549 | 86 | |
94a94e4c BR |
87 | /* |
88 | * Return the sPAPR CPU core type for @model which essentially is the CPU | |
89 | * model specified with -cpu cmdline option. | |
90 | */ | |
91 | char *spapr_get_cpu_core_type(const char *model) | |
92 | { | |
93 | char *core_type; | |
94 | gchar **model_pieces = g_strsplit(model, ",", 2); | |
95 | ||
96 | core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); | |
4babfaf0 TH |
97 | |
98 | /* Check whether it exists or whether we have to look up an alias name */ | |
99 | if (!object_class_by_name(core_type)) { | |
100 | const char *realmodel; | |
101 | ||
102 | g_free(core_type); | |
e17a8779 GK |
103 | core_type = NULL; |
104 | realmodel = ppc_cpu_lookup_alias(model_pieces[0]); | |
4babfaf0 | 105 | if (realmodel) { |
e17a8779 | 106 | core_type = spapr_get_cpu_core_type(realmodel); |
4babfaf0 | 107 | } |
4babfaf0 TH |
108 | } |
109 | ||
e17a8779 | 110 | g_strfreev(model_pieces); |
94a94e4c BR |
111 | return core_type; |
112 | } | |
113 | ||
f844616b | 114 | static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) |
6f4b5c3e BR |
115 | { |
116 | sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); | |
7ebaf795 BR |
117 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); |
118 | const char *typename = object_class_get_name(scc->cpu_class); | |
6f4b5c3e | 119 | size_t size = object_type_get_instance_size(typename); |
6f4b5c3e | 120 | CPUCore *cc = CPU_CORE(dev); |
6f4b5c3e BR |
121 | int i; |
122 | ||
123 | for (i = 0; i < cc->nr_threads; i++) { | |
124 | void *obj = sc->threads + i * size; | |
125 | DeviceState *dev = DEVICE(obj); | |
126 | CPUState *cs = CPU(dev); | |
127 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
128 | ||
129 | spapr_cpu_destroy(cpu); | |
130 | cpu_remove_sync(cs); | |
131 | object_unparent(obj); | |
132 | } | |
8a1eb71b | 133 | g_free(sc->threads); |
6f4b5c3e BR |
134 | } |
135 | ||
7093645a | 136 | static void spapr_cpu_core_realize_child(Object *child, Error **errp) |
3b542549 | 137 | { |
7093645a | 138 | Error *local_err = NULL; |
3b542549 BR |
139 | sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); |
140 | CPUState *cs = CPU(child); | |
141 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
5bc8d26d CLG |
142 | Object *obj; |
143 | ||
144 | obj = object_new(spapr->icp_type); | |
145 | object_property_add_child(OBJECT(cpu), "icp", obj, NULL); | |
146 | object_property_add_const_link(obj, "xics", OBJECT(spapr), &error_abort); | |
147 | object_property_set_bool(obj, true, "realized", &local_err); | |
148 | if (local_err) { | |
149 | error_propagate(errp, local_err); | |
150 | return; | |
151 | } | |
3b542549 | 152 | |
f11235b9 GK |
153 | object_property_set_bool(child, true, "realized", &local_err); |
154 | if (local_err) { | |
5bc8d26d | 155 | object_unparent(obj); |
f11235b9 | 156 | error_propagate(errp, local_err); |
7093645a | 157 | return; |
3b542549 BR |
158 | } |
159 | ||
f11235b9 GK |
160 | spapr_cpu_init(spapr, cpu, &local_err); |
161 | if (local_err) { | |
5bc8d26d | 162 | object_unparent(obj); |
f11235b9 | 163 | error_propagate(errp, local_err); |
7093645a | 164 | return; |
3b542549 | 165 | } |
5bc8d26d CLG |
166 | |
167 | xics_cpu_setup(XICS_FABRIC(spapr), cpu, ICP(obj)); | |
3b542549 BR |
168 | } |
169 | ||
170 | static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) | |
171 | { | |
172 | sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); | |
7ebaf795 | 173 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); |
3b542549 | 174 | CPUCore *cc = CPU_CORE(OBJECT(dev)); |
7ebaf795 | 175 | const char *typename = object_class_get_name(scc->cpu_class); |
3b542549 BR |
176 | size_t size = object_type_get_instance_size(typename); |
177 | Error *local_err = NULL; | |
17b7c39e | 178 | int core_node_id = numa_get_node_for_cpu(cc->core_id);; |
7093645a BR |
179 | void *obj; |
180 | int i, j; | |
3b542549 BR |
181 | |
182 | sc->threads = g_malloc0(size * cc->nr_threads); | |
183 | for (i = 0; i < cc->nr_threads; i++) { | |
17b7c39e | 184 | int node_id; |
3b542549 | 185 | char id[32]; |
b63578bd IM |
186 | CPUState *cs; |
187 | ||
7093645a | 188 | obj = sc->threads + i * size; |
3b542549 BR |
189 | |
190 | object_initialize(obj, size, typename); | |
b63578bd IM |
191 | cs = CPU(obj); |
192 | cs->cpu_index = cc->core_id + i; | |
17b7c39e IM |
193 | |
194 | /* Set NUMA node for the added CPUs */ | |
195 | node_id = numa_get_node_for_cpu(cs->cpu_index); | |
196 | if (node_id != core_node_id) { | |
197 | error_setg(&local_err, "Invalid node-id=%d of thread[cpu-index: %d]" | |
198 | " on CPU[core-id: %d, node-id: %d], node-id must be the same", | |
199 | node_id, cs->cpu_index, cc->core_id, core_node_id); | |
200 | goto err; | |
201 | } | |
202 | if (node_id < nb_numa_nodes) { | |
203 | cs->numa_node = node_id; | |
204 | } | |
205 | ||
3b542549 BR |
206 | snprintf(id, sizeof(id), "thread[%d]", i); |
207 | object_property_add_child(OBJECT(sc), id, obj, &local_err); | |
208 | if (local_err) { | |
209 | goto err; | |
210 | } | |
8e758dee | 211 | object_unref(obj); |
3b542549 | 212 | } |
7093645a BR |
213 | |
214 | for (j = 0; j < cc->nr_threads; j++) { | |
215 | obj = sc->threads + j * size; | |
216 | ||
217 | spapr_cpu_core_realize_child(obj, &local_err); | |
218 | if (local_err) { | |
219 | goto err; | |
220 | } | |
3b542549 | 221 | } |
7093645a | 222 | return; |
3b542549 BR |
223 | |
224 | err: | |
dde35bc9 | 225 | while (--i >= 0) { |
3b542549 BR |
226 | obj = sc->threads + i * size; |
227 | object_unparent(obj); | |
3b542549 BR |
228 | } |
229 | g_free(sc->threads); | |
230 | error_propagate(errp, local_err); | |
231 | } | |
232 | ||
7ebaf795 | 233 | static const char *spapr_core_models[] = { |
4babfaf0 | 234 | /* 970 */ |
7ebaf795 | 235 | "970_v2.2", |
ff461b8d | 236 | |
4babfaf0 | 237 | /* 970MP variants */ |
7ebaf795 BR |
238 | "970MP_v1.0", |
239 | "970mp_v1.0", | |
240 | "970MP_v1.1", | |
241 | "970mp_v1.1", | |
470f2157 | 242 | |
4babfaf0 | 243 | /* POWER5+ */ |
7ebaf795 | 244 | "POWER5+_v2.1", |
ff461b8d | 245 | |
4babfaf0 | 246 | /* POWER7 */ |
7ebaf795 | 247 | "POWER7_v2.3", |
3b542549 | 248 | |
4babfaf0 | 249 | /* POWER7+ */ |
7ebaf795 | 250 | "POWER7+_v2.1", |
3b542549 | 251 | |
4babfaf0 | 252 | /* POWER8 */ |
7ebaf795 | 253 | "POWER8_v2.0", |
3b542549 | 254 | |
4babfaf0 | 255 | /* POWER8E */ |
7ebaf795 | 256 | "POWER8E_v2.1", |
3b542549 | 257 | |
4babfaf0 | 258 | /* POWER8NVL */ |
7ebaf795 | 259 | "POWER8NVL_v1.0", |
24d8e565 SJS |
260 | |
261 | /* POWER9 */ | |
262 | "POWER9_v1.0", | |
3b542549 BR |
263 | }; |
264 | ||
7ebaf795 | 265 | void spapr_cpu_core_class_init(ObjectClass *oc, void *data) |
3b542549 | 266 | { |
7ebaf795 BR |
267 | DeviceClass *dc = DEVICE_CLASS(oc); |
268 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); | |
269 | ||
270 | dc->realize = spapr_cpu_core_realize; | |
f844616b | 271 | dc->unrealize = spapr_cpu_core_unrealizefn; |
7ebaf795 BR |
272 | scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data); |
273 | g_assert(scc->cpu_class); | |
3b542549 BR |
274 | } |
275 | ||
276 | static const TypeInfo spapr_cpu_core_type_info = { | |
277 | .name = TYPE_SPAPR_CPU_CORE, | |
278 | .parent = TYPE_CPU_CORE, | |
279 | .abstract = true, | |
280 | .instance_size = sizeof(sPAPRCPUCore), | |
7ebaf795 | 281 | .class_size = sizeof(sPAPRCPUCoreClass), |
3b542549 BR |
282 | }; |
283 | ||
284 | static void spapr_cpu_core_register_types(void) | |
285 | { | |
7ebaf795 | 286 | int i; |
3b542549 BR |
287 | |
288 | type_register_static(&spapr_cpu_core_type_info); | |
7ebaf795 BR |
289 | |
290 | for (i = 0; i < ARRAY_SIZE(spapr_core_models); i++) { | |
291 | TypeInfo type_info = { | |
292 | .parent = TYPE_SPAPR_CPU_CORE, | |
293 | .instance_size = sizeof(sPAPRCPUCore), | |
294 | .class_init = spapr_cpu_core_class_init, | |
295 | .class_data = (void *) spapr_core_models[i], | |
296 | }; | |
297 | ||
298 | type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, | |
299 | spapr_core_models[i]); | |
300 | type_register(&type_info); | |
301 | g_free((void *)type_info.name); | |
3b542549 BR |
302 | } |
303 | } | |
304 | ||
305 | type_init(spapr_cpu_core_register_types) |