Commit 51c4518a authored by Linus Torvalds's avatar Linus Torvalds

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
parents e652049b b46b4a8a
...@@ -282,25 +282,51 @@ static struct { ...@@ -282,25 +282,51 @@ static struct {
spinlock_t lock; spinlock_t lock;
} host_ts; } host_ts;
static struct timespec64 hv_get_adj_host_time(void) static inline u64 reftime_to_ns(u64 reftime)
{ {
struct timespec64 ts; return (reftime - WLTIMEDELTA) * 100;
u64 newtime, reftime; }
/*
* Hard coded threshold for host timesync delay: 600 seconds
*/
static const u64 HOST_TIMESYNC_DELAY_THRESH = 600 * (u64)NSEC_PER_SEC;
static int hv_get_adj_host_time(struct timespec64 *ts)
{
u64 newtime, reftime, timediff_adj;
unsigned long flags; unsigned long flags;
int ret = 0;
spin_lock_irqsave(&host_ts.lock, flags); spin_lock_irqsave(&host_ts.lock, flags);
reftime = hv_read_reference_counter(); reftime = hv_read_reference_counter();
newtime = host_ts.host_time + (reftime - host_ts.ref_time);
ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100); /*
* We need to let the caller know that last update from host
* is older than the max allowable threshold. clock_gettime()
* and PTP ioctl do not have a documented error that we could
* return for this specific case. Use ESTALE to report this.
*/
timediff_adj = reftime - host_ts.ref_time;
if (timediff_adj * 100 > HOST_TIMESYNC_DELAY_THRESH) {
pr_warn_once("TIMESYNC IC: Stale time stamp, %llu nsecs old\n",
(timediff_adj * 100));
ret = -ESTALE;
}
newtime = host_ts.host_time + timediff_adj;
*ts = ns_to_timespec64(reftime_to_ns(newtime));
spin_unlock_irqrestore(&host_ts.lock, flags); spin_unlock_irqrestore(&host_ts.lock, flags);
return ts; return ret;
} }
static void hv_set_host_time(struct work_struct *work) static void hv_set_host_time(struct work_struct *work)
{ {
struct timespec64 ts = hv_get_adj_host_time();
struct timespec64 ts;
if (!hv_get_adj_host_time(&ts))
do_settimeofday64(&ts); do_settimeofday64(&ts);
} }
...@@ -361,10 +387,23 @@ static void timesync_onchannelcallback(void *context) ...@@ -361,10 +387,23 @@ static void timesync_onchannelcallback(void *context)
struct ictimesync_ref_data *refdata; struct ictimesync_ref_data *refdata;
u8 *time_txf_buf = util_timesynch.recv_buffer; u8 *time_txf_buf = util_timesynch.recv_buffer;
vmbus_recvpacket(channel, time_txf_buf, /*
HV_HYP_PAGE_SIZE, &recvlen, &requestid); * Drain the ring buffer and use the last packet to update
* host_ts
*/
while (1) {
int ret = vmbus_recvpacket(channel, time_txf_buf,
HV_HYP_PAGE_SIZE, &recvlen,
&requestid);
if (ret) {
pr_warn_once("TimeSync IC pkt recv failed (Err: %d)\n",
ret);
break;
}
if (!recvlen)
break;
if (recvlen > 0) {
icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[ icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr)]; sizeof(struct vmbuspipe_hdr)];
...@@ -622,9 +661,7 @@ static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ...@@ -622,9 +661,7 @@ static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts) static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
{ {
*ts = hv_get_adj_host_time(); return hv_get_adj_host_time(ts);
return 0;
} }
static struct ptp_clock_info ptp_hyperv_info = { static struct ptp_clock_info ptp_hyperv_info = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment