Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.4 573 lines 14 kB view raw
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 49static int sd_srv_version; 50static int ts_srv_version; 51static int hb_srv_version; 52 53#define SD_VER_COUNT 2 54static const int sd_versions[] = { 55 SD_VERSION, 56 SD_VERSION_1 57}; 58 59#define TS_VER_COUNT 3 60static const int ts_versions[] = { 61 TS_VERSION, 62 TS_VERSION_3, 63 TS_VERSION_1 64}; 65 66#define HB_VER_COUNT 2 67static const int hb_versions[] = { 68 HB_VERSION, 69 HB_VERSION_1 70}; 71 72#define FW_VER_COUNT 2 73static const int fw_versions[] = { 74 UTIL_FW_VERSION, 75 UTIL_WS2K8_FW_VERSION 76}; 77 78static void shutdown_onchannelcallback(void *context); 79static struct hv_util_service util_shutdown = { 80 .util_cb = shutdown_onchannelcallback, 81}; 82 83static int hv_timesync_init(struct hv_util_service *srv); 84static void hv_timesync_deinit(void); 85 86static void timesync_onchannelcallback(void *context); 87static 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 93static void heartbeat_onchannelcallback(void *context); 94static struct hv_util_service util_heartbeat = { 95 .util_cb = heartbeat_onchannelcallback, 96}; 97 98static 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 104static 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 110static 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 116static 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 */ 124static DECLARE_WORK(shutdown_work, perform_shutdown); 125 126static 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 */ 194static 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 */ 201static struct { 202 u64 host_time; 203 u64 ref_time; 204 spinlock_t lock; 205} host_ts; 206 207static 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 222static 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 */ 242static 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 */ 276static 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 */ 337static 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 386static 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 423error: 424 if (srv->util_deinit) 425 srv->util_deinit(); 426error1: 427 kfree(srv->recv_buffer); 428 return ret; 429} 430 431static 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 443static 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 471MODULE_DEVICE_TABLE(vmbus, id_table); 472 473/* The one and only one */ 474static 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 484static int hv_ptp_enable(struct ptp_clock_info *info, 485 struct ptp_clock_request *request, int on) 486{ 487 return -EOPNOTSUPP; 488} 489 490static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts) 491{ 492 return -EOPNOTSUPP; 493} 494 495static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta) 496{ 497 return -EOPNOTSUPP; 498} 499static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 500{ 501 return -EOPNOTSUPP; 502} 503 504static 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 511static 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 521static struct ptp_clock *hv_ptp_clock; 522 523static 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 548static 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 555static 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 562static void exit_hyperv_utils(void) 563{ 564 pr_info("De-Registered HyperV Utility Driver\n"); 565 566 vmbus_driver_unregister(&util_drv); 567} 568 569module_init(init_hyperv_utils); 570module_exit(exit_hyperv_utils); 571 572MODULE_DESCRIPTION("Hyper-V Utilities"); 573MODULE_LICENSE("GPL");