1 /* 2 * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: target_if_psoc_wake_lock.c 22 * 23 * This file provide definition for APIs related to wake lock 24 */ 25 26 #include "qdf_lock.h" 27 #include <target_if_psoc_wake_lock.h> 28 #include <wlan_lmac_if_def.h> 29 #include <host_diag_core_event.h> 30 #include <wlan_objmgr_psoc_obj.h> 31 #include <target_if.h> 32 #include <target_if_vdev_mgr_rx_ops.h> 33 #include <wlan_reg_services_api.h> 34 #include "init_deinit_lmac.h" 35 36 void target_if_wake_lock_init(struct wlan_objmgr_psoc *psoc) 37 { 38 struct psoc_mlme_wakelock *psoc_wakelock; 39 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 40 41 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 42 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 43 mlme_err("psoc_id:%d No Rx Ops", 44 wlan_psoc_get_id(psoc)); 45 return; 46 } 47 48 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 49 50 qdf_wake_lock_create(&psoc_wakelock->start_wakelock, "vdev_start"); 51 qdf_wake_lock_create(&psoc_wakelock->stop_wakelock, "vdev_stop"); 52 qdf_wake_lock_create(&psoc_wakelock->delete_wakelock, "vdev_delete"); 53 54 qdf_runtime_lock_init(&psoc_wakelock->wmi_cmd_rsp_runtime_lock); 55 qdf_runtime_lock_init(&psoc_wakelock->prevent_runtime_lock); 56 qdf_runtime_lock_init(&psoc_wakelock->roam_sync_runtime_lock); 57 58 psoc_wakelock->is_link_up = false; 59 } 60 61 void target_if_wake_lock_deinit(struct wlan_objmgr_psoc *psoc) 62 { 63 struct psoc_mlme_wakelock *psoc_wakelock; 64 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 65 66 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 67 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 68 mlme_err("psoc_id:%d No Rx Ops", 69 wlan_psoc_get_id(psoc)); 70 return; 71 } 72 73 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 74 75 qdf_wake_lock_destroy(&psoc_wakelock->start_wakelock); 76 qdf_wake_lock_destroy(&psoc_wakelock->stop_wakelock); 77 qdf_wake_lock_destroy(&psoc_wakelock->delete_wakelock); 78 79 qdf_runtime_lock_deinit(&psoc_wakelock->wmi_cmd_rsp_runtime_lock); 80 qdf_runtime_lock_deinit(&psoc_wakelock->prevent_runtime_lock); 81 qdf_runtime_lock_deinit(&psoc_wakelock->roam_sync_runtime_lock); 82 } 83 84 QDF_STATUS target_if_wake_lock_timeout_acquire( 85 struct wlan_objmgr_psoc *psoc, 86 enum wakelock_mode mode) 87 { 88 struct psoc_mlme_wakelock *psoc_wakelock; 89 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 90 91 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 92 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 93 mlme_err("psoc_id:%d No Rx Ops", 94 wlan_psoc_get_id(psoc)); 95 return QDF_STATUS_E_INVAL; 96 } 97 98 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 99 switch (mode) { 100 case START_WAKELOCK: 101 qdf_wake_lock_timeout_acquire(&psoc_wakelock->start_wakelock, 102 START_RESPONSE_TIMER); 103 break; 104 case STOP_WAKELOCK: 105 qdf_wake_lock_timeout_acquire(&psoc_wakelock->stop_wakelock, 106 STOP_RESPONSE_TIMER); 107 break; 108 case DELETE_WAKELOCK: 109 qdf_wake_lock_timeout_acquire(&psoc_wakelock->delete_wakelock, 110 DELETE_RESPONSE_TIMER); 111 break; 112 default: 113 target_if_err("operation mode is invalid"); 114 return QDF_STATUS_E_FAILURE; 115 } 116 117 qdf_runtime_pm_prevent_suspend( 118 &psoc_wakelock->wmi_cmd_rsp_runtime_lock); 119 120 return QDF_STATUS_SUCCESS; 121 } 122 123 QDF_STATUS target_if_wake_lock_timeout_release( 124 struct wlan_objmgr_psoc *psoc, 125 enum wakelock_mode mode) 126 { 127 struct psoc_mlme_wakelock *psoc_wakelock; 128 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 129 130 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 131 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 132 mlme_err("psoc_id:%d No Rx Ops", wlan_psoc_get_id(psoc)); 133 return QDF_STATUS_E_INVAL; 134 } 135 136 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 137 switch (mode) { 138 case START_WAKELOCK: 139 qdf_wake_lock_release(&psoc_wakelock->start_wakelock, 140 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); 141 break; 142 case STOP_WAKELOCK: 143 qdf_wake_lock_release(&psoc_wakelock->stop_wakelock, 144 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); 145 break; 146 case DELETE_WAKELOCK: 147 qdf_wake_lock_release(&psoc_wakelock->delete_wakelock, 148 WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); 149 break; 150 default: 151 target_if_err("operation mode is invalid"); 152 return QDF_STATUS_E_FAILURE; 153 } 154 155 qdf_runtime_pm_allow_suspend(&psoc_wakelock->wmi_cmd_rsp_runtime_lock); 156 157 return QDF_STATUS_SUCCESS; 158 } 159 160 static void 161 target_if_vote_for_link_down(struct wlan_objmgr_psoc *psoc, 162 struct psoc_mlme_wakelock *psoc_wakelock) 163 { 164 void *htc_handle; 165 166 htc_handle = lmac_get_htc_hdl(psoc); 167 if (!htc_handle) { 168 mlme_err("HTC handle is NULL"); 169 return; 170 } 171 172 if (psoc_wakelock->is_link_up) { 173 htc_vote_link_down(htc_handle, HTC_LINK_VOTE_SAP_DFS_USER_ID); 174 qdf_runtime_pm_allow_suspend(&psoc_wakelock->prevent_runtime_lock); 175 psoc_wakelock->is_link_up = false; 176 } 177 } 178 179 static void 180 target_if_vote_for_link_up(struct wlan_objmgr_psoc *psoc, 181 struct psoc_mlme_wakelock *psoc_wakelock) 182 { 183 void *htc_handle; 184 185 htc_handle = lmac_get_htc_hdl(psoc); 186 if (!htc_handle) { 187 mlme_err("HTC handle is NULL"); 188 return; 189 } 190 191 if (!psoc_wakelock->is_link_up) { 192 htc_vote_link_up(htc_handle, HTC_LINK_VOTE_SAP_DFS_USER_ID); 193 qdf_runtime_pm_prevent_suspend(&psoc_wakelock->prevent_runtime_lock); 194 psoc_wakelock->is_link_up = true; 195 } 196 } 197 198 void target_if_vdev_start_link_handler(struct wlan_objmgr_vdev *vdev, 199 bool is_restart) 200 { 201 struct wlan_objmgr_psoc *psoc; 202 struct wlan_objmgr_pdev *pdev; 203 struct psoc_mlme_wakelock *psoc_wakelock; 204 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 205 struct wlan_channel *curr_channel, *prev_channel; 206 uint32_t ch_freq, prev_ch_freq; 207 enum phy_ch_width ch_width, prev_ch_width; 208 uint32_t is_dfs, prev_ch_is_dfs; 209 enum channel_state ch_state, prev_ch_state; 210 struct ch_params ch_params = {0}; 211 212 psoc = wlan_vdev_get_psoc(vdev); 213 pdev = wlan_vdev_get_pdev(vdev); 214 215 if (!pdev) { 216 mlme_err("pdev is NULL"); 217 return; 218 } 219 220 curr_channel = wlan_vdev_mlme_get_des_chan(vdev); 221 ch_freq = curr_channel->ch_freq; 222 ch_width = curr_channel->ch_width; 223 is_dfs = wlan_reg_is_dfs_for_freq(pdev, ch_freq); 224 225 ch_params.ch_width = ch_width; 226 ch_state = 227 wlan_reg_get_5g_bonded_channel_state_for_pwrmode( 228 pdev, ch_freq, &ch_params, 229 REG_CURRENT_PWR_MODE); 230 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 231 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 232 mlme_err("psoc_id:%d No Rx Ops", 233 wlan_psoc_get_id(psoc)); 234 return; 235 } 236 237 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 238 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 239 if (is_restart) { 240 prev_channel = wlan_vdev_mlme_get_bss_chan(vdev); 241 prev_ch_freq = prev_channel->ch_freq; 242 prev_ch_width = prev_channel->ch_width; 243 prev_ch_is_dfs = wlan_reg_is_dfs_for_freq(pdev, 244 prev_ch_freq); 245 ch_params.ch_width = prev_ch_width; 246 prev_ch_state = 247 wlan_reg_get_5g_bonded_channel_state_for_pwrmode( 248 pdev, 249 prev_ch_freq, &ch_params, 250 REG_CURRENT_PWR_MODE); 251 /* 252 * In restart case, if SAP is on non DFS channel and 253 * previously it was on DFS channel then vote for link 254 * down. 255 */ 256 if ((prev_ch_is_dfs || 257 prev_ch_state == CHANNEL_STATE_DFS) && 258 !(is_dfs || ch_state == CHANNEL_STATE_DFS)) 259 target_if_vote_for_link_down(psoc, 260 psoc_wakelock); 261 262 /* 263 * If SAP is on DFS channel and previously it was on 264 * non DFS channel then vote for link up 265 */ 266 if (!(prev_ch_is_dfs || 267 prev_ch_state == CHANNEL_STATE_DFS) && 268 (is_dfs || ch_state == CHANNEL_STATE_DFS)) 269 target_if_vote_for_link_up(psoc, psoc_wakelock); 270 } else if (is_dfs || ch_state == CHANNEL_STATE_DFS) 271 target_if_vote_for_link_up(psoc, psoc_wakelock); 272 } 273 } 274 275 void target_if_vdev_stop_link_handler(struct wlan_objmgr_vdev *vdev) 276 { 277 struct wlan_objmgr_psoc *psoc; 278 struct wlan_objmgr_pdev *pdev; 279 struct psoc_mlme_wakelock *psoc_wakelock; 280 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 281 struct wlan_channel *curr_channel; 282 uint32_t ch_freq; 283 enum phy_ch_width ch_width; 284 uint32_t is_dfs; 285 struct ch_params ch_params = {0}; 286 287 psoc = wlan_vdev_get_psoc(vdev); 288 pdev = wlan_vdev_get_pdev(vdev); 289 290 if (!pdev) { 291 mlme_err("pdev is NULL"); 292 return; 293 } 294 295 curr_channel = wlan_vdev_mlme_get_bss_chan(vdev); 296 ch_freq = curr_channel->ch_freq; 297 ch_width = curr_channel->ch_width; 298 is_dfs = wlan_reg_is_dfs_for_freq(pdev, ch_freq); 299 300 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 301 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 302 mlme_err("psoc_id:%d No Rx Ops", 303 wlan_psoc_get_id(psoc)); 304 return; 305 } 306 307 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 308 ch_params.ch_width = ch_width; 309 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) 310 if (is_dfs || 311 (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( 312 pdev, 313 ch_freq, 314 &ch_params, 315 REG_CURRENT_PWR_MODE) == CHANNEL_STATE_DFS)) 316 target_if_vote_for_link_down(psoc, psoc_wakelock); 317 } 318 319 void target_if_prevent_pm_during_roam_sync(struct wlan_objmgr_psoc *psoc) 320 { 321 struct psoc_mlme_wakelock *psoc_wakelock; 322 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 323 324 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 325 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 326 target_if_err("psoc_id:%d No Rx Ops", 327 wlan_psoc_get_id(psoc)); 328 return; 329 } 330 331 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 332 qdf_runtime_pm_prevent_suspend(&psoc_wakelock->roam_sync_runtime_lock); 333 } 334 335 void target_if_allow_pm_after_roam_sync(struct wlan_objmgr_psoc *psoc) 336 { 337 struct psoc_mlme_wakelock *psoc_wakelock; 338 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 339 340 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 341 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 342 target_if_err("psoc_id:%d No Rx Ops", 343 wlan_psoc_get_id(psoc)); 344 return; 345 } 346 347 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 348 qdf_runtime_pm_allow_suspend(&psoc_wakelock->roam_sync_runtime_lock); 349 } 350