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