162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_VDSO_GETTIMEOFDAY_H
362306a36Sopenharmony_ci#define _ASM_POWERPC_VDSO_GETTIMEOFDAY_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifndef __ASSEMBLY__
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/page.h>
862306a36Sopenharmony_ci#include <asm/vdso/timebase.h>
962306a36Sopenharmony_ci#include <asm/barrier.h>
1062306a36Sopenharmony_ci#include <asm/unistd.h>
1162306a36Sopenharmony_ci#include <uapi/linux/time.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define VDSO_HAS_CLOCK_GETRES		1
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define VDSO_HAS_TIME			1
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic __always_inline int do_syscall_2(const unsigned long _r0, const unsigned long _r3,
1862306a36Sopenharmony_ci					const unsigned long _r4)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	register long r0 asm("r0") = _r0;
2162306a36Sopenharmony_ci	register unsigned long r3 asm("r3") = _r3;
2262306a36Sopenharmony_ci	register unsigned long r4 asm("r4") = _r4;
2362306a36Sopenharmony_ci	register int ret asm ("r3");
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	asm volatile(
2662306a36Sopenharmony_ci		"       sc\n"
2762306a36Sopenharmony_ci		"	bns+	1f\n"
2862306a36Sopenharmony_ci		"	neg	%0, %0\n"
2962306a36Sopenharmony_ci		"1:\n"
3062306a36Sopenharmony_ci	: "=r" (ret), "+r" (r4), "+r" (r0)
3162306a36Sopenharmony_ci	: "r" (r3)
3262306a36Sopenharmony_ci	: "memory", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "cr0", "ctr");
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	return ret;
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic __always_inline
3862306a36Sopenharmony_ciint gettimeofday_fallback(struct __kernel_old_timeval *_tv, struct timezone *_tz)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	return do_syscall_2(__NR_gettimeofday, (unsigned long)_tv, (unsigned long)_tz);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#ifdef __powerpc64__
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic __always_inline
4662306a36Sopenharmony_ciint clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	return do_syscall_2(__NR_clock_gettime, _clkid, (unsigned long)_ts);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic __always_inline
5262306a36Sopenharmony_ciint clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	return do_syscall_2(__NR_clock_getres, _clkid, (unsigned long)_ts);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#else
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define BUILD_VDSO32		1
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic __always_inline
6262306a36Sopenharmony_ciint clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	return do_syscall_2(__NR_clock_gettime64, _clkid, (unsigned long)_ts);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic __always_inline
6862306a36Sopenharmony_ciint clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return do_syscall_2(__NR_clock_getres_time64, _clkid, (unsigned long)_ts);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic __always_inline
7462306a36Sopenharmony_ciint clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	return do_syscall_2(__NR_clock_gettime, _clkid, (unsigned long)_ts);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic __always_inline
8062306a36Sopenharmony_ciint clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	return do_syscall_2(__NR_clock_getres, _clkid, (unsigned long)_ts);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci#endif
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
8762306a36Sopenharmony_ci						 const struct vdso_data *vd)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	return get_tb();
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciconst struct vdso_data *__arch_get_vdso_data(void);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#ifdef CONFIG_TIME_NS
9562306a36Sopenharmony_cistatic __always_inline
9662306a36Sopenharmony_ciconst struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	return (void *)vd + PAGE_SIZE;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci#endif
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic inline bool vdso_clocksource_ok(const struct vdso_data *vd)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	return true;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci#define vdso_clocksource_ok vdso_clocksource_ok
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/*
10962306a36Sopenharmony_ci * powerpc specific delta calculation.
11062306a36Sopenharmony_ci *
11162306a36Sopenharmony_ci * This variant removes the masking of the subtraction because the
11262306a36Sopenharmony_ci * clocksource mask of all VDSO capable clocksources on powerpc is U64_MAX
11362306a36Sopenharmony_ci * which would result in a pointless operation. The compiler cannot
11462306a36Sopenharmony_ci * optimize it away as the mask comes from the vdso data and is not compile
11562306a36Sopenharmony_ci * time constant.
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_cistatic __always_inline u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	return (cycles - last) * mult;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci#define vdso_calc_delta vdso_calc_delta
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#ifndef __powerpc64__
12462306a36Sopenharmony_cistatic __always_inline u64 vdso_shift_ns(u64 ns, unsigned long shift)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	u32 hi = ns >> 32;
12762306a36Sopenharmony_ci	u32 lo = ns;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	lo >>= shift;
13062306a36Sopenharmony_ci	lo |= hi << (32 - shift);
13162306a36Sopenharmony_ci	hi >>= shift;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (likely(hi == 0))
13462306a36Sopenharmony_ci		return lo;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return ((u64)hi << 32) | lo;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci#define vdso_shift_ns vdso_shift_ns
13962306a36Sopenharmony_ci#endif
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#ifdef __powerpc64__
14262306a36Sopenharmony_ciint __c_kernel_clock_gettime(clockid_t clock, struct __kernel_timespec *ts,
14362306a36Sopenharmony_ci			     const struct vdso_data *vd);
14462306a36Sopenharmony_ciint __c_kernel_clock_getres(clockid_t clock_id, struct __kernel_timespec *res,
14562306a36Sopenharmony_ci			    const struct vdso_data *vd);
14662306a36Sopenharmony_ci#else
14762306a36Sopenharmony_ciint __c_kernel_clock_gettime(clockid_t clock, struct old_timespec32 *ts,
14862306a36Sopenharmony_ci			     const struct vdso_data *vd);
14962306a36Sopenharmony_ciint __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts,
15062306a36Sopenharmony_ci			       const struct vdso_data *vd);
15162306a36Sopenharmony_ciint __c_kernel_clock_getres(clockid_t clock_id, struct old_timespec32 *res,
15262306a36Sopenharmony_ci			    const struct vdso_data *vd);
15362306a36Sopenharmony_ci#endif
15462306a36Sopenharmony_ciint __c_kernel_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz,
15562306a36Sopenharmony_ci			    const struct vdso_data *vd);
15662306a36Sopenharmony_ci__kernel_old_time_t __c_kernel_time(__kernel_old_time_t *time,
15762306a36Sopenharmony_ci				    const struct vdso_data *vd);
15862306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci#endif /* _ASM_POWERPC_VDSO_GETTIMEOFDAY_H */
161