1 /*
2 * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022,2024 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: qdf_defer.h
22 * This file abstracts deferred execution API's.
23 */
24
25 #ifndef __QDF_DEFER_H
26 #define __QDF_DEFER_H
27
28 #include <qdf_types.h>
29 #include <i_qdf_defer.h>
30
31 /*
32 * TODO This implements work queues (worker threads, kernel threads etc.).
33 * Note that there is no cancel on a scheduled work. You cannot free a work
34 * item if its queued. You cannot know if a work item is queued or not unless
35 * its running, hence you know its not queued.
36 *
37 * so if, say, a module is asked to unload itself, how exactly will it make
38 * sure that the work's not queued, for OS'es that dont provide such a
39 * mechanism??
40 */
41
42 /*
43 * Representation of a work queue.
44 */
45 typedef __qdf_work_t qdf_work_t;
46 typedef __qdf_workqueue_t qdf_workqueue_t;
47
48 /*
49 * Representation of a bottom half.
50 */
51 typedef __qdf_bh_t qdf_bh_t;
52
53 #ifdef ENHANCED_OS_ABSTRACTION
54 /**
55 * qdf_create_bh - creates the bottom half deferred handler
56 * @bh: pointer to bottom
57 * @func: deferred function to run at bottom half interrupt context.
58 * @arg: argument for the deferred function
59 * Return: none
60 */
61 void
62 qdf_create_bh(qdf_bh_t *bh, qdf_defer_fn_t func, void *arg);
63
64 /**
65 * qdf_sched_bh - schedule a bottom half (DPC)
66 * @bh: pointer to bottom
67 * Return: none
68 */
69 void qdf_sched_bh(qdf_bh_t *bh);
70
71 /**
72 * qdf_destroy_bh - destroy the bh (synchronous)
73 * @bh: pointer to bottom
74 * Return: none
75 */
76 void qdf_destroy_bh(qdf_bh_t *bh);
77
78 /**
79 * qdf_create_workqueue - create a workqueue, This runs in non-interrupt
80 * context, so can be preempted by H/W & S/W intr
81 * @name: string
82 *
83 * Return: pointer of type qdf_workqueue_t
84 */
85 qdf_workqueue_t *qdf_create_workqueue(char *name);
86
87 /**
88 * qdf_create_singlethread_workqueue() - create a single threaded workqueue
89 * @name: string
90 *
91 * This API creates a dedicated work queue with a single worker thread to avoid
92 * wasting unnecessary resources when works which needs to be submitted in this
93 * queue are not very critical and frequent.
94 *
95 * Return: pointer of type qdf_workqueue_t
96 */
97 qdf_workqueue_t *qdf_create_singlethread_workqueue(char *name);
98
99 /**
100 * qdf_alloc_unbound_workqueue - allocate an unbound workqueue
101 * @name: string
102 *
103 * Return: pointer of type qdf_workqueue_t
104 */
105 qdf_workqueue_t *qdf_alloc_unbound_workqueue(char *name);
106
107 /**
108 * qdf_destroy_workqueue - Destroy the workqueue
109 * @hdl: OS handle
110 * @wqueue: pointer to workqueue
111 *
112 * Return: none
113 */
114 void qdf_destroy_workqueue(qdf_handle_t hdl, qdf_workqueue_t *wqueue);
115
116 /**
117 * qdf_cancel_work() - Cancel a work
118 * @work: pointer to work
119 *
120 * Cancel work and wait for its execution to finish.
121 * This function can be used even if the work re-queues
122 * itself or migrates to another workqueue. On return
123 * from this function, work is guaranteed to be not
124 * pending or executing on any CPU. The caller must
125 * ensure that the workqueue on which work was last
126 * queued can't be destroyed before this function returns.
127 *
128 * Return: true if work was pending, false otherwise
129 */
130 bool qdf_cancel_work(qdf_work_t *work);
131
132 /**
133 * qdf_disable_work - disable the deferred task (synchronous)
134 * @work: pointer to work
135 *
136 * Return: unsigned int
137 */
138 uint32_t qdf_disable_work(qdf_work_t *work);
139
140 /**
141 * qdf_flush_work - Flush a deferred task on non-interrupt context
142 * @work: pointer to work
143 *
144 * Wait until work has finished execution. work is guaranteed to be
145 * idle on return if it hasn't been requeued since flush started.
146 *
147 * Return: none
148 */
149 void qdf_flush_work(qdf_work_t *work);
150
151 /**
152 * qdf_create_work - create a work/task queue, This runs in non-interrupt
153 * context, so can be preempted by H/W & S/W intr
154 * @hdl: OS handle
155 * @work: pointer to work
156 * @func: deferred function to run at bottom half non-interrupt context.
157 * @arg: argument for the deferred function
158 *
159 * Return: QDF status
160 */
161 QDF_STATUS qdf_create_work(qdf_handle_t hdl, qdf_work_t *work,
162 qdf_defer_fn_t func, void *arg);
163
164 /**
165 * qdf_sched_work - Schedule a deferred task on non-interrupt context
166 * @hdl: OS handle
167 * @work: pointer to work
168 *
169 * Return: false if work was already on a queue, true otherwise
170 */
171 bool qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work);
172
173 /**
174 * qdf_queue_work - Queue the work/task
175 * @hdl: OS handle
176 * @wqueue: pointer to workqueue
177 * @work: pointer to work
178 *
179 * Return: false if work was already on a queue, true otherwise
180 */
181 bool
182 qdf_queue_work(qdf_handle_t hdl, qdf_workqueue_t *wqueue, qdf_work_t *work);
183
184 /**
185 * qdf_flush_workqueue - flush the workqueue
186 * @hdl: OS handle
187 * @wqueue: pointer to workqueue
188 *
189 * Return: none
190 */
191 void qdf_flush_workqueue(qdf_handle_t hdl, qdf_workqueue_t *wqueue);
192
193 /**
194 * qdf_destroy_work - destroy the deferred task (synchronous)
195 * @hdl: OS handle
196 * @work: pointer to work
197 *
198 * Return: none
199 */
200 void qdf_destroy_work(qdf_handle_t hdl, qdf_work_t *work);
201
202 /**
203 * qdf_local_bh_disable - Disables softirq and tasklet processing
204 * on the local processor
205 *
206 * Return: none
207 */
208 void qdf_local_bh_disable(void);
209
210 /**
211 * qdf_local_bh_enable - Disables softirq and tasklet processing
212 * on the local processor
213 *
214 * Return: none
215 */
216 void qdf_local_bh_enable(void);
217
218 #else
219 /**
220 * qdf_create_bh - creates the bottom half deferred handler
221 * @bh: pointer to bottom
222 * @func: deferred function to run at bottom half interrupt context.
223 * @arg: argument for the deferred function
224 * Return: none
225 */
226 static inline void
qdf_create_bh(qdf_bh_t * bh,qdf_defer_fn_t func,void * arg)227 qdf_create_bh(qdf_bh_t *bh, qdf_defer_fn_t func, void *arg)
228 {
229 __qdf_init_bh(bh, func, arg);
230 }
231
232 /**
233 * qdf_sched_bh - schedule a bottom half (DPC)
234 * @bh: pointer to bottom
235 * Return: none
236 */
qdf_sched_bh(qdf_bh_t * bh)237 static inline void qdf_sched_bh(qdf_bh_t *bh)
238 {
239 __qdf_sched_bh(bh);
240 }
241
242 /**
243 * qdf_destroy_bh - destroy the bh (synchronous)
244 * @bh: pointer to bottom
245 * Return: none
246 */
qdf_destroy_bh(qdf_bh_t * bh)247 static inline void qdf_destroy_bh(qdf_bh_t *bh)
248 {
249 __qdf_disable_bh(bh);
250 }
251
252 /**
253 * qdf_local_bh_disable - Disables softirq and tasklet processing
254 * on the local processor
255 *
256 * Return: none
257 */
qdf_local_bh_disable(void)258 static inline void qdf_local_bh_disable(void)
259 {
260 __qdf_local_bh_disable();
261 }
262
263 /**
264 * qdf_local_bh_enable - Enables softirq and tasklet processing
265 * on the local processor
266 *
267 * Return: none
268 */
qdf_local_bh_enable(void)269 static inline void qdf_local_bh_enable(void)
270 {
271 __qdf_local_bh_enable();
272 }
273
274 /*********************Non-Interrupt Context deferred Execution***************/
275
276 /**
277 * qdf_create_work - create a work/task queue, This runs in non-interrupt
278 * context, so can be preempted by H/W & S/W intr
279 * @hdl: OS handle
280 * @work: pointer to work
281 * @func: deferred function to run at bottom half non-interrupt context.
282 * @arg: argument for the deferred function
283 *
284 * Return: QDF status
285 */
qdf_create_work(qdf_handle_t hdl,qdf_work_t * work,qdf_defer_fn_t func,void * arg)286 static inline QDF_STATUS qdf_create_work(qdf_handle_t hdl, qdf_work_t *work,
287 qdf_defer_fn_t func, void *arg)
288 {
289 return __qdf_init_work(work, func, arg);
290 }
291
292 /**
293 * qdf_create_workqueue - create a workqueue, This runs in non-interrupt
294 * context, so can be preempted by H/W & S/W intr
295 * @name: string
296 * Return: pointer of type qdf_workqueue_t
297 */
qdf_create_workqueue(char * name)298 static inline qdf_workqueue_t *qdf_create_workqueue(char *name)
299 {
300 return __qdf_create_workqueue(name);
301 }
302
303 /**
304 * qdf_create_singlethread_workqueue() - create a single threaded workqueue
305 * @name: string
306 *
307 * This API creates a dedicated work queue with a single worker thread to avoid
308 * wasting unnecessary resources when works which needs to be submitted in this
309 * queue are not very critical and frequent.
310 *
311 * Return: pointer of type qdf_workqueue_t
312 */
qdf_create_singlethread_workqueue(char * name)313 static inline qdf_workqueue_t *qdf_create_singlethread_workqueue(char *name)
314 {
315 return __qdf_create_singlethread_workqueue(name);
316 }
317
318 /**
319 * qdf_alloc_high_prior_ordered_workqueue - alloc high-prior ordered workqueue
320 * @name: string
321 *
322 * Return: pointer of type qdf_workqueue_t
323 */
324 static inline
qdf_alloc_high_prior_ordered_workqueue(char * name)325 qdf_workqueue_t *qdf_alloc_high_prior_ordered_workqueue(char *name)
326 {
327 return __qdf_alloc_high_prior_ordered_workqueue(name);
328 }
329
330 /**
331 * qdf_alloc_unbound_workqueue - allocate an unbound workqueue
332 * @name: string
333 *
334 * Return: pointer of type qdf_workqueue_t
335 */
qdf_alloc_unbound_workqueue(char * name)336 static inline qdf_workqueue_t *qdf_alloc_unbound_workqueue(char *name)
337 {
338 return __qdf_alloc_unbound_workqueue(name);
339 }
340
341 /**
342 * qdf_queue_work - Queue the work/task
343 * @hdl: OS handle
344 * @wqueue: pointer to workqueue
345 * @work: pointer to work
346 * Return: false if work was already on a queue, true otherwise
347 */
348 static inline bool
qdf_queue_work(qdf_handle_t hdl,qdf_workqueue_t * wqueue,qdf_work_t * work)349 qdf_queue_work(qdf_handle_t hdl, qdf_workqueue_t *wqueue, qdf_work_t *work)
350 {
351 return __qdf_queue_work(wqueue, work);
352 }
353
354 /**
355 * qdf_flush_workqueue - flush the workqueue
356 * @hdl: OS handle
357 * @wqueue: pointer to workqueue
358 * Return: none
359 */
qdf_flush_workqueue(qdf_handle_t hdl,qdf_workqueue_t * wqueue)360 static inline void qdf_flush_workqueue(qdf_handle_t hdl,
361 qdf_workqueue_t *wqueue)
362 {
363 return __qdf_flush_workqueue(wqueue);
364 }
365
366 /**
367 * qdf_destroy_workqueue - Destroy the workqueue
368 * @hdl: OS handle
369 * @wqueue: pointer to workqueue
370 * Return: none
371 */
qdf_destroy_workqueue(qdf_handle_t hdl,qdf_workqueue_t * wqueue)372 static inline void qdf_destroy_workqueue(qdf_handle_t hdl,
373 qdf_workqueue_t *wqueue)
374 {
375 return __qdf_destroy_workqueue(wqueue);
376 }
377
378 /**
379 * qdf_sched_work - Schedule a deferred task on non-interrupt context
380 * @hdl: OS handle
381 * @work: pointer to work
382 *
383 * Return: false if work was already on a queue, true otherwise
384 */
qdf_sched_work(qdf_handle_t hdl,qdf_work_t * work)385 static inline bool qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work)
386 {
387 return __qdf_sched_work(work);
388 }
389
390 /**
391 * qdf_cancel_work() - Cancel a work
392 * @work: pointer to work
393 *
394 * Cancel work and wait for its execution to finish.
395 * This function can be used even if the work re-queues
396 * itself or migrates to another workqueue. On return
397 * from this function, work is guaranteed to be not
398 * pending or executing on any CPU. The caller must
399 * ensure that the workqueue on which work was last
400 * queued can't be destroyed before this function returns.
401 *
402 * Return: true if work was pending, false otherwise
403 */
qdf_cancel_work(qdf_work_t * work)404 static inline bool qdf_cancel_work(qdf_work_t *work)
405 {
406 return __qdf_cancel_work(work);
407 }
408
409 /**
410 * qdf_flush_work - Flush a deferred task on non-interrupt context
411 * @work: pointer to work
412 *
413 * Wait until work has finished execution. work is guaranteed to be
414 * idle on return if it hasn't been requeued since flush started.
415 *
416 * Return: none
417 */
qdf_flush_work(qdf_work_t * work)418 static inline void qdf_flush_work(qdf_work_t *work)
419 {
420 __qdf_flush_work(work);
421 }
422
423 /**
424 * qdf_disable_work - disable the deferred task (synchronous)
425 * @work: pointer to work
426 * Return: unsigned int
427 */
qdf_disable_work(qdf_work_t * work)428 static inline uint32_t qdf_disable_work(qdf_work_t *work)
429 {
430 return __qdf_disable_work(work);
431 }
432
433 /**
434 * qdf_destroy_work - destroy the deferred task (synchronous)
435 * @hdl: OS handle
436 * @work: pointer to work
437 * Return: none
438 */
qdf_destroy_work(qdf_handle_t hdl,qdf_work_t * work)439 static inline void qdf_destroy_work(qdf_handle_t hdl, qdf_work_t *work)
440 {
441 __qdf_disable_work(work);
442 }
443 #endif
444
445 #endif /*_QDF_DEFER_H*/
446