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