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