@@ -64,6 +64,7 @@ struct kvm_arch_memory_slot {
#define HOST_MAX_PMNUM 16
struct kvm_context {
unsigned long vpid_cache;
+ unsigned long vmid_cache;
struct kvm_vcpu *last_vcpu;
/* Host PMU CSR */
u64 perf_ctrl[HOST_MAX_PMNUM];
@@ -116,6 +117,7 @@ struct kvm_arch {
unsigned long pv_features;
s64 time_offset;
+ unsigned long vmid[NR_CPUS];
struct kvm_context __percpu *vmcs;
};
@@ -252,9 +252,33 @@ static void __kvm_check_vpid(struct kvm_vcpu *vcpu)
change_csr_gstat(vpid_mask << CSR_GSTAT_GID_SHIFT, vpid);
}
-static void __kvm_check_vmid(struct kvm_vcpu *vcpu)
+static void kvm_update_vmid(struct kvm_vcpu *vcpu, int cpu)
{
unsigned long vmid;
+ struct kvm_context *context;
+
+ context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+ vmid = context->vmid_cache + 1;
+ if (!(vmid & vpid_mask)) {
+ /* finish round of vmid loop */
+ if (unlikely(!vmid))
+ vmid = vpid_mask + 1;
+
+ ++vmid; /* vmid 0 reserved for root */
+
+ /* start new vmid cycle */
+ kvm_flush_tlb_all_stage2();
+ }
+
+ context->vmid_cache = vmid;
+ vcpu->kvm->arch.vmid[cpu] = vmid;
+}
+
+static void __kvm_check_vmid(struct kvm_vcpu *vcpu)
+{
+ int cpu;
+ unsigned long ver, old, vmid;
+ struct kvm_context *context;
/* On some machines like 3A5000, vmid needs the same with vpid */
if (!cpu_has_guestid) {
@@ -265,6 +289,21 @@ static void __kvm_check_vmid(struct kvm_vcpu *vcpu)
}
return;
}
+
+ cpu = smp_processor_id();
+ context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
+
+ /*
+ * Check if our vmid is of an older version
+ */
+ ver = vcpu->kvm->arch.vmid[cpu] & ~vpid_mask;
+ old = context->vmid_cache & ~vpid_mask;
+ if (ver != old) {
+ kvm_update_vmid(vcpu, cpu);
+ kvm_clear_request(KVM_REQ_TLB_FLUSH_GPA, vcpu);
+ }
+
+ vcpu->arch.vmid = vcpu->kvm->arch.vmid[cpu] & vpid_mask;
}
void kvm_check_vpid(struct kvm_vcpu *vcpu)
@@ -386,6 +425,7 @@ static int kvm_loongarch_env_init(void)
for_each_possible_cpu(cpu) {
context = per_cpu_ptr(vmcs, cpu);
context->vpid_cache = vpid_mask + 1;
+ context->vmid_cache = vpid_mask + 1;
context->last_vcpu = NULL;
}
For every physical CPU, there is one vmid calculation method. For vCPUs on the same VM, vmid is the same. However for vCPUs on different VM, vmid is different. When vCPU is scheduled on the physical CPU, it checked vmid of this VM and the global cached vmid, and judge whether it is valid or not. Signed-off-by: Bibo Mao <maobibo@loongson.cn> --- arch/loongarch/include/asm/kvm_host.h | 2 ++ arch/loongarch/kvm/main.c | 42 ++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-)