Add back pending irqs for apic timer to get precise guest
    APIC timer interrupt.
    
    Signed-off-by: Yaozu (Eddie) Dong <[EMAIL PROTECTED]>


diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
index ed6d20a..8867c82 100644
--- a/drivers/kvm/irq.h
+++ b/drivers/kvm/irq.h
@@ -110,7 +110,7 @@ struct kvm_lapic {
        unsigned long base_address;
        struct kvm_io_device dev;
        struct {
-               unsigned long pending;
+               atomic_t pending;
                s64 period;     /* unit: ns */
                u32 divide_count;
                ktime_t last_update;
@@ -153,5 +153,7 @@ int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec,
u8 trig);
 void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
 int kvm_ioapic_init(struct kvm *kvm);
 void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
+void kvm_pt_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_pt_update_irq(struct kvm_vcpu *vcpu);
 
 #endif
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
index 352b8a7..cb4d3ca 100644
--- a/drivers/kvm/lapic.c
+++ b/drivers/kvm/lapic.c
@@ -30,6 +30,7 @@
 #include <asm/page.h>
 #include <asm/current.h>
 #include <asm/apicdef.h>
+#include <asm/atomic.h>
 #include "irq.h"
 
 #define PRId64 "d"
@@ -300,6 +301,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic,
int delivery_mode,
                             int vector, int level, int trig_mode)
 {
        int result = 0;
+       int orig_irr;
 
        switch (delivery_mode) {
        case APIC_DM_FIXED:
@@ -308,7 +310,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic,
int delivery_mode,
                if (unlikely(!apic_enabled(apic)))
                        break;
 
-               if (apic_test_and_set_irr(vector, apic) && trig_mode) {
+               orig_irr = apic_test_and_set_irr(vector, apic);
+               if (orig_irr && trig_mode) {
                        apic_debug("level trig mode repeatedly for
vector %d",
                                   vector);
                        break;
@@ -322,7 +325,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic,
int delivery_mode,
 
                kvm_vcpu_kick(apic->vcpu);
 
-               result = 1;
+               result = (orig_irr == 0);
                break;
 
        case APIC_DM_REMRD:
@@ -352,18 +355,6 @@ static int __apic_accept_irq(struct kvm_lapic
*apic, int delivery_mode,
        return result;
 }
 
-static inline int apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,
-                                 int vector, int level, int trig_mode)
-{
-       int result = 0;
-
-       spin_lock_bh(&apic->lock);
-       result = __apic_accept_irq(apic, delivery_mode,
-                                  vector, level, trig_mode);
-       spin_unlock_bh(&apic->lock);
-       return result;
-}
-
 struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
                                       unsigned long bitmap)
 {
@@ -595,6 +586,7 @@ static void apic_mmio_write(struct kvm_io_device
*this,
                                apic_set_reg(apic, APIC_LVTT + 0x10 * i,
                                             lvt_val | APIC_LVT_MASKED);
                        }
+                       atomic_set(&apic->timer.pending, 0);
 
                }
                break;
@@ -632,12 +624,14 @@ static void apic_mmio_write(struct kvm_io_device
*this,
                        apic->timer.last_update = now;
                        apic->timer.period =
                            APIC_BUS_CYCLE_NS * apic->timer.divide_count
* val;
+                       apic_debug("LAPIC period = %lld\n",
apic->timer.period);
 
                        /* Make sure the lock ordering is coherent */
                        spin_unlock_bh(&apic->lock);
                        hrtimer_cancel(&apic->timer.dev);
+                       atomic_set(&apic->timer.pending, 0);
                        hrtimer_start(&apic->timer.dev,
-                                     ktime_add_ns(now, offset),
+                                     ktime_add_ns(now,
apic->timer.period),
                                      HRTIMER_MODE_ABS);
 
                        apic_debug("%s: bus cycle is %" PRId64 "ns, now
0x%016"
@@ -816,7 +810,7 @@ static void lapic_reset(struct kvm_vcpu *vcpu)
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
        apic->timer.divide_count = 0;
-       apic->timer.pending = 0;
+       atomic_set(&apic->timer.pending, 0);
        if (vcpu->vcpu_id == 0)
                vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
        apic_update_ppr(apic);
@@ -857,38 +851,30 @@ EXPORT_SYMBOL_GPL(kvm_lapic_get_regs);
  * timer interface
 
*----------------------------------------------------------------------
  */
+
+/* TODO: make sure __apic_timer_fn runs in current pCPU */
 static int __apic_timer_fn(struct kvm_lapic *apic)
 {
-       u32 vector;
        int result = 0;
 
-       if (unlikely(!apic_enabled(apic) ||
-                    !apic_lvt_enabled(apic, APIC_LVTT))) {
-               apic_debug("%s: time interrupt although apic is down\n",
-                          __FUNCTION__);
-               return 0;
-       }
-
-       vector = apic_lvt_vector(apic, APIC_LVTT);
-       apic->timer.last_update = apic->timer.dev.expires;
-       apic->timer.pending++;
-       __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
-
+       atomic_inc (&apic->timer.pending);
        if (apic_lvtt_period(apic)) {
-               u32 offset;
-               u32 tmict = apic_get_reg(apic, APIC_TMICT);
-
-               offset = APIC_BUS_CYCLE_NS * apic->timer.divide_count *
tmict;
-
                result = 1;
                apic->timer.dev.expires = ktime_add_ns(
                                        apic->timer.dev.expires,
                                        apic->timer.period);
        }
-
        return result;
 }
 
+static int inject_apic_timer_irq(struct kvm_lapic *apic)
+{
+       int vector;
+
+       vector = apic_lvt_vector(apic, APIC_LVTT);
+       return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
+}
+
 static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
 {
        struct kvm_lapic *apic;
@@ -963,6 +949,28 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
        return highest_irr;
 }
 
+void kvm_pt_update_irq(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+
+       if (apic && atomic_read(&apic->timer.pending) > 0) {
+               if (inject_apic_timer_irq(apic))
+                       atomic_dec(&apic->timer.pending);
+       }
+}
+EXPORT_SYMBOL_GPL(kvm_pt_update_irq);
+
+void kvm_pt_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+
+       if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
+               apic->timer.last_update = ktime_add_ns(
+                               apic->timer.last_update,
+                               apic->timer.period);
+}
+EXPORT_SYMBOL_GPL(kvm_pt_intr_post);
+
 int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
 {
        int vector = kvm_apic_has_interrupt(vcpu);
@@ -992,7 +1000,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu
*vcpu)
        /* TODO: following code can be in a common API */
        spin_lock_bh(&apic->lock);
        hrtimer_cancel(&apic->timer.dev);
-       apic->timer.pending = 0;
+       atomic_set(&apic->timer.pending, 0);
        val = apic_get_reg(apic, APIC_TDCR);
        tmp = ((val & 0x3) | ((val & 0x8) >> 1)) + 1;
        apic->timer.divide_count = 0x1 << (tmp & 0x7);
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 96db35a..5e45e12 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -1462,6 +1462,7 @@ static void svm_intr_assist(struct vcpu_svm *svm)
        struct vmcb *vmcb = svm->vmcb;
        int intr_vector = -1;
 
+       kvm_pt_update_irq(vcpu);
        if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
            ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0))
{
                intr_vector = vmcb->control.exit_int_info &
@@ -1488,6 +1489,7 @@ static void svm_intr_assist(struct vcpu_svm *svm)
        /* Okay, we can deliver the interrupt: grab it and update PIC
state. */
        intr_vector = kvm_cpu_get_interrupt(&svm->vcpu);
        svm_inject_irq(svm, intr_vector);
+       kvm_pt_intr_post(vcpu, vector);
 }
 
 static void kvm_reput_irq(struct vcpu_svm *svm)
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 019197b..499bb45 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -2144,7 +2144,9 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
 {
        u32 idtv_info_field, intr_info_field;
        int has_ext_irq, interrupt_window_open;
+       int vector;
 
+       kvm_pt_update_irq(vcpu);
        has_ext_irq = kvm_cpu_has_interrupt(vcpu);
        intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
        idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
@@ -2174,9 +2176,11 @@ static void vmx_intr_assist(struct kvm_vcpu
*vcpu)
        interrupt_window_open =
                ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
                 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
-       if (interrupt_window_open)
-               vmx_inject_irq(vcpu, kvm_cpu_get_interrupt(vcpu));
-       else
+       if (interrupt_window_open) {
+               vector = kvm_cpu_get_interrupt(vcpu);
+               vmx_inject_irq(vcpu, vector);
+               kvm_pt_intr_post(vcpu, vector);
+       } else
                enable_irq_window(vcpu);
 }
 

Attachment: apic-timer-pending.patch
Description: apic-timer-pending.patch

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to