--- /dev/null
+From fc57ac2c9ca8109ea97fcc594f4be436944230cc Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini@redhat.com>
+Date: Wed, 14 May 2014 17:40:58 +0200
+Subject: KVM: lapic: sync highest ISR to hardware apic on EOI
+
+From: Paolo Bonzini <pbonzini@redhat.com>
+
+commit fc57ac2c9ca8109ea97fcc594f4be436944230cc upstream.
+
+When Hyper-V enlightenments are in effect, Windows prefers to issue an
+Hyper-V MSR write to issue an EOI rather than an x2apic MSR write.
+The Hyper-V MSR write is not handled by the processor, and besides
+being slower, this also causes bugs with APIC virtualization. The
+reason is that on EOI the processor will modify the highest in-service
+interrupt (SVI) field of the VMCS, as explained in section 29.1.4 of
+the SDM; every other step in EOI virtualization is already done by
+apic_send_eoi or on VM entry, but this one is missing.
+
+We need to do the same, and be careful not to muck with the isr_count
+and highest_isr_cache fields that are unused when virtual interrupt
+delivery is enabled.
+
+Reviewed-by: Yang Zhang <yang.z.zhang@intel.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kvm/lapic.c | 62 +++++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 43 insertions(+), 19 deletions(-)
+
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -370,6 +370,8 @@ static inline void apic_clear_irr(int ve
+
+ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
+ {
++ /* Note that we never get here with APIC virtualization enabled. */
++
+ if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR))
+ ++apic->isr_count;
+ BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
+@@ -381,12 +383,48 @@ static inline void apic_set_isr(int vec,
+ apic->highest_isr_cache = vec;
+ }
+
++static inline int apic_find_highest_isr(struct kvm_lapic *apic)
++{
++ int result;
++
++ /*
++ * Note that isr_count is always 1, and highest_isr_cache
++ * is always -1, with APIC virtualization enabled.
++ */
++ if (!apic->isr_count)
++ return -1;
++ if (likely(apic->highest_isr_cache != -1))
++ return apic->highest_isr_cache;
++
++ result = find_highest_vector(apic->regs + APIC_ISR);
++ ASSERT(result == -1 || result >= 16);
++
++ return result;
++}
++
+ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
+ {
+- if (__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR))
++ struct kvm_vcpu *vcpu;
++ if (!__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR))
++ return;
++
++ vcpu = apic->vcpu;
++
++ /*
++ * We do get here for APIC virtualization enabled if the guest
++ * uses the Hyper-V APIC enlightenment. In this case we may need
++ * to trigger a new interrupt delivery by writing the SVI field;
++ * on the other hand isr_count and highest_isr_cache are unused
++ * and must be left alone.
++ */
++ if (unlikely(kvm_apic_vid_enabled(vcpu->kvm)))
++ kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
++ apic_find_highest_isr(apic));
++ else {
+ --apic->isr_count;
+- BUG_ON(apic->isr_count < 0);
+- apic->highest_isr_cache = -1;
++ BUG_ON(apic->isr_count < 0);
++ apic->highest_isr_cache = -1;
++ }
+ }
+
+ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
+@@ -466,22 +504,6 @@ static void pv_eoi_clr_pending(struct kv
+ __clear_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention);
+ }
+
+-static inline int apic_find_highest_isr(struct kvm_lapic *apic)
+-{
+- int result;
+-
+- /* Note that isr_count is always 1 with vid enabled */
+- if (!apic->isr_count)
+- return -1;
+- if (likely(apic->highest_isr_cache != -1))
+- return apic->highest_isr_cache;
+-
+- result = find_highest_vector(apic->regs + APIC_ISR);
+- ASSERT(result == -1 || result >= 16);
+-
+- return result;
+-}
+-
+ void kvm_apic_update_tmr(struct kvm_vcpu *vcpu, u32 *tmr)
+ {
+ struct kvm_lapic *apic = vcpu->arch.apic;
+@@ -1619,6 +1641,8 @@ int kvm_get_apic_interrupt(struct kvm_vc
+ int vector = kvm_apic_has_interrupt(vcpu);
+ struct kvm_lapic *apic = vcpu->arch.apic;
+
++ /* Note that we never get here with APIC virtualization enabled. */
++
+ if (vector == -1)
+ return -1;
+