Skip to content

Commit 74aaddc

Browse files
matosattibonzini
authored andcommitted
kvm: i386: allow TSC to differ by NTP correction bounds without TSC scaling
The Linux TSC calibration procedure is subject to small variations (its common to see +-1 kHz difference between reboots on a given CPU, for example). So migrating a guest between two hosts with identical processor can fail, in case of a small variation in calibrated TSC between them. Allow a conservative 250ppm error between host TSC and VM TSC frequencies, rather than requiring an exact match. NTP daemon in the guest can correct this difference. Also change migration to accept this bound. KVM_SET_TSC_KHZ depends on a kernel interface change. Without this change, the behaviour remains the same: in case of a different frequency between host and VM, KVM_SET_TSC_KHZ will fail and QEMU will exit. Signed-off-by: Marcelo Tosatti <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 32a354d commit 74aaddc

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

target/i386/kvm.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -740,26 +740,62 @@ static bool hyperv_enabled(X86CPU *cpu)
740740
cpu->hyperv_features || cpu->hyperv_passthrough);
741741
}
742742

743+
/*
744+
* Check whether target_freq is within conservative
745+
* ntp correctable bounds (250ppm) of freq
746+
*/
747+
static inline bool freq_within_bounds(int freq, int target_freq)
748+
{
749+
int max_freq = freq + (freq * 250 / 1000000);
750+
int min_freq = freq - (freq * 250 / 1000000);
751+
752+
if (target_freq >= min_freq && target_freq <= max_freq) {
753+
return true;
754+
}
755+
756+
return false;
757+
}
758+
743759
static int kvm_arch_set_tsc_khz(CPUState *cs)
744760
{
745761
X86CPU *cpu = X86_CPU(cs);
746762
CPUX86State *env = &cpu->env;
747-
int r;
763+
int r, cur_freq;
764+
bool set_ioctl = false;
748765

749766
if (!env->tsc_khz) {
750767
return 0;
751768
}
752769

753-
r = kvm_check_extension(cs->kvm_state, KVM_CAP_TSC_CONTROL) ?
770+
cur_freq = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ?
771+
kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) : -ENOTSUP;
772+
773+
/*
774+
* If TSC scaling is supported, attempt to set TSC frequency.
775+
*/
776+
if (kvm_check_extension(cs->kvm_state, KVM_CAP_TSC_CONTROL)) {
777+
set_ioctl = true;
778+
}
779+
780+
/*
781+
* If desired TSC frequency is within bounds of NTP correction,
782+
* attempt to set TSC frequency.
783+
*/
784+
if (cur_freq != -ENOTSUP && freq_within_bounds(cur_freq, env->tsc_khz)) {
785+
set_ioctl = true;
786+
}
787+
788+
r = set_ioctl ?
754789
kvm_vcpu_ioctl(cs, KVM_SET_TSC_KHZ, env->tsc_khz) :
755790
-ENOTSUP;
791+
756792
if (r < 0) {
757793
/* When KVM_SET_TSC_KHZ fails, it's an error only if the current
758794
* TSC frequency doesn't match the one we want.
759795
*/
760-
int cur_freq = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ?
761-
kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) :
762-
-ENOTSUP;
796+
cur_freq = kvm_check_extension(cs->kvm_state, KVM_CAP_GET_TSC_KHZ) ?
797+
kvm_vcpu_ioctl(cs, KVM_GET_TSC_KHZ) :
798+
-ENOTSUP;
763799
if (cur_freq <= 0 || cur_freq != env->tsc_khz) {
764800
warn_report("TSC frequency mismatch between "
765801
"VM (%" PRId64 " kHz) and host (%d kHz), "

0 commit comments

Comments
 (0)