Browse Source

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 years ago
parent
commit
a9df1ff921
2 changed files with 27 additions and 0 deletions
  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)) ||