kvm_arch_vcpu_load/put() will be called every time when KVM process switch out/in. But some work have not to do on every time when this happen. Such as E500 TLB load/put, host won't override guest TLB1 entries and TLB0 has a large size. so that the work only need to be done on every KVM vcpu switch. Not sure it's worth doing the same thing for 44x TLB load/put. As 44x host share only 64 entries with guest, host kvm process switch in without loading valid guest TLB entries might hurt the performance. Only test it on non-SMP environment. Any comments? Signed-off-by: Liu Yu <yu.liu@xxxxxxxxxxxxx> --- arch/powerpc/include/asm/kvm_ppc.h | 1 + arch/powerpc/kvm/44x.c | 4 ++++ arch/powerpc/kvm/e500.c | 7 +++++-- arch/powerpc/kvm/e500_tlb.c | 9 +++------ arch/powerpc/kvm/e500_tlb.h | 3 +-- arch/powerpc/kvm/powerpc.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 82547c8..ac155a0 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -76,6 +76,7 @@ extern int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu, extern void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu); extern void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu); +extern void kvmppc_core_vcpu_refresh(struct kvm_vcpu *vcpu, int cpu); extern void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu); extern void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu); diff --git a/arch/powerpc/kvm/44x.c b/arch/powerpc/kvm/44x.c index 8383603..47a3e11 100644 --- a/arch/powerpc/kvm/44x.c +++ b/arch/powerpc/kvm/44x.c @@ -104,6 +104,10 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) kvmppc_44x_tlb_put(vcpu); } +void kvmppc_core_vcpu_refresh(struct kvm_vcpu *vcpu, int cpu) +{ +} + int kvmppc_core_check_processor_compat(void) { int r; diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index d8067fd..7a50bbd 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -34,12 +34,15 @@ void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { - kvmppc_e500_tlb_load(vcpu, cpu); } void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) { - kvmppc_e500_tlb_put(vcpu); +} + +void kvmppc_core_vcpu_refresh(struct kvm_vcpu *vcpu, int cpu) +{ + kvmppc_e500_tlb_refresh(vcpu, cpu); } int kvmppc_core_check_processor_compat(void) diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index 30ce5c7..d4fbddd 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c @@ -134,12 +134,14 @@ static inline void write_host_tlbe(struct kvmppc_vcpu_e500 *vcpu_e500, local_irq_enable(); } -void kvmppc_e500_tlb_load(struct kvm_vcpu *vcpu, int cpu) +void kvmppc_e500_tlb_refresh(struct kvm_vcpu *vcpu, int cpu) { struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); int i; unsigned register mas0; + _tlbia(); + /* Load all valid TLB1 entries to reduce guest tlb miss fault */ local_irq_disable(); mas0 = mfspr(SPRN_MAS0); @@ -156,11 +158,6 @@ void kvmppc_e500_tlb_load(struct kvm_vcpu *vcpu, int cpu) local_irq_enable(); } -void kvmppc_e500_tlb_put(struct kvm_vcpu *vcpu) -{ - _tlbia(); -} - /* Search the guest TLB for a matching entry. */ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500, gva_t eaddr, int tlbsel, unsigned int pid, int as) diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h index ab49e93..a1c6c35 100644 --- a/arch/powerpc/kvm/e500_tlb.h +++ b/arch/powerpc/kvm/e500_tlb.h @@ -49,8 +49,7 @@ extern int kvmppc_e500_emul_tlbre(struct kvm_vcpu *); extern int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *, int, int); extern int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *, int); extern int kvmppc_e500_tlb_search(struct kvm_vcpu *, gva_t, unsigned int, int); -extern void kvmppc_e500_tlb_put(struct kvm_vcpu *); -extern void kvmppc_e500_tlb_load(struct kvm_vcpu *, int); +extern void kvmppc_e500_tlb_refresh(struct kvm_vcpu *, int); extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *); extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *); extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *); diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index fd84d9c..9707e7c 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -30,6 +30,9 @@ #include <asm/tlbflush.h> #include "timing.h" +static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu) = NULL; +static spinlock_t refresh_lock = SPIN_LOCK_UNLOCKED; + gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) { return gfn; @@ -214,15 +217,42 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) { + unsigned long flags; + kvmppc_mmu_destroy(vcpu); + + spin_lock_irqsave(&refresh_lock, flags); + __get_cpu_var(last_vcpu) = NULL; + spin_unlock_irqrestore(&refresh_lock, flags); } void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { + int need_refresh = 0; + unsigned long flags; + if (vcpu->guest_debug.enabled) kvmppc_core_load_guest_debugstate(vcpu); kvmppc_core_vcpu_load(vcpu, cpu); + + /* Only need to refresh work when switch vcpu */ + spin_lock_irqsave(&refresh_lock, flags); + if (__get_cpu_var(last_vcpu) != vcpu) { + int i; + + need_refresh = 1; + for_each_possible_cpu(i) { + if (i == cpu) + per_cpu(last_vcpu, i) = vcpu; + else if (per_cpu(last_vcpu, i) == vcpu) + per_cpu(last_vcpu, i) = NULL; + } + } + spin_unlock_irqrestore(&refresh_lock, flags); + + if (need_refresh) + kvmppc_core_vcpu_refresh(vcpu, cpu); } void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) -- 1.5.4 -- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html