Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/e2e_tests/guest_under_test/kernel/patches/virtio_pvclock.patch
5394 views
1
From 7f8eba774852bad453f9015ca408612337acc86d Mon Sep 17 00:00:00 2001
2
From: Hikaru Nishida <[email protected]>
3
Date: Wed, 24 Jan 2024 14:23:40 +0900
4
Subject: [PATCH] CHROMIUM: virtio_pvclock: port driver impl from Android
5
6
Initial virtio_pvclock device driver implementation from Android.
7
8
This is a squash of aosp/1959549, aosp/1962079, aosp/2395934:
9
- ANDROID: virtio: virtio_pvclock: initial driver impl
10
- ANDROID: virtio: virtio_pvclock: call vclocks_set_used
11
- ANDROID: virtio: virtio_pvclock: fix rating decl
12
13
BUG=b:271057959, b:295256641
14
TEST=make O=../v5.10-arcvm_build x86_64_arcvm_defconfig
15
TEST=make -j`nproc` O=../v5.10-arcvm_build bzImage
16
TEST=tast run ${DUT} arc.PlayStore.vm arc.Suspend.*
17
UPSTREAM-TASK=b:321618282
18
19
Change-Id: I068da510e17283b13791e3ae51542b74d4601975
20
Signed-off-by: Hikaru Nishida <[email protected]>
21
---
22
arch/x86/entry/vdso/vma.c | 1 +
23
arch/x86/kernel/pvclock.c | 2 +
24
drivers/virtio/Kconfig | 36 +++
25
drivers/virtio/Makefile | 1 +
26
drivers/virtio/virtio_pvclock.c | 345 ++++++++++++++++++++++++++++
27
include/uapi/linux/virtio_ids.h | 3 +
28
include/uapi/linux/virtio_pvclock.h | 74 ++++++
29
kernel/time/timekeeping.c | 4 +
30
8 files changed, 466 insertions(+)
31
create mode 100644 drivers/virtio/virtio_pvclock.c
32
create mode 100644 include/uapi/linux/virtio_pvclock.h
33
34
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
35
index 128866139..51520db4a 100644
36
--- a/arch/x86/entry/vdso/vma.c
37
+++ b/arch/x86/entry/vdso/vma.c
38
@@ -39,6 +39,7 @@ struct vdso_data *arch_get_vdso_data(void *vvar_page)
39
#undef EMIT_VVAR
40
41
unsigned int vclocks_used __read_mostly;
42
+EXPORT_SYMBOL_GPL(vclocks_used);
43
44
#if defined(CONFIG_X86_64)
45
unsigned int __read_mostly vdso64_enabled = 1;
46
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c
47
index eda37df01..54b41d759 100644
48
--- a/arch/x86/kernel/pvclock.c
49
+++ b/arch/x86/kernel/pvclock.c
50
@@ -109,6 +109,7 @@ u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
51
52
return ret;
53
}
54
+EXPORT_SYMBOL_GPL(pvclock_clocksource_read);
55
56
void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
57
struct pvclock_vcpu_time_info *vcpu_time,
58
@@ -148,6 +149,7 @@ void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti)
59
WARN_ON(vclock_was_used(VDSO_CLOCKMODE_PVCLOCK));
60
pvti_cpu0_va = pvti;
61
}
62
+EXPORT_SYMBOL_GPL(pvclock_set_pvti_cpu0_va);
63
64
struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void)
65
{
66
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
67
index 0a53a6123..72921084e 100644
68
--- a/drivers/virtio/Kconfig
69
+++ b/drivers/virtio/Kconfig
70
@@ -173,4 +173,40 @@ config VIRTIO_DMA_SHARED_BUFFER
71
This option adds a flavor of dma buffers that are backed by
72
virtio resources.
73
74
+config VIRTIO_PVCLOCK
75
+ tristate "Virtio pvclock driver"
76
+ depends on VIRTIO
77
+ depends on X86
78
+ select PARAVIRT_CLOCK
79
+ help
80
+ This driver supports virtio pvclock devices.
81
+ It helps emulating CLOCK_BOOTTIME behavior around host's suspend / resume
82
+ without actually suspends the guest with the hypervisor's support.
83
+
84
+ If unsure, say M.
85
+
86
+config VIRTIO_PVCLOCK
87
+ tristate "Virtio pvclock driver"
88
+ depends on VIRTIO
89
+ depends on X86
90
+ select PARAVIRT_CLOCK
91
+ help
92
+ This driver supports virtio pvclock devices.
93
+ It helps emulating CLOCK_BOOTTIME behavior around host's suspend / resume
94
+ without actually suspends the guest with the hypervisor's support.
95
+
96
+ If unsure, say M.
97
+
98
+config VIRTIO_PVCLOCK
99
+ tristate "Virtio pvclock driver"
100
+ depends on VIRTIO
101
+ depends on X86
102
+ select PARAVIRT_CLOCK
103
+ help
104
+ This driver supports virtio pvclock devices.
105
+ It helps emulating CLOCK_BOOTTIME behavior around host's suspend / resume
106
+ without actually suspends the guest with the hypervisor's support.
107
+
108
+ If unsure, say M.
109
+
110
endif # VIRTIO_MENU
111
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
112
index 8e98d2491..79e6dea7c 100644
113
--- a/drivers/virtio/Makefile
114
+++ b/drivers/virtio/Makefile
115
@@ -12,3 +12,4 @@ obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
116
obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o
117
obj-$(CONFIG_VIRTIO_MEM) += virtio_mem.o
118
obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) += virtio_dma_buf.o
119
+obj-$(CONFIG_VIRTIO_PVCLOCK) += virtio_pvclock.o
120
diff --git a/drivers/virtio/virtio_pvclock.c b/drivers/virtio/virtio_pvclock.c
121
new file mode 100644
122
index 000000000..7d6fd0b52
123
--- /dev/null
124
+++ b/drivers/virtio/virtio_pvclock.c
125
@@ -0,0 +1,345 @@
126
+// SPDX-License-Identifier: GPL-2.0-or-later
127
+/*
128
+ * Virtio pvclock implementation.
129
+ *
130
+ * Copyright (C) 2021 Google, Inc.
131
+ */
132
+
133
+#include <linux/clocksource.h>
134
+#include <linux/dma-mapping.h>
135
+#include <linux/module.h>
136
+#include <linux/slab.h>
137
+#include <linux/virtio.h>
138
+#include <linux/virtio_pvclock.h>
139
+#include <linux/workqueue.h>
140
+#include <asm/pvclock.h>
141
+
142
+enum virtio_pvclock_vq {
143
+ VIRTIO_PVCLOCK_VQ_SET_PVCLOCK_PAGE,
144
+ VIRTIO_PVCLOCK_VQ_MAX
145
+};
146
+
147
+struct virtio_pvclock {
148
+ struct virtio_device *vdev;
149
+ struct virtqueue *set_pvclock_page_vq;
150
+ struct virtio_pvclock_set_pvclock_page_req set_page_request;
151
+
152
+ /* Updating the suspend time happens via scheduled work. */
153
+ struct work_struct update_suspend_time_work;
154
+ /* Creating the clocksource happens via scheduled work. */
155
+ struct work_struct create_clocksource_work;
156
+
157
+ /* Synchronize access/update to injected_suspend_ns. */
158
+ struct mutex inject_suspend_lock;
159
+ /* Total ns injected as sleep time. */
160
+ u64 injected_suspend_ns;
161
+
162
+ /* DMA address of virtio_pvclock_page. */
163
+ dma_addr_t pvclock_page_dma_addr;
164
+};
165
+
166
+/* CPU accessible pointer to pvclock page. */
167
+static struct pvclock_vsyscall_time_info *virtio_pvclock_page;
168
+
169
+static struct virtio_device_id id_table[] = {
170
+ { VIRTIO_ID_PVCLOCK, VIRTIO_DEV_ANY_ID },
171
+ { 0 },
172
+};
173
+
174
+void update_suspend_time(struct work_struct *work)
175
+{
176
+ u64 suspend_ns, suspend_time_delta = 0;
177
+ struct timespec64 inject_time;
178
+ struct virtio_pvclock *vp;
179
+
180
+ vp = container_of(work, struct virtio_pvclock,
181
+ update_suspend_time_work);
182
+
183
+ virtio_cread(vp->vdev, struct virtio_pvclock_config, suspend_time_ns,
184
+ &suspend_ns);
185
+
186
+ mutex_lock(&vp->inject_suspend_lock);
187
+ if (suspend_ns > vp->injected_suspend_ns) {
188
+ suspend_time_delta = suspend_ns - vp->injected_suspend_ns;
189
+ vp->injected_suspend_ns = suspend_ns;
190
+ }
191
+ mutex_unlock(&vp->inject_suspend_lock);
192
+
193
+ if (suspend_time_delta == 0) {
194
+ dev_err(&vp->vdev->dev,
195
+ "%s: suspend_time_ns is less than injected_suspend_ns\n",
196
+ __func__);
197
+ return;
198
+ }
199
+
200
+ inject_time = ns_to_timespec64(suspend_time_delta);
201
+
202
+ timekeeping_inject_sleeptime64(&inject_time);
203
+
204
+ dev_info(&vp->vdev->dev, "injected sleeptime: %llu ns\n",
205
+ suspend_time_delta);
206
+}
207
+
208
+static u64 virtio_pvclock_clocksource_read(struct clocksource *cs)
209
+{
210
+ u64 ret;
211
+
212
+ preempt_disable_notrace();
213
+ ret = pvclock_clocksource_read(&virtio_pvclock_page->pvti);
214
+ preempt_enable_notrace();
215
+ return ret;
216
+}
217
+
218
+static int virtio_pvclock_cs_enable(struct clocksource *cs)
219
+{
220
+ if (cs->vdso_clock_mode == VDSO_CLOCKMODE_PVCLOCK)
221
+ vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK);
222
+ return 0;
223
+}
224
+
225
+static struct clocksource virtio_pvclock_clocksource = {
226
+ .name = "virtio-pvclock",
227
+ .rating = 200, /* default rating, updated by virtpvclock_validate */
228
+ .read = virtio_pvclock_clocksource_read,
229
+ .mask = CLOCKSOURCE_MASK(64),
230
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
231
+ .enable = virtio_pvclock_cs_enable,
232
+};
233
+
234
+static void set_pvclock_page_callback(struct virtqueue *vq)
235
+{
236
+ struct virtio_pvclock *vp = vq->vdev->priv;
237
+
238
+ if (vp->set_page_request.status != VIRTIO_PVCLOCK_S_OK) {
239
+ dev_err(&vq->vdev->dev,
240
+ "%s: set_pvclock_page req status is %u\n", __func__,
241
+ vp->set_page_request.status);
242
+ return;
243
+ }
244
+
245
+ /*
246
+ * Create the actual clocksource via a work queue because we're in an
247
+ * interrupt handler right now.
248
+ */
249
+ schedule_work(&vp->create_clocksource_work);
250
+}
251
+
252
+static void create_clocksource(struct work_struct *work)
253
+{
254
+ struct virtio_pvclock *vp;
255
+
256
+ vp = container_of(work, struct virtio_pvclock, create_clocksource_work);
257
+
258
+ /*
259
+ * VDSO pvclock can only be used if the TSCs are stable. The device also
260
+ * must set PVCLOCK_TSC_STABLE_BIT in the pvclock flags field.
261
+ */
262
+ if (virtio_has_feature(vp->vdev, VIRTIO_PVCLOCK_F_TSC_STABLE)) {
263
+ pvclock_set_pvti_cpu0_va(virtio_pvclock_page);
264
+ virtio_pvclock_clocksource.vdso_clock_mode =
265
+ VDSO_CLOCKMODE_PVCLOCK;
266
+ }
267
+
268
+ clocksource_register_hz(&virtio_pvclock_clocksource, NSEC_PER_SEC);
269
+
270
+ dev_info(&vp->vdev->dev, "registered clocksource\n");
271
+}
272
+
273
+static void virtpvclock_changed(struct virtio_device *vdev)
274
+{
275
+ struct virtio_pvclock *vp = vdev->priv;
276
+
277
+ schedule_work(&vp->update_suspend_time_work);
278
+}
279
+
280
+static int set_pvclock_page(struct virtio_pvclock *vp)
281
+{
282
+ struct scatterlist sg;
283
+ int err;
284
+
285
+ vp->set_page_request.pvclock_page_pa = vp->pvclock_page_dma_addr;
286
+ vp->set_page_request.system_time = ktime_get();
287
+ vp->set_page_request.tsc_timestamp = rdtsc_ordered();
288
+
289
+ sg_init_one(&sg, &vp->set_page_request, sizeof(vp->set_page_request));
290
+ err = virtqueue_add_outbuf(vp->set_pvclock_page_vq, &sg, 1, vp,
291
+ GFP_KERNEL);
292
+
293
+ if (err) {
294
+ dev_err(&vp->vdev->dev, "%s: failed to add output\n", __func__);
295
+ return err;
296
+ }
297
+ virtqueue_kick(vp->set_pvclock_page_vq);
298
+
299
+ return 0;
300
+}
301
+
302
+static int init_vqs(struct virtio_pvclock *vp)
303
+{
304
+ vq_callback_t *callbacks[VIRTIO_PVCLOCK_VQ_MAX];
305
+ struct virtqueue *vqs[VIRTIO_PVCLOCK_VQ_MAX];
306
+ const char *names[VIRTIO_PVCLOCK_VQ_MAX];
307
+ int err;
308
+
309
+ callbacks[VIRTIO_PVCLOCK_VQ_SET_PVCLOCK_PAGE] =
310
+ set_pvclock_page_callback;
311
+ names[VIRTIO_PVCLOCK_VQ_SET_PVCLOCK_PAGE] = "set_pvclock_page";
312
+
313
+ err = vp->vdev->config->find_vqs(vp->vdev, VIRTIO_PVCLOCK_VQ_MAX, vqs,
314
+ callbacks, names, NULL, NULL);
315
+ if (err)
316
+ return err;
317
+
318
+ vp->set_pvclock_page_vq = vqs[VIRTIO_PVCLOCK_VQ_SET_PVCLOCK_PAGE];
319
+
320
+ return set_pvclock_page(vp);
321
+}
322
+
323
+static int virtpvclock_probe(struct virtio_device *vdev)
324
+{
325
+ struct virtio_pvclock *vp;
326
+ int err;
327
+
328
+ if (!vdev->config->get) {
329
+ dev_err(&vdev->dev, "%s: config access disabled\n", __func__);
330
+ return -EINVAL;
331
+ }
332
+
333
+ vp = kzalloc(sizeof(*vp), GFP_KERNEL);
334
+ if (!vp) {
335
+ err = -ENOMEM;
336
+ goto out;
337
+ }
338
+
339
+ virtio_pvclock_page =
340
+ dma_alloc_coherent(vdev->dev.parent,
341
+ sizeof(*virtio_pvclock_page),
342
+ &vp->pvclock_page_dma_addr, GFP_KERNEL);
343
+
344
+ if (!virtio_pvclock_page) {
345
+ err = -ENOMEM;
346
+ goto out_free_vp;
347
+ }
348
+
349
+ INIT_WORK(&vp->update_suspend_time_work, update_suspend_time);
350
+ INIT_WORK(&vp->create_clocksource_work, create_clocksource);
351
+ mutex_init(&vp->inject_suspend_lock);
352
+
353
+ vp->vdev = vdev;
354
+ vdev->priv = vp;
355
+
356
+ err = init_vqs(vp);
357
+ if (err)
358
+ goto out_free_pvclock_page;
359
+
360
+ virtio_device_ready(vdev);
361
+
362
+ return 0;
363
+
364
+out_free_pvclock_page:
365
+ dma_free_coherent(vdev->dev.parent, sizeof(*virtio_pvclock_page),
366
+ virtio_pvclock_page, vp->pvclock_page_dma_addr);
367
+
368
+out_free_vp:
369
+ kfree(vp);
370
+out:
371
+ return err;
372
+}
373
+
374
+static void remove_common(struct virtio_pvclock *vp)
375
+{
376
+ /* Now we reset the device so we can clean up the queues. */
377
+ vp->vdev->config->reset(vp->vdev);
378
+
379
+ vp->vdev->config->del_vqs(vp->vdev);
380
+}
381
+
382
+static void virtpvclock_remove(struct virtio_device *vdev)
383
+{
384
+ struct virtio_pvclock *vp = vdev->priv;
385
+
386
+ remove_common(vp);
387
+
388
+ dma_free_coherent(vdev->dev.parent, sizeof(*virtio_pvclock_page),
389
+ virtio_pvclock_page, vp->pvclock_page_dma_addr);
390
+
391
+ kfree(vp);
392
+}
393
+
394
+#ifdef CONFIG_PM_SLEEP
395
+static int virtpvclock_freeze(struct virtio_device *vdev)
396
+{
397
+ struct virtio_pvclock *vp = vdev->priv;
398
+
399
+ /*
400
+ * The workqueue is already frozen by the PM core before this
401
+ * function is called.
402
+ */
403
+ remove_common(vp);
404
+ return 0;
405
+}
406
+
407
+static int virtpvclock_restore(struct virtio_device *vdev)
408
+{
409
+ int ret;
410
+
411
+ ret = init_vqs(vdev->priv);
412
+ if (ret)
413
+ return ret;
414
+
415
+ virtio_device_ready(vdev);
416
+
417
+ return 0;
418
+}
419
+#endif
420
+
421
+#define MAX_CLOCKSOURCE_RATING 450
422
+
423
+static int virtpvclock_validate(struct virtio_device *vdev)
424
+{
425
+ uint32_t rating;
426
+
427
+ if (!virtio_has_feature(vdev, VIRTIO_PVCLOCK_F_CLOCKSOURCE_RATING))
428
+ return 0;
429
+
430
+ rating = virtio_cread32(vdev, offsetof(struct virtio_pvclock_config,
431
+ clocksource_rating));
432
+ if (rating > MAX_CLOCKSOURCE_RATING) {
433
+ dev_warn(
434
+ &vdev->dev,
435
+ "device clocksource rating too high: %u, using max rating: %u\n",
436
+ rating, MAX_CLOCKSOURCE_RATING);
437
+ __virtio_clear_bit(vdev, VIRTIO_PVCLOCK_F_CLOCKSOURCE_RATING);
438
+ virtio_pvclock_clocksource.rating = (int)MAX_CLOCKSOURCE_RATING;
439
+ } else {
440
+ dev_info(&vdev->dev, "clocksource rating set to %u\n", rating);
441
+ virtio_pvclock_clocksource.rating = (int)rating;
442
+ }
443
+
444
+ return 0;
445
+}
446
+
447
+static unsigned int features[] = { VIRTIO_PVCLOCK_F_TSC_STABLE,
448
+ VIRTIO_PVCLOCK_F_INJECT_SLEEP,
449
+ VIRTIO_PVCLOCK_F_CLOCKSOURCE_RATING };
450
+
451
+static struct virtio_driver virtio_pvclock_driver = {
452
+ .feature_table = features,
453
+ .feature_table_size = ARRAY_SIZE(features),
454
+ .driver.name = KBUILD_MODNAME,
455
+ .driver.owner = THIS_MODULE,
456
+ .id_table = id_table,
457
+ .validate = virtpvclock_validate,
458
+ .probe = virtpvclock_probe,
459
+ .remove = virtpvclock_remove,
460
+ .config_changed = virtpvclock_changed,
461
+#ifdef CONFIG_PM_SLEEP
462
+ .freeze = virtpvclock_freeze,
463
+ .restore = virtpvclock_restore,
464
+#endif
465
+};
466
+
467
+module_virtio_driver(virtio_pvclock_driver);
468
+MODULE_DEVICE_TABLE(virtio, id_table);
469
+MODULE_DESCRIPTION("Virtio pvclock driver");
470
+MODULE_LICENSE("GPL");
471
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
472
index 7aa2eb766..c4ce86b44 100644
473
--- a/include/uapi/linux/virtio_ids.h
474
+++ b/include/uapi/linux/virtio_ids.h
475
@@ -69,6 +69,9 @@
476
#define VIRTIO_ID_BT 40 /* virtio bluetooth */
477
#define VIRTIO_ID_GPIO 41 /* virtio gpio */
478
479
+/* Chrome OS-specific devices */
480
+#define VIRTIO_ID_PVCLOCK 61 /* virtio pvclock (experimental id) */
481
+
482
/*
483
* Virtio Transitional IDs
484
*/
485
diff --git a/include/uapi/linux/virtio_pvclock.h b/include/uapi/linux/virtio_pvclock.h
486
new file mode 100644
487
index 000000000..808d47b21
488
--- /dev/null
489
+++ b/include/uapi/linux/virtio_pvclock.h
490
@@ -0,0 +1,74 @@
491
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause */
492
+/* This header is BSD licensed so anyone can use the definitions to implement
493
+ * compatible drivers/servers.
494
+ *
495
+ * Redistribution and use in source and binary forms, with or without
496
+ * modification, are permitted provided that the following conditions
497
+ * are met:
498
+ * 1. Redistributions of source code must retain the above copyright
499
+ * notice, this list of conditions and the following disclaimer.
500
+ * 2. Redistributions in binary form must reproduce the above copyright
501
+ * notice, this list of conditions and the following disclaimer in the
502
+ * documentation and/or other materials provided with the distribution.
503
+ * 3. Neither the name of IBM nor the names of its contributors
504
+ * may be used to endorse or promote products derived from this software
505
+ * without specific prior written permission.
506
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
507
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
508
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
509
+ * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
510
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
511
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
512
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
513
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
514
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
515
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
516
+ * SUCH DAMAGE.
517
+ */
518
+
519
+#ifndef _LINUX_VIRTIO_PVCLOCK_H
520
+#define _LINUX_VIRTIO_PVCLOCK_H
521
+
522
+#include <linux/types.h>
523
+#include <linux/virtio_types.h>
524
+#include <linux/virtio_ids.h>
525
+#include <linux/virtio_config.h>
526
+
527
+/* The feature bitmap for virtio pvclock */
528
+/* TSC is stable */
529
+#define VIRTIO_PVCLOCK_F_TSC_STABLE 0
530
+/* Inject sleep for suspend */
531
+#define VIRTIO_PVCLOCK_F_INJECT_SLEEP 1
532
+/* Use device clocksource rating */
533
+#define VIRTIO_PVCLOCK_F_CLOCKSOURCE_RATING 2
534
+
535
+struct virtio_pvclock_config {
536
+ /* Number of ns the VM has been suspended without guest suspension. */
537
+ __u64 suspend_time_ns;
538
+ /* Device-suggested rating of the pvclock clocksource. */
539
+ __u32 clocksource_rating;
540
+ __u32 padding;
541
+};
542
+
543
+/* Status values for a virtio_pvclock request. */
544
+#define VIRTIO_PVCLOCK_S_OK 0
545
+#define VIRTIO_PVCLOCK_S_IOERR 1
546
+#define VIRTIO_PVCLOCK_S_UNSUPP 2
547
+
548
+/*
549
+ * Virtio pvclock set pvclock page request. Sets up the shared memory
550
+ * pvclock_vsyscall_time_info struct.
551
+ */
552
+struct virtio_pvclock_set_pvclock_page_req {
553
+ /* Physical address of pvclock_vsyscall_time_info. */
554
+ __u64 pvclock_page_pa;
555
+ /* Current system time. */
556
+ __u64 system_time;
557
+ /* Current tsc value. */
558
+ __u64 tsc_timestamp;
559
+ /* Status of this request, one of VIRTIO_PVCLOCK_S_*. */
560
+ __u8 status;
561
+ __u8 padding[7];
562
+};
563
+
564
+#endif /* _LINUX_VIRTIO_PVCLOCK_H */
565
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
566
index 221c8c404..3fd9bb166 100644
567
--- a/kernel/time/timekeeping.c
568
+++ b/kernel/time/timekeeping.c
569
@@ -1735,7 +1735,10 @@ bool timekeeping_rtc_skipsuspend(void)
570
{
571
return persistent_clock_exists;
572
}
573
+#endif
574
575
+#if (defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)) || \
576
+ defined(CONFIG_VIRTIO_PVCLOCK)
577
/**
578
* timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values
579
* @delta: pointer to a timespec64 delta value
580
@@ -1769,6 +1772,7 @@ void timekeeping_inject_sleeptime64(const struct timespec64 *delta)
581
/* Signal hrtimers about time change */
582
clock_was_set(CLOCK_SET_WALL | CLOCK_SET_BOOT);
583
}
584
+EXPORT_SYMBOL_GPL(timekeeping_inject_sleeptime64);
585
#endif
586
587
/**
588
--
589
2.43.0.429.g432eaa2c6b-goog
590
591
592