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