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