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 [email protected] https://lists.sourceforge.net/lists/listinfo/kvm-devel
