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 #else 382 static inline uint64_t __qdf_hrtimer_forward(__qdf_hrtimer_data_t *timer, 383 ktime_t now, 384 ktime_t interval) 385 { 386 struct hrtimer *hrtimer = &timer->u.hrtimer; 387 struct tasklet_hrtimer *tasklet_hrtimer = &timer->u.tasklet_hrtimer; 388 389 if (timer->ctx == QDF_CONTEXT_HARDWARE) 390 return hrtimer_forward(hrtimer, now, interval); 391 else 392 return hrtimer_forward(&tasklet_hrtimer->timer, now, interval); 393 } 394 #endif 395 396 #endif /* _I_QDF_HRTIMER_H */ 397