2 * QEMU PowerPC pSeries Logical Partition capabilities handling
4 * Copyright (c) 2017 David Gibson, Red Hat Inc.
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 #include "qemu/osdep.h"
25 #include "qemu/error-report.h"
26 #include "qapi/error.h"
27 #include "qapi/visitor.h"
28 #include "sysemu/hw_accel.h"
29 #include "target/ppc/cpu.h"
30 #include "cpu-models.h"
33 #include "hw/ppc/spapr.h"
35 typedef struct sPAPRCapabilityInfo {
37 const char *description;
40 /* Getter and Setter Function Pointers */
41 ObjectPropertyAccessor *get;
42 ObjectPropertyAccessor *set;
44 /* Make sure the virtual hardware can support this capability */
45 void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp);
46 } sPAPRCapabilityInfo;
48 static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name,
49 void *opaque, Error **errp)
51 sPAPRCapabilityInfo *cap = opaque;
52 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
53 bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON;
55 visit_type_bool(v, name, &value, errp);
58 static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name,
59 void *opaque, Error **errp)
61 sPAPRCapabilityInfo *cap = opaque;
62 sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
64 Error *local_err = NULL;
66 visit_type_bool(v, name, &value, &local_err);
68 error_propagate(errp, local_err);
72 spapr->cmd_line_caps[cap->index] = true;
73 spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF;
76 static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
79 /* TODO: We don't support disabling htm yet */
84 "No Transactional Memory support in TCG, try cap-htm=off");
85 } else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
87 "KVM implementation does not support Transactional Memory, try cap-htm=off"
92 static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
94 PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
95 CPUPPCState *env = &cpu->env;
98 /* TODO: We don't support disabling vsx yet */
101 /* Allowable CPUs in spapr_cpu_core.c should already have gotten
102 * rid of anything that doesn't do VMX */
103 g_assert(env->insns_flags & PPC_ALTIVEC);
104 if (!(env->insns_flags2 & PPC2_VSX)) {
105 error_setg(errp, "VSX support not available, try cap-vsx=off");
109 static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp)
111 PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
112 CPUPPCState *env = &cpu->env;
115 /* TODO: We don't support disabling dfp yet */
118 if (!(env->insns_flags2 & PPC2_DFP)) {
119 error_setg(errp, "DFP support not available, try cap-dfp=off");
124 sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
127 .description = "Allow Hardware Transactional Memory (HTM)",
128 .index = SPAPR_CAP_HTM,
129 .get = spapr_cap_get_bool,
130 .set = spapr_cap_set_bool,
132 .apply = cap_htm_apply,
136 .description = "Allow Vector Scalar Extensions (VSX)",
137 .index = SPAPR_CAP_VSX,
138 .get = spapr_cap_get_bool,
139 .set = spapr_cap_set_bool,
141 .apply = cap_vsx_apply,
145 .description = "Allow Decimal Floating Point (DFP)",
146 .index = SPAPR_CAP_DFP,
147 .get = spapr_cap_get_bool,
148 .set = spapr_cap_set_bool,
150 .apply = cap_dfp_apply,
154 static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr,
157 sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
158 PowerPCCPU *cpu = POWERPC_CPU(cs);
159 sPAPRCapabilities caps;
161 caps = smc->default_caps;
163 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07,
164 0, spapr->max_compat_pvr)) {
165 caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
168 if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06,
169 0, spapr->max_compat_pvr)) {
170 caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF;
171 caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF;
177 int spapr_caps_pre_load(void *opaque)
179 sPAPRMachineState *spapr = opaque;
181 /* Set to default so we can tell if this came in with the migration */
182 spapr->mig = spapr->def;
186 int spapr_caps_pre_save(void *opaque)
188 sPAPRMachineState *spapr = opaque;
190 spapr->mig = spapr->eff;
194 /* This has to be called from the top-level spapr post_load, not the
195 * caps specific one. Otherwise it wouldn't be called when the source
196 * caps are all defaults, which could still conflict with overridden
197 * caps on the destination */
198 int spapr_caps_post_migration(sPAPRMachineState *spapr)
202 sPAPRCapabilities dstcaps = spapr->eff;
203 sPAPRCapabilities srccaps;
205 srccaps = default_caps_with_cpu(spapr, first_cpu);
206 for (i = 0; i < SPAPR_CAP_NUM; i++) {
207 /* If not default value then assume came in with the migration */
208 if (spapr->mig.caps[i] != spapr->def.caps[i]) {
209 srccaps.caps[i] = spapr->mig.caps[i];
213 for (i = 0; i < SPAPR_CAP_NUM; i++) {
214 sPAPRCapabilityInfo *info = &capability_table[i];
216 if (srccaps.caps[i] > dstcaps.caps[i]) {
217 error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)",
218 info->name, srccaps.caps[i], dstcaps.caps[i]);
222 if (srccaps.caps[i] < dstcaps.caps[i]) {
223 warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)",
224 info->name, srccaps.caps[i], dstcaps.caps[i]);
228 return ok ? 0 : -EINVAL;
231 static bool spapr_cap_htm_needed(void *opaque)
233 sPAPRMachineState *spapr = opaque;
235 return spapr->cmd_line_caps[SPAPR_CAP_HTM] &&
236 (spapr->eff.caps[SPAPR_CAP_HTM] != spapr->def.caps[SPAPR_CAP_HTM]);
239 const VMStateDescription vmstate_spapr_cap_htm = {
240 .name = "spapr/cap/htm",
242 .minimum_version_id = 1,
243 .needed = spapr_cap_htm_needed,
244 .fields = (VMStateField[]) {
245 VMSTATE_UINT8(mig.caps[SPAPR_CAP_HTM], sPAPRMachineState),
246 VMSTATE_END_OF_LIST()
250 static bool spapr_cap_vsx_needed(void *opaque)
252 sPAPRMachineState *spapr = opaque;
254 return spapr->cmd_line_caps[SPAPR_CAP_VSX] &&
255 (spapr->eff.caps[SPAPR_CAP_VSX] != spapr->def.caps[SPAPR_CAP_VSX]);
258 const VMStateDescription vmstate_spapr_cap_vsx = {
259 .name = "spapr/cap/vsx",
261 .minimum_version_id = 1,
262 .needed = spapr_cap_vsx_needed,
263 .fields = (VMStateField[]) {
264 VMSTATE_UINT8(mig.caps[SPAPR_CAP_VSX], sPAPRMachineState),
265 VMSTATE_END_OF_LIST()
269 static bool spapr_cap_dfp_needed(void *opaque)
271 sPAPRMachineState *spapr = opaque;
273 return spapr->cmd_line_caps[SPAPR_CAP_DFP] &&
274 (spapr->eff.caps[SPAPR_CAP_DFP] != spapr->def.caps[SPAPR_CAP_DFP]);
277 const VMStateDescription vmstate_spapr_cap_dfp = {
278 .name = "spapr/cap/dfp",
280 .minimum_version_id = 1,
281 .needed = spapr_cap_dfp_needed,
282 .fields = (VMStateField[]) {
283 VMSTATE_UINT8(mig.caps[SPAPR_CAP_DFP], sPAPRMachineState),
284 VMSTATE_END_OF_LIST()
288 void spapr_caps_reset(sPAPRMachineState *spapr)
290 sPAPRCapabilities default_caps;
293 /* First compute the actual set of caps we're running with.. */
294 default_caps = default_caps_with_cpu(spapr, first_cpu);
296 for (i = 0; i < SPAPR_CAP_NUM; i++) {
297 /* Store the defaults */
298 spapr->def.caps[i] = default_caps.caps[i];
299 /* If not set on the command line then apply the default value */
300 if (!spapr->cmd_line_caps[i]) {
301 spapr->eff.caps[i] = default_caps.caps[i];
305 /* .. then apply those caps to the virtual hardware */
307 for (i = 0; i < SPAPR_CAP_NUM; i++) {
308 sPAPRCapabilityInfo *info = &capability_table[i];
311 * If the apply function can't set the desired level and thinks it's
312 * fatal, it should cause that.
314 info->apply(spapr, spapr->eff.caps[i], &error_fatal);
318 void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp)
320 Error *local_err = NULL;
321 ObjectClass *klass = OBJECT_CLASS(smc);
324 for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
325 sPAPRCapabilityInfo *cap = &capability_table[i];
326 const char *name = g_strdup_printf("cap-%s", cap->name);
329 object_class_property_add(klass, name, cap->type,
331 NULL, cap, &local_err);
333 error_propagate(errp, local_err);
337 desc = g_strdup_printf("%s", cap->description);
338 object_class_property_set_description(klass, name, desc, &local_err);
341 error_propagate(errp, local_err);