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