xref: /linux/arch/powerpc/include/asm/vdso/gettimeofday.h (revision ef9226cd56b718c79184a3466d32984a51cb449c)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_POWERPC_VDSO_GETTIMEOFDAY_H
3 #define _ASM_POWERPC_VDSO_GETTIMEOFDAY_H
4 
5 #ifndef __ASSEMBLY__
6 
7 #include <asm/vdso/timebase.h>
8 #include <asm/barrier.h>
9 #include <asm/unistd.h>
10 #include <uapi/linux/time.h>
11 
12 #define VDSO_HAS_CLOCK_GETRES		1
13 
14 #define VDSO_HAS_TIME			1
15 
16 static __always_inline int do_syscall_2(const unsigned long _r0, const unsigned long _r3,
17 					const unsigned long _r4)
18 {
19 	register long r0 asm("r0") = _r0;
20 	register unsigned long r3 asm("r3") = _r3;
21 	register unsigned long r4 asm("r4") = _r4;
22 	register int ret asm ("r3");
23 
24 	asm volatile(
25 		"       sc\n"
26 		"	bns+	1f\n"
27 		"	neg	%0, %0\n"
28 		"1:\n"
29 	: "=r" (ret), "+r" (r4), "+r" (r0)
30 	: "r" (r3)
31 	: "memory", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "cr0", "ctr");
32 
33 	return ret;
34 }
35 
36 static __always_inline
37 int gettimeofday_fallback(struct __kernel_old_timeval *_tv, struct timezone *_tz)
38 {
39 	return do_syscall_2(__NR_gettimeofday, (unsigned long)_tv, (unsigned long)_tz);
40 }
41 
42 #ifdef __powerpc64__
43 
44 static __always_inline
45 int clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
46 {
47 	return do_syscall_2(__NR_clock_gettime, _clkid, (unsigned long)_ts);
48 }
49 
50 static __always_inline
51 int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
52 {
53 	return do_syscall_2(__NR_clock_getres, _clkid, (unsigned long)_ts);
54 }
55 
56 #else
57 
58 #define BUILD_VDSO32		1
59 
60 static __always_inline
61 int clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
62 {
63 	return do_syscall_2(__NR_clock_gettime64, _clkid, (unsigned long)_ts);
64 }
65 
66 static __always_inline
67 int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
68 {
69 	return do_syscall_2(__NR_clock_getres_time64, _clkid, (unsigned long)_ts);
70 }
71 
72 static __always_inline
73 int clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
74 {
75 	return do_syscall_2(__NR_clock_gettime, _clkid, (unsigned long)_ts);
76 }
77 
78 static __always_inline
79 int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
80 {
81 	return do_syscall_2(__NR_clock_getres, _clkid, (unsigned long)_ts);
82 }
83 #endif
84 
85 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode,
86 						 const struct vdso_data *vd)
87 {
88 	return get_tb();
89 }
90 
91 const struct vdso_data *__arch_get_vdso_data(void);
92 
93 #ifdef CONFIG_TIME_NS
94 static __always_inline
95 const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd)
96 {
97 	return (void *)vd + (1U << CONFIG_PAGE_SHIFT);
98 }
99 #endif
100 
101 static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
102 {
103 	return true;
104 }
105 #define vdso_clocksource_ok vdso_clocksource_ok
106 
107 /*
108  * powerpc specific delta calculation.
109  *
110  * This variant removes the masking of the subtraction because the
111  * clocksource mask of all VDSO capable clocksources on powerpc is U64_MAX
112  * which would result in a pointless operation. The compiler cannot
113  * optimize it away as the mask comes from the vdso data and is not compile
114  * time constant.
115  */
116 static __always_inline u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
117 {
118 	return (cycles - last) * mult;
119 }
120 #define vdso_calc_delta vdso_calc_delta
121 
122 #ifndef __powerpc64__
123 static __always_inline u64 vdso_shift_ns(u64 ns, unsigned long shift)
124 {
125 	u32 hi = ns >> 32;
126 	u32 lo = ns;
127 
128 	lo >>= shift;
129 	lo |= hi << (32 - shift);
130 	hi >>= shift;
131 
132 	if (likely(hi == 0))
133 		return lo;
134 
135 	return ((u64)hi << 32) | lo;
136 }
137 #define vdso_shift_ns vdso_shift_ns
138 #endif
139 
140 #ifdef __powerpc64__
141 int __c_kernel_clock_gettime(clockid_t clock, struct __kernel_timespec *ts,
142 			     const struct vdso_data *vd);
143 int __c_kernel_clock_getres(clockid_t clock_id, struct __kernel_timespec *res,
144 			    const struct vdso_data *vd);
145 #else
146 int __c_kernel_clock_gettime(clockid_t clock, struct old_timespec32 *ts,
147 			     const struct vdso_data *vd);
148 int __c_kernel_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts,
149 			       const struct vdso_data *vd);
150 int __c_kernel_clock_getres(clockid_t clock_id, struct old_timespec32 *res,
151 			    const struct vdso_data *vd);
152 #endif
153 int __c_kernel_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz,
154 			    const struct vdso_data *vd);
155 __kernel_old_time_t __c_kernel_time(__kernel_old_time_t *time,
156 				    const struct vdso_data *vd);
157 #endif /* __ASSEMBLY__ */
158 
159 #endif /* _ASM_POWERPC_VDSO_GETTIMEOFDAY_H */
160