aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv/hv_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hv/hv_util.c')
-rw-r--r--drivers/hv/hv_util.c283
1 files changed, 208 insertions, 75 deletions
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index e7707747f56d..3042eaa13062 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -27,6 +27,9 @@
27#include <linux/sysctl.h> 27#include <linux/sysctl.h>
28#include <linux/reboot.h> 28#include <linux/reboot.h>
29#include <linux/hyperv.h> 29#include <linux/hyperv.h>
30#include <linux/clockchips.h>
31#include <linux/ptp_clock_kernel.h>
32#include <asm/mshyperv.h>
30 33
31#include "hyperv_vmbus.h" 34#include "hyperv_vmbus.h"
32 35
@@ -57,7 +60,31 @@
57static int sd_srv_version; 60static int sd_srv_version;
58static int ts_srv_version; 61static int ts_srv_version;
59static int hb_srv_version; 62static int hb_srv_version;
60static int util_fw_version; 63
64#define SD_VER_COUNT 2
65static const int sd_versions[] = {
66 SD_VERSION,
67 SD_VERSION_1
68};
69
70#define TS_VER_COUNT 3
71static const int ts_versions[] = {
72 TS_VERSION,
73 TS_VERSION_3,
74 TS_VERSION_1
75};
76
77#define HB_VER_COUNT 2
78static const int hb_versions[] = {
79 HB_VERSION,
80 HB_VERSION_1
81};
82
83#define FW_VER_COUNT 2
84static const int fw_versions[] = {
85 UTIL_FW_VERSION,
86 UTIL_WS2K8_FW_VERSION
87};
61 88
62static void shutdown_onchannelcallback(void *context); 89static void shutdown_onchannelcallback(void *context);
63static struct hv_util_service util_shutdown = { 90static struct hv_util_service util_shutdown = {
@@ -118,7 +145,6 @@ static void shutdown_onchannelcallback(void *context)
118 struct shutdown_msg_data *shutdown_msg; 145 struct shutdown_msg_data *shutdown_msg;
119 146
120 struct icmsg_hdr *icmsghdrp; 147 struct icmsg_hdr *icmsghdrp;
121 struct icmsg_negotiate *negop = NULL;
122 148
123 vmbus_recvpacket(channel, shut_txf_buf, 149 vmbus_recvpacket(channel, shut_txf_buf,
124 PAGE_SIZE, &recvlen, &requestid); 150 PAGE_SIZE, &recvlen, &requestid);
@@ -128,9 +154,14 @@ static void shutdown_onchannelcallback(void *context)
128 sizeof(struct vmbuspipe_hdr)]; 154 sizeof(struct vmbuspipe_hdr)];
129 155
130 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 156 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
131 vmbus_prep_negotiate_resp(icmsghdrp, negop, 157 if (vmbus_prep_negotiate_resp(icmsghdrp, shut_txf_buf,
132 shut_txf_buf, util_fw_version, 158 fw_versions, FW_VER_COUNT,
133 sd_srv_version); 159 sd_versions, SD_VER_COUNT,
160 NULL, &sd_srv_version)) {
161 pr_info("Shutdown IC version %d.%d\n",
162 sd_srv_version >> 16,
163 sd_srv_version & 0xFFFF);
164 }
134 } else { 165 } else {
135 shutdown_msg = 166 shutdown_msg =
136 (struct shutdown_msg_data *)&shut_txf_buf[ 167 (struct shutdown_msg_data *)&shut_txf_buf[
@@ -181,31 +212,17 @@ struct adj_time_work {
181 212
182static void hv_set_host_time(struct work_struct *work) 213static void hv_set_host_time(struct work_struct *work)
183{ 214{
184 struct adj_time_work *wrk; 215 struct adj_time_work *wrk;
185 s64 host_tns; 216 struct timespec64 host_ts;
186 u64 newtime; 217 u64 reftime, newtime;
187 struct timespec host_ts;
188 218
189 wrk = container_of(work, struct adj_time_work, work); 219 wrk = container_of(work, struct adj_time_work, work);
190 220
191 newtime = wrk->host_time; 221 reftime = hyperv_cs->read(hyperv_cs);
192 if (ts_srv_version > TS_VERSION_3) { 222 newtime = wrk->host_time + (reftime - wrk->ref_time);
193 /* 223 host_ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
194 * Some latency has been introduced since Hyper-V generated
195 * its time sample. Take that latency into account before
196 * using TSC reference time sample from Hyper-V.
197 *
198 * This sample is given by TimeSync v4 and above hosts.
199 */
200 u64 current_tick;
201
202 rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
203 newtime += (current_tick - wrk->ref_time);
204 }
205 host_tns = (newtime - WLTIMEDELTA) * 100;
206 host_ts = ns_to_timespec(host_tns);
207 224
208 do_settimeofday(&host_ts); 225 do_settimeofday64(&host_ts);
209} 226}
210 227
211/* 228/*
@@ -222,22 +239,60 @@ static void hv_set_host_time(struct work_struct *work)
222 * to discipline the clock. 239 * to discipline the clock.
223 */ 240 */
224static struct adj_time_work wrk; 241static struct adj_time_work wrk;
225static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 flags) 242
243/*
244 * The last time sample, received from the host. PTP device responds to
245 * requests by using this data and the current partition-wide time reference
246 * count.
247 */
248static struct {
249 u64 host_time;
250 u64 ref_time;
251 struct system_time_snapshot snap;
252 spinlock_t lock;
253} host_ts;
254
255static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags)
226{ 256{
257 unsigned long flags;
258 u64 cur_reftime;
227 259
228 /* 260 /*
229 * This check is safe since we are executing in the 261 * This check is safe since we are executing in the
230 * interrupt context and time synch messages arre always 262 * interrupt context and time synch messages are always
231 * delivered on the same CPU. 263 * delivered on the same CPU.
232 */ 264 */
233 if (work_pending(&wrk.work)) 265 if (adj_flags & ICTIMESYNCFLAG_SYNC) {
234 return; 266 /* Queue a job to do do_settimeofday64() */
235 267 if (work_pending(&wrk.work))
236 wrk.host_time = hosttime; 268 return;
237 wrk.ref_time = reftime; 269
238 wrk.flags = flags; 270 wrk.host_time = hosttime;
239 if ((flags & (ICTIMESYNCFLAG_SYNC | ICTIMESYNCFLAG_SAMPLE)) != 0) { 271 wrk.ref_time = reftime;
272 wrk.flags = adj_flags;
240 schedule_work(&wrk.work); 273 schedule_work(&wrk.work);
274 } else {
275 /*
276 * Save the adjusted time sample from the host and the snapshot
277 * of the current system time for PTP device.
278 */
279 spin_lock_irqsave(&host_ts.lock, flags);
280
281 cur_reftime = hyperv_cs->read(hyperv_cs);
282 host_ts.host_time = hosttime;
283 host_ts.ref_time = cur_reftime;
284 ktime_get_snapshot(&host_ts.snap);
285
286 /*
287 * TimeSync v4 messages contain reference time (guest's Hyper-V
288 * clocksource read when the time sample was generated), we can
289 * improve the precision by adding the delta between now and the
290 * time of generation.
291 */
292 if (ts_srv_version > TS_VERSION_3)
293 host_ts.host_time += (cur_reftime - reftime);
294
295 spin_unlock_irqrestore(&host_ts.lock, flags);
241 } 296 }
242} 297}
243 298
@@ -253,7 +308,6 @@ static void timesync_onchannelcallback(void *context)
253 struct ictimesync_data *timedatap; 308 struct ictimesync_data *timedatap;
254 struct ictimesync_ref_data *refdata; 309 struct ictimesync_ref_data *refdata;
255 u8 *time_txf_buf = util_timesynch.recv_buffer; 310 u8 *time_txf_buf = util_timesynch.recv_buffer;
256 struct icmsg_negotiate *negop = NULL;
257 311
258 vmbus_recvpacket(channel, time_txf_buf, 312 vmbus_recvpacket(channel, time_txf_buf,
259 PAGE_SIZE, &recvlen, &requestid); 313 PAGE_SIZE, &recvlen, &requestid);
@@ -263,12 +317,14 @@ static void timesync_onchannelcallback(void *context)
263 sizeof(struct vmbuspipe_hdr)]; 317 sizeof(struct vmbuspipe_hdr)];
264 318
265 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 319 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
266 vmbus_prep_negotiate_resp(icmsghdrp, negop, 320 if (vmbus_prep_negotiate_resp(icmsghdrp, time_txf_buf,
267 time_txf_buf, 321 fw_versions, FW_VER_COUNT,
268 util_fw_version, 322 ts_versions, TS_VER_COUNT,
269 ts_srv_version); 323 NULL, &ts_srv_version)) {
270 pr_info("Using TimeSync version %d.%d\n", 324 pr_info("TimeSync IC version %d.%d\n",
271 ts_srv_version >> 16, ts_srv_version & 0xFFFF); 325 ts_srv_version >> 16,
326 ts_srv_version & 0xFFFF);
327 }
272 } else { 328 } else {
273 if (ts_srv_version > TS_VERSION_3) { 329 if (ts_srv_version > TS_VERSION_3) {
274 refdata = (struct ictimesync_ref_data *) 330 refdata = (struct ictimesync_ref_data *)
@@ -312,7 +368,6 @@ static void heartbeat_onchannelcallback(void *context)
312 struct icmsg_hdr *icmsghdrp; 368 struct icmsg_hdr *icmsghdrp;
313 struct heartbeat_msg_data *heartbeat_msg; 369 struct heartbeat_msg_data *heartbeat_msg;
314 u8 *hbeat_txf_buf = util_heartbeat.recv_buffer; 370 u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
315 struct icmsg_negotiate *negop = NULL;
316 371
317 while (1) { 372 while (1) {
318 373
@@ -326,9 +381,16 @@ static void heartbeat_onchannelcallback(void *context)
326 sizeof(struct vmbuspipe_hdr)]; 381 sizeof(struct vmbuspipe_hdr)];
327 382
328 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { 383 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
329 vmbus_prep_negotiate_resp(icmsghdrp, negop, 384 if (vmbus_prep_negotiate_resp(icmsghdrp,
330 hbeat_txf_buf, util_fw_version, 385 hbeat_txf_buf,
331 hb_srv_version); 386 fw_versions, FW_VER_COUNT,
387 hb_versions, HB_VER_COUNT,
388 NULL, &hb_srv_version)) {
389
390 pr_info("Heartbeat IC version %d.%d\n",
391 hb_srv_version >> 16,
392 hb_srv_version & 0xFFFF);
393 }
332 } else { 394 } else {
333 heartbeat_msg = 395 heartbeat_msg =
334 (struct heartbeat_msg_data *)&hbeat_txf_buf[ 396 (struct heartbeat_msg_data *)&hbeat_txf_buf[
@@ -373,38 +435,10 @@ static int util_probe(struct hv_device *dev,
373 * Turn off batched reading for all util drivers before we open the 435 * Turn off batched reading for all util drivers before we open the
374 * channel. 436 * channel.
375 */ 437 */
376 438 set_channel_read_mode(dev->channel, HV_CALL_DIRECT);
377 set_channel_read_state(dev->channel, false);
378 439
379 hv_set_drvdata(dev, srv); 440 hv_set_drvdata(dev, srv);
380 441
381 /*
382 * Based on the host; initialize the framework and
383 * service version numbers we will negotiate.
384 */
385 switch (vmbus_proto_version) {
386 case (VERSION_WS2008):
387 util_fw_version = UTIL_WS2K8_FW_VERSION;
388 sd_srv_version = SD_VERSION_1;
389 ts_srv_version = TS_VERSION_1;
390 hb_srv_version = HB_VERSION_1;
391 break;
392 case VERSION_WIN7:
393 case VERSION_WIN8:
394 case VERSION_WIN8_1:
395 util_fw_version = UTIL_FW_VERSION;
396 sd_srv_version = SD_VERSION;
397 ts_srv_version = TS_VERSION_3;
398 hb_srv_version = HB_VERSION;
399 break;
400 case VERSION_WIN10:
401 default:
402 util_fw_version = UTIL_FW_VERSION;
403 sd_srv_version = SD_VERSION;
404 ts_srv_version = TS_VERSION;
405 hb_srv_version = HB_VERSION;
406 }
407
408 ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0, 442 ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
409 srv->util_cb, dev->channel); 443 srv->util_cb, dev->channel);
410 if (ret) 444 if (ret)
@@ -470,14 +504,113 @@ static struct hv_driver util_drv = {
470 .remove = util_remove, 504 .remove = util_remove,
471}; 505};
472 506
507static int hv_ptp_enable(struct ptp_clock_info *info,
508 struct ptp_clock_request *request, int on)
509{
510 return -EOPNOTSUPP;
511}
512
513static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts)
514{
515 return -EOPNOTSUPP;
516}
517
518static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
519{
520 return -EOPNOTSUPP;
521}
522static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
523{
524 return -EOPNOTSUPP;
525}
526
527static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
528{
529 unsigned long flags;
530 u64 newtime, reftime;
531
532 spin_lock_irqsave(&host_ts.lock, flags);
533 reftime = hyperv_cs->read(hyperv_cs);
534 newtime = host_ts.host_time + (reftime - host_ts.ref_time);
535 *ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
536 spin_unlock_irqrestore(&host_ts.lock, flags);
537
538 return 0;
539}
540
541static int hv_ptp_get_syncdevicetime(ktime_t *device,
542 struct system_counterval_t *system,
543 void *ctx)
544{
545 system->cs = hyperv_cs;
546 system->cycles = host_ts.ref_time;
547 *device = ns_to_ktime((host_ts.host_time - WLTIMEDELTA) * 100);
548
549 return 0;
550}
551
552static int hv_ptp_getcrosststamp(struct ptp_clock_info *ptp,
553 struct system_device_crosststamp *xtstamp)
554{
555 unsigned long flags;
556 int ret;
557
558 spin_lock_irqsave(&host_ts.lock, flags);
559
560 /*
561 * host_ts contains the last time sample from the host and the snapshot
562 * of system time. We don't need to calculate the time delta between
563 * the reception and now as get_device_system_crosststamp() does the
564 * required interpolation.
565 */
566 ret = get_device_system_crosststamp(hv_ptp_get_syncdevicetime,
567 NULL, &host_ts.snap, xtstamp);
568
569 spin_unlock_irqrestore(&host_ts.lock, flags);
570
571 return ret;
572}
573
574static struct ptp_clock_info ptp_hyperv_info = {
575 .name = "hyperv",
576 .enable = hv_ptp_enable,
577 .adjtime = hv_ptp_adjtime,
578 .adjfreq = hv_ptp_adjfreq,
579 .gettime64 = hv_ptp_gettime,
580 .getcrosststamp = hv_ptp_getcrosststamp,
581 .settime64 = hv_ptp_settime,
582 .owner = THIS_MODULE,
583};
584
585static struct ptp_clock *hv_ptp_clock;
586
473static int hv_timesync_init(struct hv_util_service *srv) 587static int hv_timesync_init(struct hv_util_service *srv)
474{ 588{
589 /* TimeSync requires Hyper-V clocksource. */
590 if (!hyperv_cs)
591 return -ENODEV;
592
475 INIT_WORK(&wrk.work, hv_set_host_time); 593 INIT_WORK(&wrk.work, hv_set_host_time);
594
595 /*
596 * ptp_clock_register() returns NULL when CONFIG_PTP_1588_CLOCK is
597 * disabled but the driver is still useful without the PTP device
598 * as it still handles the ICTIMESYNCFLAG_SYNC case.
599 */
600 hv_ptp_clock = ptp_clock_register(&ptp_hyperv_info, NULL);
601 if (IS_ERR_OR_NULL(hv_ptp_clock)) {
602 pr_err("cannot register PTP clock: %ld\n",
603 PTR_ERR(hv_ptp_clock));
604 hv_ptp_clock = NULL;
605 }
606
476 return 0; 607 return 0;
477} 608}
478 609
479static void hv_timesync_deinit(void) 610static void hv_timesync_deinit(void)
480{ 611{
612 if (hv_ptp_clock)
613 ptp_clock_unregister(hv_ptp_clock);
481 cancel_work_sync(&wrk.work); 614 cancel_work_sync(&wrk.work);
482} 615}
483 616