]>
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; | |
af81cf32 BR |
66 | CPUState *cs = CPU(cpu); |
67 | int i; | |
afd10a0f BR |
68 | |
69 | /* Set time-base frequency to 512 MHz */ | |
70 | cpu_ppc_tb_init(env, SPAPR_TIMEBASE_FREQ); | |
71 | ||
72 | /* Enable PAPR mode in TCG or KVM */ | |
b7b0b1f1 | 73 | cpu_ppc_set_papr(cpu, PPC_VIRTUAL_HYPERVISOR(spapr)); |
afd10a0f BR |
74 | |
75 | if (cpu->max_compat) { | |
76 | Error *local_err = NULL; | |
77 | ||
78 | ppc_set_compat(cpu, cpu->max_compat, &local_err); | |
79 | if (local_err) { | |
80 | error_propagate(errp, local_err); | |
81 | return; | |
82 | } | |
83 | } | |
84 | ||
af81cf32 | 85 | /* Set NUMA node for the added CPUs */ |
6bea1ddf IM |
86 | i = numa_get_node_for_cpu(cs->cpu_index); |
87 | if (i < nb_numa_nodes) { | |
af81cf32 | 88 | cs->numa_node = i; |
af81cf32 BR |
89 | } |
90 | ||
b4f27d71 | 91 | xics_cpu_setup(XICS_FABRIC(spapr), cpu); |
afd10a0f BR |
92 | |
93 | qemu_register_reset(spapr_cpu_reset, cpu); | |
af81cf32 | 94 | spapr_cpu_reset(cpu); |
afd10a0f | 95 | } |
3b542549 | 96 | |
94a94e4c BR |
97 | /* |
98 | * Return the sPAPR CPU core type for @model which essentially is the CPU | |
99 | * model specified with -cpu cmdline option. | |
100 | */ | |
101 | char *spapr_get_cpu_core_type(const char *model) | |
102 | { | |
103 | char *core_type; | |
104 | gchar **model_pieces = g_strsplit(model, ",", 2); | |
105 | ||
106 | core_type = g_strdup_printf("%s-%s", model_pieces[0], TYPE_SPAPR_CPU_CORE); | |
4babfaf0 TH |
107 | |
108 | /* Check whether it exists or whether we have to look up an alias name */ | |
109 | if (!object_class_by_name(core_type)) { | |
110 | const char *realmodel; | |
111 | ||
112 | g_free(core_type); | |
e17a8779 GK |
113 | core_type = NULL; |
114 | realmodel = ppc_cpu_lookup_alias(model_pieces[0]); | |
4babfaf0 | 115 | if (realmodel) { |
e17a8779 | 116 | core_type = spapr_get_cpu_core_type(realmodel); |
4babfaf0 | 117 | } |
4babfaf0 TH |
118 | } |
119 | ||
e17a8779 | 120 | g_strfreev(model_pieces); |
94a94e4c BR |
121 | return core_type; |
122 | } | |
123 | ||
f844616b | 124 | static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) |
6f4b5c3e BR |
125 | { |
126 | sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); | |
7ebaf795 BR |
127 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); |
128 | const char *typename = object_class_get_name(scc->cpu_class); | |
6f4b5c3e | 129 | size_t size = object_type_get_instance_size(typename); |
6f4b5c3e | 130 | CPUCore *cc = CPU_CORE(dev); |
6f4b5c3e BR |
131 | int i; |
132 | ||
133 | for (i = 0; i < cc->nr_threads; i++) { | |
134 | void *obj = sc->threads + i * size; | |
135 | DeviceState *dev = DEVICE(obj); | |
136 | CPUState *cs = CPU(dev); | |
137 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
138 | ||
139 | spapr_cpu_destroy(cpu); | |
140 | cpu_remove_sync(cs); | |
141 | object_unparent(obj); | |
142 | } | |
8a1eb71b | 143 | g_free(sc->threads); |
6f4b5c3e BR |
144 | } |
145 | ||
7093645a | 146 | static void spapr_cpu_core_realize_child(Object *child, Error **errp) |
3b542549 | 147 | { |
7093645a | 148 | Error *local_err = NULL; |
3b542549 BR |
149 | sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); |
150 | CPUState *cs = CPU(child); | |
151 | PowerPCCPU *cpu = POWERPC_CPU(cs); | |
152 | ||
f11235b9 GK |
153 | object_property_set_bool(child, true, "realized", &local_err); |
154 | if (local_err) { | |
155 | error_propagate(errp, local_err); | |
7093645a | 156 | return; |
3b542549 BR |
157 | } |
158 | ||
f11235b9 GK |
159 | spapr_cpu_init(spapr, cpu, &local_err); |
160 | if (local_err) { | |
161 | error_propagate(errp, local_err); | |
7093645a | 162 | return; |
3b542549 | 163 | } |
3b542549 BR |
164 | } |
165 | ||
166 | static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) | |
167 | { | |
168 | sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); | |
7ebaf795 | 169 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); |
3b542549 | 170 | CPUCore *cc = CPU_CORE(OBJECT(dev)); |
7ebaf795 | 171 | const char *typename = object_class_get_name(scc->cpu_class); |
3b542549 BR |
172 | size_t size = object_type_get_instance_size(typename); |
173 | Error *local_err = NULL; | |
7093645a BR |
174 | void *obj; |
175 | int i, j; | |
3b542549 BR |
176 | |
177 | sc->threads = g_malloc0(size * cc->nr_threads); | |
178 | for (i = 0; i < cc->nr_threads; i++) { | |
179 | char id[32]; | |
b63578bd IM |
180 | CPUState *cs; |
181 | ||
7093645a | 182 | obj = sc->threads + i * size; |
3b542549 BR |
183 | |
184 | object_initialize(obj, size, typename); | |
b63578bd IM |
185 | cs = CPU(obj); |
186 | cs->cpu_index = cc->core_id + i; | |
3b542549 BR |
187 | snprintf(id, sizeof(id), "thread[%d]", i); |
188 | object_property_add_child(OBJECT(sc), id, obj, &local_err); | |
189 | if (local_err) { | |
190 | goto err; | |
191 | } | |
8e758dee | 192 | object_unref(obj); |
3b542549 | 193 | } |
7093645a BR |
194 | |
195 | for (j = 0; j < cc->nr_threads; j++) { | |
196 | obj = sc->threads + j * size; | |
197 | ||
198 | spapr_cpu_core_realize_child(obj, &local_err); | |
199 | if (local_err) { | |
200 | goto err; | |
201 | } | |
3b542549 | 202 | } |
7093645a | 203 | return; |
3b542549 BR |
204 | |
205 | err: | |
dde35bc9 | 206 | while (--i >= 0) { |
3b542549 BR |
207 | obj = sc->threads + i * size; |
208 | object_unparent(obj); | |
3b542549 BR |
209 | } |
210 | g_free(sc->threads); | |
211 | error_propagate(errp, local_err); | |
212 | } | |
213 | ||
7ebaf795 | 214 | static const char *spapr_core_models[] = { |
4babfaf0 | 215 | /* 970 */ |
7ebaf795 | 216 | "970_v2.2", |
ff461b8d | 217 | |
4babfaf0 | 218 | /* 970MP variants */ |
7ebaf795 BR |
219 | "970MP_v1.0", |
220 | "970mp_v1.0", | |
221 | "970MP_v1.1", | |
222 | "970mp_v1.1", | |
470f2157 | 223 | |
4babfaf0 | 224 | /* POWER5+ */ |
7ebaf795 | 225 | "POWER5+_v2.1", |
ff461b8d | 226 | |
4babfaf0 | 227 | /* POWER7 */ |
7ebaf795 | 228 | "POWER7_v2.3", |
3b542549 | 229 | |
4babfaf0 | 230 | /* POWER7+ */ |
7ebaf795 | 231 | "POWER7+_v2.1", |
3b542549 | 232 | |
4babfaf0 | 233 | /* POWER8 */ |
7ebaf795 | 234 | "POWER8_v2.0", |
3b542549 | 235 | |
4babfaf0 | 236 | /* POWER8E */ |
7ebaf795 | 237 | "POWER8E_v2.1", |
3b542549 | 238 | |
4babfaf0 | 239 | /* POWER8NVL */ |
7ebaf795 | 240 | "POWER8NVL_v1.0", |
3b542549 BR |
241 | }; |
242 | ||
7ebaf795 | 243 | void spapr_cpu_core_class_init(ObjectClass *oc, void *data) |
3b542549 | 244 | { |
7ebaf795 BR |
245 | DeviceClass *dc = DEVICE_CLASS(oc); |
246 | sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); | |
247 | ||
248 | dc->realize = spapr_cpu_core_realize; | |
f844616b | 249 | dc->unrealize = spapr_cpu_core_unrealizefn; |
7ebaf795 BR |
250 | scc->cpu_class = cpu_class_by_name(TYPE_POWERPC_CPU, data); |
251 | g_assert(scc->cpu_class); | |
3b542549 BR |
252 | } |
253 | ||
254 | static const TypeInfo spapr_cpu_core_type_info = { | |
255 | .name = TYPE_SPAPR_CPU_CORE, | |
256 | .parent = TYPE_CPU_CORE, | |
257 | .abstract = true, | |
258 | .instance_size = sizeof(sPAPRCPUCore), | |
7ebaf795 | 259 | .class_size = sizeof(sPAPRCPUCoreClass), |
3b542549 BR |
260 | }; |
261 | ||
262 | static void spapr_cpu_core_register_types(void) | |
263 | { | |
7ebaf795 | 264 | int i; |
3b542549 BR |
265 | |
266 | type_register_static(&spapr_cpu_core_type_info); | |
7ebaf795 BR |
267 | |
268 | for (i = 0; i < ARRAY_SIZE(spapr_core_models); i++) { | |
269 | TypeInfo type_info = { | |
270 | .parent = TYPE_SPAPR_CPU_CORE, | |
271 | .instance_size = sizeof(sPAPRCPUCore), | |
272 | .class_init = spapr_cpu_core_class_init, | |
273 | .class_data = (void *) spapr_core_models[i], | |
274 | }; | |
275 | ||
276 | type_info.name = g_strdup_printf("%s-" TYPE_SPAPR_CPU_CORE, | |
277 | spapr_core_models[i]); | |
278 | type_register(&type_info); | |
279 | g_free((void *)type_info.name); | |
3b542549 BR |
280 | } |
281 | } | |
282 | ||
283 | type_init(spapr_cpu_core_register_types) |