root/drivers/hv/hv_util.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. perform_shutdown
  2. shutdown_onchannelcallback
  3. hv_get_adj_host_time
  4. hv_set_host_time
  5. adj_guesttime
  6. timesync_onchannelcallback
  7. heartbeat_onchannelcallback
  8. util_probe
  9. util_remove
  10. hv_ptp_enable
  11. hv_ptp_settime
  12. hv_ptp_adjfreq
  13. hv_ptp_adjtime
  14. hv_ptp_gettime
  15. hv_timesync_init
  16. hv_timesync_deinit
  17. init_hyperv_utils
  18. exit_hyperv_utils

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2010, Microsoft Corporation.
   4  *
   5  * Authors:
   6  *   Haiyang Zhang <haiyangz@microsoft.com>
   7  *   Hank Janssen  <hjanssen@microsoft.com>
   8  */
   9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/init.h>
  13 #include <linux/module.h>
  14 #include <linux/slab.h>
  15 #include <linux/sysctl.h>
  16 #include <linux/reboot.h>
  17 #include <linux/hyperv.h>
  18 #include <linux/clockchips.h>
  19 #include <linux/ptp_clock_kernel.h>
  20 #include <clocksource/hyperv_timer.h>
  21 #include <asm/mshyperv.h>
  22 
  23 #include "hyperv_vmbus.h"
  24 
  25 #define SD_MAJOR        3
  26 #define SD_MINOR        0
  27 #define SD_VERSION      (SD_MAJOR << 16 | SD_MINOR)
  28 
  29 #define SD_MAJOR_1      1
  30 #define SD_VERSION_1    (SD_MAJOR_1 << 16 | SD_MINOR)
  31 
  32 #define TS_MAJOR        4
  33 #define TS_MINOR        0
  34 #define TS_VERSION      (TS_MAJOR << 16 | TS_MINOR)
  35 
  36 #define TS_MAJOR_1      1
  37 #define TS_VERSION_1    (TS_MAJOR_1 << 16 | TS_MINOR)
  38 
  39 #define TS_MAJOR_3      3
  40 #define TS_VERSION_3    (TS_MAJOR_3 << 16 | TS_MINOR)
  41 
  42 #define HB_MAJOR        3
  43 #define HB_MINOR        0
  44 #define HB_VERSION      (HB_MAJOR << 16 | HB_MINOR)
  45 
  46 #define HB_MAJOR_1      1
  47 #define HB_VERSION_1    (HB_MAJOR_1 << 16 | HB_MINOR)
  48 
  49 static int sd_srv_version;
  50 static int ts_srv_version;
  51 static int hb_srv_version;
  52 
  53 #define SD_VER_COUNT 2
  54 static const int sd_versions[] = {
  55         SD_VERSION,
  56         SD_VERSION_1
  57 };
  58 
  59 #define TS_VER_COUNT 3
  60 static const int ts_versions[] = {
  61         TS_VERSION,
  62         TS_VERSION_3,
  63         TS_VERSION_1
  64 };
  65 
  66 #define HB_VER_COUNT 2
  67 static const int hb_versions[] = {
  68         HB_VERSION,
  69         HB_VERSION_1
  70 };
  71 
  72 #define FW_VER_COUNT 2
  73 static const int fw_versions[] = {
  74         UTIL_FW_VERSION,
  75         UTIL_WS2K8_FW_VERSION
  76 };
  77 
  78 static void shutdown_onchannelcallback(void *context);
  79 static struct hv_util_service util_shutdown = {
  80         .util_cb = shutdown_onchannelcallback,
  81 };
  82 
  83 static int hv_timesync_init(struct hv_util_service *srv);
  84 static void hv_timesync_deinit(void);
  85 
  86 static void timesync_onchannelcallback(void *context);
  87 static struct hv_util_service util_timesynch = {
  88         .util_cb = timesync_onchannelcallback,
  89         .util_init = hv_timesync_init,
  90         .util_deinit = hv_timesync_deinit,
  91 };
  92 
  93 static void heartbeat_onchannelcallback(void *context);
  94 static struct hv_util_service util_heartbeat = {
  95         .util_cb = heartbeat_onchannelcallback,
  96 };
  97 
  98 static struct hv_util_service util_kvp = {
  99         .util_cb = hv_kvp_onchannelcallback,
 100         .util_init = hv_kvp_init,
 101         .util_deinit = hv_kvp_deinit,
 102 };
 103 
 104 static struct hv_util_service util_vss = {
 105         .util_cb = hv_vss_onchannelcallback,
 106         .util_init = hv_vss_init,
 107         .util_deinit = hv_vss_deinit,
 108 };
 109 
 110 static struct hv_util_service util_fcopy = {
 111         .util_cb = hv_fcopy_onchannelcallback,
 112         .util_init = hv_fcopy_init,
 113         .util_deinit = hv_fcopy_deinit,
 114 };
 115 
 116 static void perform_shutdown(struct work_struct *dummy)
 117 {
 118         orderly_poweroff(true);
 119 }
 120 
 121 /*
 122  * Perform the shutdown operation in a thread context.
 123  */
 124 static DECLARE_WORK(shutdown_work, perform_shutdown);
 125 
 126 static void shutdown_onchannelcallback(void *context)
 127 {
 128         struct vmbus_channel *channel = context;
 129         u32 recvlen;
 130         u64 requestid;
 131         bool execute_shutdown = false;
 132         u8  *shut_txf_buf = util_shutdown.recv_buffer;
 133 
 134         struct shutdown_msg_data *shutdown_msg;
 135 
 136         struct icmsg_hdr *icmsghdrp;
 137 
 138         vmbus_recvpacket(channel, shut_txf_buf,
 139                          PAGE_SIZE, &recvlen, &requestid);
 140 
 141         if (recvlen > 0) {
 142                 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
 143                         sizeof(struct vmbuspipe_hdr)];
 144 
 145                 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 146                         if (vmbus_prep_negotiate_resp(icmsghdrp, shut_txf_buf,
 147                                         fw_versions, FW_VER_COUNT,
 148                                         sd_versions, SD_VER_COUNT,
 149                                         NULL, &sd_srv_version)) {
 150                                 pr_info("Shutdown IC version %d.%d\n",
 151                                         sd_srv_version >> 16,
 152                                         sd_srv_version & 0xFFFF);
 153                         }
 154                 } else {
 155                         shutdown_msg =
 156                                 (struct shutdown_msg_data *)&shut_txf_buf[
 157                                         sizeof(struct vmbuspipe_hdr) +
 158                                         sizeof(struct icmsg_hdr)];
 159 
 160                         switch (shutdown_msg->flags) {
 161                         case 0:
 162                         case 1:
 163                                 icmsghdrp->status = HV_S_OK;
 164                                 execute_shutdown = true;
 165 
 166                                 pr_info("Shutdown request received -"
 167                                             " graceful shutdown initiated\n");
 168                                 break;
 169                         default:
 170                                 icmsghdrp->status = HV_E_FAIL;
 171                                 execute_shutdown = false;
 172 
 173                                 pr_info("Shutdown request received -"
 174                                             " Invalid request\n");
 175                                 break;
 176                         }
 177                 }
 178 
 179                 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
 180                         | ICMSGHDRFLAG_RESPONSE;
 181 
 182                 vmbus_sendpacket(channel, shut_txf_buf,
 183                                        recvlen, requestid,
 184                                        VM_PKT_DATA_INBAND, 0);
 185         }
 186 
 187         if (execute_shutdown == true)
 188                 schedule_work(&shutdown_work);
 189 }
 190 
 191 /*
 192  * Set the host time in a process context.
 193  */
 194 static struct work_struct adj_time_work;
 195 
 196 /*
 197  * The last time sample, received from the host. PTP device responds to
 198  * requests by using this data and the current partition-wide time reference
 199  * count.
 200  */
 201 static struct {
 202         u64                             host_time;
 203         u64                             ref_time;
 204         spinlock_t                      lock;
 205 } host_ts;
 206 
 207 static struct timespec64 hv_get_adj_host_time(void)
 208 {
 209         struct timespec64 ts;
 210         u64 newtime, reftime;
 211         unsigned long flags;
 212 
 213         spin_lock_irqsave(&host_ts.lock, flags);
 214         reftime = hyperv_cs->read(hyperv_cs);
 215         newtime = host_ts.host_time + (reftime - host_ts.ref_time);
 216         ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
 217         spin_unlock_irqrestore(&host_ts.lock, flags);
 218 
 219         return ts;
 220 }
 221 
 222 static void hv_set_host_time(struct work_struct *work)
 223 {
 224         struct timespec64 ts = hv_get_adj_host_time();
 225 
 226         do_settimeofday64(&ts);
 227 }
 228 
 229 /*
 230  * Synchronize time with host after reboot, restore, etc.
 231  *
 232  * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
 233  * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
 234  * message after the timesync channel is opened. Since the hv_utils module is
 235  * loaded after hv_vmbus, the first message is usually missed. This bit is
 236  * considered a hard request to discipline the clock.
 237  *
 238  * ICTIMESYNCFLAG_SAMPLE bit indicates a time sample from host. This is
 239  * typically used as a hint to the guest. The guest is under no obligation
 240  * to discipline the clock.
 241  */
 242 static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags)
 243 {
 244         unsigned long flags;
 245         u64 cur_reftime;
 246 
 247         /*
 248          * Save the adjusted time sample from the host and the snapshot
 249          * of the current system time.
 250          */
 251         spin_lock_irqsave(&host_ts.lock, flags);
 252 
 253         cur_reftime = hyperv_cs->read(hyperv_cs);
 254         host_ts.host_time = hosttime;
 255         host_ts.ref_time = cur_reftime;
 256 
 257         /*
 258          * TimeSync v4 messages contain reference time (guest's Hyper-V
 259          * clocksource read when the time sample was generated), we can
 260          * improve the precision by adding the delta between now and the
 261          * time of generation. For older protocols we set
 262          * reftime == cur_reftime on call.
 263          */
 264         host_ts.host_time += (cur_reftime - reftime);
 265 
 266         spin_unlock_irqrestore(&host_ts.lock, flags);
 267 
 268         /* Schedule work to do do_settimeofday64() */
 269         if (adj_flags & ICTIMESYNCFLAG_SYNC)
 270                 schedule_work(&adj_time_work);
 271 }
 272 
 273 /*
 274  * Time Sync Channel message handler.
 275  */
 276 static void timesync_onchannelcallback(void *context)
 277 {
 278         struct vmbus_channel *channel = context;
 279         u32 recvlen;
 280         u64 requestid;
 281         struct icmsg_hdr *icmsghdrp;
 282         struct ictimesync_data *timedatap;
 283         struct ictimesync_ref_data *refdata;
 284         u8 *time_txf_buf = util_timesynch.recv_buffer;
 285 
 286         vmbus_recvpacket(channel, time_txf_buf,
 287                          PAGE_SIZE, &recvlen, &requestid);
 288 
 289         if (recvlen > 0) {
 290                 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
 291                                 sizeof(struct vmbuspipe_hdr)];
 292 
 293                 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 294                         if (vmbus_prep_negotiate_resp(icmsghdrp, time_txf_buf,
 295                                                 fw_versions, FW_VER_COUNT,
 296                                                 ts_versions, TS_VER_COUNT,
 297                                                 NULL, &ts_srv_version)) {
 298                                 pr_info("TimeSync IC version %d.%d\n",
 299                                         ts_srv_version >> 16,
 300                                         ts_srv_version & 0xFFFF);
 301                         }
 302                 } else {
 303                         if (ts_srv_version > TS_VERSION_3) {
 304                                 refdata = (struct ictimesync_ref_data *)
 305                                         &time_txf_buf[
 306                                         sizeof(struct vmbuspipe_hdr) +
 307                                         sizeof(struct icmsg_hdr)];
 308 
 309                                 adj_guesttime(refdata->parenttime,
 310                                                 refdata->vmreferencetime,
 311                                                 refdata->flags);
 312                         } else {
 313                                 timedatap = (struct ictimesync_data *)
 314                                         &time_txf_buf[
 315                                         sizeof(struct vmbuspipe_hdr) +
 316                                         sizeof(struct icmsg_hdr)];
 317                                 adj_guesttime(timedatap->parenttime,
 318                                               hyperv_cs->read(hyperv_cs),
 319                                               timedatap->flags);
 320                         }
 321                 }
 322 
 323                 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
 324                         | ICMSGHDRFLAG_RESPONSE;
 325 
 326                 vmbus_sendpacket(channel, time_txf_buf,
 327                                 recvlen, requestid,
 328                                 VM_PKT_DATA_INBAND, 0);
 329         }
 330 }
 331 
 332 /*
 333  * Heartbeat functionality.
 334  * Every two seconds, Hyper-V send us a heartbeat request message.
 335  * we respond to this message, and Hyper-V knows we are alive.
 336  */
 337 static void heartbeat_onchannelcallback(void *context)
 338 {
 339         struct vmbus_channel *channel = context;
 340         u32 recvlen;
 341         u64 requestid;
 342         struct icmsg_hdr *icmsghdrp;
 343         struct heartbeat_msg_data *heartbeat_msg;
 344         u8 *hbeat_txf_buf = util_heartbeat.recv_buffer;
 345 
 346         while (1) {
 347 
 348                 vmbus_recvpacket(channel, hbeat_txf_buf,
 349                                  PAGE_SIZE, &recvlen, &requestid);
 350 
 351                 if (!recvlen)
 352                         break;
 353 
 354                 icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
 355                                 sizeof(struct vmbuspipe_hdr)];
 356 
 357                 if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
 358                         if (vmbus_prep_negotiate_resp(icmsghdrp,
 359                                         hbeat_txf_buf,
 360                                         fw_versions, FW_VER_COUNT,
 361                                         hb_versions, HB_VER_COUNT,
 362                                         NULL, &hb_srv_version)) {
 363 
 364                                 pr_info("Heartbeat IC version %d.%d\n",
 365                                         hb_srv_version >> 16,
 366                                         hb_srv_version & 0xFFFF);
 367                         }
 368                 } else {
 369                         heartbeat_msg =
 370                                 (struct heartbeat_msg_data *)&hbeat_txf_buf[
 371                                         sizeof(struct vmbuspipe_hdr) +
 372                                         sizeof(struct icmsg_hdr)];
 373 
 374                         heartbeat_msg->seq_num += 1;
 375                 }
 376 
 377                 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
 378                         | ICMSGHDRFLAG_RESPONSE;
 379 
 380                 vmbus_sendpacket(channel, hbeat_txf_buf,
 381                                        recvlen, requestid,
 382                                        VM_PKT_DATA_INBAND, 0);
 383         }
 384 }
 385 
 386 static int util_probe(struct hv_device *dev,
 387                         const struct hv_vmbus_device_id *dev_id)
 388 {
 389         struct hv_util_service *srv =
 390                 (struct hv_util_service *)dev_id->driver_data;
 391         int ret;
 392 
 393         srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
 394         if (!srv->recv_buffer)
 395                 return -ENOMEM;
 396         srv->channel = dev->channel;
 397         if (srv->util_init) {
 398                 ret = srv->util_init(srv);
 399                 if (ret) {
 400                         ret = -ENODEV;
 401                         goto error1;
 402                 }
 403         }
 404 
 405         /*
 406          * The set of services managed by the util driver are not performance
 407          * critical and do not need batched reading. Furthermore, some services
 408          * such as KVP can only handle one message from the host at a time.
 409          * Turn off batched reading for all util drivers before we open the
 410          * channel.
 411          */
 412         set_channel_read_mode(dev->channel, HV_CALL_DIRECT);
 413 
 414         hv_set_drvdata(dev, srv);
 415 
 416         ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
 417                         srv->util_cb, dev->channel);
 418         if (ret)
 419                 goto error;
 420 
 421         return 0;
 422 
 423 error:
 424         if (srv->util_deinit)
 425                 srv->util_deinit();
 426 error1:
 427         kfree(srv->recv_buffer);
 428         return ret;
 429 }
 430 
 431 static int util_remove(struct hv_device *dev)
 432 {
 433         struct hv_util_service *srv = hv_get_drvdata(dev);
 434 
 435         if (srv->util_deinit)
 436                 srv->util_deinit();
 437         vmbus_close(dev->channel);
 438         kfree(srv->recv_buffer);
 439 
 440         return 0;
 441 }
 442 
 443 static const struct hv_vmbus_device_id id_table[] = {
 444         /* Shutdown guid */
 445         { HV_SHUTDOWN_GUID,
 446           .driver_data = (unsigned long)&util_shutdown
 447         },
 448         /* Time synch guid */
 449         { HV_TS_GUID,
 450           .driver_data = (unsigned long)&util_timesynch
 451         },
 452         /* Heartbeat guid */
 453         { HV_HEART_BEAT_GUID,
 454           .driver_data = (unsigned long)&util_heartbeat
 455         },
 456         /* KVP guid */
 457         { HV_KVP_GUID,
 458           .driver_data = (unsigned long)&util_kvp
 459         },
 460         /* VSS GUID */
 461         { HV_VSS_GUID,
 462           .driver_data = (unsigned long)&util_vss
 463         },
 464         /* File copy GUID */
 465         { HV_FCOPY_GUID,
 466           .driver_data = (unsigned long)&util_fcopy
 467         },
 468         { },
 469 };
 470 
 471 MODULE_DEVICE_TABLE(vmbus, id_table);
 472 
 473 /* The one and only one */
 474 static  struct hv_driver util_drv = {
 475         .name = "hv_utils",
 476         .id_table = id_table,
 477         .probe =  util_probe,
 478         .remove =  util_remove,
 479         .driver = {
 480                 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
 481         },
 482 };
 483 
 484 static int hv_ptp_enable(struct ptp_clock_info *info,
 485                          struct ptp_clock_request *request, int on)
 486 {
 487         return -EOPNOTSUPP;
 488 }
 489 
 490 static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts)
 491 {
 492         return -EOPNOTSUPP;
 493 }
 494 
 495 static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
 496 {
 497         return -EOPNOTSUPP;
 498 }
 499 static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 500 {
 501         return -EOPNOTSUPP;
 502 }
 503 
 504 static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
 505 {
 506         *ts = hv_get_adj_host_time();
 507 
 508         return 0;
 509 }
 510 
 511 static struct ptp_clock_info ptp_hyperv_info = {
 512         .name           = "hyperv",
 513         .enable         = hv_ptp_enable,
 514         .adjtime        = hv_ptp_adjtime,
 515         .adjfreq        = hv_ptp_adjfreq,
 516         .gettime64      = hv_ptp_gettime,
 517         .settime64      = hv_ptp_settime,
 518         .owner          = THIS_MODULE,
 519 };
 520 
 521 static struct ptp_clock *hv_ptp_clock;
 522 
 523 static int hv_timesync_init(struct hv_util_service *srv)
 524 {
 525         /* TimeSync requires Hyper-V clocksource. */
 526         if (!hyperv_cs)
 527                 return -ENODEV;
 528 
 529         spin_lock_init(&host_ts.lock);
 530 
 531         INIT_WORK(&adj_time_work, hv_set_host_time);
 532 
 533         /*
 534          * ptp_clock_register() returns NULL when CONFIG_PTP_1588_CLOCK is
 535          * disabled but the driver is still useful without the PTP device
 536          * as it still handles the ICTIMESYNCFLAG_SYNC case.
 537          */
 538         hv_ptp_clock = ptp_clock_register(&ptp_hyperv_info, NULL);
 539         if (IS_ERR_OR_NULL(hv_ptp_clock)) {
 540                 pr_err("cannot register PTP clock: %ld\n",
 541                        PTR_ERR(hv_ptp_clock));
 542                 hv_ptp_clock = NULL;
 543         }
 544 
 545         return 0;
 546 }
 547 
 548 static void hv_timesync_deinit(void)
 549 {
 550         if (hv_ptp_clock)
 551                 ptp_clock_unregister(hv_ptp_clock);
 552         cancel_work_sync(&adj_time_work);
 553 }
 554 
 555 static int __init init_hyperv_utils(void)
 556 {
 557         pr_info("Registering HyperV Utility Driver\n");
 558 
 559         return vmbus_driver_register(&util_drv);
 560 }
 561 
 562 static void exit_hyperv_utils(void)
 563 {
 564         pr_info("De-Registered HyperV Utility Driver\n");
 565 
 566         vmbus_driver_unregister(&util_drv);
 567 }
 568 
 569 module_init(init_hyperv_utils);
 570 module_exit(exit_hyperv_utils);
 571 
 572 MODULE_DESCRIPTION("Hyper-V Utilities");
 573 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */