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

Commit 0293615f authored by Glauber Costa's avatar Glauber Costa Committed by Avi Kivity
Browse files

x86: KVM guest: use paravirt function to calculate cpu khz



We're currently facing timing problems in guests that do
calibration under heavy load, and then the load vanishes.
This means we'll have a much lower lpj than we actually should,
and delays end up taking less time than they should, which is a
nasty bug.

Solution is to pass on the lpj value from host to guest, and have it
preset.

Signed-off-by: default avatarGlauber Costa <gcosta@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
parent 3807f345
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -78,6 +78,34 @@ static cycle_t kvm_clock_read(void)
	return ret;
}

/*
 * If we don't do that, there is the possibility that the guest
 * will calibrate under heavy load - thus, getting a lower lpj -
 * and execute the delays themselves without load. This is wrong,
 * because no delay loop can finish beforehand.
 * Any heuristics is subject to fail, because ultimately, a large
 * poll of guests can be running and trouble each other. So we preset
 * lpj here
 */
static unsigned long kvm_get_tsc_khz(void)
{
	return preset_lpj;
}

static void kvm_get_preset_lpj(void)
{
	struct pvclock_vcpu_time_info *src;
	unsigned long khz;
	u64 lpj;

	src = &per_cpu(hv_clock, 0);
	khz = pvclock_tsc_khz(src);

	lpj = ((u64)khz * 1000);
	do_div(lpj, HZ);
	preset_lpj = lpj;
}

static struct clocksource kvm_clock = {
	.name = "kvm-clock",
	.read = kvm_clock_read,
@@ -153,6 +181,7 @@ void __init kvmclock_init(void)
		pv_time_ops.get_wallclock = kvm_get_wallclock;
		pv_time_ops.set_wallclock = kvm_set_wallclock;
		pv_time_ops.sched_clock = kvm_clock_read;
		pv_time_ops.get_tsc_khz = kvm_get_tsc_khz;
#ifdef CONFIG_X86_LOCAL_APIC
		pv_apic_ops.setup_secondary_clock = kvm_setup_secondary_clock;
#endif
@@ -163,6 +192,7 @@ void __init kvmclock_init(void)
#ifdef CONFIG_KEXEC
		machine_ops.crash_shutdown  = kvm_crash_shutdown;
#endif
		kvm_get_preset_lpj();
		clocksource_register(&kvm_clock);
	}
}