aboutsummaryrefslogtreecommitdiffstats
path: root/include/os/linux/timers.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/os/linux/timers.c')
-rw-r--r--include/os/linux/timers.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/include/os/linux/timers.c b/include/os/linux/timers.c
new file mode 100644
index 0000000..018fd2d
--- /dev/null
+++ b/include/os/linux/timers.c
@@ -0,0 +1,269 @@
1/*
2 * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/ktime.h>
18#include <linux/delay.h>
19
20#include <nvgpu/timers.h>
21#include <nvgpu/soc.h>
22#include <nvgpu/gk20a.h>
23
24#include "platform_gk20a.h"
25
26/*
27 * Returns 1 if the platform is pre-Si and should ignore the timeout checking.
28 * Setting %NVGPU_TIMER_NO_PRE_SI will make this always return 0 (i.e do the
29 * timeout check regardless of platform).
30 */
31static int nvgpu_timeout_is_pre_silicon(struct nvgpu_timeout *timeout)
32{
33 if (timeout->flags & NVGPU_TIMER_NO_PRE_SI)
34 return 0;
35
36 return !nvgpu_platform_is_silicon(timeout->g);
37}
38
39/**
40 * nvgpu_timeout_init - Init timer.
41 *
42 * @g - nvgpu device.
43 * @timeout - The timer.
44 * @duration - Timeout in milliseconds or number of retries.
45 * @flags - Flags for timer.
46 *
47 * This configures the timeout to start the timeout duration now, i.e: when this
48 * function is called. Available flags to pass to @flags:
49 *
50 * %NVGPU_TIMER_CPU_TIMER
51 * %NVGPU_TIMER_RETRY_TIMER
52 * %NVGPU_TIMER_NO_PRE_SI
53 * %NVGPU_TIMER_SILENT_TIMEOUT
54 *
55 * If neither %NVGPU_TIMER_CPU_TIMER or %NVGPU_TIMER_RETRY_TIMER is passed then
56 * a CPU timer is used by default.
57 */
58int nvgpu_timeout_init(struct gk20a *g, struct nvgpu_timeout *timeout,
59 u32 duration, unsigned long flags)
60{
61 if (flags & ~NVGPU_TIMER_FLAG_MASK)
62 return -EINVAL;
63
64 memset(timeout, 0, sizeof(*timeout));
65
66 timeout->g = g;
67 timeout->flags = flags;
68
69 if (flags & NVGPU_TIMER_RETRY_TIMER)
70 timeout->retries.max = duration;
71 else
72 timeout->time = ktime_to_ns(ktime_add_ns(ktime_get(),
73 (s64)NSEC_PER_MSEC * duration));
74
75 return 0;
76}
77
78static int __nvgpu_timeout_expired_msg_cpu(struct nvgpu_timeout *timeout,
79 void *caller,
80 const char *fmt, va_list args)
81{
82 struct gk20a *g = timeout->g;
83 ktime_t now = ktime_get();
84
85 if (nvgpu_timeout_is_pre_silicon(timeout))
86 return 0;
87
88 if (ktime_after(now, ns_to_ktime(timeout->time))) {
89 if (!(timeout->flags & NVGPU_TIMER_SILENT_TIMEOUT)) {
90 char buf[128];
91
92 vsnprintf(buf, sizeof(buf), fmt, args);
93
94 nvgpu_err(g, "Timeout detected @ %pF %s", caller, buf);
95 }
96
97 return -ETIMEDOUT;
98 }
99
100 return 0;
101}
102
103static int __nvgpu_timeout_expired_msg_retry(struct nvgpu_timeout *timeout,
104 void *caller,
105 const char *fmt, va_list args)
106{
107 struct gk20a *g = timeout->g;
108
109 if (nvgpu_timeout_is_pre_silicon(timeout))
110 return 0;
111
112 if (timeout->retries.attempted >= timeout->retries.max) {
113 if (!(timeout->flags & NVGPU_TIMER_SILENT_TIMEOUT)) {
114 char buf[128];
115
116 vsnprintf(buf, sizeof(buf), fmt, args);
117
118 nvgpu_err(g, "No more retries @ %pF %s", caller, buf);
119 }
120
121 return -ETIMEDOUT;
122 }
123
124 timeout->retries.attempted++;
125
126 return 0;
127}
128
129/**
130 * __nvgpu_timeout_expired_msg - Check if a timeout has expired.
131 *
132 * @timeout - The timeout to check.
133 * @caller - Address of the caller of this function.
134 * @fmt - The fmt string.
135 *
136 * Returns -ETIMEDOUT if the timeout has expired, 0 otherwise.
137 *
138 * If a timeout occurs and %NVGPU_TIMER_SILENT_TIMEOUT is not set in the timeout
139 * then a message is printed based on %fmt.
140 */
141int __nvgpu_timeout_expired_msg(struct nvgpu_timeout *timeout,
142 void *caller, const char *fmt, ...)
143{
144 int ret;
145 va_list args;
146
147 va_start(args, fmt);
148 if (timeout->flags & NVGPU_TIMER_RETRY_TIMER)
149 ret = __nvgpu_timeout_expired_msg_retry(timeout, caller, fmt,
150 args);
151 else
152 ret = __nvgpu_timeout_expired_msg_cpu(timeout, caller, fmt,
153 args);
154 va_end(args);
155
156 return ret;
157}
158
159/**
160 * nvgpu_timeout_peek_expired - Check the status of a timeout.
161 *
162 * @timeout - The timeout to check.
163 *
164 * Returns non-zero if the timeout is expired, zero otherwise. In the case of
165 * retry timers this will not increment the underlying retry count. Also if the
166 * timer has expired no messages will be printed.
167 *
168 * This function honors the pre-Si check as well.
169 */
170int nvgpu_timeout_peek_expired(struct nvgpu_timeout *timeout)
171{
172 if (nvgpu_timeout_is_pre_silicon(timeout))
173 return 0;
174
175 if (timeout->flags & NVGPU_TIMER_RETRY_TIMER)
176 return timeout->retries.attempted >= timeout->retries.max;
177 else
178 return ktime_after(ktime_get(), ns_to_ktime(timeout->time));
179}
180
181/**
182 * nvgpu_udelay - Delay for some number of microseconds.
183 *
184 * @usecs - Microseconds to wait for.
185 *
186 * Wait for at least @usecs microseconds. This is not guaranteed to be perfectly
187 * accurate. This is normally backed by a busy-loop so this means waits should
188 * be kept short, below 100us. If longer delays are necessary then
189 * nvgpu_msleep() should be preferred.
190 *
191 * Alternatively, on some platforms, nvgpu_usleep_range() is usable. This
192 * function will attempt to not use a busy-loop.
193 */
194void nvgpu_udelay(unsigned int usecs)
195{
196 udelay(usecs);
197}
198
199/**
200 * nvgpu_usleep_range - Sleep for a range of microseconds.
201 *
202 * @min_us - Minimum wait time.
203 * @max_us - Maximum wait time.
204 *
205 * Wait for some number of microseconds between @min_us and @max_us. This,
206 * unlike nvgpu_udelay(), will attempt to sleep for the passed number of
207 * microseconds instead of busy looping. Not all platforms support this,
208 * and in that case this reduces to nvgpu_udelay(min_us).
209 *
210 * Linux note: this is not safe to use in atomic context. If you are in
211 * atomic context you must use nvgpu_udelay().
212 */
213void nvgpu_usleep_range(unsigned int min_us, unsigned int max_us)
214{
215 usleep_range(min_us, max_us);
216}
217
218/**
219 * nvgpu_msleep - Sleep for some milliseconds.
220 *
221 * @msecs - Sleep for at least this many milliseconds.
222 *
223 * Sleep for at least @msecs of milliseconds. For small @msecs (less than 20 ms
224 * or so) the sleep will be significantly longer due to scheduling overhead and
225 * mechanics.
226 */
227void nvgpu_msleep(unsigned int msecs)
228{
229 msleep(msecs);
230}
231
232/**
233 * nvgpu_current_time_ms - Time in milliseconds from a monotonic clock.
234 *
235 * Return a clock in millisecond units. The start time of the clock is
236 * unspecified; the time returned can be compared with older ones to measure
237 * durations. The source clock does not jump when the system clock is adjusted.
238 */
239s64 nvgpu_current_time_ms(void)
240{
241 return ktime_to_ms(ktime_get());
242}
243
244/**
245 * nvgpu_current_time_ns - Time in nanoseconds from a monotonic clock.
246 *
247 * Return a clock in nanosecond units. The start time of the clock is
248 * unspecified; the time returned can be compared with older ones to measure
249 * durations. The source clock does not jump when the system clock is adjusted.
250 */
251s64 nvgpu_current_time_ns(void)
252{
253 return ktime_to_ns(ktime_get());
254}
255
256/**
257 * nvgpu_hr_timestamp - Opaque 'high resolution' time stamp.
258 *
259 * Return a "high resolution" time stamp. It does not really matter exactly what
260 * it is, so long as it generally returns unique values and monotonically
261 * increases - wrap around _is_ possible though in a system running for long
262 * enough.
263 *
264 * Note: what high resolution means is system dependent.
265 */
266u64 nvgpu_hr_timestamp(void)
267{
268 return get_cycles();
269}