[PATCH 427/577] Staging: hv: Add Time Sync feature to hv_utils module.

Greg Kroah-Hartman gregkh at suse.de
Fri May 21 20:02:36 UTC 2010


From: Haiyang Zhang <haiyangz at microsoft.com>

The Time Sync feature synchronizes guest time to host UTC time after reboot,
and restore from saved/paused state.

Signed-off-by: Hank Janssen <hjanssen at microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz at microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
---
 drivers/staging/hv/ChannelMgmt.c  |   24 ++++++++++-
 drivers/staging/hv/hyperv_utils.c |   84 +++++++++++++++++++++++++++++++++++++
 drivers/staging/hv/utils.h        |   25 ++++++++++-
 3 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/hv/ChannelMgmt.c b/drivers/staging/hv/ChannelMgmt.c
index 05e6699..3698230 100644
--- a/drivers/staging/hv/ChannelMgmt.c
+++ b/drivers/staging/hv/ChannelMgmt.c
@@ -33,8 +33,8 @@ struct vmbus_channel_message_table_entry {
 	void (*messageHandler)(struct vmbus_channel_message_header *msg);
 };
 
-#define MAX_MSG_TYPES                    1
-#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 5
+#define MAX_MSG_TYPES                    2
+#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 6
 
 static const struct hv_guid
 	gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
@@ -81,6 +81,14 @@ static const struct hv_guid
 			0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
 		}
 	},
+	/* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+	/* TimeSync */
+	{
+		.data = {
+			0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+			0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+		}
+	},
 };
 
 
@@ -191,6 +199,18 @@ struct hyperv_service_callback hv_cb_utils[MAX_MSG_TYPES] = {
 		.callback = chn_cb_negotiate,
 		.log_msg = "Shutdown channel functionality initialized"
 	},
+
+	/* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
+	/* TimeSync */
+	{
+		.msg_type = HV_TIMESYNC_MSG,
+		.data = {
+			0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
+			0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
+		},
+		.callback = chn_cb_negotiate,
+		.log_msg = "Timesync channel functionality initialized"
+	},
 };
 EXPORT_SYMBOL(hv_cb_utils);
 
diff --git a/drivers/staging/hv/hyperv_utils.c b/drivers/staging/hv/hyperv_utils.c
index cbebad3..9174f79 100644
--- a/drivers/staging/hv/hyperv_utils.c
+++ b/drivers/staging/hv/hyperv_utils.c
@@ -106,6 +106,82 @@ static void shutdown_onchannelcallback(void *context)
 		orderly_poweroff(false);
 }
 
+
+/*
+ * Synchronize time with host after reboot, restore, etc.
+ */
+static void adj_guesttime(winfiletime_t hosttime, u8 flags)
+{
+	s64 host_tns;
+	struct timespec host_ts;
+	static s32 scnt = 50;
+
+	host_tns = (hosttime - WLTIMEDELTA) * 100;
+	host_ts = ns_to_timespec(host_tns);
+
+	if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
+		do_settimeofday(&host_ts);
+		return;
+	}
+
+	if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 &&
+	    scnt > 0) {
+		scnt--;
+		do_settimeofday(&host_ts);
+	}
+
+	return;
+}
+
+/*
+ * Time Sync Channel message handler.
+ */
+static void timesync_onchannelcallback(void *context)
+{
+	struct vmbus_channel *channel = context;
+	u8 *buf;
+	u32 buflen, recvlen;
+	u64 requestid;
+	struct icmsg_hdr *icmsghdrp;
+	struct ictimesync_data *timedatap;
+
+	DPRINT_ENTER(VMBUS);
+
+	buflen = PAGE_SIZE;
+	buf = kmalloc(buflen, GFP_ATOMIC);
+
+	VmbusChannelRecvPacket(channel, buf, buflen, &recvlen, &requestid);
+
+	if (recvlen > 0) {
+		DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld",
+			recvlen, requestid);
+
+		icmsghdrp = (struct icmsg_hdr *)&buf[
+				sizeof(struct vmbuspipe_hdr)];
+
+		if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+			prep_negotiate_resp(icmsghdrp, NULL, buf);
+		} else {
+			timedatap = (struct ictimesync_data *)&buf[
+				sizeof(struct vmbuspipe_hdr) +
+				sizeof(struct icmsg_hdr)];
+			adj_guesttime(timedatap->parenttime, timedatap->flags);
+		}
+
+		icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+			| ICMSGHDRFLAG_RESPONSE;
+
+		VmbusChannelSendPacket(channel, buf,
+				recvlen, requestid,
+				VmbusPacketTypeDataInBand, 0);
+	}
+
+	kfree(buf);
+
+	DPRINT_EXIT(VMBUS);
+}
+
+
 static int __init init_hyperv_utils(void)
 {
 	printk(KERN_INFO "Registering HyperV Utility Driver\n");
@@ -114,6 +190,10 @@ static int __init init_hyperv_utils(void)
 		&shutdown_onchannelcallback;
 	hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
 
+	hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
+		&timesync_onchannelcallback;
+	hv_cb_utils[HV_TIMESYNC_MSG].callback = &timesync_onchannelcallback;
+
 	return 0;
 }
 
@@ -124,6 +204,10 @@ static void exit_hyperv_utils(void)
 	hv_cb_utils[HV_SHUTDOWN_MSG].channel->OnChannelCallback =
 		&chn_cb_negotiate;
 	hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate;
+
+	hv_cb_utils[HV_TIMESYNC_MSG].channel->OnChannelCallback =
+		&chn_cb_negotiate;
+	hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate;
 }
 
 module_init(init_hyperv_utils);
diff --git a/drivers/staging/hv/utils.h b/drivers/staging/hv/utils.h
index e404b21..d1d2f28 100644
--- a/drivers/staging/hv/utils.h
+++ b/drivers/staging/hv/utils.h
@@ -75,7 +75,30 @@ struct shutdown_msg_data {
 	u8  display_message[2048];
 } __attribute__((packed));
 
-#define HV_SHUTDOWN_MSG		0
+
+/* Time Sync IC defs */
+#define ICTIMESYNCFLAG_PROBE 0
+#define ICTIMESYNCFLAG_SYNC 1
+#define ICTIMESYNCFLAG_SAMPLE 2
+
+#ifdef __x86_64__
+#define WLTIMEDELTA 116444736000000000L  /* in 100ns unit */
+#else
+#define WLTIMEDELTA 116444736000000000LL
+#endif
+
+typedef u64 winfiletime_t; /* Windows FILETIME type */
+
+struct ictimesync_data{
+    winfiletime_t parenttime;
+    winfiletime_t childtime;
+    winfiletime_t roundtriptime;
+    u8 flags;
+} __attribute__((packed));
+
+/* Index for each IC struct in array hv_cb_utils[] */
+#define HV_SHUTDOWN_MSG 0
+#define HV_TIMESYNC_MSG 1
 
 struct hyperv_service_callback {
 	u8 msg_type;
-- 
1.7.0.3




More information about the devel mailing list