Linux-libre 5.4.39-gnu
[librecmc/linux-libre.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 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 */