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@xxxxxxxxxxx> --- arch/loongarch/include/asm/kvm_host.h | 2 ++ arch/loongarch/kvm/main.c | 42 ++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h index 92ec3660d221..725d9c4e1965 100644 --- a/arch/loongarch/include/asm/kvm_host.h +++ b/arch/loongarch/include/asm/kvm_host.h @@ -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; }; diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c index afb2e10eba68..367653b49a35 100644 --- a/arch/loongarch/kvm/main.c +++ b/arch/loongarch/kvm/main.c @@ -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; } -- 2.39.3