1 /* 2 * Copyright (c) 2013-2020 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 /** 20 * DOC: target_if_psoc_wake_lock.c 21 * 22 * This file provide definition for APIs related to wake lock 23 */ 24 25 #include "qdf_lock.h" 26 #include <target_if_psoc_wake_lock.h> 27 #include <wlan_lmac_if_def.h> 28 #include <host_diag_core_event.h> 29 #include <wlan_objmgr_psoc_obj.h> 30 #include <target_if.h> 31 #include <target_if_vdev_mgr_rx_ops.h> 32 #include <wlan_reg_services_api.h> 33 #include "init_deinit_lmac.h" 34 35 void target_if_wake_lock_init(struct wlan_objmgr_psoc *psoc) 36 { 37 struct psoc_mlme_wakelock *psoc_wakelock; 38 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 39 40 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 41 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 42 mlme_err("psoc_id:%d No Rx Ops", 43 wlan_psoc_get_id(psoc)); 44 return; 45 } 46 47 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 48 49 qdf_wake_lock_create(&psoc_wakelock->start_wakelock, "vdev_start"); 50 qdf_wake_lock_create(&psoc_wakelock->stop_wakelock, "vdev_stop"); 51 qdf_wake_lock_create(&psoc_wakelock->delete_wakelock, "vdev_delete"); 52 53 qdf_runtime_lock_init(&psoc_wakelock->wmi_cmd_rsp_runtime_lock); 54 qdf_runtime_lock_init(&psoc_wakelock->prevent_runtime_lock); 55 psoc_wakelock->is_link_up = false; 56 } 57 58 void target_if_wake_lock_deinit(struct wlan_objmgr_psoc *psoc) 59 { 60 struct psoc_mlme_wakelock *psoc_wakelock; 61 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 62 63 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 64 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 65 mlme_err("psoc_id:%d No Rx Ops", 66 wlan_psoc_get_id(psoc)); 67 return; 68 } 69 70 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 71 72 qdf_wake_lock_destroy(&psoc_wakelock->start_wakelock); 73 qdf_wake_lock_destroy(&psoc_wakelock->stop_wakelock); 74 qdf_wake_lock_destroy(&psoc_wakelock->delete_wakelock); 75 76 qdf_runtime_lock_deinit(&psoc_wakelock->wmi_cmd_rsp_runtime_lock); 77 qdf_runtime_lock_deinit(&psoc_wakelock->prevent_runtime_lock); 78 } 79 80 QDF_STATUS target_if_wake_lock_timeout_acquire( 81 struct wlan_objmgr_psoc *psoc, 82 enum wakelock_mode mode) 83 { 84 struct psoc_mlme_wakelock *psoc_wakelock; 85 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 86 87 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 88 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 89 mlme_err("psoc_id:%d No Rx Ops", 90 wlan_psoc_get_id(psoc)); 91 return QDF_STATUS_E_INVAL; 92 } 93 94 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 95 switch (mode) { 96 case START_WAKELOCK: 97 qdf_wake_lock_timeout_acquire(&psoc_wakelock->start_wakelock, 98 START_RESPONSE_TIMER); 99 break; 100 case STOP_WAKELOCK: 101 qdf_wake_lock_timeout_acquire(&psoc_wakelock->stop_wakelock, 102 STOP_RESPONSE_TIMER); 103 break; 104 case DELETE_WAKELOCK: 105 qdf_wake_lock_timeout_acquire(&psoc_wakelock->delete_wakelock, 106 DELETE_RESPONSE_TIMER); 107 break; 108 default: 109 target_if_err("operation mode is invalid"); 110 return QDF_STATUS_E_FAILURE; 111 } 112 113 qdf_runtime_pm_prevent_suspend( 114 &psoc_wakelock->wmi_cmd_rsp_runtime_lock); 115 116 return QDF_STATUS_SUCCESS; 117 } 118 119 QDF_STATUS target_if_wake_lock_timeout_release( 120 struct wlan_objmgr_psoc *psoc, 121 enum wakelock_mode mode) 122 { 123 struct psoc_mlme_wakelock *psoc_wakelock; 124 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 125 126 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 127 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 128 mlme_err("psoc_id:%d No Rx Ops", wlan_psoc_get_id(psoc)); 129 return QDF_STATUS_E_INVAL; 130 } 131 132 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 133 switch (mode) { 134 case START_WAKELOCK: 135 qdf_wake_lock_release(&psoc_wakelock->start_wakelock, 136 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); 137 break; 138 case STOP_WAKELOCK: 139 qdf_wake_lock_release(&psoc_wakelock->stop_wakelock, 140 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); 141 break; 142 case DELETE_WAKELOCK: 143 qdf_wake_lock_release(&psoc_wakelock->delete_wakelock, 144 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); 145 break; 146 default: 147 target_if_err("operation mode is invalid"); 148 return QDF_STATUS_E_FAILURE; 149 } 150 151 qdf_runtime_pm_allow_suspend(&psoc_wakelock->wmi_cmd_rsp_runtime_lock); 152 153 return QDF_STATUS_SUCCESS; 154 } 155 156 static void 157 target_if_vote_for_link_down(struct wlan_objmgr_psoc *psoc, 158 struct psoc_mlme_wakelock *psoc_wakelock) 159 { 160 void *htc_handle; 161 162 htc_handle = lmac_get_htc_hdl(psoc); 163 if (!htc_handle) { 164 mlme_err("HTC handle is NULL"); 165 return; 166 } 167 168 if (psoc_wakelock->is_link_up) { 169 htc_vote_link_down(htc_handle); 170 qdf_runtime_pm_allow_suspend(&psoc_wakelock->prevent_runtime_lock); 171 psoc_wakelock->is_link_up = false; 172 } 173 } 174 175 static void 176 target_if_vote_for_link_up(struct wlan_objmgr_psoc *psoc, 177 struct psoc_mlme_wakelock *psoc_wakelock) 178 { 179 void *htc_handle; 180 181 htc_handle = lmac_get_htc_hdl(psoc); 182 if (!htc_handle) { 183 mlme_err("HTC handle is NULL"); 184 return; 185 } 186 187 if (!psoc_wakelock->is_link_up) { 188 htc_vote_link_up(htc_handle); 189 qdf_runtime_pm_prevent_suspend(&psoc_wakelock->prevent_runtime_lock); 190 psoc_wakelock->is_link_up = true; 191 } 192 } 193 194 void target_if_vdev_start_link_handler(struct wlan_objmgr_vdev *vdev, 195 uint32_t is_dfs) 196 { 197 struct wlan_objmgr_psoc *psoc; 198 struct wlan_objmgr_pdev *pdev; 199 struct psoc_mlme_wakelock *psoc_wakelock; 200 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 201 struct wlan_channel *des_channel; 202 uint32_t ch_freq; 203 enum phy_ch_width ch_width; 204 205 psoc = wlan_vdev_get_psoc(vdev); 206 pdev = wlan_vdev_get_pdev(vdev); 207 des_channel = wlan_vdev_mlme_get_des_chan(vdev); 208 ch_freq = des_channel->ch_freq; 209 ch_width = des_channel->ch_width; 210 211 if (!pdev) { 212 mlme_err("pdev is NULL"); 213 return; 214 } 215 216 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 217 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 218 mlme_err("psoc_id:%d No Rx Ops", 219 wlan_psoc_get_id(psoc)); 220 return; 221 } 222 223 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 224 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 225 if (is_dfs || 226 (wlan_reg_get_5g_bonded_channel_state_for_freq(pdev, 227 ch_freq, ch_width) == CHANNEL_STATE_DFS)) 228 target_if_vote_for_link_up(psoc, psoc_wakelock); 229 else 230 target_if_vote_for_link_down(psoc, psoc_wakelock); 231 } 232 } 233 234 void target_if_vdev_stop_link_handler(struct wlan_objmgr_vdev *vdev) 235 { 236 struct wlan_objmgr_psoc *psoc; 237 struct psoc_mlme_wakelock *psoc_wakelock; 238 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 239 240 psoc = wlan_vdev_get_psoc(vdev); 241 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 242 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 243 mlme_err("psoc_id:%d No Rx Ops", 244 wlan_psoc_get_id(psoc)); 245 return; 246 } 247 248 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 249 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) 250 target_if_vote_for_link_down(psoc, psoc_wakelock); 251 } 252 253