1 /* 2 * Copyright (c) 2014-2018 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_defer.h 21 * This file provides OS dependent deferred API's. 22 */ 23 24 #ifndef _I_QDF_DEFER_H 25 #define _I_QDF_DEFER_H 26 27 #include <linux/workqueue.h> 28 #include <linux/interrupt.h> 29 #include <qdf_types.h> 30 #include <qdf_status.h> 31 #include <qdf_trace.h> 32 33 typedef struct tasklet_struct __qdf_bh_t; 34 typedef struct workqueue_struct __qdf_workqueue_t; 35 36 /** 37 * __qdf_work_t - wrapper around the real task func 38 * @work: Instance of work 39 * @fn: function pointer to the handler 40 * @arg: pointer to argument 41 */ 42 typedef struct { 43 struct work_struct work; 44 qdf_defer_fn_t fn; 45 void *arg; 46 } __qdf_work_t; 47 48 /** 49 * __qdf_delayed_work_t - wrapper around the real work func 50 * @dwork: Instance of delayed work 51 * @fn: function pointer to the handler 52 * @arg: pointer to argument 53 */ 54 typedef struct { 55 struct delayed_work dwork; 56 qdf_defer_fn_t fn; 57 void *arg; 58 } __qdf_delayed_work_t; 59 60 extern void __qdf_defer_func(struct work_struct *work); 61 extern void __qdf_defer_delayed_func(struct work_struct *work); 62 63 typedef void (*__qdf_bh_fn_t)(unsigned long arg); 64 65 /** 66 * __qdf_init_work - Initialize a work/task queue, This runs in non-interrupt 67 * context, so can be preempted by H/W & S/W intr 68 * @work: pointer to work 69 * @func: deferred function to run at bottom half non-interrupt context. 70 * @arg: argument for the deferred function 71 * Return: none 72 */ 73 static inline QDF_STATUS 74 __qdf_init_work(__qdf_work_t *work, qdf_defer_fn_t func, void *arg) 75 { 76 work->fn = func; 77 work->arg = arg; 78 INIT_WORK(&work->work, __qdf_defer_func); 79 return QDF_STATUS_SUCCESS; 80 } 81 82 /** 83 * __qdf_init_delayed_work - create a work/task, This runs in non-interrupt 84 * context, so can be preempted by H/W & S/W intr 85 * @work: pointer to work 86 * @func: deferred function to run at bottom half non-interrupt context. 87 * @arg: argument for the deferred function 88 * Return: none 89 */ 90 static inline uint32_t __qdf_init_delayed_work(__qdf_delayed_work_t *work, 91 qdf_defer_fn_t func, 92 void *arg) 93 { 94 /*Initialize func and argument in work struct */ 95 work->fn = func; 96 work->arg = arg; 97 INIT_DELAYED_WORK(&work->dwork, __qdf_defer_delayed_func); 98 return QDF_STATUS_SUCCESS; 99 } 100 101 /** 102 * __qdf_queue_work - Queue the work/task 103 * @wqueue: pointer to workqueue 104 * @work: pointer to work 105 * Return: none 106 */ 107 static inline void 108 __qdf_queue_work(__qdf_workqueue_t *wqueue, __qdf_work_t *work) 109 { 110 queue_work(wqueue, &work->work); 111 } 112 113 /** 114 * __qdf_queue_delayed_work - Queue the delayed work/task 115 * @wqueue: pointer to workqueue 116 * @work: pointer to work 117 * @delay: delay interval 118 * Return: none 119 */ 120 static inline void __qdf_queue_delayed_work(__qdf_workqueue_t *wqueue, 121 __qdf_delayed_work_t *work, 122 uint32_t delay) 123 { 124 queue_delayed_work(wqueue, &work->dwork, msecs_to_jiffies(delay)); 125 } 126 127 /** 128 * __qdf_sched_work - Schedule a deferred task on non-interrupt context 129 * @work: pointer to work 130 * Retrun: none 131 */ 132 static inline QDF_STATUS __qdf_sched_work(__qdf_work_t *work) 133 { 134 schedule_work(&work->work); 135 return QDF_STATUS_SUCCESS; 136 } 137 138 /** 139 * __qdf_sched_delayed_work() - Schedule a delayed work 140 * @work: pointer to delayed work 141 * @delay: delay interval 142 * Return: none 143 */ 144 static inline QDF_STATUS 145 __qdf_sched_delayed_work(__qdf_delayed_work_t *work, uint32_t delay) 146 { 147 schedule_delayed_work(&work->dwork, msecs_to_jiffies(delay)); 148 return QDF_STATUS_SUCCESS; 149 } 150 151 /** 152 * __qdf_cancel_work() - Cancel a work 153 * @work: pointer to work 154 * Return: true if work was pending, false otherwise 155 */ 156 static inline bool __qdf_cancel_work(__qdf_work_t *work) 157 { 158 return cancel_work_sync(&work->work); 159 } 160 161 /** 162 * __qdf_cancel_delayed_work() - Cancel a delayed work 163 * @work: pointer to delayed work 164 * Return: true if work was pending, false otherwise 165 */ 166 static inline bool __qdf_cancel_delayed_work(__qdf_delayed_work_t *work) 167 { 168 return cancel_delayed_work_sync(&work->dwork); 169 } 170 171 /** 172 * __qdf_flush_work - Flush a deferred task on non-interrupt context 173 * @work: pointer to work 174 * Return: none 175 */ 176 static inline uint32_t __qdf_flush_work(__qdf_work_t *work) 177 { 178 flush_work(&work->work); 179 return QDF_STATUS_SUCCESS; 180 } 181 182 /** 183 * __qdf_flush_delayed_work() - Flush a delayed work 184 * @work: pointer to delayed work 185 * Return: none 186 */ 187 static inline uint32_t __qdf_flush_delayed_work(__qdf_delayed_work_t *work) 188 { 189 flush_delayed_work(&work->dwork); 190 return QDF_STATUS_SUCCESS; 191 } 192 193 /** 194 * __qdf_create_workqueue - create a workqueue, This runs in non-interrupt 195 * context, so can be preempted by H/W & S/W intr 196 * @name: string 197 * Return: pointer of type qdf_workqueue_t 198 */ 199 static inline __qdf_workqueue_t *__qdf_create_workqueue(char *name) 200 { 201 return create_workqueue(name); 202 } 203 204 /** 205 * __qdf_create_singlethread_workqueue() - create a single threaded workqueue 206 * @name: string 207 * 208 * This API creates a dedicated work queue with a single worker thread to avoid 209 * wasting unnecessary resources when works which needs to be submitted in this 210 * queue are not very critical and frequent. 211 * 212 * Return: pointer of type qdf_workqueue_t 213 */ 214 static inline __qdf_workqueue_t *__qdf_create_singlethread_workqueue(char *name) 215 { 216 return create_singlethread_workqueue(name); 217 } 218 219 /** 220 * __qdf_alloc_unbound_workqueue - alloc an unbound workqueue 221 * @name: string 222 * 223 * Return: pointer of type qdf_workqueue_t 224 */ 225 static inline __qdf_workqueue_t *__qdf_alloc_unbound_workqueue(char *name) 226 { 227 return alloc_workqueue(name, WQ_UNBOUND, 0); 228 } 229 230 /** 231 * __qdf_flush_workqueue - flush the workqueue 232 * @wqueue: pointer to workqueue 233 * Return: none 234 */ 235 static inline void __qdf_flush_workqueue(__qdf_workqueue_t *wqueue) 236 { 237 flush_workqueue(wqueue); 238 } 239 240 /** 241 * __qdf_destroy_workqueue - Destroy the workqueue 242 * @wqueue: pointer to workqueue 243 * Return: none 244 */ 245 static inline void __qdf_destroy_workqueue(__qdf_workqueue_t *wqueue) 246 { 247 destroy_workqueue(wqueue); 248 } 249 250 /** 251 * __qdf_init_bh - creates the Bottom half deferred handler 252 * @bh: pointer to bottom 253 * @func: deferred function to run at bottom half interrupt context. 254 * @arg: argument for the deferred function 255 * Return: none 256 */ 257 static inline QDF_STATUS 258 __qdf_init_bh(struct tasklet_struct *bh, qdf_defer_fn_t func, void *arg) 259 { 260 tasklet_init(bh, (__qdf_bh_fn_t) func, (unsigned long)arg); 261 return QDF_STATUS_SUCCESS; 262 } 263 264 /** 265 * __qdf_sched_bh - schedule a bottom half (DPC) 266 * @bh: pointer to bottom 267 * Return: none 268 */ 269 static inline QDF_STATUS __qdf_sched_bh(struct tasklet_struct *bh) 270 { 271 tasklet_schedule(bh); 272 return QDF_STATUS_SUCCESS; 273 } 274 275 /** 276 * __qdf_disable_work - disable the deferred task (synchronous) 277 * @work: pointer to work 278 * Return: unsigned int 279 */ 280 static inline QDF_STATUS __qdf_disable_work(__qdf_work_t *work) 281 { 282 if (cancel_work_sync(&work->work)) 283 return QDF_STATUS_E_ALREADY; 284 285 return QDF_STATUS_SUCCESS; 286 } 287 288 /** 289 * __qdf_disable_bh - destroy the bh (synchronous) 290 * @bh: pointer to bottom 291 * Return: none 292 */ 293 static inline QDF_STATUS __qdf_disable_bh(struct tasklet_struct *bh) 294 { 295 tasklet_kill(bh); 296 return QDF_STATUS_SUCCESS; 297 } 298 299 #endif /*_I_QDF_DEFER_H*/ 300