From b87b4782e8147fd481becd946ca909edaaa58b41 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 18 Sep 2024 16:23:15 +0800 Subject: [PATCH 59/78] target/loongarch/kvm: Implement LoongArch PMU extension Implement PMU extension for LoongArch kvm mode. Use OnOffAuto type variable pmu to check the PMU feature. If the PMU Feature is not supported with KVM host, it reports error if there is pmu=on command line. If there is no any command line about pmu parameter, it checks whether KVM host supports the PMU Feature and set the corresponding value in cpucfg. This patch is based on lbt patch located at https://lore.kernel.org/qemu-devel/20240904061859.86615-1-maobibo@loongson.cn Co-developed-by: Song Gao Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20240918082315.2345034-1-maobibo@loongson.cn> Signed-off-by: Song Gao Signed-off-by: Xianglai Li --- target/loongarch/cpu.c | 63 +++++++-------------------- target/loongarch/cpu.h | 2 + target/loongarch/kvm/kvm.c | 41 +++++++++++++++++ target/loongarch/loongarch-qmp-cmds.c | 2 +- 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index a57067938d..2ee1d63989 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -695,58 +695,28 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp) } } -static bool loongarch_get_pmu(Object *obj, Error **errp) -{ - LoongArchCPU *cpu = LOONGARCH_CPU(obj); - - return !!(FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)); -} - -static void loongarch_set_pmu(Object *obj, bool value, Error **errp) -{ - LoongArchCPU *cpu = LOONGARCH_CPU(obj); - - cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, value); -} - -static void loongarch_get_pmnum(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) +static bool loongarch_get_lbt(Object *obj, Error **errp) { - LoongArchCPU *cpu = LOONGARCH_CPU(obj); - uint32_t value = FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMNUM); - - visit_type_uint32(v, name, &value, errp); + return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF; } -static void loongarch_set_pmnum(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) +static void loongarch_set_lbt(Object *obj, bool value, Error **errp) { LoongArchCPU *cpu = LOONGARCH_CPU(obj); - uint32_t *value= opaque; - if (!visit_type_uint32(v, name, value, errp)) { - return; - } - if ((*value <= PMNUM_MAX) && (*value > 0)) { - cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, *value -1); - } else { - error_report("Performance counter number need be in [1- %d]\n", PMNUM_MAX); - exit(EXIT_FAILURE); - } + cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } -static bool loongarch_get_lbt(Object *obj, Error **errp) +static bool loongarch_get_pmu(Object *obj, Error **errp) { - return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF; + return LOONGARCH_CPU(obj)->pmu != ON_OFF_AUTO_OFF; } -static void loongarch_set_lbt(Object *obj, bool value, Error **errp) +static void loongarch_set_pmu(Object *obj, bool value, Error **errp) { LoongArchCPU *cpu = LOONGARCH_CPU(obj); - cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; + cpu->pmu = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; } void loongarch_cpu_post_init(Object *obj) @@ -759,21 +729,18 @@ void loongarch_cpu_post_init(Object *obj) loongarch_set_lasx); if (kvm_enabled()) { - object_property_add_bool(obj, "pmu", loongarch_get_pmu, - loongarch_set_pmu); - if (FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)) { - uint32_t value = 4; - object_property_add(obj, "pmnum", "uint32", - loongarch_get_pmnum, - loongarch_set_pmnum, NULL, - (void *)&value); - } - cpu->lbt = ON_OFF_AUTO_AUTO; object_property_add_bool(obj, "lbt", loongarch_get_lbt, loongarch_set_lbt); object_property_set_description(obj, "lbt", "Set off to disable Binary Tranlation."); + + cpu->pmu = ON_OFF_AUTO_AUTO; + object_property_add_bool(obj, "pmu", loongarch_get_pmu, + loongarch_set_pmu); + object_property_set_description(obj, "pmu", + "Set off to performance monitor unit."); + } else { cpu->lbt = ON_OFF_AUTO_OFF; } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 2f8c5cf2dd..8ff00d17e1 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -289,6 +289,7 @@ typedef struct LoongArchTLB LoongArchTLB; enum loongarch_features { LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */ + LOONGARCH_FEATURE_PMU, }; typedef struct LoongArchBT { @@ -407,6 +408,7 @@ struct ArchCPU { QEMUTimer timer; uint32_t phy_id; OnOffAuto lbt; + OnOffAuto pmu; /* 'compatible' string for this CPU for Linux device trees */ const char *dtb_compatible; diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 118f66f742..8b0f86a201 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -870,9 +870,18 @@ static bool kvm_feature_supported(CPUState *cs, enum loongarch_features feature) attr.attr = KVM_LOONGARCH_VM_FEAT_MIPSBT; ret |= kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); return (ret == 0); + + case LOONGARCH_FEATURE_PMU: + attr.group = KVM_LOONGARCH_VM_FEAT_CTRL; + attr.attr = KVM_LOONGARCH_VM_FEAT_PMU; + ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr); + return (ret == 0); + default: return false; } + + return false; } static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) @@ -896,6 +905,32 @@ static int kvm_cpu_check_lbt(CPUState *cs, Error **errp) return 0; } +static int kvm_cpu_check_pmu(CPUState *cs, Error **errp) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = cpu_env(cs); + bool kvm_supported; + + kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PMU); + if (cpu->pmu == ON_OFF_AUTO_ON) { + if (!kvm_supported) { + error_setg(errp, "'pmu' feature not supported by KVM on the host"); + return -ENOTSUP; + } + } else if (cpu->pmu != ON_OFF_AUTO_AUTO) { + /* disable pmu if ON_OFF_AUTO_OFF is set */ + kvm_supported = false; + } + + if (kvm_supported) { + env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMP, 1); + env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMNUM, 3); + env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, PMBITS, 63); + env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6, UPM, 1); + } + return 0; +} + int kvm_arch_init_vcpu(CPUState *cs) { uint64_t val; @@ -913,6 +948,12 @@ int kvm_arch_init_vcpu(CPUState *cs) if (ret < 0) { error_report_err(local_err); } + + ret = kvm_cpu_check_pmu(cs, &local_err); + if (ret < 0) { + error_report_err(local_err); + } + return ret; } diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c index 644b528824..dc78a3ffa2 100644 --- a/target/loongarch/loongarch-qmp-cmds.c +++ b/target/loongarch/loongarch-qmp-cmds.c @@ -42,7 +42,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) } static const char *cpu_model_advertised_features[] = { - "lsx", "lasx", "lbt", "pmu", "pmnum", NULL + "lsx", "lasx", "lbt", "pmu", NULL }; CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type, -- 2.39.1