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