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
This commit is contained in:
Jingxiang Ge 2020-02-20 23:15:15 +08:00 • committed by nshrivas
commit 9a4d95c3fd
3 changed files with 30 additions and 12 deletions

View file

@ -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);
}

View file

@ -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
};

View file

@ -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);