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