Commit b682b814 authored by Marcelo Tosatti's avatar Marcelo Tosatti Committed by Avi Kivity

KVM: x86: fix LAPIC pending count calculation

Simplify LAPIC TMCCT calculation by using hrtimer provided
function to query remaining time until expiration.

Fixes host hang with nested ESX.
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent d7cff1c3
...@@ -87,13 +87,6 @@ void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) ...@@ -87,13 +87,6 @@ void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
} }
EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
{
kvm_apic_timer_intr_post(vcpu, vec);
/* TODO: PIT, RTC etc. */
}
EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
void __kvm_migrate_timers(struct kvm_vcpu *vcpu) void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
{ {
__kvm_migrate_apic_timer(vcpu); __kvm_migrate_apic_timer(vcpu);
......
...@@ -89,7 +89,6 @@ static inline int irqchip_in_kernel(struct kvm *kvm) ...@@ -89,7 +89,6 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
void kvm_pic_reset(struct kvm_kpic_state *s); void kvm_pic_reset(struct kvm_kpic_state *s);
void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu); void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu);
......
...@@ -35,6 +35,12 @@ ...@@ -35,6 +35,12 @@
#include "kvm_cache_regs.h" #include "kvm_cache_regs.h"
#include "irq.h" #include "irq.h"
#ifndef CONFIG_X86_64
#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
#else
#define mod_64(x, y) ((x) % (y))
#endif
#define PRId64 "d" #define PRId64 "d"
#define PRIx64 "llx" #define PRIx64 "llx"
#define PRIu64 "u" #define PRIu64 "u"
...@@ -511,52 +517,22 @@ static void apic_send_ipi(struct kvm_lapic *apic) ...@@ -511,52 +517,22 @@ static void apic_send_ipi(struct kvm_lapic *apic)
static u32 apic_get_tmcct(struct kvm_lapic *apic) static u32 apic_get_tmcct(struct kvm_lapic *apic)
{ {
u64 counter_passed; ktime_t remaining;
ktime_t passed, now; s64 ns;
u32 tmcct; u32 tmcct;
ASSERT(apic != NULL); ASSERT(apic != NULL);
now = apic->timer.dev.base->get_time();
tmcct = apic_get_reg(apic, APIC_TMICT);
/* if initial count is 0, current count should also be 0 */ /* if initial count is 0, current count should also be 0 */
if (tmcct == 0) if (apic_get_reg(apic, APIC_TMICT) == 0)
return 0; return 0;
if (unlikely(ktime_to_ns(now) <= remaining = hrtimer_expires_remaining(&apic->timer.dev);
ktime_to_ns(apic->timer.last_update))) { if (ktime_to_ns(remaining) < 0)
/* Wrap around */ remaining = ktime_set(0, 0);
passed = ktime_add(( {
(ktime_t) {
.tv64 = KTIME_MAX -
(apic->timer.last_update).tv64}; }
), now);
apic_debug("time elapsed\n");
} else
passed = ktime_sub(now, apic->timer.last_update);
counter_passed = div64_u64(ktime_to_ns(passed),
(APIC_BUS_CYCLE_NS * apic->timer.divide_count));
if (counter_passed > tmcct) { ns = mod_64(ktime_to_ns(remaining), apic->timer.period);
if (unlikely(!apic_lvtt_period(apic))) { tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
/* one-shot timers stick at 0 until reset */
tmcct = 0;
} else {
/*
* periodic timers reset to APIC_TMICT when they
* hit 0. The while loop simulates this happening N
* times. (counter_passed %= tmcct) would also work,
* but might be slower or not work on 32-bit??
*/
while (counter_passed > tmcct)
counter_passed -= tmcct;
tmcct -= counter_passed;
}
} else {
tmcct -= counter_passed;
}
return tmcct; return tmcct;
} }
...@@ -653,8 +629,6 @@ static void start_apic_timer(struct kvm_lapic *apic) ...@@ -653,8 +629,6 @@ static void start_apic_timer(struct kvm_lapic *apic)
{ {
ktime_t now = apic->timer.dev.base->get_time(); ktime_t now = apic->timer.dev.base->get_time();
apic->timer.last_update = now;
apic->timer.period = apic_get_reg(apic, APIC_TMICT) * apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
APIC_BUS_CYCLE_NS * apic->timer.divide_count; APIC_BUS_CYCLE_NS * apic->timer.divide_count;
atomic_set(&apic->timer.pending, 0); atomic_set(&apic->timer.pending, 0);
...@@ -1110,16 +1084,6 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) ...@@ -1110,16 +1084,6 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
} }
} }
void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
{
struct kvm_lapic *apic = vcpu->arch.apic;
if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
apic->timer.last_update = ktime_add_ns(
apic->timer.last_update,
apic->timer.period);
}
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
{ {
int vector = kvm_apic_has_interrupt(vcpu); int vector = kvm_apic_has_interrupt(vcpu);
......
...@@ -12,7 +12,6 @@ struct kvm_lapic { ...@@ -12,7 +12,6 @@ struct kvm_lapic {
atomic_t pending; atomic_t pending;
s64 period; /* unit: ns */ s64 period; /* unit: ns */
u32 divide_count; u32 divide_count;
ktime_t last_update;
struct hrtimer dev; struct hrtimer dev;
} timer; } timer;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
...@@ -42,7 +41,6 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); ...@@ -42,7 +41,6 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
int kvm_lapic_enabled(struct kvm_vcpu *vcpu); int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
......
...@@ -1600,7 +1600,6 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) ...@@ -1600,7 +1600,6 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
/* Okay, we can deliver the interrupt: grab it and update PIC state. */ /* Okay, we can deliver the interrupt: grab it and update PIC state. */
intr_vector = kvm_cpu_get_interrupt(vcpu); intr_vector = kvm_cpu_get_interrupt(vcpu);
svm_inject_irq(svm, intr_vector); svm_inject_irq(svm, intr_vector);
kvm_timer_intr_post(vcpu, intr_vector);
out: out:
update_cr8_intercept(vcpu); update_cr8_intercept(vcpu);
} }
......
...@@ -3285,7 +3285,6 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) ...@@ -3285,7 +3285,6 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
} }
if (vcpu->arch.interrupt.pending) { if (vcpu->arch.interrupt.pending) {
vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr); vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
kvm_timer_intr_post(vcpu, vcpu->arch.interrupt.nr);
if (kvm_cpu_has_interrupt(vcpu)) if (kvm_cpu_has_interrupt(vcpu))
enable_irq_window(vcpu); enable_irq_window(vcpu);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment