소스 검색

qcacld-3.0: Fix FW assert when delete VDEV

FW assert is observed when deleting VDEV due to there are peers
not deleted.

Add check for peer number in FW before sending delete VDEV
command to avoid such issue.

Change-Id: I4cc5d4c63faf3dc8f7b9d0702f92b54b298802cb
CRs-Fixed: 2163770
Min Liu 7 년 전
부모
커밋
a9df1ff921
2개의 변경된 파일27개의 추가작업 그리고 0개의 파일을 삭제
  1. 2 0
      core/wma/inc/wma.h
  2. 25 0
      core/wma/src/wma_dev_if.c

+ 2 - 0
core/wma/inc/wma.h

@@ -1110,6 +1110,8 @@ struct wma_txrx_node {
 	void *staKeyParams;
 	bool restore_dtim_setting;
 	uint32_t peer_count;
+	qdf_atomic_t fw_peer_count;
+	qdf_event_t fw_peer_delete;
 	bool roam_synch_in_progress;
 	void *plink_status_req;
 	void *psnr_req;

+ 25 - 0
core/wma/src/wma_dev_if.c

@@ -573,6 +573,8 @@ 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)
@@ -589,12 +591,20 @@ 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);
+	}
+
 	status = wmi_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		WMA_LOGE("Unable to remove an interface");
 		goto out;
 	}
 
+	qdf_event_destroy(&iface->fw_peer_delete);
+
 	WMA_LOGD("vdev_id:%hu vdev_hdl:%pK", vdev_id, iface->handle);
 	if (!generate_rsp) {
 		WMA_LOGE("Call txrx detach w/o callback for vdev %d", vdev_id);
@@ -1414,6 +1424,11 @@ void wma_remove_peer(tp_wma_handle wma, uint8_t *bssid,
 			 __func__, qdf_status);
 		/* Clear default bit and set to NOT_START_UNMAP */
 		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));
 	}
 
 peer_detach:
@@ -1551,6 +1566,10 @@ QDF_STATUS wma_create_peer(tp_wma_handle wma, struct cdp_pdev *pdev,
 		cdp_peer_delete(dp_soc, peer,
 				1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER);
 		goto err;
+	} else {
+		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));
 	}
 
 	WMA_LOGD("%s: Created peer %pK with peer_addr %pM vdev_id %d, peer_count - %d",
@@ -2213,6 +2232,12 @@ struct cdp_vdev *wma_vdev_attach(tp_wma_handle wma_handle,
 		self_sta_req->sub_type;
 	qdf_atomic_init(&wma_handle->interfaces
 			[self_sta_req->session_id].bss_status);
+	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__);
 
 	if (((self_sta_req->type == WMI_VDEV_TYPE_AP) &&
 	    (self_sta_req->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) ||