These old duplicated patches are accidentally send by the mail server... Sorry for that. > -----Original Message----- > From: Thomas Shao [mailto:huishao@xxxxxxxxxxxxx] > Sent: Tuesday, October 14, 2014 1:49 PM > To: tglx@xxxxxxxxxxxxx; gregkh@xxxxxxxxxxxxxxxxxxx; linux- > kernel@xxxxxxxxxxxxxxx; devel@xxxxxxxxxxxxxxxxxxxxxx; olaf@xxxxxxxxx; > apw@xxxxxxxxxxxxx; jasowang@xxxxxxxxxx; KY Srinivasan > Cc: Thomas Shao > Subject: [PATCH] hyperv: Implement Time Synchronization using host time > sample > > In current hyper-v time sync service,it only gets the initial clock time from the > host. It didn't process the following time samples. This change introduced a > module parameter called host_time_sync. If it is set to true, the guest will > periodically sychronize it's time with the host clock using host time sample. By > default it is disabled, because we still recommend user to configure NTP for > time synchronization. > > Signed-off-by: Thomas Shao <huishao@xxxxxxxxxxxxx> > Reviewed-by: K. Y. Srinivasan <kys@xxxxxxxxxxxxx> > --- > drivers/hv/hv_util.c | 114 > +++++++++++++++++++++++++++++++++++++++++--- > kernel/time/timekeeping.c | 1 + > 2 files changed, 107 insertions(+), 8 deletions(-) > > diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 3b9c9ef..1d8390c > 100644 > --- a/drivers/hv/hv_util.c > +++ b/drivers/hv/hv_util.c > @@ -51,11 +51,30 @@ > #define HB_WS2008_MAJOR 1 > #define HB_WS2008_VERSION (HB_WS2008_MAJOR << 16 | HB_MINOR) > > +#define TIMESAMPLE_INTERVAL 5000000000L /* 5s in nanosecond */ > + > +/*host sends time sample for every 5s.So the max polling interval *is > +128*5 = 640s. > +*/ > +#define TIME_ADJ_MAX_INTERVAL 128 /*Max polling interval */ > + > static int sd_srv_version; > static int ts_srv_version; > static int hb_srv_version; > static int util_fw_version; > > +/*host sends time sample for every 5s.So the initial polling interval > +*is 5s. > +*/ > +static s32 adj_interval = 1; > + > +/*The host_time_sync module parameter is used to control the time > + sync between host and guest. > +*/ > +static bool host_time_sync; > +module_param(host_time_sync, bool, (S_IRUGO | S_IWUSR)); > +MODULE_PARM_DESC(host_time_sync, "If the guest sync time with host"); > + > static void shutdown_onchannelcallback(void *context); static struct > hv_util_service util_shutdown = { > .util_cb = shutdown_onchannelcallback, @@ -163,15 +182,61 @@ > static void shutdown_onchannelcallback(void *context) > /* > * Set guest time to host UTC time. > */ > -static inline void do_adj_guesttime(u64 hosttime) > +static inline void do_adj_guesttime(u64 hosttime, bool forceSync) > { > - s64 host_tns; > - struct timespec host_ts; > + s64 host_tns, guest_tns, diff; > + struct timespec host_ts, guest_ts; > + struct timex txc; > + s64 tickchg; > + int diff_sign; > > host_tns = (hosttime - WLTIMEDELTA) * 100; > host_ts = ns_to_timespec(host_tns); > > - do_settimeofday(&host_ts); > + if (forceSync) { > + do_settimeofday(&host_ts); > + } else { > + guest_ts = CURRENT_TIME; > + guest_tns = timespec_to_ns(&guest_ts); > + diff = host_tns - guest_tns; > + if (diff >= 0) { > + diff_sign = 1; > + } else { > + diff_sign = -1; > + diff = -diff; > + } > + > + /*1s in nanosecond */ > + if (diff > 1000000000 || diff < -1000000000) { > + do_settimeofday(&host_ts); > + return; > + } > + > + /*1ms in nanosecond */ > + if (diff > 1000000 || diff < -1000000) { > + /* get the current tick value */ > + txc.modes = 0; > + do_adjtimex(&txc); > + > + tickchg = diff * TICK_USEC / > + (TIMESAMPLE_INTERVAL * > adj_interval); > + > + if (tickchg > TICK_USEC/10) > + tickchg = TICK_USEC/10; > + > + if (txc.tick == TICK_USEC + diff_sign * tickchg) > + return; > + > + txc.modes = ADJ_TICK; > + txc.tick = TICK_USEC + diff_sign * tickchg; > + > + do_adjtimex(&txc); > + } else { > + /* double the polling interval*/ > + if (adj_interval < TIME_ADJ_MAX_INTERVAL) > + adj_interval = adj_interval * 2; > + } > + } > } > > /* > @@ -179,8 +244,9 @@ static inline void do_adj_guesttime(u64 hosttime) > */ > > struct adj_time_work { > - struct work_struct work; > + struct work_struct work; > u64 host_time; > + bool forceSync; > }; > > static void hv_set_host_time(struct work_struct *work) @@ -188,7 +254,7 > @@ static void hv_set_host_time(struct work_struct *work) > struct adj_time_work *wrk; > > wrk = container_of(work, struct adj_time_work, work); > - do_adj_guesttime(wrk->host_time); > + do_adj_guesttime(wrk->host_time, wrk->forceSync); > kfree(wrk); > } > > @@ -202,11 +268,14 @@ static void hv_set_host_time(struct work_struct > *work) > * thing is, systime is automatically set to emulated hardware clock which > may > * not be UTC time or in the same time zone. So, to override these effects, > we > * use the first 50 time samples for initial system time setting. > + * If the host_time_sync module parameter is set, we will use the host > + time > + * samples to adjust guest time after the first 50 samples. > */ > static inline void adj_guesttime(u64 hosttime, u8 flags) { > struct adj_time_work *wrk; > static s32 scnt = 50; > + static s32 sample_count; > > wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC); > if (wrk == NULL) > @@ -214,6 +283,7 @@ static inline void adj_guesttime(u64 hosttime, u8 flags) > > wrk->host_time = hosttime; > if ((flags & ICTIMESYNCFLAG_SYNC) != 0) { > + wrk->forceSync = true; > INIT_WORK(&wrk->work, hv_set_host_time); > schedule_work(&wrk->work); > return; > @@ -221,10 +291,38 @@ static inline void adj_guesttime(u64 hosttime, u8 > flags) > > if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) { > scnt--; > + wrk->forceSync = true; > INIT_WORK(&wrk->work, hv_set_host_time); > schedule_work(&wrk->work); > - } else > - kfree(wrk); > + return; > + } > + > + if (host_time_sync) { > + /* > + * Use the Hyper-V time sample to adjust the guest time. The > + * algorithm is: If the sample offsets exceeds 1 second, we > + * directly set the clock to the server time. If the offset is > + * less than 1ms, we ignore the time sample. Otherwise we > adjust > + * the clock. > + */ > + > + if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0) { > + if (sample_count < adj_interval) { > + sample_count++; > + goto cleanup; > + } > + /* reset the polling interval */ > + sample_count = 0; > + wrk->forceSync = false; > + INIT_WORK(&wrk->work, hv_set_host_time); > + schedule_work(&wrk->work); > + return; > + } > + } > + > +cleanup: > + kfree(wrk); > + > } > > /* > diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index > ec1791f..381a1ca 100644 > --- a/kernel/time/timekeeping.c > +++ b/kernel/time/timekeeping.c > @@ -1786,6 +1786,7 @@ int do_adjtimex(struct timex *txc) > > return ret; > } > +EXPORT_SYMBOL(do_adjtimex); > > #ifdef CONFIG_NTP_PPS > /** > -- > 1.7.1 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel