1 /*
2  * Copyright (c) 2017-2018 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_status.h"
20 #include "hif_main.h"
21 #include "hif_unit_test_suspend.h"
22 #include "hif_unit_test_suspend_i.h"
23 
24 enum hif_ut_suspend_state_bits {
25 	UT_SUSPENDED_BIT = 0
26 };
27 
28 /**
29  * hif_ut_fw_resume_work() - Work handler for firmware-triggered resume
30  * @work: The work struct being passed from the linux kernel
31  *
32  * Return: None
33  */
hif_ut_fw_resume_work(struct work_struct * work)34 static void hif_ut_fw_resume_work(struct work_struct *work)
35 {
36 	struct hif_ut_suspend_context *ctx =
37 		container_of(work, struct hif_ut_suspend_context, resume_work);
38 
39 	QDF_BUG(ctx);
40 	if (!ctx)
41 		return;
42 
43 	QDF_BUG(ctx->resume_callback);
44 	if (!ctx->resume_callback)
45 		return;
46 
47 	ctx->resume_callback();
48 	ctx->resume_callback = NULL;
49 }
50 
hif_ut_suspend_init(struct hif_softc * scn)51 void hif_ut_suspend_init(struct hif_softc *scn)
52 {
53 	INIT_WORK(&scn->ut_suspend_ctx.resume_work, hif_ut_fw_resume_work);
54 }
55 
hif_is_ut_suspended(struct hif_softc * scn)56 bool hif_is_ut_suspended(struct hif_softc *scn)
57 {
58 	QDF_BUG(scn);
59 	if (!scn)
60 		return false;
61 
62 	return test_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state);
63 }
64 
hif_ut_apps_suspend(struct hif_opaque_softc * opaque_scn,hif_ut_resume_callback callback)65 QDF_STATUS hif_ut_apps_suspend(struct hif_opaque_softc *opaque_scn,
66 			       hif_ut_resume_callback callback)
67 {
68 	struct hif_softc *scn = HIF_GET_SOFTC(opaque_scn);
69 
70 	QDF_BUG(scn);
71 	if (!scn)
72 		return QDF_STATUS_E_INVAL;
73 
74 	QDF_BUG(callback);
75 	if (!callback)
76 		return QDF_STATUS_E_INVAL;
77 
78 	if (test_and_set_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state))
79 		return QDF_STATUS_E_INVAL;
80 
81 	scn->ut_suspend_ctx.resume_callback = callback;
82 
83 	return QDF_STATUS_SUCCESS;
84 }
85 
hif_ut_apps_resume(struct hif_opaque_softc * opaque_scn)86 QDF_STATUS hif_ut_apps_resume(struct hif_opaque_softc *opaque_scn)
87 {
88 	struct hif_softc *scn = HIF_GET_SOFTC(opaque_scn);
89 
90 	QDF_BUG(scn);
91 	if (!scn)
92 		return QDF_STATUS_E_INVAL;
93 
94 	if (!test_and_clear_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state))
95 		return QDF_STATUS_E_INVAL;
96 
97 	scn->ut_suspend_ctx.resume_callback = NULL;
98 
99 	return QDF_STATUS_SUCCESS;
100 }
101 
hif_ut_fw_resume(struct hif_softc * scn)102 QDF_STATUS hif_ut_fw_resume(struct hif_softc *scn)
103 {
104 	QDF_BUG(scn);
105 	if (!scn)
106 		return QDF_STATUS_E_INVAL;
107 
108 	if (!test_and_clear_bit(UT_SUSPENDED_BIT, &scn->ut_suspend_ctx.state))
109 		return QDF_STATUS_E_INVAL;
110 
111 	schedule_work(&scn->ut_suspend_ctx.resume_work);
112 
113 	return QDF_STATUS_SUCCESS;
114 }
115 
hif_irq_trigger_ut_resume(struct hif_softc * scn)116 bool hif_irq_trigger_ut_resume(struct hif_softc *scn)
117 {
118 	if (!hif_is_ut_suspended(scn))
119 		return false;
120 
121 	return true;
122 }
123