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