xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/i_qdf_hrtimer.h (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
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;
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
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
112 int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer)
113 {
114 	return hrtimer_cancel(&timer->u.hrtimer);
115 }
116 #else
117 static inline
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 
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  * @hrtimer_mode: mode of hrtimer
143  *
144  * starts hrtimer in a context passed as per the context
145  *
146  * Return: void
147  */
148 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
149 static inline void  __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
150 				       void *cback,
151 				       enum qdf_clock_id clock,
152 				       enum qdf_hrtimer_mode mode,
153 				       enum qdf_context_mode ctx)
154 {
155 	struct hrtimer *hrtimer = &timer->u.hrtimer;
156 	enum hrtimer_mode hrt_mode;
157 
158 	timer->ctx = ctx;
159 	timer->callback = cback;
160 	timer->cb_ctx = timer;
161 
162 	if (timer->ctx == QDF_CONTEXT_TASKLET)
163 		mode |= HRTIMER_MODE_SOFT;
164 
165 	hrt_mode = __qdf_hrtimer_get_mode(mode);
166 	hrtimer_init(hrtimer, clock, hrt_mode);
167 	hrtimer->function = __qdf_hrtimer_cb;
168 }
169 #else
170 static inline void  __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer,
171 				       void *cback,
172 				       enum qdf_clock_id clock,
173 				       enum qdf_hrtimer_mode mode,
174 				       enum qdf_context_mode ctx)
175 {
176 	struct hrtimer *hrtimer = &timer->u.hrtimer;
177 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
178 	enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode);
179 
180 	timer->ctx = ctx;
181 	timer->callback = cback;
182 	timer->cb_ctx = timer;
183 
184 	if (timer->ctx == QDF_CONTEXT_HARDWARE) {
185 		hrtimer_init(hrtimer, clock, hrt_mode);
186 		hrtimer->function = __qdf_hrtimer_cb;
187 	} else if (timer->ctx == QDF_CONTEXT_TASKLET) {
188 		tasklet_hrtimer_init(tasklet_hrtimer, cback, clock, hrt_mode);
189 	}
190 }
191 #endif
192 
193 /**
194  * __qdf_hrtimer_kill() - kills hrtimer in given context
195  * @timer: pointer to the hrtimer object
196  *
197  * kills hrtimer in given context
198  *
199  * Return: void
200  */
201 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
202 static inline
203 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer)
204 {
205 	hrtimer_cancel(&timer->u.hrtimer);
206 }
207 #else
208 static inline
209 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer)
210 {
211 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
212 		hrtimer_cancel(&timer->u.hrtimer);
213 	else if (timer->ctx == QDF_CONTEXT_TASKLET)
214 		tasklet_hrtimer_cancel(&timer->u.tasklet_hrtimer);
215 }
216 #endif
217 
218 /**
219  * __qdf_hrtimer_get_remaining() - check remaining time in the timer
220  * @timer: pointer to the hrtimer object
221  *
222  * check whether the timer is on one of the queues
223  *
224  * Return: remaining time as ktime object
225  */
226 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
227 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer)
228 {
229 	struct hrtimer *hrtimer = &timer->u.hrtimer;
230 
231 	return hrtimer_get_remaining(hrtimer);
232 }
233 #else
234 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer)
235 {
236 	struct hrtimer *hrtimer = &timer->u.hrtimer;
237 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
238 
239 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
240 		return hrtimer_get_remaining(hrtimer);
241 	else
242 		return hrtimer_get_remaining(&tasklet_hrtimer->timer);
243 }
244 #endif
245 
246 /**
247  * __qdf_hrtimer_is_queued() - check whether the timer is on one of the queues
248  * @timer: pointer to the hrtimer object
249  *
250  * check whether the timer is on one of the queues
251  *
252  * Return: false when the timer was not in queue
253  *         true when the timer was in queue
254  */
255 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
256 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer)
257 {
258 	struct hrtimer *hrtimer = &timer->u.hrtimer;
259 
260 	return hrtimer_is_queued(hrtimer);
261 }
262 #else
263 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer)
264 {
265 	struct hrtimer *hrtimer = &timer->u.hrtimer;
266 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
267 
268 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
269 		return hrtimer_is_queued(hrtimer);
270 	else
271 		return hrtimer_is_queued(&tasklet_hrtimer->timer);
272 }
273 #endif
274 
275 /**
276  * __qdf_hrtimer_callback_running() - check if callback is running
277  * @timer: pointer to the hrtimer object
278  *
279  * check whether the timer is running the callback function
280  *
281  * Return: false when callback is not running
282  *         true when callback is running
283  */
284 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
285 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer)
286 {
287 	struct hrtimer *hrtimer = &timer->u.hrtimer;
288 
289 	return hrtimer_callback_running(hrtimer);
290 }
291 #else
292 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer)
293 {
294 	struct hrtimer *hrtimer = &timer->u.hrtimer;
295 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
296 
297 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
298 		return hrtimer_callback_running(hrtimer);
299 	else
300 		return hrtimer_callback_running(&tasklet_hrtimer->timer);
301 }
302 #endif
303 
304 /**
305  * __qdf_hrtimer_active() - check if timer is active
306  * @timer: pointer to the hrtimer object
307  *
308  * Check if timer is active. A timer is active, when it is enqueued into
309  * the rbtree or the callback function is running.
310  *
311  * Return: false if timer is not active
312  *         true if timer is active
313  */
314 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
315 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer)
316 {
317 	struct hrtimer *hrtimer = &timer->u.hrtimer;
318 
319 	return hrtimer_active(hrtimer);
320 }
321 #else
322 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer)
323 {
324 	struct hrtimer *hrtimer = &timer->u.hrtimer;
325 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
326 
327 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
328 		return hrtimer_active(hrtimer);
329 	else
330 		return hrtimer_active(&tasklet_hrtimer->timer);
331 }
332 #endif
333 
334 /**
335  * __qdf_hrtimer_cb_get_time() - get remaining time in callback
336  * @timer: pointer to the hrtimer object
337  *
338  * Get remaining time in the hrtimer callback
339  *
340  * Return: time remaining as ktime object
341  */
342 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
343 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer)
344 {
345 	struct hrtimer *hrtimer = &timer->u.hrtimer;
346 
347 	return hrtimer_cb_get_time(hrtimer);
348 }
349 #else
350 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer)
351 {
352 	struct hrtimer *hrtimer = &timer->u.hrtimer;
353 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
354 
355 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
356 		return hrtimer_cb_get_time(hrtimer);
357 	else
358 		return hrtimer_cb_get_time(&tasklet_hrtimer->timer);
359 }
360 #endif
361 
362 /**
363  * __qdf_hrtimer_forward() - forward the hrtimer
364  * @timer: pointer to the hrtimer object
365  * @now: current ktime
366  * @interval: interval to forward as ktime object
367  *
368  * Forward the timer expiry so it will expire in the future
369  *
370  * Return:the number of overruns
371  */
372 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
373 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer,
374 					     ktime_t now,
375 					     ktime_t interval)
376 {
377 	struct hrtimer *hrtimer = &timer->u.hrtimer;
378 
379 	return hrtimer_forward(hrtimer, now, interval);
380 }
381 
382 #else
383 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer,
384 					     ktime_t now,
385 					     ktime_t interval)
386 {
387 	struct hrtimer *hrtimer = &timer->u.hrtimer;
388 	struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer;
389 
390 	if (timer->ctx == QDF_CONTEXT_HARDWARE)
391 		return hrtimer_forward(hrtimer, now, interval);
392 	else
393 		return hrtimer_forward(&tasklet_hrtimer->timer, now, interval);
394 }
395 #endif
396 
397 /**
398  * __qdf_hrtimer_add_expires() - Add expiry to hrtimer with given interval
399  * @timer: pointer to the __qdf_hrtimer_data_t object
400  * @interval: interval to add as ktime_t object
401  *
402  * Add the timer expiry so it will expire in the future
403  *
404  * Return: None
405  */
406 static inline
407 void __qdf_hrtimer_add_expires(__qdf_hrtimer_data_t *timer, ktime_t interval)
408 {
409 	hrtimer_add_expires(&timer->u.hrtimer, interval);
410 }
411 #endif /* _I_QDF_HRTIMER_H */
412