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 <asm/mshyperv.h> |
21 | |
22 | #include "hyperv_vmbus.h" |
23 | |
24 | #define SD_MAJOR 3 |
25 | #define SD_MINOR 0 |
26 | #define SD_MINOR_1 1 |
27 | #define SD_MINOR_2 2 |
28 | #define SD_VERSION_3_1 (SD_MAJOR << 16 | SD_MINOR_1) |
29 | #define SD_VERSION_3_2 (SD_MAJOR << 16 | SD_MINOR_2) |
30 | #define SD_VERSION (SD_MAJOR << 16 | SD_MINOR) |
31 | |
32 | #define SD_MAJOR_1 1 |
33 | #define SD_VERSION_1 (SD_MAJOR_1 << 16 | SD_MINOR) |
34 | |
35 | #define TS_MAJOR 4 |
36 | #define TS_MINOR 0 |
37 | #define TS_VERSION (TS_MAJOR << 16 | TS_MINOR) |
38 | |
39 | #define TS_MAJOR_1 1 |
40 | #define TS_VERSION_1 (TS_MAJOR_1 << 16 | TS_MINOR) |
41 | |
42 | #define TS_MAJOR_3 3 |
43 | #define TS_VERSION_3 (TS_MAJOR_3 << 16 | TS_MINOR) |
44 | |
45 | #define HB_MAJOR 3 |
46 | #define HB_MINOR 0 |
47 | #define HB_VERSION (HB_MAJOR << 16 | HB_MINOR) |
48 | |
49 | #define HB_MAJOR_1 1 |
50 | #define HB_VERSION_1 (HB_MAJOR_1 << 16 | HB_MINOR) |
51 | |
52 | static int sd_srv_version; |
53 | static int ts_srv_version; |
54 | static int hb_srv_version; |
55 | |
56 | #define SD_VER_COUNT 4 |
57 | static const int sd_versions[] = { |
58 | SD_VERSION_3_2, |
59 | SD_VERSION_3_1, |
60 | SD_VERSION, |
61 | SD_VERSION_1 |
62 | }; |
63 | |
64 | #define TS_VER_COUNT 3 |
65 | static const int ts_versions[] = { |
66 | TS_VERSION, |
67 | TS_VERSION_3, |
68 | TS_VERSION_1 |
69 | }; |
70 | |
71 | #define HB_VER_COUNT 2 |
72 | static const int hb_versions[] = { |
73 | HB_VERSION, |
74 | HB_VERSION_1 |
75 | }; |
76 | |
77 | #define FW_VER_COUNT 2 |
78 | static const int fw_versions[] = { |
79 | UTIL_FW_VERSION, |
80 | UTIL_WS2K8_FW_VERSION |
81 | }; |
82 | |
83 | /* |
84 | * Send the "hibernate" udev event in a thread context. |
85 | */ |
86 | struct hibernate_work_context { |
87 | struct work_struct work; |
88 | struct hv_device *dev; |
89 | }; |
90 | |
91 | static struct hibernate_work_context hibernate_context; |
92 | static bool hibernation_supported; |
93 | |
94 | static void send_hibernate_uevent(struct work_struct *work) |
95 | { |
96 | char *uevent_env[2] = { "EVENT=hibernate" , NULL }; |
97 | struct hibernate_work_context *ctx; |
98 | |
99 | ctx = container_of(work, struct hibernate_work_context, work); |
100 | |
101 | kobject_uevent_env(kobj: &ctx->dev->device.kobj, action: KOBJ_CHANGE, envp: uevent_env); |
102 | |
103 | pr_info("Sent hibernation uevent\n" ); |
104 | } |
105 | |
106 | static int hv_shutdown_init(struct hv_util_service *srv) |
107 | { |
108 | struct vmbus_channel *channel = srv->channel; |
109 | |
110 | INIT_WORK(&hibernate_context.work, send_hibernate_uevent); |
111 | hibernate_context.dev = channel->device_obj; |
112 | |
113 | hibernation_supported = hv_is_hibernation_supported(); |
114 | |
115 | return 0; |
116 | } |
117 | |
118 | static void shutdown_onchannelcallback(void *context); |
119 | static struct hv_util_service util_shutdown = { |
120 | .util_cb = shutdown_onchannelcallback, |
121 | .util_init = hv_shutdown_init, |
122 | }; |
123 | |
124 | static int hv_timesync_init(struct hv_util_service *srv); |
125 | static int hv_timesync_pre_suspend(void); |
126 | static void hv_timesync_deinit(void); |
127 | |
128 | static void timesync_onchannelcallback(void *context); |
129 | static struct hv_util_service util_timesynch = { |
130 | .util_cb = timesync_onchannelcallback, |
131 | .util_init = hv_timesync_init, |
132 | .util_pre_suspend = hv_timesync_pre_suspend, |
133 | .util_deinit = hv_timesync_deinit, |
134 | }; |
135 | |
136 | static void heartbeat_onchannelcallback(void *context); |
137 | static struct hv_util_service util_heartbeat = { |
138 | .util_cb = heartbeat_onchannelcallback, |
139 | }; |
140 | |
141 | static struct hv_util_service util_kvp = { |
142 | .util_cb = hv_kvp_onchannelcallback, |
143 | .util_init = hv_kvp_init, |
144 | .util_pre_suspend = hv_kvp_pre_suspend, |
145 | .util_pre_resume = hv_kvp_pre_resume, |
146 | .util_deinit = hv_kvp_deinit, |
147 | }; |
148 | |
149 | static struct hv_util_service util_vss = { |
150 | .util_cb = hv_vss_onchannelcallback, |
151 | .util_init = hv_vss_init, |
152 | .util_pre_suspend = hv_vss_pre_suspend, |
153 | .util_pre_resume = hv_vss_pre_resume, |
154 | .util_deinit = hv_vss_deinit, |
155 | }; |
156 | |
157 | static struct hv_util_service util_fcopy = { |
158 | .util_cb = hv_fcopy_onchannelcallback, |
159 | .util_init = hv_fcopy_init, |
160 | .util_pre_suspend = hv_fcopy_pre_suspend, |
161 | .util_pre_resume = hv_fcopy_pre_resume, |
162 | .util_deinit = hv_fcopy_deinit, |
163 | }; |
164 | |
165 | static void perform_shutdown(struct work_struct *dummy) |
166 | { |
167 | orderly_poweroff(force: true); |
168 | } |
169 | |
170 | static void perform_restart(struct work_struct *dummy) |
171 | { |
172 | orderly_reboot(); |
173 | } |
174 | |
175 | /* |
176 | * Perform the shutdown operation in a thread context. |
177 | */ |
178 | static DECLARE_WORK(shutdown_work, perform_shutdown); |
179 | |
180 | /* |
181 | * Perform the restart operation in a thread context. |
182 | */ |
183 | static DECLARE_WORK(restart_work, perform_restart); |
184 | |
185 | static void shutdown_onchannelcallback(void *context) |
186 | { |
187 | struct vmbus_channel *channel = context; |
188 | struct work_struct *work = NULL; |
189 | u32 recvlen; |
190 | u64 requestid; |
191 | u8 *shut_txf_buf = util_shutdown.recv_buffer; |
192 | |
193 | struct shutdown_msg_data *shutdown_msg; |
194 | |
195 | struct icmsg_hdr *icmsghdrp; |
196 | |
197 | if (vmbus_recvpacket(channel, buffer: shut_txf_buf, HV_HYP_PAGE_SIZE, buffer_actual_len: &recvlen, requestid: &requestid)) { |
198 | pr_err_ratelimited("Shutdown request received. Could not read into shut txf buf\n" ); |
199 | return; |
200 | } |
201 | |
202 | if (!recvlen) |
203 | return; |
204 | |
205 | /* Ensure recvlen is big enough to read header data */ |
206 | if (recvlen < ICMSG_HDR) { |
207 | pr_err_ratelimited("Shutdown request received. Packet length too small: %d\n" , |
208 | recvlen); |
209 | return; |
210 | } |
211 | |
212 | icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[sizeof(struct vmbuspipe_hdr)]; |
213 | |
214 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { |
215 | if (vmbus_prep_negotiate_resp(icmsghdrp, |
216 | buf: shut_txf_buf, buflen: recvlen, |
217 | fw_version: fw_versions, FW_VER_COUNT, |
218 | srv_version: sd_versions, SD_VER_COUNT, |
219 | NULL, nego_srv_version: &sd_srv_version)) { |
220 | pr_info("Shutdown IC version %d.%d\n" , |
221 | sd_srv_version >> 16, |
222 | sd_srv_version & 0xFFFF); |
223 | } |
224 | } else if (icmsghdrp->icmsgtype == ICMSGTYPE_SHUTDOWN) { |
225 | /* Ensure recvlen is big enough to contain shutdown_msg_data struct */ |
226 | if (recvlen < ICMSG_HDR + sizeof(struct shutdown_msg_data)) { |
227 | pr_err_ratelimited("Invalid shutdown msg data. Packet length too small: %u\n" , |
228 | recvlen); |
229 | return; |
230 | } |
231 | |
232 | shutdown_msg = (struct shutdown_msg_data *)&shut_txf_buf[ICMSG_HDR]; |
233 | |
234 | /* |
235 | * shutdown_msg->flags can be 0(shut down), 2(reboot), |
236 | * or 4(hibernate). It may bitwise-OR 1, which means |
237 | * performing the request by force. Linux always tries |
238 | * to perform the request by force. |
239 | */ |
240 | switch (shutdown_msg->flags) { |
241 | case 0: |
242 | case 1: |
243 | icmsghdrp->status = HV_S_OK; |
244 | work = &shutdown_work; |
245 | pr_info("Shutdown request received - graceful shutdown initiated\n" ); |
246 | break; |
247 | case 2: |
248 | case 3: |
249 | icmsghdrp->status = HV_S_OK; |
250 | work = &restart_work; |
251 | pr_info("Restart request received - graceful restart initiated\n" ); |
252 | break; |
253 | case 4: |
254 | case 5: |
255 | pr_info("Hibernation request received\n" ); |
256 | icmsghdrp->status = hibernation_supported ? |
257 | HV_S_OK : HV_E_FAIL; |
258 | if (hibernation_supported) |
259 | work = &hibernate_context.work; |
260 | break; |
261 | default: |
262 | icmsghdrp->status = HV_E_FAIL; |
263 | pr_info("Shutdown request received - Invalid request\n" ); |
264 | break; |
265 | } |
266 | } else { |
267 | icmsghdrp->status = HV_E_FAIL; |
268 | pr_err_ratelimited("Shutdown request received. Invalid msg type: %d\n" , |
269 | icmsghdrp->icmsgtype); |
270 | } |
271 | |
272 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
273 | | ICMSGHDRFLAG_RESPONSE; |
274 | |
275 | vmbus_sendpacket(channel, buffer: shut_txf_buf, |
276 | bufferLen: recvlen, requestid, |
277 | type: VM_PKT_DATA_INBAND, flags: 0); |
278 | |
279 | if (work) |
280 | schedule_work(work); |
281 | } |
282 | |
283 | /* |
284 | * Set the host time in a process context. |
285 | */ |
286 | static struct work_struct adj_time_work; |
287 | |
288 | /* |
289 | * The last time sample, received from the host. PTP device responds to |
290 | * requests by using this data and the current partition-wide time reference |
291 | * count. |
292 | */ |
293 | static struct { |
294 | u64 host_time; |
295 | u64 ref_time; |
296 | spinlock_t lock; |
297 | } host_ts; |
298 | |
299 | static inline u64 reftime_to_ns(u64 reftime) |
300 | { |
301 | return (reftime - WLTIMEDELTA) * 100; |
302 | } |
303 | |
304 | /* |
305 | * Hard coded threshold for host timesync delay: 600 seconds |
306 | */ |
307 | static const u64 HOST_TIMESYNC_DELAY_THRESH = 600 * (u64)NSEC_PER_SEC; |
308 | |
309 | static int hv_get_adj_host_time(struct timespec64 *ts) |
310 | { |
311 | u64 newtime, reftime, timediff_adj; |
312 | unsigned long flags; |
313 | int ret = 0; |
314 | |
315 | spin_lock_irqsave(&host_ts.lock, flags); |
316 | reftime = hv_read_reference_counter(); |
317 | |
318 | /* |
319 | * We need to let the caller know that last update from host |
320 | * is older than the max allowable threshold. clock_gettime() |
321 | * and PTP ioctl do not have a documented error that we could |
322 | * return for this specific case. Use ESTALE to report this. |
323 | */ |
324 | timediff_adj = reftime - host_ts.ref_time; |
325 | if (timediff_adj * 100 > HOST_TIMESYNC_DELAY_THRESH) { |
326 | pr_warn_once("TIMESYNC IC: Stale time stamp, %llu nsecs old\n" , |
327 | (timediff_adj * 100)); |
328 | ret = -ESTALE; |
329 | } |
330 | |
331 | newtime = host_ts.host_time + timediff_adj; |
332 | *ts = ns_to_timespec64(nsec: reftime_to_ns(reftime: newtime)); |
333 | spin_unlock_irqrestore(lock: &host_ts.lock, flags); |
334 | |
335 | return ret; |
336 | } |
337 | |
338 | static void hv_set_host_time(struct work_struct *work) |
339 | { |
340 | |
341 | struct timespec64 ts; |
342 | |
343 | if (!hv_get_adj_host_time(ts: &ts)) |
344 | do_settimeofday64(ts: &ts); |
345 | } |
346 | |
347 | /* |
348 | * Synchronize time with host after reboot, restore, etc. |
349 | * |
350 | * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM. |
351 | * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time |
352 | * message after the timesync channel is opened. Since the hv_utils module is |
353 | * loaded after hv_vmbus, the first message is usually missed. This bit is |
354 | * considered a hard request to discipline the clock. |
355 | * |
356 | * ICTIMESYNCFLAG_SAMPLE bit indicates a time sample from host. This is |
357 | * typically used as a hint to the guest. The guest is under no obligation |
358 | * to discipline the clock. |
359 | */ |
360 | static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags) |
361 | { |
362 | unsigned long flags; |
363 | u64 cur_reftime; |
364 | |
365 | /* |
366 | * Save the adjusted time sample from the host and the snapshot |
367 | * of the current system time. |
368 | */ |
369 | spin_lock_irqsave(&host_ts.lock, flags); |
370 | |
371 | cur_reftime = hv_read_reference_counter(); |
372 | host_ts.host_time = hosttime; |
373 | host_ts.ref_time = cur_reftime; |
374 | |
375 | /* |
376 | * TimeSync v4 messages contain reference time (guest's Hyper-V |
377 | * clocksource read when the time sample was generated), we can |
378 | * improve the precision by adding the delta between now and the |
379 | * time of generation. For older protocols we set |
380 | * reftime == cur_reftime on call. |
381 | */ |
382 | host_ts.host_time += (cur_reftime - reftime); |
383 | |
384 | spin_unlock_irqrestore(lock: &host_ts.lock, flags); |
385 | |
386 | /* Schedule work to do do_settimeofday64() */ |
387 | if (adj_flags & ICTIMESYNCFLAG_SYNC) |
388 | schedule_work(work: &adj_time_work); |
389 | } |
390 | |
391 | /* |
392 | * Time Sync Channel message handler. |
393 | */ |
394 | static void timesync_onchannelcallback(void *context) |
395 | { |
396 | struct vmbus_channel *channel = context; |
397 | u32 recvlen; |
398 | u64 requestid; |
399 | struct icmsg_hdr *icmsghdrp; |
400 | struct ictimesync_data *timedatap; |
401 | struct ictimesync_ref_data *refdata; |
402 | u8 *time_txf_buf = util_timesynch.recv_buffer; |
403 | |
404 | /* |
405 | * Drain the ring buffer and use the last packet to update |
406 | * host_ts |
407 | */ |
408 | while (1) { |
409 | int ret = vmbus_recvpacket(channel, buffer: time_txf_buf, |
410 | HV_HYP_PAGE_SIZE, buffer_actual_len: &recvlen, |
411 | requestid: &requestid); |
412 | if (ret) { |
413 | pr_err_ratelimited("TimeSync IC pkt recv failed (Err: %d)\n" , |
414 | ret); |
415 | break; |
416 | } |
417 | |
418 | if (!recvlen) |
419 | break; |
420 | |
421 | /* Ensure recvlen is big enough to read header data */ |
422 | if (recvlen < ICMSG_HDR) { |
423 | pr_err_ratelimited("Timesync request received. Packet length too small: %d\n" , |
424 | recvlen); |
425 | break; |
426 | } |
427 | |
428 | icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[ |
429 | sizeof(struct vmbuspipe_hdr)]; |
430 | |
431 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { |
432 | if (vmbus_prep_negotiate_resp(icmsghdrp, |
433 | buf: time_txf_buf, buflen: recvlen, |
434 | fw_version: fw_versions, FW_VER_COUNT, |
435 | srv_version: ts_versions, TS_VER_COUNT, |
436 | NULL, nego_srv_version: &ts_srv_version)) { |
437 | pr_info("TimeSync IC version %d.%d\n" , |
438 | ts_srv_version >> 16, |
439 | ts_srv_version & 0xFFFF); |
440 | } |
441 | } else if (icmsghdrp->icmsgtype == ICMSGTYPE_TIMESYNC) { |
442 | if (ts_srv_version > TS_VERSION_3) { |
443 | /* Ensure recvlen is big enough to read ictimesync_ref_data */ |
444 | if (recvlen < ICMSG_HDR + sizeof(struct ictimesync_ref_data)) { |
445 | pr_err_ratelimited("Invalid ictimesync ref data. Length too small: %u\n" , |
446 | recvlen); |
447 | break; |
448 | } |
449 | refdata = (struct ictimesync_ref_data *)&time_txf_buf[ICMSG_HDR]; |
450 | |
451 | adj_guesttime(hosttime: refdata->parenttime, |
452 | reftime: refdata->vmreferencetime, |
453 | adj_flags: refdata->flags); |
454 | } else { |
455 | /* Ensure recvlen is big enough to read ictimesync_data */ |
456 | if (recvlen < ICMSG_HDR + sizeof(struct ictimesync_data)) { |
457 | pr_err_ratelimited("Invalid ictimesync data. Length too small: %u\n" , |
458 | recvlen); |
459 | break; |
460 | } |
461 | timedatap = (struct ictimesync_data *)&time_txf_buf[ICMSG_HDR]; |
462 | |
463 | adj_guesttime(hosttime: timedatap->parenttime, |
464 | reftime: hv_read_reference_counter(), |
465 | adj_flags: timedatap->flags); |
466 | } |
467 | } else { |
468 | icmsghdrp->status = HV_E_FAIL; |
469 | pr_err_ratelimited("Timesync request received. Invalid msg type: %d\n" , |
470 | icmsghdrp->icmsgtype); |
471 | } |
472 | |
473 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
474 | | ICMSGHDRFLAG_RESPONSE; |
475 | |
476 | vmbus_sendpacket(channel, buffer: time_txf_buf, |
477 | bufferLen: recvlen, requestid, |
478 | type: VM_PKT_DATA_INBAND, flags: 0); |
479 | } |
480 | } |
481 | |
482 | /* |
483 | * Heartbeat functionality. |
484 | * Every two seconds, Hyper-V send us a heartbeat request message. |
485 | * we respond to this message, and Hyper-V knows we are alive. |
486 | */ |
487 | static void heartbeat_onchannelcallback(void *context) |
488 | { |
489 | struct vmbus_channel *channel = context; |
490 | u32 recvlen; |
491 | u64 requestid; |
492 | struct icmsg_hdr *icmsghdrp; |
493 | struct heartbeat_msg_data *heartbeat_msg; |
494 | u8 *hbeat_txf_buf = util_heartbeat.recv_buffer; |
495 | |
496 | while (1) { |
497 | |
498 | if (vmbus_recvpacket(channel, buffer: hbeat_txf_buf, HV_HYP_PAGE_SIZE, |
499 | buffer_actual_len: &recvlen, requestid: &requestid)) { |
500 | pr_err_ratelimited("Heartbeat request received. Could not read into hbeat txf buf\n" ); |
501 | return; |
502 | } |
503 | |
504 | if (!recvlen) |
505 | break; |
506 | |
507 | /* Ensure recvlen is big enough to read header data */ |
508 | if (recvlen < ICMSG_HDR) { |
509 | pr_err_ratelimited("Heartbeat request received. Packet length too small: %d\n" , |
510 | recvlen); |
511 | break; |
512 | } |
513 | |
514 | icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[ |
515 | sizeof(struct vmbuspipe_hdr)]; |
516 | |
517 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { |
518 | if (vmbus_prep_negotiate_resp(icmsghdrp, |
519 | buf: hbeat_txf_buf, buflen: recvlen, |
520 | fw_version: fw_versions, FW_VER_COUNT, |
521 | srv_version: hb_versions, HB_VER_COUNT, |
522 | NULL, nego_srv_version: &hb_srv_version)) { |
523 | |
524 | pr_info("Heartbeat IC version %d.%d\n" , |
525 | hb_srv_version >> 16, |
526 | hb_srv_version & 0xFFFF); |
527 | } |
528 | } else if (icmsghdrp->icmsgtype == ICMSGTYPE_HEARTBEAT) { |
529 | /* |
530 | * Ensure recvlen is big enough to read seq_num. Reserved area is not |
531 | * included in the check as the host may not fill it up entirely |
532 | */ |
533 | if (recvlen < ICMSG_HDR + sizeof(u64)) { |
534 | pr_err_ratelimited("Invalid heartbeat msg data. Length too small: %u\n" , |
535 | recvlen); |
536 | break; |
537 | } |
538 | heartbeat_msg = (struct heartbeat_msg_data *)&hbeat_txf_buf[ICMSG_HDR]; |
539 | |
540 | heartbeat_msg->seq_num += 1; |
541 | } else { |
542 | icmsghdrp->status = HV_E_FAIL; |
543 | pr_err_ratelimited("Heartbeat request received. Invalid msg type: %d\n" , |
544 | icmsghdrp->icmsgtype); |
545 | } |
546 | |
547 | icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION |
548 | | ICMSGHDRFLAG_RESPONSE; |
549 | |
550 | vmbus_sendpacket(channel, buffer: hbeat_txf_buf, |
551 | bufferLen: recvlen, requestid, |
552 | type: VM_PKT_DATA_INBAND, flags: 0); |
553 | } |
554 | } |
555 | |
556 | #define HV_UTIL_RING_SEND_SIZE VMBUS_RING_SIZE(3 * HV_HYP_PAGE_SIZE) |
557 | #define HV_UTIL_RING_RECV_SIZE VMBUS_RING_SIZE(3 * HV_HYP_PAGE_SIZE) |
558 | |
559 | static int util_probe(struct hv_device *dev, |
560 | const struct hv_vmbus_device_id *dev_id) |
561 | { |
562 | struct hv_util_service *srv = |
563 | (struct hv_util_service *)dev_id->driver_data; |
564 | int ret; |
565 | |
566 | srv->recv_buffer = kmalloc(HV_HYP_PAGE_SIZE * 4, GFP_KERNEL); |
567 | if (!srv->recv_buffer) |
568 | return -ENOMEM; |
569 | srv->channel = dev->channel; |
570 | if (srv->util_init) { |
571 | ret = srv->util_init(srv); |
572 | if (ret) { |
573 | ret = -ENODEV; |
574 | goto error1; |
575 | } |
576 | } |
577 | |
578 | /* |
579 | * The set of services managed by the util driver are not performance |
580 | * critical and do not need batched reading. Furthermore, some services |
581 | * such as KVP can only handle one message from the host at a time. |
582 | * Turn off batched reading for all util drivers before we open the |
583 | * channel. |
584 | */ |
585 | set_channel_read_mode(c: dev->channel, mode: HV_CALL_DIRECT); |
586 | |
587 | hv_set_drvdata(dev, data: srv); |
588 | |
589 | ret = vmbus_open(channel: dev->channel, HV_UTIL_RING_SEND_SIZE, |
590 | HV_UTIL_RING_RECV_SIZE, NULL, userdatalen: 0, onchannel_callback: srv->util_cb, |
591 | context: dev->channel); |
592 | if (ret) |
593 | goto error; |
594 | |
595 | return 0; |
596 | |
597 | error: |
598 | if (srv->util_deinit) |
599 | srv->util_deinit(); |
600 | error1: |
601 | kfree(objp: srv->recv_buffer); |
602 | return ret; |
603 | } |
604 | |
605 | static void util_remove(struct hv_device *dev) |
606 | { |
607 | struct hv_util_service *srv = hv_get_drvdata(dev); |
608 | |
609 | if (srv->util_deinit) |
610 | srv->util_deinit(); |
611 | vmbus_close(channel: dev->channel); |
612 | kfree(objp: srv->recv_buffer); |
613 | } |
614 | |
615 | /* |
616 | * When we're in util_suspend(), all the userspace processes have been frozen |
617 | * (refer to hibernate() -> freeze_processes()). The userspace is thawed only |
618 | * after the whole resume procedure, including util_resume(), finishes. |
619 | */ |
620 | static int util_suspend(struct hv_device *dev) |
621 | { |
622 | struct hv_util_service *srv = hv_get_drvdata(dev); |
623 | int ret = 0; |
624 | |
625 | if (srv->util_pre_suspend) { |
626 | ret = srv->util_pre_suspend(); |
627 | if (ret) |
628 | return ret; |
629 | } |
630 | |
631 | vmbus_close(channel: dev->channel); |
632 | |
633 | return 0; |
634 | } |
635 | |
636 | static int util_resume(struct hv_device *dev) |
637 | { |
638 | struct hv_util_service *srv = hv_get_drvdata(dev); |
639 | int ret = 0; |
640 | |
641 | if (srv->util_pre_resume) { |
642 | ret = srv->util_pre_resume(); |
643 | if (ret) |
644 | return ret; |
645 | } |
646 | |
647 | ret = vmbus_open(channel: dev->channel, HV_UTIL_RING_SEND_SIZE, |
648 | HV_UTIL_RING_RECV_SIZE, NULL, userdatalen: 0, onchannel_callback: srv->util_cb, |
649 | context: dev->channel); |
650 | return ret; |
651 | } |
652 | |
653 | static const struct hv_vmbus_device_id id_table[] = { |
654 | /* Shutdown guid */ |
655 | { HV_SHUTDOWN_GUID, |
656 | .driver_data = (unsigned long)&util_shutdown |
657 | }, |
658 | /* Time synch guid */ |
659 | { HV_TS_GUID, |
660 | .driver_data = (unsigned long)&util_timesynch |
661 | }, |
662 | /* Heartbeat guid */ |
663 | { HV_HEART_BEAT_GUID, |
664 | .driver_data = (unsigned long)&util_heartbeat |
665 | }, |
666 | /* KVP guid */ |
667 | { HV_KVP_GUID, |
668 | .driver_data = (unsigned long)&util_kvp |
669 | }, |
670 | /* VSS GUID */ |
671 | { HV_VSS_GUID, |
672 | .driver_data = (unsigned long)&util_vss |
673 | }, |
674 | /* File copy GUID */ |
675 | { HV_FCOPY_GUID, |
676 | .driver_data = (unsigned long)&util_fcopy |
677 | }, |
678 | { }, |
679 | }; |
680 | |
681 | MODULE_DEVICE_TABLE(vmbus, id_table); |
682 | |
683 | /* The one and only one */ |
684 | static struct hv_driver util_drv = { |
685 | .name = "hv_utils" , |
686 | .id_table = id_table, |
687 | .probe = util_probe, |
688 | .remove = util_remove, |
689 | .suspend = util_suspend, |
690 | .resume = util_resume, |
691 | .driver = { |
692 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
693 | }, |
694 | }; |
695 | |
696 | static int hv_ptp_enable(struct ptp_clock_info *info, |
697 | struct ptp_clock_request *request, int on) |
698 | { |
699 | return -EOPNOTSUPP; |
700 | } |
701 | |
702 | static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts) |
703 | { |
704 | return -EOPNOTSUPP; |
705 | } |
706 | |
707 | static int hv_ptp_adjfine(struct ptp_clock_info *ptp, long delta) |
708 | { |
709 | return -EOPNOTSUPP; |
710 | } |
711 | static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) |
712 | { |
713 | return -EOPNOTSUPP; |
714 | } |
715 | |
716 | static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts) |
717 | { |
718 | return hv_get_adj_host_time(ts); |
719 | } |
720 | |
721 | static struct ptp_clock_info ptp_hyperv_info = { |
722 | .name = "hyperv" , |
723 | .enable = hv_ptp_enable, |
724 | .adjtime = hv_ptp_adjtime, |
725 | .adjfine = hv_ptp_adjfine, |
726 | .gettime64 = hv_ptp_gettime, |
727 | .settime64 = hv_ptp_settime, |
728 | .owner = THIS_MODULE, |
729 | }; |
730 | |
731 | static struct ptp_clock *hv_ptp_clock; |
732 | |
733 | static int hv_timesync_init(struct hv_util_service *srv) |
734 | { |
735 | spin_lock_init(&host_ts.lock); |
736 | |
737 | INIT_WORK(&adj_time_work, hv_set_host_time); |
738 | |
739 | /* |
740 | * ptp_clock_register() returns NULL when CONFIG_PTP_1588_CLOCK is |
741 | * disabled but the driver is still useful without the PTP device |
742 | * as it still handles the ICTIMESYNCFLAG_SYNC case. |
743 | */ |
744 | hv_ptp_clock = ptp_clock_register(info: &ptp_hyperv_info, NULL); |
745 | if (IS_ERR_OR_NULL(ptr: hv_ptp_clock)) { |
746 | pr_err("cannot register PTP clock: %d\n" , |
747 | PTR_ERR_OR_ZERO(hv_ptp_clock)); |
748 | hv_ptp_clock = NULL; |
749 | } |
750 | |
751 | return 0; |
752 | } |
753 | |
754 | static void hv_timesync_cancel_work(void) |
755 | { |
756 | cancel_work_sync(work: &adj_time_work); |
757 | } |
758 | |
759 | static int hv_timesync_pre_suspend(void) |
760 | { |
761 | hv_timesync_cancel_work(); |
762 | return 0; |
763 | } |
764 | |
765 | static void hv_timesync_deinit(void) |
766 | { |
767 | if (hv_ptp_clock) |
768 | ptp_clock_unregister(ptp: hv_ptp_clock); |
769 | |
770 | hv_timesync_cancel_work(); |
771 | } |
772 | |
773 | static int __init init_hyperv_utils(void) |
774 | { |
775 | pr_info("Registering HyperV Utility Driver\n" ); |
776 | |
777 | return vmbus_driver_register(&util_drv); |
778 | } |
779 | |
780 | static void exit_hyperv_utils(void) |
781 | { |
782 | pr_info("De-Registered HyperV Utility Driver\n" ); |
783 | |
784 | vmbus_driver_unregister(hv_driver: &util_drv); |
785 | } |
786 | |
787 | module_init(init_hyperv_utils); |
788 | module_exit(exit_hyperv_utils); |
789 | |
790 | MODULE_DESCRIPTION("Hyper-V Utilities" ); |
791 | MODULE_LICENSE("GPL" ); |
792 | |