xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/i_qdf_timer.h (revision 8ddef7dd9a290d4a9b1efd5d3efacf51d78a1a0d)
1 /*
2  * Copyright (c) 2014-2019 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_timer
21  * This file provides OS dependent timer API's.
22  */
23 
24 #ifndef _I_QDF_TIMER_H
25 #define _I_QDF_TIMER_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_mc_timer.h"
32 #include <qdf_types.h>
33 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
34 #include <linux/sched/task_stack.h>
35 #endif
36 
37 typedef void (*qdf_timer_func_t)(void *);
38 
39 #define qdf_msecs_to_jiffies(msec) \
40 	(qdf_timer_get_multiplier() * msecs_to_jiffies(msec))
41 
42 struct __qdf_timer_t {
43 	struct timer_list os_timer;
44 	qdf_timer_func_t callback;
45 	void *context;
46 };
47 
48 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
49 static inline void __os_timer_shim(struct timer_list *os_timer)
50 {
51 	struct __qdf_timer_t *timer = from_timer(timer, os_timer, os_timer);
52 
53 	timer->callback(timer->context);
54 }
55 
56 static inline QDF_STATUS __qdf_timer_init(struct __qdf_timer_t *timer,
57 					  qdf_timer_func_t func, void *arg,
58 					  QDF_TIMER_TYPE type)
59 {
60 	struct timer_list *os_timer = &timer->os_timer;
61 	uint32_t flags = 0;
62 
63 	timer->callback = func;
64 	timer->context = arg;
65 
66 	if (type == QDF_TIMER_TYPE_SW)
67 		flags |= TIMER_DEFERRABLE;
68 
69 	if (object_is_on_stack(os_timer))
70 		timer_setup_on_stack(os_timer, __os_timer_shim, flags);
71 	else
72 		timer_setup(os_timer, __os_timer_shim, flags);
73 
74 	return QDF_STATUS_SUCCESS;
75 }
76 
77 #else
78 
79 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
80 #define setup_deferrable_timer(timer, fn, data) \
81 	__setup_timer((timer), (fn), (data), TIMER_DEFERRABLE)
82 #endif
83 
84 static inline void __os_timer_shim(unsigned long addr)
85 {
86 	struct __qdf_timer_t *timer = (void *)addr;
87 
88 	timer->callback(timer->context);
89 }
90 
91 static inline QDF_STATUS __qdf_timer_init(struct __qdf_timer_t *timer,
92 					  qdf_timer_func_t func, void *arg,
93 					  QDF_TIMER_TYPE type)
94 {
95 	struct timer_list *os_timer = &timer->os_timer;
96 	bool is_on_stack = object_is_on_stack(os_timer);
97 	unsigned long addr = (unsigned long)timer;
98 
99 	timer->callback = func;
100 	timer->context = arg;
101 
102 	if (type == QDF_TIMER_TYPE_SW) {
103 		if (is_on_stack)
104 			setup_deferrable_timer_on_stack(os_timer,
105 							__os_timer_shim,
106 							addr);
107 		else
108 			setup_deferrable_timer(os_timer, __os_timer_shim, addr);
109 	} else {
110 		if (is_on_stack)
111 			setup_timer_on_stack(os_timer, __os_timer_shim, addr);
112 		else
113 			setup_timer(os_timer, __os_timer_shim, addr);
114 	}
115 
116 	return QDF_STATUS_SUCCESS;
117 }
118 #endif /* KERNEL_VERSION(4, 15, 0)*/
119 
120 static inline void __qdf_timer_start(struct __qdf_timer_t *timer, uint32_t msec)
121 {
122 	struct timer_list *os_timer = &timer->os_timer;
123 
124 	os_timer->expires = jiffies + qdf_msecs_to_jiffies(msec);
125 	add_timer(os_timer);
126 }
127 
128 static inline void __qdf_timer_mod(struct __qdf_timer_t *timer, uint32_t msec)
129 {
130 	mod_timer(&timer->os_timer, jiffies + qdf_msecs_to_jiffies(msec));
131 }
132 
133 static inline bool __qdf_timer_stop(struct __qdf_timer_t *timer)
134 {
135 	return !!del_timer(&timer->os_timer);
136 }
137 
138 static inline void __qdf_timer_free(struct __qdf_timer_t *timer)
139 {
140 	struct timer_list *os_timer = &timer->os_timer;
141 
142 	del_timer_sync(os_timer);
143 
144 	if (object_is_on_stack(os_timer))
145 		destroy_timer_on_stack(os_timer);
146 }
147 
148 static inline bool __qdf_timer_sync_cancel(struct __qdf_timer_t *timer)
149 {
150 	return del_timer_sync(&timer->os_timer);
151 }
152 
153 #endif /* _I_QDF_TIMER_H */
154