]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ppc/spapr_caps.c
spapr: Handle VMX/VSX presence as an spapr capability flag
[mirror_qemu.git] / hw / ppc / spapr_caps.c
CommitLineData
33face6b
DG
1/*
2 * QEMU PowerPC pSeries Logical Partition capabilities handling
3 *
4 * Copyright (c) 2017 David Gibson, Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include "qemu/osdep.h"
be85537d 25#include "qemu/error-report.h"
33face6b
DG
26#include "qapi/error.h"
27#include "qapi/visitor.h"
ee76a09f
DG
28#include "sysemu/hw_accel.h"
29#include "target/ppc/cpu.h"
30#include "cpu-models.h"
31#include "kvm_ppc.h"
33face6b
DG
32
33#include "hw/ppc/spapr.h"
34
35typedef struct sPAPRCapabilityInfo {
36 const char *name;
37 const char *description;
38 uint64_t flag;
39
40 /* Make sure the virtual hardware can support this capability */
41 void (*allow)(sPAPRMachineState *spapr, Error **errp);
42
43 /* If possible, tell the virtual hardware not to allow the cap to
44 * be used at all */
45 void (*disallow)(sPAPRMachineState *spapr, Error **errp);
46} sPAPRCapabilityInfo;
47
ee76a09f
DG
48static void cap_htm_allow(sPAPRMachineState *spapr, Error **errp)
49{
50 if (tcg_enabled()) {
51 error_setg(errp,
52 "No Transactional Memory support in TCG, try cap-htm=off");
53 } else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
54 error_setg(errp,
55"KVM implementation does not support Transactional Memory, try cap-htm=off"
56 );
57 }
58}
59
29386642
DG
60static void cap_vsx_allow(sPAPRMachineState *spapr, Error **errp)
61{
62 PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
63 CPUPPCState *env = &cpu->env;
64
65 /* Allowable CPUs in spapr_cpu_core.c should already have gotten
66 * rid of anything that doesn't do VMX */
67 g_assert(env->insns_flags & PPC_ALTIVEC);
68 if (!(env->insns_flags2 & PPC2_VSX)) {
69 error_setg(errp, "VSX support not available, try cap-vsx=off");
70 }
71}
72
33face6b 73static sPAPRCapabilityInfo capability_table[] = {
ee76a09f
DG
74 {
75 .name = "htm",
76 .description = "Allow Hardware Transactional Memory (HTM)",
77 .flag = SPAPR_CAP_HTM,
78 .allow = cap_htm_allow,
79 /* TODO: add cap_htm_disallow */
80 },
29386642
DG
81 {
82 .name = "vsx",
83 .description = "Allow Vector Scalar Extensions (VSX)",
84 .flag = SPAPR_CAP_VSX,
85 .allow = cap_vsx_allow,
86 /* TODO: add cap_vsx_disallow */
87 },
33face6b
DG
88};
89
90static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
91 CPUState *cs)
92{
93 sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
ee76a09f 94 PowerPCCPU *cpu = POWERPC_CPU(cs);
33face6b
DG
95 sPAPRCapabilities caps;
96
97 caps = smc->default_caps;
98
ee76a09f
DG
99 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
100 0, spapr->max_compat_pvr)) {
101 caps.mask &= ~SPAPR_CAP_HTM;
102 }
33face6b 103
29386642
DG
104 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
105 0, spapr->max_compat_pvr)) {
106 caps.mask &= ~SPAPR_CAP_VSX;
107 }
108
33face6b
DG
109 return caps;
110}
111
be85537d
DG
112static bool spapr_caps_needed(void *opaque)
113{
114 sPAPRMachineState *spapr = opaque;
115
116 return (spapr->forced_caps.mask != 0) || (spapr->forbidden_caps.mask != 0);
117}
118
119/* This has to be called from the top-level spapr post_load, not the
120 * caps specific one. Otherwise it wouldn't be called when the source
121 * caps are all defaults, which could still conflict with overridden
122 * caps on the destination */
123int spapr_caps_post_migration(sPAPRMachineState *spapr)
124{
125 uint64_t allcaps = 0;
126 int i;
127 bool ok = true;
128 sPAPRCapabilities dstcaps = spapr->effective_caps;
129 sPAPRCapabilities srccaps;
130
131 srccaps = default_caps_with_cpu(spapr, first_cpu);
132 srccaps.mask |= spapr->mig_forced_caps.mask;
133 srccaps.mask &= ~spapr->mig_forbidden_caps.mask;
134
135 for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
136 sPAPRCapabilityInfo *info = &capability_table[i];
137
138 allcaps |= info->flag;
139
140 if ((srccaps.mask & info->flag) && !(dstcaps.mask & info->flag)) {
141 error_report("cap-%s=on in incoming stream, but off in destination",
142 info->name);
143 ok = false;
144 }
145
146 if (!(srccaps.mask & info->flag) && (dstcaps.mask & info->flag)) {
147 warn_report("cap-%s=off in incoming stream, but on in destination",
148 info->name);
149 }
150 }
151
152 if (spapr->mig_forced_caps.mask & ~allcaps) {
153 error_report(
154 "Unknown capabilities 0x%"PRIx64" enabled in incoming stream",
155 spapr->mig_forced_caps.mask & ~allcaps);
156 ok = false;
157 }
158 if (spapr->mig_forbidden_caps.mask & ~allcaps) {
159 warn_report(
160 "Unknown capabilities 0x%"PRIx64" disabled in incoming stream",
161 spapr->mig_forbidden_caps.mask & ~allcaps);
162 }
163
164 return ok ? 0 : -EINVAL;
165}
166
167static int spapr_caps_pre_save(void *opaque)
168{
169 sPAPRMachineState *spapr = opaque;
170
171 spapr->mig_forced_caps = spapr->forced_caps;
172 spapr->mig_forbidden_caps = spapr->forbidden_caps;
173 return 0;
174}
175
176static int spapr_caps_pre_load(void *opaque)
177{
178 sPAPRMachineState *spapr = opaque;
179
180 spapr->mig_forced_caps = spapr_caps(0);
181 spapr->mig_forbidden_caps = spapr_caps(0);
182 return 0;
183}
184
185const VMStateDescription vmstate_spapr_caps = {
186 .name = "spapr/caps",
187 .version_id = 1,
188 .minimum_version_id = 1,
189 .needed = spapr_caps_needed,
190 .pre_save = spapr_caps_pre_save,
191 .pre_load = spapr_caps_pre_load,
192 .fields = (VMStateField[]) {
193 VMSTATE_UINT64(mig_forced_caps.mask, sPAPRMachineState),
194 VMSTATE_UINT64(mig_forbidden_caps.mask, sPAPRMachineState),
195 VMSTATE_END_OF_LIST()
196 },
197};
198
33face6b
DG
199void spapr_caps_reset(sPAPRMachineState *spapr)
200{
201 Error *local_err = NULL;
202 sPAPRCapabilities caps;
203 int i;
204
205 /* First compute the actual set of caps we're running with.. */
206 caps = default_caps_with_cpu(spapr, first_cpu);
207
be85537d
DG
208 /* Remove unnecessary forced/forbidden bits (this will help us
209 * with migration) */
210 spapr->forced_caps.mask &= ~caps.mask;
211 spapr->forbidden_caps.mask &= caps.mask;
212
33face6b
DG
213 caps.mask |= spapr->forced_caps.mask;
214 caps.mask &= ~spapr->forbidden_caps.mask;
215
216 spapr->effective_caps = caps;
217
218 /* .. then apply those caps to the virtual hardware */
219
220 for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
221 sPAPRCapabilityInfo *info = &capability_table[i];
222
223 if (spapr->effective_caps.mask & info->flag) {
224 /* Failure to allow a cap is fatal - if the guest doesn't
225 * have it, we'll be supplying an incorrect environment */
226 if (info->allow) {
227 info->allow(spapr, &error_fatal);
228 }
229 } else {
230 /* Failure to enforce a cap is only a warning. The guest
231 * shouldn't be using it, since it's not advertised, so it
232 * doesn't get to complain about weird behaviour if it
233 * goes ahead anyway */
234 if (info->disallow) {
235 info->disallow(spapr, &local_err);
236 }
237 if (local_err) {
238 warn_report_err(local_err);
239 local_err = NULL;
240 }
241 }
242 }
243}
244
245static void spapr_cap_get(Object *obj, Visitor *v, const char *name,
246 void *opaque, Error **errp)
247{
248 sPAPRCapabilityInfo *cap = opaque;
249 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
250 bool value = spapr_has_cap(spapr, cap->flag);
251
252 /* TODO: Could this get called before effective_caps is finalized
253 * in spapr_caps_reset()? */
254
255 visit_type_bool(v, name, &value, errp);
256}
257
258static void spapr_cap_set(Object *obj, Visitor *v, const char *name,
259 void *opaque, Error **errp)
260{
261 sPAPRCapabilityInfo *cap = opaque;
262 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
263 bool value;
264 Error *local_err = NULL;
265
266 visit_type_bool(v, name, &value, &local_err);
267 if (local_err) {
268 error_propagate(errp, local_err);
269 return;
270 }
271
272 if (value) {
273 spapr->forced_caps.mask |= cap->flag;
274 } else {
275 spapr->forbidden_caps.mask |= cap->flag;
276 }
277}
278
279void spapr_caps_validate(sPAPRMachineState *spapr, Error **errp)
280{
281 uint64_t allcaps = 0;
282 int i;
283
284 for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
285 g_assert((allcaps & capability_table[i].flag) == 0);
286 allcaps |= capability_table[i].flag;
287 }
288
289 g_assert((spapr->forced_caps.mask & ~allcaps) == 0);
290 g_assert((spapr->forbidden_caps.mask & ~allcaps) == 0);
291
292 if (spapr->forced_caps.mask & spapr->forbidden_caps.mask) {
293 error_setg(errp, "Some sPAPR capabilities set both on and off");
294 return;
295 }
33face6b
DG
296}
297
298void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
299{
300 Error *local_err = NULL;
301 ObjectClass *klass = OBJECT_CLASS(smc);
302 int i;
303
304 for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
305 sPAPRCapabilityInfo *cap = &capability_table[i];
306 const char *name = g_strdup_printf("cap-%s", cap->name);
307
308 object_class_property_add(klass, name, "bool",
309 spapr_cap_get, spapr_cap_set, NULL,
310 cap, &local_err);
311 if (local_err) {
312 error_propagate(errp, local_err);
313 return;
314 }
315
316 object_class_property_set_description(klass, name, cap->description,
317 &local_err);
318 if (local_err) {
319 error_propagate(errp, local_err);
320 return;
321 }
322 }
323}