diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index fe733222d1fe..08b144bac72f 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -16771,8 +16771,24 @@ csr_issue_del_sta_for_session_req(tpAniSirGlobal pMac, uint32_t sessionId, { struct del_sta_self_params *del_sta_self_req; struct scheduler_msg msg = {0}; + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); tSirRetStatus status; + if (!wma_handle) { + sme_err("wma handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* Need to wait for all peer delete command sent to FW + * before sending VDEV delete command + * otherwise it will cause FW assert + * Need to do this before sending to scheduler queue + * otherwise the scheduler thread will be blocked + * and fail to handle the VDEV stop timeout callback + * in which peer delete command will also be sent + */ + wma_vdev_wait_for_peer_delete_completion(wma_handle, sessionId); + del_sta_self_req = qdf_mem_malloc(sizeof(struct del_sta_self_params)); if (NULL == del_sta_self_req) { sme_err(" mem alloc failed for tDelStaSelfParams"); diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 7cf03e45c04e..52f97d608e85 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1111,7 +1111,7 @@ struct wma_txrx_node { bool restore_dtim_setting; uint32_t peer_count; qdf_atomic_t fw_peer_count; - qdf_event_t fw_peer_delete; + qdf_event_t fw_peer_delete_completion; bool roam_synch_in_progress; void *plink_status_req; void *psnr_req; @@ -2659,4 +2659,16 @@ QDF_STATUS wma_config_bmiss_bcnt_params(uint32_t vdev_id, uint32_t first_cnt, * Return: None */ void wma_check_and_set_wake_timer(uint32_t time); + +/** + * wma_vdev_wait_for_peer_delete_completion() - wait for all peers of the vdev + * to be deleted. + * @wma_handle: wma handle + * @vdev_id: vdev id + * + * Return: None + */ +void wma_vdev_wait_for_peer_delete_completion(tp_wma_handle wma_handle, + uint8_t vdev_id); + #endif diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 14f6390a4670..75a02b06ef16 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -573,8 +573,6 @@ wma_cdp_vdev_detach(ol_txrx_soc_handle soc, iface->is_vdev_valid = false; } -#define WAIT_FW_PEER_DELETE_TIMEOUT (5*1000) - static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, struct del_sta_self_params *del_sta_self_req_param, uint8_t generate_rsp) @@ -591,11 +589,7 @@ static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, goto out; } - while (qdf_atomic_read(&iface->fw_peer_count)) { - qdf_wait_for_event_completion(&iface->fw_peer_delete, - WAIT_FW_PEER_DELETE_TIMEOUT); - qdf_event_reset(&iface->fw_peer_delete); - } + QDF_BUG(qdf_atomic_read(&iface->fw_peer_count) == 0); status = wmi_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id); if (QDF_IS_STATUS_ERROR(status)) { @@ -603,7 +597,7 @@ static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, goto out; } - qdf_event_destroy(&iface->fw_peer_delete); + qdf_event_destroy(&iface->fw_peer_delete_completion); WMA_LOGD("vdev_id:%hu vdev_hdl:%pK", vdev_id, iface->handle); if (!generate_rsp) { @@ -713,6 +707,30 @@ VDEV_DETACH: wma_cdp_vdev_detach(soc, wma_handle, vdev_id); } +#define WMA_WAIT_PEER_DELETE_COMPLETION_TIMEOUT (WMA_VDEV_STOP_REQUEST_TIMEOUT+ 1000) + +/** + * wma_vdev_wait_for_peer_delete_completion(): wait for all peers of the vdev + * to be deleted. + * @wma_handle: wma handle + * @vdev_id: vdev id + * + * Return: None + */ +void wma_vdev_wait_for_peer_delete_completion(tp_wma_handle wma_handle, + uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + + if (!iface) { + WMA_LOGE("%s: iface of vdev-%d is NULL", __func__, vdev_id); + return; + } + + qdf_wait_for_event_completion(&iface->fw_peer_delete_completion, + WMA_WAIT_PEER_DELETE_COMPLETION_TIMEOUT); +} + /** * wma_vdev_detach() - send vdev delete command to fw * @wma_handle: wma handle @@ -1426,9 +1444,10 @@ void wma_remove_peer(tp_wma_handle wma, uint8_t *bssid, bitmap = 1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER; } else { qdf_atomic_dec(&wma->interfaces[vdev_id].fw_peer_count); - qdf_event_set(&wma->interfaces[vdev_id].fw_peer_delete); WMA_LOGD("%s: vdev-%d fw_peer_count %d", __func__, vdev_id, qdf_atomic_read(&wma->interfaces[vdev_id].fw_peer_count)); + if (qdf_atomic_read(&wma->interfaces[vdev_id].fw_peer_count) == 0) + qdf_event_set(&wma->interfaces[vdev_id].fw_peer_delete_completion); } peer_detach: @@ -1570,6 +1589,7 @@ QDF_STATUS wma_create_peer(tp_wma_handle wma, struct cdp_pdev *pdev, qdf_atomic_inc(&wma->interfaces[vdev_id].fw_peer_count); WMA_LOGD("%s: vdev-%d fw_peer_count %d", __func__, vdev_id, qdf_atomic_read(&wma->interfaces[vdev_id].fw_peer_count)); + qdf_event_reset(&wma->interfaces[vdev_id].fw_peer_delete_completion); } WMA_LOGD("%s: Created peer %pK with peer_addr %pM vdev_id %d, peer_count - %d", @@ -2236,9 +2256,12 @@ struct cdp_vdev *wma_vdev_attach(tp_wma_handle wma_handle, qdf_atomic_init(&wma_handle->interfaces [self_sta_req->session_id].fw_peer_count); status = qdf_event_create(&wma_handle->interfaces - [self_sta_req->session_id].fw_peer_delete); - if (status != QDF_STATUS_SUCCESS) - WMA_LOGE("%s: Failed to create fw_peer_delete event", __func__); + [self_sta_req->session_id].fw_peer_delete_completion); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create fw_peer_delete_completion", __func__); + goto end; + } + qdf_event_set(&wma_handle->interfaces[vdev_id].fw_peer_delete_completion); if (((self_sta_req->type == WMI_VDEV_TYPE_AP) && (self_sta_req->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) ||