ptp_kvm_common.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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/slab.h>
  12. #include <linux/module.h>
  13. #include <linux/ptp_kvm.h>
  14. #include <uapi/linux/kvm_para.h>
  15. #include <asm/kvm_para.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 int ptp_kvm_get_time_fn(ktime_t *device_time,
  24. struct system_counterval_t *system_counter,
  25. void *ctx)
  26. {
  27. long ret;
  28. u64 cycle;
  29. struct timespec64 tspec;
  30. struct clocksource *cs;
  31. spin_lock(&kvm_ptp_lock);
  32. preempt_disable_notrace();
  33. ret = kvm_arch_ptp_get_crosststamp(&cycle, &tspec, &cs);
  34. if (ret) {
  35. spin_unlock(&kvm_ptp_lock);
  36. preempt_enable_notrace();
  37. return ret;
  38. }
  39. preempt_enable_notrace();
  40. system_counter->cycles = cycle;
  41. system_counter->cs = cs;
  42. *device_time = timespec64_to_ktime(tspec);
  43. spin_unlock(&kvm_ptp_lock);
  44. return 0;
  45. }
  46. static int ptp_kvm_getcrosststamp(struct ptp_clock_info *ptp,
  47. struct system_device_crosststamp *xtstamp)
  48. {
  49. return get_device_system_crosststamp(ptp_kvm_get_time_fn, NULL,
  50. NULL, xtstamp);
  51. }
  52. /*
  53. * PTP clock operations
  54. */
  55. static int ptp_kvm_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
  56. {
  57. return -EOPNOTSUPP;
  58. }
  59. static int ptp_kvm_adjtime(struct ptp_clock_info *ptp, s64 delta)
  60. {
  61. return -EOPNOTSUPP;
  62. }
  63. static int ptp_kvm_settime(struct ptp_clock_info *ptp,
  64. const struct timespec64 *ts)
  65. {
  66. return -EOPNOTSUPP;
  67. }
  68. static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
  69. {
  70. long ret;
  71. struct timespec64 tspec;
  72. spin_lock(&kvm_ptp_lock);
  73. ret = kvm_arch_ptp_get_clock(&tspec);
  74. if (ret) {
  75. spin_unlock(&kvm_ptp_lock);
  76. return ret;
  77. }
  78. spin_unlock(&kvm_ptp_lock);
  79. memcpy(ts, &tspec, sizeof(struct timespec64));
  80. return 0;
  81. }
  82. static int ptp_kvm_enable(struct ptp_clock_info *ptp,
  83. struct ptp_clock_request *rq, int on)
  84. {
  85. return -EOPNOTSUPP;
  86. }
  87. static const struct ptp_clock_info ptp_kvm_caps = {
  88. .owner = THIS_MODULE,
  89. .name = "KVM virtual PTP",
  90. .max_adj = 0,
  91. .n_ext_ts = 0,
  92. .n_pins = 0,
  93. .pps = 0,
  94. .adjfreq = ptp_kvm_adjfreq,
  95. .adjtime = ptp_kvm_adjtime,
  96. .gettime64 = ptp_kvm_gettime,
  97. .settime64 = ptp_kvm_settime,
  98. .enable = ptp_kvm_enable,
  99. .getcrosststamp = ptp_kvm_getcrosststamp,
  100. };
  101. /* module operations */
  102. static struct kvm_ptp_clock kvm_ptp_clock;
  103. static void __exit ptp_kvm_exit(void)
  104. {
  105. ptp_clock_unregister(kvm_ptp_clock.ptp_clock);
  106. }
  107. static int __init ptp_kvm_init(void)
  108. {
  109. long ret;
  110. ret = kvm_arch_ptp_init();
  111. if (ret) {
  112. if (ret != -EOPNOTSUPP)
  113. pr_err("fail to initialize ptp_kvm");
  114. return ret;
  115. }
  116. kvm_ptp_clock.caps = ptp_kvm_caps;
  117. kvm_ptp_clock.ptp_clock = ptp_clock_register(&kvm_ptp_clock.caps, NULL);
  118. return PTR_ERR_OR_ZERO(kvm_ptp_clock.ptp_clock);
  119. }
  120. module_init(ptp_kvm_init);
  121. module_exit(ptp_kvm_exit);
  122. MODULE_AUTHOR("Marcelo Tosatti <[email protected]>");
  123. MODULE_DESCRIPTION("PTP clock using KVMCLOCK");
  124. MODULE_LICENSE("GPL");