diff options
Diffstat (limited to 'arch/x86/kvm/lapic.c')
| -rw-r--r-- | arch/x86/kvm/lapic.c | 42 | 
1 files changed, 25 insertions, 17 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index bd13fdddbdc4..a21c440ff356 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only  /*   * Local APIC virtualization @@ -13,9 +14,6 @@   *   Yaozu (Eddie) Dong <[email protected]>   *   * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. - * - * This work is licensed under the terms of the GNU GPL, version 2.  See - * the COPYING file in the top-level directory.   */  #include <linux/kvm_host.h> @@ -1454,7 +1452,7 @@ static void apic_timer_expired(struct kvm_lapic *apic)  	if (swait_active(q))  		swake_up_one(q); -	if (apic_lvtt_tscdeadline(apic)) +	if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)  		ktimer->expired_tscdeadline = ktimer->tscdeadline;  } @@ -1696,37 +1694,42 @@ static void cancel_hv_timer(struct kvm_lapic *apic)  static bool start_hv_timer(struct kvm_lapic *apic)  {  	struct kvm_timer *ktimer = &apic->lapic_timer; -	int r; +	struct kvm_vcpu *vcpu = apic->vcpu; +	bool expired;  	WARN_ON(preemptible());  	if (!kvm_x86_ops->set_hv_timer)  		return false; -	if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending)) -		return false; -  	if (!ktimer->tscdeadline)  		return false; -	r = kvm_x86_ops->set_hv_timer(apic->vcpu, ktimer->tscdeadline); -	if (r < 0) +	if (kvm_x86_ops->set_hv_timer(vcpu, ktimer->tscdeadline, &expired))  		return false;  	ktimer->hv_timer_in_use = true;  	hrtimer_cancel(&ktimer->timer);  	/* -	 * Also recheck ktimer->pending, in case the sw timer triggered in -	 * the window.  For periodic timer, leave the hv timer running for -	 * simplicity, and the deadline will be recomputed on the next vmexit. +	 * To simplify handling the periodic timer, leave the hv timer running +	 * even if the deadline timer has expired, i.e. rely on the resulting +	 * VM-Exit to recompute the periodic timer's target expiration.  	 */ -	if (!apic_lvtt_period(apic) && (r || atomic_read(&ktimer->pending))) { -		if (r) +	if (!apic_lvtt_period(apic)) { +		/* +		 * Cancel the hv timer if the sw timer fired while the hv timer +		 * was being programmed, or if the hv timer itself expired. +		 */ +		if (atomic_read(&ktimer->pending)) { +			cancel_hv_timer(apic); +		} else if (expired) {  			apic_timer_expired(apic); -		return false; +			cancel_hv_timer(apic); +		}  	} -	trace_kvm_hv_timer_state(apic->vcpu->vcpu_id, true); +	trace_kvm_hv_timer_state(vcpu->vcpu_id, ktimer->hv_timer_in_use); +  	return true;  } @@ -1750,8 +1753,13 @@ static void start_sw_timer(struct kvm_lapic *apic)  static void restart_apic_timer(struct kvm_lapic *apic)  {  	preempt_disable(); + +	if (!apic_lvtt_period(apic) && atomic_read(&apic->lapic_timer.pending)) +		goto out; +  	if (!start_hv_timer(apic))  		start_sw_timer(apic); +out:  	preempt_enable();  }  |