ptp: Reorganize ptp_kvm.c to make it arch-independent
authorJianyong Wu <jianyong.wu@arm.com>
Wed, 9 Dec 2020 06:09:26 +0000 (14:09 +0800)
committerMarc Zyngier <maz@kernel.org>
Wed, 7 Apr 2021 15:33:07 +0000 (16:33 +0100)
Currently, the ptp_kvm module contains a lot of x86-specific code.
Let's move this code into a new arch-specific file in the same directory,
and rename the arch-independent file to ptp_kvm_common.c.

Acked-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201209060932.212364-4-jianyong.wu@arm.com
drivers/ptp/Makefile
drivers/ptp/ptp_kvm.c [deleted file]
drivers/ptp/ptp_kvm_common.c [new file with mode: 0644]
drivers/ptp/ptp_kvm_x86.c [new file with mode: 0644]
include/linux/ptp_kvm.h [new file with mode: 0644]

index db5aef3..d11eeb5 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 ptp-y                                  := ptp_clock.o ptp_chardev.o ptp_sysfs.o
+ptp_kvm-$(CONFIG_X86)                  := ptp_kvm_x86.o ptp_kvm_common.o
 obj-$(CONFIG_PTP_1588_CLOCK)           += ptp.o
 obj-$(CONFIG_PTP_1588_CLOCK_DTE)       += ptp_dte.o
 obj-$(CONFIG_PTP_1588_CLOCK_INES)      += ptp_ines.o
diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/ptp_kvm.c
deleted file mode 100644 (file)
index 658d33f..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Virtual PTP 1588 clock for use with KVM guests
- *
- * Copyright (C) 2017 Red Hat Inc.
- */
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <uapi/linux/kvm_para.h>
-#include <asm/kvm_para.h>
-#include <asm/pvclock.h>
-#include <asm/kvmclock.h>
-#include <uapi/asm/kvm_para.h>
-
-#include <linux/ptp_clock_kernel.h>
-
-struct kvm_ptp_clock {
-       struct ptp_clock *ptp_clock;
-       struct ptp_clock_info caps;
-};
-
-static DEFINE_SPINLOCK(kvm_ptp_lock);
-
-static struct pvclock_vsyscall_time_info *hv_clock;
-
-static struct kvm_clock_pairing clock_pair;
-static phys_addr_t clock_pair_gpa;
-
-static int ptp_kvm_get_time_fn(ktime_t *device_time,
-                              struct system_counterval_t *system_counter,
-                              void *ctx)
-{
-       unsigned long ret;
-       struct timespec64 tspec;
-       unsigned version;
-       int cpu;
-       struct pvclock_vcpu_time_info *src;
-
-       spin_lock(&kvm_ptp_lock);
-
-       preempt_disable_notrace();
-       cpu = smp_processor_id();
-       src = &hv_clock[cpu].pvti;
-
-       do {
-               /*
-                * We are using a TSC value read in the hosts
-                * kvm_hc_clock_pairing handling.
-                * So any changes to tsc_to_system_mul
-                * and tsc_shift or any other pvclock
-                * data invalidate that measurement.
-                */
-               version = pvclock_read_begin(src);
-
-               ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
-                                    clock_pair_gpa,
-                                    KVM_CLOCK_PAIRING_WALLCLOCK);
-               if (ret != 0) {
-                       pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
-                       spin_unlock(&kvm_ptp_lock);
-                       preempt_enable_notrace();
-                       return -EOPNOTSUPP;
-               }
-
-               tspec.tv_sec = clock_pair.sec;
-               tspec.tv_nsec = clock_pair.nsec;
-               ret = __pvclock_read_cycles(src, clock_pair.tsc);
-       } while (pvclock_read_retry(src, version));
-
-       preempt_enable_notrace();
-
-       system_counter->cycles = ret;
-       system_counter->cs = &kvm_clock;
-
-       *device_time = timespec64_to_ktime(tspec);
-
-       spin_unlock(&kvm_ptp_lock);
-
-       return 0;
-}
-
-static int ptp_kvm_getcrosststamp(struct ptp_clock_info *ptp,
-                                 struct system_device_crosststamp *xtstamp)
-{
-       return get_device_system_crosststamp(ptp_kvm_get_time_fn, NULL,
-                                            NULL, xtstamp);
-}
-
-/*
- * PTP clock operations
- */
-
-static int ptp_kvm_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
-{
-       return -EOPNOTSUPP;
-}
-
-static int ptp_kvm_adjtime(struct ptp_clock_info *ptp, s64 delta)
-{
-       return -EOPNOTSUPP;
-}
-
-static int ptp_kvm_settime(struct ptp_clock_info *ptp,
-                          const struct timespec64 *ts)
-{
-       return -EOPNOTSUPP;
-}
-
-static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
-{
-       unsigned long ret;
-       struct timespec64 tspec;
-
-       spin_lock(&kvm_ptp_lock);
-
-       ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
-                            clock_pair_gpa,
-                            KVM_CLOCK_PAIRING_WALLCLOCK);
-       if (ret != 0) {
-               pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);
-               spin_unlock(&kvm_ptp_lock);
-               return -EOPNOTSUPP;
-       }
-
-       tspec.tv_sec = clock_pair.sec;
-       tspec.tv_nsec = clock_pair.nsec;
-       spin_unlock(&kvm_ptp_lock);
-
-       memcpy(ts, &tspec, sizeof(struct timespec64));
-
-       return 0;
-}
-
-static int ptp_kvm_enable(struct ptp_clock_info *ptp,
-                         struct ptp_clock_request *rq, int on)
-{
-       return -EOPNOTSUPP;
-}
-
-static const struct ptp_clock_info ptp_kvm_caps = {
-       .owner          = THIS_MODULE,
-       .name           = "KVM virtual PTP",
-       .max_adj        = 0,
-       .n_ext_ts       = 0,
-       .n_pins         = 0,
-       .pps            = 0,
-       .adjfreq        = ptp_kvm_adjfreq,
-       .adjtime        = ptp_kvm_adjtime,
-       .gettime64      = ptp_kvm_gettime,
-       .settime64      = ptp_kvm_settime,
-       .enable         = ptp_kvm_enable,
-       .getcrosststamp = ptp_kvm_getcrosststamp,
-};
-
-/* module operations */
-
-static struct kvm_ptp_clock kvm_ptp_clock;
-
-static void __exit ptp_kvm_exit(void)
-{
-       ptp_clock_unregister(kvm_ptp_clock.ptp_clock);
-}
-
-static int __init ptp_kvm_init(void)
-{
-       long ret;
-
-       if (!kvm_para_available())
-               return -ENODEV;
-
-       clock_pair_gpa = slow_virt_to_phys(&clock_pair);
-       hv_clock = pvclock_get_pvti_cpu0_va();
-
-       if (!hv_clock)
-               return -ENODEV;
-
-       ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
-                       KVM_CLOCK_PAIRING_WALLCLOCK);
-       if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
-               return -ENODEV;
-
-       kvm_ptp_clock.caps = ptp_kvm_caps;
-
-       kvm_ptp_clock.ptp_clock = ptp_clock_register(&kvm_ptp_clock.caps, NULL);
-
-       return PTR_ERR_OR_ZERO(kvm_ptp_clock.ptp_clock);
-}
-
-module_init(ptp_kvm_init);
-module_exit(ptp_kvm_exit);
-
-MODULE_AUTHOR("Marcelo Tosatti <mtosatti@redhat.com>");
-MODULE_DESCRIPTION("PTP clock using KVMCLOCK");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_kvm_common.c b/drivers/ptp/ptp_kvm_common.c
new file mode 100644 (file)
index 0000000..721ddce
--- /dev/null
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/ptp_kvm.h>
+#include <uapi/linux/kvm_para.h>
+#include <asm/kvm_para.h>
+#include <uapi/asm/kvm_para.h>
+
+#include <linux/ptp_clock_kernel.h>
+
+struct kvm_ptp_clock {
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info caps;
+};
+
+static DEFINE_SPINLOCK(kvm_ptp_lock);
+
+static int ptp_kvm_get_time_fn(ktime_t *device_time,
+                              struct system_counterval_t *system_counter,
+                              void *ctx)
+{
+       long ret;
+       u64 cycle;
+       struct timespec64 tspec;
+       struct clocksource *cs;
+
+       spin_lock(&kvm_ptp_lock);
+
+       preempt_disable_notrace();
+       ret = kvm_arch_ptp_get_crosststamp(&cycle, &tspec, &cs);
+       if (ret) {
+               spin_unlock(&kvm_ptp_lock);
+               preempt_enable_notrace();
+               return ret;
+       }
+
+       preempt_enable_notrace();
+
+       system_counter->cycles = cycle;
+       system_counter->cs = cs;
+
+       *device_time = timespec64_to_ktime(tspec);
+
+       spin_unlock(&kvm_ptp_lock);
+
+       return 0;
+}
+
+static int ptp_kvm_getcrosststamp(struct ptp_clock_info *ptp,
+                                 struct system_device_crosststamp *xtstamp)
+{
+       return get_device_system_crosststamp(ptp_kvm_get_time_fn, NULL,
+                                            NULL, xtstamp);
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_kvm_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       return -EOPNOTSUPP;
+}
+
+static int ptp_kvm_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       return -EOPNOTSUPP;
+}
+
+static int ptp_kvm_settime(struct ptp_clock_info *ptp,
+                          const struct timespec64 *ts)
+{
+       return -EOPNOTSUPP;
+}
+
+static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
+{
+       long ret;
+       struct timespec64 tspec;
+
+       spin_lock(&kvm_ptp_lock);
+
+       ret = kvm_arch_ptp_get_clock(&tspec);
+       if (ret) {
+               spin_unlock(&kvm_ptp_lock);
+               return ret;
+       }
+
+       spin_unlock(&kvm_ptp_lock);
+
+       memcpy(ts, &tspec, sizeof(struct timespec64));
+
+       return 0;
+}
+
+static int ptp_kvm_enable(struct ptp_clock_info *ptp,
+                         struct ptp_clock_request *rq, int on)
+{
+       return -EOPNOTSUPP;
+}
+
+static const struct ptp_clock_info ptp_kvm_caps = {
+       .owner          = THIS_MODULE,
+       .name           = "KVM virtual PTP",
+       .max_adj        = 0,
+       .n_ext_ts       = 0,
+       .n_pins         = 0,
+       .pps            = 0,
+       .adjfreq        = ptp_kvm_adjfreq,
+       .adjtime        = ptp_kvm_adjtime,
+       .gettime64      = ptp_kvm_gettime,
+       .settime64      = ptp_kvm_settime,
+       .enable         = ptp_kvm_enable,
+       .getcrosststamp = ptp_kvm_getcrosststamp,
+};
+
+/* module operations */
+
+static struct kvm_ptp_clock kvm_ptp_clock;
+
+static void __exit ptp_kvm_exit(void)
+{
+       ptp_clock_unregister(kvm_ptp_clock.ptp_clock);
+}
+
+static int __init ptp_kvm_init(void)
+{
+       long ret;
+
+       ret = kvm_arch_ptp_init();
+       if (ret) {
+               pr_err("fail to initialize ptp_kvm");
+               return ret;
+       }
+
+       kvm_ptp_clock.caps = ptp_kvm_caps;
+
+       kvm_ptp_clock.ptp_clock = ptp_clock_register(&kvm_ptp_clock.caps, NULL);
+
+       return PTR_ERR_OR_ZERO(kvm_ptp_clock.ptp_clock);
+}
+
+module_init(ptp_kvm_init);
+module_exit(ptp_kvm_exit);
+
+MODULE_AUTHOR("Marcelo Tosatti <mtosatti@redhat.com>");
+MODULE_DESCRIPTION("PTP clock using KVMCLOCK");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_kvm_x86.c b/drivers/ptp/ptp_kvm_x86.c
new file mode 100644 (file)
index 0000000..3dd519d
--- /dev/null
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <asm/pvclock.h>
+#include <asm/kvmclock.h>
+#include <linux/module.h>
+#include <uapi/asm/kvm_para.h>
+#include <uapi/linux/kvm_para.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/ptp_kvm.h>
+
+struct pvclock_vsyscall_time_info *hv_clock;
+
+static phys_addr_t clock_pair_gpa;
+static struct kvm_clock_pairing clock_pair;
+
+int kvm_arch_ptp_init(void)
+{
+       long ret;
+
+       if (!kvm_para_available())
+               return -ENODEV;
+
+       clock_pair_gpa = slow_virt_to_phys(&clock_pair);
+       hv_clock = pvclock_get_pvti_cpu0_va();
+       if (!hv_clock)
+               return -ENODEV;
+
+       ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
+                            KVM_CLOCK_PAIRING_WALLCLOCK);
+       if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
+               return -ENODEV;
+
+       return 0;
+}
+
+int kvm_arch_ptp_get_clock(struct timespec64 *ts)
+{
+       long ret;
+
+       ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
+                            clock_pair_gpa,
+                            KVM_CLOCK_PAIRING_WALLCLOCK);
+       if (ret != 0) {
+               pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);
+               return -EOPNOTSUPP;
+       }
+
+       ts->tv_sec = clock_pair.sec;
+       ts->tv_nsec = clock_pair.nsec;
+
+       return 0;
+}
+
+int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,
+                             struct clocksource **cs)
+{
+       struct pvclock_vcpu_time_info *src;
+       unsigned int version;
+       long ret;
+       int cpu;
+
+       cpu = smp_processor_id();
+       src = &hv_clock[cpu].pvti;
+
+       do {
+               /*
+                * We are using a TSC value read in the hosts
+                * kvm_hc_clock_pairing handling.
+                * So any changes to tsc_to_system_mul
+                * and tsc_shift or any other pvclock
+                * data invalidate that measurement.
+                */
+               version = pvclock_read_begin(src);
+
+               ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
+                                    clock_pair_gpa,
+                                    KVM_CLOCK_PAIRING_WALLCLOCK);
+               if (ret != 0) {
+                       pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
+                       return -EOPNOTSUPP;
+               }
+               tspec->tv_sec = clock_pair.sec;
+               tspec->tv_nsec = clock_pair.nsec;
+               *cycle = __pvclock_read_cycles(src, clock_pair.tsc);
+       } while (pvclock_read_retry(src, version));
+
+       *cs = &kvm_clock;
+
+       return 0;
+}
diff --git a/include/linux/ptp_kvm.h b/include/linux/ptp_kvm.h
new file mode 100644 (file)
index 0000000..f960a71
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Virtual PTP 1588 clock for use with KVM guests
+ *
+ * Copyright (C) 2017 Red Hat Inc.
+ */
+
+#ifndef _PTP_KVM_H_
+#define _PTP_KVM_H_
+
+struct timespec64;
+struct clocksource;
+
+int kvm_arch_ptp_init(void);
+int kvm_arch_ptp_get_clock(struct timespec64 *ts);
+int kvm_arch_ptp_get_crosststamp(u64 *cycle,
+               struct timespec64 *tspec, struct clocksource **cs);
+
+#endif /* _PTP_KVM_H_ */