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:
parent
4ff6b67ad1
commit
74bfead8bc
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue