These old duplicated patches are accidentally send by the mail server... Sorry
for that.
-Original Message-
From: Thomas Shao [mailto:huis...@microsoft.com]
Sent: Tuesday, October 14, 2014 1:49 PM
To: t...@linutronix.de; gre...@linuxfoundation.org; linux-
ker...@vger.kernel.org; de...@linuxdriverproject.org; o...@aepfle.de;
a...@canonical.com; jasow...@redhat.com; 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 huis...@microsoft.com
Reviewed-by: K. Y. Srinivasan k...@microsoft.com
---
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 50L /* 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 10 || diff -10) {
+ do_settimeofday(host_ts);
+ return;
+ }
+
+ /*1ms in nanosecond */
+ if (diff 100 || diff -100) {
+ /* 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;
+ boolforceSync;
};
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);
-