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