2 * Copyright 2015 Mentor Graphics Corporation.
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
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.
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/>.
18 #include <linux/compiler.h>
19 #include <linux/hrtimer.h>
20 #include <linux/time.h>
21 #include <asm/arch_timer.h>
22 #include <asm/barrier.h>
25 #include <asm/unistd.h>
26 #include <asm/vdso_datapage.h>
29 #error This code depends on AEABI system call conventions
32 extern struct vdso_data
*__get_datapage(void);
34 static notrace u32
__vdso_read_begin(const struct vdso_data
*vdata
)
38 seq
= READ_ONCE(vdata
->seq_count
);
46 static notrace u32
vdso_read_begin(const struct vdso_data
*vdata
)
50 seq
= __vdso_read_begin(vdata
);
52 smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
56 static notrace
int vdso_read_retry(const struct vdso_data
*vdata
, u32 start
)
58 smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
59 return vdata
->seq_count
!= start
;
62 static notrace
long clock_gettime_fallback(clockid_t _clkid
,
65 register struct timespec
*ts
asm("r1") = _ts
;
66 register clockid_t clkid
asm("r0") = _clkid
;
67 register long ret
asm ("r0");
68 register long nr
asm("r7") = __NR_clock_gettime
;
73 : "r" (clkid
), "r" (ts
), "r" (nr
)
79 static notrace
int do_realtime_coarse(struct timespec
*ts
,
80 struct vdso_data
*vdata
)
85 seq
= vdso_read_begin(vdata
);
87 ts
->tv_sec
= vdata
->xtime_coarse_sec
;
88 ts
->tv_nsec
= vdata
->xtime_coarse_nsec
;
90 } while (vdso_read_retry(vdata
, seq
));
95 static notrace
int do_monotonic_coarse(struct timespec
*ts
,
96 struct vdso_data
*vdata
)
98 struct timespec tomono
;
102 seq
= vdso_read_begin(vdata
);
104 ts
->tv_sec
= vdata
->xtime_coarse_sec
;
105 ts
->tv_nsec
= vdata
->xtime_coarse_nsec
;
107 tomono
.tv_sec
= vdata
->wtm_clock_sec
;
108 tomono
.tv_nsec
= vdata
->wtm_clock_nsec
;
110 } while (vdso_read_retry(vdata
, seq
));
112 ts
->tv_sec
+= tomono
.tv_sec
;
113 timespec_add_ns(ts
, tomono
.tv_nsec
);
118 #ifdef CONFIG_ARM_ARCH_TIMER
120 static notrace u64
get_ns(struct vdso_data
*vdata
)
126 cycle_now
= arch_counter_get_cntvct();
128 cycle_delta
= (cycle_now
- vdata
->cs_cycle_last
) & vdata
->cs_mask
;
130 nsec
= (cycle_delta
* vdata
->cs_mult
) + vdata
->xtime_clock_snsec
;
131 nsec
>>= vdata
->cs_shift
;
136 static notrace
int do_realtime(struct timespec
*ts
, struct vdso_data
*vdata
)
142 seq
= vdso_read_begin(vdata
);
144 if (!vdata
->tk_is_cntvct
)
147 ts
->tv_sec
= vdata
->xtime_clock_sec
;
148 nsecs
= get_ns(vdata
);
150 } while (vdso_read_retry(vdata
, seq
));
153 timespec_add_ns(ts
, nsecs
);
158 static notrace
int do_monotonic(struct timespec
*ts
, struct vdso_data
*vdata
)
160 struct timespec tomono
;
165 seq
= vdso_read_begin(vdata
);
167 if (!vdata
->tk_is_cntvct
)
170 ts
->tv_sec
= vdata
->xtime_clock_sec
;
171 nsecs
= get_ns(vdata
);
173 tomono
.tv_sec
= vdata
->wtm_clock_sec
;
174 tomono
.tv_nsec
= vdata
->wtm_clock_nsec
;
176 } while (vdso_read_retry(vdata
, seq
));
178 ts
->tv_sec
+= tomono
.tv_sec
;
180 timespec_add_ns(ts
, nsecs
+ tomono
.tv_nsec
);
185 #else /* CONFIG_ARM_ARCH_TIMER */
187 static notrace
int do_realtime(struct timespec
*ts
, struct vdso_data
*vdata
)
192 static notrace
int do_monotonic(struct timespec
*ts
, struct vdso_data
*vdata
)
197 #endif /* CONFIG_ARM_ARCH_TIMER */
199 notrace
int __vdso_clock_gettime(clockid_t clkid
, struct timespec
*ts
)
201 struct vdso_data
*vdata
;
204 vdata
= __get_datapage();
207 case CLOCK_REALTIME_COARSE
:
208 ret
= do_realtime_coarse(ts
, vdata
);
210 case CLOCK_MONOTONIC_COARSE
:
211 ret
= do_monotonic_coarse(ts
, vdata
);
214 ret
= do_realtime(ts
, vdata
);
216 case CLOCK_MONOTONIC
:
217 ret
= do_monotonic(ts
, vdata
);
224 ret
= clock_gettime_fallback(clkid
, ts
);
229 static notrace
long gettimeofday_fallback(struct timeval
*_tv
,
230 struct timezone
*_tz
)
232 register struct timezone
*tz
asm("r1") = _tz
;
233 register struct timeval
*tv
asm("r0") = _tv
;
234 register long ret
asm ("r0");
235 register long nr
asm("r7") = __NR_gettimeofday
;
240 : "r" (tv
), "r" (tz
), "r" (nr
)
246 notrace
int __vdso_gettimeofday(struct timeval
*tv
, struct timezone
*tz
)
249 struct vdso_data
*vdata
;
252 vdata
= __get_datapage();
254 ret
= do_realtime(&ts
, vdata
);
256 return gettimeofday_fallback(tv
, tz
);
259 tv
->tv_sec
= ts
.tv_sec
;
260 tv
->tv_usec
= ts
.tv_nsec
/ 1000;
263 tz
->tz_minuteswest
= vdata
->tz_minuteswest
;
264 tz
->tz_dsttime
= vdata
->tz_dsttime
;
270 /* Avoid unresolved references emitted by GCC */
272 void __aeabi_unwind_cpp_pr0(void)
276 void __aeabi_unwind_cpp_pr1(void)
280 void __aeabi_unwind_cpp_pr2(void)