Browse Source

qcacld-3.0: Fix dp handle mem leak during SSR

In SSR case the mlme_vdev_obj_destroy_handler for the vdev may
get called after the dp soc is uninitialized and thus the
cdp_vdev_detach will not get called to free dp vdev.

Thus free dp vdev before sending the vdev delete and
for force cleanup due to ssr try to free it before detaching
dp soc.

Change-Id: I6f1f95a4f8bbc4cb316e8fd59f6411a6c0c2c099
CRs-Fixed: 2538481
Abhishek Ambure 5 years ago
parent
commit
c00691687c

+ 5 - 0
core/cds/src/cds_api.c

@@ -1186,6 +1186,11 @@ QDF_STATUS cds_close(struct wlan_objmgr_psoc *psoc)
 	}
 
 	gp_cds_context->mac_context = NULL;
+	/*
+	 * Call this before cdp soc detatch as it used the cdp soc to free the
+	 * cdp vdev if any.
+	 */
+	wma_release_pending_vdev_refs();
 
 	cdp_soc_detach(gp_cds_context->dp_soc);
 	gp_cds_context->dp_soc = NULL;

+ 17 - 10
core/wma/inc/wma.h

@@ -1897,8 +1897,7 @@ void wma_vdev_update_pause_bitmap(uint8_t vdev_id, uint16_t value)
 	}
 
 	if (!wlan_vdev_get_dp_handle(iface->vdev)) {
-		WMA_LOGE("%s: Failed to get iface handle: NULL",
-			 __func__);
+		WMA_LOGE("%s: Failed to get dp handle", __func__);
 		return;
 	}
 
@@ -1930,8 +1929,7 @@ uint16_t wma_vdev_get_pause_bitmap(uint8_t vdev_id)
 	}
 
 	if (!wlan_vdev_get_dp_handle(iface->vdev)) {
-		WMA_LOGE("%s: Failed to get iface handle: NULL",
-			 __func__);
+		WMA_LOGE("%s: Failed to get dp handle", __func__);
 		return 0;
 	}
 
@@ -1992,8 +1990,7 @@ static inline bool wma_vdev_is_device_in_low_pwr_mode(uint8_t vdev_id)
 	}
 
 	if (!wlan_vdev_get_dp_handle(iface->vdev)) {
-		WMA_LOGE("%s: Failed to get iface handle:NULL",
-			 __func__);
+		WMA_LOGE("%s: Failed to get dp handle", __func__);
 		return 0;
 	}
 
@@ -2116,8 +2113,7 @@ void wma_vdev_set_pause_bit(uint8_t vdev_id, wmi_tx_pause_type bit_pos)
 	}
 
 	if (!wlan_vdev_get_dp_handle(iface->vdev)) {
-		WMA_LOGE("%s: Failed to get iface handle: NULL",
-			 __func__);
+		WMA_LOGE("%s: Failed to get dp handle", __func__);
 		return;
 	}
 
@@ -2150,8 +2146,7 @@ void wma_vdev_clear_pause_bit(uint8_t vdev_id, wmi_tx_pause_type bit_pos)
 	}
 
 	if (!wlan_vdev_get_dp_handle(iface->vdev)) {
-		WMA_LOGE("%s: Failed to get iface handle: NULL",
-			 __func__);
+		WMA_LOGE("%s: Failed to get dp handle", __func__);
 		return;
 	}
 
@@ -2651,4 +2646,16 @@ QDF_STATUS wma_post_vdev_start_setup(uint8_t vdev_id);
 QDF_STATUS wma_pre_vdev_start_setup(uint8_t vdev_id,
 				    struct bss_params *add_bss);
 
+/**
+ * wma_release_pending_vdev_refs() - release vdev ref taken by interface txrx
+ * node and delete all the peers attached to this vdev.
+ *
+ * This API loop and release vdev ref taken by all iface and all the peers
+ * attached to the vdev, this need to be called on recovery to flush vdev
+ * and peer.
+ *
+ * Return: void.
+ */
+void wma_release_pending_vdev_refs(void);
+
 #endif

+ 0 - 14
core/wma/inc/wma_internal.h

@@ -708,20 +708,6 @@ struct cdp_vdev *wma_find_vdev_by_bssid(tp_wma_handle wma, uint8_t *bssid,
 QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle,
 			struct del_vdev_params *pdel_vdev_req_param);
 
-/**
- * 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);
-
 QDF_STATUS wma_vdev_set_param(wmi_unified_t wmi_handle, uint32_t if_id,
 				uint32_t param_id, uint32_t param_value);
 

+ 1 - 2
core/wma/src/wma_data.c

@@ -3034,8 +3034,7 @@ void wma_tx_abort(uint8_t vdev_id)
 	}
 	handle = wlan_vdev_get_dp_handle(iface->vdev);
 	if (!handle) {
-		WMA_LOGE("%s: Failed to get iface handle: %pK",
-			 __func__, handle);
+		WMA_LOGE("%s: Failed to get dp handle", __func__);
 		return;
 	}
 	bssid = wma_get_vdev_bssid(iface->vdev);

+ 66 - 18
core/wma/src/wma_dev_if.c

@@ -560,6 +560,26 @@ error:
 	return qdf_status;
 }
 
+static void
+wma_cdp_vdev_detach(ol_txrx_soc_handle soc, tp_wma_handle wma_handle,
+		    uint8_t vdev_id)
+{
+	struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id];
+	struct wlan_objmgr_vdev *vdev = iface->vdev;
+	struct cdp_vdev *cdp_vdev;
+
+	if (!vdev) {
+		WMA_LOGE(FL("vdev is NULL"));
+		return;
+	}
+
+	cdp_vdev = wlan_vdev_get_dp_handle(vdev);
+	if (soc && cdp_vdev) {
+		wlan_vdev_set_dp_handle(vdev, NULL);
+		cdp_vdev_detach(soc, cdp_vdev, NULL, NULL);
+	}
+}
+
 /**
  * wma_release_vdev_ref() - Release vdev object reference count
  * @iface: wma interface txrx node
@@ -620,20 +640,21 @@ static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle,
 
 	if (!soc) {
 		WMA_LOGE("%s:SOC context is NULL", __func__);
-		goto out;
+		goto rel_ref;
 	}
 
 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
 	if (!vdev_mlme) {
 		wma_err("Failed to get vdev mlme obj for vdev id %d",
 			del_vdev_req_param->vdev_id);
-		goto out;
+		goto rel_ref;
 	}
 
 	if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
 		wma_handle_monitor_mode_vdev_detach(wma_handle, vdev_id);
 
 	iface->del_staself_req = del_vdev_req_param;
+	wma_cdp_vdev_detach(soc, wma_handle, vdev_id);
 	wma_release_vdev_ref(iface);
 
 	status = vdev_mgr_delete_send(vdev_mlme);
@@ -644,9 +665,10 @@ static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle,
 
 	return status;
 
-out:
-	wlan_vdev_set_dp_handle(iface->vdev, NULL);
+rel_ref:
+	wma_cdp_vdev_detach(soc, wma_handle, vdev_id);
 	wma_release_vdev_ref(iface);
+out:
 	wma_vdev_deinit(iface);
 	qdf_mem_zero(iface, sizeof(*iface));
 	wma_vdev_init(iface);
@@ -670,6 +692,7 @@ static void wma_force_objmgr_vdev_peer_cleanup(tp_wma_handle wma,
 	struct wlan_objmgr_peer *peer = NULL;
 	struct wlan_objmgr_peer *peer_next = NULL;
 	qdf_list_t *peer_list;
+	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
 
 	if (!iface->vdev)
 		return;
@@ -682,6 +705,8 @@ static void wma_force_objmgr_vdev_peer_cleanup(tp_wma_handle wma,
 	 */
 	vdev = iface->vdev;
 
+	wma_cdp_vdev_detach(soc, wma, wlan_vdev_get_id(vdev));
+
 	WMA_LOGI("%s: SSR: force cleanup peers in vdev(%d)", __func__,
 		 wlan_vdev_get_id(vdev));
 	iface->vdev_active = false;
@@ -713,8 +738,9 @@ static void wma_force_objmgr_vdev_peer_cleanup(tp_wma_handle wma,
 	iface->peer_count = 0;
 }
 
-void wma_release_vdev_and_peer_ref(tp_wma_handle wma,
-				   struct wma_txrx_node *iface)
+static void
+wma_release_vdev_and_peer_ref(tp_wma_handle wma,
+			      struct wma_txrx_node *iface)
 {
 	if (!iface) {
 		WMA_LOGE("iface is NULL");
@@ -725,6 +751,22 @@ void wma_release_vdev_and_peer_ref(tp_wma_handle wma,
 	wma_release_vdev_ref(iface);
 }
 
+void wma_release_pending_vdev_refs(void)
+{
+	int i;
+	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
+
+	/* validate the wma_handle */
+	if (!wma) {
+		WMA_LOGE("%s: Invalid wma handle", __func__);
+		return;
+	}
+
+	for (i = 0; i < wma->max_bssid; i++)
+		/* Release peer and vdev ref hold by wma if not already done */
+		wma_release_vdev_and_peer_ref(wma, &wma->interfaces[i]);
+}
+
 static bool wma_vdev_uses_self_peer(uint32_t vdev_type, uint32_t vdev_subtype)
 {
 	switch (vdev_type) {
@@ -799,8 +841,8 @@ QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle,
 	}
 
 	if (!wlan_vdev_get_dp_handle(iface->vdev)) {
-		WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed",
-			 vdev_id);
+		WMA_LOGE("%s: Failed to get dp handle for vdev id %d",
+			 __func__, vdev_id);
 		goto send_rsp;
 	}
 
@@ -2102,7 +2144,7 @@ void wma_send_del_bss_response(tp_wma_handle wma, struct del_bss_resp *resp)
 	}
 	handle = wlan_vdev_get_dp_handle(iface->vdev);
 	if (!handle) {
-		WMA_LOGE("%s vdev id %d is already deleted",
+		WMA_LOGE("%s: Failed to get dp handle for vdev id %d",
 			 __func__, vdev_id);
 		if (resp)
 			qdf_mem_free(resp);
@@ -2324,7 +2366,7 @@ __wma_handle_vdev_stop_rsp(struct vdev_stop_response *resp_event)
 		uint8_t type;
 
 		if (!wlan_vdev_get_dp_handle(iface->vdev)) {
-			WMA_LOGE("%s vdev id %d is already deleted",
+			WMA_LOGE("%s: Failed to get dp handle for vdev id %d",
 				 __func__, resp_event->vdev_id);
 			status = -EINVAL;
 			goto free_params;
@@ -2445,17 +2487,22 @@ QDF_STATUS wma_post_vdev_create_setup(struct wlan_objmgr_vdev *vdev)
 		QDF_STATUS_SUCCESS)
 		return QDF_STATUS_E_FAILURE;
 
+	vdev_id = wlan_vdev_get_id(vdev);
+	wma_handle->interfaces[vdev_id].vdev = vdev;
+	wma_handle->interfaces[vdev_id].vdev_active = true;
+	txrx_vdev_handle = wlan_vdev_get_dp_handle(vdev);
+	if (!txrx_vdev_handle) {
+		WMA_LOGE("%s: Failed to get dp handle for vdev id %d",
+			 __func__, vdev_id);
+		goto end;
+	}
+
 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev);
 	if (!vdev_mlme) {
 		WMA_LOGE("%s: Failed to get vdev mlme obj!", __func__);
-		return QDF_STATUS_E_FAILURE;
+		goto end;
 	}
 
-	vdev_id = wlan_vdev_get_id(vdev);
-	txrx_vdev_handle = wlan_vdev_get_dp_handle(vdev);
-	wma_handle->interfaces[vdev_id].vdev = vdev;
-
-	wma_handle->interfaces[vdev_id].vdev_active = true;
 	wma_vdev_update_pause_bitmap(vdev_id, 0);
 
 	wma_handle->interfaces[vdev_id].type =
@@ -2707,9 +2754,10 @@ QDF_STATUS wma_post_vdev_create_setup(struct wlan_objmgr_vdev *vdev)
 	return QDF_STATUS_SUCCESS;
 
 end:
+	wma_cdp_vdev_detach(soc, wma_handle, vdev_id);
+	wma_handle->interfaces[vdev_id].vdev = NULL;
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID);
 	wma_handle->interfaces[vdev_id].vdev_active = false;
-	txrx_vdev_handle = NULL;
 
 	return QDF_STATUS_E_FAILURE;
 }
@@ -3385,7 +3433,7 @@ QDF_STATUS wma_pre_vdev_start_setup(uint8_t vdev_id,
 
 	vdev = wlan_vdev_get_dp_handle(iface->vdev);
 	if (!vdev) {
-		wma_err("Failed to get vdev handle: %d", vdev_id);
+		wma_err("Failed to get dp handle fro vdev id %d", vdev_id);
 		return QDF_STATUS_E_FAILURE;
 	}
 

+ 1 - 5
core/wma/src/wma_main.c

@@ -4600,12 +4600,8 @@ QDF_STATUS wma_wmi_service_close(void)
 	wmi_unified_detach(wma_handle->wmi_handle);
 	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]);
+	for (i = 0; i < wma_handle->max_bssid; i++)
 		wma_vdev_deinit(&wma_handle->interfaces[i]);
-	}
 
 	qdf_mem_free(wma_handle->interfaces);
 

+ 2 - 1
core/wma/src/wma_mgmt.c

@@ -554,7 +554,8 @@ int wma_unified_bcntx_status_event_handler(void *handle,
 	dp_handle = wlan_vdev_get_dp_handle
 			(wma->interfaces[resp_event->vdev_id].vdev);
 	if (!dp_handle) {
-		WMA_LOGE("%s: The session does not exist", __func__);
+		WMA_LOGE("%s: Failed to get dp handle for vdev id %d",
+			 __func__, resp_event->vdev_id);
 		return -EINVAL;
 	}
 

+ 1 - 1
core/wma/src/wma_utils.c

@@ -1994,7 +1994,7 @@ QDF_STATUS wma_process_ll_stats_clear_req(tp_wma_handle wma,
 	}
 
 	if (!wlan_vdev_get_dp_handle(vdev)) {
-		WMA_LOGE("%s: vdev_id %d handle is NULL",
+		WMA_LOGE("%s: vdev_id %d dp handle is NULL",
 			 __func__, clearReq->staId);
 		return QDF_STATUS_E_FAILURE;
 	}