ptp_kvm.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Virtual PTP 1588 clock for use with KVM guests
  4. *
  5. * Copyright (C) 2017 Red Hat Inc.
  6. */
  7. #include <linux/device.h>
  8. #include <linux/err.h>
  9. #include <linux/init.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <uapi/linux/kvm_para.h>
  13. #include <asm/kvm_para.h>
  14. #include <asm/pvclock.h>
  15. #include <asm/kvmclock.h>
  16. #include <uapi/asm/kvm_para.h>
  17. #include <linux/ptp_clock_kernel.h>
  18. struct kvm_ptp_clock {
  19. struct ptp_clock *ptp_clock;
  20. struct ptp_clock_info caps;
  21. };
  22. static DEFINE_SPINLOCK(kvm_ptp_lock);
  23. static struct pvclock_vsyscall_time_info *hv_clock;
  24. static struct kvm_clock_pairing clock_pair;
  25. static phys_addr_t clock_pair_gpa;
  26. static int ptp_kvm_get_time_fn(ktime_t *device_time,
  27. struct system_counterval_t *system_counter,
  28. void *ctx)
  29. {
  30. unsigned long ret;
  31. struct timespec64 tspec;
  32. unsigned version;
  33. int cpu;
  34. struct pvclock_vcpu_time_info *src;
  35. spin_lock(&kvm_ptp_lock);
  36. preempt_disable_notrace();
  37. cpu = smp_processor_id();
  38. src = &hv_clock[cpu].pvti;
  39. do {
  40. /*
  41. * We are using a TSC value read in the hosts
  42. * kvm_hc_clock_pairing handling.
  43. * So any changes to tsc_to_system_mul
  44. * and tsc_shift or any other pvclock
  45. * data invalidate that measurement.
  46. */
  47. version = pvclock_read_begin(src);
  48. ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
  49. clock_pair_gpa,
  50. KVM_CLOCK_PAIRING_WALLCLOCK);
  51. if (ret != 0) {
  52. pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
  53. spin_unlock(&kvm_ptp_lock);
  54. preempt_enable_notrace();
  55. return -EOPNOTSUPP;
  56. }
  57. tspec.tv_sec = clock_pair.sec;
  58. tspec.tv_nsec = clock_pair.nsec;
  59. ret = __pvclock_read_cycles(src, clock_pair.tsc);
  60. } while (pvclock_read_retry(src, version));
  61. preempt_enable_notrace();
  62. system_counter->cycles = ret;
  63. system_counter->cs = &kvm_clock;
  64. *device_time = timespec64_to_ktime(tspec);
  65. spin_unlock(&kvm_ptp_lock);
  66. return 0;
  67. }
  68. static int ptp_kvm_getcrosststamp(struct ptp_clock_info *ptp,
  69. struct system_device_crosststamp *xtstamp)
  70. {
  71. return get_device_system_crosststamp(ptp_kvm_get_time_fn, NULL,
  72. NULL, xtstamp);
  73. }
  74. /*
  75. * PTP clock operations
  76. */
  77. static int ptp_kvm_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
  78. {
  79. return -EOPNOTSUPP;
  80. }
  81. static int ptp_kvm_adjtime(struct ptp_clock_info *ptp, s64 delta)
  82. {
  83. return -EOPNOTSUPP;
  84. }
  85. static int ptp_kvm_settime(struct ptp_clock_info *ptp,
  86. const struct timespec64 *ts)
  87. {
  88. return -EOPNOTSUPP;
  89. }
  90. static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
  91. {
  92. unsigned long ret;
  93. struct timespec64 tspec;
  94. spin_lock(&kvm_ptp_lock);
  95. ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
  96. clock_pair_gpa,
  97. KVM_CLOCK_PAIRING_WALLCLOCK);
  98. if (ret != 0) {
  99. pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);
  100. spin_unlock(&kvm_ptp_lock);
  101. return -EOPNOTSUPP;
  102. }
  103. tspec.tv_sec = clock_pair.sec;
  104. tspec.tv_nsec = clock_pair.nsec;
  105. spin_unlock(&kvm_ptp_lock);
  106. memcpy(ts, &tspec, sizeof(struct timespec64));
  107. return 0;
  108. }
  109. static int ptp_kvm_enable(struct ptp_clock_info *ptp,
  110. struct ptp_clock_request *rq, int on)
  111. {
  112. return -EOPNOTSUPP;
  113. }
  114. static const struct ptp_clock_info ptp_kvm_caps = {
  115. .owner = THIS_MODULE,
  116. .name = "KVM virtual PTP",
  117. .max_adj = 0,
  118. .n_ext_ts = 0,
  119. .n_pins = 0,
  120. .pps = 0,
  121. .adjfreq = ptp_kvm_adjfreq,
  122. .adjtime = ptp_kvm_adjtime,
  123. .gettime64 = ptp_kvm_gettime,
  124. .settime64 = ptp_kvm_settime,
  125. .enable = ptp_kvm_enable,
  126. .getcrosststamp = ptp_kvm_getcrosststamp,
  127. };
  128. /* module operations */
  129. static struct kvm_ptp_clock kvm_ptp_clock;
  130. static void __exit ptp_kvm_exit(void)
  131. {
  132. ptp_clock_unregister(kvm_ptp_clock.ptp_clock);
  133. }
  134. static int __init ptp_kvm_init(void)
  135. {
  136. long ret;
  137. if (!kvm_para_available())
  138. return -ENODEV;
  139. clock_pair_gpa = slow_virt_to_phys(&clock_pair);
  140. hv_clock = pvclock_get_pvti_cpu0_va();
  141. if (!hv_clock)
  142. return -ENODEV;
  143. ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
  144. KVM_CLOCK_PAIRING_WALLCLOCK);
  145. if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
  146. return -ENODEV;
  147. kvm_ptp_clock.caps = ptp_kvm_caps;
  148. kvm_ptp_clock.ptp_clock = ptp_clock_register(&kvm_ptp_clock.caps, NULL);
  149. return PTR_ERR_OR_ZERO(kvm_ptp_clock.ptp_clock);
  150. }
  151. module_init(ptp_kvm_init);
  152. module_exit(ptp_kvm_exit);
  153. MODULE_AUTHOR("Marcelo Tosatti <mtosatti@redhat.com>");
  154. MODULE_DESCRIPTION("PTP clock using KVMCLOCK");
  155. MODULE_LICENSE("GPL");