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