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_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 33 /* hrtimer data type */ 34 typedef struct { 35 union { 36 struct hrtimer hrtimer; 37 #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)) 38 struct tasklet_hrtimer tasklet_hrtimer; 39 #endif 40 } u; 41 enum qdf_context_mode ctx; 42 } __qdf_hrtimer_data_t; 43 44 /** 45 * __qdf_hrtimer_get_mode() - Get hrtimer_mode with qdf mode 46 * @mode: mode of hrtimer 47 * 48 * Get hrtimer_mode with qdf hrtimer mode 49 * 50 * Return: void 51 */ 52 static inline 53 enum hrtimer_mode __qdf_hrtimer_get_mode(enum qdf_hrtimer_mode mode) 54 { 55 return (enum hrtimer_mode)mode; 56 } 57 58 /** 59 * __qdf_hrtimer_start() - Starts hrtimer in given context 60 * @timer: pointer to the hrtimer object 61 * @interval: interval to forward as qdf_ktime_t object 62 * @mode: mode of hrtimer 63 * 64 * Starts hrtimer in given context 65 * 66 * Return: void 67 */ 68 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 69 static inline 70 void __qdf_hrtimer_start(__qdf_hrtimer_data_t *timer, ktime_t interval, 71 enum qdf_hrtimer_mode mode) 72 { 73 enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode); 74 75 hrtimer_start(&timer->u.hrtimer, interval, hrt_mode); 76 } 77 #else 78 static inline 79 void __qdf_hrtimer_start(__qdf_hrtimer_data_t *timer, ktime_t interval, 80 enum qdf_hrtimer_mode mode) 81 { 82 enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode); 83 84 if (timer->ctx == QDF_CONTEXT_HARDWARE) 85 hrtimer_start(&timer->u.hrtimer, interval, hrt_mode); 86 else if (timer->ctx == QDF_CONTEXT_TASKLET) 87 tasklet_hrtimer_start(&timer->u.tasklet_hrtimer, 88 interval, hrt_mode); 89 } 90 #endif 91 92 /** 93 * __qdf_hrtimer_cancel() - cancels hrtimer in given context 94 * @timer: pointer to the hrtimer object 95 * 96 * cancels hrtimer in given context 97 * 98 * Return: int 99 */ 100 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 101 static inline 102 int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer) 103 { 104 if (timer->ctx == QDF_CONTEXT_HARDWARE) 105 return hrtimer_cancel(&timer->u.hrtimer); 106 107 return 0; 108 } 109 #else 110 static inline 111 int __qdf_hrtimer_cancel(__qdf_hrtimer_data_t *timer) 112 { 113 if (timer->ctx == QDF_CONTEXT_HARDWARE) 114 return hrtimer_cancel(&timer->u.hrtimer); 115 else if (timer->ctx == QDF_CONTEXT_TASKLET) 116 return hrtimer_cancel(&timer->u.tasklet_hrtimer.timer); 117 118 return 0; 119 } 120 #endif 121 122 /** 123 * __qdf_hrtimer_init() - init hrtimer in a given context 124 * @timer: pointer to the hrtimer object 125 * @cback: callback function to be fired 126 * @clock: clock id 127 * @hrtimer_mode: mode of hrtimer 128 * 129 * starts hrtimer in a context passed as per the context 130 * 131 * Return: void 132 */ 133 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 134 static inline void __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer, 135 void *cback, 136 enum qdf_clock_id clock, 137 enum qdf_hrtimer_mode mode, 138 enum qdf_context_mode ctx) 139 { 140 struct hrtimer *hrtimer = &timer->u.hrtimer; 141 enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode); 142 143 timer->ctx = ctx; 144 145 if (timer->ctx == QDF_CONTEXT_HARDWARE) { 146 hrtimer_init(hrtimer, clock, hrt_mode); 147 hrtimer->function = cback; 148 } else if (timer->ctx == QDF_CONTEXT_TASKLET) { 149 QDF_BUG(0); 150 } 151 } 152 #else 153 static inline void __qdf_hrtimer_init(__qdf_hrtimer_data_t *timer, 154 void *cback, 155 enum qdf_clock_id clock, 156 enum qdf_hrtimer_mode mode, 157 enum qdf_context_mode ctx) 158 { 159 struct hrtimer *hrtimer = &timer->u.hrtimer; 160 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 161 enum hrtimer_mode hrt_mode = __qdf_hrtimer_get_mode(mode); 162 163 timer->ctx = ctx; 164 165 if (timer->ctx == QDF_CONTEXT_HARDWARE) { 166 hrtimer_init(hrtimer, clock, hrt_mode); 167 hrtimer->function = cback; 168 } else if (timer->ctx == QDF_CONTEXT_TASKLET) { 169 tasklet_hrtimer_init(tasklet_hrtimer, cback, clock, hrt_mode); 170 } 171 } 172 #endif 173 174 /** 175 * __qdf_hrtimer_kill() - kills hrtimer in given context 176 * @timer: pointer to the hrtimer object 177 * 178 * kills hrtimer in given context 179 * 180 * Return: void 181 */ 182 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 183 static inline 184 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer) 185 { 186 hrtimer_cancel(&timer->u.hrtimer); 187 } 188 #else 189 static inline 190 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer) 191 { 192 if (timer->ctx == QDF_CONTEXT_HARDWARE) 193 hrtimer_cancel(&timer->u.hrtimer); 194 else if (timer->ctx == QDF_CONTEXT_TASKLET) 195 tasklet_hrtimer_cancel(&timer->u.tasklet_hrtimer); 196 } 197 #endif 198 199 /** 200 * __qdf_hrtimer_get_remaining() - check remaining time in the timer 201 * @timer: pointer to the hrtimer object 202 * 203 * check whether the timer is on one of the queues 204 * 205 * Return: remaining time as ktime object 206 */ 207 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 208 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer) 209 { 210 struct hrtimer *hrtimer = &timer->u.hrtimer; 211 212 return hrtimer_get_remaining(hrtimer); 213 } 214 #else 215 static inline ktime_t __qdf_hrtimer_get_remaining(__qdf_hrtimer_data_t *timer) 216 { 217 struct hrtimer *hrtimer = &timer->u.hrtimer; 218 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 219 220 if (timer->ctx == QDF_CONTEXT_HARDWARE) 221 return hrtimer_get_remaining(hrtimer); 222 else 223 return hrtimer_get_remaining(&tasklet_hrtimer->timer); 224 } 225 #endif 226 227 /** 228 * __qdf_hrtimer_is_queued() - check whether the timer is on one of the queues 229 * @timer: pointer to the hrtimer object 230 * 231 * check whether the timer is on one of the queues 232 * 233 * Return: false when the timer was not in queue 234 * true when the timer was in queue 235 */ 236 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 237 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer) 238 { 239 struct hrtimer *hrtimer = &timer->u.hrtimer; 240 241 return hrtimer_is_queued(hrtimer); 242 } 243 #else 244 static inline bool __qdf_hrtimer_is_queued(__qdf_hrtimer_data_t *timer) 245 { 246 struct hrtimer *hrtimer = &timer->u.hrtimer; 247 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 248 249 if (timer->ctx == QDF_CONTEXT_HARDWARE) 250 return hrtimer_is_queued(hrtimer); 251 else 252 return hrtimer_is_queued(&tasklet_hrtimer->timer); 253 } 254 #endif 255 256 /** 257 * __qdf_hrtimer_callback_running() - check if callback is running 258 * @timer: pointer to the hrtimer object 259 * 260 * check whether the timer is running the callback function 261 * 262 * Return: false when callback is not running 263 * true when callback is running 264 */ 265 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 266 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer) 267 { 268 struct hrtimer *hrtimer = &timer->u.hrtimer; 269 270 return hrtimer_callback_running(hrtimer); 271 } 272 #else 273 static inline bool __qdf_hrtimer_callback_running(__qdf_hrtimer_data_t *timer) 274 { 275 struct hrtimer *hrtimer = &timer->u.hrtimer; 276 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 277 278 if (timer->ctx == QDF_CONTEXT_HARDWARE) 279 return hrtimer_callback_running(hrtimer); 280 else 281 return hrtimer_callback_running(&tasklet_hrtimer->timer); 282 } 283 #endif 284 285 /** 286 * __qdf_hrtimer_active() - check if timer is active 287 * @timer: pointer to the hrtimer object 288 * 289 * Check if timer is active. A timer is active, when it is enqueued into 290 * the rbtree or the callback function is running. 291 * 292 * Return: false if timer is not active 293 * true if timer is active 294 */ 295 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 296 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer) 297 { 298 struct hrtimer *hrtimer = &timer->u.hrtimer; 299 300 return hrtimer_active(hrtimer); 301 } 302 #else 303 static inline bool __qdf_hrtimer_active(__qdf_hrtimer_data_t *timer) 304 { 305 struct hrtimer *hrtimer = &timer->u.hrtimer; 306 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 307 308 if (timer->ctx == QDF_CONTEXT_HARDWARE) 309 return hrtimer_active(hrtimer); 310 else 311 return hrtimer_active(&tasklet_hrtimer->timer); 312 } 313 #endif 314 315 /** 316 * __qdf_hrtimer_cb_get_time() - get remaining time in callback 317 * @timer: pointer to the hrtimer object 318 * 319 * Get remaining time in the hrtimer callback 320 * 321 * Return: time remaining as ktime object 322 */ 323 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 324 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer) 325 { 326 struct hrtimer *hrtimer = &timer->u.hrtimer; 327 328 return hrtimer_cb_get_time(hrtimer); 329 } 330 #else 331 static inline ktime_t __qdf_hrtimer_cb_get_time(__qdf_hrtimer_data_t *timer) 332 { 333 struct hrtimer *hrtimer = &timer->u.hrtimer; 334 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 335 336 if (timer->ctx == QDF_CONTEXT_HARDWARE) 337 return hrtimer_cb_get_time(hrtimer); 338 else 339 return hrtimer_cb_get_time(&tasklet_hrtimer->timer); 340 } 341 #endif 342 343 /** 344 * __qdf_hrtimer_forward() - forward the hrtimer 345 * @timer: pointer to the hrtimer object 346 * @now: current ktime 347 * @interval: interval to forward as ktime object 348 * 349 * Forward the timer expiry so it will expire in the future 350 * 351 * Return:the number of overruns 352 */ 353 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)) 354 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer, 355 ktime_t now, 356 ktime_t interval) 357 { 358 struct hrtimer *hrtimer = &timer->u.hrtimer; 359 360 return hrtimer_forward(hrtimer, now, interval); 361 } 362 #else 363 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer, 364 ktime_t now, 365 ktime_t interval) 366 { 367 struct hrtimer *hrtimer = &timer->u.hrtimer; 368 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 369 370 if (timer->ctx == QDF_CONTEXT_HARDWARE) 371 return hrtimer_forward(hrtimer, now, interval); 372 else 373 return hrtimer_forward(&tasklet_hrtimer->timer, now, interval); 374 } 375 #endif 376 377 #endif /* _I_QDF_HRTIMER_H */ 378