1 /* 2 * Copyright (C) 2018 ARM Limited 3 * Copyright (C) 2015 Imagination Technologies 4 * Author: Alex Smith <alex.smith@imgtec.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 */ 11 #ifndef __ASM_VDSO_GETTIMEOFDAY_H 12 #define __ASM_VDSO_GETTIMEOFDAY_H 13 14 #ifndef __ASSEMBLY__ 15 16 #include <linux/compiler.h> 17 #include <linux/time.h> 18 19 #include <asm/vdso/vdso.h> 20 #include <asm/clocksource.h> 21 #include <asm/io.h> 22 #include <asm/unistd.h> 23 #include <asm/vdso.h> 24 25 #define VDSO_HAS_CLOCK_GETRES 1 26 27 #define __VDSO_USE_SYSCALL ULLONG_MAX 28 29 #ifdef CONFIG_MIPS_CLOCK_VSYSCALL 30 31 static __always_inline long gettimeofday_fallback( 32 struct __kernel_old_timeval *_tv, 33 struct timezone *_tz) 34 { 35 register struct timezone *tz asm("a1") = _tz; 36 register struct __kernel_old_timeval *tv asm("a0") = _tv; 37 register long ret asm("v0"); 38 register long nr asm("v0") = __NR_gettimeofday; 39 register long error asm("a3"); 40 41 asm volatile( 42 " syscall\n" 43 : "=r" (ret), "=r" (error) 44 : "r" (tv), "r" (tz), "r" (nr) 45 : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 46 "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 47 48 return error ? -ret : ret; 49 } 50 51 #else 52 53 static __always_inline long gettimeofday_fallback( 54 struct __kernel_old_timeval *_tv, 55 struct timezone *_tz) 56 { 57 return -1; 58 } 59 60 #endif 61 62 static __always_inline long clock_gettime_fallback( 63 clockid_t _clkid, 64 struct __kernel_timespec *_ts) 65 { 66 register struct __kernel_timespec *ts asm("a1") = _ts; 67 register clockid_t clkid asm("a0") = _clkid; 68 register long ret asm("v0"); 69 #if _MIPS_SIM == _MIPS_SIM_ABI64 70 register long nr asm("v0") = __NR_clock_gettime; 71 #else 72 register long nr asm("v0") = __NR_clock_gettime64; 73 #endif 74 register long error asm("a3"); 75 76 asm volatile( 77 " syscall\n" 78 : "=r" (ret), "=r" (error) 79 : "r" (clkid), "r" (ts), "r" (nr) 80 : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 81 "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 82 83 return error ? -ret : ret; 84 } 85 86 static __always_inline int clock_getres_fallback( 87 clockid_t _clkid, 88 struct __kernel_timespec *_ts) 89 { 90 register struct __kernel_timespec *ts asm("a1") = _ts; 91 register clockid_t clkid asm("a0") = _clkid; 92 register long ret asm("v0"); 93 #if _MIPS_SIM == _MIPS_SIM_ABI64 94 register long nr asm("v0") = __NR_clock_getres; 95 #else 96 register long nr asm("v0") = __NR_clock_getres_time64; 97 #endif 98 register long error asm("a3"); 99 100 asm volatile( 101 " syscall\n" 102 : "=r" (ret), "=r" (error) 103 : "r" (clkid), "r" (ts), "r" (nr) 104 : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 105 "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 106 107 return error ? -ret : ret; 108 } 109 110 #if _MIPS_SIM != _MIPS_SIM_ABI64 111 112 #define VDSO_HAS_32BIT_FALLBACK 1 113 114 static __always_inline long clock_gettime32_fallback( 115 clockid_t _clkid, 116 struct old_timespec32 *_ts) 117 { 118 register struct old_timespec32 *ts asm("a1") = _ts; 119 register clockid_t clkid asm("a0") = _clkid; 120 register long ret asm("v0"); 121 register long nr asm("v0") = __NR_clock_gettime; 122 register long error asm("a3"); 123 124 asm volatile( 125 " syscall\n" 126 : "=r" (ret), "=r" (error) 127 : "r" (clkid), "r" (ts), "r" (nr) 128 : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 129 "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 130 131 return error ? -ret : ret; 132 } 133 134 static __always_inline int clock_getres32_fallback( 135 clockid_t _clkid, 136 struct old_timespec32 *_ts) 137 { 138 register struct old_timespec32 *ts asm("a1") = _ts; 139 register clockid_t clkid asm("a0") = _clkid; 140 register long ret asm("v0"); 141 register long nr asm("v0") = __NR_clock_getres; 142 register long error asm("a3"); 143 144 asm volatile( 145 " syscall\n" 146 : "=r" (ret), "=r" (error) 147 : "r" (clkid), "r" (ts), "r" (nr) 148 : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 149 "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 150 151 return error ? -ret : ret; 152 } 153 #endif 154 155 #ifdef CONFIG_CSRC_R4K 156 157 static __always_inline u64 read_r4k_count(void) 158 { 159 unsigned int count; 160 161 __asm__ __volatile__( 162 " .set push\n" 163 " .set mips32r2\n" 164 " rdhwr %0, $2\n" 165 " .set pop\n" 166 : "=r" (count)); 167 168 return count; 169 } 170 171 #endif 172 173 #ifdef CONFIG_CLKSRC_MIPS_GIC 174 175 static __always_inline u64 read_gic_count(const struct vdso_data *data) 176 { 177 void __iomem *gic = get_gic(data); 178 u32 hi, hi2, lo; 179 180 do { 181 hi = __raw_readl(gic + sizeof(lo)); 182 lo = __raw_readl(gic); 183 hi2 = __raw_readl(gic + sizeof(lo)); 184 } while (hi2 != hi); 185 186 return (((u64)hi) << 32) + lo; 187 } 188 189 #endif 190 191 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) 192 { 193 #ifdef CONFIG_CLKSRC_MIPS_GIC 194 const struct vdso_data *data = get_vdso_data(); 195 #endif 196 u64 cycle_now; 197 198 switch (clock_mode) { 199 #ifdef CONFIG_CSRC_R4K 200 case VDSO_CLOCK_R4K: 201 cycle_now = read_r4k_count(); 202 break; 203 #endif 204 #ifdef CONFIG_CLKSRC_MIPS_GIC 205 case VDSO_CLOCK_GIC: 206 cycle_now = read_gic_count(data); 207 break; 208 #endif 209 default: 210 cycle_now = __VDSO_USE_SYSCALL; 211 break; 212 } 213 214 return cycle_now; 215 } 216 217 static __always_inline const struct vdso_data *__arch_get_vdso_data(void) 218 { 219 return get_vdso_data(); 220 } 221 222 #endif /* !__ASSEMBLY__ */ 223 224 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ 225