103 lines
3.2 KiB
Diff
103 lines
3.2 KiB
Diff
From d24c954fa7a252b093fa8ba9ed12c00bc3829bbe Mon Sep 17 00:00:00 2001
|
|
From: Marcelo Tosatti <mtosatti@redhat.com>
|
|
Date: Wed, 8 Apr 2015 20:33:25 -0300
|
|
Subject: [PATCH 2/2] KVM: lapic: mark LAPIC timer handler as irqsafe
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.0/patches-4.0.5-rt3.tar.xz
|
|
|
|
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.
|
|
|
|
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
arch/x86/kvm/lapic.c | 40 +++++++++++++++++++++++++++++++++++++---
|
|
1 file changed, 37 insertions(+), 3 deletions(-)
|
|
|
|
--- a/arch/x86/kvm/lapic.c
|
|
+++ b/arch/x86/kvm/lapic.c
|
|
@@ -1130,8 +1130,36 @@ void wait_lapic_expire(struct kvm_vcpu *
|
|
__delay(tsc_deadline - guest_tsc);
|
|
}
|
|
|
|
+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);
|
|
@@ -1162,9 +1190,11 @@ static void start_apic_timer(struct kvm_
|
|
}
|
|
}
|
|
|
|
- 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 ", "
|
|
@@ -1196,8 +1226,10 @@ static void start_apic_timer(struct kvm_
|
|
do_div(ns, this_tsc_khz);
|
|
expire = ktime_add_ns(now, ns);
|
|
expire = ktime_sub_ns(expire, lapic_timer_advance_ns);
|
|
- hrtimer_start(&apic->lapic_timer.timer,
|
|
+ ret = hrtimer_start(&apic->lapic_timer.timer,
|
|
expire, HRTIMER_MODE_ABS);
|
|
+ if (ret == -ETIME)
|
|
+ __apic_timer_expired(&apic->lapic_timer.timer);
|
|
} else
|
|
apic_timer_expired(apic);
|
|
|
|
@@ -1678,6 +1710,7 @@ int kvm_create_lapic(struct kvm_vcpu *vc
|
|
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
|
|
@@ -1803,7 +1836,8 @@ void __kvm_migrate_apic_timer(struct kvm
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|