From: Tao Cui <[email protected]>

Probe the KVM_LOONGARCH_VM_FEAT_PV_TLB_FLUSH VM-level capability and, when
the host supports it, advertise KVM_FEATURE_PV_TLB_FLUSH to the guest by
including it in the CPUCFG_KVM_FEATURE feature mask handed to the kernel.

This mirrors the existing PV IPI / steal-time enablement.  A new
kvm-pv-tlb-flush CPU property (on/off/auto, default auto) lets users
disable the feature, e.g. when migrating to a host that lacks it.

The feature is only advertised when the host actually supports it, so a
guest never observes KVM_FEATURE_PV_TLB_FLUSH on a host that cannot
service PV TLB flush requests (which would otherwise lead to stale TLBs).

Signed-off-by: Tao Cui <[email protected]>
---
 target/loongarch/cpu.h                |  2 ++
 target/loongarch/kvm/kvm.c            | 38 +++++++++++++++++++++++++++
 target/loongarch/loongarch-qmp-cmds.c |  4 +--
 3 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ad30c73167..94e8f176f4 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -300,6 +300,7 @@ enum loongarch_features {
     LOONGARCH_FEATURE_PMU,
     LOONGARCH_FEATURE_PV_IPI,
     LOONGARCH_FEATURE_STEALTIME,
+    LOONGARCH_FEATURE_PV_TLB_FLUSH,
     LOONGARCH_FEATURE_PTW,
 };
 
@@ -447,6 +448,7 @@ struct ArchCPU {
     OnOffAuto msgint;
     OnOffAuto kvm_pv_ipi;
     OnOffAuto kvm_steal_time;
+    OnOffAuto kvm_pv_tlb_flush;
     int32_t socket_id;  /* socket-id of this CPU */
     int32_t core_id;    /* core-id of this CPU */
     int32_t thread_id;  /* thread-id of this CPU */
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index d6539c12ac..f91c388bf3 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -981,6 +981,12 @@ static bool kvm_feature_supported(CPUState *cs, enum 
loongarch_features feature)
         ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
         return (ret == 0);
 
+    case LOONGARCH_FEATURE_PV_TLB_FLUSH:
+        attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
+        attr.attr = KVM_LOONGARCH_VM_FEAT_PV_TLB_FLUSH;
+        ret = kvm_vm_ioctl(kvm_state, KVM_HAS_DEVICE_ATTR, &attr);
+        return (ret == 0);
+
     case LOONGARCH_FEATURE_PTW:
         attr.group = KVM_LOONGARCH_VM_FEAT_CTRL;
         attr.attr = KVM_LOONGARCH_VM_FEAT_PTW;
@@ -1150,6 +1156,20 @@ static int kvm_cpu_check_pv_features(CPUState *cs, Error 
**errp)
         env->pv_features |= BIT(KVM_FEATURE_STEAL_TIME);
     }
 
+    kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_PV_TLB_FLUSH);
+    if (cpu->kvm_pv_tlb_flush == ON_OFF_AUTO_ON) {
+        if (!kvm_supported) {
+            error_setg(errp, "'pv_tlb_flush' not supported by KVM host");
+            return -ENOTSUP;
+        }
+    } else if (cpu->kvm_pv_tlb_flush != ON_OFF_AUTO_AUTO) {
+        kvm_supported = false;
+    }
+
+    if (kvm_supported) {
+        env->pv_features |= BIT(KVM_FEATURE_PV_TLB_FLUSH);
+    }
+
     if (object_dynamic_cast(OBJECT(ms), TYPE_LOONGARCH_VIRT_MACHINE)) {
         LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(ms);
 
@@ -1266,6 +1286,18 @@ static void kvm_steal_time_set(Object *obj, bool value, 
Error **errp)
     cpu->kvm_steal_time = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
 }
 
+static bool kvm_pv_tlb_flush_get(Object *obj, Error **errp)
+{
+    return LOONGARCH_CPU(obj)->kvm_pv_tlb_flush != ON_OFF_AUTO_OFF;
+}
+
+static void kvm_pv_tlb_flush_set(Object *obj, bool value, Error **errp)
+{
+    LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+    cpu->kvm_pv_tlb_flush = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+}
+
 void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
 {
     cpu->lbt = ON_OFF_AUTO_AUTO;
@@ -1291,6 +1323,12 @@ void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
                              kvm_steal_time_set);
     object_property_set_description(OBJECT(cpu), "kvm-steal-time",
                                     "Set off to disable KVM steal time.");
+
+    cpu->kvm_pv_tlb_flush = ON_OFF_AUTO_AUTO;
+    object_property_add_bool(OBJECT(cpu), "kvm-pv-tlb-flush",
+                             kvm_pv_tlb_flush_get, kvm_pv_tlb_flush_set);
+    object_property_set_description(OBJECT(cpu), "kvm-pv-tlb-flush",
+                                    "Set off to disable KVM PV TLB flush.");
 }
 
 int kvm_arch_destroy_vcpu(CPUState *cs)
diff --git a/target/loongarch/loongarch-qmp-cmds.c 
b/target/loongarch/loongarch-qmp-cmds.c
index f053f22bb8..5f372d85a9 100644
--- a/target/loongarch/loongarch-qmp-cmds.c
+++ b/target/loongarch/loongarch-qmp-cmds.c
@@ -41,8 +41,8 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 }
 
 static const char *cpu_model_advertised_features[] = {
-    "lsx", "lasx", "lbt", "pmu", "kvm-pv-ipi", "kvm-steal-time", "msgint",
-    "ptw", NULL
+    "lsx", "lasx", "lbt", "pmu", "kvm-pv-ipi", "kvm-steal-time",
+    "kvm-pv-tlb-flush", "msgint", "ptw", NULL
 };
 
 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType 
type,
-- 
2.43.0


Reply via email to