xref: /wlan-driver/qcacld-3.0/components/dsc/test/wlan_dsc_test.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include "__wlan_dsc.h"
21*5113495bSYour Name #include "qdf_event.h"
22*5113495bSYour Name #include "qdf_threads.h"
23*5113495bSYour Name #include "qdf_trace.h"
24*5113495bSYour Name #include "qdf_types.h"
25*5113495bSYour Name #include "wlan_dsc.h"
26*5113495bSYour Name #include "wlan_dsc_test.h"
27*5113495bSYour Name #include "cds_api.h"
28*5113495bSYour Name 
29*5113495bSYour Name #define dsc_driver_trans_start(driver) dsc_driver_trans_start(driver, __func__)
30*5113495bSYour Name #define dsc_psoc_trans_start(psoc) dsc_psoc_trans_start(psoc, __func__)
31*5113495bSYour Name #define dsc_vdev_trans_start(vdev) dsc_vdev_trans_start(vdev, __func__)
32*5113495bSYour Name 
33*5113495bSYour Name #define dsc_driver_trans_start_wait(driver) \
34*5113495bSYour Name 	dsc_driver_trans_start_wait(driver, "")
35*5113495bSYour Name #define dsc_psoc_trans_start_wait(psoc) \
36*5113495bSYour Name 	dsc_psoc_trans_start_wait(psoc, __func__)
37*5113495bSYour Name #define dsc_vdev_trans_start_wait(vdev) \
38*5113495bSYour Name 	dsc_vdev_trans_start_wait(vdev, __func__)
39*5113495bSYour Name 
nth_psoc(struct dsc_driver * driver,int n)40*5113495bSYour Name static struct dsc_psoc *nth_psoc(struct dsc_driver *driver, int n)
41*5113495bSYour Name {
42*5113495bSYour Name 	struct dsc_psoc *psoc;
43*5113495bSYour Name 
44*5113495bSYour Name 	QDF_BUG(n > 0);
45*5113495bSYour Name 	if (n <= 0)
46*5113495bSYour Name 		return NULL;
47*5113495bSYour Name 
48*5113495bSYour Name 	dsc_for_each_driver_psoc(driver, psoc) {
49*5113495bSYour Name 		n--;
50*5113495bSYour Name 		if (n)
51*5113495bSYour Name 			continue;
52*5113495bSYour Name 
53*5113495bSYour Name 		return psoc;
54*5113495bSYour Name 	}
55*5113495bSYour Name 
56*5113495bSYour Name 	QDF_DEBUG_PANIC("Failed to find nth psoc: %d", n);
57*5113495bSYour Name 
58*5113495bSYour Name 	return NULL;
59*5113495bSYour Name }
60*5113495bSYour Name 
nth_vdev(struct dsc_psoc * psoc,int n)61*5113495bSYour Name static struct dsc_vdev *nth_vdev(struct dsc_psoc *psoc, int n)
62*5113495bSYour Name {
63*5113495bSYour Name 	struct dsc_vdev *vdev;
64*5113495bSYour Name 
65*5113495bSYour Name 	QDF_BUG(n > 0);
66*5113495bSYour Name 	if (n <= 0)
67*5113495bSYour Name 		return NULL;
68*5113495bSYour Name 
69*5113495bSYour Name 	dsc_for_each_psoc_vdev(psoc, vdev) {
70*5113495bSYour Name 		n--;
71*5113495bSYour Name 		if (n)
72*5113495bSYour Name 			continue;
73*5113495bSYour Name 
74*5113495bSYour Name 		return vdev;
75*5113495bSYour Name 	}
76*5113495bSYour Name 
77*5113495bSYour Name 	QDF_DEBUG_PANIC("Failed to find nth vdev: %d", n);
78*5113495bSYour Name 
79*5113495bSYour Name 	return NULL;
80*5113495bSYour Name }
81*5113495bSYour Name 
__dsc_tree_destroy(struct dsc_driver * driver)82*5113495bSYour Name static void __dsc_tree_destroy(struct dsc_driver *driver)
83*5113495bSYour Name {
84*5113495bSYour Name 	struct dsc_psoc *psoc;
85*5113495bSYour Name 	struct dsc_psoc *next_psoc;
86*5113495bSYour Name 
87*5113495bSYour Name 	QDF_BUG(driver);
88*5113495bSYour Name 
89*5113495bSYour Name 	qdf_list_for_each_del(&driver->psocs, psoc, next_psoc, node) {
90*5113495bSYour Name 		struct dsc_vdev *vdev;
91*5113495bSYour Name 		struct dsc_vdev *next_vdev;
92*5113495bSYour Name 
93*5113495bSYour Name 		qdf_list_for_each_del(&psoc->vdevs, vdev, next_vdev, node)
94*5113495bSYour Name 			dsc_vdev_destroy(&vdev);
95*5113495bSYour Name 
96*5113495bSYour Name 		dsc_psoc_destroy(&psoc);
97*5113495bSYour Name 	}
98*5113495bSYour Name 
99*5113495bSYour Name 	dsc_driver_destroy(&driver);
100*5113495bSYour Name }
101*5113495bSYour Name 
__dsc_tree_create(struct dsc_driver ** out_driver,uint8_t psocs_per_driver,uint8_t vdevs_per_psoc)102*5113495bSYour Name static QDF_STATUS __dsc_tree_create(struct dsc_driver **out_driver,
103*5113495bSYour Name 				    uint8_t psocs_per_driver,
104*5113495bSYour Name 				    uint8_t vdevs_per_psoc)
105*5113495bSYour Name {
106*5113495bSYour Name 	QDF_STATUS status;
107*5113495bSYour Name 	struct dsc_driver *driver;
108*5113495bSYour Name 	int i, j;
109*5113495bSYour Name 
110*5113495bSYour Name 	status = dsc_driver_create(&driver);
111*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
112*5113495bSYour Name 		dsc_err("Failed to create driver; status:%u", status);
113*5113495bSYour Name 		return status;
114*5113495bSYour Name 	}
115*5113495bSYour Name 
116*5113495bSYour Name 	for (i = 0; i < psocs_per_driver; i++) {
117*5113495bSYour Name 		struct dsc_psoc *psoc;
118*5113495bSYour Name 
119*5113495bSYour Name 		status = dsc_psoc_create(driver, &psoc);
120*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
121*5113495bSYour Name 			dsc_err("Failed to create psoc; status:%u", status);
122*5113495bSYour Name 			goto free_tree;
123*5113495bSYour Name 		}
124*5113495bSYour Name 
125*5113495bSYour Name 		for (j = 0; j < vdevs_per_psoc; j++) {
126*5113495bSYour Name 			struct dsc_vdev *vdev;
127*5113495bSYour Name 
128*5113495bSYour Name 			status = dsc_vdev_create(psoc, &vdev);
129*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status)) {
130*5113495bSYour Name 				dsc_err("Failed to create vdev; status:%u",
131*5113495bSYour Name 					status);
132*5113495bSYour Name 				goto free_tree;
133*5113495bSYour Name 			}
134*5113495bSYour Name 		}
135*5113495bSYour Name 	}
136*5113495bSYour Name 
137*5113495bSYour Name 	*out_driver = driver;
138*5113495bSYour Name 
139*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
140*5113495bSYour Name 
141*5113495bSYour Name free_tree:
142*5113495bSYour Name 	__dsc_tree_destroy(driver);
143*5113495bSYour Name 
144*5113495bSYour Name 	return status;
145*5113495bSYour Name }
146*5113495bSYour Name 
dsc_test_create_destroy(void)147*5113495bSYour Name static uint32_t dsc_test_create_destroy(void)
148*5113495bSYour Name {
149*5113495bSYour Name 	uint32_t errors = 0;
150*5113495bSYour Name 	QDF_STATUS status;
151*5113495bSYour Name 	struct dsc_driver *driver;
152*5113495bSYour Name 
153*5113495bSYour Name 	dsc_enter();
154*5113495bSYour Name 
155*5113495bSYour Name 	status = __dsc_tree_create(&driver, 2, 2);
156*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
157*5113495bSYour Name 		errors++;
158*5113495bSYour Name 		goto exit;
159*5113495bSYour Name 	}
160*5113495bSYour Name 
161*5113495bSYour Name 	__dsc_tree_destroy(driver);
162*5113495bSYour Name 
163*5113495bSYour Name exit:
164*5113495bSYour Name 	dsc_exit();
165*5113495bSYour Name 
166*5113495bSYour Name 	return errors;
167*5113495bSYour Name }
168*5113495bSYour Name 
169*5113495bSYour Name #define action_expect(obj, action, status, errors) \
170*5113495bSYour Name do { \
171*5113495bSYour Name 	void *__obj = obj; \
172*5113495bSYour Name 	QDF_STATUS __expected = status; \
173*5113495bSYour Name 	QDF_STATUS __result; \
174*5113495bSYour Name \
175*5113495bSYour Name 	__result = dsc_##obj##_##action##_start(__obj); \
176*5113495bSYour Name 	if (__result != __expected) { \
177*5113495bSYour Name 		dsc_err("FAIL: " #obj " " #action \
178*5113495bSYour Name 			"; expected " #status " (%u), found %u", \
179*5113495bSYour Name 			__expected, __result); \
180*5113495bSYour Name 		(errors)++; \
181*5113495bSYour Name 	} \
182*5113495bSYour Name 	if (QDF_IS_STATUS_SUCCESS(__result) && QDF_IS_STATUS_ERROR(__expected))\
183*5113495bSYour Name 		dsc_##obj##_##action##_stop(__obj); \
184*5113495bSYour Name } while (false)
185*5113495bSYour Name 
dsc_test_driver_trans_blocks(void)186*5113495bSYour Name static uint32_t dsc_test_driver_trans_blocks(void)
187*5113495bSYour Name {
188*5113495bSYour Name 	uint32_t errors = 0;
189*5113495bSYour Name 	QDF_STATUS status;
190*5113495bSYour Name 	struct dsc_driver *driver;
191*5113495bSYour Name 	struct dsc_psoc *psoc;
192*5113495bSYour Name 	struct dsc_vdev *vdev;
193*5113495bSYour Name 
194*5113495bSYour Name 	dsc_enter();
195*5113495bSYour Name 
196*5113495bSYour Name 	/* setup */
197*5113495bSYour Name 
198*5113495bSYour Name 	status = __dsc_tree_create(&driver, 2, 2);
199*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
200*5113495bSYour Name 		errors++;
201*5113495bSYour Name 		goto exit;
202*5113495bSYour Name 	}
203*5113495bSYour Name 
204*5113495bSYour Name 	/* test */
205*5113495bSYour Name 	/* a driver in transition should cause ... */
206*5113495bSYour Name 	action_expect(driver, trans, QDF_STATUS_SUCCESS, errors);
207*5113495bSYour Name 
208*5113495bSYour Name 	/* ... the same driver trans/ops to fail */
209*5113495bSYour Name 	action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors);
210*5113495bSYour Name 	action_expect(driver, op, QDF_STATUS_E_AGAIN, errors);
211*5113495bSYour Name 
212*5113495bSYour Name 	/* ... children psoc trans/ops to fail */
213*5113495bSYour Name 	dsc_for_each_driver_psoc(driver, psoc) {
214*5113495bSYour Name 		action_expect(psoc, trans, QDF_STATUS_E_INVAL, errors);
215*5113495bSYour Name 		action_expect(psoc, op, QDF_STATUS_E_INVAL, errors);
216*5113495bSYour Name 
217*5113495bSYour Name 		/* ... grandchildren vdev trans/ops to fail */
218*5113495bSYour Name 		dsc_for_each_psoc_vdev(psoc, vdev) {
219*5113495bSYour Name 			action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors);
220*5113495bSYour Name 			action_expect(vdev, op, QDF_STATUS_E_INVAL, errors);
221*5113495bSYour Name 		}
222*5113495bSYour Name 	}
223*5113495bSYour Name 
224*5113495bSYour Name 	/* teardown */
225*5113495bSYour Name 
226*5113495bSYour Name 	dsc_driver_trans_stop(driver);
227*5113495bSYour Name 
228*5113495bSYour Name 	__dsc_tree_destroy(driver);
229*5113495bSYour Name 
230*5113495bSYour Name exit:
231*5113495bSYour Name 	dsc_exit();
232*5113495bSYour Name 
233*5113495bSYour Name 	return errors;
234*5113495bSYour Name }
235*5113495bSYour Name 
dsc_test_psoc_trans_blocks(void)236*5113495bSYour Name static uint32_t dsc_test_psoc_trans_blocks(void)
237*5113495bSYour Name {
238*5113495bSYour Name 	uint32_t errors = 0;
239*5113495bSYour Name 	QDF_STATUS status;
240*5113495bSYour Name 	struct dsc_driver *driver;
241*5113495bSYour Name 	struct dsc_psoc *psoc;
242*5113495bSYour Name 	struct dsc_vdev *vdev;
243*5113495bSYour Name 
244*5113495bSYour Name 	dsc_enter();
245*5113495bSYour Name 
246*5113495bSYour Name 	/* setup */
247*5113495bSYour Name 
248*5113495bSYour Name 	status = __dsc_tree_create(&driver, 2, 2);
249*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
250*5113495bSYour Name 		errors++;
251*5113495bSYour Name 		goto exit;
252*5113495bSYour Name 	}
253*5113495bSYour Name 
254*5113495bSYour Name 	/* test */
255*5113495bSYour Name 	/* a psoc in transition should cause ... */
256*5113495bSYour Name 	psoc = nth_psoc(driver, 1);
257*5113495bSYour Name 	action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors);
258*5113495bSYour Name 
259*5113495bSYour Name 	/* ... driver trans/ops to fail */
260*5113495bSYour Name 	action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors);
261*5113495bSYour Name 	action_expect(driver, op, QDF_STATUS_E_AGAIN, errors);
262*5113495bSYour Name 
263*5113495bSYour Name 	/* ... the same psoc trans/ops to fail */
264*5113495bSYour Name 	action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
265*5113495bSYour Name 	action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors);
266*5113495bSYour Name 
267*5113495bSYour Name 	/* ... children vdev trans/ops to fail */
268*5113495bSYour Name 	dsc_for_each_psoc_vdev(psoc, vdev) {
269*5113495bSYour Name 		action_expect(vdev, trans, QDF_STATUS_E_BUSY, errors);
270*5113495bSYour Name 		action_expect(vdev, op, QDF_STATUS_E_BUSY, errors);
271*5113495bSYour Name 	}
272*5113495bSYour Name 
273*5113495bSYour Name 	/* ... while driver unload in progress vdev op and trans should be
274*5113495bSYour Name 	 * rejected with EINVAL
275*5113495bSYour Name 	 */
276*5113495bSYour Name 	cds_set_unload_in_progress(true);
277*5113495bSYour Name 	dsc_for_each_psoc_vdev(psoc, vdev) {
278*5113495bSYour Name 		action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors);
279*5113495bSYour Name 		action_expect(vdev, op, QDF_STATUS_E_INVAL, errors);
280*5113495bSYour Name 	}
281*5113495bSYour Name 	cds_set_unload_in_progress(false);
282*5113495bSYour Name 
283*5113495bSYour Name 	/* ... while SSR recovery in progress vdev op and trans should be
284*5113495bSYour Name 	 * rejected with EINVAL
285*5113495bSYour Name 	 */
286*5113495bSYour Name 	cds_set_recovery_in_progress(true);
287*5113495bSYour Name 	dsc_for_each_psoc_vdev(psoc, vdev) {
288*5113495bSYour Name 		action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors);
289*5113495bSYour Name 		action_expect(vdev, op, QDF_STATUS_E_INVAL, errors);
290*5113495bSYour Name 	}
291*5113495bSYour Name 	cds_set_recovery_in_progress(false);
292*5113495bSYour Name 
293*5113495bSYour Name 	/* a sibling psoc in transition should succeed and cause ... */
294*5113495bSYour Name 	psoc = nth_psoc(driver, 2);
295*5113495bSYour Name 	action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors);
296*5113495bSYour Name 
297*5113495bSYour Name 	/* ... driver trans/ops to fail */
298*5113495bSYour Name 	action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors);
299*5113495bSYour Name 	action_expect(driver, op, QDF_STATUS_E_AGAIN, errors);
300*5113495bSYour Name 
301*5113495bSYour Name 	/* ... the same psoc trans/ops to fail */
302*5113495bSYour Name 	action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
303*5113495bSYour Name 	action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors);
304*5113495bSYour Name 
305*5113495bSYour Name 	/* ... children vdev trans/ops to fail */
306*5113495bSYour Name 	dsc_for_each_psoc_vdev(psoc, vdev) {
307*5113495bSYour Name 		action_expect(vdev, trans, QDF_STATUS_E_BUSY, errors);
308*5113495bSYour Name 		action_expect(vdev, op, QDF_STATUS_E_BUSY, errors);
309*5113495bSYour Name 	}
310*5113495bSYour Name 
311*5113495bSYour Name 	/* teardown */
312*5113495bSYour Name 
313*5113495bSYour Name 	dsc_for_each_driver_psoc(driver, psoc)
314*5113495bSYour Name 		dsc_psoc_trans_stop(psoc);
315*5113495bSYour Name 
316*5113495bSYour Name 	__dsc_tree_destroy(driver);
317*5113495bSYour Name 
318*5113495bSYour Name exit:
319*5113495bSYour Name 	dsc_exit();
320*5113495bSYour Name 
321*5113495bSYour Name 	return errors;
322*5113495bSYour Name }
323*5113495bSYour Name 
dsc_test_vdev_trans_blocks(void)324*5113495bSYour Name static uint32_t dsc_test_vdev_trans_blocks(void)
325*5113495bSYour Name {
326*5113495bSYour Name 	uint32_t errors = 0;
327*5113495bSYour Name 	QDF_STATUS status;
328*5113495bSYour Name 	struct dsc_driver *driver;
329*5113495bSYour Name 	struct dsc_psoc *psoc;
330*5113495bSYour Name 	struct dsc_vdev *vdev;
331*5113495bSYour Name 
332*5113495bSYour Name 	dsc_enter();
333*5113495bSYour Name 
334*5113495bSYour Name 	/* setup */
335*5113495bSYour Name 
336*5113495bSYour Name 	status = __dsc_tree_create(&driver, 2, 2);
337*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
338*5113495bSYour Name 		errors++;
339*5113495bSYour Name 		goto exit;
340*5113495bSYour Name 	}
341*5113495bSYour Name 
342*5113495bSYour Name 	/* test */
343*5113495bSYour Name 
344*5113495bSYour Name 	/* a vdev in transition should cause ... */
345*5113495bSYour Name 	dsc_for_each_driver_psoc(driver, psoc) {
346*5113495bSYour Name 		dsc_for_each_psoc_vdev(psoc, vdev)
347*5113495bSYour Name 			action_expect(vdev, trans, QDF_STATUS_SUCCESS, errors);
348*5113495bSYour Name 	}
349*5113495bSYour Name 
350*5113495bSYour Name 	/* ... driver trans/ops to fail */
351*5113495bSYour Name 	action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors);
352*5113495bSYour Name 	action_expect(driver, op, QDF_STATUS_E_AGAIN, errors);
353*5113495bSYour Name 
354*5113495bSYour Name 	/* ... psoc trans/ops to fail */
355*5113495bSYour Name 	dsc_for_each_driver_psoc(driver, psoc) {
356*5113495bSYour Name 		action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors);
357*5113495bSYour Name 		action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors);
358*5113495bSYour Name 
359*5113495bSYour Name 		/* ... the same vdev trans/ops to fail */
360*5113495bSYour Name 		dsc_for_each_psoc_vdev(psoc, vdev) {
361*5113495bSYour Name 			action_expect(vdev, trans, QDF_STATUS_E_BUSY, errors);
362*5113495bSYour Name 			action_expect(vdev, op, QDF_STATUS_E_BUSY, errors);
363*5113495bSYour Name 		}
364*5113495bSYour Name 	}
365*5113495bSYour Name 
366*5113495bSYour Name 	/* teardown */
367*5113495bSYour Name 
368*5113495bSYour Name 	dsc_for_each_driver_psoc(driver, psoc) {
369*5113495bSYour Name 		dsc_for_each_psoc_vdev(psoc, vdev)
370*5113495bSYour Name 			dsc_vdev_trans_stop(vdev);
371*5113495bSYour Name 	}
372*5113495bSYour Name 
373*5113495bSYour Name 	__dsc_tree_destroy(driver);
374*5113495bSYour Name 
375*5113495bSYour Name exit:
376*5113495bSYour Name 	dsc_exit();
377*5113495bSYour Name 
378*5113495bSYour Name 	return errors;
379*5113495bSYour Name }
380*5113495bSYour Name 
381*5113495bSYour Name #define THREAD_TIMEOUT 1000 /* ms */
382*5113495bSYour Name #define dsc_event_wait(event) qdf_wait_single_event(event, THREAD_TIMEOUT)
383*5113495bSYour Name 
384*5113495bSYour Name #define step_assert(field, expected) \
385*5113495bSYour Name do { \
386*5113495bSYour Name 	uint32_t _step = ++(field); \
387*5113495bSYour Name 	uint32_t _expected = (expected); \
388*5113495bSYour Name \
389*5113495bSYour Name 	if (_step != _expected) \
390*5113495bSYour Name 		QDF_DEBUG_PANIC("Step count is %u; Expected %u", \
391*5113495bSYour Name 				_step, _expected); \
392*5113495bSYour Name } while (false)
393*5113495bSYour Name 
394*5113495bSYour Name #define trans_waiting(ctx) (!qdf_list_empty(&(ctx)->trans.queue))
395*5113495bSYour Name 
396*5113495bSYour Name struct thread_ctx {
397*5113495bSYour Name 	struct dsc_driver *driver;
398*5113495bSYour Name 	qdf_event_t start_vdev_trans;
399*5113495bSYour Name 	qdf_event_t start_vdev_wait;
400*5113495bSYour Name 	uint32_t step;
401*5113495bSYour Name };
402*5113495bSYour Name 
dsc_thread_ops(void * context)403*5113495bSYour Name static QDF_STATUS dsc_thread_ops(void *context)
404*5113495bSYour Name {
405*5113495bSYour Name 	struct thread_ctx *ctx = context;
406*5113495bSYour Name 	struct dsc_driver *driver = ctx->driver;
407*5113495bSYour Name 	struct dsc_psoc *psoc = nth_psoc(driver, 1);
408*5113495bSYour Name 	struct dsc_vdev *vdev = nth_vdev(psoc, 1);
409*5113495bSYour Name 
410*5113495bSYour Name 	dsc_enter();
411*5113495bSYour Name 
412*5113495bSYour Name 	/* thread 1 is doing some operations ... */
413*5113495bSYour Name 	step_assert(ctx->step, 1);
414*5113495bSYour Name 	dsc_assert_success(dsc_driver_op_start(driver));
415*5113495bSYour Name 	dsc_assert_success(dsc_psoc_op_start(psoc));
416*5113495bSYour Name 	dsc_assert_success(dsc_vdev_op_start(vdev));
417*5113495bSYour Name 	step_assert(ctx->step, 2);
418*5113495bSYour Name 
419*5113495bSYour Name 	/* ... at which point, thread 2 starts to transition the vdevs */
420*5113495bSYour Name 	qdf_event_set(&ctx->start_vdev_trans);
421*5113495bSYour Name 
422*5113495bSYour Name 	/* meanwhile, thread 3,4,5 queue up to transition vdev/psoc/driver */
423*5113495bSYour Name 	while (!trans_waiting(driver))
424*5113495bSYour Name 		schedule();
425*5113495bSYour Name 
426*5113495bSYour Name 	/* at this point, each thread is:
427*5113495bSYour Name 	 * 1) doing operations
428*5113495bSYour Name 	 * 2) transitioning vdevs 1/2, waiting for ops to finish
429*5113495bSYour Name 	 * 3) waiting to transition vdev 1
430*5113495bSYour Name 	 * 4) waiting to transition psoc
431*5113495bSYour Name 	 * 5) waitint to transition driver
432*5113495bSYour Name 	 */
433*5113495bSYour Name 
434*5113495bSYour Name 	step_assert(ctx->step, 8);
435*5113495bSYour Name 	dsc_driver_op_stop(driver);
436*5113495bSYour Name 	schedule();
437*5113495bSYour Name 	dsc_psoc_op_stop(psoc);
438*5113495bSYour Name 	schedule();
439*5113495bSYour Name 	dsc_vdev_op_stop(vdev);
440*5113495bSYour Name 
441*5113495bSYour Name 	/* all operations complete; thread2 is now unblocked */
442*5113495bSYour Name 
443*5113495bSYour Name 	dsc_exit();
444*5113495bSYour Name 
445*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
446*5113495bSYour Name }
447*5113495bSYour Name 
dsc_thread_vdev_trans(void * context)448*5113495bSYour Name static QDF_STATUS dsc_thread_vdev_trans(void *context)
449*5113495bSYour Name {
450*5113495bSYour Name 	struct thread_ctx *ctx = context;
451*5113495bSYour Name 	struct dsc_driver *driver = ctx->driver;
452*5113495bSYour Name 	struct dsc_psoc *psoc = nth_psoc(driver, 1);
453*5113495bSYour Name 	struct dsc_vdev *vdev;
454*5113495bSYour Name 
455*5113495bSYour Name 	dsc_enter();
456*5113495bSYour Name 
457*5113495bSYour Name 	/* wait for thread 1 to start operations */
458*5113495bSYour Name 	dsc_assert_success(dsc_event_wait(&ctx->start_vdev_trans));
459*5113495bSYour Name 
460*5113495bSYour Name 	/* start transitions on all vdevs */
461*5113495bSYour Name 	step_assert(ctx->step, 3);
462*5113495bSYour Name 	dsc_for_each_psoc_vdev(psoc, vdev)
463*5113495bSYour Name 		dsc_assert_success(dsc_vdev_trans_start(vdev));
464*5113495bSYour Name 	step_assert(ctx->step, 4);
465*5113495bSYour Name 
466*5113495bSYour Name 	/* meanwhile, thread 3,4,5 queue up to transition vdev/psoc/driver */
467*5113495bSYour Name 	qdf_event_set(&ctx->start_vdev_wait);
468*5113495bSYour Name 
469*5113495bSYour Name 	/* wait for thread 1 to complete pending vdev ops */
470*5113495bSYour Name 	dsc_for_each_psoc_vdev(psoc, vdev)
471*5113495bSYour Name 		dsc_vdev_wait_for_ops(vdev);
472*5113495bSYour Name 
473*5113495bSYour Name 	/* actual vdev transition work would happen here */
474*5113495bSYour Name 
475*5113495bSYour Name 	/* stop transition on vdev 1 */
476*5113495bSYour Name 	step_assert(ctx->step, 9);
477*5113495bSYour Name 	dsc_vdev_trans_stop(nth_vdev(psoc, 1));
478*5113495bSYour Name 
479*5113495bSYour Name 	/* psoc trans should not start until both vdev trans are complete */
480*5113495bSYour Name 	schedule();
481*5113495bSYour Name 	step_assert(ctx->step, 10);
482*5113495bSYour Name 	dsc_vdev_trans_stop(nth_vdev(psoc, 2));
483*5113495bSYour Name 
484*5113495bSYour Name 	dsc_exit();
485*5113495bSYour Name 
486*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
487*5113495bSYour Name }
488*5113495bSYour Name 
dsc_thread_vdev_wait(void * context)489*5113495bSYour Name static QDF_STATUS dsc_thread_vdev_wait(void *context)
490*5113495bSYour Name {
491*5113495bSYour Name 	struct thread_ctx *ctx = context;
492*5113495bSYour Name 	struct dsc_vdev *vdev = nth_vdev(nth_psoc(ctx->driver, 1), 1);
493*5113495bSYour Name 
494*5113495bSYour Name 	dsc_enter();
495*5113495bSYour Name 
496*5113495bSYour Name 	dsc_assert_success(dsc_event_wait(&ctx->start_vdev_wait));
497*5113495bSYour Name 
498*5113495bSYour Name 	step_assert(ctx->step, 5);
499*5113495bSYour Name 	/* vdev trans queues first ... */
500*5113495bSYour Name 	dsc_assert_success(dsc_vdev_trans_start_wait(vdev));
501*5113495bSYour Name 	/* ... but de-queues third */
502*5113495bSYour Name 	step_assert(ctx->step, 15);
503*5113495bSYour Name 
504*5113495bSYour Name 	dsc_vdev_wait_for_ops(vdev);
505*5113495bSYour Name 
506*5113495bSYour Name 	step_assert(ctx->step, 16);
507*5113495bSYour Name 	dsc_vdev_trans_stop(vdev);
508*5113495bSYour Name 
509*5113495bSYour Name 	dsc_exit();
510*5113495bSYour Name 
511*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
512*5113495bSYour Name }
513*5113495bSYour Name 
dsc_thread_psoc_wait(void * context)514*5113495bSYour Name static QDF_STATUS dsc_thread_psoc_wait(void *context)
515*5113495bSYour Name {
516*5113495bSYour Name 	struct thread_ctx *ctx = context;
517*5113495bSYour Name 	struct dsc_psoc *psoc = nth_psoc(ctx->driver, 1);
518*5113495bSYour Name 	struct dsc_vdev *vdev = nth_vdev(psoc, 1);
519*5113495bSYour Name 
520*5113495bSYour Name 	dsc_enter();
521*5113495bSYour Name 
522*5113495bSYour Name 	while (!trans_waiting(vdev))
523*5113495bSYour Name 		schedule();
524*5113495bSYour Name 
525*5113495bSYour Name 	step_assert(ctx->step, 6);
526*5113495bSYour Name 	/* psoc trans queues second ... */
527*5113495bSYour Name 	dsc_assert_success(dsc_psoc_trans_start_wait(psoc));
528*5113495bSYour Name 	/* ... and de-queues second */
529*5113495bSYour Name 	step_assert(ctx->step, 13);
530*5113495bSYour Name 
531*5113495bSYour Name 	dsc_psoc_wait_for_ops(psoc);
532*5113495bSYour Name 
533*5113495bSYour Name 	step_assert(ctx->step, 14);
534*5113495bSYour Name 	dsc_psoc_trans_stop(psoc);
535*5113495bSYour Name 
536*5113495bSYour Name 	dsc_exit();
537*5113495bSYour Name 
538*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
539*5113495bSYour Name }
540*5113495bSYour Name 
dsc_thread_driver_wait(void * context)541*5113495bSYour Name static QDF_STATUS dsc_thread_driver_wait(void *context)
542*5113495bSYour Name {
543*5113495bSYour Name 	struct thread_ctx *ctx = context;
544*5113495bSYour Name 	struct dsc_driver *driver = ctx->driver;
545*5113495bSYour Name 	struct dsc_psoc *psoc = nth_psoc(driver, 1);
546*5113495bSYour Name 
547*5113495bSYour Name 	dsc_enter();
548*5113495bSYour Name 
549*5113495bSYour Name 	while (!trans_waiting(psoc))
550*5113495bSYour Name 		schedule();
551*5113495bSYour Name 
552*5113495bSYour Name 	step_assert(ctx->step, 7);
553*5113495bSYour Name 	/* driver trans queues third ... */
554*5113495bSYour Name 	dsc_assert_success(dsc_driver_trans_start_wait(driver));
555*5113495bSYour Name 	/* ... but de-queues first */
556*5113495bSYour Name 	step_assert(ctx->step, 11);
557*5113495bSYour Name 
558*5113495bSYour Name 	dsc_driver_wait_for_ops(driver);
559*5113495bSYour Name 
560*5113495bSYour Name 	step_assert(ctx->step, 12);
561*5113495bSYour Name 	dsc_driver_trans_stop(driver);
562*5113495bSYour Name 
563*5113495bSYour Name 	dsc_exit();
564*5113495bSYour Name 
565*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
566*5113495bSYour Name }
567*5113495bSYour Name 
dsc_test_trans_wait(void)568*5113495bSYour Name static uint32_t dsc_test_trans_wait(void)
569*5113495bSYour Name {
570*5113495bSYour Name 	uint32_t errors = 0;
571*5113495bSYour Name 	QDF_STATUS status;
572*5113495bSYour Name 	qdf_thread_t *ops_thread;
573*5113495bSYour Name 	qdf_thread_t *vdev_trans_thread;
574*5113495bSYour Name 	qdf_thread_t *vdev_wait_thread;
575*5113495bSYour Name 	qdf_thread_t *psoc_wait_thread;
576*5113495bSYour Name 	qdf_thread_t *driver_wait_thread;
577*5113495bSYour Name 	struct thread_ctx ctx = { 0 };
578*5113495bSYour Name 
579*5113495bSYour Name 	dsc_enter();
580*5113495bSYour Name 
581*5113495bSYour Name 	status = __dsc_tree_create(&ctx.driver, 1, 2);
582*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
583*5113495bSYour Name 		errors++;
584*5113495bSYour Name 		goto exit;
585*5113495bSYour Name 	}
586*5113495bSYour Name 
587*5113495bSYour Name 	dsc_assert_success(qdf_event_create(&ctx.start_vdev_trans));
588*5113495bSYour Name 	dsc_assert_success(qdf_event_create(&ctx.start_vdev_wait));
589*5113495bSYour Name 
590*5113495bSYour Name 	dsc_debug("starting threads");
591*5113495bSYour Name 
592*5113495bSYour Name 	ops_thread = qdf_thread_run(dsc_thread_ops, &ctx);
593*5113495bSYour Name 	vdev_trans_thread = qdf_thread_run(dsc_thread_vdev_trans, &ctx);
594*5113495bSYour Name 	vdev_wait_thread = qdf_thread_run(dsc_thread_vdev_wait, &ctx);
595*5113495bSYour Name 	psoc_wait_thread = qdf_thread_run(dsc_thread_psoc_wait, &ctx);
596*5113495bSYour Name 	driver_wait_thread = qdf_thread_run(dsc_thread_driver_wait, &ctx);
597*5113495bSYour Name 
598*5113495bSYour Name 	qdf_thread_join(ops_thread);
599*5113495bSYour Name 	qdf_thread_join(vdev_trans_thread);
600*5113495bSYour Name 	qdf_thread_join(vdev_wait_thread);
601*5113495bSYour Name 	qdf_thread_join(psoc_wait_thread);
602*5113495bSYour Name 	qdf_thread_join(driver_wait_thread);
603*5113495bSYour Name 
604*5113495bSYour Name 	dsc_debug("threads joined");
605*5113495bSYour Name 
606*5113495bSYour Name 	qdf_event_destroy(&ctx.start_vdev_wait);
607*5113495bSYour Name 	qdf_event_destroy(&ctx.start_vdev_trans);
608*5113495bSYour Name 
609*5113495bSYour Name 	__dsc_tree_destroy(ctx.driver);
610*5113495bSYour Name 
611*5113495bSYour Name exit:
612*5113495bSYour Name 	dsc_exit();
613*5113495bSYour Name 
614*5113495bSYour Name 	return errors;
615*5113495bSYour Name }
616*5113495bSYour Name 
dsc_unit_test(void)617*5113495bSYour Name uint32_t dsc_unit_test(void)
618*5113495bSYour Name {
619*5113495bSYour Name 	uint32_t errors = 0;
620*5113495bSYour Name 
621*5113495bSYour Name 	errors += dsc_test_create_destroy();
622*5113495bSYour Name 	errors += dsc_test_driver_trans_blocks();
623*5113495bSYour Name 	errors += dsc_test_psoc_trans_blocks();
624*5113495bSYour Name 	errors += dsc_test_vdev_trans_blocks();
625*5113495bSYour Name 	errors += dsc_test_trans_wait();
626*5113495bSYour Name 
627*5113495bSYour Name 	return errors;
628*5113495bSYour Name }
629*5113495bSYour Name 
630