KVM: lapic: mark LAPIC timer handler as irqsafe

Since lapic timer handler only wakes up a simple waitqueue,
it can be executed from hardirq context.

Also handle the case where hrtimer_start_expires fails due to -ETIME,
by injecting the interrupt to the guest immediately.

Reduces average cyclictest latency by 3us.

Cc: stable-rt@vger.kernel.org
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
Marcelo Tosatti 2015-04-08 20:33:25 -03:00 committed by Alibek Omarov
parent 4ff6b67ad1
commit 74bfead8bc
1 changed files with 39 additions and 3 deletions

View File

@ -1031,8 +1031,38 @@ static void update_divide_count(struct kvm_lapic *apic)
apic->divide_count);
}
static enum hrtimer_restart apic_timer_fn(struct hrtimer *data);
static void apic_timer_expired(struct hrtimer *data)
{
int ret, i = 0;
enum hrtimer_restart r;
struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
r = apic_timer_fn(data);
if (r == HRTIMER_RESTART) {
do {
ret = hrtimer_start_expires(data, HRTIMER_MODE_ABS);
if (ret == -ETIME)
hrtimer_add_expires_ns(&ktimer->timer,
ktimer->period);
i++;
} while (ret == -ETIME && i < 10);
if (ret == -ETIME) {
printk_once(KERN_ERR "%s: failed to reprogram timer\n",
__func__);
WARN_ON_ONCE(1);
}
}
}
static void start_apic_timer(struct kvm_lapic *apic)
{
int ret;
ktime_t now;
atomic_set(&apic->lapic_timer.pending, 0);
@ -1062,9 +1092,11 @@ static void start_apic_timer(struct kvm_lapic *apic)
}
}
hrtimer_start(&apic->lapic_timer.timer,
ret = hrtimer_start(&apic->lapic_timer.timer,
ktime_add_ns(now, apic->lapic_timer.period),
HRTIMER_MODE_ABS);
if (ret == -ETIME)
apic_timer_expired(&apic->lapic_timer.timer);
apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
PRIx64 ", "
@ -1094,8 +1126,10 @@ static void start_apic_timer(struct kvm_lapic *apic)
ns = (tscdeadline - guest_tsc) * 1000000ULL;
do_div(ns, this_tsc_khz);
}
hrtimer_start(&apic->lapic_timer.timer,
ret = hrtimer_start(&apic->lapic_timer.timer,
ktime_add_ns(now, ns), HRTIMER_MODE_ABS);
if (ret == -ETIME)
apic_timer_expired(&apic->lapic_timer.timer);
local_irq_restore(flags);
}
@ -1581,6 +1615,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
apic->lapic_timer.timer.function = apic_timer_fn;
apic->lapic_timer.timer.irqsafe = 1;
/*
* APIC is created enabled. This will prevent kvm_lapic_set_base from
@ -1699,7 +1734,8 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
timer = &vcpu->arch.apic->lapic_timer.timer;
if (hrtimer_cancel(timer))
hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
if (hrtimer_start_expires(timer, HRTIMER_MODE_ABS) == -ETIME)
apic_timer_expired(timer);
}
/*