1 /*
2 * Copyright (c) 2014-2019,2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: i_qdf_hrtimer
22 * This file provides OS dependent timer API's.
23 */
24
25 #ifndef _I_QDF_HRTIMER_H
26 #define _I_QDF_HRTIMER_H
27
28 #include <linux/version.h>
29 #include <linux/delay.h>
30 #include <linux/timer.h>
31 #include <linux/jiffies.h>
32 #include <qdf_types.h>
33 #include <i_qdf_trace.h>
34
35 struct __qdf_hrtimer_data_internal_t;
36 /* hrtimer data type */
37 typedef struct __qdf_hrtimer_data_internal_t {
38 union {
39 struct hrtimer hrtimer;
40 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0))
41 struct tasklet_hrtimer tasklet_hrtimer;
42 #endif
43 } u;
44 enum qdf_context_mode ctx;
45 struct __qdf_hrtimer_data_internal_t *cb_ctx;
46 enum qdf_hrtimer_restart_status (*callback)
47 (struct __qdf_hrtimer_data_internal_t *);
48 } __qdf_hrtimer_data_t;
49
50 /**
51 * __qdf_hrtimer_get_mode() - Get hrtimer_mode with qdf mode
52 * @mode: mode of hrtimer
53 *
54 * Get hrtimer_mode with qdf hrtimer mode
55 *
56 * Return: void
57 */
58 static inline
__qdf_hrtimer_get_mode(enum qdf_hrtimer_mode mode)59 enum hrtimer_mode __qdf_hrtimer_get_mode(enum qdf_hrtimer_mode mode)
60 {
61 return (enum hrtimer_mode)mode;
62 }
63
64 /**
65 * __qdf_hrtimer_start() - Starts hrtimer in given context
66 * @timer: pointer to the hrtimer object
67 * @interval: interval to forward as qdf_ktime_t object
68 * @mode: mode of hrtimer
69 *
70 * Starts hrtimer in given context
71 *
72 * Return: void
73 */
74 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
75 static inline
__qdf_hrtimer_start(__qdf_hrtimer_data_t * timer,ktime_t interval,enum qdf_hrtimer_mode mode)76 void __qdf_hrtimer_start(__qdf_hrtimer_data_t *timer, ktime_t interval,
77 enum qdf_hrtimer_mode mode)
78 {
79 enum hrtimer_mode hrt_mode;
80
81 if (timer->ctx == QDF_CONTEXT_TASKLET)
82 mode |= HRTIMER_MODE_SOFT;
83
84 hrt_mode = __qdf_hrtimer_get_mode(mode);
85 hrtimer_start(&timer->u.hrtimer, interval, hrt_mode);
86 }
87 #else
88 static inline
__qdf_hrtimer_start(__qdf_hrtimer_data_t * timer,ktime_t interval,enum qdf_hrtimer_mode mode)89 void __qdf_hrtimer_start(__qdf_hrtimer_data_t *timer, ktime_t interval,
90 enum qdf_hrtimer_mode mode)
91 {
92 enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
93
94 if (timer->ctx == QDF_CONTEXT_HARDWARE)
95 hrtimer_start(&timer->u.hrtimer, interval, hrt_mode);
96 else if (timer->ctx == QDF_CONTEXT_TASKLET)
97 tasklet_hrtimer_start(&timer->u.tasklet_hrtimer,
98 interval, hrt_mode);
99 }
100 #endif
101
102 /**
103 * __qdf_hrtimer_cancel() - cancels hrtimer in given context
104 * @timer: pointer to the hrtimer object
105 *
106 * cancels hrtimer in given context
107 *
108 * Return: int
109 */
110 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
111 static inline
__qdf_hrtimer_cancel(__qdf_hrtimer_data_t * timer)112 int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer)
113 {
114 return hrtimer_cancel(&timer->u.hrtimer);
115 }
116 #else
117 static inline
__qdf_hrtimer_cancel(__qdf_hrtimer_data_t * timer)118 int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer)
119 {
120 if (timer->ctx == QDF_CONTEXT_HARDWARE)
121 return hrtimer_cancel(&timer->u.hrtimer);
122 else if (timer->ctx == QDF_CONTEXT_TASKLET)
123 return hrtimer_cancel(&timer->u.tasklet_hrtimer.timer);
124
125 return 0;
126 }
127 #endif
128
__qdf_hrtimer_cb(struct hrtimer * arg)129 static enum hrtimer_restart __qdf_hrtimer_cb(struct hrtimer *arg)
130 {
131 __qdf_hrtimer_data_t *timer = container_of(arg, __qdf_hrtimer_data_t,
132 u.hrtimer);
133
134 return (enum hrtimer_restart)timer->callback(timer->cb_ctx);
135 }
136
137 /**
138 * __qdf_hrtimer_init() - init hrtimer in a given context
139 * @timer: pointer to the hrtimer object
140 * @cback: callback function to be fired
141 * @clock: clock id
142 * @mode: mode of hrtimer
143 * @ctx: interrupt context mode
144 *
145 * starts hrtimer in a context passed as per the context
146 *
147 * Return: void
148 */
149 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
__qdf_hrtimer_init(__qdf_hrtimer_data_t * timer,void * cback,enum qdf_clock_id clock,enum qdf_hrtimer_mode mode,enum qdf_context_mode ctx)150 static inline void __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
151 void *cback,
152 enum qdf_clock_id clock,
153 enum qdf_hrtimer_mode mode,
154 enum qdf_context_mode ctx)
155 {
156 struct hrtimer *hrtimer = &timer->u.hrtimer;
157 enum hrtimer_mode hrt_mode;
158
159 timer->ctx = ctx;
160 timer->callback = cback;
161 timer->cb_ctx = timer;
162
163 if (timer->ctx == QDF_CONTEXT_TASKLET)
164 mode |= HRTIMER_MODE_SOFT;
165
166 hrt_mode = __qdf_hrtimer_get_mode(mode);
167 hrtimer_init(hrtimer, clock, hrt_mode);
168 hrtimer->function = __qdf_hrtimer_cb;
169 }
170 #else
__qdf_hrtimer_init(__qdf_hrtimer_data_t * timer,void * cback,enum qdf_clock_id clock,enum qdf_hrtimer_mode mode,enum qdf_context_mode ctx)171 static inline void __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
172 void *cback,
173 enum qdf_clock_id clock,
174 enum qdf_hrtimer_mode mode,
175 enum qdf_context_mode ctx)
176 {
177 struct hrtimer *hrtimer = &timer->u.hrtimer;
178 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
179 enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
180
181 timer->ctx = ctx;
182 timer->callback = cback;
183 timer->cb_ctx = timer;
184
185 if (timer->ctx == QDF_CONTEXT_HARDWARE) {
186 hrtimer_init(hrtimer, clock, hrt_mode);
187 hrtimer->function = __qdf_hrtimer_cb;
188 } else if (timer->ctx == QDF_CONTEXT_TASKLET) {
189 tasklet_hrtimer_init(tasklet_hrtimer, cback, clock, hrt_mode);
190 }
191 }
192 #endif
193
194 /**
195 * __qdf_hrtimer_kill() - kills hrtimer in given context
196 * @timer: pointer to the hrtimer object
197 *
198 * kills hrtimer in given context
199 *
200 * Return: void
201 */
202 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
203 static inline
__qdf_hrtimer_kill(__qdf_hrtimer_data_t * timer)204 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer)
205 {
206 hrtimer_cancel(&timer->u.hrtimer);
207 }
208 #else
209 static inline
__qdf_hrtimer_kill(__qdf_hrtimer_data_t * timer)210 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer)
211 {
212 if (timer->ctx == QDF_CONTEXT_HARDWARE)
213 hrtimer_cancel(&timer->u.hrtimer);
214 else if (timer->ctx == QDF_CONTEXT_TASKLET)
215 tasklet_hrtimer_cancel(&timer->u.tasklet_hrtimer);
216 }
217 #endif
218
219 /**
220 * __qdf_hrtimer_get_remaining() - check remaining time in the timer
221 * @timer: pointer to the hrtimer object
222 *
223 * check whether the timer is on one of the queues
224 *
225 * Return: remaining time as ktime object
226 */
227 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
__qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t * timer)228 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer)
229 {
230 struct hrtimer *hrtimer = &timer->u.hrtimer;
231
232 return hrtimer_get_remaining(hrtimer);
233 }
234 #else
__qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t * timer)235 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer)
236 {
237 struct hrtimer *hrtimer = &timer->u.hrtimer;
238 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
239
240 if (timer->ctx == QDF_CONTEXT_HARDWARE)
241 return hrtimer_get_remaining(hrtimer);
242 else
243 return hrtimer_get_remaining(&tasklet_hrtimer->timer);
244 }
245 #endif
246
247 /**
248 * __qdf_hrtimer_is_queued() - check whether the timer is on one of the queues
249 * @timer: pointer to the hrtimer object
250 *
251 * check whether the timer is on one of the queues
252 *
253 * Return: false when the timer was not in queue
254 * true when the timer was in queue
255 */
256 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
__qdf_hrtimer_is_queued(__qdf_hrtimer_data_t * timer)257 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer)
258 {
259 struct hrtimer *hrtimer = &timer->u.hrtimer;
260
261 return hrtimer_is_queued(hrtimer);
262 }
263 #else
__qdf_hrtimer_is_queued(__qdf_hrtimer_data_t * timer)264 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer)
265 {
266 struct hrtimer *hrtimer = &timer->u.hrtimer;
267 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
268
269 if (timer->ctx == QDF_CONTEXT_HARDWARE)
270 return hrtimer_is_queued(hrtimer);
271 else
272 return hrtimer_is_queued(&tasklet_hrtimer->timer);
273 }
274 #endif
275
276 /**
277 * __qdf_hrtimer_callback_running() - check if callback is running
278 * @timer: pointer to the hrtimer object
279 *
280 * check whether the timer is running the callback function
281 *
282 * Return: false when callback is not running
283 * true when callback is running
284 */
285 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
__qdf_hrtimer_callback_running(__qdf_hrtimer_data_t * timer)286 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer)
287 {
288 struct hrtimer *hrtimer = &timer->u.hrtimer;
289
290 return hrtimer_callback_running(hrtimer);
291 }
292 #else
__qdf_hrtimer_callback_running(__qdf_hrtimer_data_t * timer)293 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer)
294 {
295 struct hrtimer *hrtimer = &timer->u.hrtimer;
296 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
297
298 if (timer->ctx == QDF_CONTEXT_HARDWARE)
299 return hrtimer_callback_running(hrtimer);
300 else
301 return hrtimer_callback_running(&tasklet_hrtimer->timer);
302 }
303 #endif
304
305 /**
306 * __qdf_hrtimer_active() - check if timer is active
307 * @timer: pointer to the hrtimer object
308 *
309 * Check if timer is active. A timer is active, when it is enqueued into
310 * the rbtree or the callback function is running.
311 *
312 * Return: false if timer is not active
313 * true if timer is active
314 */
315 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
__qdf_hrtimer_active(__qdf_hrtimer_data_t * timer)316 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer)
317 {
318 struct hrtimer *hrtimer = &timer->u.hrtimer;
319
320 return hrtimer_active(hrtimer);
321 }
322 #else
__qdf_hrtimer_active(__qdf_hrtimer_data_t * timer)323 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer)
324 {
325 struct hrtimer *hrtimer = &timer->u.hrtimer;
326 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
327
328 if (timer->ctx == QDF_CONTEXT_HARDWARE)
329 return hrtimer_active(hrtimer);
330 else
331 return hrtimer_active(&tasklet_hrtimer->timer);
332 }
333 #endif
334
335 /**
336 * __qdf_hrtimer_cb_get_time() - get remaining time in callback
337 * @timer: pointer to the hrtimer object
338 *
339 * Get remaining time in the hrtimer callback
340 *
341 * Return: time remaining as ktime object
342 */
343 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
__qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t * timer)344 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer)
345 {
346 struct hrtimer *hrtimer = &timer->u.hrtimer;
347
348 return hrtimer_cb_get_time(hrtimer);
349 }
350 #else
__qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t * timer)351 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer)
352 {
353 struct hrtimer *hrtimer = &timer->u.hrtimer;
354 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
355
356 if (timer->ctx == QDF_CONTEXT_HARDWARE)
357 return hrtimer_cb_get_time(hrtimer);
358 else
359 return hrtimer_cb_get_time(&tasklet_hrtimer->timer);
360 }
361 #endif
362
363 /**
364 * __qdf_hrtimer_forward() - forward the hrtimer
365 * @timer: pointer to the hrtimer object
366 * @now: current ktime
367 * @interval: interval to forward as ktime object
368 *
369 * Forward the timer expiry so it will expire in the future
370 *
371 * Return:the number of overruns
372 */
373 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
__qdf_hrtimer_forward(__qdf_hrtimer_data_t * timer,ktime_t now,ktime_t interval)374 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer,
375 ktime_t now,
376 ktime_t interval)
377 {
378 struct hrtimer *hrtimer = &timer->u.hrtimer;
379
380 return hrtimer_forward(hrtimer, now, interval);
381 }
382
383 #else
__qdf_hrtimer_forward(__qdf_hrtimer_data_t * timer,ktime_t now,ktime_t interval)384 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer,
385 ktime_t now,
386 ktime_t interval)
387 {
388 struct hrtimer *hrtimer = &timer->u.hrtimer;
389 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
390
391 if (timer->ctx == QDF_CONTEXT_HARDWARE)
392 return hrtimer_forward(hrtimer, now, interval);
393 else
394 return hrtimer_forward(&tasklet_hrtimer->timer, now, interval);
395 }
396 #endif
397
398 /**
399 * __qdf_hrtimer_add_expires() - Add expiry to hrtimer with given interval
400 * @timer: pointer to the __qdf_hrtimer_data_t object
401 * @interval: interval to add as ktime_t object
402 *
403 * Add the timer expiry so it will expire in the future
404 *
405 * Return: None
406 */
407 static inline
__qdf_hrtimer_add_expires(__qdf_hrtimer_data_t * timer,ktime_t interval)408 void __qdf_hrtimer_add_expires(__qdf_hrtimer_data_t *timer, ktime_t interval)
409 {
410 hrtimer_add_expires(&timer->u.hrtimer, interval);
411 }
412 #endif /* _I_QDF_HRTIMER_H */
413