128b1a824SVincenzo Frascino /* SPDX-License-Identifier: GPL-2.0 */
228b1a824SVincenzo Frascino /*
328b1a824SVincenzo Frascino * Copyright (C) 2018 ARM Limited
428b1a824SVincenzo Frascino */
528b1a824SVincenzo Frascino #ifndef __ASM_VDSO_GETTIMEOFDAY_H
628b1a824SVincenzo Frascino #define __ASM_VDSO_GETTIMEOFDAY_H
728b1a824SVincenzo Frascino
828b1a824SVincenzo Frascino #ifndef __ASSEMBLY__
928b1a824SVincenzo Frascino
10*9025cebfSJoey Gouly #include <asm/alternative.h>
11002dff36SWill Deacon #include <asm/barrier.h>
1228b1a824SVincenzo Frascino #include <asm/unistd.h>
13*9025cebfSJoey Gouly #include <asm/sysreg.h>
1428b1a824SVincenzo Frascino
1528b1a824SVincenzo Frascino #define VDSO_HAS_CLOCK_GETRES 1
1628b1a824SVincenzo Frascino
1728b1a824SVincenzo Frascino static __always_inline
gettimeofday_fallback(struct __kernel_old_timeval * _tv,struct timezone * _tz)1828b1a824SVincenzo Frascino int gettimeofday_fallback(struct __kernel_old_timeval *_tv,
1928b1a824SVincenzo Frascino struct timezone *_tz)
2028b1a824SVincenzo Frascino {
2128b1a824SVincenzo Frascino register struct timezone *tz asm("x1") = _tz;
2228b1a824SVincenzo Frascino register struct __kernel_old_timeval *tv asm("x0") = _tv;
2328b1a824SVincenzo Frascino register long ret asm ("x0");
2428b1a824SVincenzo Frascino register long nr asm("x8") = __NR_gettimeofday;
2528b1a824SVincenzo Frascino
2628b1a824SVincenzo Frascino asm volatile(
2728b1a824SVincenzo Frascino " svc #0\n"
2828b1a824SVincenzo Frascino : "=r" (ret)
2928b1a824SVincenzo Frascino : "r" (tv), "r" (tz), "r" (nr)
3028b1a824SVincenzo Frascino : "memory");
3128b1a824SVincenzo Frascino
3228b1a824SVincenzo Frascino return ret;
3328b1a824SVincenzo Frascino }
3428b1a824SVincenzo Frascino
3528b1a824SVincenzo Frascino static __always_inline
clock_gettime_fallback(clockid_t _clkid,struct __kernel_timespec * _ts)3628b1a824SVincenzo Frascino long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
3728b1a824SVincenzo Frascino {
3828b1a824SVincenzo Frascino register struct __kernel_timespec *ts asm("x1") = _ts;
3928b1a824SVincenzo Frascino register clockid_t clkid asm("x0") = _clkid;
4028b1a824SVincenzo Frascino register long ret asm ("x0");
4128b1a824SVincenzo Frascino register long nr asm("x8") = __NR_clock_gettime;
4228b1a824SVincenzo Frascino
4328b1a824SVincenzo Frascino asm volatile(
4428b1a824SVincenzo Frascino " svc #0\n"
4528b1a824SVincenzo Frascino : "=r" (ret)
4628b1a824SVincenzo Frascino : "r" (clkid), "r" (ts), "r" (nr)
4728b1a824SVincenzo Frascino : "memory");
4828b1a824SVincenzo Frascino
4928b1a824SVincenzo Frascino return ret;
5028b1a824SVincenzo Frascino }
5128b1a824SVincenzo Frascino
5228b1a824SVincenzo Frascino static __always_inline
clock_getres_fallback(clockid_t _clkid,struct __kernel_timespec * _ts)5328b1a824SVincenzo Frascino int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
5428b1a824SVincenzo Frascino {
5528b1a824SVincenzo Frascino register struct __kernel_timespec *ts asm("x1") = _ts;
5628b1a824SVincenzo Frascino register clockid_t clkid asm("x0") = _clkid;
5728b1a824SVincenzo Frascino register long ret asm ("x0");
5828b1a824SVincenzo Frascino register long nr asm("x8") = __NR_clock_getres;
5928b1a824SVincenzo Frascino
6028b1a824SVincenzo Frascino asm volatile(
6128b1a824SVincenzo Frascino " svc #0\n"
6228b1a824SVincenzo Frascino : "=r" (ret)
6328b1a824SVincenzo Frascino : "r" (clkid), "r" (ts), "r" (nr)
6428b1a824SVincenzo Frascino : "memory");
6528b1a824SVincenzo Frascino
6628b1a824SVincenzo Frascino return ret;
6728b1a824SVincenzo Frascino }
6828b1a824SVincenzo Frascino
__arch_get_hw_counter(s32 clock_mode,const struct vdso_data * vd)694c5a116aSThomas Gleixner static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
704c5a116aSThomas Gleixner const struct vdso_data *vd)
7128b1a824SVincenzo Frascino {
7228b1a824SVincenzo Frascino u64 res;
7328b1a824SVincenzo Frascino
7427e11a9fSVincenzo Frascino /*
755e3c6a31SThomas Gleixner * Core checks for mode already, so this raced against a concurrent
765e3c6a31SThomas Gleixner * update. Return something. Core will do another round and then
775e3c6a31SThomas Gleixner * see the mode change and fallback to the syscall.
7827e11a9fSVincenzo Frascino */
795e3c6a31SThomas Gleixner if (clock_mode == VDSO_CLOCKMODE_NONE)
805e3c6a31SThomas Gleixner return 0;
8127e11a9fSVincenzo Frascino
8227e11a9fSVincenzo Frascino /*
83*9025cebfSJoey Gouly * If FEAT_ECV is available, use the self-synchronizing counter.
84*9025cebfSJoey Gouly * Otherwise the isb is required to prevent that the counter value
8527e11a9fSVincenzo Frascino * is speculated.
8627e11a9fSVincenzo Frascino */
87*9025cebfSJoey Gouly asm volatile(
88*9025cebfSJoey Gouly ALTERNATIVE("isb\n"
89*9025cebfSJoey Gouly "mrs %0, cntvct_el0",
90*9025cebfSJoey Gouly "nop\n"
91*9025cebfSJoey Gouly __mrs_s("%0", SYS_CNTVCTSS_EL0),
92*9025cebfSJoey Gouly ARM64_HAS_ECV)
93*9025cebfSJoey Gouly : "=r" (res)
94*9025cebfSJoey Gouly :
95*9025cebfSJoey Gouly : "memory");
96*9025cebfSJoey Gouly
9777ec4625SWill Deacon arch_counter_enforce_ordering(res);
9828b1a824SVincenzo Frascino
9928b1a824SVincenzo Frascino return res;
10028b1a824SVincenzo Frascino }
10128b1a824SVincenzo Frascino
10228b1a824SVincenzo Frascino static __always_inline
__arch_get_vdso_data(void)10328b1a824SVincenzo Frascino const struct vdso_data *__arch_get_vdso_data(void)
10428b1a824SVincenzo Frascino {
10528b1a824SVincenzo Frascino return _vdso_data;
10628b1a824SVincenzo Frascino }
10728b1a824SVincenzo Frascino
1083503d56cSAndrei Vagin #ifdef CONFIG_TIME_NS
1093503d56cSAndrei Vagin static __always_inline
__arch_get_timens_vdso_data(const struct vdso_data * vd)110808094fcSChristophe Leroy const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
1113503d56cSAndrei Vagin {
1123503d56cSAndrei Vagin return _timens_data;
1133503d56cSAndrei Vagin }
1143503d56cSAndrei Vagin #endif
1153503d56cSAndrei Vagin
11628b1a824SVincenzo Frascino #endif /* !__ASSEMBLY__ */
11728b1a824SVincenzo Frascino
11828b1a824SVincenzo Frascino #endif /* __ASM_VDSO_GETTIMEOFDAY_H */
119