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