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/arch_timer.h>
  21. #include <asm/barrier.h>
  22. #include <asm/bug.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 = ACCESS_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. cycle_now = arch_counter_get_cntvct();
  101. cycle_delta = (cycle_now - vdata->cs_cycle_last) & vdata->cs_mask;
  102. nsec = (cycle_delta * vdata->cs_mult) + vdata->xtime_clock_snsec;
  103. nsec >>= vdata->cs_shift;
  104. return nsec;
  105. }
  106. static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
  107. {
  108. u64 nsecs;
  109. u32 seq;
  110. do {
  111. seq = vdso_read_begin(vdata);
  112. if (!vdata->tk_is_cntvct)
  113. return -1;
  114. ts->tv_sec = vdata->xtime_clock_sec;
  115. nsecs = get_ns(vdata);
  116. } while (vdso_read_retry(vdata, seq));
  117. ts->tv_nsec = 0;
  118. timespec_add_ns(ts, nsecs);
  119. return 0;
  120. }
  121. static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
  122. {
  123. struct timespec tomono;
  124. u64 nsecs;
  125. u32 seq;
  126. do {
  127. seq = vdso_read_begin(vdata);
  128. if (!vdata->tk_is_cntvct)
  129. return -1;
  130. ts->tv_sec = vdata->xtime_clock_sec;
  131. nsecs = get_ns(vdata);
  132. tomono.tv_sec = vdata->wtm_clock_sec;
  133. tomono.tv_nsec = vdata->wtm_clock_nsec;
  134. } while (vdso_read_retry(vdata, seq));
  135. ts->tv_sec += tomono.tv_sec;
  136. ts->tv_nsec = 0;
  137. timespec_add_ns(ts, nsecs + tomono.tv_nsec);
  138. return 0;
  139. }
  140. #else /* CONFIG_ARM_ARCH_TIMER */
  141. static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata)
  142. {
  143. return -1;
  144. }
  145. static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata)
  146. {
  147. return -1;
  148. }
  149. #endif /* CONFIG_ARM_ARCH_TIMER */
  150. notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
  151. {
  152. struct vdso_data *vdata;
  153. int ret = -1;
  154. vdata = __get_datapage();
  155. switch (clkid) {
  156. case CLOCK_REALTIME_COARSE:
  157. ret = do_realtime_coarse(ts, vdata);
  158. break;
  159. case CLOCK_MONOTONIC_COARSE:
  160. ret = do_monotonic_coarse(ts, vdata);
  161. break;
  162. case CLOCK_REALTIME:
  163. ret = do_realtime(ts, vdata);
  164. break;
  165. case CLOCK_MONOTONIC:
  166. ret = do_monotonic(ts, vdata);
  167. break;
  168. default:
  169. break;
  170. }
  171. if (ret)
  172. ret = clock_gettime_fallback(clkid, ts);
  173. return ret;
  174. }
  175. static notrace long gettimeofday_fallback(struct timeval *_tv,
  176. struct timezone *_tz)
  177. {
  178. register struct timezone *tz asm("r1") = _tz;
  179. register struct timeval *tv asm("r0") = _tv;
  180. register long ret asm ("r0");
  181. register long nr asm("r7") = __NR_gettimeofday;
  182. asm volatile(
  183. " swi #0\n"
  184. : "=r" (ret)
  185. : "r" (tv), "r" (tz), "r" (nr)
  186. : "memory");
  187. return ret;
  188. }
  189. notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
  190. {
  191. struct timespec ts;
  192. struct vdso_data *vdata;
  193. int ret;
  194. vdata = __get_datapage();
  195. ret = do_realtime(&ts, vdata);
  196. if (ret)
  197. return gettimeofday_fallback(tv, tz);
  198. if (tv) {
  199. tv->tv_sec = ts.tv_sec;
  200. tv->tv_usec = ts.tv_nsec / 1000;
  201. }
  202. if (tz) {
  203. tz->tz_minuteswest = vdata->tz_minuteswest;
  204. tz->tz_dsttime = vdata->tz_dsttime;
  205. }
  206. return ret;
  207. }
  208. /* Avoid unresolved references emitted by GCC */
  209. void __aeabi_unwind_cpp_pr0(void)
  210. {
  211. }
  212. void __aeabi_unwind_cpp_pr1(void)
  213. {
  214. }
  215. void __aeabi_unwind_cpp_pr2(void)
  216. {
  217. }