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);
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