]>
Commit | Line | Data |
---|---|---|
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 | ||
87175d1b SJS |
35 | typedef struct sPAPRCapPossible { |
36 | int num; /* size of vals array below */ | |
37 | const char *help; /* help text for vals */ | |
38 | /* | |
39 | * Note: | |
40 | * - because of the way compatibility is determined vals MUST be ordered | |
41 | * such that later options are a superset of all preceding options. | |
42 | * - the order of vals must be preserved, that is their index is important, | |
43 | * however vals may be added to the end of the list so long as the above | |
44 | * point is observed | |
45 | */ | |
46 | const char *vals[]; | |
47 | } sPAPRCapPossible; | |
48 | ||
33face6b DG |
49 | typedef struct sPAPRCapabilityInfo { |
50 | const char *name; | |
51 | const char *description; | |
4e5fe368 | 52 | int index; |
33face6b | 53 | |
4e5fe368 SJS |
54 | /* Getter and Setter Function Pointers */ |
55 | ObjectPropertyAccessor *get; | |
56 | ObjectPropertyAccessor *set; | |
57 | const char *type; | |
87175d1b SJS |
58 | /* Possible values if this is a custom string type */ |
59 | sPAPRCapPossible *possible; | |
33face6b | 60 | /* Make sure the virtual hardware can support this capability */ |
4e5fe368 | 61 | void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp); |
33face6b DG |
62 | } sPAPRCapabilityInfo; |
63 | ||
4e5fe368 SJS |
64 | static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name, |
65 | void *opaque, Error **errp) | |
66 | { | |
67 | sPAPRCapabilityInfo *cap = opaque; | |
68 | sPAPRMachineState *spapr = SPAPR_MACHINE(obj); | |
69 | bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON; | |
70 | ||
71 | visit_type_bool(v, name, &value, errp); | |
72 | } | |
73 | ||
74 | static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, | |
75 | void *opaque, Error **errp) | |
ee76a09f | 76 | { |
4e5fe368 SJS |
77 | sPAPRCapabilityInfo *cap = opaque; |
78 | sPAPRMachineState *spapr = SPAPR_MACHINE(obj); | |
79 | bool value; | |
80 | Error *local_err = NULL; | |
81 | ||
82 | visit_type_bool(v, name, &value, &local_err); | |
83 | if (local_err) { | |
84 | error_propagate(errp, local_err); | |
85 | return; | |
86 | } | |
87 | ||
88 | spapr->cmd_line_caps[cap->index] = true; | |
89 | spapr->eff.caps[cap->index] = value ? SPAPR_CAP_ON : SPAPR_CAP_OFF; | |
90 | } | |
91 | ||
6898aed7 | 92 | |
f27aa81e SJS |
93 | static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name, |
94 | void *opaque, Error **errp) | |
87175d1b SJS |
95 | { |
96 | sPAPRCapabilityInfo *cap = opaque; | |
97 | sPAPRMachineState *spapr = SPAPR_MACHINE(obj); | |
98 | char *val = NULL; | |
99 | uint8_t value = spapr_get_cap(spapr, cap->index); | |
100 | ||
101 | if (value >= cap->possible->num) { | |
102 | error_setg(errp, "Invalid value (%d) for cap-%s", value, cap->name); | |
103 | return; | |
104 | } | |
105 | ||
106 | val = g_strdup(cap->possible->vals[value]); | |
107 | ||
108 | visit_type_str(v, name, &val, errp); | |
109 | g_free(val); | |
110 | } | |
111 | ||
f27aa81e SJS |
112 | static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name, |
113 | void *opaque, Error **errp) | |
87175d1b SJS |
114 | { |
115 | sPAPRCapabilityInfo *cap = opaque; | |
116 | sPAPRMachineState *spapr = SPAPR_MACHINE(obj); | |
117 | Error *local_err = NULL; | |
118 | uint8_t i; | |
119 | char *val; | |
120 | ||
121 | visit_type_str(v, name, &val, &local_err); | |
122 | if (local_err) { | |
123 | error_propagate(errp, local_err); | |
124 | return; | |
125 | } | |
126 | ||
127 | if (!strcmp(val, "?")) { | |
128 | error_setg(errp, "%s", cap->possible->help); | |
129 | goto out; | |
130 | } | |
131 | for (i = 0; i < cap->possible->num; i++) { | |
132 | if (!strcasecmp(val, cap->possible->vals[i])) { | |
133 | spapr->cmd_line_caps[cap->index] = true; | |
134 | spapr->eff.caps[cap->index] = i; | |
135 | goto out; | |
136 | } | |
137 | } | |
138 | ||
139 | error_setg(errp, "Invalid capability mode \"%s\" for cap-%s", val, | |
140 | cap->name); | |
141 | out: | |
142 | g_free(val); | |
143 | } | |
144 | ||
4e5fe368 SJS |
145 | static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) |
146 | { | |
147 | if (!val) { | |
148 | /* TODO: We don't support disabling htm yet */ | |
149 | return; | |
150 | } | |
ee76a09f DG |
151 | if (tcg_enabled()) { |
152 | error_setg(errp, | |
153 | "No Transactional Memory support in TCG, try cap-htm=off"); | |
154 | } else if (kvm_enabled() && !kvmppc_has_cap_htm()) { | |
155 | error_setg(errp, | |
156 | "KVM implementation does not support Transactional Memory, try cap-htm=off" | |
157 | ); | |
158 | } | |
159 | } | |
160 | ||
4e5fe368 | 161 | static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) |
29386642 DG |
162 | { |
163 | PowerPCCPU *cpu = POWERPC_CPU(first_cpu); | |
164 | CPUPPCState *env = &cpu->env; | |
165 | ||
4e5fe368 SJS |
166 | if (!val) { |
167 | /* TODO: We don't support disabling vsx yet */ | |
168 | return; | |
169 | } | |
29386642 DG |
170 | /* Allowable CPUs in spapr_cpu_core.c should already have gotten |
171 | * rid of anything that doesn't do VMX */ | |
172 | g_assert(env->insns_flags & PPC_ALTIVEC); | |
173 | if (!(env->insns_flags2 & PPC2_VSX)) { | |
174 | error_setg(errp, "VSX support not available, try cap-vsx=off"); | |
175 | } | |
176 | } | |
177 | ||
4e5fe368 | 178 | static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) |
2d1fb9bc DG |
179 | { |
180 | PowerPCCPU *cpu = POWERPC_CPU(first_cpu); | |
181 | CPUPPCState *env = &cpu->env; | |
182 | ||
4e5fe368 SJS |
183 | if (!val) { |
184 | /* TODO: We don't support disabling dfp yet */ | |
185 | return; | |
186 | } | |
2d1fb9bc DG |
187 | if (!(env->insns_flags2 & PPC2_DFP)) { |
188 | error_setg(errp, "DFP support not available, try cap-dfp=off"); | |
189 | } | |
190 | } | |
191 | ||
f27aa81e SJS |
192 | sPAPRCapPossible cap_cfpc_possible = { |
193 | .num = 3, | |
194 | .vals = {"broken", "workaround", "fixed"}, | |
195 | .help = "broken - no protection, workaround - workaround available," | |
196 | " fixed - fixed in hardware", | |
197 | }; | |
198 | ||
8f38eaf8 SJS |
199 | static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, |
200 | Error **errp) | |
201 | { | |
f27aa81e SJS |
202 | uint8_t kvm_val = kvmppc_get_cap_safe_cache(); |
203 | ||
8f38eaf8 SJS |
204 | if (tcg_enabled() && val) { |
205 | /* TODO - for now only allow broken for TCG */ | |
f27aa81e SJS |
206 | error_setg(errp, |
207 | "Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); | |
208 | } else if (kvm_enabled() && (val > kvm_val)) { | |
209 | error_setg(errp, | |
210 | "Requested safe cache capability level not supported by kvm, try cap-cfpc=%s", | |
211 | cap_cfpc_possible.vals[kvm_val]); | |
8f38eaf8 SJS |
212 | } |
213 | } | |
214 | ||
aaf265ff SJS |
215 | sPAPRCapPossible cap_sbbc_possible = { |
216 | .num = 3, | |
217 | .vals = {"broken", "workaround", "fixed"}, | |
218 | .help = "broken - no protection, workaround - workaround available," | |
219 | " fixed - fixed in hardware", | |
220 | }; | |
221 | ||
09114fd8 SJS |
222 | static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, |
223 | Error **errp) | |
224 | { | |
aaf265ff SJS |
225 | uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check(); |
226 | ||
09114fd8 SJS |
227 | if (tcg_enabled() && val) { |
228 | /* TODO - for now only allow broken for TCG */ | |
aaf265ff SJS |
229 | error_setg(errp, |
230 | "Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); | |
231 | } else if (kvm_enabled() && (val > kvm_val)) { | |
232 | error_setg(errp, | |
233 | "Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s", | |
234 | cap_sbbc_possible.vals[kvm_val]); | |
09114fd8 SJS |
235 | } |
236 | } | |
237 | ||
c76c0d30 SJS |
238 | sPAPRCapPossible cap_ibs_possible = { |
239 | .num = 4, | |
240 | /* Note workaround only maintained for compatibility */ | |
241 | .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"}, | |
242 | .help = "broken - no protection, fixed-ibs - indirect branch serialisation," | |
243 | " fixed-ccd - cache count disabled", | |
244 | }; | |
245 | ||
4be8d4e7 SJS |
246 | static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, |
247 | uint8_t val, Error **errp) | |
248 | { | |
c76c0d30 SJS |
249 | uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch(); |
250 | ||
4f5b039d | 251 | if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */ |
c76c0d30 SJS |
252 | error_setg(errp, |
253 | "Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s", | |
254 | cap_ibs_possible.vals[kvm_val]); | |
4f5b039d | 255 | } else if (tcg_enabled() && val) { |
4be8d4e7 | 256 | /* TODO - for now only allow broken for TCG */ |
c76c0d30 SJS |
257 | error_setg(errp, |
258 | "Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); | |
259 | } else if (kvm_enabled() && val && (val != kvm_val)) { | |
260 | error_setg(errp, | |
261 | "Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s", | |
262 | cap_ibs_possible.vals[kvm_val]); | |
4be8d4e7 SJS |
263 | } |
264 | } | |
265 | ||
8f38eaf8 | 266 | #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" |
4e5fe368 SJS |
267 | |
268 | sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { | |
269 | [SPAPR_CAP_HTM] = { | |
ee76a09f DG |
270 | .name = "htm", |
271 | .description = "Allow Hardware Transactional Memory (HTM)", | |
4e5fe368 SJS |
272 | .index = SPAPR_CAP_HTM, |
273 | .get = spapr_cap_get_bool, | |
274 | .set = spapr_cap_set_bool, | |
275 | .type = "bool", | |
276 | .apply = cap_htm_apply, | |
ee76a09f | 277 | }, |
4e5fe368 | 278 | [SPAPR_CAP_VSX] = { |
29386642 DG |
279 | .name = "vsx", |
280 | .description = "Allow Vector Scalar Extensions (VSX)", | |
4e5fe368 SJS |
281 | .index = SPAPR_CAP_VSX, |
282 | .get = spapr_cap_get_bool, | |
283 | .set = spapr_cap_set_bool, | |
284 | .type = "bool", | |
285 | .apply = cap_vsx_apply, | |
29386642 | 286 | }, |
4e5fe368 | 287 | [SPAPR_CAP_DFP] = { |
2d1fb9bc DG |
288 | .name = "dfp", |
289 | .description = "Allow Decimal Floating Point (DFP)", | |
4e5fe368 SJS |
290 | .index = SPAPR_CAP_DFP, |
291 | .get = spapr_cap_get_bool, | |
292 | .set = spapr_cap_set_bool, | |
293 | .type = "bool", | |
294 | .apply = cap_dfp_apply, | |
2d1fb9bc | 295 | }, |
8f38eaf8 SJS |
296 | [SPAPR_CAP_CFPC] = { |
297 | .name = "cfpc", | |
298 | .description = "Cache Flush on Privilege Change" VALUE_DESC_TRISTATE, | |
299 | .index = SPAPR_CAP_CFPC, | |
f27aa81e SJS |
300 | .get = spapr_cap_get_string, |
301 | .set = spapr_cap_set_string, | |
8f38eaf8 | 302 | .type = "string", |
f27aa81e | 303 | .possible = &cap_cfpc_possible, |
8f38eaf8 SJS |
304 | .apply = cap_safe_cache_apply, |
305 | }, | |
09114fd8 SJS |
306 | [SPAPR_CAP_SBBC] = { |
307 | .name = "sbbc", | |
308 | .description = "Speculation Barrier Bounds Checking" VALUE_DESC_TRISTATE, | |
309 | .index = SPAPR_CAP_SBBC, | |
aaf265ff SJS |
310 | .get = spapr_cap_get_string, |
311 | .set = spapr_cap_set_string, | |
09114fd8 | 312 | .type = "string", |
aaf265ff | 313 | .possible = &cap_sbbc_possible, |
09114fd8 SJS |
314 | .apply = cap_safe_bounds_check_apply, |
315 | }, | |
4be8d4e7 SJS |
316 | [SPAPR_CAP_IBS] = { |
317 | .name = "ibs", | |
c76c0d30 SJS |
318 | .description = |
319 | "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)", | |
4be8d4e7 | 320 | .index = SPAPR_CAP_IBS, |
c76c0d30 SJS |
321 | .get = spapr_cap_get_string, |
322 | .set = spapr_cap_set_string, | |
4be8d4e7 | 323 | .type = "string", |
c76c0d30 | 324 | .possible = &cap_ibs_possible, |
4be8d4e7 SJS |
325 | .apply = cap_safe_indirect_branch_apply, |
326 | }, | |
33face6b DG |
327 | }; |
328 | ||
329 | static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, | |
330 | CPUState *cs) | |
331 | { | |
332 | sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); | |
ee76a09f | 333 | PowerPCCPU *cpu = POWERPC_CPU(cs); |
33face6b DG |
334 | sPAPRCapabilities caps; |
335 | ||
336 | caps = smc->default_caps; | |
337 | ||
ee76a09f DG |
338 | if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_07, |
339 | 0, spapr->max_compat_pvr)) { | |
4e5fe368 | 340 | caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; |
b2540203 | 341 | caps.caps[SPAPR_CAP_CFPC] = SPAPR_CAP_BROKEN; |
ee76a09f | 342 | } |
33face6b | 343 | |
813f3cf6 SJS |
344 | if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06_PLUS, |
345 | 0, spapr->max_compat_pvr)) { | |
346 | caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; | |
347 | } | |
348 | ||
29386642 DG |
349 | if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_2_06, |
350 | 0, spapr->max_compat_pvr)) { | |
4e5fe368 SJS |
351 | caps.caps[SPAPR_CAP_VSX] = SPAPR_CAP_OFF; |
352 | caps.caps[SPAPR_CAP_DFP] = SPAPR_CAP_OFF; | |
813f3cf6 | 353 | caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; |
29386642 DG |
354 | } |
355 | ||
33face6b DG |
356 | return caps; |
357 | } | |
358 | ||
4e5fe368 | 359 | int spapr_caps_pre_load(void *opaque) |
be85537d DG |
360 | { |
361 | sPAPRMachineState *spapr = opaque; | |
362 | ||
4e5fe368 SJS |
363 | /* Set to default so we can tell if this came in with the migration */ |
364 | spapr->mig = spapr->def; | |
365 | return 0; | |
366 | } | |
367 | ||
368 | int spapr_caps_pre_save(void *opaque) | |
369 | { | |
370 | sPAPRMachineState *spapr = opaque; | |
371 | ||
372 | spapr->mig = spapr->eff; | |
373 | return 0; | |
be85537d DG |
374 | } |
375 | ||
376 | /* This has to be called from the top-level spapr post_load, not the | |
377 | * caps specific one. Otherwise it wouldn't be called when the source | |
378 | * caps are all defaults, which could still conflict with overridden | |
379 | * caps on the destination */ | |
380 | int spapr_caps_post_migration(sPAPRMachineState *spapr) | |
381 | { | |
be85537d DG |
382 | int i; |
383 | bool ok = true; | |
4e5fe368 | 384 | sPAPRCapabilities dstcaps = spapr->eff; |
be85537d DG |
385 | sPAPRCapabilities srccaps; |
386 | ||
387 | srccaps = default_caps_with_cpu(spapr, first_cpu); | |
4e5fe368 SJS |
388 | for (i = 0; i < SPAPR_CAP_NUM; i++) { |
389 | /* If not default value then assume came in with the migration */ | |
390 | if (spapr->mig.caps[i] != spapr->def.caps[i]) { | |
391 | srccaps.caps[i] = spapr->mig.caps[i]; | |
392 | } | |
393 | } | |
be85537d | 394 | |
4e5fe368 | 395 | for (i = 0; i < SPAPR_CAP_NUM; i++) { |
be85537d DG |
396 | sPAPRCapabilityInfo *info = &capability_table[i]; |
397 | ||
4e5fe368 SJS |
398 | if (srccaps.caps[i] > dstcaps.caps[i]) { |
399 | error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)", | |
400 | info->name, srccaps.caps[i], dstcaps.caps[i]); | |
be85537d DG |
401 | ok = false; |
402 | } | |
403 | ||
4e5fe368 SJS |
404 | if (srccaps.caps[i] < dstcaps.caps[i]) { |
405 | warn_report("cap-%s lower level (%d) in incoming stream than on destination (%d)", | |
406 | info->name, srccaps.caps[i], dstcaps.caps[i]); | |
be85537d DG |
407 | } |
408 | } | |
409 | ||
be85537d DG |
410 | return ok ? 0 : -EINVAL; |
411 | } | |
412 | ||
1f63ebaa | 413 | /* Used to generate the migration field and needed function for a spapr cap */ |
8c5909c4 SJS |
414 | #define SPAPR_CAP_MIG_STATE(sname, cap) \ |
415 | static bool spapr_cap_##sname##_needed(void *opaque) \ | |
1f63ebaa SJS |
416 | { \ |
417 | sPAPRMachineState *spapr = opaque; \ | |
418 | \ | |
8c5909c4 SJS |
419 | return spapr->cmd_line_caps[cap] && \ |
420 | (spapr->eff.caps[cap] != \ | |
421 | spapr->def.caps[cap]); \ | |
1f63ebaa SJS |
422 | } \ |
423 | \ | |
8c5909c4 SJS |
424 | const VMStateDescription vmstate_spapr_cap_##sname = { \ |
425 | .name = "spapr/cap/" #sname, \ | |
1f63ebaa SJS |
426 | .version_id = 1, \ |
427 | .minimum_version_id = 1, \ | |
8c5909c4 | 428 | .needed = spapr_cap_##sname##_needed, \ |
1f63ebaa | 429 | .fields = (VMStateField[]) { \ |
8c5909c4 | 430 | VMSTATE_UINT8(mig.caps[cap], \ |
1f63ebaa SJS |
431 | sPAPRMachineState), \ |
432 | VMSTATE_END_OF_LIST() \ | |
433 | }, \ | |
be85537d DG |
434 | } |
435 | ||
8c5909c4 SJS |
436 | SPAPR_CAP_MIG_STATE(htm, SPAPR_CAP_HTM); |
437 | SPAPR_CAP_MIG_STATE(vsx, SPAPR_CAP_VSX); | |
438 | SPAPR_CAP_MIG_STATE(dfp, SPAPR_CAP_DFP); | |
439 | SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC); | |
440 | SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC); | |
441 | SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS); | |
33face6b | 442 | |
4e5fe368 | 443 | void spapr_caps_reset(sPAPRMachineState *spapr) |
33face6b | 444 | { |
4e5fe368 | 445 | sPAPRCapabilities default_caps; |
33face6b DG |
446 | int i; |
447 | ||
4e5fe368 SJS |
448 | /* First compute the actual set of caps we're running with.. */ |
449 | default_caps = default_caps_with_cpu(spapr, first_cpu); | |
450 | ||
451 | for (i = 0; i < SPAPR_CAP_NUM; i++) { | |
452 | /* Store the defaults */ | |
453 | spapr->def.caps[i] = default_caps.caps[i]; | |
454 | /* If not set on the command line then apply the default value */ | |
455 | if (!spapr->cmd_line_caps[i]) { | |
456 | spapr->eff.caps[i] = default_caps.caps[i]; | |
457 | } | |
33face6b DG |
458 | } |
459 | ||
4e5fe368 SJS |
460 | /* .. then apply those caps to the virtual hardware */ |
461 | ||
462 | for (i = 0; i < SPAPR_CAP_NUM; i++) { | |
463 | sPAPRCapabilityInfo *info = &capability_table[i]; | |
33face6b | 464 | |
4e5fe368 SJS |
465 | /* |
466 | * If the apply function can't set the desired level and thinks it's | |
467 | * fatal, it should cause that. | |
468 | */ | |
469 | info->apply(spapr, spapr->eff.caps[i], &error_fatal); | |
33face6b | 470 | } |
33face6b DG |
471 | } |
472 | ||
473 | void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) | |
474 | { | |
475 | Error *local_err = NULL; | |
476 | ObjectClass *klass = OBJECT_CLASS(smc); | |
477 | int i; | |
478 | ||
479 | for (i = 0; i < ARRAY_SIZE(capability_table); i++) { | |
480 | sPAPRCapabilityInfo *cap = &capability_table[i]; | |
481 | const char *name = g_strdup_printf("cap-%s", cap->name); | |
4e5fe368 | 482 | char *desc; |
33face6b | 483 | |
4e5fe368 SJS |
484 | object_class_property_add(klass, name, cap->type, |
485 | cap->get, cap->set, | |
486 | NULL, cap, &local_err); | |
33face6b DG |
487 | if (local_err) { |
488 | error_propagate(errp, local_err); | |
489 | return; | |
490 | } | |
491 | ||
895d5cd6 | 492 | desc = g_strdup_printf("%s", cap->description); |
4e5fe368 SJS |
493 | object_class_property_set_description(klass, name, desc, &local_err); |
494 | g_free(desc); | |
33face6b DG |
495 | if (local_err) { |
496 | error_propagate(errp, local_err); | |
497 | return; | |
498 | } | |
499 | } | |
500 | } |