xref: /wlan-driver/qcacld-3.0/components/dsc/src/wlan_dsc_psoc.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2023 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 #include "qdf_list.h"
21 #include "qdf_status.h"
22 #include "qdf_talloc.h"
23 #include "qdf_types.h"
24 #include "__wlan_dsc.h"
25 #include "wlan_dsc.h"
26 
27 #define __dsc_driver_lock(psoc) __dsc_lock((psoc)->driver)
28 #define __dsc_driver_unlock(psoc) __dsc_unlock((psoc)->driver)
29 
30 static QDF_STATUS
__dsc_psoc_create(struct dsc_driver * driver,struct dsc_psoc ** out_psoc)31 __dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc)
32 {
33 	struct dsc_psoc *psoc;
34 
35 	if (!dsc_assert(driver))
36 		return QDF_STATUS_E_INVAL;
37 
38 	if (!dsc_assert(out_psoc))
39 		return QDF_STATUS_E_INVAL;
40 
41 	*out_psoc = NULL;
42 
43 	psoc = qdf_talloc_type(driver, psoc);
44 	if (!psoc)
45 		return QDF_STATUS_E_NOMEM;
46 
47 	/* init */
48 	psoc->driver = driver;
49 	qdf_list_create(&psoc->vdevs, 0);
50 	__dsc_trans_init(&psoc->trans);
51 	__dsc_ops_init(&psoc->ops);
52 
53 	/* attach */
54 	__dsc_driver_lock(psoc);
55 	qdf_list_insert_back(&driver->psocs, &psoc->node);
56 	__dsc_driver_unlock(psoc);
57 
58 	*out_psoc = psoc;
59 
60 	return QDF_STATUS_SUCCESS;
61 }
62 
63 QDF_STATUS
dsc_psoc_create(struct dsc_driver * driver,struct dsc_psoc ** out_psoc)64 dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc)
65 {
66 	QDF_STATUS status;
67 
68 	status =  __dsc_psoc_create(driver, out_psoc);
69 
70 	return status;
71 }
72 
__dsc_psoc_destroy(struct dsc_psoc ** out_psoc)73 static void __dsc_psoc_destroy(struct dsc_psoc **out_psoc)
74 {
75 	struct dsc_psoc *psoc;
76 
77 	if (!dsc_assert(out_psoc))
78 		return;
79 
80 	psoc = *out_psoc;
81 	if (!dsc_assert(psoc))
82 		return;
83 
84 	/* assert no children */
85 	dsc_assert(qdf_list_empty(&psoc->vdevs));
86 
87 	/* flush pending transitions */
88 	while (__dsc_trans_abort(&psoc->trans))
89 		;
90 
91 	/* detach */
92 	__dsc_driver_lock(psoc);
93 	qdf_list_remove_node(&psoc->driver->psocs, &psoc->node);
94 	__dsc_driver_unlock(psoc);
95 
96 	/* de-init */
97 	__dsc_ops_deinit(&psoc->ops);
98 	__dsc_trans_deinit(&psoc->trans);
99 	qdf_list_destroy(&psoc->vdevs);
100 	psoc->driver = NULL;
101 
102 	*out_psoc = NULL;
103 
104 	qdf_tfree(psoc);
105 }
106 
dsc_psoc_destroy(struct dsc_psoc ** out_psoc)107 void dsc_psoc_destroy(struct dsc_psoc **out_psoc)
108 {
109 	__dsc_psoc_destroy(out_psoc);
110 }
111 
__dsc_psoc_trans_active_down_tree(struct dsc_psoc * psoc)112 static bool __dsc_psoc_trans_active_down_tree(struct dsc_psoc *psoc)
113 {
114 	struct dsc_vdev *vdev;
115 
116 	dsc_for_each_psoc_vdev(psoc, vdev) {
117 		if (__dsc_trans_active(&vdev->trans))
118 			return true;
119 	}
120 
121 	return false;
122 }
123 
124 #define __dsc_psoc_can_op(psoc) __dsc_psoc_can_trans(psoc)
125 
126 /*
127  * __dsc_psoc_can_trans() - Returns if the psoc transition can occur or not
128  * @psoc: The DSC psoc
129  *
130  * This function checks if the psoc transition can occur or not by checking if
131  * any other down the tree/up the tree transition/operation is taking place.
132  *
133  * If there are any driver transition taking place, then the psoc trans/ops
134  * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL
135  * in this case.
136  *
137  * If there any psoc or vdev trans/ops is taking place, then the psoc trans/ops
138  * should be rejected and queued in the DSC queue so that it may be resumed
139  * after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this
140  * case.
141  *
142  * Return: QDF_STATUS_SUCCESS if transition is allowed, error code if not.
143  */
__dsc_psoc_can_trans(struct dsc_psoc * psoc)144 static QDF_STATUS __dsc_psoc_can_trans(struct dsc_psoc *psoc)
145 {
146 	if (__dsc_trans_active_or_queued(&psoc->driver->trans))
147 		return QDF_STATUS_E_INVAL;
148 
149 	if (__dsc_trans_active_or_queued(&psoc->trans) ||
150 	    __dsc_psoc_trans_active_down_tree(psoc))
151 		return QDF_STATUS_E_AGAIN;
152 
153 	return QDF_STATUS_SUCCESS;
154 }
155 
__dsc_psoc_can_trigger(struct dsc_psoc * psoc)156 static bool __dsc_psoc_can_trigger(struct dsc_psoc *psoc)
157 {
158 	return !__dsc_trans_active_or_queued(&psoc->driver->trans) &&
159 		!__dsc_trans_active(&psoc->trans) &&
160 		!__dsc_psoc_trans_active_down_tree(psoc);
161 }
162 
163 static QDF_STATUS
__dsc_psoc_trans_start_nolock(struct dsc_psoc * psoc,const char * desc)164 __dsc_psoc_trans_start_nolock(struct dsc_psoc *psoc, const char *desc)
165 {
166 	QDF_STATUS status;
167 
168 	status = __dsc_psoc_can_trans(psoc);
169 	if (QDF_IS_STATUS_ERROR(status))
170 		return status;
171 
172 	return __dsc_trans_start(&psoc->trans, desc);
173 }
174 
175 static QDF_STATUS
__dsc_psoc_trans_start(struct dsc_psoc * psoc,const char * desc)176 __dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc)
177 {
178 	QDF_STATUS status;
179 
180 	if (!dsc_assert(psoc))
181 		return QDF_STATUS_E_INVAL;
182 
183 	if (!dsc_assert(desc))
184 		return QDF_STATUS_E_INVAL;
185 
186 	__dsc_driver_lock(psoc);
187 	status = __dsc_psoc_trans_start_nolock(psoc, desc);
188 	__dsc_driver_unlock(psoc);
189 
190 	return status;
191 }
192 
dsc_psoc_trans_start(struct dsc_psoc * psoc,const char * desc)193 QDF_STATUS dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc)
194 {
195 	QDF_STATUS status;
196 
197 	dsc_enter_str(desc);
198 	status = __dsc_psoc_trans_start(psoc, desc);
199 	if (QDF_IS_STATUS_ERROR(status))
200 		dsc_exit_status(status);
201 
202 	return status;
203 }
204 
205 static QDF_STATUS
__dsc_psoc_trans_start_wait(struct dsc_psoc * psoc,const char * desc)206 __dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc)
207 {
208 	QDF_STATUS status;
209 	struct dsc_tran tran = { 0 };
210 
211 	if (!dsc_assert(psoc))
212 		return QDF_STATUS_E_INVAL;
213 
214 	if (!dsc_assert(desc))
215 		return QDF_STATUS_E_INVAL;
216 
217 	__dsc_driver_lock(psoc);
218 
219 	/* try to start without waiting */
220 	status = __dsc_psoc_trans_start_nolock(psoc, desc);
221 	if (QDF_IS_STATUS_SUCCESS(status) || status == QDF_STATUS_E_INVAL)
222 		goto unlock;
223 
224 	status = __dsc_trans_queue(&psoc->trans, &tran, desc);
225 	if (QDF_IS_STATUS_ERROR(status))
226 		goto unlock;
227 
228 	__dsc_driver_unlock(psoc);
229 
230 	return __dsc_tran_wait(&tran);
231 
232 unlock:
233 	__dsc_driver_unlock(psoc);
234 
235 	return status;
236 }
237 
dsc_psoc_trans_start_wait(struct dsc_psoc * psoc,const char * desc)238 QDF_STATUS dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc)
239 {
240 	QDF_STATUS status;
241 
242 	dsc_enter_str(desc);
243 	status = __dsc_psoc_trans_start_wait(psoc, desc);
244 	if (QDF_IS_STATUS_ERROR(status))
245 		dsc_exit_status(status);
246 
247 	return status;
248 }
249 
__dsc_psoc_trigger_trans(struct dsc_psoc * psoc)250 static void __dsc_psoc_trigger_trans(struct dsc_psoc *psoc)
251 {
252 	struct dsc_vdev *vdev;
253 
254 	if (__dsc_driver_trans_trigger_checked(psoc->driver))
255 		return;
256 
257 	if (__dsc_trans_trigger(&psoc->trans))
258 		return;
259 
260 	dsc_for_each_psoc_vdev(psoc, vdev)
261 		__dsc_trans_trigger(&vdev->trans);
262 }
263 
__dsc_psoc_trans_stop(struct dsc_psoc * psoc)264 static void __dsc_psoc_trans_stop(struct dsc_psoc *psoc)
265 {
266 	if (!dsc_assert(psoc))
267 		return;
268 
269 	__dsc_driver_lock(psoc);
270 
271 	__dsc_trans_stop(&psoc->trans);
272 	__dsc_psoc_trigger_trans(psoc);
273 
274 	__dsc_driver_unlock(psoc);
275 }
276 
dsc_psoc_trans_stop(struct dsc_psoc * psoc)277 void dsc_psoc_trans_stop(struct dsc_psoc *psoc)
278 {
279 	__dsc_psoc_trans_stop(psoc);
280 }
281 
__dsc_psoc_assert_trans_protected(struct dsc_psoc * psoc)282 static void __dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc)
283 {
284 	if (!dsc_assert(psoc))
285 		return;
286 
287 	__dsc_driver_lock(psoc);
288 	dsc_assert(__dsc_trans_active(&psoc->trans) ||
289 		   __dsc_trans_active(&psoc->driver->trans));
290 	__dsc_driver_unlock(psoc);
291 }
292 
dsc_psoc_assert_trans_protected(struct dsc_psoc * psoc)293 void dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc)
294 {
295 	__dsc_psoc_assert_trans_protected(psoc);
296 }
297 
__dsc_psoc_trans_trigger_checked(struct dsc_psoc * psoc)298 bool __dsc_psoc_trans_trigger_checked(struct dsc_psoc *psoc)
299 {
300 	if (qdf_list_empty(&psoc->trans.queue))
301 		return false;
302 
303 	/* handled, but don't trigger; we need to wait for more children */
304 	if (!__dsc_psoc_can_trigger(psoc))
305 		return true;
306 
307 	return __dsc_trans_trigger(&psoc->trans);
308 }
309 
__dsc_psoc_op_start(struct dsc_psoc * psoc,const char * func)310 static QDF_STATUS __dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func)
311 {
312 	QDF_STATUS status;
313 
314 	if (!dsc_assert(psoc))
315 		return QDF_STATUS_E_INVAL;
316 
317 	if (!dsc_assert(func))
318 		return QDF_STATUS_E_INVAL;
319 
320 	__dsc_driver_lock(psoc);
321 
322 	status = __dsc_psoc_can_op(psoc);
323 	if (QDF_IS_STATUS_ERROR(status))
324 		goto unlock;
325 
326 	status = __dsc_ops_insert(&psoc->ops, func);
327 
328 unlock:
329 	__dsc_driver_unlock(psoc);
330 
331 	return status;
332 }
333 
_dsc_psoc_op_start(struct dsc_psoc * psoc,const char * func)334 QDF_STATUS _dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func)
335 {
336 	QDF_STATUS status;
337 
338 	status = __dsc_psoc_op_start(psoc, func);
339 
340 	return status;
341 }
342 
__dsc_psoc_op_stop(struct dsc_psoc * psoc,const char * func)343 static void __dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func)
344 {
345 	if (!dsc_assert(psoc))
346 		return;
347 
348 	if (!dsc_assert(func))
349 		return;
350 
351 	__dsc_driver_lock(psoc);
352 	if (__dsc_ops_remove(&psoc->ops, func))
353 		qdf_event_set(&psoc->ops.event);
354 	__dsc_driver_unlock(psoc);
355 }
356 
_dsc_psoc_op_stop(struct dsc_psoc * psoc,const char * func)357 void _dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func)
358 {
359 	__dsc_psoc_op_stop(psoc, func);
360 }
361 
__dsc_psoc_wait_for_ops(struct dsc_psoc * psoc)362 static void __dsc_psoc_wait_for_ops(struct dsc_psoc *psoc)
363 {
364 	struct dsc_vdev *vdev;
365 	bool wait;
366 
367 	if (!dsc_assert(psoc))
368 		return;
369 
370 	__dsc_driver_lock(psoc);
371 
372 	wait = psoc->ops.count > 0;
373 	if (wait)
374 		qdf_event_reset(&psoc->ops.event);
375 
376 	__dsc_driver_unlock(psoc);
377 
378 	if (wait)
379 		qdf_wait_single_event(&psoc->ops.event, 0);
380 
381 	/* wait for down-tree ops to complete as well */
382 	dsc_for_each_psoc_vdev(psoc, vdev)
383 		dsc_vdev_wait_for_ops(vdev);
384 }
385 
dsc_psoc_wait_for_ops(struct dsc_psoc * psoc)386 void dsc_psoc_wait_for_ops(struct dsc_psoc *psoc)
387 {
388 	__dsc_psoc_wait_for_ops(psoc);
389 }
390 
391