[RFC PATCH] target/loongarch/kvm: Add pmu support

Song Gao posted 1 patch 10 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20240514094630.988617-1-gaosong@loongson.cn
Maintainers: Song Gao <gaosong@loongson.cn>
There is a newer version of this series
target/loongarch/cpu.h                |  2 +
target/loongarch/cpu.c                | 64 +++++++++++++++++++++++++++
target/loongarch/kvm/kvm.c            | 55 ++++++++++++++++++++++-
target/loongarch/loongarch-qmp-cmds.c |  2 +-
4 files changed, 121 insertions(+), 2 deletions(-)
[RFC PATCH] target/loongarch/kvm: Add pmu support
Posted by Song Gao 10 months ago
This patch adds PMU support, We just sets some cpucfg6 default value
to PMU config on kvm mode, and then check the PMU config with kvm ioctl
KVM_GET_DEVICE_ATTR.
  e.g
    '...  -cpu max,pmu=on,pmnum=[1-16]';
    '...  -cpu max,pmu=on' (default pmnum = 4);
    '...  -cpu max,pmu=off' (disable PMU)

Signed-off-by: Song Gao <gaosong@loongson.cn>
---

This patch adds the 'RFC' heading because it requires
the kernel to merge into patch[1] first

[1]: https://lore.kernel.org/all/20240507120140.3119714-1-gaosong@loongson.cn/


 target/loongarch/cpu.h                |  2 +
 target/loongarch/cpu.c                | 64 +++++++++++++++++++++++++++
 target/loongarch/kvm/kvm.c            | 55 ++++++++++++++++++++++-
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 4 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 6c41fafb70..d834649106 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -184,6 +184,8 @@ FIELD(CPUCFG6, PMNUM, 4, 4)
 FIELD(CPUCFG6, PMBITS, 8, 6)
 FIELD(CPUCFG6, UPM, 14, 1)
 
+#define PMNUM_MAX 16
+
 /* cpucfg[16] bits */
 FIELD(CPUCFG16, L1_IUPRE, 0, 1)
 FIELD(CPUCFG16, L1_IUUNIFY, 1, 1)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index a0cad53676..c78ee3f0b1 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -8,6 +8,7 @@
 #include "qemu/osdep.h"
 #include "qemu/log.h"
 #include "qemu/qemu-print.h"
+#include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
 #include "sysemu/qtest.h"
@@ -19,6 +20,7 @@
 #include "internals.h"
 #include "fpu/softfloat-helpers.h"
 #include "cpu-csr.h"
+#include "qapi/visitor.h"
 #ifndef CONFIG_USER_ONLY
 #include "sysemu/reset.h"
 #endif
@@ -421,6 +423,14 @@ static void loongarch_la464_initfn(Object *obj)
     data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
     env->cpucfg[5] = data;
 
+    if (kvm_enabled()) {
+        data = 0;
+        data = FIELD_DP32(data, CPUCFG6, PMP, 1);
+        data = FIELD_DP32(data, CPUCFG6, PMNUM, 3);
+        data = FIELD_DP32(data, CPUCFG6, PMBITS, 63);
+        env->cpucfg[6] = data;
+    }
+
     data = 0;
     data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
     data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
@@ -643,6 +653,48 @@ 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)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+    uint32_t value = FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMNUM);
+
+    visit_type_uint32(v, name, &value, errp);
+}
+
+static void loongarch_set_pmnum(Object *obj, Visitor *v,
+                                const char *name, void *opaque,
+                                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);
+    }
+}
+
 void loongarch_cpu_post_init(Object *obj)
 {
     LoongArchCPU *cpu = LOONGARCH_CPU(obj);
@@ -655,6 +707,18 @@ void loongarch_cpu_post_init(Object *obj)
         object_property_add_bool(obj, "lasx", loongarch_get_lasx,
                                  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);
+        }
+    }
 }
 
 static void loongarch_cpu_init(Object *obj)
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index bc75552d0f..a9f9020071 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -556,6 +556,53 @@ static int kvm_check_cpucfg2(CPUState *cs)
     return ret;
 }
 
+static int kvm_check_cpucfg6(CPUState *cs)
+{
+    int ret;
+    uint64_t val;
+    struct kvm_device_attr attr = {
+        .group = KVM_LOONGARCH_VCPU_CPUCFG,
+        .attr = 6,
+        .addr = (uint64_t)&val,
+    };
+    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    CPULoongArchState *env = &cpu->env;
+
+    ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
+    if (!ret) {
+        kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
+
+        if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) {
+             /* Check PMP */
+             if (!FIELD_EX32(val, CPUCFG6, PMP)) {
+                 error_report("'pmu' feature not supported by KVM on this host"
+                              " Please disable 'pmu' with "
+                              "'... -cpu XXX,pmu=off ...'\n");
+                 exit(EXIT_FAILURE);
+             }
+             /* Check PMNUM */
+             int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM);
+             int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM);
+             if (guest_pmnum > host_pmnum){
+                 warn_report("The guest pmnum %d larger than KVM support %d\n",
+                              guest_pmnum, host_pmnum);
+                 env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6,
+                                             PMNUM, host_pmnum);
+             }
+             /* Check PMBITS */
+             int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS);
+             int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS);
+             if (guest_pmbits != host_pmbits) {
+                 warn_report("The host not support PMBITS %d\n", guest_pmbits);
+                 env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6,
+                                             PMBITS, host_pmbits);
+             }
+        }
+    }
+
+    return ret;
+}
+
 static int kvm_loongarch_put_cpucfg(CPUState *cs)
 {
     int i, ret = 0;
@@ -568,7 +615,13 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
             if (ret) {
                 return ret;
             }
-	}
+        }
+        if (i == 6) {
+            ret = kvm_check_cpucfg6(cs);
+            if (ret) {
+                return ret;
+            }
+        }
         val = env->cpucfg[i];
         ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
         if (ret < 0) {
diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c
index 8721a5eb13..d7f2af363b 100644
--- a/target/loongarch/loongarch-qmp-cmds.c
+++ b/target/loongarch/loongarch-qmp-cmds.c
@@ -40,7 +40,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 }
 
 static const char *cpu_model_advertised_features[] = {
-    "lsx", "lasx", NULL
+    "lsx", "lasx", "pmu", "pmnum", NULL
 };
 
 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
-- 
2.25.1
Re: [RFC PATCH] target/loongarch/kvm: Add pmu support
Posted by maobibo 10 months ago

On 2024/5/14 下午5:46, Song Gao wrote:
> This patch adds PMU support, We just sets some cpucfg6 default value
> to PMU config on kvm mode, and then check the PMU config with kvm ioctl
> KVM_GET_DEVICE_ATTR.
>    e.g
>      '...  -cpu max,pmu=on,pmnum=[1-16]';
>      '...  -cpu max,pmu=on' (default pmnum = 4);
Do we need expose interface pmnum to user?
The default PMU number is 4 on la464/la664, it should equal to real HW.
There is no much meaning with pmnum == 1 although it supports.

>      '...  -cpu max,pmu=off' (disable PMU)
> 
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
> 
> This patch adds the 'RFC' heading because it requires
> the kernel to merge into patch[1] first
> 
> [1]: https://lore.kernel.org/all/20240507120140.3119714-1-gaosong@loongson.cn/
> 
> 
>   target/loongarch/cpu.h                |  2 +
>   target/loongarch/cpu.c                | 64 +++++++++++++++++++++++++++
>   target/loongarch/kvm/kvm.c            | 55 ++++++++++++++++++++++-
>   target/loongarch/loongarch-qmp-cmds.c |  2 +-
>   4 files changed, 121 insertions(+), 2 deletions(-)
> 
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 6c41fafb70..d834649106 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -184,6 +184,8 @@ FIELD(CPUCFG6, PMNUM, 4, 4)
>   FIELD(CPUCFG6, PMBITS, 8, 6)
>   FIELD(CPUCFG6, UPM, 14, 1)
>   
> +#define PMNUM_MAX 16
> +
>   /* cpucfg[16] bits */
>   FIELD(CPUCFG16, L1_IUPRE, 0, 1)
>   FIELD(CPUCFG16, L1_IUUNIFY, 1, 1)
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index a0cad53676..c78ee3f0b1 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -8,6 +8,7 @@
>   #include "qemu/osdep.h"
>   #include "qemu/log.h"
>   #include "qemu/qemu-print.h"
> +#include "qemu/error-report.h"
>   #include "qapi/error.h"
>   #include "qemu/module.h"
>   #include "sysemu/qtest.h"
> @@ -19,6 +20,7 @@
>   #include "internals.h"
>   #include "fpu/softfloat-helpers.h"
>   #include "cpu-csr.h"
> +#include "qapi/visitor.h"
>   #ifndef CONFIG_USER_ONLY
>   #include "sysemu/reset.h"
>   #endif
> @@ -421,6 +423,14 @@ static void loongarch_la464_initfn(Object *obj)
>       data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
>       env->cpucfg[5] = data;
>   
> +    if (kvm_enabled()) {
> +        data = 0;
> +        data = FIELD_DP32(data, CPUCFG6, PMP, 1);
> +        data = FIELD_DP32(data, CPUCFG6, PMNUM, 3);
> +        data = FIELD_DP32(data, CPUCFG6, PMBITS, 63);
> +        env->cpucfg[6] = data;
> +    }
> +
>       data = 0;
>       data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
>       data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
> @@ -643,6 +653,48 @@ 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)
> +{
> +    LoongArchCPU *cpu = LOONGARCH_CPU(obj);
> +    uint32_t value = FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMNUM);
> +
> +    visit_type_uint32(v, name, &value, errp);
> +}
> +
> +static void loongarch_set_pmnum(Object *obj, Visitor *v,
> +                                const char *name, void *opaque,
> +                                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);
> +    }
> +}
> +
>   void loongarch_cpu_post_init(Object *obj)
>   {
>       LoongArchCPU *cpu = LOONGARCH_CPU(obj);
> @@ -655,6 +707,18 @@ void loongarch_cpu_post_init(Object *obj)
>           object_property_add_bool(obj, "lasx", loongarch_get_lasx,
>                                    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);
> +        }
> +    }
>   }
>   
>   static void loongarch_cpu_init(Object *obj)
> diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
> index bc75552d0f..a9f9020071 100644
> --- a/target/loongarch/kvm/kvm.c
> +++ b/target/loongarch/kvm/kvm.c
> @@ -556,6 +556,53 @@ static int kvm_check_cpucfg2(CPUState *cs)
>       return ret;
>   }
>   
> +static int kvm_check_cpucfg6(CPUState *cs)
> +{
> +    int ret;
> +    uint64_t val;
> +    struct kvm_device_attr attr = {
> +        .group = KVM_LOONGARCH_VCPU_CPUCFG,
> +        .attr = 6,
> +        .addr = (uint64_t)&val,
> +    };
> +    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> +    CPULoongArchState *env = &cpu->env;
> +
> +    ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
> +    if (!ret) {
> +        kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
> +
> +        if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) {
> +             /* Check PMP */
> +             if (!FIELD_EX32(val, CPUCFG6, PMP)) {
> +                 error_report("'pmu' feature not supported by KVM on this host"
> +                              " Please disable 'pmu' with "
> +                              "'... -cpu XXX,pmu=off ...'\n");
> +                 exit(EXIT_FAILURE);
> +             }
> +             /* Check PMNUM */
> +             int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM);
> +             int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM);
> +             if (guest_pmnum > host_pmnum){
> +                 warn_report("The guest pmnum %d larger than KVM support %d\n",
> +                              guest_pmnum, host_pmnum);
It should report error and exit.
When VM migrates to physical machine with smaller pmu number, it should 
fail to migrate.

Regards
Bibo Mao
> +                 env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6,
> +                                             PMNUM, host_pmnum);
> +             }
> +             /* Check PMBITS */
> +             int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS);
> +             int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS);
> +             if (guest_pmbits != host_pmbits) {
> +                 warn_report("The host not support PMBITS %d\n", guest_pmbits);
> +                 env->cpucfg[6] = FIELD_DP32(env->cpucfg[6], CPUCFG6,
> +                                             PMBITS, host_pmbits);
> +             }
> +        }
> +    }
> +
> +    return ret;
> +}
> +
>   static int kvm_loongarch_put_cpucfg(CPUState *cs)
>   {
>       int i, ret = 0;
> @@ -568,7 +615,13 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
>               if (ret) {
>                   return ret;
>               }
> -	}
> +        }
> +        if (i == 6) {
> +            ret = kvm_check_cpucfg6(cs);
> +            if (ret) {
> +                return ret;
> +            }
> +        }
>           val = env->cpucfg[i];
>           ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
>           if (ret < 0) {
> diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c
> index 8721a5eb13..d7f2af363b 100644
> --- a/target/loongarch/loongarch-qmp-cmds.c
> +++ b/target/loongarch/loongarch-qmp-cmds.c
> @@ -40,7 +40,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
>   }
>   
>   static const char *cpu_model_advertised_features[] = {
> -    "lsx", "lasx", NULL
> +    "lsx", "lasx", "pmu", "pmnum", NULL
>   };
>   
>   CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
>