From 22202b703ad4d375fb8fb500dc0d3f9e647ff3f0 Mon Sep 17 00:00:00 2001 From: Min Liu Date: Mon, 12 Feb 2018 14:01:24 +0800 Subject: [PATCH] qcacld-3.0: Peer is not deleted when delete VDEV Failure can be observed when waiting for peer deletion before sending WMI command. Peer deletion in VDEV stop timeout handler also need to be handled in the scheduler queues. Change the logic to wait for peer delete completion before sending message to scheduler queue to delete VDEV. Change-Id: I78d3070a73c85d212bc33c346b3e60edf3c016f8 CRs-Fixed: 2187430 --- core/sme/src/csr/csr_api_roam.c | 16 +++++++++++ core/wma/inc/wma.h | 14 +++++++++- core/wma/src/wma_dev_if.c | 47 ++++++++++++++++++++++++--------- 3 files changed, 64 insertions(+), 13 deletions(-) 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)) ||