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 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 * @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)) 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 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 204 void __qdf_hrtimer_kill(__qdf_hrtimer_data_t *timer) 205 { 206 hrtimer_cancel(&timer->u.hrtimer); 207 } 208 #else 209 static inline 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)) 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 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)) 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 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)) 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 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)) 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 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)) 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 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)) 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 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 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