1 /*
2  * Copyright (c) 2019 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_periodic_work.h"
20 #include "qdf_periodic_work_test.h"
21 #include "qdf_trace.h"
22 
23 #define pwork_iterations 2
24 #define pwork_delay_ms 1
25 
26 struct qdf_pwork_ut_ctx {
27 	struct qdf_periodic_work pwork;
28 	uint32_t count;
29 };
30 
__qdf_pwork_inside_cb(void * context)31 static void __qdf_pwork_inside_cb(void *context)
32 {
33 	struct qdf_pwork_ut_ctx *ut_ctx = context;
34 
35 	/* stop before incrementing; the main thread is looking at @count */
36 	if (ut_ctx->count + 1 == pwork_iterations)
37 		qdf_periodic_work_stop_async(&ut_ctx->pwork);
38 
39 	ut_ctx->count++;
40 }
41 
qdf_pwork_stop_inside_cb(void)42 static uint32_t qdf_pwork_stop_inside_cb(void)
43 {
44 	struct qdf_pwork_ut_ctx ut_ctx = { .count = 0 };
45 	QDF_STATUS status;
46 
47 	status = qdf_periodic_work_create(&ut_ctx.pwork,
48 					  __qdf_pwork_inside_cb, &ut_ctx);
49 	QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
50 
51 	QDF_BUG(qdf_periodic_work_start(&ut_ctx.pwork, pwork_delay_ms));
52 
53 	while (ut_ctx.count < pwork_iterations)
54 		schedule();
55 
56 	QDF_BUG(!qdf_periodic_work_stop_sync(&ut_ctx.pwork));
57 	QDF_BUG(ut_ctx.count == pwork_iterations);
58 
59 	qdf_periodic_work_destroy(&ut_ctx.pwork);
60 
61 	return 0;
62 }
63 
__qdf_pwork_outside_cb(void * context)64 static void __qdf_pwork_outside_cb(void *context)
65 {
66 	struct qdf_pwork_ut_ctx *ut_ctx = context;
67 
68 	ut_ctx->count++;
69 }
70 
qdf_pwork_stop_outside_cb(void)71 static uint32_t qdf_pwork_stop_outside_cb(void)
72 {
73 	struct qdf_pwork_ut_ctx ut_ctx = { .count = 0 };
74 	QDF_STATUS status;
75 
76 	status = qdf_periodic_work_create(&ut_ctx.pwork,
77 					  __qdf_pwork_outside_cb, &ut_ctx);
78 	QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
79 
80 	QDF_BUG(qdf_periodic_work_start(&ut_ctx.pwork, pwork_delay_ms));
81 
82 	while (ut_ctx.count < pwork_iterations)
83 		schedule();
84 
85 	QDF_BUG(qdf_periodic_work_stop_sync(&ut_ctx.pwork));
86 	QDF_BUG(ut_ctx.count >= pwork_iterations);
87 
88 	qdf_periodic_work_destroy(&ut_ctx.pwork);
89 
90 	return 0;
91 }
92 
qdf_periodic_work_unit_test(void)93 uint32_t qdf_periodic_work_unit_test(void)
94 {
95 	uint32_t errors = 0;
96 
97 	errors += qdf_pwork_stop_inside_cb();
98 	errors += qdf_pwork_stop_outside_cb();
99 
100 	return errors;
101 }
102 
103