18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2018 ARM Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#ifndef __ASM_VDSO_GETTIMEOFDAY_H
68c2ecf20Sopenharmony_ci#define __ASM_VDSO_GETTIMEOFDAY_H
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <asm/barrier.h>
118c2ecf20Sopenharmony_ci#include <asm/errno.h>
128c2ecf20Sopenharmony_ci#include <asm/unistd.h>
138c2ecf20Sopenharmony_ci#include <asm/vdso/cp15.h>
148c2ecf20Sopenharmony_ci#include <uapi/linux/time.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define VDSO_HAS_CLOCK_GETRES		1
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ciextern struct vdso_data *__get_datapage(void);
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic __always_inline int gettimeofday_fallback(
218c2ecf20Sopenharmony_ci				struct __kernel_old_timeval *_tv,
228c2ecf20Sopenharmony_ci				struct timezone *_tz)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	register struct timezone *tz asm("r1") = _tz;
258c2ecf20Sopenharmony_ci	register struct __kernel_old_timeval *tv asm("r0") = _tv;
268c2ecf20Sopenharmony_ci	register long ret asm ("r0");
278c2ecf20Sopenharmony_ci	register long nr asm("r7") = __NR_gettimeofday;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	asm volatile(
308c2ecf20Sopenharmony_ci	"	swi #0\n"
318c2ecf20Sopenharmony_ci	: "=r" (ret)
328c2ecf20Sopenharmony_ci	: "r" (tv), "r" (tz), "r" (nr)
338c2ecf20Sopenharmony_ci	: "memory");
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	return ret;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic __always_inline long clock_gettime_fallback(
398c2ecf20Sopenharmony_ci					clockid_t _clkid,
408c2ecf20Sopenharmony_ci					struct __kernel_timespec *_ts)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	register struct __kernel_timespec *ts asm("r1") = _ts;
438c2ecf20Sopenharmony_ci	register clockid_t clkid asm("r0") = _clkid;
448c2ecf20Sopenharmony_ci	register long ret asm ("r0");
458c2ecf20Sopenharmony_ci	register long nr asm("r7") = __NR_clock_gettime64;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	asm volatile(
488c2ecf20Sopenharmony_ci	"	swi #0\n"
498c2ecf20Sopenharmony_ci	: "=r" (ret)
508c2ecf20Sopenharmony_ci	: "r" (clkid), "r" (ts), "r" (nr)
518c2ecf20Sopenharmony_ci	: "memory");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return ret;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic __always_inline long clock_gettime32_fallback(
578c2ecf20Sopenharmony_ci					clockid_t _clkid,
588c2ecf20Sopenharmony_ci					struct old_timespec32 *_ts)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	register struct old_timespec32 *ts asm("r1") = _ts;
618c2ecf20Sopenharmony_ci	register clockid_t clkid asm("r0") = _clkid;
628c2ecf20Sopenharmony_ci	register long ret asm ("r0");
638c2ecf20Sopenharmony_ci	register long nr asm("r7") = __NR_clock_gettime;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	asm volatile(
668c2ecf20Sopenharmony_ci	"	swi #0\n"
678c2ecf20Sopenharmony_ci	: "=r" (ret)
688c2ecf20Sopenharmony_ci	: "r" (clkid), "r" (ts), "r" (nr)
698c2ecf20Sopenharmony_ci	: "memory");
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return ret;
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic __always_inline int clock_getres_fallback(
758c2ecf20Sopenharmony_ci					clockid_t _clkid,
768c2ecf20Sopenharmony_ci					struct __kernel_timespec *_ts)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	register struct __kernel_timespec *ts asm("r1") = _ts;
798c2ecf20Sopenharmony_ci	register clockid_t clkid asm("r0") = _clkid;
808c2ecf20Sopenharmony_ci	register long ret asm ("r0");
818c2ecf20Sopenharmony_ci	register long nr asm("r7") = __NR_clock_getres_time64;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	asm volatile(
848c2ecf20Sopenharmony_ci	"       swi #0\n"
858c2ecf20Sopenharmony_ci	: "=r" (ret)
868c2ecf20Sopenharmony_ci	: "r" (clkid), "r" (ts), "r" (nr)
878c2ecf20Sopenharmony_ci	: "memory");
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return ret;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic __always_inline int clock_getres32_fallback(
938c2ecf20Sopenharmony_ci					clockid_t _clkid,
948c2ecf20Sopenharmony_ci					struct old_timespec32 *_ts)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	register struct old_timespec32 *ts asm("r1") = _ts;
978c2ecf20Sopenharmony_ci	register clockid_t clkid asm("r0") = _clkid;
988c2ecf20Sopenharmony_ci	register long ret asm ("r0");
998c2ecf20Sopenharmony_ci	register long nr asm("r7") = __NR_clock_getres;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	asm volatile(
1028c2ecf20Sopenharmony_ci	"       swi #0\n"
1038c2ecf20Sopenharmony_ci	: "=r" (ret)
1048c2ecf20Sopenharmony_ci	: "r" (clkid), "r" (ts), "r" (nr)
1058c2ecf20Sopenharmony_ci	: "memory");
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return ret;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic inline bool arm_vdso_hres_capable(void)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	return IS_ENABLED(CONFIG_ARM_ARCH_TIMER);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci#define __arch_vdso_hres_capable arm_vdso_hres_capable
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic __always_inline u64 __arch_get_hw_counter(int clock_mode,
1178c2ecf20Sopenharmony_ci						 const struct vdso_data *vd)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM_ARCH_TIMER
1208c2ecf20Sopenharmony_ci	u64 cycle_now;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/*
1238c2ecf20Sopenharmony_ci	 * Core checks for mode already, so this raced against a concurrent
1248c2ecf20Sopenharmony_ci	 * update. Return something. Core will do another round and then
1258c2ecf20Sopenharmony_ci	 * see the mode change and fallback to the syscall.
1268c2ecf20Sopenharmony_ci	 */
1278c2ecf20Sopenharmony_ci	if (clock_mode == VDSO_CLOCKMODE_NONE)
1288c2ecf20Sopenharmony_ci		return 0;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	isb();
1318c2ecf20Sopenharmony_ci	cycle_now = read_sysreg(CNTVCT);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return cycle_now;
1348c2ecf20Sopenharmony_ci#else
1358c2ecf20Sopenharmony_ci	/* Make GCC happy. This is compiled out anyway */
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci#endif
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic __always_inline const struct vdso_data *__arch_get_vdso_data(void)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	return __get_datapage();
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
148