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" 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" 31 #include "kvm_ppc.h" 32 33 #include "hw/ppc/spapr.h" 34 35 typedef struct sPAPRCapabilityInfo { 36 const char *name; 37 const char *description; 38 int index; 39 40 /* Getter and Setter Function Pointers */ 41 ObjectPropertyAccessor *get; 42 ObjectPropertyAccessor *set; 43 const char *type; 44 /* Make sure the virtual hardware can support this capability */ 45 void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp); 46 } sPAPRCapabilityInfo; 47 48 static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name, 49 void *opaque, Error **errp) 50 { 51 sPAPRCapabilityInfo *cap = opaque; 52 sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 53 bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON; 54 55 visit_type_bool(v, name, &value, errp); 56 } 57 58 static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, 59 void *opaque, Error **errp) 60 { 61 sPAPRCapabilityInfo *cap = opaque; 62 sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 63 bool value; 64 Error *local_err = NULL; 65 66 visit_type_bool(v, name, &value, &local_err); 67 if (local_err) { 68 error_propagate(errp, local_err); 69 return; 70 } 71 72 spapr->cmd_line_caps[cap->index] = true; 73 spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; 74 } 75 76 static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) 77 { 78 if (!val) { 79 /* TODO: We don't support disabling htm yet */ 80 return; 81 } 82 if (tcg_enabled()) { 83 error_setg(errp, 84 "No Transactional Memory support in TCG, try cap-htm=off"); 85 } else if (kvm_enabled() && !kvmppc_has_cap_htm()) { 86 error_setg(errp, 87 "KVM implementation does not support Transactional Memory, try cap-htm=off" 88 ); 89 } 90 } 91 92 static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) 93 { 94 PowerPCCPU *cpu = POWERPC_CPU(first_cpu); 95 CPUPPCState *env = &cpu->env; 96 97 if (!val) { 98 /* TODO: We don't support disabling vsx yet */ 99 return; 100 } 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"); 106 } 107 } 108 109 static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) 110 { 111 PowerPCCPU *cpu = POWERPC_CPU(first_cpu); 112 CPUPPCState *env = &cpu->env; 113 114 if (!val) { 115 /* TODO: We don't support disabling dfp yet */ 116 return; 117 } 118 if (!(env->insns_flags2 & PPC2_DFP)) { 119 error_setg(errp, "DFP support not available, try cap-dfp=off"); 120 } 121 } 122 123 124 sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { 125 [SPAPR_CAP_HTM] = { 126 .name = "htm", 127 .description = "Allow Hardware Transactional Memory (HTM)", 128 .index = SPAPR_CAP_HTM, 129 .get = spapr_cap_get_bool, 130 .set = spapr_cap_set_bool, 131 .type = "bool", 132 .apply = cap_htm_apply, 133 }, 134 [SPAPR_CAP_VSX] = { 135 .name = "vsx", 136 .description = "Allow Vector Scalar Extensions (VSX)", 137 .index = SPAPR_CAP_VSX, 138 .get = spapr_cap_get_bool, 139 .set = spapr_cap_set_bool, 140 .type = "bool", 141 .apply = cap_vsx_apply, 142 }, 143 [SPAPR_CAP_DFP] = { 144 .name = "dfp", 145 .description = "Allow Decimal Floating Point (DFP)", 146 .index = SPAPR_CAP_DFP, 147 .get = spapr_cap_get_bool, 148 .set = spapr_cap_set_bool, 149 .type = "bool", 150 .apply = cap_dfp_apply, 151 }, 152 }; 153 154 static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, 155 CPUState *cs) 156 { 157 sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); 158 PowerPCCPU *cpu = POWERPC_CPU(cs); 159 sPAPRCapabilities caps; 160 161 caps = smc->default_caps; 162 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; 166 } 167 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; 172 } 173 174 return caps; 175 } 176 177 int spapr_caps_pre_load(void *opaque) 178 { 179 sPAPRMachineState *spapr = opaque; 180 181 /* Set to default so we can tell if this came in with the migration */ 182 spapr->mig = spapr->def; 183 return 0; 184 } 185 186 int spapr_caps_pre_save(void *opaque) 187 { 188 sPAPRMachineState *spapr = opaque; 189 190 spapr->mig = spapr->eff; 191 return 0; 192 } 193 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) 199 { 200 int i; 201 bool ok = true; 202 sPAPRCapabilities dstcaps = spapr->eff; 203 sPAPRCapabilities srccaps; 204 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]; 210 } 211 } 212 213 for (i = 0; i < SPAPR_CAP_NUM; i++) { 214 sPAPRCapabilityInfo *info = &capability_table[i]; 215 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]); 219 ok = false; 220 } 221 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]); 225 } 226 } 227 228 return ok ? 0 : -EINVAL; 229 } 230 231 static bool spapr_cap_htm_needed(void *opaque) 232 { 233 sPAPRMachineState *spapr = opaque; 234 235 return spapr->cmd_line_caps[SPAPR_CAP_HTM] && 236 (spapr->eff.caps[SPAPR_CAP_HTM] != spapr->def.caps[SPAPR_CAP_HTM]); 237 } 238 239 const VMStateDescription vmstate_spapr_cap_htm = { 240 .name = "spapr/cap/htm", 241 .version_id = 1, 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() 247 }, 248 }; 249 250 static bool spapr_cap_vsx_needed(void *opaque) 251 { 252 sPAPRMachineState *spapr = opaque; 253 254 return spapr->cmd_line_caps[SPAPR_CAP_VSX] && 255 (spapr->eff.caps[SPAPR_CAP_VSX] != spapr->def.caps[SPAPR_CAP_VSX]); 256 } 257 258 const VMStateDescription vmstate_spapr_cap_vsx = { 259 .name = "spapr/cap/vsx", 260 .version_id = 1, 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() 266 }, 267 }; 268 269 static bool spapr_cap_dfp_needed(void *opaque) 270 { 271 sPAPRMachineState *spapr = opaque; 272 273 return spapr->cmd_line_caps[SPAPR_CAP_DFP] && 274 (spapr->eff.caps[SPAPR_CAP_DFP] != spapr->def.caps[SPAPR_CAP_DFP]); 275 } 276 277 const VMStateDescription vmstate_spapr_cap_dfp = { 278 .name = "spapr/cap/dfp", 279 .version_id = 1, 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() 285 }, 286 }; 287 288 void spapr_caps_reset(sPAPRMachineState *spapr) 289 { 290 sPAPRCapabilities default_caps; 291 int i; 292 293 /* First compute the actual set of caps we're running with.. */ 294 default_caps = default_caps_with_cpu(spapr, first_cpu); 295 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]; 302 } 303 } 304 305 /* .. then apply those caps to the virtual hardware */ 306 307 for (i = 0; i < SPAPR_CAP_NUM; i++) { 308 sPAPRCapabilityInfo *info = &capability_table[i]; 309 310 /* 311 * If the apply function can't set the desired level and thinks it's 312 * fatal, it should cause that. 313 */ 314 info->apply(spapr, spapr->eff.caps[i], &error_fatal); 315 } 316 } 317 318 void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) 319 { 320 Error *local_err = NULL; 321 ObjectClass *klass = OBJECT_CLASS(smc); 322 int i; 323 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); 327 char *desc; 328 329 object_class_property_add(klass, name, cap->type, 330 cap->get, cap->set, 331 NULL, cap, &local_err); 332 if (local_err) { 333 error_propagate(errp, local_err); 334 return; 335 } 336 337 desc = g_strdup_printf("%s", cap->description); 338 object_class_property_set_description(klass, name, desc, &local_err); 339 g_free(desc); 340 if (local_err) { 341 error_propagate(errp, local_err); 342 return; 343 } 344 } 345 } 346