--- /dev/null
+From ecf08dad723d3e000aecff6c396f54772d124733 Mon Sep 17 00:00:00 2001
+From: Anthoine Bourgeois <anthoine.bourgeois@blade-group.com>
+Date: Sun, 29 Apr 2018 22:05:58 +0000
+Subject: KVM: x86: remove APIC Timer periodic/oneshot spikes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Anthoine Bourgeois <anthoine.bourgeois@blade-group.com>
+
+commit ecf08dad723d3e000aecff6c396f54772d124733 upstream.
+
+Since the commit "8003c9ae204e: add APIC Timer periodic/oneshot mode VMX
+preemption timer support", a Windows 10 guest has some erratic timer
+spikes.
+
+Here the results on a 150000 times 1ms timer without any load:
+ Before 8003c9ae204e | After 8003c9ae204e
+Max 1834us | 86000us
+Mean 1100us | 1021us
+Deviation 59us | 149us
+Here the results on a 150000 times 1ms timer with a cpu-z stress test:
+ Before 8003c9ae204e | After 8003c9ae204e
+Max 32000us | 140000us
+Mean 1006us | 1997us
+Deviation 140us | 11095us
+
+The root cause of the problem is starting hrtimer with an expiry time
+already in the past can take more than 20 milliseconds to trigger the
+timer function. It can be solved by forward such past timers
+immediately, rather than submitting them to hrtimer_start().
+In case the timer is periodic, update the target expiration and call
+hrtimer_start with it.
+
+v2: Check if the tsc deadline is already expired. Thank you Mika.
+v3: Execute the past timers immediately rather than submitting them to
+hrtimer_start().
+v4: Rearm the periodic timer with advance_periodic_target_expiration() a
+simpler version of set_target_expiration(). Thank you Paolo.
+
+Cc: Mika Penttilä <mika.penttila@nextfour.com>
+Cc: Wanpeng Li <kernellwp@gmail.com>
+Cc: Paolo Bonzini <pbonzini@redhat.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Anthoine Bourgeois <anthoine.bourgeois@blade-group.com>
+8003c9ae204e ("KVM: LAPIC: add APIC Timer periodic/oneshot mode VMX preemption timer support")
+Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ arch/x86/kvm/lapic.c | 37 ++++++++++++++++++++-----------------
+ 1 file changed, 20 insertions(+), 17 deletions(-)
+
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -1418,23 +1418,6 @@ static void start_sw_tscdeadline(struct
+ local_irq_restore(flags);
+ }
+
+-static void start_sw_period(struct kvm_lapic *apic)
+-{
+- if (!apic->lapic_timer.period)
+- return;
+-
+- if (apic_lvtt_oneshot(apic) &&
+- ktime_after(ktime_get(),
+- apic->lapic_timer.target_expiration)) {
+- apic_timer_expired(apic);
+- return;
+- }
+-
+- hrtimer_start(&apic->lapic_timer.timer,
+- apic->lapic_timer.target_expiration,
+- HRTIMER_MODE_ABS_PINNED);
+-}
+-
+ static bool set_target_expiration(struct kvm_lapic *apic)
+ {
+ ktime_t now;
+@@ -1491,6 +1474,26 @@ static void advance_periodic_target_expi
+ apic->lapic_timer.period);
+ }
+
++static void start_sw_period(struct kvm_lapic *apic)
++{
++ if (!apic->lapic_timer.period)
++ return;
++
++ if (ktime_after(ktime_get(),
++ apic->lapic_timer.target_expiration)) {
++ apic_timer_expired(apic);
++
++ if (apic_lvtt_oneshot(apic))
++ return;
++
++ advance_periodic_target_expiration(apic);
++ }
++
++ hrtimer_start(&apic->lapic_timer.timer,
++ apic->lapic_timer.target_expiration,
++ HRTIMER_MODE_ABS_PINNED);
++}
++
+ bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
+ {
+ if (!lapic_in_kernel(vcpu))