Use preemption timer to handle host timer Signed-off-by: Zhimin Feng <fengzhimin@xxxxxxxxxxxxx> --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx/vmx.c | 54 +++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 1 + 3 files changed, 56 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index eb6a611963b7..82a51f0d01a2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -826,6 +826,7 @@ struct kvm_vcpu_arch { } pv_cpuid; bool timer_passth_enable; + u64 tscd; }; struct kvm_lpage_info { diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 38b8d80fa157..0bf9941df842 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -5629,6 +5629,13 @@ static fastpath_t handle_fastpath_preemption_timer(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); + if (vcpu->arch.timer_passth_enable) { + local_irq_disable(); + apic->send_IPI_mask(get_cpu_mask(vcpu->cpu), LOCAL_TIMER_VECTOR); + local_irq_enable(); + + return EXIT_FASTPATH_NONE; + } if (!vmx->req_immediate_exit && !unlikely(vmx->loaded_vmcs->hv_timer_soft_disabled)) { kvm_lapic_expired_hv_timer(vcpu); @@ -6640,6 +6647,51 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu) bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs, bool launched); +static void vmx_host_lapic_timer_offload(struct kvm_vcpu *vcpu) +{ + struct timer_passth_info *local_timer_info; + u64 tscl; + u64 guest_tscl; + u64 delta_tsc; + struct hrtimer *timer; + + if (!vcpu->arch.timer_passth_enable) + return; + + local_timer_info = &per_cpu(passth_info, smp_processor_id()); + + tscl = rdtsc(); + guest_tscl = kvm_read_l1_tsc(vcpu, tscl); + + timer = &vcpu->arch.apic->lapic_timer.timer; + if (hrtimer_active(timer)) + hrtimer_cancel(timer); + + if (local_timer_info->host_tscd > tscl) { + delta_tsc = (u32)((local_timer_info->host_tscd - tscl) >> + cpu_preemption_timer_multi); + vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, delta_tsc); + vmcs_set_bits(PIN_BASED_VM_EXEC_CONTROL, + PIN_BASED_VMX_PREEMPTION_TIMER); + } else { + vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL, + PIN_BASED_VMX_PREEMPTION_TIMER); + } + + wrmsrl(MSR_IA32_TSCDEADLINE, 0); + if (vcpu->arch.tscd > guest_tscl) { + wrmsrl(MSR_IA32_TSCDEADLINE, vcpu->arch.tscd); + } else { + if (vcpu->arch.tscd > 0) { + if (!atomic_read(&vcpu->arch.apic->lapic_timer.pending)) { + atomic_inc(&vcpu->arch.apic->lapic_timer.pending); + kvm_inject_pending_timer_irqs(vcpu); + kvm_x86_ops.sync_pir_to_irr(vcpu); + } + } + } +} + static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx) { @@ -6761,6 +6813,8 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu) kvm_wait_lapic_expire(vcpu); + vmx_host_lapic_timer_offload(vcpu); + /* * If this vCPU has touched SPEC_CTRL, restore the guest's value if * it's non-zero. Since vmentry is serialising on affected CPUs, there diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5d353a9c9881..e51fd52a4862 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9912,6 +9912,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.pending_external_vector = -1; vcpu->arch.preempted_in_kernel = false; vcpu->arch.timer_passth_enable = false; + vcpu->arch.tscd = 0; kvm_hv_vcpu_init(vcpu); -- 2.11.0