diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 1963de9fb8..e2a3d87527 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5358,12 +5358,18 @@ qemuProcessStartValidateDisks(virDomainObjPtr vm, } +/* 250 parts per million (ppm) is a half of NTP threshold */ +#define TSC_TOLERANCE 250 + static int qemuProcessStartValidateTSC(virQEMUDriverPtr driver, virDomainObjPtr vm) { size_t i; unsigned long long freq = 0; + unsigned long long tolerance; + unsigned long long minFreq; + unsigned long long maxFreq; virHostCPUTscInfoPtr tsc; g_autoptr(virCPUDef) cpu = NULL; @@ -5389,23 +5395,34 @@ qemuProcessStartValidateTSC(virQEMUDriverPtr driver, } tsc = cpu->tsc; - VIR_DEBUG("Host TSC frequency %llu Hz, scaling %s", - tsc->frequency, virTristateBoolTypeToString(tsc->scaling)); + tolerance = tsc->frequency * TSC_TOLERANCE / 1000000; + minFreq = tsc->frequency - tolerance; + maxFreq = tsc->frequency + tolerance; - if (freq == tsc->frequency || tsc->scaling == VIR_TRISTATE_BOOL_YES) + VIR_DEBUG("Host TSC frequency %llu Hz, scaling %s, tolerance +/- %llu Hz", + tsc->frequency, virTristateBoolTypeToString(tsc->scaling), + tolerance); + + if (freq > minFreq && freq < maxFreq) { + VIR_DEBUG("Requested TSC frequency is within tolerance interval"); + return 0; + } + + if (tsc->scaling == VIR_TRISTATE_BOOL_YES) return 0; if (tsc->scaling == VIR_TRISTATE_BOOL_ABSENT) { - VIR_DEBUG("TSC frequencies do not match and scaling support is " - "unknown, QEMU will try and possibly fail later"); + VIR_DEBUG("Requested TSC frequency falls outside tolerance range and " + "scaling support is unknown, QEMU will try and possibly " + "fail later"); return 0; } virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Requested TSC frequency %llu Hz does not match " - "host (%llu Hz) and TSC scaling is not supported " - "by the host CPU"), - freq, tsc->frequency); + _("Requested TSC frequency %llu Hz is outside tolerance " + "range ([%llu, %llu] Hz) around host frequency %llu Hz " + "and TSC scaling is not supported by the host CPU"), + freq, minFreq, maxFreq, tsc->frequency); return -1; }