ASoC: Intel: bytcht_es8316: Fix Irbis NB41 netbook quirk
[linux/fpc-iii.git] / drivers / hv / hv_util.c
blobe32681ee7b9f6a3119610eef0578e46a153656be
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2010, Microsoft Corporation.
5 * Authors:
6 * Haiyang Zhang <haiyangz@microsoft.com>
7 * Hank Janssen <hjanssen@microsoft.com>
8 */
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
23 #include "hyperv_vmbus.h"
25 #define SD_MAJOR 3
26 #define SD_MINOR 0
27 #define SD_VERSION (SD_MAJOR << 16 | SD_MINOR)
29 #define SD_MAJOR_1 1
30 #define SD_VERSION_1 (SD_MAJOR_1 << 16 | SD_MINOR)
32 #define TS_MAJOR 4
33 #define TS_MINOR 0
34 #define TS_VERSION (TS_MAJOR << 16 | TS_MINOR)
36 #define TS_MAJOR_1 1
37 #define TS_VERSION_1 (TS_MAJOR_1 << 16 | TS_MINOR)
39 #define TS_MAJOR_3 3
40 #define TS_VERSION_3 (TS_MAJOR_3 << 16 | TS_MINOR)
42 #define HB_MAJOR 3
43 #define HB_MINOR 0
44 #define HB_VERSION (HB_MAJOR << 16 | HB_MINOR)
46 #define HB_MAJOR_1 1
47 #define HB_VERSION_1 (HB_MAJOR_1 << 16 | HB_MINOR)
49 static int sd_srv_version;
50 static int ts_srv_version;
51 static int hb_srv_version;
53 #define SD_VER_COUNT 2
54 static const int sd_versions[] = {
55 SD_VERSION,
56 SD_VERSION_1
59 #define TS_VER_COUNT 3
60 static const int ts_versions[] = {
61 TS_VERSION,
62 TS_VERSION_3,
63 TS_VERSION_1
66 #define HB_VER_COUNT 2
67 static const int hb_versions[] = {
68 HB_VERSION,
69 HB_VERSION_1
72 #define FW_VER_COUNT 2
73 static const int fw_versions[] = {
74 UTIL_FW_VERSION,
75 UTIL_WS2K8_FW_VERSION
78 static void shutdown_onchannelcallback(void *context);
79 static struct hv_util_service util_shutdown = {
80 .util_cb = shutdown_onchannelcallback,
83 static int hv_timesync_init(struct hv_util_service *srv);
84 static void hv_timesync_deinit(void);
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,
93 static void heartbeat_onchannelcallback(void *context);
94 static struct hv_util_service util_heartbeat = {
95 .util_cb = heartbeat_onchannelcallback,
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,
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,
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,
116 static void perform_shutdown(struct work_struct *dummy)
118 orderly_poweroff(true);
122 * Perform the shutdown operation in a thread context.
124 static DECLARE_WORK(shutdown_work, perform_shutdown);
126 static void shutdown_onchannelcallback(void *context)
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;
134 struct shutdown_msg_data *shutdown_msg;
136 struct icmsg_hdr *icmsghdrp;
138 vmbus_recvpacket(channel, shut_txf_buf,
139 PAGE_SIZE, &recvlen, &requestid);
141 if (recvlen > 0) {
142 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
143 sizeof(struct vmbuspipe_hdr)];
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);
154 } else {
155 shutdown_msg =
156 (struct shutdown_msg_data *)&shut_txf_buf[
157 sizeof(struct vmbuspipe_hdr) +
158 sizeof(struct icmsg_hdr)];
160 switch (shutdown_msg->flags) {
161 case 0:
162 case 1:
163 icmsghdrp->status = HV_S_OK;
164 execute_shutdown = true;
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;
173 pr_info("Shutdown request received -"
174 " Invalid request\n");
175 break;
179 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
180 | ICMSGHDRFLAG_RESPONSE;
182 vmbus_sendpacket(channel, shut_txf_buf,
183 recvlen, requestid,
184 VM_PKT_DATA_INBAND, 0);
187 if (execute_shutdown == true)
188 schedule_work(&shutdown_work);
192 * Set the host time in a process context.
194 static struct work_struct adj_time_work;
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.
201 static struct {
202 u64 host_time;
203 u64 ref_time;
204 spinlock_t lock;
205 } host_ts;
207 static struct timespec64 hv_get_adj_host_time(void)
209 struct timespec64 ts;
210 u64 newtime, reftime;
211 unsigned long flags;
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);
219 return ts;
222 static void hv_set_host_time(struct work_struct *work)
224 struct timespec64 ts = hv_get_adj_host_time();
226 do_settimeofday64(&ts);
230 * Synchronize time with host after reboot, restore, etc.
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.
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.
242 static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags)
244 unsigned long flags;
245 u64 cur_reftime;
248 * Save the adjusted time sample from the host and the snapshot
249 * of the current system time.
251 spin_lock_irqsave(&host_ts.lock, flags);
253 cur_reftime = hyperv_cs->read(hyperv_cs);
254 host_ts.host_time = hosttime;
255 host_ts.ref_time = cur_reftime;
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.
264 host_ts.host_time += (cur_reftime - reftime);
266 spin_unlock_irqrestore(&host_ts.lock, flags);
268 /* Schedule work to do do_settimeofday64() */
269 if (adj_flags & ICTIMESYNCFLAG_SYNC)
270 schedule_work(&adj_time_work);
274 * Time Sync Channel message handler.
276 static void timesync_onchannelcallback(void *context)
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;
286 vmbus_recvpacket(channel, time_txf_buf,
287 PAGE_SIZE, &recvlen, &requestid);
289 if (recvlen > 0) {
290 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
291 sizeof(struct vmbuspipe_hdr)];
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);
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)];
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);
323 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
324 | ICMSGHDRFLAG_RESPONSE;
326 vmbus_sendpacket(channel, time_txf_buf,
327 recvlen, requestid,
328 VM_PKT_DATA_INBAND, 0);
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.
337 static void heartbeat_onchannelcallback(void *context)
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;
346 while (1) {
348 vmbus_recvpacket(channel, hbeat_txf_buf,
349 PAGE_SIZE, &recvlen, &requestid);
351 if (!recvlen)
352 break;
354 icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
355 sizeof(struct vmbuspipe_hdr)];
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)) {
364 pr_info("Heartbeat IC version %d.%d\n",
365 hb_srv_version >> 16,
366 hb_srv_version & 0xFFFF);
368 } else {
369 heartbeat_msg =
370 (struct heartbeat_msg_data *)&hbeat_txf_buf[
371 sizeof(struct vmbuspipe_hdr) +
372 sizeof(struct icmsg_hdr)];
374 heartbeat_msg->seq_num += 1;
377 icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
378 | ICMSGHDRFLAG_RESPONSE;
380 vmbus_sendpacket(channel, hbeat_txf_buf,
381 recvlen, requestid,
382 VM_PKT_DATA_INBAND, 0);
386 static int util_probe(struct hv_device *dev,
387 const struct hv_vmbus_device_id *dev_id)
389 struct hv_util_service *srv =
390 (struct hv_util_service *)dev_id->driver_data;
391 int ret;
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;
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.
412 set_channel_read_mode(dev->channel, HV_CALL_DIRECT);
414 hv_set_drvdata(dev, srv);
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;
421 return 0;
423 error:
424 if (srv->util_deinit)
425 srv->util_deinit();
426 error1:
427 kfree(srv->recv_buffer);
428 return ret;
431 static int util_remove(struct hv_device *dev)
433 struct hv_util_service *srv = hv_get_drvdata(dev);
435 if (srv->util_deinit)
436 srv->util_deinit();
437 vmbus_close(dev->channel);
438 kfree(srv->recv_buffer);
440 return 0;
443 static const struct hv_vmbus_device_id id_table[] = {
444 /* Shutdown guid */
445 { HV_SHUTDOWN_GUID,
446 .driver_data = (unsigned long)&util_shutdown
448 /* Time synch guid */
449 { HV_TS_GUID,
450 .driver_data = (unsigned long)&util_timesynch
452 /* Heartbeat guid */
453 { HV_HEART_BEAT_GUID,
454 .driver_data = (unsigned long)&util_heartbeat
456 /* KVP guid */
457 { HV_KVP_GUID,
458 .driver_data = (unsigned long)&util_kvp
460 /* VSS GUID */
461 { HV_VSS_GUID,
462 .driver_data = (unsigned long)&util_vss
464 /* File copy GUID */
465 { HV_FCOPY_GUID,
466 .driver_data = (unsigned long)&util_fcopy
468 { },
471 MODULE_DEVICE_TABLE(vmbus, id_table);
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,
484 static int hv_ptp_enable(struct ptp_clock_info *info,
485 struct ptp_clock_request *request, int on)
487 return -EOPNOTSUPP;
490 static int hv_ptp_settime(struct ptp_clock_info *p, const struct timespec64 *ts)
492 return -EOPNOTSUPP;
495 static int hv_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
497 return -EOPNOTSUPP;
499 static int hv_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
501 return -EOPNOTSUPP;
504 static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
506 *ts = hv_get_adj_host_time();
508 return 0;
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,
521 static struct ptp_clock *hv_ptp_clock;
523 static int hv_timesync_init(struct hv_util_service *srv)
525 /* TimeSync requires Hyper-V clocksource. */
526 if (!hyperv_cs)
527 return -ENODEV;
529 spin_lock_init(&host_ts.lock);
531 INIT_WORK(&adj_time_work, hv_set_host_time);
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.
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;
545 return 0;
548 static void hv_timesync_deinit(void)
550 if (hv_ptp_clock)
551 ptp_clock_unregister(hv_ptp_clock);
552 cancel_work_sync(&adj_time_work);
555 static int __init init_hyperv_utils(void)
557 pr_info("Registering HyperV Utility Driver\n");
559 return vmbus_driver_register(&util_drv);
562 static void exit_hyperv_utils(void)
564 pr_info("De-Registered HyperV Utility Driver\n");
566 vmbus_driver_unregister(&util_drv);
569 module_init(init_hyperv_utils);
570 module_exit(exit_hyperv_utils);
572 MODULE_DESCRIPTION("Hyper-V Utilities");
573 MODULE_LICENSE("GPL");