vgettimeofday.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*
  2. * Copyright 2015 Mentor Graphics Corporation.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; version 2 of the
  7. * License.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <linux/compiler.h>
  18. #include <linux/hrtimer.h>
  19. #include <linux/time.h>
  20. #include <asm/barrier.h>
  21. #include <asm/bug.h>
  22. #include <asm/cp15.h>
  23. #include <asm/page.h>
  24. #include <asm/unistd.h>
  25. #include <asm/vdso_datapage.h>
  26. #ifndef CONFIG_AEABI
  27. #error This code depends on AEABI system call conventions
  28. #endif
  29. extern struct vdso_data *__get_datapage(void);
  30. static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
  31. {
  32. u32 seq;
  33. repeat:
  34. seq = READ_ONCE(vdata->seq_count);
  35. if (seq & 1) {
  36. cpu_relax();
  37. goto repeat;
  38. }
  39. return seq;
  40. }
  41. static notrace u32 vdso_read_begin(const struct vdso_data *vdata)
  42. {
  43. u32 seq;
  44. seq = __vdso_read_begin(vdata);
  45. smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
  46. return seq;
  47. }
  48. static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
  49. {
  50. smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
  51. return vdata->seq_count != start;
  52. }
  53. static notrace long clock_gettime_fallback(clockid_t _clkid,
  54. struct timespec *_ts)
  55. {
  56. register struct timespec *ts asm("r1") = _ts;
  57. register clockid_t clkid asm("r0") = _clkid;
  58. register long ret asm ("r0");
  59. register long nr asm("r7") = __NR_clock_gettime;
  60. asm volatile(
  61. " swi #0\n"
  62. : "=r" (ret)
  63. : "r" (clkid), "r" (ts), "r" (nr)
  64. : "memory");
  65. return ret;
  66. }
  67. static notrace int do_realtime_coarse(struct timespec *ts,
  68. struct vdso_data *vdata)
  69. {
  70. u32 seq;
  71. do {
  72. seq = vdso_read_begin(vdata);
  73. ts->tv_sec = vdata->xtime_coarse_sec;
  74. ts->tv_nsec = vdata->xtime_coarse_nsec;
  75. } while (vdso_read_retry(vdata, seq));
  76. return 0;
  77. }
  78. static notrace int do_monotonic_coarse(struct timespec *ts,
  79. struct vdso_data *vdata)
  80. {
  81. struct timespec tomono;
  82. u32 seq;
  83. do {
  84. seq = vdso_read_begin(vdata);
  85. ts->tv_sec = vdata->xtime_coarse_sec;
  86. ts->tv_nsec = vdata->xtime_coarse_nsec;
  87. tomono.tv_sec = vdata->wtm_clock_sec;
  88. tomono.tv_nsec = vdata->wtm_clock_nsec;
  89. } while (vdso_read_retry(vdata, seq));
  90. ts->tv_sec += tomono.tv_sec;
  91. timespec_add_ns(ts, tomono.tv_nsec);
  92. return 0;
  93. }
  94. #ifdef CONFIG_ARM_ARCH_TIMER
  95. static notrace u64 get_ns(struct vdso_data *vdata)
  96. {
  97. u64 cycle_delta;
  98. u64 cycle_now;
  99. u64 nsec;
  100. isb();
  101. cycle_now = read_sysreg(CNTVCT);
  102. cycle_delta = (cycle_now - vdata->cs_cycle_last) & vdata->cs_mask;
  103. nsec = (cycle_delta * vdata->cs_mult) + vdata->xtime_clock_snsec;
  104. nsec >>= vdata->cs_shift;
  105. return nsec;
  106. }
  107. static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
  108. {
  109. u64 nsecs;
  110. u32 seq;
  111. do {
  112. seq = vdso_read_begin(vdata);
  113. if (!vdata->tk_is_cntvct)
  114. return -1;
  115. ts->tv_sec = vdata->xtime_clock_sec;
  116. nsecs = get_ns(vdata);
  117. } while (vdso_read_retry(vdata, seq));
  118. ts->tv_nsec = 0;
  119. timespec_add_ns(ts, nsecs);
  120. return 0;
  121. }
  122. static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
  123. {
  124. struct timespec tomono;
  125. u64 nsecs;
  126. u32 seq;
  127. do {
  128. seq = vdso_read_begin(vdata);
  129. if (!vdata->tk_is_cntvct)
  130. return -1;
  131. ts->tv_sec = vdata->xtime_clock_sec;
  132. nsecs = get_ns(vdata);
  133. tomono.tv_sec = vdata->wtm_clock_sec;
  134. tomono.tv_nsec = vdata->wtm_clock_nsec;
  135. } while (vdso_read_retry(vdata, seq));
  136. ts->tv_sec += tomono.tv_sec;
  137. ts->tv_nsec = 0;
  138. timespec_add_ns(ts, nsecs + tomono.tv_nsec);
  139. return 0;
  140. }
  141. #else /* CONFIG_ARM_ARCH_TIMER */
  142. static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
  143. {
  144. return -1;
  145. }
  146. static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
  147. {
  148. return -1;
  149. }
  150. #endif /* CONFIG_ARM_ARCH_TIMER */
  151. notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
  152. {
  153. struct vdso_data *vdata;
  154. int ret = -1;
  155. vdata = __get_datapage();
  156. switch (clkid) {
  157. case CLOCK_REALTIME_COARSE:
  158. ret = do_realtime_coarse(ts, vdata);
  159. break;
  160. case CLOCK_MONOTONIC_COARSE:
  161. ret = do_monotonic_coarse(ts, vdata);
  162. break;
  163. case CLOCK_REALTIME:
  164. ret = do_realtime(ts, vdata);
  165. break;
  166. case CLOCK_MONOTONIC:
  167. ret = do_monotonic(ts, vdata);
  168. break;
  169. default:
  170. break;
  171. }
  172. if (ret)
  173. ret = clock_gettime_fallback(clkid, ts);
  174. return ret;
  175. }
  176. static notrace long gettimeofday_fallback(struct timeval *_tv,
  177. struct timezone *_tz)
  178. {
  179. register struct timezone *tz asm("r1") = _tz;
  180. register struct timeval *tv asm("r0") = _tv;
  181. register long ret asm ("r0");
  182. register long nr asm("r7") = __NR_gettimeofday;
  183. asm volatile(
  184. " swi #0\n"
  185. : "=r" (ret)
  186. : "r" (tv), "r" (tz), "r" (nr)
  187. : "memory");
  188. return ret;
  189. }
  190. notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
  191. {
  192. struct timespec ts;
  193. struct vdso_data *vdata;
  194. int ret;
  195. vdata = __get_datapage();
  196. ret = do_realtime(&ts, vdata);
  197. if (ret)
  198. return gettimeofday_fallback(tv, tz);
  199. if (tv) {
  200. tv->tv_sec = ts.tv_sec;
  201. tv->tv_usec = ts.tv_nsec / 1000;
  202. }
  203. if (tz) {
  204. tz->tz_minuteswest = vdata->tz_minuteswest;
  205. tz->tz_dsttime = vdata->tz_dsttime;
  206. }
  207. return ret;
  208. }
  209. /* Avoid unresolved references emitted by GCC */
  210. void __aeabi_unwind_cpp_pr0(void)
  211. {
  212. }
  213. void __aeabi_unwind_cpp_pr1(void)
  214. {
  215. }
  216. void __aeabi_unwind_cpp_pr2(void)
  217. {
  218. }