KVM: x86: Do not change ICR on write to APIC_SELF_IPI
[linux-2.6-microblaze.git] / arch / x86 / kvm / lapic.c
index d7e6fde..d5a33b6 100644 (file)
@@ -113,7 +113,8 @@ static inline u32 kvm_x2apic_id(struct kvm_lapic *apic)
 
 static bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu)
 {
-       return pi_inject_timer && kvm_vcpu_apicv_active(vcpu);
+       return pi_inject_timer && kvm_vcpu_apicv_active(vcpu) &&
+               (kvm_mwait_in_guest(vcpu->kvm) || kvm_hlt_in_guest(vcpu->kvm));
 }
 
 bool kvm_can_use_hv_timer(struct kvm_vcpu *vcpu)
@@ -491,8 +492,7 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
        if (unlikely(vcpu->arch.apicv_active)) {
                /* need to update RVI */
                kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR);
-               static_call(kvm_x86_hwapic_irr_update)(vcpu,
-                               apic_find_highest_irr(apic));
+               static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, apic_find_highest_irr(apic));
        } else {
                apic->irr_pending = false;
                kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR);
@@ -522,7 +522,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
         * just set SVI.
         */
        if (unlikely(vcpu->arch.apicv_active))
-               static_call(kvm_x86_hwapic_isr_update)(vcpu, vec);
+               static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, vec);
        else {
                ++apic->isr_count;
                BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
@@ -570,8 +570,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
         * and must be left alone.
         */
        if (unlikely(vcpu->arch.apicv_active))
-               static_call(kvm_x86_hwapic_isr_update)(vcpu,
-                                               apic_find_highest_isr(apic));
+               static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, apic_find_highest_isr(apic));
        else {
                --apic->isr_count;
                BUG_ON(apic->isr_count < 0);
@@ -2121,10 +2120,9 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
                break;
 
        case APIC_SELF_IPI:
-               if (apic_x2apic_mode(apic)) {
-                       kvm_lapic_reg_write(apic, APIC_ICR,
-                                           APIC_DEST_SELF | (val & APIC_VECTOR_MASK));
-               } else
+               if (apic_x2apic_mode(apic))
+                       kvm_apic_send_ipi(apic, APIC_DEST_SELF | (val & APIC_VECTOR_MASK), 0);
+               else
                        ret = 1;
                break;
        default:
@@ -2242,10 +2240,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data)
 
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
-
-       apic_set_tpr(apic, ((cr8 & 0x0f) << 4)
-                    | (kvm_lapic_get_reg(apic, APIC_TASKPRI) & 4));
+       apic_set_tpr(vcpu->arch.apic, (cr8 & 0x0f) << 4);
 }
 
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
@@ -2287,7 +2282,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
                kvm_apic_set_x2apic_id(apic, vcpu->vcpu_id);
 
        if ((old_value ^ value) & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE))
-               static_call(kvm_x86_set_virtual_apic_mode)(vcpu);
+               static_call_cond(kvm_x86_set_virtual_apic_mode)(vcpu);
 
        apic->base_address = apic->vcpu->arch.apic_base &
                             MSR_IA32_APICBASE_BASE;
@@ -2306,7 +2301,12 @@ void kvm_apic_update_apicv(struct kvm_vcpu *vcpu)
                apic->irr_pending = true;
                apic->isr_count = 1;
        } else {
-               apic->irr_pending = (apic_search_irr(apic) != -1);
+               /*
+                * Don't clear irr_pending, searching the IRR can race with
+                * updates from the CPU as APICv is still active from hardware's
+                * perspective.  The flag will be cleared as appropriate when
+                * KVM injects the interrupt.
+                */
                apic->isr_count = count_vectors(apic->regs + APIC_ISR);
        }
 }
@@ -2368,9 +2368,9 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
        vcpu->arch.pv_eoi.msr_val = 0;
        apic_update_ppr(apic);
        if (vcpu->arch.apicv_active) {
-               static_call(kvm_x86_apicv_post_state_restore)(vcpu);
-               static_call(kvm_x86_hwapic_irr_update)(vcpu, -1);
-               static_call(kvm_x86_hwapic_isr_update)(vcpu, -1);
+               static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu);
+               static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, -1);
+               static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, -1);
        }
 
        vcpu->arch.apic_arb_prio = 0;
@@ -2633,11 +2633,9 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
        kvm_apic_update_apicv(vcpu);
        apic->highest_isr_cache = -1;
        if (vcpu->arch.apicv_active) {
-               static_call(kvm_x86_apicv_post_state_restore)(vcpu);
-               static_call(kvm_x86_hwapic_irr_update)(vcpu,
-                               apic_find_highest_irr(apic));
-               static_call(kvm_x86_hwapic_isr_update)(vcpu,
-                               apic_find_highest_isr(apic));
+               static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu);
+               static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, apic_find_highest_irr(apic));
+               static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, apic_find_highest_isr(apic));
        }
        kvm_make_request(KVM_REQ_EVENT, vcpu);
        if (ioapic_in_kernel(vcpu->kvm))
@@ -2928,7 +2926,7 @@ int kvm_apic_accept_events(struct kvm_vcpu *vcpu)
                        /* evaluate pending_events before reading the vector */
                        smp_rmb();
                        sipi_vector = apic->sipi_vector;
-                       kvm_x86_ops.vcpu_deliver_sipi_vector(vcpu, sipi_vector);
+                       static_call(kvm_x86_vcpu_deliver_sipi_vector)(vcpu, sipi_vector);
                        vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
                }
        }