1 /*
2 * Copyright (c) 2014-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_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
40 struct __qdf_timer_t {
41 struct timer_list os_timer;
42 qdf_timer_func_t callback;
43 void *context;
44 };
45
46 #define __qdf_scaled_msecs_to_jiffies(msec) \
47 (qdf_timer_get_multiplier() * msecs_to_jiffies(msec))
48
49 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
__os_timer_shim(struct timer_list * os_timer)50 static inline void __os_timer_shim(struct timer_list *os_timer)
51 {
52 struct __qdf_timer_t *timer = from_timer(timer, os_timer, os_timer);
53
54 timer->callback(timer->context);
55 }
56
__qdf_timer_init(struct __qdf_timer_t * timer,qdf_timer_func_t func,void * arg,QDF_TIMER_TYPE type)57 static inline QDF_STATUS __qdf_timer_init(struct __qdf_timer_t *timer,
58 qdf_timer_func_t func, void *arg,
59 QDF_TIMER_TYPE type)
60 {
61 struct timer_list *os_timer = &timer->os_timer;
62 uint32_t flags = 0;
63
64 timer->callback = func;
65 timer->context = arg;
66
67 if (type == QDF_TIMER_TYPE_SW)
68 flags |= TIMER_DEFERRABLE;
69 else if (type == QDF_TIMER_TYPE_SW_SPIN)
70 flags |= TIMER_DEFERRABLE | TIMER_PINNED;
71
72 if (object_is_on_stack(os_timer))
73 timer_setup_on_stack(os_timer, __os_timer_shim, flags);
74 else
75 timer_setup(os_timer, __os_timer_shim, flags);
76
77 return QDF_STATUS_SUCCESS;
78 }
79 #else
80
81 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
82 #define setup_deferrable_timer(timer, fn, data) \
83 __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE)
84 #endif
85
__os_timer_shim(unsigned long addr)86 static inline void __os_timer_shim(unsigned long addr)
87 {
88 struct __qdf_timer_t *timer = (void *)addr;
89
90 timer->callback(timer->context);
91 }
92
__qdf_timer_init(struct __qdf_timer_t * timer,qdf_timer_func_t func,void * arg,QDF_TIMER_TYPE type)93 static inline QDF_STATUS __qdf_timer_init(struct __qdf_timer_t *timer,
94 qdf_timer_func_t func, void *arg,
95 QDF_TIMER_TYPE type)
96 {
97 struct timer_list *os_timer = &timer->os_timer;
98 bool is_on_stack = object_is_on_stack(os_timer);
99 unsigned long addr = (unsigned long)timer;
100
101 timer->callback = func;
102 timer->context = arg;
103
104 if (type == QDF_TIMER_TYPE_SW) {
105 if (is_on_stack)
106 setup_deferrable_timer_on_stack(os_timer,
107 __os_timer_shim,
108 addr);
109 else
110 setup_deferrable_timer(os_timer, __os_timer_shim, addr);
111 } else if (type == QDF_TIMER_TYPE_SW_SPIN) {
112 if (is_on_stack)
113 __setup_timer_on_stack(os_timer,
114 __os_timer_shim,
115 addr,
116 TIMER_DEFERRABLE | TIMER_PINNED);
117 else
118 __setup_timer(os_timer,
119 __os_timer_shim,
120 addr,
121 TIMER_DEFERRABLE | TIMER_PINNED);
122 } else {
123 if (is_on_stack)
124 setup_timer_on_stack(os_timer, __os_timer_shim, addr);
125 else
126 setup_timer(os_timer, __os_timer_shim, addr);
127 }
128
129 return QDF_STATUS_SUCCESS;
130 }
131 #endif /* KERNEL_VERSION(4, 15, 0)*/
132
__qdf_timer_start(struct __qdf_timer_t * timer,uint32_t msec)133 static inline void __qdf_timer_start(struct __qdf_timer_t *timer, uint32_t msec)
134 {
135 struct timer_list *os_timer = &timer->os_timer;
136
137 os_timer->expires = jiffies + __qdf_scaled_msecs_to_jiffies(msec);
138 add_timer(os_timer);
139 }
140
141 static inline
__qdf_timer_start_on(struct __qdf_timer_t * timer,uint32_t msec,int cpu)142 void __qdf_timer_start_on(struct __qdf_timer_t *timer, uint32_t msec,
143 int cpu)
144 {
145 struct timer_list *os_timer = &timer->os_timer;
146
147 os_timer->expires = jiffies + __qdf_scaled_msecs_to_jiffies(msec);
148 add_timer_on(os_timer, cpu);
149 }
150
__qdf_timer_mod(struct __qdf_timer_t * timer,uint32_t msec)151 static inline bool __qdf_timer_mod(struct __qdf_timer_t *timer, uint32_t msec)
152 {
153 return mod_timer(&timer->os_timer,
154 jiffies + __qdf_scaled_msecs_to_jiffies(msec));
155 }
156
__qdf_timer_stop(struct __qdf_timer_t * timer)157 static inline bool __qdf_timer_stop(struct __qdf_timer_t *timer)
158 {
159 return !!del_timer(&timer->os_timer);
160 }
161
__qdf_timer_free(struct __qdf_timer_t * timer)162 static inline void __qdf_timer_free(struct __qdf_timer_t *timer)
163 {
164 struct timer_list *os_timer = &timer->os_timer;
165
166 del_timer_sync(os_timer);
167
168 if (object_is_on_stack(os_timer))
169 destroy_timer_on_stack(os_timer);
170 }
171
__qdf_timer_sync_cancel(struct __qdf_timer_t * timer)172 static inline bool __qdf_timer_sync_cancel(struct __qdf_timer_t *timer)
173 {
174 return del_timer_sync(&timer->os_timer);
175 }
176
177 #endif /* _I_QDF_TIMER_H */
178