The TSC correction in ptp_kvm_gettime was an attempt to handle high load situations. Unfortunately it is incorrect because userspace expects PTP clock reads to happen in the middle point between realtime clock reads: |* | | | | | | | | | | | |* | | | | | | | | | | | |* | rt-read-1 ptp-clock-read-1 rt-read-2 The TSC correction causes the PTP clock reads to read the clock at: |* | | | | | | | | | | | | | | | | |* | | | | | | |* | rt-read-1 ptp-clock-read-1 rt-read-2 So drop the TSC offset correction, increasing precision of synchronization of an idle guest to <= 10ns. Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx> diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/ptp_kvm.c index 3ea41b8..994aa04 100644 --- a/drivers/ptp/ptp_kvm.c +++ b/drivers/ptp/ptp_kvm.c @@ -123,61 +123,21 @@ static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { unsigned long ret; struct timespec64 tspec; - u64 delta, offset; - unsigned version; - int cpu; - struct pvclock_vcpu_time_info *src; spin_lock(&kvm_ptp_lock); - preempt_disable_notrace(); - cpu = smp_processor_id(); - src = &hv_clock[cpu].pvti; - - do { - /* - * We are measuring the delay between - * kvm_hypercall and rdtsc using TSC, - * and converting that delta through - * tsc_to_system_mul and tsc_shift - * So any changes to tsc_to_system_mul - * and tsc_shift in this region - * invalidate the measurement. - */ - version = pvclock_read_begin(src); - - ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, - clock_pair_gpa, - KVM_CLOCK_PAIRING_WALLCLOCK); - if (ret != 0) { - pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret); - spin_unlock(&kvm_ptp_lock); - preempt_enable_notrace(); - return -EOPNOTSUPP; - } - - tspec.tv_sec = clock_pair.sec; - tspec.tv_nsec = clock_pair.nsec; - - delta = rdtsc_ordered() - clock_pair.tsc; - offset = pvclock_scale_delta(delta, src->tsc_to_system_mul, - src->tsc_shift); - } while (pvclock_read_retry(src, version)); - - preempt_enable_notrace(); - - spin_unlock(&kvm_ptp_lock); - - while (unlikely(offset >= NSEC_PER_SEC)) { - tspec.tv_sec++; - offset -= NSEC_PER_SEC; + ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, + clock_pair_gpa, + KVM_CLOCK_PAIRING_WALLCLOCK); + if (ret != 0) { + pr_err("clock offset hypercall ret %lu\n", ret); + spin_unlock(&kvm_ptp_lock); + return -EOPNOTSUPP; } - tspec.tv_nsec = tspec.tv_nsec + offset; - if (tspec.tv_nsec >= NSEC_PER_SEC) { - tspec.tv_sec++; - tspec.tv_nsec -= NSEC_PER_SEC; - } + tspec.tv_sec = clock_pair.sec; + tspec.tv_nsec = clock_pair.nsec; + spin_unlock(&kvm_ptp_lock); memcpy(ts, &tspec, sizeof(struct timespec64));