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