@@ -282,26 +282,52 @@ static struct {
282282 spinlock_t lock ;
283283} host_ts ;
284284
285- static struct timespec64 hv_get_adj_host_time ( void )
285+ static inline u64 reftime_to_ns ( u64 reftime )
286286{
287- struct timespec64 ts ;
288- u64 newtime , reftime ;
287+ return (reftime - WLTIMEDELTA ) * 100 ;
288+ }
289+
290+ /*
291+ * Hard coded threshold for host timesync delay: 600 seconds
292+ */
293+ static const u64 HOST_TIMESYNC_DELAY_THRESH = 600 * (u64 )NSEC_PER_SEC ;
294+
295+ static int hv_get_adj_host_time (struct timespec64 * ts )
296+ {
297+ u64 newtime , reftime , timediff_adj ;
289298 unsigned long flags ;
299+ int ret = 0 ;
290300
291301 spin_lock_irqsave (& host_ts .lock , flags );
292302 reftime = hv_read_reference_counter ();
293- newtime = host_ts .host_time + (reftime - host_ts .ref_time );
294- ts = ns_to_timespec64 ((newtime - WLTIMEDELTA ) * 100 );
303+
304+ /*
305+ * We need to let the caller know that last update from host
306+ * is older than the max allowable threshold. clock_gettime()
307+ * and PTP ioctl do not have a documented error that we could
308+ * return for this specific case. Use ESTALE to report this.
309+ */
310+ timediff_adj = reftime - host_ts .ref_time ;
311+ if (timediff_adj * 100 > HOST_TIMESYNC_DELAY_THRESH ) {
312+ pr_warn_once ("TIMESYNC IC: Stale time stamp, %llu nsecs old\n" ,
313+ (timediff_adj * 100 ));
314+ ret = - ESTALE ;
315+ }
316+
317+ newtime = host_ts .host_time + timediff_adj ;
318+ * ts = ns_to_timespec64 (reftime_to_ns (newtime ));
295319 spin_unlock_irqrestore (& host_ts .lock , flags );
296320
297- return ts ;
321+ return ret ;
298322}
299323
300324static void hv_set_host_time (struct work_struct * work )
301325{
302- struct timespec64 ts = hv_get_adj_host_time ();
303326
304- do_settimeofday64 (& ts );
327+ struct timespec64 ts ;
328+
329+ if (!hv_get_adj_host_time (& ts ))
330+ do_settimeofday64 (& ts );
305331}
306332
307333/*
@@ -361,10 +387,23 @@ static void timesync_onchannelcallback(void *context)
361387 struct ictimesync_ref_data * refdata ;
362388 u8 * time_txf_buf = util_timesynch .recv_buffer ;
363389
364- vmbus_recvpacket (channel , time_txf_buf ,
365- HV_HYP_PAGE_SIZE , & recvlen , & requestid );
390+ /*
391+ * Drain the ring buffer and use the last packet to update
392+ * host_ts
393+ */
394+ while (1 ) {
395+ int ret = vmbus_recvpacket (channel , time_txf_buf ,
396+ HV_HYP_PAGE_SIZE , & recvlen ,
397+ & requestid );
398+ if (ret ) {
399+ pr_warn_once ("TimeSync IC pkt recv failed (Err: %d)\n" ,
400+ ret );
401+ break ;
402+ }
403+
404+ if (!recvlen )
405+ break ;
366406
367- if (recvlen > 0 ) {
368407 icmsghdrp = (struct icmsg_hdr * )& time_txf_buf [
369408 sizeof (struct vmbuspipe_hdr )];
370409
@@ -622,9 +661,7 @@ static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
622661
623662static int hv_ptp_gettime (struct ptp_clock_info * info , struct timespec64 * ts )
624663{
625- * ts = hv_get_adj_host_time ();
626-
627- return 0 ;
664+ return hv_get_adj_host_time (ts );
628665}
629666
630667static struct ptp_clock_info ptp_hyperv_info = {
0 commit comments