diff options
Diffstat (limited to 'hw/ppc/spapr_caps.c')
-rw-r--r-- | hw/ppc/spapr_caps.c | 254 |
1 files changed, 182 insertions, 72 deletions
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 64f98ae68d..edc5ed0e0c 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -31,10 +31,11 @@ #include "target/ppc/mmu-hash64.h" #include "cpu-models.h" #include "kvm_ppc.h" +#include "sysemu/qtest.h" #include "hw/ppc/spapr.h" -typedef struct sPAPRCapPossible { +typedef struct SpaprCapPossible { int num; /* size of vals array below */ const char *help; /* help text for vals */ /* @@ -46,9 +47,9 @@ typedef struct sPAPRCapPossible { * point is observed */ const char *vals[]; -} sPAPRCapPossible; +} SpaprCapPossible; -typedef struct sPAPRCapabilityInfo { +typedef struct SpaprCapabilityInfo { const char *name; const char *description; int index; @@ -58,18 +59,18 @@ typedef struct sPAPRCapabilityInfo { ObjectPropertyAccessor *set; const char *type; /* Possible values if this is a custom string type */ - sPAPRCapPossible *possible; + SpaprCapPossible *possible; /* Make sure the virtual hardware can support this capability */ - void (*apply)(sPAPRMachineState *spapr, uint8_t val, Error **errp); - void (*cpu_apply)(sPAPRMachineState *spapr, PowerPCCPU *cpu, + void (*apply)(SpaprMachineState *spapr, uint8_t val, Error **errp); + void (*cpu_apply)(SpaprMachineState *spapr, PowerPCCPU *cpu, uint8_t val, Error **errp); -} sPAPRCapabilityInfo; +} SpaprCapabilityInfo; static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + SpaprCapabilityInfo *cap = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(obj); bool value = spapr_get_cap(spapr, cap->index) == SPAPR_CAP_ON; visit_type_bool(v, name, &value, errp); @@ -78,8 +79,8 @@ static void spapr_cap_get_bool(Object *obj, Visitor *v, const char *name, static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + SpaprCapabilityInfo *cap = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(obj); bool value; Error *local_err = NULL; @@ -97,8 +98,8 @@ static void spapr_cap_set_bool(Object *obj, Visitor *v, const char *name, static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + SpaprCapabilityInfo *cap = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(obj); char *val = NULL; uint8_t value = spapr_get_cap(spapr, cap->index); @@ -116,8 +117,8 @@ static void spapr_cap_get_string(Object *obj, Visitor *v, const char *name, static void spapr_cap_set_string(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + SpaprCapabilityInfo *cap = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(obj); Error *local_err = NULL; uint8_t i; char *val; @@ -149,8 +150,8 @@ out: static void spapr_cap_get_pagesize(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + SpaprCapabilityInfo *cap = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(obj); uint8_t val = spapr_get_cap(spapr, cap->index); uint64_t pagesize = (1ULL << val); @@ -160,8 +161,8 @@ static void spapr_cap_get_pagesize(Object *obj, Visitor *v, const char *name, static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - sPAPRCapabilityInfo *cap = opaque; - sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + SpaprCapabilityInfo *cap = opaque; + SpaprMachineState *spapr = SPAPR_MACHINE(obj); uint64_t pagesize; uint8_t val; Error *local_err = NULL; @@ -182,7 +183,7 @@ static void spapr_cap_set_pagesize(Object *obj, Visitor *v, const char *name, spapr->eff.caps[cap->index] = val; } -static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) +static void cap_htm_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { if (!val) { /* TODO: We don't support disabling htm yet */ @@ -198,7 +199,7 @@ static void cap_htm_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) } } -static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) +static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { PowerPCCPU *cpu = POWERPC_CPU(first_cpu); CPUPPCState *env = &cpu->env; @@ -215,7 +216,7 @@ static void cap_vsx_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) } } -static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) +static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { PowerPCCPU *cpu = POWERPC_CPU(first_cpu); CPUPPCState *env = &cpu->env; @@ -229,83 +230,97 @@ static void cap_dfp_apply(sPAPRMachineState *spapr, uint8_t val, Error **errp) } } -sPAPRCapPossible cap_cfpc_possible = { +SpaprCapPossible cap_cfpc_possible = { .num = 3, .vals = {"broken", "workaround", "fixed"}, .help = "broken - no protection, workaround - workaround available," " fixed - fixed in hardware", }; -static void cap_safe_cache_apply(sPAPRMachineState *spapr, uint8_t val, +static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + Error *local_err = NULL; uint8_t kvm_val = kvmppc_get_cap_safe_cache(); if (tcg_enabled() && val) { - /* TODO - for now only allow broken for TCG */ - error_setg(errp, -"Requested safe cache capability level not supported by tcg, try a different value for cap-cfpc"); + /* TCG only supports broken, allow other values and print a warning */ + error_setg(&local_err, + "TCG doesn't support requested feature, cap-cfpc=%s", + cap_cfpc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, "Requested safe cache capability level not supported by kvm, try cap-cfpc=%s", cap_cfpc_possible.vals[kvm_val]); } + + if (local_err != NULL) + warn_report_err(local_err); } -sPAPRCapPossible cap_sbbc_possible = { +SpaprCapPossible cap_sbbc_possible = { .num = 3, .vals = {"broken", "workaround", "fixed"}, .help = "broken - no protection, workaround - workaround available," " fixed - fixed in hardware", }; -static void cap_safe_bounds_check_apply(sPAPRMachineState *spapr, uint8_t val, +static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + Error *local_err = NULL; uint8_t kvm_val = kvmppc_get_cap_safe_bounds_check(); if (tcg_enabled() && val) { - /* TODO - for now only allow broken for TCG */ - error_setg(errp, -"Requested safe bounds check capability level not supported by tcg, try a different value for cap-sbbc"); + /* TCG only supports broken, allow other values and print a warning */ + error_setg(&local_err, + "TCG doesn't support requested feature, cap-sbbc=%s", + cap_sbbc_possible.vals[val]); } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, "Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s", cap_sbbc_possible.vals[kvm_val]); } + + if (local_err != NULL) + warn_report_err(local_err); } -sPAPRCapPossible cap_ibs_possible = { - .num = 4, +SpaprCapPossible cap_ibs_possible = { + .num = 5, /* Note workaround only maintained for compatibility */ - .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd"}, - .help = "broken - no protection, fixed-ibs - indirect branch serialisation," - " fixed-ccd - cache count disabled", + .vals = {"broken", "workaround", "fixed-ibs", "fixed-ccd", "fixed-na"}, + .help = "broken - no protection, workaround - count cache flush" + ", fixed-ibs - indirect branch serialisation," + " fixed-ccd - cache count disabled," + " fixed-na - fixed in hardware (no longer applicable)", }; -static void cap_safe_indirect_branch_apply(sPAPRMachineState *spapr, +static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { + Error *local_err = NULL; uint8_t kvm_val = kvmppc_get_cap_safe_indirect_branch(); - if (val == SPAPR_CAP_WORKAROUND) { /* Can only be Broken or Fixed */ - error_setg(errp, -"Requested safe indirect branch capability level \"workaround\" not valid, try cap-ibs=%s", - cap_ibs_possible.vals[kvm_val]); - } else if (tcg_enabled() && val) { - /* TODO - for now only allow broken for TCG */ - error_setg(errp, -"Requested safe indirect branch capability level not supported by tcg, try a different value for cap-ibs"); - } else if (kvm_enabled() && val && (val != kvm_val)) { + if (tcg_enabled() && val) { + /* TCG only supports broken, allow other values and print a warning */ + error_setg(&local_err, + "TCG doesn't support requested feature, cap-ibs=%s", + cap_ibs_possible.vals[val]); + } else if (kvm_enabled() && (val > kvm_val)) { error_setg(errp, "Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s", cap_ibs_possible.vals[kvm_val]); } + + if (local_err != NULL) { + warn_report_err(local_err); + } } #define VALUE_DESC_TRISTATE " (broken, workaround, fixed)" -void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize, +void spapr_check_pagesize(SpaprMachineState *spapr, hwaddr pagesize, Error **errp) { hwaddr maxpagesize = (1ULL << spapr->eff.caps[SPAPR_CAP_HPT_MAXPAGESIZE]); @@ -322,7 +337,7 @@ void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize, } } -static void cap_hpt_maxpagesize_apply(sPAPRMachineState *spapr, +static void cap_hpt_maxpagesize_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { if (val < 12) { @@ -359,7 +374,7 @@ static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift, return true; } -static void cap_hpt_maxpagesize_cpu_apply(sPAPRMachineState *spapr, +static void cap_hpt_maxpagesize_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu, uint8_t val, Error **errp) { @@ -368,7 +383,7 @@ static void cap_hpt_maxpagesize_cpu_apply(sPAPRMachineState *spapr, ppc_hash64_filter_pagesizes(cpu, spapr_pagesize_cb, &maxshift); } -static void cap_nested_kvm_hv_apply(sPAPRMachineState *spapr, +static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr, uint8_t val, Error **errp) { if (!val) { @@ -390,7 +405,75 @@ static void cap_nested_kvm_hv_apply(sPAPRMachineState *spapr, } } -sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { +static void cap_large_decr_apply(SpaprMachineState *spapr, + uint8_t val, Error **errp) +{ + PowerPCCPU *cpu = POWERPC_CPU(first_cpu); + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + + if (!val) { + return; /* Disabled by default */ + } + + if (tcg_enabled()) { + if (!ppc_check_compat(cpu, CPU_POWERPC_LOGICAL_3_00, 0, + spapr->max_compat_pvr)) { + error_setg(errp, + "Large decrementer only supported on POWER9, try -cpu POWER9"); + return; + } + } else if (kvm_enabled()) { + int kvm_nr_bits = kvmppc_get_cap_large_decr(); + + if (!kvm_nr_bits) { + error_setg(errp, + "No large decrementer support, try cap-large-decr=off"); + } else if (pcc->lrg_decr_bits != kvm_nr_bits) { + error_setg(errp, +"KVM large decrementer size (%d) differs to model (%d), try -cap-large-decr=off", + kvm_nr_bits, pcc->lrg_decr_bits); + } + } +} + +static void cap_large_decr_cpu_apply(SpaprMachineState *spapr, + PowerPCCPU *cpu, + uint8_t val, Error **errp) +{ + CPUPPCState *env = &cpu->env; + target_ulong lpcr = env->spr[SPR_LPCR]; + + if (kvm_enabled()) { + if (kvmppc_enable_cap_large_decr(cpu, val)) { + error_setg(errp, + "No large decrementer support, try cap-large-decr=off"); + } + } + + if (val) { + lpcr |= LPCR_LD; + } else { + lpcr &= ~LPCR_LD; + } + ppc_store_lpcr(cpu, lpcr); +} + +static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val, + Error **errp) +{ + uint8_t kvm_val = kvmppc_get_cap_count_cache_flush_assist(); + + if (tcg_enabled() && val) { + /* TODO - for now only allow broken for TCG */ + error_setg(errp, +"Requested count cache flush assist capability level not supported by tcg, try cap-ccf-assist=off"); + } else if (kvm_enabled() && (val > kvm_val)) { + error_setg(errp, +"Requested count cache flush assist capability level not supported by kvm, try cap-ccf-assist=off"); + } +} + +SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = { [SPAPR_CAP_HTM] = { .name = "htm", .description = "Allow Hardware Transactional Memory (HTM)", @@ -441,7 +524,8 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { [SPAPR_CAP_IBS] = { .name = "ibs", .description = - "Indirect Branch Speculation (broken, fixed-ibs, fixed-ccd)", + "Indirect Branch Speculation (broken, workaround, fixed-ibs," + "fixed-ccd, fixed-na)", .index = SPAPR_CAP_IBS, .get = spapr_cap_get_string, .set = spapr_cap_set_string, @@ -468,16 +552,40 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { .type = "bool", .apply = cap_nested_kvm_hv_apply, }, + [SPAPR_CAP_LARGE_DECREMENTER] = { + .name = "large-decr", + .description = "Allow Large Decrementer", + .index = SPAPR_CAP_LARGE_DECREMENTER, + .get = spapr_cap_get_bool, + .set = spapr_cap_set_bool, + .type = "bool", + .apply = cap_large_decr_apply, + .cpu_apply = cap_large_decr_cpu_apply, + }, + [SPAPR_CAP_CCF_ASSIST] = { + .name = "ccf-assist", + .description = "Count Cache Flush Assist via HW Instruction", + .index = SPAPR_CAP_CCF_ASSIST, + .get = spapr_cap_get_bool, + .set = spapr_cap_set_bool, + .type = "bool", + .apply = cap_ccf_assist_apply, + }, }; -static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, +static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr, const char *cputype) { - sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); - sPAPRCapabilities caps; + SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); + SpaprCapabilities caps; caps = smc->default_caps; + if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_3_00, + 0, spapr->max_compat_pvr)) { + caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF; + } + if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_07, 0, spapr->max_compat_pvr)) { caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF; @@ -514,7 +622,7 @@ static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, int spapr_caps_pre_load(void *opaque) { - sPAPRMachineState *spapr = opaque; + SpaprMachineState *spapr = opaque; /* Set to default so we can tell if this came in with the migration */ spapr->mig = spapr->def; @@ -523,7 +631,7 @@ int spapr_caps_pre_load(void *opaque) int spapr_caps_pre_save(void *opaque) { - sPAPRMachineState *spapr = opaque; + SpaprMachineState *spapr = opaque; spapr->mig = spapr->eff; return 0; @@ -533,12 +641,12 @@ int spapr_caps_pre_save(void *opaque) * caps specific one. Otherwise it wouldn't be called when the source * caps are all defaults, which could still conflict with overridden * caps on the destination */ -int spapr_caps_post_migration(sPAPRMachineState *spapr) +int spapr_caps_post_migration(SpaprMachineState *spapr) { int i; bool ok = true; - sPAPRCapabilities dstcaps = spapr->eff; - sPAPRCapabilities srccaps; + SpaprCapabilities dstcaps = spapr->eff; + SpaprCapabilities srccaps; srccaps = default_caps_with_cpu(spapr, MACHINE(spapr)->cpu_type); for (i = 0; i < SPAPR_CAP_NUM; i++) { @@ -549,7 +657,7 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr) } for (i = 0; i < SPAPR_CAP_NUM; i++) { - sPAPRCapabilityInfo *info = &capability_table[i]; + SpaprCapabilityInfo *info = &capability_table[i]; if (srccaps.caps[i] > dstcaps.caps[i]) { error_report("cap-%s higher level (%d) in incoming stream than on destination (%d)", @@ -570,7 +678,7 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr) #define SPAPR_CAP_MIG_STATE(sname, cap) \ static bool spapr_cap_##sname##_needed(void *opaque) \ { \ - sPAPRMachineState *spapr = opaque; \ + SpaprMachineState *spapr = opaque; \ \ return spapr->cmd_line_caps[cap] && \ (spapr->eff.caps[cap] != \ @@ -584,7 +692,7 @@ const VMStateDescription vmstate_spapr_cap_##sname = { \ .needed = spapr_cap_##sname##_needed, \ .fields = (VMStateField[]) { \ VMSTATE_UINT8(mig.caps[cap], \ - sPAPRMachineState), \ + SpaprMachineState), \ VMSTATE_END_OF_LIST() \ }, \ } @@ -596,10 +704,12 @@ SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC); SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC); SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS); SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV); +SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER); +SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST); -void spapr_caps_init(sPAPRMachineState *spapr) +void spapr_caps_init(SpaprMachineState *spapr) { - sPAPRCapabilities default_caps; + SpaprCapabilities default_caps; int i; /* Compute the actual set of caps we should run with */ @@ -615,12 +725,12 @@ void spapr_caps_init(sPAPRMachineState *spapr) } } -void spapr_caps_apply(sPAPRMachineState *spapr) +void spapr_caps_apply(SpaprMachineState *spapr) { int i; for (i = 0; i < SPAPR_CAP_NUM; i++) { - sPAPRCapabilityInfo *info = &capability_table[i]; + SpaprCapabilityInfo *info = &capability_table[i]; /* * If the apply function can't set the desired level and thinks it's @@ -630,12 +740,12 @@ void spapr_caps_apply(sPAPRMachineState *spapr) } } -void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu) +void spapr_caps_cpu_apply(SpaprMachineState *spapr, PowerPCCPU *cpu) { int i; for (i = 0; i < SPAPR_CAP_NUM; i++) { - sPAPRCapabilityInfo *info = &capability_table[i]; + SpaprCapabilityInfo *info = &capability_table[i]; /* * If the apply function can't set the desired level and thinks it's @@ -647,14 +757,14 @@ void spapr_caps_cpu_apply(sPAPRMachineState *spapr, PowerPCCPU *cpu) } } -void spapr_caps_add_properties(sPAPRMachineClass *smc, Error **errp) +void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp) { Error *local_err = NULL; ObjectClass *klass = OBJECT_CLASS(smc); int i; for (i = 0; i < ARRAY_SIZE(capability_table); i++) { - sPAPRCapabilityInfo *cap = &capability_table[i]; + SpaprCapabilityInfo *cap = &capability_table[i]; const char *name = g_strdup_printf("cap-%s", cap->name); char *desc; |