|
@@ -1501,24 +1501,38 @@ static void cancel_hv_timer(struct kvm_lapic *apic)
|
|
|
preempt_enable();
|
|
|
}
|
|
|
|
|
|
-static bool start_hv_timer(struct kvm_lapic *apic)
|
|
|
+static bool __start_hv_timer(struct kvm_lapic *apic)
|
|
|
{
|
|
|
- u64 tscdeadline = apic->lapic_timer.tscdeadline;
|
|
|
+ struct kvm_timer *ktimer = &apic->lapic_timer;
|
|
|
+ int r;
|
|
|
|
|
|
- if ((atomic_read(&apic->lapic_timer.pending) &&
|
|
|
- !apic_lvtt_period(apic)) ||
|
|
|
- kvm_x86_ops->set_hv_timer(apic->vcpu, tscdeadline)) {
|
|
|
- if (apic->lapic_timer.hv_timer_in_use)
|
|
|
- cancel_hv_timer(apic);
|
|
|
- } else {
|
|
|
- apic->lapic_timer.hv_timer_in_use = true;
|
|
|
- hrtimer_cancel(&apic->lapic_timer.timer);
|
|
|
+ if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ r = kvm_x86_ops->set_hv_timer(apic->vcpu, ktimer->tscdeadline);
|
|
|
+ if (r < 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ ktimer->hv_timer_in_use = true;
|
|
|
+ hrtimer_cancel(&ktimer->timer);
|
|
|
|
|
|
- /* In case the sw timer triggered in the window */
|
|
|
- if (atomic_read(&apic->lapic_timer.pending) &&
|
|
|
- !apic_lvtt_period(apic))
|
|
|
+ /*
|
|
|
+ * 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.
|
|
|
+ */
|
|
|
+ if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending))
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool start_hv_timer(struct kvm_lapic *apic)
|
|
|
+{
|
|
|
+ if (!__start_hv_timer(apic)) {
|
|
|
+ if (apic->lapic_timer.hv_timer_in_use)
|
|
|
cancel_hv_timer(apic);
|
|
|
}
|
|
|
+
|
|
|
trace_kvm_hv_timer_state(apic->vcpu->vcpu_id,
|
|
|
apic->lapic_timer.hv_timer_in_use);
|
|
|
return apic->lapic_timer.hv_timer_in_use;
|