Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -87,13 +87,6 @@ void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
}
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)
{
	__kvm_migrate_apic_timer(vcpu);
+0 −1
Original line number Diff line number Diff line
@@ -89,7 +89,6 @@ static inline int irqchip_in_kernel(struct kvm *kvm)

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_apic_timer_irqs(struct kvm_vcpu *vcpu);
void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu);
+15 −51
Original line number Diff line number Diff line
@@ -35,6 +35,12 @@
#include "kvm_cache_regs.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 PRIx64 "llx"
#define PRIu64 "u"
@@ -511,52 +517,22 @@ static void apic_send_ipi(struct kvm_lapic *apic)

static u32 apic_get_tmcct(struct kvm_lapic *apic)
{
	u64 counter_passed;
	ktime_t passed, now;
	ktime_t remaining;
	s64 ns;
	u32 tmcct;

	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 (tmcct == 0)
	if (apic_get_reg(apic, APIC_TMICT) == 0)
		return 0;

	if (unlikely(ktime_to_ns(now) <=
		ktime_to_ns(apic->timer.last_update))) {
		/* Wrap around */
		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));
	remaining = hrtimer_expires_remaining(&apic->timer.dev);
	if (ktime_to_ns(remaining) < 0)
		remaining = ktime_set(0, 0);

	if (counter_passed > tmcct) {
		if (unlikely(!apic_lvtt_period(apic))) {
			/* 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;
	}
	ns = mod_64(ktime_to_ns(remaining), apic->timer.period);
	tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count));

	return tmcct;
}
@@ -653,8 +629,6 @@ static void start_apic_timer(struct kvm_lapic *apic)
{
	ktime_t now = apic->timer.dev.base->get_time();

	apic->timer.last_update = now;

	apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
		    APIC_BUS_CYCLE_NS * apic->timer.divide_count;
	atomic_set(&apic->timer.pending, 0);
@@ -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 vector = kvm_apic_has_interrupt(vcpu);
+0 −2
Original line number Diff line number Diff line
@@ -12,7 +12,6 @@ struct kvm_lapic {
		atomic_t pending;
		s64 period;	/* unit: ns */
		u32 divide_count;
		ktime_t last_update;
		struct hrtimer dev;
	} timer;
	struct kvm_vcpu *vcpu;
@@ -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);
int kvm_lapic_enabled(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_sync_from_vapic(struct kvm_vcpu *vcpu);
+0 −1
Original line number Diff line number Diff line
@@ -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. */
	intr_vector = kvm_cpu_get_interrupt(vcpu);
	svm_inject_irq(svm, intr_vector);
	kvm_timer_intr_post(vcpu, intr_vector);
out:
	update_cr8_intercept(vcpu);
}
Loading