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