162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2018 ARM Limited
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#ifndef __ASM_VDSO_GETTIMEOFDAY_H
662306a36Sopenharmony_ci#define __ASM_VDSO_GETTIMEOFDAY_H
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef __ASSEMBLY__
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/alternative.h>
1162306a36Sopenharmony_ci#include <asm/barrier.h>
1262306a36Sopenharmony_ci#include <asm/unistd.h>
1362306a36Sopenharmony_ci#include <asm/sysreg.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define VDSO_HAS_CLOCK_GETRES		1
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic __always_inline
1862306a36Sopenharmony_ciint gettimeofday_fallback(struct __kernel_old_timeval *_tv,
1962306a36Sopenharmony_ci			  struct timezone *_tz)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	register struct timezone *tz asm("x1") = _tz;
2262306a36Sopenharmony_ci	register struct __kernel_old_timeval *tv asm("x0") = _tv;
2362306a36Sopenharmony_ci	register long ret asm ("x0");
2462306a36Sopenharmony_ci	register long nr asm("x8") = __NR_gettimeofday;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	asm volatile(
2762306a36Sopenharmony_ci	"       svc #0\n"
2862306a36Sopenharmony_ci	: "=r" (ret)
2962306a36Sopenharmony_ci	: "r" (tv), "r" (tz), "r" (nr)
3062306a36Sopenharmony_ci	: "memory");
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	return ret;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic __always_inline
3662306a36Sopenharmony_cilong clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	register struct __kernel_timespec *ts asm("x1") = _ts;
3962306a36Sopenharmony_ci	register clockid_t clkid asm("x0") = _clkid;
4062306a36Sopenharmony_ci	register long ret asm ("x0");
4162306a36Sopenharmony_ci	register long nr asm("x8") = __NR_clock_gettime;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	asm volatile(
4462306a36Sopenharmony_ci	"       svc #0\n"
4562306a36Sopenharmony_ci	: "=r" (ret)
4662306a36Sopenharmony_ci	: "r" (clkid), "r" (ts), "r" (nr)
4762306a36Sopenharmony_ci	: "memory");
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return ret;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic __always_inline
5362306a36Sopenharmony_ciint clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	register struct __kernel_timespec *ts asm("x1") = _ts;
5662306a36Sopenharmony_ci	register clockid_t clkid asm("x0") = _clkid;
5762306a36Sopenharmony_ci	register long ret asm ("x0");
5862306a36Sopenharmony_ci	register long nr asm("x8") = __NR_clock_getres;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	asm volatile(
6162306a36Sopenharmony_ci	"       svc #0\n"
6262306a36Sopenharmony_ci	: "=r" (ret)
6362306a36Sopenharmony_ci	: "r" (clkid), "r" (ts), "r" (nr)
6462306a36Sopenharmony_ci	: "memory");
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return ret;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
7062306a36Sopenharmony_ci						 const struct vdso_data *vd)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	u64 res;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/*
7562306a36Sopenharmony_ci	 * Core checks for mode already, so this raced against a concurrent
7662306a36Sopenharmony_ci	 * update. Return something. Core will do another round and then
7762306a36Sopenharmony_ci	 * see the mode change and fallback to the syscall.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci	if (clock_mode == VDSO_CLOCKMODE_NONE)
8062306a36Sopenharmony_ci		return 0;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/*
8362306a36Sopenharmony_ci	 * If FEAT_ECV is available, use the self-synchronizing counter.
8462306a36Sopenharmony_ci	 * Otherwise the isb is required to prevent that the counter value
8562306a36Sopenharmony_ci	 * is speculated.
8662306a36Sopenharmony_ci	*/
8762306a36Sopenharmony_ci	asm volatile(
8862306a36Sopenharmony_ci	ALTERNATIVE("isb\n"
8962306a36Sopenharmony_ci		    "mrs %0, cntvct_el0",
9062306a36Sopenharmony_ci		    "nop\n"
9162306a36Sopenharmony_ci		    __mrs_s("%0", SYS_CNTVCTSS_EL0),
9262306a36Sopenharmony_ci		    ARM64_HAS_ECV)
9362306a36Sopenharmony_ci	: "=r" (res)
9462306a36Sopenharmony_ci	:
9562306a36Sopenharmony_ci	: "memory");
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	arch_counter_enforce_ordering(res);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return res;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic __always_inline
10362306a36Sopenharmony_ciconst struct vdso_data *__arch_get_vdso_data(void)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	return _vdso_data;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#ifdef CONFIG_TIME_NS
10962306a36Sopenharmony_cistatic __always_inline
11062306a36Sopenharmony_ciconst struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	return _timens_data;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci#endif
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#endif /* __ASM_VDSO_GETTIMEOFDAY_H */
119