forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-09 244b2c5ca8b14627e4a17755e5922221e121c771
kernel/drivers/hv/hv_util.c
....@@ -1,18 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (c) 2010, Microsoft Corporation.
3
- *
4
- * This program is free software; you can redistribute it and/or modify it
5
- * under the terms and conditions of the GNU General Public License,
6
- * version 2, as published by the Free Software Foundation.
7
- *
8
- * This program is distributed in the hope it will be useful, but WITHOUT
9
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11
- * more details.
12
- *
13
- * You should have received a copy of the GNU General Public License along with
14
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
- * Place - Suite 330, Boston, MA 02111-1307 USA.
164 *
175 * Authors:
186 * Haiyang Zhang <haiyangz@microsoft.com>
....@@ -29,12 +17,17 @@
2917 #include <linux/hyperv.h>
3018 #include <linux/clockchips.h>
3119 #include <linux/ptp_clock_kernel.h>
20
+#include <clocksource/hyperv_timer.h>
3221 #include <asm/mshyperv.h>
3322
3423 #include "hyperv_vmbus.h"
3524
3625 #define SD_MAJOR 3
3726 #define SD_MINOR 0
27
+#define SD_MINOR_1 1
28
+#define SD_MINOR_2 2
29
+#define SD_VERSION_3_1 (SD_MAJOR << 16 | SD_MINOR_1)
30
+#define SD_VERSION_3_2 (SD_MAJOR << 16 | SD_MINOR_2)
3831 #define SD_VERSION (SD_MAJOR << 16 | SD_MINOR)
3932
4033 #define SD_MAJOR_1 1
....@@ -61,8 +54,10 @@
6154 static int ts_srv_version;
6255 static int hb_srv_version;
6356
64
-#define SD_VER_COUNT 2
57
+#define SD_VER_COUNT 4
6558 static const int sd_versions[] = {
59
+ SD_VERSION_3_2,
60
+ SD_VERSION_3_1,
6661 SD_VERSION,
6762 SD_VERSION_1
6863 };
....@@ -86,18 +81,56 @@
8681 UTIL_WS2K8_FW_VERSION
8782 };
8883
84
+/*
85
+ * Send the "hibernate" udev event in a thread context.
86
+ */
87
+struct hibernate_work_context {
88
+ struct work_struct work;
89
+ struct hv_device *dev;
90
+};
91
+
92
+static struct hibernate_work_context hibernate_context;
93
+static bool hibernation_supported;
94
+
95
+static void send_hibernate_uevent(struct work_struct *work)
96
+{
97
+ char *uevent_env[2] = { "EVENT=hibernate", NULL };
98
+ struct hibernate_work_context *ctx;
99
+
100
+ ctx = container_of(work, struct hibernate_work_context, work);
101
+
102
+ kobject_uevent_env(&ctx->dev->device.kobj, KOBJ_CHANGE, uevent_env);
103
+
104
+ pr_info("Sent hibernation uevent\n");
105
+}
106
+
107
+static int hv_shutdown_init(struct hv_util_service *srv)
108
+{
109
+ struct vmbus_channel *channel = srv->channel;
110
+
111
+ INIT_WORK(&hibernate_context.work, send_hibernate_uevent);
112
+ hibernate_context.dev = channel->device_obj;
113
+
114
+ hibernation_supported = hv_is_hibernation_supported();
115
+
116
+ return 0;
117
+}
118
+
89119 static void shutdown_onchannelcallback(void *context);
90120 static struct hv_util_service util_shutdown = {
91121 .util_cb = shutdown_onchannelcallback,
122
+ .util_init = hv_shutdown_init,
92123 };
93124
94125 static int hv_timesync_init(struct hv_util_service *srv);
126
+static int hv_timesync_pre_suspend(void);
95127 static void hv_timesync_deinit(void);
96128
97129 static void timesync_onchannelcallback(void *context);
98130 static struct hv_util_service util_timesynch = {
99131 .util_cb = timesync_onchannelcallback,
100132 .util_init = hv_timesync_init,
133
+ .util_pre_suspend = hv_timesync_pre_suspend,
101134 .util_deinit = hv_timesync_deinit,
102135 };
103136
....@@ -109,18 +142,24 @@
109142 static struct hv_util_service util_kvp = {
110143 .util_cb = hv_kvp_onchannelcallback,
111144 .util_init = hv_kvp_init,
145
+ .util_pre_suspend = hv_kvp_pre_suspend,
146
+ .util_pre_resume = hv_kvp_pre_resume,
112147 .util_deinit = hv_kvp_deinit,
113148 };
114149
115150 static struct hv_util_service util_vss = {
116151 .util_cb = hv_vss_onchannelcallback,
117152 .util_init = hv_vss_init,
153
+ .util_pre_suspend = hv_vss_pre_suspend,
154
+ .util_pre_resume = hv_vss_pre_resume,
118155 .util_deinit = hv_vss_deinit,
119156 };
120157
121158 static struct hv_util_service util_fcopy = {
122159 .util_cb = hv_fcopy_onchannelcallback,
123160 .util_init = hv_fcopy_init,
161
+ .util_pre_suspend = hv_fcopy_pre_suspend,
162
+ .util_pre_resume = hv_fcopy_pre_resume,
124163 .util_deinit = hv_fcopy_deinit,
125164 };
126165
....@@ -129,17 +168,27 @@
129168 orderly_poweroff(true);
130169 }
131170
171
+static void perform_restart(struct work_struct *dummy)
172
+{
173
+ orderly_reboot();
174
+}
175
+
132176 /*
133177 * Perform the shutdown operation in a thread context.
134178 */
135179 static DECLARE_WORK(shutdown_work, perform_shutdown);
136180
181
+/*
182
+ * Perform the restart operation in a thread context.
183
+ */
184
+static DECLARE_WORK(restart_work, perform_restart);
185
+
137186 static void shutdown_onchannelcallback(void *context)
138187 {
139188 struct vmbus_channel *channel = context;
189
+ struct work_struct *work = NULL;
140190 u32 recvlen;
141191 u64 requestid;
142
- bool execute_shutdown = false;
143192 u8 *shut_txf_buf = util_shutdown.recv_buffer;
144193
145194 struct shutdown_msg_data *shutdown_msg;
....@@ -147,7 +196,7 @@
147196 struct icmsg_hdr *icmsghdrp;
148197
149198 vmbus_recvpacket(channel, shut_txf_buf,
150
- PAGE_SIZE, &recvlen, &requestid);
199
+ HV_HYP_PAGE_SIZE, &recvlen, &requestid);
151200
152201 if (recvlen > 0) {
153202 icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
....@@ -168,19 +217,37 @@
168217 sizeof(struct vmbuspipe_hdr) +
169218 sizeof(struct icmsg_hdr)];
170219
220
+ /*
221
+ * shutdown_msg->flags can be 0(shut down), 2(reboot),
222
+ * or 4(hibernate). It may bitwise-OR 1, which means
223
+ * performing the request by force. Linux always tries
224
+ * to perform the request by force.
225
+ */
171226 switch (shutdown_msg->flags) {
172227 case 0:
173228 case 1:
174229 icmsghdrp->status = HV_S_OK;
175
- execute_shutdown = true;
176
-
230
+ work = &shutdown_work;
177231 pr_info("Shutdown request received -"
178232 " graceful shutdown initiated\n");
179233 break;
234
+ case 2:
235
+ case 3:
236
+ icmsghdrp->status = HV_S_OK;
237
+ work = &restart_work;
238
+ pr_info("Restart request received -"
239
+ " graceful restart initiated\n");
240
+ break;
241
+ case 4:
242
+ case 5:
243
+ pr_info("Hibernation request received\n");
244
+ icmsghdrp->status = hibernation_supported ?
245
+ HV_S_OK : HV_E_FAIL;
246
+ if (hibernation_supported)
247
+ work = &hibernate_context.work;
248
+ break;
180249 default:
181250 icmsghdrp->status = HV_E_FAIL;
182
- execute_shutdown = false;
183
-
184251 pr_info("Shutdown request received -"
185252 " Invalid request\n");
186253 break;
....@@ -195,8 +262,8 @@
195262 VM_PKT_DATA_INBAND, 0);
196263 }
197264
198
- if (execute_shutdown == true)
199
- schedule_work(&shutdown_work);
265
+ if (work)
266
+ schedule_work(work);
200267 }
201268
202269 /*
....@@ -215,26 +282,52 @@
215282 spinlock_t lock;
216283 } host_ts;
217284
218
-static struct timespec64 hv_get_adj_host_time(void)
285
+static inline u64 reftime_to_ns(u64 reftime)
219286 {
220
- struct timespec64 ts;
221
- u64 newtime, reftime;
287
+ return (reftime - WLTIMEDELTA) * 100;
288
+}
289
+
290
+/*
291
+ * Hard coded threshold for host timesync delay: 600 seconds
292
+ */
293
+static const u64 HOST_TIMESYNC_DELAY_THRESH = 600 * (u64)NSEC_PER_SEC;
294
+
295
+static int hv_get_adj_host_time(struct timespec64 *ts)
296
+{
297
+ u64 newtime, reftime, timediff_adj;
222298 unsigned long flags;
299
+ int ret = 0;
223300
224301 spin_lock_irqsave(&host_ts.lock, flags);
225
- reftime = hyperv_cs->read(hyperv_cs);
226
- newtime = host_ts.host_time + (reftime - host_ts.ref_time);
227
- ts = ns_to_timespec64((newtime - WLTIMEDELTA) * 100);
302
+ reftime = hv_read_reference_counter();
303
+
304
+ /*
305
+ * We need to let the caller know that last update from host
306
+ * is older than the max allowable threshold. clock_gettime()
307
+ * and PTP ioctl do not have a documented error that we could
308
+ * return for this specific case. Use ESTALE to report this.
309
+ */
310
+ timediff_adj = reftime - host_ts.ref_time;
311
+ if (timediff_adj * 100 > HOST_TIMESYNC_DELAY_THRESH) {
312
+ pr_warn_once("TIMESYNC IC: Stale time stamp, %llu nsecs old\n",
313
+ (timediff_adj * 100));
314
+ ret = -ESTALE;
315
+ }
316
+
317
+ newtime = host_ts.host_time + timediff_adj;
318
+ *ts = ns_to_timespec64(reftime_to_ns(newtime));
228319 spin_unlock_irqrestore(&host_ts.lock, flags);
229320
230
- return ts;
321
+ return ret;
231322 }
232323
233324 static void hv_set_host_time(struct work_struct *work)
234325 {
235
- struct timespec64 ts = hv_get_adj_host_time();
236326
237
- do_settimeofday64(&ts);
327
+ struct timespec64 ts;
328
+
329
+ if (!hv_get_adj_host_time(&ts))
330
+ do_settimeofday64(&ts);
238331 }
239332
240333 /*
....@@ -261,7 +354,7 @@
261354 */
262355 spin_lock_irqsave(&host_ts.lock, flags);
263356
264
- cur_reftime = hyperv_cs->read(hyperv_cs);
357
+ cur_reftime = hv_read_reference_counter();
265358 host_ts.host_time = hosttime;
266359 host_ts.ref_time = cur_reftime;
267360
....@@ -294,10 +387,23 @@
294387 struct ictimesync_ref_data *refdata;
295388 u8 *time_txf_buf = util_timesynch.recv_buffer;
296389
297
- vmbus_recvpacket(channel, time_txf_buf,
298
- PAGE_SIZE, &recvlen, &requestid);
390
+ /*
391
+ * Drain the ring buffer and use the last packet to update
392
+ * host_ts
393
+ */
394
+ while (1) {
395
+ int ret = vmbus_recvpacket(channel, time_txf_buf,
396
+ HV_HYP_PAGE_SIZE, &recvlen,
397
+ &requestid);
398
+ if (ret) {
399
+ pr_warn_once("TimeSync IC pkt recv failed (Err: %d)\n",
400
+ ret);
401
+ break;
402
+ }
299403
300
- if (recvlen > 0) {
404
+ if (!recvlen)
405
+ break;
406
+
301407 icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
302408 sizeof(struct vmbuspipe_hdr)];
303409
....@@ -326,7 +432,7 @@
326432 sizeof(struct vmbuspipe_hdr) +
327433 sizeof(struct icmsg_hdr)];
328434 adj_guesttime(timedatap->parenttime,
329
- hyperv_cs->read(hyperv_cs),
435
+ hv_read_reference_counter(),
330436 timedatap->flags);
331437 }
332438 }
....@@ -357,7 +463,7 @@
357463 while (1) {
358464
359465 vmbus_recvpacket(channel, hbeat_txf_buf,
360
- PAGE_SIZE, &recvlen, &requestid);
466
+ HV_HYP_PAGE_SIZE, &recvlen, &requestid);
361467
362468 if (!recvlen)
363469 break;
....@@ -394,6 +500,9 @@
394500 }
395501 }
396502
503
+#define HV_UTIL_RING_SEND_SIZE VMBUS_RING_SIZE(3 * HV_HYP_PAGE_SIZE)
504
+#define HV_UTIL_RING_RECV_SIZE VMBUS_RING_SIZE(3 * HV_HYP_PAGE_SIZE)
505
+
397506 static int util_probe(struct hv_device *dev,
398507 const struct hv_vmbus_device_id *dev_id)
399508 {
....@@ -401,7 +510,7 @@
401510 (struct hv_util_service *)dev_id->driver_data;
402511 int ret;
403512
404
- srv->recv_buffer = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
513
+ srv->recv_buffer = kmalloc(HV_HYP_PAGE_SIZE * 4, GFP_KERNEL);
405514 if (!srv->recv_buffer)
406515 return -ENOMEM;
407516 srv->channel = dev->channel;
....@@ -424,8 +533,9 @@
424533
425534 hv_set_drvdata(dev, srv);
426535
427
- ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
428
- srv->util_cb, dev->channel);
536
+ ret = vmbus_open(dev->channel, HV_UTIL_RING_SEND_SIZE,
537
+ HV_UTIL_RING_RECV_SIZE, NULL, 0, srv->util_cb,
538
+ dev->channel);
429539 if (ret)
430540 goto error;
431541
....@@ -449,6 +559,44 @@
449559 kfree(srv->recv_buffer);
450560
451561 return 0;
562
+}
563
+
564
+/*
565
+ * When we're in util_suspend(), all the userspace processes have been frozen
566
+ * (refer to hibernate() -> freeze_processes()). The userspace is thawed only
567
+ * after the whole resume procedure, including util_resume(), finishes.
568
+ */
569
+static int util_suspend(struct hv_device *dev)
570
+{
571
+ struct hv_util_service *srv = hv_get_drvdata(dev);
572
+ int ret = 0;
573
+
574
+ if (srv->util_pre_suspend) {
575
+ ret = srv->util_pre_suspend();
576
+ if (ret)
577
+ return ret;
578
+ }
579
+
580
+ vmbus_close(dev->channel);
581
+
582
+ return 0;
583
+}
584
+
585
+static int util_resume(struct hv_device *dev)
586
+{
587
+ struct hv_util_service *srv = hv_get_drvdata(dev);
588
+ int ret = 0;
589
+
590
+ if (srv->util_pre_resume) {
591
+ ret = srv->util_pre_resume();
592
+ if (ret)
593
+ return ret;
594
+ }
595
+
596
+ ret = vmbus_open(dev->channel, HV_UTIL_RING_SEND_SIZE,
597
+ HV_UTIL_RING_RECV_SIZE, NULL, 0, srv->util_cb,
598
+ dev->channel);
599
+ return ret;
452600 }
453601
454602 static const struct hv_vmbus_device_id id_table[] = {
....@@ -483,10 +631,12 @@
483631
484632 /* The one and only one */
485633 static struct hv_driver util_drv = {
486
- .name = "hv_util",
634
+ .name = "hv_utils",
487635 .id_table = id_table,
488636 .probe = util_probe,
489637 .remove = util_remove,
638
+ .suspend = util_suspend,
639
+ .resume = util_resume,
490640 .driver = {
491641 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
492642 },
....@@ -514,9 +664,7 @@
514664
515665 static int hv_ptp_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
516666 {
517
- *ts = hv_get_adj_host_time();
518
-
519
- return 0;
667
+ return hv_get_adj_host_time(ts);
520668 }
521669
522670 static struct ptp_clock_info ptp_hyperv_info = {
....@@ -534,7 +682,7 @@
534682 static int hv_timesync_init(struct hv_util_service *srv)
535683 {
536684 /* TimeSync requires Hyper-V clocksource. */
537
- if (!hyperv_cs)
685
+ if (!hv_read_reference_counter)
538686 return -ENODEV;
539687
540688 spin_lock_init(&host_ts.lock);
....@@ -556,11 +704,23 @@
556704 return 0;
557705 }
558706
707
+static void hv_timesync_cancel_work(void)
708
+{
709
+ cancel_work_sync(&adj_time_work);
710
+}
711
+
712
+static int hv_timesync_pre_suspend(void)
713
+{
714
+ hv_timesync_cancel_work();
715
+ return 0;
716
+}
717
+
559718 static void hv_timesync_deinit(void)
560719 {
561720 if (hv_ptp_clock)
562721 ptp_clock_unregister(hv_ptp_clock);
563
- cancel_work_sync(&adj_time_work);
722
+
723
+ hv_timesync_cancel_work();
564724 }
565725
566726 static int __init init_hyperv_utils(void)