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