xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/i_qdf_hrtimer.h (revision 2b23d2e388c3e0ba9ac6113a9da98706fc6be2fd)
1 /*
2  * Copyright (c) 2014-2019,2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 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
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
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 = __qdf_hrtimer_get_mode(mode);
80 
81 	hrtimer_start(&timer->u.hrtimer, interval, hrt_mode);
82 }
83 #else
84 static inline
85 void __qdf_hrtimer_start(__qdf_hrtimer_data_t *timer, ktime_t interval,
86 			 enum qdf_hrtimer_mode mode)
87 {
88 	enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
89 
90 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
91 		hrtimer_start(&timer->u.hrtimer, interval, hrt_mode);
92 	else if (timer->ctx == QDF_CONTEXT_TASKLET)
93 		tasklet_hrtimer_start(&timer->u.tasklet_hrtimer,
94 				      interval, hrt_mode);
95 }
96 #endif
97 
98 /**
99  * __qdf_hrtimer_cancel() - cancels hrtimer in given context
100  * @timer: pointer to the hrtimer object
101  *
102  * cancels hrtimer in given context
103  *
104  * Return: int
105  */
106 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
107 static inline
108 int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer)
109 {
110 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
111 		return hrtimer_cancel(&timer->u.hrtimer);
112 
113 	return 0;
114 }
115 #else
116 static inline
117 int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer)
118 {
119 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
120 		return hrtimer_cancel(&timer->u.hrtimer);
121 	else if (timer->ctx == QDF_CONTEXT_TASKLET)
122 		return hrtimer_cancel(&timer->u.tasklet_hrtimer.timer);
123 
124 	return 0;
125 }
126 #endif
127 
128 static enum hrtimer_restart __qdf_hrtimer_cb(struct hrtimer *arg)
129 {
130 	__qdf_hrtimer_data_t *timer = container_of(arg, __qdf_hrtimer_data_t,
131 						   u.hrtimer);
132 
133 	return (enum hrtimer_restart)timer->callback(timer->cb_ctx);
134 }
135 
136 /**
137  * __qdf_hrtimer_init() - init hrtimer in a given context
138  * @timer: pointer to the hrtimer object
139  * @cback: callback function to be fired
140  * @clock: clock id
141  * @hrtimer_mode: mode of hrtimer
142  *
143  * starts hrtimer in a context passed as per the context
144  *
145  * Return: void
146  */
147 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
148 static inline void  __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
149 				       void *cback,
150 				       enum qdf_clock_id clock,
151 				       enum qdf_hrtimer_mode mode,
152 				       enum qdf_context_mode ctx)
153 {
154 	struct hrtimer *hrtimer = &timer->u.hrtimer;
155 	enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
156 
157 	timer->ctx = ctx;
158 	timer->callback = cback;
159 	timer->cb_ctx = timer;
160 
161 	if (timer->ctx == QDF_CONTEXT_HARDWARE) {
162 		hrtimer_init(hrtimer, clock, hrt_mode);
163 		hrtimer->function = __qdf_hrtimer_cb;
164 	} else if (timer->ctx == QDF_CONTEXT_TASKLET) {
165 		QDF_BUG(0);
166 	}
167 }
168 #else
169 static inline void  __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
170 				       void *cback,
171 				       enum qdf_clock_id clock,
172 				       enum qdf_hrtimer_mode mode,
173 				       enum qdf_context_mode ctx)
174 {
175 	struct hrtimer *hrtimer = &timer->u.hrtimer;
176 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
177 	enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
178 
179 	timer->ctx = ctx;
180 	timer->callback = cback;
181 	timer->cb_ctx = timer;
182 
183 	if (timer->ctx == QDF_CONTEXT_HARDWARE) {
184 		hrtimer_init(hrtimer, clock, hrt_mode);
185 		hrtimer->function = __qdf_hrtimer_cb;
186 	} else if (timer->ctx == QDF_CONTEXT_TASKLET) {
187 		tasklet_hrtimer_init(tasklet_hrtimer, cback, clock, hrt_mode);
188 	}
189 }
190 #endif
191 
192 /**
193  * __qdf_hrtimer_kill() - kills hrtimer in given context
194  * @timer: pointer to the hrtimer object
195  *
196  * kills hrtimer in given context
197  *
198  * Return: void
199  */
200 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
201 static inline
202 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer)
203 {
204 	hrtimer_cancel(&timer->u.hrtimer);
205 }
206 #else
207 static inline
208 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer)
209 {
210 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
211 		hrtimer_cancel(&timer->u.hrtimer);
212 	else if (timer->ctx == QDF_CONTEXT_TASKLET)
213 		tasklet_hrtimer_cancel(&timer->u.tasklet_hrtimer);
214 }
215 #endif
216 
217 /**
218  * __qdf_hrtimer_get_remaining() - check remaining time in the timer
219  * @timer: pointer to the hrtimer object
220  *
221  * check whether the timer is on one of the queues
222  *
223  * Return: remaining time as ktime object
224  */
225 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
226 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer)
227 {
228 	struct hrtimer *hrtimer = &timer->u.hrtimer;
229 
230 	return hrtimer_get_remaining(hrtimer);
231 }
232 #else
233 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer)
234 {
235 	struct hrtimer *hrtimer = &timer->u.hrtimer;
236 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
237 
238 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
239 		return hrtimer_get_remaining(hrtimer);
240 	else
241 		return hrtimer_get_remaining(&tasklet_hrtimer->timer);
242 }
243 #endif
244 
245 /**
246  * __qdf_hrtimer_is_queued() - check whether the timer is on one of the queues
247  * @timer: pointer to the hrtimer object
248  *
249  * check whether the timer is on one of the queues
250  *
251  * Return: false when the timer was not in queue
252  *         true when the timer was in queue
253  */
254 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
255 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer)
256 {
257 	struct hrtimer *hrtimer = &timer->u.hrtimer;
258 
259 	return hrtimer_is_queued(hrtimer);
260 }
261 #else
262 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer)
263 {
264 	struct hrtimer *hrtimer = &timer->u.hrtimer;
265 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
266 
267 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
268 		return hrtimer_is_queued(hrtimer);
269 	else
270 		return hrtimer_is_queued(&tasklet_hrtimer->timer);
271 }
272 #endif
273 
274 /**
275  * __qdf_hrtimer_callback_running() - check if callback is running
276  * @timer: pointer to the hrtimer object
277  *
278  * check whether the timer is running the callback function
279  *
280  * Return: false when callback is not running
281  *         true when callback is running
282  */
283 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
284 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer)
285 {
286 	struct hrtimer *hrtimer = &timer->u.hrtimer;
287 
288 	return hrtimer_callback_running(hrtimer);
289 }
290 #else
291 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer)
292 {
293 	struct hrtimer *hrtimer = &timer->u.hrtimer;
294 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
295 
296 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
297 		return hrtimer_callback_running(hrtimer);
298 	else
299 		return hrtimer_callback_running(&tasklet_hrtimer->timer);
300 }
301 #endif
302 
303 /**
304  * __qdf_hrtimer_active() - check if timer is active
305  * @timer: pointer to the hrtimer object
306  *
307  * Check if timer is active. A timer is active, when it is enqueued into
308  * the rbtree or the callback function is running.
309  *
310  * Return: false if timer is not active
311  *         true if timer is active
312  */
313 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
314 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer)
315 {
316 	struct hrtimer *hrtimer = &timer->u.hrtimer;
317 
318 	return hrtimer_active(hrtimer);
319 }
320 #else
321 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer)
322 {
323 	struct hrtimer *hrtimer = &timer->u.hrtimer;
324 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
325 
326 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
327 		return hrtimer_active(hrtimer);
328 	else
329 		return hrtimer_active(&tasklet_hrtimer->timer);
330 }
331 #endif
332 
333 /**
334  * __qdf_hrtimer_cb_get_time() - get remaining time in callback
335  * @timer: pointer to the hrtimer object
336  *
337  * Get remaining time in the hrtimer callback
338  *
339  * Return: time remaining as ktime object
340  */
341 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
342 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer)
343 {
344 	struct hrtimer *hrtimer = &timer->u.hrtimer;
345 
346 	return hrtimer_cb_get_time(hrtimer);
347 }
348 #else
349 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer)
350 {
351 	struct hrtimer *hrtimer = &timer->u.hrtimer;
352 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
353 
354 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
355 		return hrtimer_cb_get_time(hrtimer);
356 	else
357 		return hrtimer_cb_get_time(&tasklet_hrtimer->timer);
358 }
359 #endif
360 
361 /**
362  * __qdf_hrtimer_forward() - forward the hrtimer
363  * @timer: pointer to the hrtimer object
364  * @now: current ktime
365  * @interval: interval to forward as ktime object
366  *
367  * Forward the timer expiry so it will expire in the future
368  *
369  * Return:the number of overruns
370  */
371 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
372 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer,
373 					     ktime_t now,
374 					     ktime_t interval)
375 {
376 	struct hrtimer *hrtimer = &timer->u.hrtimer;
377 
378 	return hrtimer_forward(hrtimer, now, interval);
379 }
380 #else
381 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer,
382 					     ktime_t now,
383 					     ktime_t interval)
384 {
385 	struct hrtimer *hrtimer = &timer->u.hrtimer;
386 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
387 
388 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
389 		return hrtimer_forward(hrtimer, now, interval);
390 	else
391 		return hrtimer_forward(&tasklet_hrtimer->timer, now, interval);
392 }
393 #endif
394 
395 #endif /* _I_QDF_HRTIMER_H */
396