2 * Userspace implementations of gettimeofday() and friends.
4 * Copyright (C) 2017 Cavium, Inc.
5 * Copyright (C) 2015 Mentor Graphics Corporation
6 * Copyright (C) 2012 ARM Limited
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * Author: Will Deacon <will.deacon@arm.com>
21 * Rewriten from arch64 version into C by: Andrew Pinski <apinski@cavium.com>
22 * Reworked and rebased over arm version by: Mark Salyzyn <salyzyn@android.com>
25 #include <asm/barrier.h>
26 #include <linux/compiler.h> /* for notrace */
27 #include <linux/math64.h> /* for __iter_div_u64_rem() */
28 #include <uapi/linux/time.h> /* for struct timespec */
33 DEFINE_FALLBACK(gettimeofday
, struct timeval
*, tv
, struct timezone
*, tz
)
34 DEFINE_FALLBACK(clock_gettime
, clockid_t
, clock
, struct timespec
*, ts
)
35 DEFINE_FALLBACK(clock_getres
, clockid_t
, clock
, struct timespec
*, ts
)
37 static notrace u32
vdso_read_begin(const struct vdso_data
*vd
)
42 seq
= READ_ONCE(vd
->tb_seq_count
);
50 smp_rmb(); /* Pairs with second smp_wmb in update_vsyscall */
54 static notrace
int vdso_read_retry(const struct vdso_data
*vd
, u32 start
)
58 smp_rmb(); /* Pairs with first smp_wmb in update_vsyscall */
59 seq
= READ_ONCE(vd
->tb_seq_count
);
63 static notrace
int do_realtime_coarse(const struct vdso_data
*vd
,
69 seq
= vdso_read_begin(vd
);
71 ts
->tv_sec
= vd
->xtime_coarse_sec
;
72 ts
->tv_nsec
= vd
->xtime_coarse_nsec
;
74 } while (vdso_read_retry(vd
, seq
));
79 static notrace
int do_monotonic_coarse(const struct vdso_data
*vd
,
82 struct timespec tomono
;
87 seq
= vdso_read_begin(vd
);
89 ts
->tv_sec
= vd
->xtime_coarse_sec
;
90 ts
->tv_nsec
= vd
->xtime_coarse_nsec
;
92 tomono
.tv_sec
= vd
->wtm_clock_sec
;
93 tomono
.tv_nsec
= vd
->wtm_clock_nsec
;
95 } while (vdso_read_retry(vd
, seq
));
97 ts
->tv_sec
+= tomono
.tv_sec
;
98 /* open coding timespec_add_ns */
99 ts
->tv_sec
+= __iter_div_u64_rem(ts
->tv_nsec
+ tomono
.tv_nsec
,
100 NSEC_PER_SEC
, &nsec
);
106 #ifdef CONFIG_ARM_ARCH_TIMER
109 * Returns the clock delta, in nanoseconds left-shifted by the clock
112 static notrace u64
get_clock_shifted_nsec(const u64 cycle_last
,
118 /* Read the virtual counter. */
119 res
= arch_vdso_read_counter();
121 res
= res
- cycle_last
;
127 static notrace
int do_realtime(const struct vdso_data
*vd
, struct timespec
*ts
)
129 u32 seq
, mult
, shift
;
130 u64 nsec
, cycle_last
;
132 vdso_xtime_clock_sec_t sec
;
135 seq
= vdso_read_begin(vd
);
140 cycle_last
= vd
->cs_cycle_last
;
142 mult
= vd
->cs_mono_mult
;
143 shift
= vd
->cs_shift
;
146 sec
= vd
->xtime_clock_sec
;
147 nsec
= vd
->xtime_clock_snsec
;
149 } while (unlikely(vdso_read_retry(vd
, seq
)));
151 nsec
+= get_clock_shifted_nsec(cycle_last
, mult
, mask
);
153 /* open coding timespec_add_ns to save a ts->tv_nsec = 0 */
154 ts
->tv_sec
= sec
+ __iter_div_u64_rem(nsec
, NSEC_PER_SEC
, &nsec
);
160 static notrace
int do_monotonic(const struct vdso_data
*vd
, struct timespec
*ts
)
162 u32 seq
, mult
, shift
;
163 u64 nsec
, cycle_last
;
165 vdso_wtm_clock_nsec_t wtm_nsec
;
169 seq
= vdso_read_begin(vd
);
174 cycle_last
= vd
->cs_cycle_last
;
176 mult
= vd
->cs_mono_mult
;
177 shift
= vd
->cs_shift
;
180 sec
= vd
->xtime_clock_sec
;
181 nsec
= vd
->xtime_clock_snsec
;
183 sec
+= vd
->wtm_clock_sec
;
184 wtm_nsec
= vd
->wtm_clock_nsec
;
186 } while (unlikely(vdso_read_retry(vd
, seq
)));
188 nsec
+= get_clock_shifted_nsec(cycle_last
, mult
, mask
);
191 /* open coding timespec_add_ns to save a ts->tv_nsec = 0 */
192 ts
->tv_sec
= sec
+ __iter_div_u64_rem(nsec
, NSEC_PER_SEC
, &nsec
);
198 static notrace
int do_monotonic_raw(const struct vdso_data
*vd
,
201 u32 seq
, mult
, shift
;
202 u64 nsec
, cycle_last
;
204 vdso_raw_time_sec_t sec
;
207 seq
= vdso_read_begin(vd
);
212 cycle_last
= vd
->cs_cycle_last
;
214 mult
= vd
->cs_raw_mult
;
215 shift
= vd
->cs_shift
;
218 sec
= vd
->raw_time_sec
;
219 nsec
= vd
->raw_time_nsec
;
221 } while (unlikely(vdso_read_retry(vd
, seq
)));
223 nsec
+= get_clock_shifted_nsec(cycle_last
, mult
, mask
);
225 /* open coding timespec_add_ns to save a ts->tv_nsec = 0 */
226 ts
->tv_sec
= sec
+ __iter_div_u64_rem(nsec
, NSEC_PER_SEC
, &nsec
);
232 #else /* CONFIG_ARM_ARCH_TIMER */
234 static notrace
int do_realtime(const struct vdso_data
*vd
, struct timespec
*ts
)
239 static notrace
int do_monotonic(const struct vdso_data
*vd
, struct timespec
*ts
)
244 static notrace
int do_monotonic_raw(const struct vdso_data
*vd
,
250 #endif /* CONFIG_ARM_ARCH_TIMER */
252 notrace
int __vdso_clock_gettime(clockid_t clock
, struct timespec
*ts
)
254 const struct vdso_data
*vd
= __get_datapage();
257 case CLOCK_REALTIME_COARSE
:
258 do_realtime_coarse(vd
, ts
);
260 case CLOCK_MONOTONIC_COARSE
:
261 do_monotonic_coarse(vd
, ts
);
264 if (do_realtime(vd
, ts
))
267 case CLOCK_MONOTONIC
:
268 if (do_monotonic(vd
, ts
))
271 case CLOCK_MONOTONIC_RAW
:
272 if (do_monotonic_raw(vd
, ts
))
281 return clock_gettime_fallback(clock
, ts
);
284 notrace
int __vdso_gettimeofday(struct timeval
*tv
, struct timezone
*tz
)
286 const struct vdso_data
*vd
= __get_datapage();
288 if (likely(tv
!= NULL
)) {
291 if (do_realtime(vd
, &ts
))
292 return gettimeofday_fallback(tv
, tz
);
294 tv
->tv_sec
= ts
.tv_sec
;
295 tv
->tv_usec
= ts
.tv_nsec
/ 1000;
298 if (unlikely(tz
!= NULL
)) {
299 tz
->tz_minuteswest
= vd
->tz_minuteswest
;
300 tz
->tz_dsttime
= vd
->tz_dsttime
;
306 int __vdso_clock_getres(clockid_t clock
, struct timespec
*res
)
310 if (clock
== CLOCK_REALTIME
||
311 clock
== CLOCK_MONOTONIC
||
312 clock
== CLOCK_MONOTONIC_RAW
)
313 nsec
= MONOTONIC_RES_NSEC
;
314 else if (clock
== CLOCK_REALTIME_COARSE
||
315 clock
== CLOCK_MONOTONIC_COARSE
)
318 return clock_getres_fallback(clock
, res
);
320 if (likely(res
!= NULL
)) {