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