1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2024 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: Define API's for suspend / resume handling 22 */ 23 24 #include "wlan_pmo_wow.h" 25 #include "wlan_pmo_tgt_api.h" 26 #include "wlan_pmo_main.h" 27 #include "wlan_pmo_obj_mgmt_public_struct.h" 28 #include "wlan_pmo_lphb.h" 29 #include "wlan_pmo_hw_filter.h" 30 #include "wlan_pmo_suspend_resume.h" 31 #include "cdp_txrx_ops.h" 32 #include "cdp_txrx_misc.h" 33 #include "cdp_txrx_flow_ctrl_legacy.h" 34 #include "hif.h" 35 #include "htc_api.h" 36 #include "wlan_pmo_obj_mgmt_api.h" 37 #include <wlan_scan_ucfg_api.h> 38 #include <wlan_dp_api.h> 39 #include "cds_api.h" 40 #include "wlan_pmo_static_config.h" 41 #include "wlan_mlme_ucfg_api.h" 42 #include "cfg_mlme_sap.h" 43 #include "cfg_ucfg_api.h" 44 #include "cdp_txrx_bus.h" 45 #include "wlan_pmo_ucfg_api.h" 46 #include "hif.h" 47 #include "target_type.h" 48 49 /** 50 * pmo_core_get_vdev_dtim_period() - Get vdev dtim period 51 * @vdev: objmgr vdev handle 52 * 53 * Return: Vdev dtim period 54 */ pmo_core_get_vdev_dtim_period(struct wlan_objmgr_vdev * vdev)55 static uint8_t pmo_core_get_vdev_dtim_period(struct wlan_objmgr_vdev *vdev) 56 { 57 uint8_t dtim_period = 0; 58 struct pmo_psoc_priv_obj *psoc_ctx; 59 struct wlan_objmgr_psoc *psoc; 60 QDF_STATUS ret = QDF_STATUS_E_FAILURE; 61 62 psoc = pmo_vdev_get_psoc(vdev); 63 64 pmo_psoc_with_ctx(psoc, psoc_ctx) { 65 if (psoc_ctx->get_dtim_period) 66 ret = psoc_ctx->get_dtim_period(pmo_vdev_get_id(vdev), 67 &dtim_period); 68 } 69 70 if (QDF_IS_STATUS_ERROR(ret)) 71 pmo_err("Failed to get to dtim period for vdevId %d", 72 pmo_vdev_get_id(vdev)); 73 74 return dtim_period; 75 } 76 77 /** 78 * pmo_core_get_vdev_beacon_interval() - Get vdev beacon interval 79 * @vdev: objmgr vdev handle 80 * 81 * Return: Vdev beacon interval 82 */ pmo_core_get_vdev_beacon_interval(struct wlan_objmgr_vdev * vdev)83 static uint16_t pmo_core_get_vdev_beacon_interval(struct wlan_objmgr_vdev *vdev) 84 { 85 uint16_t beacon_interval = 0; 86 struct pmo_psoc_priv_obj *psoc_ctx; 87 struct wlan_objmgr_psoc *psoc; 88 QDF_STATUS ret = QDF_STATUS_E_FAILURE; 89 90 psoc = pmo_vdev_get_psoc(vdev); 91 92 pmo_psoc_with_ctx(psoc, psoc_ctx) { 93 if (psoc_ctx->get_beacon_interval) 94 ret = psoc_ctx->get_beacon_interval( 95 pmo_vdev_get_id(vdev), 96 &beacon_interval); 97 } 98 99 if (QDF_IS_STATUS_ERROR(ret)) 100 pmo_err("Failed to get beacon interval for vdev id %d", 101 pmo_vdev_get_id(vdev)); 102 103 return beacon_interval; 104 } 105 106 /** 107 * pmo_core_calculate_listen_interval() - Calculate vdev listen interval 108 * @vdev: objmgr vdev handle 109 * @vdev_ctx: pmo vdev priv ctx 110 * @listen_interval: listen interval which is computed for vdev 111 * 112 * Return: QDF_STATUS 113 */ pmo_core_calculate_listen_interval(struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx,uint32_t * listen_interval)114 static QDF_STATUS pmo_core_calculate_listen_interval( 115 struct wlan_objmgr_vdev *vdev, 116 struct pmo_vdev_priv_obj *vdev_ctx, 117 uint32_t *listen_interval) 118 { 119 uint32_t max_mod_dtim, max_dtim = 0; 120 uint32_t beacon_interval_mod; 121 struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; 122 struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); 123 124 if (psoc_cfg->sta_dynamic_dtim) { 125 *listen_interval = psoc_cfg->sta_dynamic_dtim; 126 } else if ((psoc_cfg->sta_mod_dtim) && 127 (psoc_cfg->sta_max_li_mod_dtim)) { 128 /* 129 * When the system is in suspend 130 * (maximum beacon will be at 1s == 10) 131 * If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM) 132 * equal or larger than MDTIM 133 * (configured in WCNSS_qcom_cfg.ini) 134 * Set LI to MDTIM * AP_DTIM 135 * If Dtim = 2 and Mdtim = 2 then LI is 4 136 * Else 137 * Set LI to maxModulatedDTIM * AP_DTIM 138 */ 139 beacon_interval_mod = 140 pmo_core_get_vdev_beacon_interval(vdev) / 100; 141 if (beacon_interval_mod == 0) 142 beacon_interval_mod = 1; 143 144 max_dtim = pmo_core_get_vdev_dtim_period(vdev) * 145 beacon_interval_mod; 146 147 if (!max_dtim) { 148 pmo_err("Invalid dtim period"); 149 return QDF_STATUS_E_INVAL; 150 } 151 152 max_mod_dtim = psoc_cfg->sta_max_li_mod_dtim / max_dtim; 153 154 if (max_mod_dtim <= 0) 155 max_mod_dtim = 1; 156 157 if (max_mod_dtim >= psoc_cfg->sta_mod_dtim) { 158 *listen_interval = 159 (psoc_cfg->sta_mod_dtim * 160 pmo_core_get_vdev_dtim_period(vdev)); 161 } else { 162 *listen_interval = 163 (max_mod_dtim * 164 pmo_core_get_vdev_dtim_period(vdev)); 165 } 166 } else { 167 /* Get Listen Interval */ 168 if (QDF_IS_STATUS_ERROR(ucfg_mlme_get_listen_interval(psoc, 169 listen_interval))) { 170 pmo_err("Failed to get value for listen interval"); 171 *listen_interval = cfg_default(CFG_LISTEN_INTERVAL); 172 } 173 } 174 175 pmo_info("sta dynamic dtim %d sta mod dtim %d sta_max_li_mod_dtim %d max_dtim %d", 176 psoc_cfg->sta_dynamic_dtim, psoc_cfg->sta_mod_dtim, 177 psoc_cfg->sta_max_li_mod_dtim, max_dtim); 178 179 return QDF_STATUS_SUCCESS; 180 } 181 pmo_configure_vdev_suspend_params(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)182 static void pmo_configure_vdev_suspend_params( 183 struct wlan_objmgr_psoc *psoc, 184 struct wlan_objmgr_vdev *vdev, 185 struct pmo_vdev_priv_obj *vdev_ctx) 186 { 187 QDF_STATUS ret; 188 uint8_t vdev_id; 189 enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); 190 struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; 191 uint8_t ito_repeat_count_value = 0; 192 uint32_t non_wow_inactivity_time, wow_inactivity_time; 193 194 vdev_id = pmo_vdev_get_id(vdev); 195 if (!PMO_VDEV_IN_STA_MODE(opmode)) 196 return; 197 ret = pmo_tgt_send_vdev_sta_ps_param(vdev, 198 pmo_sta_ps_param_inactivity_time, 199 psoc_cfg->wow_data_inactivity_timeout); 200 if (QDF_IS_STATUS_ERROR(ret)) { 201 pmo_err("Failed to Set wow inactivity timeout vdevId %d", 202 vdev_id); 203 } 204 ret = pmo_tgt_send_vdev_sta_ps_param(vdev, 205 pmo_sta_ps_param_spec_wake_interval, 206 psoc_cfg->wow_spec_wake_interval); 207 if (QDF_IS_STATUS_ERROR(ret)) { 208 pmo_err("Failed to Set wow spec wake interval vdevId %d", 209 vdev_id); 210 } 211 212 non_wow_inactivity_time = PMO_PS_DATA_INACTIVITY_TIMEOUT; 213 wow_inactivity_time = psoc_cfg->wow_data_inactivity_timeout; 214 /* 215 * To keep ito repeat count same in wow mode as in non wow mode, 216 * modulating ito repeat count value. 217 */ 218 ito_repeat_count_value = (non_wow_inactivity_time / 219 wow_inactivity_time) * 220 psoc_cfg->ito_repeat_count; 221 if (ito_repeat_count_value) 222 ret = pmo_tgt_send_vdev_sta_ps_param(vdev, 223 pmo_sta_ps_param_ito_repeat_count, 224 psoc_cfg->wow_data_inactivity_timeout); 225 if (QDF_IS_STATUS_ERROR(ret)) { 226 pmo_err("Failed to Set ito repeat count vdevId %d", 227 vdev_id); 228 } 229 230 pmo_exit(); 231 } 232 pmo_configure_vdev_resume_params(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)233 static void pmo_configure_vdev_resume_params( 234 struct wlan_objmgr_psoc *psoc, 235 struct wlan_objmgr_vdev *vdev, 236 struct pmo_vdev_priv_obj *vdev_ctx) 237 { 238 QDF_STATUS ret; 239 uint8_t vdev_id; 240 enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); 241 242 pmo_enter(); 243 244 vdev_id = pmo_vdev_get_id(vdev); 245 if (!PMO_VDEV_IN_STA_MODE(opmode)) 246 return; 247 ret = pmo_tgt_send_vdev_sta_ps_param(vdev, 248 pmo_sta_ps_param_inactivity_time, 249 vdev_ctx->ps_params.ps_ito); 250 if (QDF_IS_STATUS_ERROR(ret)) { 251 pmo_err("Failed to Set inactivity timeout vdevId %d", 252 vdev_id); 253 } 254 ret = pmo_tgt_send_vdev_sta_ps_param(vdev, 255 pmo_sta_ps_param_spec_wake_interval, 256 vdev_ctx->ps_params.spec_wake); 257 if (QDF_IS_STATUS_ERROR(ret)) { 258 pmo_err("Failed to Set wow spec wake interval vdevId %d", 259 vdev_id); 260 } 261 } 262 263 /** 264 * pmo_core_set_vdev_suspend_dtim() - set suspend dtim parameters in fw 265 * @psoc: objmgr psoc handle 266 * @vdev: objmgr vdev handle 267 * @vdev_ctx: pmo vdev priv ctx 268 * 269 * Return: none 270 */ pmo_core_set_vdev_suspend_dtim(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)271 static void pmo_core_set_vdev_suspend_dtim(struct wlan_objmgr_psoc *psoc, 272 struct wlan_objmgr_vdev *vdev, 273 struct pmo_vdev_priv_obj *vdev_ctx) 274 { 275 QDF_STATUS ret; 276 uint8_t vdev_id; 277 enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); 278 uint32_t listen_interval = cfg_default(CFG_LISTEN_INTERVAL); 279 280 vdev_id = pmo_vdev_get_id(vdev); 281 if (PMO_VDEV_IN_STA_MODE(opmode) && 282 pmo_core_get_vdev_dtim_period(vdev) != 0) { 283 /* calculate listen interval */ 284 ret = pmo_core_calculate_listen_interval(vdev, vdev_ctx, 285 &listen_interval); 286 if (ret != QDF_STATUS_SUCCESS) { 287 /* even it fails continue fwr will take default LI */ 288 pmo_debug("Fail to calculate listen interval"); 289 } 290 ret = pmo_tgt_vdev_update_param_req(vdev, 291 pmo_vdev_param_listen_interval, 292 listen_interval); 293 if (QDF_IS_STATUS_ERROR(ret)) { 294 /* even it fails continue fwr will take default LI */ 295 pmo_debug("Failed to Set Listen Interval vdevId %d", 296 vdev_id); 297 } 298 pmo_debug("Set Listen Interval vdevId %d Listen Intv %d", 299 vdev_id, listen_interval); 300 301 pmo_core_vdev_set_restore_dtim(vdev, true); 302 } 303 } 304 305 /* 306 * pmo_is_listen_interval_user_set() - Check if listen interval is configured 307 * by user or not 308 * @vdev_ctx: PMO vdev private object 309 * 310 * Return: true if listen interval is user configured else false 311 */ 312 static inline pmo_is_listen_interval_user_set(struct pmo_vdev_priv_obj * vdev_ctx)313 bool pmo_is_listen_interval_user_set(struct pmo_vdev_priv_obj *vdev_ctx) 314 { 315 bool retval; 316 317 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); 318 retval = vdev_ctx->dyn_modulated_dtim_enabled 319 || vdev_ctx->dyn_listen_interval; 320 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); 321 322 return retval; 323 } 324 325 /** 326 * pmo_core_set_suspend_dtim() - set suspend dtim 327 * @psoc: objmgr psoc handle 328 * 329 * Return: none 330 */ pmo_core_set_suspend_dtim(struct wlan_objmgr_psoc * psoc)331 static void pmo_core_set_suspend_dtim(struct wlan_objmgr_psoc *psoc) 332 { 333 uint8_t vdev_id; 334 struct wlan_objmgr_vdev *vdev; 335 struct pmo_vdev_priv_obj *vdev_ctx; 336 struct pmo_psoc_priv_obj *psoc_ctx; 337 bool li_offload_support = false; 338 339 pmo_psoc_with_ctx(psoc, psoc_ctx) { 340 li_offload_support = psoc_ctx->caps.li_offload; 341 } 342 343 if (li_offload_support) 344 pmo_debug("listen interval offload support is enabled"); 345 346 /* Iterate through VDEV list */ 347 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 348 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 349 WLAN_PMO_ID); 350 if (!vdev) 351 continue; 352 353 vdev_ctx = pmo_vdev_get_priv(vdev); 354 if (!pmo_is_listen_interval_user_set(vdev_ctx) 355 && !li_offload_support) 356 pmo_core_set_vdev_suspend_dtim(psoc, vdev, vdev_ctx); 357 pmo_configure_vdev_suspend_params(psoc, vdev, vdev_ctx); 358 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 359 } 360 } 361 362 /** 363 * pmo_core_update_wow_bus_suspend() - set wow bus suspend flag 364 * @psoc: objmgr psoc handle 365 * @psoc_ctx: pmo psoc priv ctx 366 * @val: true for enable else false 367 * Return: none 368 */ 369 static inline pmo_core_update_wow_bus_suspend(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx,int val)370 void pmo_core_update_wow_bus_suspend(struct wlan_objmgr_psoc *psoc, 371 struct pmo_psoc_priv_obj *psoc_ctx, int val) 372 { 373 qdf_spin_lock_bh(&psoc_ctx->lock); 374 psoc_ctx->wow.is_wow_bus_suspended = val; 375 qdf_spin_unlock_bh(&psoc_ctx->lock); 376 pmo_tgt_psoc_update_wow_bus_suspend_state(psoc, val); 377 } 378 379 /* Define for conciseness */ 380 #define BM_LEN PMO_WOW_MAX_EVENT_BM_LEN 381 #define EV_NLO WOW_NLO_SCAN_COMPLETE_EVENT 382 #define EV_PWR WOW_CHIP_POWER_FAILURE_DETECT_EVENT 383 pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc * psoc)384 void pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc *psoc) 385 { 386 int vdev_id; 387 uint32_t adapter_type; 388 uint32_t enable_mask[BM_LEN]; 389 uint32_t disable_mask[BM_LEN]; 390 struct wlan_objmgr_vdev *vdev; 391 struct pmo_psoc_priv_obj *psoc_ctx; 392 bool enable_configured; 393 bool disable_configured; 394 395 /* Iterate through VDEV list */ 396 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 397 398 enable_configured = false; 399 disable_configured = false; 400 401 qdf_mem_zero(enable_mask, sizeof(uint32_t) * BM_LEN); 402 qdf_mem_zero(disable_mask, sizeof(uint32_t) * BM_LEN); 403 404 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 405 WLAN_PMO_ID); 406 if (!vdev) 407 continue; 408 409 if (ucfg_scan_get_pno_in_progress(vdev)) { 410 if (ucfg_scan_get_pno_match(vdev)) { 411 pmo_set_wow_event_bitmap(EV_NLO, 412 BM_LEN, 413 enable_mask); 414 enable_configured = true; 415 } else { 416 pmo_set_wow_event_bitmap(EV_NLO, 417 BM_LEN, 418 disable_mask); 419 disable_configured = true; 420 } 421 } 422 423 adapter_type = pmo_get_vdev_opmode(vdev); 424 425 psoc_ctx = pmo_psoc_get_priv(psoc); 426 427 if (psoc_ctx->psoc_cfg.auto_power_save_fail_mode == 428 PMO_FW_TO_SEND_WOW_IND_ON_PWR_FAILURE && 429 (adapter_type == QDF_STA_MODE || 430 adapter_type == QDF_P2P_CLIENT_MODE)) { 431 if (psoc_ctx->is_device_in_low_pwr_mode && 432 psoc_ctx->is_device_in_low_pwr_mode(vdev_id)) { 433 pmo_set_wow_event_bitmap(EV_PWR, 434 BM_LEN, 435 enable_mask); 436 enable_configured = true; 437 } 438 } 439 440 if (enable_configured) 441 pmo_tgt_enable_wow_wakeup_event(vdev, enable_mask); 442 if (disable_configured) 443 pmo_tgt_disable_wow_wakeup_event(vdev, disable_mask); 444 445 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 446 } 447 448 } 449 pmo_core_enable_runtime_pm_offloads(struct wlan_objmgr_psoc * psoc)450 static void pmo_core_enable_runtime_pm_offloads(struct wlan_objmgr_psoc *psoc) 451 { 452 uint8_t vdev_id; 453 struct wlan_objmgr_vdev *vdev; 454 455 /* Iterate through VDEV list */ 456 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 457 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 458 WLAN_PMO_ID); 459 if (!vdev) 460 continue; 461 462 pmo_register_action_frame_patterns(vdev, QDF_RUNTIME_SUSPEND); 463 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 464 } 465 } 466 pmo_core_disable_runtime_pm_offloads(struct wlan_objmgr_psoc * psoc)467 static void pmo_core_disable_runtime_pm_offloads(struct wlan_objmgr_psoc *psoc) 468 { 469 uint8_t vdev_id; 470 struct wlan_objmgr_vdev *vdev; 471 472 /* Iterate through VDEV list */ 473 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 474 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 475 WLAN_PMO_ID); 476 if (!vdev) 477 continue; 478 479 pmo_clear_action_frame_patterns(vdev); 480 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 481 } 482 } 483 484 /** 485 * pmo_core_psoc_configure_suspend(): configure suspend req events 486 * @psoc: objmgr psoc 487 * @is_runtime_pm: indicate if it is used by runtime PM 488 * 489 * Responsibility of the caller to take the psoc reference. 490 * 491 * Return: QDF_STATUS_SUCCESS for success or error code 492 */ pmo_core_psoc_configure_suspend(struct wlan_objmgr_psoc * psoc,bool is_runtime_pm)493 static QDF_STATUS pmo_core_psoc_configure_suspend(struct wlan_objmgr_psoc *psoc, 494 bool is_runtime_pm) 495 { 496 struct pmo_psoc_priv_obj *psoc_ctx; 497 struct hif_target_info *tgt_info; 498 struct hif_opaque_softc *hif_ctx; 499 500 psoc_ctx = pmo_psoc_get_priv(psoc); 501 502 if (is_runtime_pm) 503 pmo_core_enable_runtime_pm_offloads(psoc); 504 505 hif_ctx = pmo_core_psoc_get_hif_handle(psoc); 506 if (!hif_ctx) { 507 pmo_err("Invalid hif ctx"); 508 return QDF_STATUS_E_NULL_VALUE; 509 } 510 tgt_info = hif_get_target_info_handle(hif_ctx); 511 512 if ((is_runtime_pm) || 513 (psoc_ctx->psoc_cfg.suspend_mode == PMO_SUSPEND_WOW && 514 ((tgt_info->target_type == TARGET_TYPE_QCA6490) || 515 pmo_core_is_wow_applicable(psoc)))) { 516 pmo_debug("WOW Suspend"); 517 pmo_core_apply_lphb(psoc); 518 /* 519 * Dynamic wake events should not be needed for runtime PM. 520 * Any wake events can be configured by default if they are 521 * really needed for runtime PM. In fact, most of them are 522 * only needed for system suspend. 523 */ 524 if (!is_runtime_pm) 525 pmo_core_configure_dynamic_wake_events(psoc); 526 pmo_core_update_wow_enable(psoc_ctx, true); 527 pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false); 528 } else { 529 pmo_debug("Non WOW PDEV Suspend"); 530 pmo_core_update_wow_enable(psoc_ctx, false); 531 } 532 533 /* 534 * For runtime PM, since system is awake, DTIM related commands 535 * do not have to be sent with WOW sequence. They can be sent 536 * through other paths which will just trigger a runtime resume. 537 */ 538 if (!is_runtime_pm) 539 pmo_core_set_suspend_dtim(psoc); 540 541 /* 542 * To handle race between hif_pci_suspend and unpause/pause tx handler. 543 * This happens when host sending WMI_WOW_ENABLE_CMDID to FW and receive 544 * WMI_TX_PAUSE_EVENT with ACTON_UNPAUSE almost at same time. 545 */ 546 pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, true); 547 548 pmo_exit(); 549 550 return QDF_STATUS_SUCCESS; 551 } 552 pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type)553 QDF_STATUS pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc, 554 enum qdf_suspend_type type) 555 { 556 QDF_STATUS status; 557 558 pmo_enter(); 559 560 status = pmo_psoc_get_ref(psoc); 561 if (status != QDF_STATUS_SUCCESS) { 562 pmo_err("pmo cannot get the reference out of psoc"); 563 goto out; 564 } 565 566 status = pmo_core_psoc_configure_suspend(psoc, false); 567 if (status != QDF_STATUS_SUCCESS) 568 pmo_err("Failed to configure suspend"); 569 570 pmo_psoc_put_ref(psoc); 571 out: 572 return status; 573 } 574 575 /** 576 * pmo_core_set_vdev_resume_dtim() - set resume dtim parameters in fw 577 * @psoc: objmgr psoc handle 578 * @vdev: objmgr vdev handle 579 * @vdev_ctx: pmo vdev priv ctx 580 * 581 * Return: none 582 */ pmo_core_set_vdev_resume_dtim(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,struct pmo_vdev_priv_obj * vdev_ctx)583 static void pmo_core_set_vdev_resume_dtim(struct wlan_objmgr_psoc *psoc, 584 struct wlan_objmgr_vdev *vdev, 585 struct pmo_vdev_priv_obj *vdev_ctx) 586 { 587 QDF_STATUS ret; 588 uint8_t vdev_id; 589 enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); 590 int32_t cfg_data_val = 0; 591 592 vdev_id = pmo_vdev_get_id(vdev); 593 if ((PMO_VDEV_IN_STA_MODE(opmode)) && 594 (pmo_core_vdev_get_restore_dtim(vdev))) { 595 /* Get Listen Interval */ 596 if (QDF_IS_STATUS_ERROR(ucfg_mlme_get_listen_interval(psoc, 597 &cfg_data_val))) { 598 pmo_err("Failed to get value for listen interval"); 599 cfg_data_val = cfg_default(CFG_LISTEN_INTERVAL); 600 } 601 602 ret = pmo_tgt_vdev_update_param_req(vdev, 603 pmo_vdev_param_listen_interval, cfg_data_val); 604 if (QDF_IS_STATUS_ERROR(ret)) { 605 /* Even it fails continue Fw will take default LI */ 606 pmo_err("Failed to Set Listen Interval vdevId %d", 607 vdev_id); 608 } 609 pmo_debug("Set Listen Interval vdevId %d Listen Intv %d", 610 vdev_id, cfg_data_val); 611 pmo_core_vdev_set_restore_dtim(vdev, false); 612 } 613 } 614 615 /** 616 * pmo_core_set_resume_dtim() - set resume time dtim 617 * @psoc: objmgr psoc handle 618 * 619 * Return: none 620 */ pmo_core_set_resume_dtim(struct wlan_objmgr_psoc * psoc)621 static void pmo_core_set_resume_dtim(struct wlan_objmgr_psoc *psoc) 622 { 623 uint8_t vdev_id; 624 struct wlan_objmgr_vdev *vdev; 625 struct pmo_vdev_priv_obj *vdev_ctx; 626 struct pmo_psoc_priv_obj *psoc_ctx; 627 bool li_offload_support = false; 628 629 pmo_psoc_with_ctx(psoc, psoc_ctx) { 630 li_offload_support = psoc_ctx->caps.li_offload; 631 } 632 633 if (li_offload_support) 634 pmo_debug("listen interval offload support is enabled"); 635 636 /* Iterate through VDEV list */ 637 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 638 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 639 WLAN_PMO_ID); 640 if (!vdev) 641 continue; 642 643 vdev_ctx = pmo_vdev_get_priv(vdev); 644 if (!pmo_is_listen_interval_user_set(vdev_ctx) 645 && !li_offload_support) 646 pmo_core_set_vdev_resume_dtim(psoc, vdev, vdev_ctx); 647 pmo_configure_vdev_resume_params(psoc, vdev, vdev_ctx); 648 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 649 } 650 } 651 652 #if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) 653 /** 654 * pmo_unpause_all_vdev() - unpause all vdev 655 * @psoc: objmgr psoc handle 656 * @psoc_ctx: pmo psoc contaxt 657 * 658 * unpause all vdev aftter resume/coming out of wow mode 659 * 660 * Return: none 661 */ pmo_unpause_all_vdev(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)662 static void pmo_unpause_all_vdev(struct wlan_objmgr_psoc *psoc, 663 struct pmo_psoc_priv_obj *psoc_ctx) 664 { 665 uint8_t vdev_id; 666 667 /* Iterate through VDEV list */ 668 for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { 669 /* When host resumes, by default unpause all active vdev */ 670 if (pmo_core_vdev_get_pause_bitmap(psoc_ctx, vdev_id)) { 671 cdp_fc_vdev_unpause(pmo_core_psoc_get_dp_handle(psoc), 672 vdev_id, 673 0xffffffff, 0); 674 if (psoc_ctx->pause_bitmap_notifier) 675 psoc_ctx->pause_bitmap_notifier(vdev_id, 0); 676 } 677 } 678 } 679 #else pmo_unpause_all_vdev(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)680 static inline void pmo_unpause_all_vdev(struct wlan_objmgr_psoc *psoc, 681 struct pmo_psoc_priv_obj *psoc_ctx) 682 { 683 } 684 #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ 685 686 /** 687 * pmo_core_psoc_configure_resume(): configure events after bus resume 688 * @psoc: objmgr psoc 689 * @is_runtime_pm: indicate if it is used by runtime PM 690 * 691 * Responsibility of the caller to take the psoc reference. 692 * 693 * Return: QDF_STATUS_SUCCESS for success or error code 694 */ pmo_core_psoc_configure_resume(struct wlan_objmgr_psoc * psoc,bool is_runtime_pm)695 static QDF_STATUS pmo_core_psoc_configure_resume(struct wlan_objmgr_psoc *psoc, 696 bool is_runtime_pm) 697 { 698 struct pmo_psoc_priv_obj *psoc_ctx; 699 700 psoc_ctx = pmo_psoc_get_priv(psoc); 701 if (is_runtime_pm) 702 pmo_core_disable_runtime_pm_offloads(psoc); 703 704 /* 705 * For runtime PM, since system is awake, DTIM related commands 706 * do not have to be sent with WOW sequence. They can be sent 707 * through other paths which will just trigger a runtime resume. 708 */ 709 if (!is_runtime_pm) 710 pmo_core_set_resume_dtim(psoc); 711 pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false); 712 pmo_unpause_all_vdev(psoc, psoc_ctx); 713 714 return QDF_STATUS_SUCCESS; 715 } 716 pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type)717 QDF_STATUS pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc, 718 enum qdf_suspend_type type) 719 { 720 QDF_STATUS status = QDF_STATUS_SUCCESS; 721 722 pmo_enter(); 723 724 status = pmo_psoc_get_ref(psoc); 725 if (status != QDF_STATUS_SUCCESS) { 726 pmo_err("pmo cannot get the reference out of psoc"); 727 goto out; 728 } 729 730 status = pmo_core_psoc_configure_resume(psoc, false); 731 if (status != QDF_STATUS_SUCCESS) 732 pmo_err("Failed to configure resume"); 733 734 pmo_psoc_put_ref(psoc); 735 out: 736 pmo_exit(); 737 738 return status; 739 } 740 741 /** 742 * pmo_core_enable_wow_in_fw() - enable wow in fw 743 * @psoc: objmgr psoc handle 744 * @psoc_ctx: pmo psoc private ctx 745 * @wow_params: collection of wow enable override parameters 746 * @type: type of wow suspend 747 * 748 * Return: QDF status 749 */ 750 static QDF_STATUS pmo_core_enable_wow_in_fw(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx,struct pmo_wow_enable_params * wow_params,enum qdf_suspend_type type)751 pmo_core_enable_wow_in_fw(struct wlan_objmgr_psoc *psoc, 752 struct pmo_psoc_priv_obj *psoc_ctx, 753 struct pmo_wow_enable_params *wow_params, 754 enum qdf_suspend_type type) 755 { 756 int host_credits, wmi_pending_cmds; 757 struct pmo_wow_cmd_params param = {0}; 758 struct pmo_psoc_cfg *psoc_cfg = &psoc_ctx->psoc_cfg; 759 QDF_STATUS status; 760 void *hif_ctx; 761 uint16_t reason_code; 762 763 hif_ctx = pmo_core_psoc_get_hif_handle(psoc); 764 qdf_event_reset(&psoc_ctx->wow.target_suspend); 765 pmo_core_set_wow_nack(psoc_ctx, false, 0); 766 host_credits = pmo_tgt_psoc_get_host_credits(psoc); 767 wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc); 768 pmo_debug("Credits:%d; Pending_Cmds: %d", 769 host_credits, wmi_pending_cmds); 770 771 param.enable = true; 772 if (wow_params->is_unit_test) 773 param.flags = WMI_WOW_FLAG_UNIT_TEST_ENABLE; 774 775 switch (wow_params->interface_pause) { 776 default: 777 pmo_err("Invalid interface pause setting: %d", 778 wow_params->interface_pause); 779 /* intentional to default */ 780 fallthrough; 781 case PMO_WOW_INTERFACE_PAUSE_DEFAULT: 782 param.can_suspend_link = 783 htc_can_suspend_link( 784 pmo_core_psoc_get_htc_handle(psoc)); 785 break; 786 case PMO_WOW_INTERFACE_PAUSE_ENABLE: 787 param.can_suspend_link = true; 788 break; 789 case PMO_WOW_INTERFACE_PAUSE_DISABLE: 790 param.can_suspend_link = false; 791 break; 792 } 793 794 switch (wow_params->resume_trigger) { 795 default: 796 pmo_err("Invalid resume trigger setting: %d", 797 wow_params->resume_trigger); 798 fallthrough; 799 case PMO_WOW_RESUME_TRIGGER_DEFAULT: 800 case PMO_WOW_RESUME_TRIGGER_GPIO: 801 /* 802 * GPIO is currently implicit. This means you can't actually 803 * force GPIO if a platform's default wake trigger is HTC wakeup 804 */ 805 break; 806 case PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP: 807 param.flags |= WMI_WOW_FLAG_DO_HTC_WAKEUP; 808 break; 809 } 810 811 if (psoc_ctx->psoc_cfg.d0_wow_supported && 812 !psoc_ctx->caps.unified_wow && 813 !param.can_suspend_link) { 814 psoc_ctx->wow.wow_state = pmo_wow_state_legacy_d0; 815 } else if (param.can_suspend_link) { 816 psoc_ctx->wow.wow_state = pmo_wow_state_unified_d3; 817 } else { 818 psoc_ctx->wow.wow_state = pmo_wow_state_unified_d0; 819 } 820 821 if (htc_can_suspend_link(pmo_core_psoc_get_htc_handle(psoc))) { 822 if (qdf_is_drv_connected()) { 823 pmo_info("drv wow is enabled"); 824 param.flags |= WMI_WOW_FLAG_ENABLE_DRV_PCIE_L1SS_SLEEP; 825 } else { 826 pmo_debug("non-drv wow is enabled"); 827 } 828 } else { 829 pmo_info("Prevent link down, non-drv wow is enabled"); 830 if (hif_ctx) { 831 hif_rtpm_print_prevent_list(); 832 htc_log_link_user_votes(); 833 } 834 } 835 if (wow_params->is_unit_test) { 836 pmo_info("Unit test WoW, force DRV mode"); 837 param.flags |= WMI_WOW_FLAG_ENABLE_DRV_PCIE_L1SS_SLEEP; 838 } 839 if (type == QDF_SYSTEM_SUSPEND) { 840 pmo_info("system suspend wow"); 841 param.flags |= WMI_WOW_FLAG_SYSTEM_SUSPEND_WOW; 842 } else if (type == QDF_UNIT_TEST_WOW_SUSPEND) { 843 pmo_info("unit test wow suspend"); 844 } else { 845 pmo_debug("RTPM wow"); 846 } 847 848 if (psoc_cfg->is_mod_dtim_on_sys_suspend_enabled) { 849 pmo_debug("mod DTIM enabled"); 850 param.flags |= WMI_WOW_FLAG_MOD_DTIM_ON_SYS_SUSPEND; 851 } 852 853 if (psoc_cfg->sta_forced_dtim) { 854 pmo_debug("forced DTIM enabled"); 855 param.flags |= WMI_WOW_FLAG_FORCED_DTIM_ON_SYS_SUSPEND; 856 } 857 status = pmo_tgt_psoc_send_wow_enable_req(psoc, ¶m); 858 if (status != QDF_STATUS_SUCCESS) { 859 pmo_err("Failed to enable wow in fw"); 860 goto out; 861 } 862 863 pmo_tgt_update_target_suspend_flag(psoc, true); 864 865 status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_suspend, 866 PMO_TARGET_SUSPEND_TIMEOUT); 867 if (QDF_IS_STATUS_ERROR(status)) { 868 if (hif_ctx) { 869 hif_display_ctrl_traffic_pipes_state(hif_ctx); 870 hif_display_latest_desc_hist(hif_ctx); 871 } 872 pmo_err("Failed to receive WoW Enable Ack from FW"); 873 pmo_err("Credits:%d; Pending_Cmds: %d", 874 pmo_tgt_psoc_get_host_credits(psoc), 875 pmo_tgt_psoc_get_pending_cmnds(psoc)); 876 if (!psoc_ctx->wow.target_suspend.force_set) { 877 pmo_tgt_psoc_set_wow_enable_ack_failed(psoc); 878 qdf_trigger_self_recovery(psoc, QDF_SUSPEND_TIMEOUT); 879 } 880 pmo_tgt_update_target_suspend_flag(psoc, false); 881 goto out; 882 } 883 884 if (pmo_core_get_wow_nack(psoc_ctx)) { 885 reason_code = pmo_core_get_wow_reason_code(psoc_ctx); 886 pmo_err("FW not ready to WOW reason code: %d", reason_code); 887 pmo_tgt_update_target_suspend_flag(psoc, false); 888 status = QDF_STATUS_E_AGAIN; 889 goto out; 890 } 891 892 pmo_tgt_update_target_suspend_acked_flag(psoc, true); 893 894 host_credits = pmo_tgt_psoc_get_host_credits(psoc); 895 wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc); 896 897 if (host_credits < PMO_WOW_REQUIRED_CREDITS) { 898 pmo_err("No Credits after HTC ACK:%d, pending_cmds:%d," 899 "cannot resume back", host_credits, wmi_pending_cmds); 900 htc_dump_counter_info(pmo_core_psoc_get_htc_handle(psoc)); 901 qdf_trigger_self_recovery(psoc, QDF_SUSPEND_NO_CREDIT); 902 } 903 pmo_debug("WOW enabled successfully in fw: credits:%d pending_cmds: %d", 904 host_credits, wmi_pending_cmds); 905 906 hif_latency_detect_timer_stop(pmo_core_psoc_get_hif_handle(psoc)); 907 908 if (hif_rtpm_get_autosuspend_delay() == WOW_LARGE_RX_RTPM_DELAY) 909 hif_rtpm_restore_autosuspend_delay(); 910 911 pmo_core_update_wow_enable_cmd_sent(psoc_ctx, true); 912 913 out: 914 return status; 915 } 916 pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc * psoc,int disable_target_intr)917 QDF_STATUS pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc *psoc, 918 int disable_target_intr) 919 { 920 QDF_STATUS status; 921 struct pmo_suspend_params param; 922 struct pmo_psoc_priv_obj *psoc_ctx; 923 void *dp_soc = pmo_core_psoc_get_dp_handle(psoc); 924 925 pmo_enter(); 926 927 psoc_ctx = pmo_psoc_get_priv(psoc); 928 929 cdp_process_target_suspend_req(dp_soc, OL_TXRX_PDEV_ID); 930 qdf_event_reset(&psoc_ctx->wow.target_suspend); 931 param.disable_target_intr = disable_target_intr; 932 status = pmo_tgt_psoc_send_supend_req(psoc, ¶m); 933 if (status != QDF_STATUS_SUCCESS) 934 goto out; 935 936 pmo_tgt_update_target_suspend_flag(psoc, true); 937 938 status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_suspend, 939 PMO_TARGET_SUSPEND_TIMEOUT); 940 if (QDF_IS_STATUS_ERROR(status)) { 941 pmo_err("Failed to get ACK from firmware for pdev suspend"); 942 pmo_tgt_update_target_suspend_flag(psoc, false); 943 if (!psoc_ctx->wow.target_suspend.force_set) 944 qdf_trigger_self_recovery(psoc, QDF_SUSPEND_TIMEOUT); 945 } else { 946 pmo_tgt_update_target_suspend_acked_flag(psoc, true); 947 } 948 949 out: 950 pmo_exit(); 951 952 return status; 953 } 954 pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type,struct pmo_wow_enable_params * wow_params)955 QDF_STATUS pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc, 956 enum qdf_suspend_type type, 957 struct pmo_wow_enable_params *wow_params) 958 { 959 struct pmo_psoc_priv_obj *psoc_ctx; 960 QDF_STATUS status; 961 bool wow_mode_selected = false; 962 qdf_time_t begin, end; 963 964 if (!psoc) { 965 pmo_err("psoc is NULL"); 966 status = QDF_STATUS_E_NULL_VALUE; 967 goto out; 968 } 969 970 if (!wow_params) { 971 pmo_err("wow_params is NULL"); 972 status = QDF_STATUS_E_NULL_VALUE; 973 goto out; 974 } 975 976 status = pmo_psoc_get_ref(psoc); 977 if (status != QDF_STATUS_SUCCESS) { 978 pmo_err("pmo cannot get the reference out of psoc"); 979 goto out; 980 } 981 982 psoc_ctx = pmo_psoc_get_priv(psoc); 983 984 wow_mode_selected = pmo_core_is_wow_enabled(psoc_ctx); 985 986 begin = qdf_get_log_timestamp_usecs(); 987 if (wow_mode_selected) 988 status = pmo_core_enable_wow_in_fw(psoc, psoc_ctx, 989 wow_params, 990 type); 991 else 992 status = pmo_core_psoc_suspend_target(psoc, 0); 993 end = qdf_get_log_timestamp_usecs(); 994 pmo_debug("fw took total time %lu microseconds to enable wow", 995 end - begin); 996 997 pmo_psoc_put_ref(psoc); 998 out: 999 return status; 1000 } 1001 pmo_core_txrx_suspend(struct wlan_objmgr_psoc * psoc)1002 QDF_STATUS pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc) 1003 { 1004 struct pmo_psoc_priv_obj *pmo_ctx; 1005 QDF_STATUS status; 1006 void *hif_ctx; 1007 void *dp_soc; 1008 int ret; 1009 1010 status = pmo_psoc_get_ref(psoc); 1011 if (QDF_IS_STATUS_ERROR(status)) { 1012 pmo_err("pmo cannot get the reference out of psoc"); 1013 return status; 1014 } 1015 1016 pmo_ctx = pmo_psoc_get_priv(psoc); 1017 if (pmo_core_get_wow_state(pmo_ctx) != pmo_wow_state_unified_d3) 1018 goto out; 1019 1020 hif_ctx = pmo_core_psoc_get_hif_handle(psoc); 1021 dp_soc = pmo_core_psoc_get_dp_handle(psoc); 1022 if (!hif_ctx || !dp_soc) { 1023 pmo_err("Invalid ctx hif: %pK, dp: %pK", hif_ctx, dp_soc); 1024 status = QDF_STATUS_E_INVAL; 1025 goto out; 1026 } 1027 1028 ret = hif_disable_grp_irqs(hif_ctx); 1029 if (ret && ret != -EOPNOTSUPP) { 1030 pmo_err("Prevent suspend, failed to disable grp irqs: %d", ret); 1031 status = qdf_status_from_os_return(ret); 1032 goto out; 1033 } 1034 1035 if (ret == -EOPNOTSUPP) { 1036 /* For chips, which not support IRQ disable, 1037 * drain will not be called, display and check 1038 * rings HP/TP once again 1039 */ 1040 if (!cdp_display_txrx_hw_info(dp_soc)) { 1041 pmo_err("Prevent suspend, ring not empty"); 1042 status = QDF_STATUS_E_AGAIN; 1043 } 1044 1045 goto out; 1046 } 1047 1048 status = cdp_drain_txrx(dp_soc, 0); 1049 if (QDF_IS_STATUS_ERROR(status)) { 1050 pmo_err("Prevent suspend unable to drain txrx status:%u", 1051 status); 1052 ret = hif_enable_grp_irqs(hif_ctx); 1053 if (ret && ret != -EOPNOTSUPP) { 1054 pmo_err("Failed to enable grp irqs: %d", ret); 1055 qdf_trigger_self_recovery(psoc, QDF_ENABLE_IRQ_FAILURE); 1056 } 1057 goto out; 1058 } 1059 1060 pmo_ctx->wow.txrx_suspended = true; 1061 out: 1062 pmo_psoc_put_ref(psoc); 1063 return status; 1064 } 1065 pmo_core_txrx_resume(struct wlan_objmgr_psoc * psoc)1066 QDF_STATUS pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc) 1067 { 1068 struct pmo_psoc_priv_obj *pmo_ctx; 1069 QDF_STATUS status; 1070 void *hif_ctx; 1071 int ret; 1072 1073 status = pmo_psoc_get_ref(psoc); 1074 if (QDF_IS_STATUS_ERROR(status)) { 1075 pmo_err("pmo cannot get the reference out of psoc"); 1076 return status; 1077 } 1078 1079 pmo_ctx = pmo_psoc_get_priv(psoc); 1080 if (!pmo_ctx->wow.txrx_suspended) 1081 goto out; 1082 1083 hif_ctx = pmo_core_psoc_get_hif_handle(psoc); 1084 if (!hif_ctx) { 1085 pmo_err("Invalid hif ctx"); 1086 status = QDF_STATUS_E_INVAL; 1087 goto out; 1088 } 1089 1090 ret = hif_enable_grp_irqs(hif_ctx); 1091 if (ret && ret != -EOPNOTSUPP) { 1092 pmo_err("Failed to enable grp irqs: %d", ret); 1093 status = qdf_status_from_os_return(ret); 1094 goto out; 1095 } 1096 1097 pmo_ctx->wow.txrx_suspended = false; 1098 out: 1099 pmo_psoc_put_ref(psoc); 1100 return status; 1101 } 1102 1103 #ifdef FEATURE_RUNTIME_PM 1104 #define PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(__condition) ({ \ 1105 typeof(__condition) condition = __condition; \ 1106 if (condition && !qdf_is_fw_down()) \ 1107 QDF_BUG(0); \ 1108 }) 1109 pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc * psoc,pmo_pld_auto_suspend_cb pld_cb)1110 QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, 1111 pmo_pld_auto_suspend_cb pld_cb) 1112 { 1113 void *hif_ctx; 1114 void *dp_soc; 1115 uint8_t pdev_id; 1116 void *htc_ctx; 1117 QDF_STATUS status; 1118 int ret; 1119 struct pmo_wow_enable_params wow_params = {0}; 1120 struct pmo_psoc_priv_obj *psoc_ctx; 1121 qdf_time_t begin, end; 1122 int pending; 1123 1124 pmo_enter(); 1125 1126 if (!psoc) { 1127 pmo_err("psoc is NULL"); 1128 status = QDF_STATUS_E_INVAL; 1129 goto out; 1130 } 1131 1132 status = pmo_psoc_get_ref(psoc); 1133 if (status != QDF_STATUS_SUCCESS) { 1134 pmo_err("pmo cannot get the reference out of psoc"); 1135 goto out; 1136 } 1137 1138 hif_ctx = pmo_core_psoc_get_hif_handle(psoc); 1139 dp_soc = pmo_core_psoc_get_dp_handle(psoc); 1140 pdev_id = pmo_core_psoc_get_txrx_handle(psoc); 1141 htc_ctx = pmo_core_psoc_get_htc_handle(psoc); 1142 if (!hif_ctx || !dp_soc || !htc_ctx || 1143 pdev_id == OL_TXRX_INVALID_PDEV_ID) { 1144 pmo_err("Invalid hif: %pK, dp: %pK, pdev_id: %d, htc: %pK", 1145 hif_ctx, dp_soc, pdev_id, htc_ctx); 1146 status = QDF_STATUS_E_INVAL; 1147 goto dec_psoc_ref; 1148 } 1149 1150 wow_params.interface_pause = PMO_WOW_INTERFACE_PAUSE_ENABLE; 1151 wow_params.resume_trigger = PMO_WOW_RESUME_TRIGGER_GPIO; 1152 1153 ret = hif_pre_runtime_suspend(hif_ctx); 1154 if (ret) { 1155 status = qdf_status_from_os_return(ret); 1156 goto runtime_failure; 1157 } 1158 1159 status = wlan_dp_runtime_suspend(dp_soc, pdev_id); 1160 if (status != QDF_STATUS_SUCCESS) 1161 goto runtime_failure; 1162 1163 ret = htc_runtime_suspend(htc_ctx); 1164 if (ret) { 1165 status = qdf_status_from_os_return(ret); 1166 goto dp_runtime_resume; 1167 } 1168 1169 status = pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, true); 1170 if (status != QDF_STATUS_SUCCESS) 1171 goto resume_htc; 1172 1173 status = pmo_core_psoc_configure_suspend(psoc, true); 1174 if (status != QDF_STATUS_SUCCESS) 1175 goto resume_htc; 1176 1177 status = pmo_core_psoc_bus_suspend_req(psoc, QDF_RUNTIME_SUSPEND, 1178 &wow_params); 1179 if (status != QDF_STATUS_SUCCESS) 1180 goto pmo_resume_configure; 1181 1182 ret = hif_runtime_suspend(hif_ctx); 1183 if (ret) { 1184 status = qdf_status_from_os_return(ret); 1185 goto pmo_bus_resume; 1186 } 1187 1188 status = pmo_core_txrx_suspend(psoc); 1189 if (QDF_IS_STATUS_ERROR(status)) 1190 goto resume_hif; 1191 1192 pending = cdp_rx_get_pending(cds_get_context(QDF_MODULE_ID_SOC)); 1193 if (pending) { 1194 pmo_debug("Prevent suspend, RX frame pending %d", pending); 1195 status = QDF_STATUS_E_BUSY; 1196 goto resume_txrx; 1197 } 1198 1199 if (pld_cb) { 1200 begin = qdf_get_log_timestamp_usecs(); 1201 ret = pld_cb(); 1202 end = qdf_get_log_timestamp_usecs(); 1203 pmo_debug("runtime pci bus suspend took total time %lu microseconds", 1204 end - begin); 1205 1206 if (ret) { 1207 status = qdf_status_from_os_return(ret); 1208 goto resume_txrx; 1209 } 1210 } 1211 1212 if (hif_pm_get_wake_irq_type(hif_ctx) == HIF_PM_CE_WAKE) { 1213 /* 1214 * In moselle, there is no separate interrupt for wake_irq, 1215 * shares CE interrupt, there is a chance of wow wakeup 1216 * while suspend is in-progress, so handling such scenario 1217 */ 1218 hif_rtpm_suspend_lock(); 1219 psoc_ctx = pmo_psoc_get_priv(psoc); 1220 if (pmo_core_get_wow_initial_wake_up(psoc_ctx)) { 1221 hif_rtpm_suspend_unlock(); 1222 pmo_err("Target wake up received before suspend completion"); 1223 status = QDF_STATUS_E_BUSY; 1224 goto resume_txrx; 1225 } 1226 hif_process_runtime_suspend_success(); 1227 hif_rtpm_suspend_unlock(); 1228 } else { 1229 hif_process_runtime_suspend_success(); 1230 } 1231 1232 if (hif_try_prevent_ep_vote_access(hif_ctx)) { 1233 pmo_debug("Prevent suspend, ep work pending"); 1234 status = QDF_STATUS_E_BUSY; 1235 goto resume_txrx; 1236 } 1237 1238 goto dec_psoc_ref; 1239 1240 resume_txrx: 1241 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != 1242 pmo_core_txrx_resume(psoc)); 1243 1244 resume_hif: 1245 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(hif_runtime_resume(hif_ctx)); 1246 1247 pmo_bus_resume: 1248 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != 1249 pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND)); 1250 1251 pmo_resume_configure: 1252 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != 1253 pmo_core_psoc_configure_resume(psoc, true)); 1254 1255 resume_htc: 1256 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != 1257 pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false)); 1258 1259 dp_runtime_resume: 1260 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != 1261 wlan_dp_runtime_resume(dp_soc, pdev_id)); 1262 1263 runtime_failure: 1264 hif_process_runtime_suspend_failure(); 1265 1266 /* always make sure HTC queue kicker is at the end, so if any 1267 * cmd is pending during suspending, it can re-trigger if suspend 1268 * failure. 1269 */ 1270 PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(htc_runtime_resume(htc_ctx)); 1271 1272 dec_psoc_ref: 1273 pmo_psoc_put_ref(psoc); 1274 1275 out: 1276 pmo_exit(); 1277 1278 return status; 1279 } 1280 pmo_core_psoc_bus_runtime_resume(struct wlan_objmgr_psoc * psoc,pmo_pld_auto_resume_cb pld_cb)1281 QDF_STATUS pmo_core_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc, 1282 pmo_pld_auto_resume_cb pld_cb) 1283 { 1284 int ret; 1285 void *hif_ctx; 1286 void *dp_soc; 1287 uint8_t pdev_id; 1288 void *htc_ctx; 1289 QDF_STATUS status; 1290 qdf_time_t begin, end; 1291 1292 pmo_enter(); 1293 1294 if (!psoc) { 1295 pmo_err("psoc is NULL"); 1296 status = QDF_STATUS_E_INVAL; 1297 goto out; 1298 } 1299 1300 status = pmo_psoc_get_ref(psoc); 1301 if (status != QDF_STATUS_SUCCESS) { 1302 pmo_err("pmo cannot get the reference out of psoc"); 1303 goto out; 1304 } 1305 1306 hif_ctx = pmo_core_psoc_get_hif_handle(psoc); 1307 dp_soc = pmo_core_psoc_get_dp_handle(psoc); 1308 pdev_id = pmo_core_psoc_get_txrx_handle(psoc); 1309 htc_ctx = pmo_core_psoc_get_htc_handle(psoc); 1310 if (!hif_ctx || !dp_soc || !htc_ctx || 1311 pdev_id == OL_TXRX_INVALID_PDEV_ID) { 1312 pmo_err("Invalid hif: %pK, dp: %pK, pdev_id: %d, htc: %pK", 1313 hif_ctx, dp_soc, pdev_id, htc_ctx); 1314 status = QDF_STATUS_E_INVAL; 1315 goto dec_psoc_ref; 1316 } 1317 1318 hif_pre_runtime_resume(); 1319 if (pld_cb) { 1320 begin = qdf_get_log_timestamp_usecs(); 1321 ret = pld_cb(); 1322 end = qdf_get_log_timestamp_usecs(); 1323 pmo_debug("pci bus resume took total time %lu microseconds", 1324 end - begin); 1325 if (ret) { 1326 status = QDF_STATUS_E_FAILURE; 1327 goto fail; 1328 } 1329 } 1330 1331 if (hif_runtime_resume(hif_ctx)) { 1332 status = QDF_STATUS_E_FAILURE; 1333 goto fail; 1334 } 1335 1336 status = pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND); 1337 if (status != QDF_STATUS_SUCCESS) 1338 goto fail; 1339 1340 status = pmo_core_txrx_resume(psoc); 1341 if (QDF_IS_STATUS_ERROR(status)) 1342 goto fail; 1343 1344 hif_process_runtime_resume_linkup(); 1345 1346 status = pmo_core_psoc_configure_resume(psoc, true); 1347 if (status != QDF_STATUS_SUCCESS) 1348 goto fail; 1349 1350 status = pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false); 1351 if (status != QDF_STATUS_SUCCESS) 1352 goto fail; 1353 1354 hif_process_runtime_resume_success(); 1355 1356 if (htc_runtime_resume(htc_ctx)) { 1357 status = QDF_STATUS_E_FAILURE; 1358 goto fail; 1359 } 1360 1361 status = wlan_dp_runtime_resume(dp_soc, pdev_id); 1362 if (status != QDF_STATUS_SUCCESS) 1363 goto fail; 1364 1365 fail: 1366 if (status != QDF_STATUS_SUCCESS) 1367 qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT); 1368 1369 dec_psoc_ref: 1370 pmo_psoc_put_ref(psoc); 1371 1372 out: 1373 return status; 1374 } 1375 #endif 1376 1377 /** 1378 * pmo_core_psoc_send_host_wakeup_ind_to_fw() - send wakeup ind to fw 1379 * @psoc: objmgr psoc handle 1380 * @psoc_ctx: pmo psoc private context 1381 * 1382 * Sends host wakeup indication to FW. On receiving this indication, 1383 * FW will come out of WOW. 1384 * 1385 * Return: QDF status 1386 */ 1387 static pmo_core_psoc_send_host_wakeup_ind_to_fw(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)1388 QDF_STATUS pmo_core_psoc_send_host_wakeup_ind_to_fw( 1389 struct wlan_objmgr_psoc *psoc, 1390 struct pmo_psoc_priv_obj *psoc_ctx) 1391 { 1392 QDF_STATUS status = QDF_STATUS_SUCCESS; 1393 void *hif_ctx; 1394 1395 hif_ctx = pmo_core_psoc_get_hif_handle(psoc); 1396 1397 if (!hif_ctx) { 1398 pmo_err("hif_ctx is NULL"); 1399 status = QDF_STATUS_E_INVAL; 1400 goto out; 1401 } 1402 1403 hif_set_ep_intermediate_vote_access(hif_ctx); 1404 1405 qdf_event_reset(&psoc_ctx->wow.target_resume); 1406 1407 status = pmo_tgt_psoc_send_host_wakeup_ind(psoc); 1408 if (status) { 1409 hif_set_ep_vote_access(hif_ctx, 1410 HIF_EP_VOTE_NONDP_ACCESS, 1411 HIF_EP_VOTE_ACCESS_DISABLE); 1412 status = QDF_STATUS_E_FAILURE; 1413 goto out; 1414 } 1415 pmo_info("Host wakeup indication sent to fw"); 1416 1417 status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_resume, 1418 PMO_RESUME_TIMEOUT); 1419 if (status != QDF_STATUS_SUCCESS) { 1420 pmo_err("Timeout waiting for resume event from FW"); 1421 pmo_err("Pending commands %d credits %d", 1422 pmo_tgt_psoc_get_pending_cmnds(psoc), 1423 pmo_tgt_psoc_get_host_credits(psoc)); 1424 1425 if (!psoc_ctx->wow.target_resume.force_set) 1426 qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT); 1427 } else { 1428 pmo_debug("Host wakeup received"); 1429 pmo_tgt_update_target_suspend_flag(psoc, false); 1430 pmo_tgt_update_target_suspend_acked_flag(psoc, false); 1431 hif_set_ep_vote_access(hif_ctx, 1432 HIF_EP_VOTE_NONDP_ACCESS, 1433 HIF_EP_VOTE_ACCESS_ENABLE); 1434 hif_set_ep_vote_access(hif_ctx, 1435 HIF_EP_VOTE_DP_ACCESS, 1436 HIF_EP_VOTE_ACCESS_ENABLE); 1437 } 1438 out: 1439 return status; 1440 } 1441 1442 /** 1443 * pmo_core_psoc_disable_wow_in_fw() - Disable wow in bus resume context. 1444 * @psoc: objmgr psoc handle 1445 * @psoc_ctx: pmo psoc private context 1446 * 1447 * Return: QDF_STATUS_SUCCESS for success or error code 1448 */ 1449 static pmo_core_psoc_disable_wow_in_fw(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)1450 QDF_STATUS pmo_core_psoc_disable_wow_in_fw(struct wlan_objmgr_psoc *psoc, 1451 struct pmo_psoc_priv_obj *psoc_ctx) 1452 { 1453 QDF_STATUS ret; 1454 1455 ret = pmo_core_psoc_send_host_wakeup_ind_to_fw(psoc, psoc_ctx); 1456 if (ret != QDF_STATUS_SUCCESS) 1457 goto out; 1458 1459 pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false); 1460 1461 /* To allow the tx pause/unpause events */ 1462 pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false); 1463 /* Unpause the vdev as we are resuming */ 1464 pmo_unpause_all_vdev(psoc, psoc_ctx); 1465 out: 1466 return ret; 1467 } 1468 1469 /** 1470 * pmo_core_psoc_resume_target() - resume target 1471 * @psoc: objmgr psoc handle 1472 * @psoc_ctx: pmo psoc private context 1473 * 1474 * Return: QDF_STATUS_SUCCESS for success or error code 1475 */ 1476 static pmo_core_psoc_resume_target(struct wlan_objmgr_psoc * psoc,struct pmo_psoc_priv_obj * psoc_ctx)1477 QDF_STATUS pmo_core_psoc_resume_target(struct wlan_objmgr_psoc *psoc, 1478 struct pmo_psoc_priv_obj *psoc_ctx) 1479 { 1480 QDF_STATUS status = QDF_STATUS_SUCCESS; 1481 1482 qdf_event_reset(&psoc_ctx->wow.target_resume); 1483 1484 status = pmo_tgt_psoc_send_target_resume_req(psoc); 1485 if (status != QDF_STATUS_SUCCESS) { 1486 status = QDF_STATUS_E_FAILURE; 1487 goto out; 1488 } 1489 1490 status = qdf_wait_single_event(&psoc_ctx->wow.target_resume, 1491 PMO_RESUME_TIMEOUT); 1492 if (status != QDF_STATUS_SUCCESS) { 1493 pmo_fatal("Timeout waiting for resume event from FW"); 1494 pmo_fatal("Pending commands %d credits %d", 1495 pmo_tgt_psoc_get_pending_cmnds(psoc), 1496 pmo_tgt_psoc_get_host_credits(psoc)); 1497 if (!psoc_ctx->wow.target_resume.force_set) 1498 qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT); 1499 } else { 1500 pmo_debug("Host wakeup received"); 1501 pmo_tgt_update_target_suspend_flag(psoc, false); 1502 pmo_tgt_update_target_suspend_acked_flag(psoc, false); 1503 } 1504 out: 1505 return status; 1506 } 1507 pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc * psoc,enum qdf_suspend_type type)1508 QDF_STATUS pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, 1509 enum qdf_suspend_type type) 1510 { 1511 struct pmo_psoc_priv_obj *psoc_ctx; 1512 bool wow_mode; 1513 QDF_STATUS status; 1514 qdf_time_t begin, end; 1515 1516 if (!psoc) { 1517 pmo_err("psoc is null"); 1518 status = QDF_STATUS_E_NULL_VALUE; 1519 goto out; 1520 } 1521 1522 status = pmo_psoc_get_ref(psoc); 1523 if (status != QDF_STATUS_SUCCESS) { 1524 pmo_err("pmo cannot get the reference out of psoc"); 1525 goto out; 1526 } 1527 1528 hif_latency_detect_timer_start(pmo_core_psoc_get_hif_handle(psoc)); 1529 1530 psoc_ctx = pmo_psoc_get_priv(psoc); 1531 wow_mode = pmo_core_is_wow_enabled(psoc_ctx); 1532 pmo_debug("wow mode %d", wow_mode); 1533 1534 pmo_core_update_wow_initial_wake_up(psoc_ctx, 0); 1535 1536 /* If target was not suspended, bail out */ 1537 if (qdf_is_fw_down() || !pmo_tgt_is_target_suspended(psoc)) { 1538 pmo_psoc_put_ref(psoc); 1539 status = QDF_STATUS_E_AGAIN; 1540 goto out; 1541 } 1542 1543 begin = qdf_get_log_timestamp_usecs(); 1544 if (wow_mode) 1545 status = pmo_core_psoc_disable_wow_in_fw(psoc, psoc_ctx); 1546 else 1547 status = pmo_core_psoc_resume_target(psoc, psoc_ctx); 1548 end = qdf_get_log_timestamp_usecs(); 1549 pmo_debug("fw took total time %lu microseconds to disable wow", 1550 end - begin); 1551 1552 pmo_psoc_put_ref(psoc); 1553 1554 out: 1555 return status; 1556 } 1557 pmo_core_psoc_target_suspend_acknowledge(void * context,bool wow_nack,uint16_t reason_code)1558 void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack, 1559 uint16_t reason_code) 1560 { 1561 struct pmo_psoc_priv_obj *psoc_ctx; 1562 struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)context; 1563 void *dp_soc = pmo_core_psoc_get_dp_handle(psoc); 1564 QDF_STATUS status; 1565 1566 if (!psoc) { 1567 pmo_err("psoc is null"); 1568 goto out; 1569 } 1570 1571 status = pmo_psoc_get_ref(psoc); 1572 if (status != QDF_STATUS_SUCCESS) { 1573 pmo_err("Failed to get psoc reference"); 1574 goto out; 1575 } 1576 1577 psoc_ctx = pmo_psoc_get_priv(psoc); 1578 1579 pmo_core_set_wow_nack(psoc_ctx, wow_nack, reason_code); 1580 qdf_event_set(&psoc_ctx->wow.target_suspend); 1581 if (!pmo_tgt_psoc_get_runtime_pm_in_progress(psoc)) { 1582 if (wow_nack) 1583 qdf_wake_lock_timeout_acquire( 1584 &psoc_ctx->wow.wow_wake_lock, 1585 PMO_WAKE_LOCK_TIMEOUT); 1586 else 1587 cdp_process_wow_ack_rsp(dp_soc, OL_TXRX_PDEV_ID); 1588 } 1589 1590 pmo_psoc_put_ref(psoc); 1591 out: 1592 pmo_exit(); 1593 } 1594 pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc * psoc)1595 void pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc) 1596 { 1597 struct pmo_psoc_priv_obj *psoc_ctx; 1598 1599 if (!psoc) { 1600 pmo_err("psoc is null"); 1601 return; 1602 } 1603 1604 psoc_ctx = pmo_psoc_get_priv(psoc); 1605 psoc_ctx->wow.wow_state = pmo_wow_state_none; 1606 qdf_event_set(&psoc_ctx->wow.target_resume); 1607 } 1608 pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc * psoc)1609 int pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc) 1610 { 1611 struct pmo_psoc_priv_obj *psoc_ctx; 1612 int ret = 0; 1613 QDF_STATUS status; 1614 1615 if (!psoc) { 1616 pmo_err("psoc is NULL"); 1617 ret = -EAGAIN; 1618 goto out; 1619 } 1620 1621 status = pmo_psoc_get_ref(psoc); 1622 if (status != QDF_STATUS_SUCCESS) { 1623 pmo_err("Failed to get psoc reference"); 1624 ret = -EAGAIN; 1625 goto out; 1626 } 1627 1628 psoc_ctx = pmo_psoc_get_priv(psoc); 1629 if (pmo_core_get_wow_initial_wake_up(psoc_ctx)) { 1630 pmo_err("Target initial wake up received try again"); 1631 ret = -EAGAIN; 1632 } 1633 1634 pmo_psoc_put_ref(psoc); 1635 out: 1636 pmo_exit(); 1637 1638 return ret; 1639 } 1640 1641 pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc * psoc)1642 int pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc) 1643 { 1644 struct pmo_psoc_priv_obj *psoc_ctx; 1645 int ret = 0; 1646 QDF_STATUS status; 1647 1648 if (!psoc) { 1649 pmo_err("psoc is NULL"); 1650 ret = -EAGAIN; 1651 goto out; 1652 } 1653 1654 status = pmo_psoc_get_ref(psoc); 1655 if (status != QDF_STATUS_SUCCESS) { 1656 pmo_err("Failed to get psoc reference"); 1657 ret = -EAGAIN; 1658 goto out; 1659 } 1660 1661 psoc_ctx = pmo_psoc_get_priv(psoc); 1662 pmo_core_update_wow_initial_wake_up(psoc_ctx, 0); 1663 1664 pmo_psoc_put_ref(psoc); 1665 out: 1666 return ret; 1667 } 1668 pmo_core_psoc_handle_initial_wake_up(void * cb_ctx)1669 void pmo_core_psoc_handle_initial_wake_up(void *cb_ctx) 1670 { 1671 struct pmo_psoc_priv_obj *psoc_ctx; 1672 struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)cb_ctx; 1673 void *hif_ctx; 1674 1675 if (!psoc) { 1676 pmo_err("cb ctx/psoc is null"); 1677 return; 1678 } 1679 1680 psoc_ctx = pmo_psoc_get_priv(psoc); 1681 hif_ctx = psoc_ctx->hif_hdl; 1682 if (!hif_ctx) 1683 pmo_err("hif ctx is null, request resume not called"); 1684 else if(hif_pm_get_wake_irq_type(hif_ctx) == HIF_PM_CE_WAKE) 1685 hif_rtpm_check_and_request_resume(true); 1686 1687 pmo_core_update_wow_initial_wake_up(psoc_ctx, 1); 1688 } 1689 pmo_core_config_listen_interval(struct wlan_objmgr_vdev * vdev,uint32_t new_li)1690 QDF_STATUS pmo_core_config_listen_interval(struct wlan_objmgr_vdev *vdev, 1691 uint32_t new_li) 1692 { 1693 QDF_STATUS status; 1694 uint8_t vdev_id; 1695 uint32_t listen_interval; 1696 struct pmo_vdev_priv_obj *vdev_ctx; 1697 struct pmo_psoc_priv_obj *psoc_ctx; 1698 struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); 1699 1700 pmo_enter(); 1701 1702 status = pmo_vdev_get_ref(vdev); 1703 if (QDF_IS_STATUS_ERROR(status)) 1704 goto out; 1705 1706 vdev_ctx = pmo_vdev_get_priv(vdev); 1707 vdev_id = pmo_vdev_get_id(vdev); 1708 1709 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); 1710 if (vdev_ctx->dyn_listen_interval == new_li) { 1711 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); 1712 status = QDF_STATUS_SUCCESS; 1713 pmo_debug("Listen Interval(%d) already set for vdev id %d", 1714 new_li, vdev_id); 1715 goto dec_ref; 1716 } 1717 1718 vdev_ctx->dyn_listen_interval = new_li; 1719 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); 1720 1721 listen_interval = new_li ? new_li : cfg_default(CFG_LISTEN_INTERVAL); 1722 1723 if (!new_li) { 1724 /* Configure default LI as we do on resume */ 1725 pmo_psoc_with_ctx(pmo_vdev_get_psoc(vdev), psoc_ctx) { 1726 if (QDF_IS_STATUS_ERROR( 1727 ucfg_mlme_get_listen_interval(psoc, 1728 &listen_interval))) { 1729 pmo_err("Failed to get listen interval"); 1730 listen_interval = 1731 cfg_default(CFG_LISTEN_INTERVAL); 1732 } 1733 } 1734 } 1735 1736 pmo_debug("Set Listen Interval %d for vdevId %d", listen_interval, 1737 vdev_id); 1738 ucfg_mlme_set_sap_listen_interval(psoc, listen_interval); 1739 status = pmo_tgt_vdev_update_param_req(vdev, 1740 pmo_vdev_param_listen_interval, 1741 listen_interval); 1742 if (QDF_IS_STATUS_ERROR(status)) { 1743 /* even it fails continue fwr will take default LI */ 1744 pmo_err("Failed to Set Listen Interval"); 1745 } 1746 1747 /* Set it to Normal DTIM */ 1748 status = pmo_tgt_vdev_update_param_req(vdev, 1749 pmo_vdev_param_dtim_policy, 1750 pmo_normal_dtim); 1751 if (QDF_IS_STATUS_ERROR(status)) { 1752 pmo_err("Failed to set Normal DTIM for vdev id %d", vdev_id); 1753 } else { 1754 pmo_debug("Set DTIM Policy to Normal for vdev id %d", vdev_id); 1755 pmo_core_vdev_set_restore_dtim(vdev, true); 1756 } 1757 1758 dec_ref: 1759 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 1760 out: 1761 pmo_exit(); 1762 1763 return status; 1764 } 1765 1766 #ifdef WLAN_FEATURE_IGMP_OFFLOAD 1767 QDF_STATUS pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev * vdev,struct pmo_igmp_offload_req * pmo_igmp_req)1768 pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev, 1769 struct pmo_igmp_offload_req *pmo_igmp_req) 1770 { 1771 QDF_STATUS status = QDF_STATUS_SUCCESS; 1772 uint8_t vdev_id; 1773 enum QDF_OPMODE op_mode; 1774 struct pmo_vdev_priv_obj *vdev_ctx; 1775 uint32_t version_support; 1776 1777 if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) 1778 return QDF_STATUS_E_INVAL; 1779 1780 op_mode = pmo_get_vdev_opmode(vdev); 1781 if (QDF_STA_MODE != op_mode) { 1782 pmo_debug("igmp offload supported in STA mode"); 1783 return QDF_STATUS_E_INVAL; 1784 } 1785 1786 vdev_ctx = pmo_vdev_get_priv(vdev); 1787 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); 1788 if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_offload_enable) { 1789 pmo_debug("igmp offload not supported"); 1790 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); 1791 return QDF_STATUS_E_NOSUPPORT; 1792 } 1793 version_support = 1794 vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_version_support; 1795 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); 1796 vdev_id = pmo_vdev_get_id(vdev); 1797 pmo_igmp_req->vdev_id = vdev_id; 1798 pmo_igmp_req->version_support = version_support; 1799 status = pmo_tgt_send_igmp_offload_req(vdev, pmo_igmp_req); 1800 1801 return status; 1802 } 1803 #endif 1804 pmo_core_config_forced_dtim(struct wlan_objmgr_vdev * vdev,uint32_t dynamic_dtim)1805 QDF_STATUS pmo_core_config_forced_dtim(struct wlan_objmgr_vdev *vdev, 1806 uint32_t dynamic_dtim) 1807 { 1808 struct pmo_vdev_priv_obj *vdev_ctx; 1809 uint8_t vdev_id; 1810 QDF_STATUS status; 1811 1812 vdev_id = pmo_vdev_get_id(vdev); 1813 vdev_ctx = pmo_vdev_get_priv(vdev); 1814 1815 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); 1816 vdev_ctx->dyn_modulated_dtim = dynamic_dtim; 1817 vdev_ctx->dyn_modulated_dtim_enabled = dynamic_dtim >= 1; 1818 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); 1819 1820 status = pmo_tgt_vdev_update_param_req(vdev, 1821 pmo_vdev_param_forced_dtim_count, 1822 dynamic_dtim); 1823 1824 if (QDF_IS_STATUS_ERROR(status)) { 1825 pmo_err("Failed to set forced DTIM for vdev id %d", 1826 vdev_id); 1827 } 1828 1829 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 1830 return status; 1831 } 1832 1833 static QDF_STATUS pmo_core_config_non_li_offload_modulated_dtim(struct wlan_objmgr_vdev * vdev,uint32_t mod_dtim)1834 pmo_core_config_non_li_offload_modulated_dtim(struct wlan_objmgr_vdev *vdev, 1835 uint32_t mod_dtim) 1836 { 1837 struct pmo_vdev_priv_obj *vdev_ctx; 1838 struct pmo_psoc_cfg *psoc_cfg; 1839 bool prev_dtim_enabled; 1840 uint32_t listen_interval; 1841 uint32_t beacon_interval_mod; 1842 uint32_t max_mod_dtim; 1843 QDF_STATUS status; 1844 uint8_t vdev_id; 1845 uint32_t max_dtim; 1846 1847 pmo_enter(); 1848 1849 status = pmo_vdev_get_ref(vdev); 1850 if (status != QDF_STATUS_SUCCESS) 1851 goto out; 1852 1853 vdev_id = pmo_vdev_get_id(vdev); 1854 vdev_ctx = pmo_vdev_get_priv(vdev); 1855 psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; 1856 1857 if (psoc_cfg->sta_forced_dtim) 1858 return pmo_core_config_forced_dtim(vdev, mod_dtim); 1859 1860 /* Calculate Maximum allowed modulated DTIM */ 1861 beacon_interval_mod = 1862 pmo_core_get_vdev_beacon_interval(vdev) / 100; 1863 if (!beacon_interval_mod) 1864 beacon_interval_mod = 1; 1865 1866 max_dtim = (pmo_core_get_vdev_dtim_period(vdev) 1867 * beacon_interval_mod); 1868 1869 if (!max_dtim) { 1870 pmo_err("Invalid dtim period"); 1871 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 1872 return QDF_STATUS_E_INVAL; 1873 } 1874 1875 max_mod_dtim = psoc_cfg->sta_max_li_mod_dtim / 1876 max_dtim; 1877 1878 if (!max_mod_dtim) 1879 max_mod_dtim = 1; 1880 1881 /* Calculate Listen Interval from provided mod DTIM */ 1882 qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); 1883 vdev_ctx->dyn_modulated_dtim = mod_dtim; 1884 prev_dtim_enabled = vdev_ctx->dyn_modulated_dtim_enabled; 1885 vdev_ctx->dyn_modulated_dtim_enabled = mod_dtim != 1; 1886 if (vdev_ctx->dyn_modulated_dtim > max_mod_dtim) { 1887 listen_interval = max_mod_dtim * 1888 pmo_core_get_vdev_dtim_period(vdev); 1889 } else { 1890 listen_interval = vdev_ctx->dyn_modulated_dtim * 1891 pmo_core_get_vdev_dtim_period(vdev); 1892 } 1893 qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); 1894 1895 if (prev_dtim_enabled || mod_dtim != 1) { 1896 status = pmo_tgt_vdev_update_param_req(vdev, 1897 pmo_vdev_param_listen_interval, 1898 listen_interval); 1899 if (QDF_IS_STATUS_ERROR(status)) 1900 /* even it fails continue fwr will take default LI */ 1901 pmo_err("Failed to set Listen Interval for vdev id %d", 1902 vdev_id); 1903 else 1904 pmo_debug("Set Listen Interval %d for vdev id %d", 1905 listen_interval, vdev_id); 1906 1907 status = pmo_tgt_vdev_update_param_req(vdev, 1908 pmo_vdev_param_dtim_policy, 1909 pmo_normal_dtim); 1910 if (QDF_IS_STATUS_ERROR(status)) { 1911 pmo_err("Failed to set Normal DTIM for vdev id %d", 1912 vdev_id); 1913 } else { 1914 pmo_debug("Set DTIM Policy to Normal for vdev id %d", 1915 vdev_id); 1916 pmo_core_vdev_set_restore_dtim(vdev, true); 1917 } 1918 } 1919 1920 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 1921 out: 1922 pmo_exit(); 1923 return status; 1924 } 1925 1926 static QDF_STATUS pmo_core_config_li_offload_modulated_dtim(struct wlan_objmgr_vdev * vdev,uint32_t mod_dtim)1927 pmo_core_config_li_offload_modulated_dtim(struct wlan_objmgr_vdev *vdev, 1928 uint32_t mod_dtim) 1929 { 1930 struct pmo_vdev_priv_obj *vdev_ctx; 1931 struct pmo_psoc_cfg *psoc_cfg; 1932 QDF_STATUS status; 1933 uint8_t vdev_id; 1934 1935 pmo_enter(); 1936 1937 status = pmo_vdev_get_ref(vdev); 1938 if (status != QDF_STATUS_SUCCESS) 1939 goto out; 1940 1941 vdev_id = pmo_vdev_get_id(vdev); 1942 vdev_ctx = pmo_vdev_get_priv(vdev); 1943 psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; 1944 1945 if (mod_dtim > psoc_cfg->sta_max_li_mod_dtim) 1946 mod_dtim = psoc_cfg->sta_max_li_mod_dtim; 1947 pmo_core_vdev_set_moddtim_user(vdev, mod_dtim); 1948 pmo_core_vdev_set_moddtim_user_enabled(vdev, true); 1949 1950 if (!ucfg_pmo_is_vdev_connected(vdev)) { 1951 pmo_core_vdev_set_moddtim_user_active(vdev, false); 1952 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 1953 goto out; 1954 } 1955 1956 status = pmo_tgt_vdev_update_param_req(vdev, 1957 pmo_vdev_param_moddtim, 1958 mod_dtim); 1959 if (QDF_IS_STATUS_SUCCESS(status)) { 1960 pmo_debug("Set modulated dtim for vdev id %d", 1961 vdev_id); 1962 pmo_core_vdev_set_moddtim_user_active(vdev, true); 1963 } else { 1964 pmo_err("Failed to Set modulated dtim for vdev id %d", 1965 vdev_id); 1966 } 1967 1968 wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); 1969 out: 1970 pmo_exit(); 1971 return status; 1972 } 1973 pmo_core_config_modulated_dtim(struct wlan_objmgr_vdev * vdev,uint32_t mod_dtim)1974 QDF_STATUS pmo_core_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, 1975 uint32_t mod_dtim) 1976 { 1977 struct pmo_vdev_priv_obj *vdev_ctx; 1978 struct pmo_psoc_priv_obj *psoc_ctx; 1979 QDF_STATUS status; 1980 1981 vdev_ctx = pmo_vdev_get_priv(vdev); 1982 psoc_ctx = vdev_ctx->pmo_psoc_ctx; 1983 1984 if (psoc_ctx->caps.li_offload) 1985 status = pmo_core_config_li_offload_modulated_dtim(vdev, 1986 mod_dtim); 1987 else 1988 status = pmo_core_config_non_li_offload_modulated_dtim(vdev, 1989 mod_dtim); 1990 1991 return status; 1992 } 1993 1994 #ifdef SYSTEM_PM_CHECK pmo_core_system_resume(struct wlan_objmgr_psoc * psoc)1995 void pmo_core_system_resume(struct wlan_objmgr_psoc *psoc) 1996 { 1997 struct pmo_psoc_priv_obj *psoc_ctx; 1998 QDF_STATUS status; 1999 2000 if (!psoc) { 2001 pmo_err("psoc is NULL"); 2002 return; 2003 } 2004 2005 status = pmo_psoc_get_ref(psoc); 2006 if (status != QDF_STATUS_SUCCESS) { 2007 pmo_err("pmo cannot get the reference out of psoc"); 2008 return; 2009 } 2010 2011 psoc_ctx = pmo_psoc_get_priv(psoc); 2012 2013 htc_system_resume(psoc_ctx->htc_hdl); 2014 2015 pmo_psoc_put_ref(psoc); 2016 } 2017 #endif 2018