Skip to content

Commit 51c4518

Browse files
committed
Merge tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux
Pull hyperv fixes from Wei Liu: "Two patches from Vineeth to improve Hyper-V timesync facility" * tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: hv_utils: drain the timesync packets on onchannelcallback hv_utils: return error if host timesysnc update is stale
2 parents e652049 + b46b4a8 commit 51c4518

1 file changed

Lines changed: 51 additions & 14 deletions

File tree

drivers/hv/hv_util.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

300324
static 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

623662
static 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

630667
static struct ptp_clock_info ptp_hyperv_info = {

0 commit comments

Comments
 (0)