1 /*
2  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "qdf_list.h"
20 #include "qdf_mem.h"
21 #include "qdf_status.h"
22 #include "qdf_types.h"
23 #include "__wlan_dsc.h"
24 #include "wlan_dsc.h"
25 
__dsc_lock(struct dsc_driver * driver)26 void __dsc_lock(struct dsc_driver *driver)
27 {
28 	dsc_assert(driver);
29 	qdf_spin_lock_bh(&driver->lock);
30 }
31 
__dsc_unlock(struct dsc_driver * driver)32 void __dsc_unlock(struct dsc_driver *driver)
33 {
34 	dsc_assert(driver);
35 	qdf_spin_unlock_bh(&driver->lock);
36 }
37 
__dsc_driver_create(struct dsc_driver ** out_driver)38 static QDF_STATUS __dsc_driver_create(struct dsc_driver **out_driver)
39 {
40 	struct dsc_driver *driver;
41 
42 	if (!dsc_assert(out_driver))
43 		return QDF_STATUS_E_INVAL;
44 
45 	*out_driver = NULL;
46 
47 	driver = qdf_mem_malloc(sizeof(*driver));
48 	if (!driver)
49 		return QDF_STATUS_E_NOMEM;
50 
51 	qdf_spinlock_create(&driver->lock);
52 	qdf_list_create(&driver->psocs, 0);
53 	__dsc_trans_init(&driver->trans);
54 	__dsc_ops_init(&driver->ops);
55 
56 	*out_driver = driver;
57 
58 	return QDF_STATUS_SUCCESS;
59 }
60 
dsc_driver_create(struct dsc_driver ** out_driver)61 QDF_STATUS dsc_driver_create(struct dsc_driver **out_driver)
62 {
63 	QDF_STATUS status;
64 
65 	status = __dsc_driver_create(out_driver);
66 
67 	return status;
68 }
69 
__dsc_driver_destroy(struct dsc_driver ** out_driver)70 static void __dsc_driver_destroy(struct dsc_driver **out_driver)
71 {
72 	struct dsc_driver *driver;
73 
74 	if (!dsc_assert(out_driver))
75 		return;
76 
77 	driver = *out_driver;
78 	if (!dsc_assert(driver))
79 		return;
80 
81 	*out_driver = NULL;
82 
83 	/* assert no children */
84 	dsc_assert(qdf_list_empty(&driver->psocs));
85 
86 	/* flush pending transitions */
87 	while (__dsc_trans_abort(&driver->trans))
88 		;
89 
90 	/* de-init */
91 	__dsc_ops_deinit(&driver->ops);
92 	__dsc_trans_deinit(&driver->trans);
93 	qdf_list_destroy(&driver->psocs);
94 	qdf_spinlock_destroy(&driver->lock);
95 
96 	qdf_mem_free(driver);
97 }
98 
dsc_driver_destroy(struct dsc_driver ** out_driver)99 void dsc_driver_destroy(struct dsc_driver **out_driver)
100 {
101 	__dsc_driver_destroy(out_driver);
102 }
103 
__dsc_driver_trans_active_down_tree(struct dsc_driver * driver)104 static bool __dsc_driver_trans_active_down_tree(struct dsc_driver *driver)
105 {
106 	struct dsc_psoc *psoc;
107 	struct dsc_vdev *vdev;
108 
109 	dsc_for_each_driver_psoc(driver, psoc) {
110 		if (__dsc_trans_active(&psoc->trans))
111 			return true;
112 
113 		dsc_for_each_psoc_vdev(psoc, vdev) {
114 			if (__dsc_trans_active(&vdev->trans))
115 				return true;
116 		}
117 	}
118 
119 	return false;
120 }
121 
122 #define __dsc_driver_can_op(driver) __dsc_driver_can_trans(driver)
123 
__dsc_driver_can_trans(struct dsc_driver * driver)124 static bool __dsc_driver_can_trans(struct dsc_driver *driver)
125 {
126 	return !__dsc_trans_active_or_queued(&driver->trans) &&
127 		!__dsc_driver_trans_active_down_tree(driver);
128 }
129 
__dsc_driver_can_trigger(struct dsc_driver * driver)130 static bool __dsc_driver_can_trigger(struct dsc_driver *driver)
131 {
132 	return !__dsc_trans_active(&driver->trans) &&
133 		!__dsc_driver_trans_active_down_tree(driver);
134 }
135 
136 static QDF_STATUS
__dsc_driver_trans_start_nolock(struct dsc_driver * driver,const char * desc)137 __dsc_driver_trans_start_nolock(struct dsc_driver *driver, const char *desc)
138 {
139 	if (!__dsc_driver_can_trans(driver))
140 		return QDF_STATUS_E_AGAIN;
141 
142 	return __dsc_trans_start(&driver->trans, desc);
143 }
144 
145 static QDF_STATUS
__dsc_driver_trans_start(struct dsc_driver * driver,const char * desc)146 __dsc_driver_trans_start(struct dsc_driver *driver, const char *desc)
147 {
148 	QDF_STATUS status;
149 
150 	if (!dsc_assert(driver))
151 		return QDF_STATUS_E_INVAL;
152 
153 	if (!dsc_assert(desc))
154 		return QDF_STATUS_E_INVAL;
155 
156 	__dsc_lock(driver);
157 	status = __dsc_driver_trans_start_nolock(driver, desc);
158 	__dsc_unlock(driver);
159 
160 	return status;
161 }
162 
dsc_driver_trans_start(struct dsc_driver * driver,const char * desc)163 QDF_STATUS dsc_driver_trans_start(struct dsc_driver *driver, const char *desc)
164 {
165 	QDF_STATUS status;
166 
167 	dsc_enter_str(desc);
168 	status = __dsc_driver_trans_start(driver, desc);
169 	if (QDF_IS_STATUS_ERROR(status))
170 		dsc_exit_status(status);
171 
172 	return status;
173 }
174 
175 static QDF_STATUS
__dsc_driver_trans_start_wait(struct dsc_driver * driver,const char * desc)176 __dsc_driver_trans_start_wait(struct dsc_driver *driver, const char *desc)
177 {
178 	QDF_STATUS status;
179 	struct dsc_tran tran = { 0 };
180 
181 	if (!dsc_assert(driver))
182 		return QDF_STATUS_E_INVAL;
183 
184 	if (!dsc_assert(desc))
185 		return QDF_STATUS_E_INVAL;
186 
187 	__dsc_lock(driver);
188 
189 	/* try to start without waiting */
190 	status = __dsc_driver_trans_start_nolock(driver, desc);
191 	if (QDF_IS_STATUS_SUCCESS(status))
192 		goto unlock;
193 
194 	status = __dsc_trans_queue(&driver->trans, &tran, desc);
195 	if (QDF_IS_STATUS_ERROR(status))
196 		goto unlock;
197 
198 	__dsc_unlock(driver);
199 
200 	return __dsc_tran_wait(&tran);
201 
202 unlock:
203 	__dsc_unlock(driver);
204 
205 	return status;
206 }
207 
208 QDF_STATUS
dsc_driver_trans_start_wait(struct dsc_driver * driver,const char * desc)209 dsc_driver_trans_start_wait(struct dsc_driver *driver, const char *desc)
210 {
211 	QDF_STATUS status;
212 
213 	dsc_enter_str(desc);
214 	status = __dsc_driver_trans_start_wait(driver, desc);
215 	if (QDF_IS_STATUS_ERROR(status))
216 		dsc_exit_status(status);
217 
218 	return status;
219 }
220 
__dsc_driver_trans_trigger_checked(struct dsc_driver * driver)221 bool __dsc_driver_trans_trigger_checked(struct dsc_driver *driver)
222 {
223 	if (!__dsc_trans_queued(&driver->trans))
224 		return false;
225 
226 	/* handled, but don't trigger; we need to wait for more children */
227 	if (!__dsc_driver_can_trigger(driver))
228 		return true;
229 
230 	return __dsc_trans_trigger(&driver->trans);
231 }
232 
__dsc_driver_trigger_trans(struct dsc_driver * driver)233 static void __dsc_driver_trigger_trans(struct dsc_driver *driver)
234 {
235 	struct dsc_psoc *psoc;
236 	struct dsc_vdev *vdev;
237 
238 	if (__dsc_trans_trigger(&driver->trans))
239 		return;
240 
241 	dsc_for_each_driver_psoc(driver, psoc) {
242 		if (__dsc_trans_trigger(&psoc->trans))
243 			continue;
244 
245 		dsc_for_each_psoc_vdev(psoc, vdev)
246 			__dsc_trans_trigger(&vdev->trans);
247 	}
248 }
249 
__dsc_driver_trans_stop(struct dsc_driver * driver)250 static void __dsc_driver_trans_stop(struct dsc_driver *driver)
251 {
252 	if (!dsc_assert(driver))
253 		return;
254 
255 	__dsc_lock(driver);
256 
257 	__dsc_trans_stop(&driver->trans);
258 	__dsc_driver_trigger_trans(driver);
259 
260 	__dsc_unlock(driver);
261 }
262 
dsc_driver_trans_stop(struct dsc_driver * driver)263 void dsc_driver_trans_stop(struct dsc_driver *driver)
264 {
265 	__dsc_driver_trans_stop(driver);
266 }
267 
__dsc_driver_assert_trans_protected(struct dsc_driver * driver)268 static void __dsc_driver_assert_trans_protected(struct dsc_driver *driver)
269 {
270 	if (!dsc_assert(driver))
271 		return;
272 
273 	__dsc_lock(driver);
274 	dsc_assert(__dsc_trans_active(&driver->trans));
275 	__dsc_unlock(driver);
276 }
277 
dsc_driver_assert_trans_protected(struct dsc_driver * driver)278 void dsc_driver_assert_trans_protected(struct dsc_driver *driver)
279 {
280 	__dsc_driver_assert_trans_protected(driver);
281 }
282 
283 static QDF_STATUS
__dsc_driver_op_start(struct dsc_driver * driver,const char * func)284 __dsc_driver_op_start(struct dsc_driver *driver, const char *func)
285 {
286 	QDF_STATUS status;
287 
288 	if (!dsc_assert(driver))
289 		return QDF_STATUS_E_INVAL;
290 
291 	if (!dsc_assert(func))
292 		return QDF_STATUS_E_INVAL;
293 
294 	__dsc_lock(driver);
295 
296 	if (!__dsc_driver_can_op(driver)) {
297 		status = QDF_STATUS_E_AGAIN;
298 		goto unlock;
299 	}
300 
301 	status = __dsc_ops_insert(&driver->ops, func);
302 
303 unlock:
304 	__dsc_unlock(driver);
305 
306 	return status;
307 }
308 
_dsc_driver_op_start(struct dsc_driver * driver,const char * func)309 QDF_STATUS _dsc_driver_op_start(struct dsc_driver *driver, const char *func)
310 {
311 	QDF_STATUS status;
312 
313 	dsc_enter_str(func);
314 	status = __dsc_driver_op_start(driver, func);
315 	if (QDF_IS_STATUS_ERROR(status))
316 		dsc_exit_status(status);
317 
318 	return status;
319 }
320 
__dsc_driver_op_stop(struct dsc_driver * driver,const char * func)321 static void __dsc_driver_op_stop(struct dsc_driver *driver, const char *func)
322 {
323 	if (!dsc_assert(driver))
324 		return;
325 
326 	if (!dsc_assert(func))
327 		return;
328 
329 	__dsc_lock(driver);
330 	if (__dsc_ops_remove(&driver->ops, func))
331 		qdf_event_set(&driver->ops.event);
332 	__dsc_unlock(driver);
333 }
334 
_dsc_driver_op_stop(struct dsc_driver * driver,const char * func)335 void _dsc_driver_op_stop(struct dsc_driver *driver, const char *func)
336 {
337 	__dsc_driver_op_stop(driver, func);
338 }
339 
__dsc_driver_wait_for_ops(struct dsc_driver * driver)340 static void __dsc_driver_wait_for_ops(struct dsc_driver *driver)
341 {
342 	struct dsc_psoc *psoc;
343 	bool wait;
344 
345 	if (!dsc_assert(driver))
346 		return;
347 
348 	__dsc_lock(driver);
349 
350 	/* flushing without preventing new ops is almost certainly a bug */
351 	dsc_assert(!__dsc_driver_can_op(driver));
352 
353 	wait = driver->ops.count > 0;
354 	if (wait)
355 		qdf_event_reset(&driver->ops.event);
356 
357 	__dsc_unlock(driver);
358 
359 	if (wait)
360 		qdf_wait_single_event(&driver->ops.event, 0);
361 
362 	/* wait for down-tree ops to complete as well */
363 	dsc_for_each_driver_psoc(driver, psoc)
364 		dsc_psoc_wait_for_ops(psoc);
365 }
366 
dsc_driver_wait_for_ops(struct dsc_driver * driver)367 void dsc_driver_wait_for_ops(struct dsc_driver *driver)
368 {
369 	__dsc_driver_wait_for_ops(driver);
370 }
371 
372