xref: /aosp_15_r20/external/crosvm/e2e_tests/guest_under_test/kernel/patches/virtio_pvclock.patch (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1From 7f8eba774852bad453f9015ca408612337acc86d Mon Sep 17 00:00:00 2001
2From: Hikaru Nishida <[email protected]>
3Date: Wed, 24 Jan 2024 14:23:40 +0900
4Subject: [PATCH] CHROMIUM: virtio_pvclock: port driver impl from Android
5
6Initial virtio_pvclock device driver implementation from Android.
7
8This 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
13BUG=b:271057959, b:295256641
14TEST=make O=../v5.10-arcvm_build x86_64_arcvm_defconfig
15TEST=make -j`nproc` O=../v5.10-arcvm_build bzImage
16TEST=tast run ${DUT} arc.PlayStore.vm arc.Suspend.*
17UPSTREAM-TASK=b:321618282
18
19Change-Id: I068da510e17283b13791e3ae51542b74d4601975
20Signed-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
34diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
35index 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;
46diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c
47index 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 {
66diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
67index 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
111diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
112index 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
120diff --git a/drivers/virtio/virtio_pvclock.c b/drivers/virtio/virtio_pvclock.c
121new file mode 100644
122index 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");
471diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
472index 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  */
485diff --git a/include/uapi/linux/virtio_pvclock.h b/include/uapi/linux/virtio_pvclock.h
486new file mode 100644
487index 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 */
565diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
566index 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--
5892.43.0.429.g432eaa2c6b-goog
590
591