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 static __always_inline long clock_gettime32_fallback( 100 clockid_t _clkid, 101 struct old_timespec32 *_ts) 102 { 103 register struct old_timespec32 *ts asm("a1") = _ts; 104 register clockid_t clkid asm("a0") = _clkid; 105 register long ret asm("v0"); 106 register long nr asm("v0") = __NR_clock_gettime; 107 register long error asm("a3"); 108 109 asm volatile( 110 " syscall\n" 111 : "=r" (ret), "=r" (error) 112 : "r" (clkid), "r" (ts), "r" (nr) 113 : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 114 "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 115 116 return error ? -ret : ret; 117 } 118 119 static __always_inline int clock_getres32_fallback( 120 clockid_t _clkid, 121 struct old_timespec32 *_ts) 122 { 123 register struct old_timespec32 *ts asm("a1") = _ts; 124 register clockid_t clkid asm("a0") = _clkid; 125 register long ret asm("v0"); 126 register long nr asm("v0") = __NR_clock_getres; 127 register long error asm("a3"); 128 129 asm volatile( 130 " syscall\n" 131 : "=r" (ret), "=r" (error) 132 : "r" (clkid), "r" (ts), "r" (nr) 133 : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", 134 "$14", "$15", "$24", "$25", "hi", "lo", "memory"); 135 136 return error ? -ret : ret; 137 } 138 #endif 139 140 #ifdef CONFIG_CSRC_R4K 141 142 static __always_inline u64 read_r4k_count(void) 143 { 144 unsigned int count; 145 146 __asm__ __volatile__( 147 " .set push\n" 148 " .set mips32r2\n" 149 " rdhwr %0, $2\n" 150 " .set pop\n" 151 : "=r" (count)); 152 153 return count; 154 } 155 156 #endif 157 158 #ifdef CONFIG_CLKSRC_MIPS_GIC 159 160 static __always_inline u64 read_gic_count(const struct vdso_data *data) 161 { 162 void __iomem *gic = get_gic(data); 163 u32 hi, hi2, lo; 164 165 do { 166 hi = __raw_readl(gic + sizeof(lo)); 167 lo = __raw_readl(gic); 168 hi2 = __raw_readl(gic + sizeof(lo)); 169 } while (hi2 != hi); 170 171 return (((u64)hi) << 32) + lo; 172 } 173 174 #endif 175 176 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) 177 { 178 #ifdef CONFIG_CLKSRC_MIPS_GIC 179 const struct vdso_data *data = get_vdso_data(); 180 #endif 181 u64 cycle_now; 182 183 switch (clock_mode) { 184 #ifdef CONFIG_CSRC_R4K 185 case VDSO_CLOCK_R4K: 186 cycle_now = read_r4k_count(); 187 break; 188 #endif 189 #ifdef CONFIG_CLKSRC_MIPS_GIC 190 case VDSO_CLOCK_GIC: 191 cycle_now = read_gic_count(data); 192 break; 193 #endif 194 default: 195 cycle_now = __VDSO_USE_SYSCALL; 196 break; 197 } 198 199 return cycle_now; 200 } 201 202 static __always_inline const struct vdso_data *__arch_get_vdso_data(void) 203 { 204 return get_vdso_data(); 205 } 206 207 #endif /* !__ASSEMBLY__ */ 208 209 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ 210