When local apic timer is inactive or is expired in oneshot mode, it
    should not be restarted in save/restore or hrtimer migration. This
    patch fixes this.

    Signed-off-by: Eddie (Yaozu) Dong <[EMAIL PROTECTED]>
    Signed-off-by: Qing He <[EMAIL PROTECTED]>


---
 drivers/kvm/irq.h      |    2 ++
 drivers/kvm/kvm_main.c |    1 +
 drivers/kvm/lapic.c    |   41 +++++++++++++++++++++++++++++++++++------
 3 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
index 5f97e25..68d454c 100644
--- a/drivers/kvm/irq.h
+++ b/drivers/kvm/irq.h
@@ -110,6 +110,7 @@ struct kvm_lapic {
        struct kvm_io_device dev;
        struct {
                atomic_t pending;
+               atomic_t active;
                s64 period;     /* unit: ns */
                u32 divide_count;
                ktime_t last_update;
@@ -150,6 +151,7 @@ int kvm_apic_match_physical_addr(struct kvm_lapic
*apic, u16 dest);
 void kvm_ioapic_update_eoi(struct kvm *kvm, int vector);
 int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
 int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig);
+void kvm_apic_pre_state_save(struct kvm_vcpu *vcpu);
 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);
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index f101430..694fe1e 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -2679,6 +2679,7 @@ static int kvm_vcpu_ioctl_get_lapic(struct
kvm_vcpu *vcpu,
                                    struct kvm_lapic_state *s)
 {
        vcpu_load(vcpu);
+       kvm_apic_pre_state_save(vcpu);
        memcpy(s->regs, vcpu->apic->regs, sizeof *s);
        vcpu_put(vcpu);
 
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
index 57810fa..ae85eb0 100644
--- a/drivers/kvm/lapic.c
+++ b/drivers/kvm/lapic.c
@@ -603,6 +603,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
        apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
                    APIC_BUS_CYCLE_NS * apic->timer.divide_count;
        atomic_set(&apic->timer.pending, 0);
+       atomic_set(&apic->timer.active, 1);
        hrtimer_start(&apic->timer.dev,
                      ktime_add_ns(now, apic->timer.period),
                      HRTIMER_MODE_ABS);
@@ -750,6 +751,7 @@ void kvm_free_apic(struct kvm_lapic *apic)
        if (!apic)
                return;
 
+       atomic_set(&apic->timer.active, 0);
        hrtimer_cancel(&apic->timer.dev);
 
        if (apic->regs_page) {
@@ -828,6 +830,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
        ASSERT(apic != NULL);
 
        /* Stop the timer in case it's a reset to an active apic */
+       atomic_set(&apic->timer.active, 0);
        hrtimer_cancel(&apic->timer.dev);
 
        apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
@@ -900,6 +903,9 @@ static int __apic_timer_fn(struct kvm_lapic *apic)
                                        apic->timer.dev.expires,
                                        apic->timer.period);
        }
+       else
+               atomic_set(&apic->timer.active, 0);
+               
        return result;
 }
 
@@ -1018,9 +1024,23 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
        return vector;
 }
 
+void kvm_apic_pre_state_save(struct kvm_vcpu *vcpu)
+{
+       struct kvm_lapic *apic = vcpu->apic;
+       u32 tmict;
+
+       tmict = apic_get_reg(apic, APIC_TMICT);
+
+       if (atomic_read(&apic->timer.active))
+               apic_set_reg(apic, APIC_TMCCT, tmict);
+       else
+               apic_set_reg(apic, APIC_TMCCT, 0);
+}
+
 void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->apic;
+       u32 tmcct;
 
        apic->base_address = vcpu->apic_base &
                             MSR_IA32_APICBASE_BASE;
@@ -1028,7 +1048,13 @@ void kvm_apic_post_state_restore(struct kvm_vcpu
*vcpu)
        apic_update_ppr(apic);
        hrtimer_cancel(&apic->timer.dev);
        update_divide_count(apic);
-       start_apic_timer(apic);
+       tmcct = apic_get_reg(apic, APIC_TMCCT);
+       if (tmcct) {
+               atomic_set(&apic->timer.active, 1);
+               start_apic_timer(apic);
+       }
+       else
+               atomic_set(&apic->timer.active, 0);
 }
 
 void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
@@ -1036,11 +1062,14 @@ void kvm_migrate_apic_timer(struct kvm_vcpu
*vcpu)
        struct kvm_lapic *apic = vcpu->apic;
        struct hrtimer *timer;
 
-       if (apic) {
-               timer = &apic->timer.dev;
-               hrtimer_cancel(timer);
-               hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS);
-       }
+       if (!apic)
+               return;
+
+       timer = &apic->timer.dev;
+       hrtimer_cancel(timer);
+       if (atomic_read(&apic->timer.active))
+               hrtimer_start(timer, timer->expires,
+                             HRTIMER_MODE_ABS);
 }
 EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer);
 

Attachment: 02-kvm-inactive-apic-timer-sr.patch
Description: 02-kvm-inactive-apic-timer-sr.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