120e2fc42SVincenzo Frascino /* SPDX-License-Identifier: GPL-2.0 */
220e2fc42SVincenzo Frascino /*
320e2fc42SVincenzo Frascino  * Copyright (C) 2018 ARM Limited
420e2fc42SVincenzo Frascino  */
520e2fc42SVincenzo Frascino #ifndef __ASM_VDSO_GETTIMEOFDAY_H
620e2fc42SVincenzo Frascino #define __ASM_VDSO_GETTIMEOFDAY_H
720e2fc42SVincenzo Frascino 
820e2fc42SVincenzo Frascino #ifndef __ASSEMBLY__
920e2fc42SVincenzo Frascino 
10002dff36SWill Deacon #include <asm/barrier.h>
1178c85161SVincenzo Frascino #include <asm/errno.h>
1220e2fc42SVincenzo Frascino #include <asm/unistd.h>
1378c85161SVincenzo Frascino #include <asm/vdso/cp15.h>
1420e2fc42SVincenzo Frascino #include <uapi/linux/time.h>
1520e2fc42SVincenzo Frascino 
16052e76a3SVincenzo Frascino #define VDSO_HAS_CLOCK_GETRES		1
17052e76a3SVincenzo Frascino 
1820e2fc42SVincenzo Frascino extern struct vdso_data *__get_datapage(void);
1920e2fc42SVincenzo Frascino 
gettimeofday_fallback(struct __kernel_old_timeval * _tv,struct timezone * _tz)2020e2fc42SVincenzo Frascino static __always_inline int gettimeofday_fallback(
2120e2fc42SVincenzo Frascino 				struct __kernel_old_timeval *_tv,
2220e2fc42SVincenzo Frascino 				struct timezone *_tz)
2320e2fc42SVincenzo Frascino {
2420e2fc42SVincenzo Frascino 	register struct timezone *tz asm("r1") = _tz;
2520e2fc42SVincenzo Frascino 	register struct __kernel_old_timeval *tv asm("r0") = _tv;
2620e2fc42SVincenzo Frascino 	register long ret asm ("r0");
2720e2fc42SVincenzo Frascino 	register long nr asm("r7") = __NR_gettimeofday;
2820e2fc42SVincenzo Frascino 
2920e2fc42SVincenzo Frascino 	asm volatile(
3020e2fc42SVincenzo Frascino 	"	swi #0\n"
3120e2fc42SVincenzo Frascino 	: "=r" (ret)
3220e2fc42SVincenzo Frascino 	: "r" (tv), "r" (tz), "r" (nr)
3320e2fc42SVincenzo Frascino 	: "memory");
3420e2fc42SVincenzo Frascino 
3520e2fc42SVincenzo Frascino 	return ret;
3620e2fc42SVincenzo Frascino }
3720e2fc42SVincenzo Frascino 
clock_gettime_fallback(clockid_t _clkid,struct __kernel_timespec * _ts)3820e2fc42SVincenzo Frascino static __always_inline long clock_gettime_fallback(
3920e2fc42SVincenzo Frascino 					clockid_t _clkid,
4020e2fc42SVincenzo Frascino 					struct __kernel_timespec *_ts)
4120e2fc42SVincenzo Frascino {
4220e2fc42SVincenzo Frascino 	register struct __kernel_timespec *ts asm("r1") = _ts;
4320e2fc42SVincenzo Frascino 	register clockid_t clkid asm("r0") = _clkid;
4420e2fc42SVincenzo Frascino 	register long ret asm ("r0");
4520e2fc42SVincenzo Frascino 	register long nr asm("r7") = __NR_clock_gettime64;
4620e2fc42SVincenzo Frascino 
4720e2fc42SVincenzo Frascino 	asm volatile(
4820e2fc42SVincenzo Frascino 	"	swi #0\n"
4920e2fc42SVincenzo Frascino 	: "=r" (ret)
5020e2fc42SVincenzo Frascino 	: "r" (clkid), "r" (ts), "r" (nr)
5120e2fc42SVincenzo Frascino 	: "memory");
5220e2fc42SVincenzo Frascino 
5320e2fc42SVincenzo Frascino 	return ret;
5420e2fc42SVincenzo Frascino }
5520e2fc42SVincenzo Frascino 
clock_gettime32_fallback(clockid_t _clkid,struct old_timespec32 * _ts)56715f23b6SThomas Gleixner static __always_inline long clock_gettime32_fallback(
57715f23b6SThomas Gleixner 					clockid_t _clkid,
58715f23b6SThomas Gleixner 					struct old_timespec32 *_ts)
59715f23b6SThomas Gleixner {
60715f23b6SThomas Gleixner 	register struct old_timespec32 *ts asm("r1") = _ts;
61715f23b6SThomas Gleixner 	register clockid_t clkid asm("r0") = _clkid;
62715f23b6SThomas Gleixner 	register long ret asm ("r0");
63715f23b6SThomas Gleixner 	register long nr asm("r7") = __NR_clock_gettime;
64715f23b6SThomas Gleixner 
65715f23b6SThomas Gleixner 	asm volatile(
66715f23b6SThomas Gleixner 	"	swi #0\n"
67715f23b6SThomas Gleixner 	: "=r" (ret)
68715f23b6SThomas Gleixner 	: "r" (clkid), "r" (ts), "r" (nr)
69715f23b6SThomas Gleixner 	: "memory");
70715f23b6SThomas Gleixner 
71715f23b6SThomas Gleixner 	return ret;
72715f23b6SThomas Gleixner }
73715f23b6SThomas Gleixner 
clock_getres_fallback(clockid_t _clkid,struct __kernel_timespec * _ts)74052e76a3SVincenzo Frascino static __always_inline int clock_getres_fallback(
75052e76a3SVincenzo Frascino 					clockid_t _clkid,
76052e76a3SVincenzo Frascino 					struct __kernel_timespec *_ts)
77052e76a3SVincenzo Frascino {
78052e76a3SVincenzo Frascino 	register struct __kernel_timespec *ts asm("r1") = _ts;
79052e76a3SVincenzo Frascino 	register clockid_t clkid asm("r0") = _clkid;
80052e76a3SVincenzo Frascino 	register long ret asm ("r0");
81052e76a3SVincenzo Frascino 	register long nr asm("r7") = __NR_clock_getres_time64;
82052e76a3SVincenzo Frascino 
83052e76a3SVincenzo Frascino 	asm volatile(
84052e76a3SVincenzo Frascino 	"       swi #0\n"
85052e76a3SVincenzo Frascino 	: "=r" (ret)
86052e76a3SVincenzo Frascino 	: "r" (clkid), "r" (ts), "r" (nr)
87052e76a3SVincenzo Frascino 	: "memory");
88052e76a3SVincenzo Frascino 
89052e76a3SVincenzo Frascino 	return ret;
90052e76a3SVincenzo Frascino }
91052e76a3SVincenzo Frascino 
clock_getres32_fallback(clockid_t _clkid,struct old_timespec32 * _ts)92715f23b6SThomas Gleixner static __always_inline int clock_getres32_fallback(
93715f23b6SThomas Gleixner 					clockid_t _clkid,
94715f23b6SThomas Gleixner 					struct old_timespec32 *_ts)
95715f23b6SThomas Gleixner {
96715f23b6SThomas Gleixner 	register struct old_timespec32 *ts asm("r1") = _ts;
97715f23b6SThomas Gleixner 	register clockid_t clkid asm("r0") = _clkid;
98715f23b6SThomas Gleixner 	register long ret asm ("r0");
99715f23b6SThomas Gleixner 	register long nr asm("r7") = __NR_clock_getres;
100715f23b6SThomas Gleixner 
101715f23b6SThomas Gleixner 	asm volatile(
102715f23b6SThomas Gleixner 	"       swi #0\n"
103715f23b6SThomas Gleixner 	: "=r" (ret)
104715f23b6SThomas Gleixner 	: "r" (clkid), "r" (ts), "r" (nr)
105715f23b6SThomas Gleixner 	: "memory");
106715f23b6SThomas Gleixner 
107715f23b6SThomas Gleixner 	return ret;
108715f23b6SThomas Gleixner }
109715f23b6SThomas Gleixner 
arm_vdso_hres_capable(void)1103280badbSThomas Gleixner static inline bool arm_vdso_hres_capable(void)
1113280badbSThomas Gleixner {
1123280badbSThomas Gleixner 	return IS_ENABLED(CONFIG_ARM_ARCH_TIMER);
1133280badbSThomas Gleixner }
1143280badbSThomas Gleixner #define __arch_vdso_hres_capable arm_vdso_hres_capable
1153280badbSThomas Gleixner 
__arch_get_hw_counter(int clock_mode,const struct vdso_data * vd)1164c5a116aSThomas Gleixner static __always_inline u64 __arch_get_hw_counter(int clock_mode,
1174c5a116aSThomas Gleixner 						 const struct vdso_data *vd)
11820e2fc42SVincenzo Frascino {
11920e2fc42SVincenzo Frascino #ifdef CONFIG_ARM_ARCH_TIMER
12020e2fc42SVincenzo Frascino 	u64 cycle_now;
12120e2fc42SVincenzo Frascino 
1225e3c6a31SThomas Gleixner 	/*
1235e3c6a31SThomas Gleixner 	 * Core checks for mode already, so this raced against a concurrent
1245e3c6a31SThomas Gleixner 	 * update. Return something. Core will do another round and then
1255e3c6a31SThomas Gleixner 	 * see the mode change and fallback to the syscall.
1265e3c6a31SThomas Gleixner 	 */
1275e3c6a31SThomas Gleixner 	if (clock_mode == VDSO_CLOCKMODE_NONE)
1285e3c6a31SThomas Gleixner 		return 0;
12904bb9642SVincenzo Frascino 
13020e2fc42SVincenzo Frascino 	isb();
13120e2fc42SVincenzo Frascino 	cycle_now = read_sysreg(CNTVCT);
13220e2fc42SVincenzo Frascino 
13320e2fc42SVincenzo Frascino 	return cycle_now;
13420e2fc42SVincenzo Frascino #else
1355e3c6a31SThomas Gleixner 	/* Make GCC happy. This is compiled out anyway */
1365e3c6a31SThomas Gleixner 	return 0;
13720e2fc42SVincenzo Frascino #endif
13820e2fc42SVincenzo Frascino }
13920e2fc42SVincenzo Frascino 
__arch_get_vdso_data(void)14020e2fc42SVincenzo Frascino static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
14120e2fc42SVincenzo Frascino {
14220e2fc42SVincenzo Frascino 	return __get_datapage();
14320e2fc42SVincenzo Frascino }
14420e2fc42SVincenzo Frascino 
14520e2fc42SVincenzo Frascino #endif /* !__ASSEMBLY__ */
14620e2fc42SVincenzo Frascino 
14720e2fc42SVincenzo Frascino #endif /* __ASM_VDSO_GETTIMEOFDAY_H */
148