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