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 #ifdef CONFIG_CSRC_R4K 109 110 static __always_inline u64 read_r4k_count(void) 111 { 112 unsigned int count; 113 114 __asm__ __volatile__( 115 " .set push\n" 116 " .set mips32r2\n" 117 " rdhwr %0, $2\n" 118 " .set pop\n" 119 : "=r" (count)); 120 121 return count; 122 } 123 124 #endif 125 126 #ifdef CONFIG_CLKSRC_MIPS_GIC 127 128 static __always_inline u64 read_gic_count(const struct vdso_data *data) 129 { 130 void __iomem *gic = get_gic(data); 131 u32 hi, hi2, lo; 132 133 do { 134 hi = __raw_readl(gic + sizeof(lo)); 135 lo = __raw_readl(gic); 136 hi2 = __raw_readl(gic + sizeof(lo)); 137 } while (hi2 != hi); 138 139 return (((u64)hi) << 32) + lo; 140 } 141 142 #endif 143 144 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) 145 { 146 #ifdef CONFIG_CLKSRC_MIPS_GIC 147 const struct vdso_data *data = get_vdso_data(); 148 #endif 149 u64 cycle_now; 150 151 switch (clock_mode) { 152 #ifdef CONFIG_CSRC_R4K 153 case VDSO_CLOCK_R4K: 154 cycle_now = read_r4k_count(); 155 break; 156 #endif 157 #ifdef CONFIG_CLKSRC_MIPS_GIC 158 case VDSO_CLOCK_GIC: 159 cycle_now = read_gic_count(data); 160 break; 161 #endif 162 default: 163 cycle_now = 0; 164 break; 165 } 166 167 return cycle_now; 168 } 169 170 static __always_inline const struct vdso_data *__arch_get_vdso_data(void) 171 { 172 return get_vdso_data(); 173 } 174 175 #endif /* !__ASSEMBLY__ */ 176 177 #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ 178