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