1 /* 2 * Copyright (c) 2013-2021 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, HTC_LINK_VOTE_SAP_DFS_USER_ID); 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, HTC_LINK_VOTE_SAP_DFS_USER_ID); 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 bool is_restart) 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 *curr_channel, *prev_channel; 202 uint32_t ch_freq, prev_ch_freq; 203 enum phy_ch_width ch_width, prev_ch_width; 204 uint32_t is_dfs, prev_ch_is_dfs; 205 enum channel_state ch_state, prev_ch_state; 206 207 psoc = wlan_vdev_get_psoc(vdev); 208 pdev = wlan_vdev_get_pdev(vdev); 209 210 if (!pdev) { 211 mlme_err("pdev is NULL"); 212 return; 213 } 214 215 curr_channel = wlan_vdev_mlme_get_des_chan(vdev); 216 ch_freq = curr_channel->ch_freq; 217 ch_width = curr_channel->ch_width; 218 is_dfs = wlan_reg_is_dfs_for_freq(pdev, ch_freq); 219 ch_state = wlan_reg_get_5g_bonded_channel_state_for_freq(pdev, ch_freq, 220 ch_width); 221 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 222 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 223 mlme_err("psoc_id:%d No Rx Ops", 224 wlan_psoc_get_id(psoc)); 225 return; 226 } 227 228 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 229 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) { 230 if (is_restart) { 231 prev_channel = wlan_vdev_mlme_get_bss_chan(vdev); 232 prev_ch_freq = prev_channel->ch_freq; 233 prev_ch_width = prev_channel->ch_width; 234 prev_ch_is_dfs = wlan_reg_is_dfs_for_freq(pdev, 235 prev_ch_freq); 236 prev_ch_state = 237 wlan_reg_get_5g_bonded_channel_state_for_freq(pdev, 238 prev_ch_freq, prev_ch_width); 239 /* 240 * In restart case, if SAP is on non DFS channel and 241 * previously it was on DFS channel then vote for link 242 * down. 243 */ 244 if ((prev_ch_is_dfs || 245 prev_ch_state == CHANNEL_STATE_DFS) && 246 !(is_dfs || ch_state == CHANNEL_STATE_DFS)) 247 target_if_vote_for_link_down(psoc, 248 psoc_wakelock); 249 250 /* 251 * If SAP is on DFS channel and previously it was on 252 * non DFS channel then vote for link up 253 */ 254 if (!(prev_ch_is_dfs || 255 prev_ch_state == CHANNEL_STATE_DFS) && 256 (is_dfs || ch_state == CHANNEL_STATE_DFS)) 257 target_if_vote_for_link_up(psoc, psoc_wakelock); 258 } else if (is_dfs || ch_state == CHANNEL_STATE_DFS) 259 target_if_vote_for_link_up(psoc, psoc_wakelock); 260 } 261 } 262 263 void target_if_vdev_stop_link_handler(struct wlan_objmgr_vdev *vdev) 264 { 265 struct wlan_objmgr_psoc *psoc; 266 struct wlan_objmgr_pdev *pdev; 267 struct psoc_mlme_wakelock *psoc_wakelock; 268 struct wlan_lmac_if_mlme_rx_ops *rx_ops; 269 struct wlan_channel *curr_channel; 270 uint32_t ch_freq; 271 enum phy_ch_width ch_width; 272 uint32_t is_dfs; 273 274 psoc = wlan_vdev_get_psoc(vdev); 275 pdev = wlan_vdev_get_pdev(vdev); 276 277 if (!pdev) { 278 mlme_err("pdev is NULL"); 279 return; 280 } 281 282 curr_channel = wlan_vdev_mlme_get_bss_chan(vdev); 283 ch_freq = curr_channel->ch_freq; 284 ch_width = curr_channel->ch_width; 285 is_dfs = wlan_reg_is_dfs_for_freq(pdev, ch_freq); 286 287 rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); 288 if (!rx_ops || !rx_ops->psoc_get_wakelock_info) { 289 mlme_err("psoc_id:%d No Rx Ops", 290 wlan_psoc_get_id(psoc)); 291 return; 292 } 293 294 psoc_wakelock = rx_ops->psoc_get_wakelock_info(psoc); 295 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) 296 if (is_dfs || 297 (wlan_reg_get_5g_bonded_channel_state_for_freq(pdev, 298 ch_freq, ch_width) == CHANNEL_STATE_DFS)) 299 target_if_vote_for_link_down(psoc, psoc_wakelock); 300 } 301 302