Просмотр исходного кода

qcacld-3.0: Fix dp_rx_thread hang issue

Issue happens as below scenaio:
1 suspend happens, but dp_rx_thread didn't finish in time,
  so timeout happens for suspend_event, here suspend will
  return success to kernel.
2 resume happens before dp_rx_thread to reset resume_event,
  and resume finished.
3 if dp_rx_thread finished and blocking with resume_event,
  and in following test, suspend didn't come(longer then
  hang detect time).
4 hang detect will alarm.

Fix is to return failure if dp_rx_thread can't be suspend
in time. Suspend can triger again later.

Change-Id: Ifbfdef5bb1c8d6e00b8fa5cc5e6dc74d3495c9ea
CRs-Fixed: 2626468
Jingxiang Ge 5 лет назад
Родитель
Сommit
9a4d95c3fd
3 измененных файлов с 30 добавлено и 12 удалено
  1. 23 8
      core/dp/txrx3.0/dp_rx_thread.c
  2. 2 0
      core/dp/txrx3.0/dp_rx_thread.h
  3. 5 4
      core/hdd/src/wlan_hdd_power.c

+ 23 - 8
core/dp/txrx3.0/dp_rx_thread.c

@@ -407,7 +407,6 @@ static int dp_rx_thread_sub_loop(struct dp_rx_thread *rx_thread, bool *shutdown)
 			dp_debug("received suspend ind (%s) id %d pid %d",
 				 qdf_get_current_comm(), rx_thread->id,
 				 qdf_get_current_pid());
-			qdf_event_reset(&rx_thread->resume_event);
 			qdf_event_set(&rx_thread->suspend_event);
 			dp_debug("waiting for resume (%s) id %d pid %d",
 				 qdf_get_current_comm(), rx_thread->id,
@@ -648,7 +647,7 @@ ret:
  * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread
  *            infrastructure
  *
- * Return: QDF_STATUS_SUCCESS
+ * Return: Success/Failure
  */
 QDF_STATUS dp_rx_tm_suspend(struct dp_rx_tm_handle *rx_tm_hdl)
 {
@@ -661,9 +660,12 @@ QDF_STATUS dp_rx_tm_suspend(struct dp_rx_tm_handle *rx_tm_hdl)
 		return QDF_STATUS_E_INVAL;
 	}
 
+	rx_tm_hdl->state = DP_RX_THREADS_SUSPENDING;
+
 	for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) {
 		if (!rx_tm_hdl->rx_thread[i])
 			continue;
+		qdf_event_reset(&rx_tm_hdl->rx_thread[i]->resume_event);
 		qdf_event_reset(&rx_tm_hdl->rx_thread[i]->suspend_event);
 		qdf_set_bit(RX_SUSPEND_EVENT,
 			    &rx_tm_hdl->rx_thread[i]->event_flag);
@@ -679,16 +681,22 @@ QDF_STATUS dp_rx_tm_suspend(struct dp_rx_tm_handle *rx_tm_hdl)
 						   DP_RX_THREAD_WAIT_TIMEOUT);
 		if (QDF_IS_STATUS_SUCCESS(qdf_status))
 			dp_debug("thread:%d suspended", rx_thread->id);
-		else if (qdf_status == QDF_STATUS_E_TIMEOUT)
-			dp_err("thread:%d timed out waiting for suspend",
-			       rx_thread->id);
 		else
-			dp_err("thread:%d failed while waiting for suspend",
-			       rx_thread->id);
+			goto suspend_fail;
 	}
 	rx_tm_hdl->state = DP_RX_THREADS_SUSPENDED;
 
 	return QDF_STATUS_SUCCESS;
+
+suspend_fail:
+	dp_err("thread:%d %s(%d) while waiting for suspend",
+	       rx_thread->id,
+	       qdf_status == QDF_STATUS_E_TIMEOUT ? "timeout out" : "failed",
+	       qdf_status);
+
+	dp_rx_tm_resume(rx_tm_hdl);
+
+	return qdf_status;
 }
 
 /**
@@ -781,7 +789,8 @@ QDF_STATUS dp_rx_tm_resume(struct dp_rx_tm_handle *rx_tm_hdl)
 {
 	int i;
 
-	if (rx_tm_hdl->state != DP_RX_THREADS_SUSPENDED) {
+	if (rx_tm_hdl->state != DP_RX_THREADS_SUSPENDED &&
+	    rx_tm_hdl->state != DP_RX_THREADS_SUSPENDING) {
 		dp_info("resume callback received w/o suspend! Ignoring.");
 		return QDF_STATUS_E_INVAL;
 	}
@@ -790,6 +799,12 @@ QDF_STATUS dp_rx_tm_resume(struct dp_rx_tm_handle *rx_tm_hdl)
 		if (!rx_tm_hdl->rx_thread[i])
 			continue;
 		dp_debug("calling thread %d to resume", i);
+
+		/* postively reset event_flag for DP_RX_THREADS_SUSPENDING
+		 * state
+		 */
+		qdf_clear_bit(RX_SUSPEND_EVENT,
+			      &rx_tm_hdl->rx_thread[i]->event_flag);
 		qdf_event_set(&rx_tm_hdl->rx_thread[i]->resume_event);
 	}
 

+ 2 - 0
core/dp/txrx3.0/dp_rx_thread.h

@@ -110,11 +110,13 @@ struct dp_rx_thread {
  * @DP_RX_THREADS_INVALID: initial invalid state
  * @DP_RX_THREADS_RUNNING: rx threads functional(NOT suspended, processing
  *			  packets or waiting on a wait_queue)
+ * @DP_RX_THREADS_SUSPENDING: rx thread is suspending
  * @DP_RX_THREADS_SUSPENDED: rx_threads suspended from cfg8011 suspend
  */
 enum dp_rx_thread_state {
 	DP_RX_THREADS_INVALID,
 	DP_RX_THREADS_RUNNING,
+	DP_RX_THREADS_SUSPENDING,
 	DP_RX_THREADS_SUSPENDED
 };
 

+ 5 - 4
core/hdd/src/wlan_hdd_power.c

@@ -1958,14 +1958,16 @@ static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy,
 			goto resume_ol_rx;
 	}
 
-	if (hdd_ctx->enable_dp_rx_threads)
-		dp_txrx_suspend(cds_get_context(QDF_MODULE_ID_SOC));
+	if (hdd_ctx->enable_dp_rx_threads) {
+		if (dp_txrx_suspend(cds_get_context(QDF_MODULE_ID_SOC)))
+			goto resume_ol_rx;
+	}
 
 	if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc)) {
 		adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE);
 		if (adapter)
 			if (ucfg_pkt_capture_suspend_mon_thread(adapter->vdev))
-				goto resume_pkt_capture_mon_thread;
+				goto resume_dp_thread;
 	}
 
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
@@ -1988,7 +1990,6 @@ resume_dp_thread:
 	if (hdd_ctx->enable_dp_rx_threads)
 		dp_txrx_resume(cds_get_context(QDF_MODULE_ID_SOC));
 
-resume_pkt_capture_mon_thread:
 	/* Resume packet capture MON thread */
 	if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc)) {
 		adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE);