Browse Source

qcacld-3.0: Do not sched IPA UC op work when de-init is in progress

In the scenario where IPA UC ready work is processed after
wlan_ipa_uc_ol_deinit, triggered as part of idle shutdown,
there is a possibility for NULL wbm srng pointer derefernce
when setting the tx doorbell address.

Fix is to avoid scheduling UC op work when deinit is in
progress.

Change-Id: Ifa0908912b77f45b7d93c5f9c2f5aaf9e17685c5
CRs-Fixed: 2807218
Yeshwanth Sriram Guntuka 4 years ago
parent
commit
fd1b019165
2 changed files with 18 additions and 9 deletions
  1. 1 0
      components/ipa/core/inc/wlan_ipa_priv.h
  2. 17 9
      components/ipa/core/src/wlan_ipa_core.c

+ 1 - 0
components/ipa/core/inc/wlan_ipa_priv.h

@@ -710,6 +710,7 @@ struct wlan_ipa_priv {
 	bool is_smmu_enabled;	/* IPA caps returned from ipa_wdi_init */
 	qdf_atomic_t stats_quota;
 	uint8_t curr_bw_level;
+	qdf_atomic_t deinit_in_prog;
 };
 
 #define WLAN_IPA_WLAN_FRAG_HEADER        sizeof(struct frag_header)

+ 17 - 9
components/ipa/core/src/wlan_ipa_core.c

@@ -168,7 +168,13 @@ static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt)
 		goto done;
 
 	uc_op_work->msg = msg;
-	qdf_sched_work(0, &uc_op_work->work);
+
+	if (!qdf_atomic_read(&ipa_ctx->deinit_in_prog)) {
+		qdf_sched_work(0, &uc_op_work->work);
+	} else {
+		uc_op_work->msg = NULL;
+		goto done;
+	}
 
 	/* work handler will free the msg buffer */
 	return;
@@ -3210,6 +3216,7 @@ QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx,
 	qdf_list_create(&ipa_ctx->pending_event, 1000);
 	qdf_mutex_create(&ipa_ctx->event_lock);
 	qdf_mutex_create(&ipa_ctx->ipa_lock);
+	qdf_atomic_init(&ipa_ctx->deinit_in_prog);
 
 	status = wlan_ipa_wdi_setup_rm(ipa_ctx);
 	if (status != QDF_STATUS_SUCCESS)
@@ -3767,6 +3774,15 @@ QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
 
 	wlan_ipa_uc_disable_pipes(ipa_ctx, true);
 
+	cdp_ipa_deregister_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev_id);
+	qdf_atomic_set(&ipa_ctx->deinit_in_prog, 1);
+
+	for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
+		qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
+		qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
+		ipa_ctx->uc_op_work[i].msg = NULL;
+	}
+
 	if (true == ipa_ctx->uc_loaded) {
 		cdp_ipa_tx_buf_smmu_unmapping(ipa_ctx->dp_soc,
 					      ipa_ctx->dp_pdev_id);
@@ -3783,14 +3799,6 @@ QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
 	wlan_ipa_cleanup_pending_event(ipa_ctx);
 	qdf_mutex_release(&ipa_ctx->ipa_lock);
 
-	cdp_ipa_deregister_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev_id);
-
-	for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
-		qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
-		qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
-		ipa_ctx->uc_op_work[i].msg = NULL;
-	}
-
 	ipa_debug("exit: ret=%d", status);
 	return status;
 }