KVM: x86: return bool from kvm_apic_match*()
[deliverable/linux.git] / arch / x86 / kvm / lapic.c
index 4f0c0b954686cbf5e980f761b5b9bd4f7bc2df9a..62f624656549f4169d35ba7a2cadccc81bed17d8 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/page.h>
 #include <asm/current.h>
 #include <asm/apicdef.h>
+#include <asm/delay.h>
 #include <linux/atomic.h>
 #include <linux/jump_label.h>
 #include "kvm_cache_regs.h"
@@ -402,7 +403,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
         * because the processor can modify ISR under the hood.  Instead
         * just set SVI.
         */
-       if (unlikely(kvm_apic_vid_enabled(vcpu->kvm)))
+       if (unlikely(kvm_x86_ops->hwapic_isr_update))
                kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec);
        else {
                ++apic->isr_count;
@@ -450,7 +451,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
         * 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)))
+       if (unlikely(kvm_x86_ops->hwapic_isr_update))
                kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
                                               apic_find_highest_isr(apic));
        else {
@@ -577,18 +578,18 @@ static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
        apic_update_ppr(apic);
 }
 
-static int kvm_apic_broadcast(struct kvm_lapic *apic, u32 dest)
+static bool kvm_apic_broadcast(struct kvm_lapic *apic, u32 dest)
 {
        return dest == (apic_x2apic_mode(apic) ?
                        X2APIC_BROADCAST : APIC_BROADCAST);
 }
 
-int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u32 dest)
+static bool kvm_apic_match_physical_addr(struct kvm_lapic *apic, u32 dest)
 {
        return kvm_apic_id(apic) == dest || kvm_apic_broadcast(apic, dest);
 }
 
-int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
+static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
 {
        int result = 0;
        u32 logical_id;
@@ -622,7 +623,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
        return result;
 }
 
-int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
                           int short_hand, unsigned int dest, int dest_mode)
 {
        int result = 0;
@@ -1073,25 +1074,72 @@ static void apic_timer_expired(struct kvm_lapic *apic)
 {
        struct kvm_vcpu *vcpu = apic->vcpu;
        wait_queue_head_t *q = &vcpu->wq;
+       struct kvm_timer *ktimer = &apic->lapic_timer;
 
-       /*
-        * Note: KVM_REQ_PENDING_TIMER is implicitly checked in
-        * vcpu_enter_guest.
-        */
        if (atomic_read(&apic->lapic_timer.pending))
                return;
 
        atomic_inc(&apic->lapic_timer.pending);
-       /* FIXME: this code should not know anything about vcpus */
-       kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+       kvm_set_pending_timer(vcpu);
 
        if (waitqueue_active(q))
                wake_up_interruptible(q);
+
+       if (apic_lvtt_tscdeadline(apic))
+               ktimer->expired_tscdeadline = ktimer->tscdeadline;
+}
+
+/*
+ * On APICv, this test will cause a busy wait
+ * during a higher-priority task.
+ */
+
+static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       u32 reg = kvm_apic_get_reg(apic, APIC_LVTT);
+
+       if (kvm_apic_hw_enabled(apic)) {
+               int vec = reg & APIC_VECTOR_MASK;
+
+               if (kvm_x86_ops->test_posted_interrupt)
+                       return kvm_x86_ops->test_posted_interrupt(vcpu, vec);
+               else {
+                       if (apic_test_vector(vec, apic->regs + APIC_ISR))
+                               return true;
+               }
+       }
+       return false;
+}
+
+void wait_lapic_expire(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       u64 guest_tsc, tsc_deadline;
+
+       if (!kvm_vcpu_has_lapic(vcpu))
+               return;
+
+       if (apic->lapic_timer.expired_tscdeadline == 0)
+               return;
+
+       if (!lapic_timer_int_injected(vcpu))
+               return;
+
+       tsc_deadline = apic->lapic_timer.expired_tscdeadline;
+       apic->lapic_timer.expired_tscdeadline = 0;
+       guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, native_read_tsc());
+       trace_kvm_wait_lapic_expire(vcpu->vcpu_id, guest_tsc - tsc_deadline);
+
+       /* __delay is delay_tsc whenever the hardware has TSC, thus always.  */
+       if (guest_tsc < tsc_deadline)
+               __delay(tsc_deadline - guest_tsc);
 }
 
 static void start_apic_timer(struct kvm_lapic *apic)
 {
        ktime_t now;
+
        atomic_set(&apic->lapic_timer.pending, 0);
 
        if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) {
@@ -1137,6 +1185,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
                /* lapic timer in tsc deadline mode */
                u64 guest_tsc, tscdeadline = apic->lapic_timer.tscdeadline;
                u64 ns = 0;
+               ktime_t expire;
                struct kvm_vcpu *vcpu = apic->vcpu;
                unsigned long this_tsc_khz = vcpu->arch.virtual_tsc_khz;
                unsigned long flags;
@@ -1151,8 +1200,10 @@ static void start_apic_timer(struct kvm_lapic *apic)
                if (likely(tscdeadline > guest_tsc)) {
                        ns = (tscdeadline - guest_tsc) * 1000000ULL;
                        do_div(ns, this_tsc_khz);
+                       expire = ktime_add_ns(now, ns);
+                       expire = ktime_sub_ns(expire, lapic_timer_advance_ns);
                        hrtimer_start(&apic->lapic_timer.timer,
-                               ktime_add_ns(now, ns), HRTIMER_MODE_ABS);
+                                     expire, HRTIMER_MODE_ABS);
                } else
                        apic_timer_expired(apic);
 
@@ -1742,7 +1793,9 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
        if (kvm_x86_ops->hwapic_irr_update)
                kvm_x86_ops->hwapic_irr_update(vcpu,
                                apic_find_highest_irr(apic));
-       kvm_x86_ops->hwapic_isr_update(vcpu->kvm, apic_find_highest_isr(apic));
+       if (unlikely(kvm_x86_ops->hwapic_isr_update))
+               kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
+                               apic_find_highest_isr(apic));
        kvm_make_request(KVM_REQ_EVENT, vcpu);
        kvm_rtc_eoi_tracking_restore_one(vcpu);
 }
This page took 0.027751 seconds and 5 git commands to generate.