[RFC: timer passthrough 2/9] KVM: vmx: enable host lapic timer offload preemtion timer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux