From bb9deb4ae08b669ee7e5c2e87de40c4a3366b69a Mon Sep 17 00:00:00 2001 From: Abhishek Singh Date: Fri, 24 May 2019 10:11:24 +0530 Subject: [PATCH] qcacld-3.0: Release vdev ref and delete pending peers in wma close In hdd_vdev_destroy, if policy_mgr_check_and_stop_opportunistic_timer decides to move to single mac mode and while sending the HW mode change the target goes down, this leads to timeout of the HW mode change req in WMA layer which is 2 sec and in serialization its 4 sec, but policy_mgr_check_and_stop_opportunistic_timer timeout in 1 sec and proceed to sme_close_session and wait for it to complete. sme_close_session queue WLAN_SER_CMD_DEL_STA_SESSION to serialization but it remains in pending queue, behind HW mode change req. Now due to SSR the wait event for sme_close_session is set and thus hdd_vdev_destroy logically deletes the vdev. Now on WMA timeout the HW mode change try to remove the request from serialization which it fails to remove as it fails to get ref for vdev with vdev being logically deleted. Thus WLAN_SER_CMD_DEL_STA_SESSION is not processed and is flushed in hdd_wlan_shutdown. Thus as SSR WLAN_SER_CMD_DEL_STA_SESSION is flushed from serialization queue, the wma_vdev_detach() is not called for that vdev and thus the peer attached to the vdev are not deleted and wma vdev ref is also not released, this lead vdev/peer ref leak. To fix this update the wait timeout in policy_mgr_check_and_stop_opportunistic_timer with proper value higher than the serialization timeout for the HW mode change request. ALso set the wait event in policy_mgr_pdev_set_hw_mode_cb in failure cases as well to avoid timeout in case of hw mode change failures. Also release pending peer and vdef refs in wma_wmi_service_close. Change-Id: I5ddf8263b0dbf889be506332a67f5e18c1bfb111 CRs-Fixed: 2458034 --- .../policy_mgr/src/wlan_policy_mgr_core.c | 17 +++--- .../policy_mgr/src/wlan_policy_mgr_i.h | 7 ++- core/sme/inc/sme_api.h | 5 ++ core/wma/inc/wma_internal.h | 14 +++++ core/wma/src/wma_dev_if.c | 57 +++++++++++-------- core/wma/src/wma_main.c | 3 + 6 files changed, 69 insertions(+), 34 deletions(-) diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c index 572c316763e4..58fd099cd859 100644 --- a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c +++ b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c @@ -881,7 +881,7 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, pm_ctx = policy_mgr_get_context(context); if (!pm_ctx) { policy_mgr_err("Invalid Context"); - return; + goto set_done_event; } policy_mgr_set_hw_mode_change_in_progress(context, @@ -889,14 +889,14 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, if (status != SET_HW_MODE_STATUS_OK) { policy_mgr_err("Set HW mode failed with status %d", status); - return; + goto set_done_event; } /* vdev mac map for NAN Discovery is expected in NAN Enable resp */ if (reason != POLICY_MGR_UPDATE_REASON_NAN_DISCOVERY && !vdev_mac_map) { policy_mgr_err("vdev_mac_map is NULL"); - return; + goto set_done_event; } policy_mgr_debug("cfgd_hw_mode_index=%d", cfgd_hw_mode_index); @@ -910,7 +910,7 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, &hw_mode); if (ret != QDF_STATUS_SUCCESS) { policy_mgr_err("Get HW mode failed: %d", ret); - return; + goto set_done_event; } policy_mgr_debug("MAC0: TxSS:%d, RxSS:%d, Bw:%d, band_cap %d", @@ -940,12 +940,15 @@ void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, next_action, reason); else { policy_mgr_debug("No action needed right now"); - ret = policy_mgr_set_opportunistic_update(context); - if (!QDF_IS_STATUS_SUCCESS(ret)) - policy_mgr_err("ERROR: set opportunistic_update event failed"); + goto set_done_event; } return; + +set_done_event: + ret = policy_mgr_set_opportunistic_update(context); + if (!QDF_IS_STATUS_SUCCESS(ret)) + policy_mgr_err("ERROR: set opportunistic_update event failed"); } /** diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h index 3bbd588e9b4c..34230d846cdb 100644 --- a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h +++ b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h @@ -27,10 +27,13 @@ #include "wlan_reg_services_api.h" #define DBS_OPPORTUNISTIC_TIME 5 + +#define POLICY_MGR_SER_CMD_TIMEOUT 4000 + #ifdef QCA_WIFI_3_0_EMU -#define CONNECTION_UPDATE_TIMEOUT 3000 +#define CONNECTION_UPDATE_TIMEOUT (POLICY_MGR_SER_CMD_TIMEOUT + 3000) #else -#define CONNECTION_UPDATE_TIMEOUT 1000 +#define CONNECTION_UPDATE_TIMEOUT (POLICY_MGR_SER_CMD_TIMEOUT + 2000) #endif #define PM_24_GHZ_CHANNEL_6 (6) diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index c317494f8c42..20bcfb4925f9 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -122,6 +122,11 @@ #define SME_CMD_ROAM_CMD_TIMEOUT (SIR_VDEV_START_REQUEST_TIMEOUT + 4000) #define SME_CMD_ADD_DEL_TS_TIMEOUT (4 * 1000) +/* + * POLICY_MGR_SER_CMD_TIMEOUT should be same as SME_CMD_POLICY_MGR_CMD_TIMEOUT + * if SME_CMD_POLICY_MGR_CMD_TIMEOUT is changed change + * POLICY_MGR_SER_CMD_TIMEOUT as well. + */ #define SME_CMD_POLICY_MGR_CMD_TIMEOUT (SIR_VDEV_PLCY_MGR_TIMEOUT + 2000) #define SME_POLICY_MGR_CMD_TIMEOUT (SME_CMD_POLICY_MGR_CMD_TIMEOUT + 1000) diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 519605585509..f640e0dc0f1d 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -575,6 +575,20 @@ QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, struct del_sta_self_params *pdel_sta_self_req_param, uint8_t generateRsp); +/** + * wma_release_vdev_and_peer_ref() - release vdev ref taken by interface txrx + * node and delete all the peers attached to this vdev + * @wma - wma handle + * @iface: wma interface txrx node + * + * This API release vdev ref taken by iface and all the peers attached to this + * vdev, this need to be called on recovery to flush vdev and peer. + * + * Return: void. + */ +void wma_release_vdev_and_peer_ref(tp_wma_handle wma, + struct wma_txrx_node *iface); + int wma_vdev_start_resp_handler(void *handle, uint8_t *cmd_param_info, uint32_t len); diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 0d5437958bc9..1b642db6c4dc 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -704,8 +704,7 @@ wma_cdp_vdev_detach(ol_txrx_soc_handle soc, /** * wma_release_vdev_ref() - Release vdev object reference count - * @wma_handle: wma handle - * @vdev_id: used to get wma interface txrx node + * @iface: wma interface txrx node * * Purpose of this function is to release vdev object reference count * from wma interface txrx node. @@ -713,12 +712,10 @@ wma_cdp_vdev_detach(ol_txrx_soc_handle soc, * Return: None */ static void -wma_release_vdev_ref(tp_wma_handle wma_handle, uint8_t vdev_id) +wma_release_vdev_ref(struct wma_txrx_node *iface) { - struct wma_txrx_node *iface; struct wlan_objmgr_vdev *vdev; - iface = &wma_handle->interfaces[vdev_id]; vdev = iface->vdev; iface->vdev = NULL; @@ -797,7 +794,7 @@ static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION); } WMA_LOGD("Call txrx detach with callback for vdev %d", vdev_id); - wma_release_vdev_ref(wma_handle, vdev_id); + wma_release_vdev_ref(iface); wma_cdp_vdev_detach(soc, wma_handle, vdev_id); /* @@ -811,7 +808,7 @@ static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, out: WMA_LOGE("Call txrx detach callback for vdev %d, generate_rsp %u", vdev_id, generate_rsp); - wma_release_vdev_ref(wma_handle, vdev_id); + wma_release_vdev_ref(iface); wma_cdp_vdev_detach(soc, wma_handle, vdev_id); wma_vdev_deinit(iface); @@ -827,35 +824,36 @@ out: /** * wma_force_objmgr_vdev_peer_cleanup() - Cleanup ObjMgr Vdev peers during SSR * @wma_handle: WMA handle - * @vdev_id: vdev ID + * @iface: wma interface txrx node * * Return: none */ static void wma_force_objmgr_vdev_peer_cleanup(tp_wma_handle wma, - uint8_t vdev_id) + struct wma_txrx_node *iface) { - struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; struct wlan_objmgr_vdev *vdev; struct wlan_objmgr_peer *peer = NULL; struct wlan_objmgr_peer *peer_next = NULL; qdf_list_t *peer_list; - WMA_LOGE("%s: SSR: force cleanup peers in vdev(%d)", - __func__, vdev_id); - iface->vdev_active = false; - - vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, - WLAN_LEGACY_WMA_ID); - - if (!vdev) { - WMA_LOGE("Failed to get Objmgr Vdev"); + if (!iface->vdev) return; - } + + /* + * No need to take ref as if iface->vdev is valid then WMA already hold + * ref and this can be used diretly. ALso this API may get called after + * vdev deleted logically so taking ref for vdev will fail and peer + * wont be deleted for the vdev. + */ + vdev = iface->vdev; + + WMA_LOGI("%s: SSR: force cleanup peers in vdev(%d)", __func__, + wlan_vdev_get_id(vdev)); + iface->vdev_active = false; peer_list = &vdev->vdev_objmgr.wlan_peer_list; if (!peer_list) { WMA_LOGE("%s: peer_list is NULL", __func__); - wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); return; } @@ -876,12 +874,22 @@ static void wma_force_objmgr_vdev_peer_cleanup(tp_wma_handle wma, peer = peer_next; } - wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); - /* Force delete all the peers, set the wma interface peer_count to 0 */ iface->peer_count = 0; } +void wma_release_vdev_and_peer_ref(tp_wma_handle wma, + struct wma_txrx_node *iface) +{ + if (!iface) { + WMA_LOGE("iface is NULL"); + return; + } + + wma_force_objmgr_vdev_peer_cleanup(wma, iface); + wma_release_vdev_ref(iface); +} + static bool wma_vdev_uses_self_peer(uint32_t vdev_type, uint32_t vdev_subtype) { switch (vdev_type) { @@ -974,8 +982,7 @@ QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, * CDP Vdev. */ if (!cds_is_target_ready()) { - wma_force_objmgr_vdev_peer_cleanup(wma_handle, vdev_id); - wma_release_vdev_ref(wma_handle, vdev_id); + wma_release_vdev_and_peer_ref(wma_handle, iface); wma_cdp_vdev_detach(soc, wma_handle, vdev_id); goto send_rsp; } diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 61989ab3e1d9..c0bd8f05bacc 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -4660,6 +4660,9 @@ QDF_STATUS wma_wmi_service_close(void) wma_handle->wmi_handle = NULL; for (i = 0; i < wma_handle->max_bssid; i++) { + /* Release peer and vdev ref hold by wma if not already done */ + wma_release_vdev_and_peer_ref(wma_handle, + &wma_handle->interfaces[i]); wma_vdev_deinit(&wma_handle->interfaces[i]); }