From 7011182571af81e9cd139a135d0e163b3d1959bc Mon Sep 17 00:00:00 2001 From: Dustin Brown Date: Thu, 30 Mar 2017 15:31:40 -0700 Subject: [PATCH] qcacld-3.0: Prevent getting stuck in SSR with external thread During driver recovery, following a crash in firmware, there is a chance to get stuck waiting for the MC thread to exit after it has already done so. This is due to an external thread being active in the driver when it should not be possible. Improve logging in such cases to find out which thread is running, and skip waiting for MC thread shutdown if it is already stopped to prevent getting hung. Change-Id: I53ddc3afb8561ecd2d6b708b6488c503068c49a6 CRs-Fixed: 2027020 --- core/cds/inc/cds_sched.h | 1 + core/cds/src/cds_sched.c | 8 ++++++-- core/hdd/src/wlan_hdd_main.c | 24 ++++++++++++++++-------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/core/cds/inc/cds_sched.h b/core/cds/inc/cds_sched.h index 82c2a8e7bc94..c0d3e1bd32ba 100644 --- a/core/cds/inc/cds_sched.h +++ b/core/cds/inc/cds_sched.h @@ -444,6 +444,7 @@ void cds_ssr_protect_init(void); void cds_ssr_protect(const char *caller_func); void cds_ssr_unprotect(const char *caller_func); bool cds_wait_for_external_threads_completion(const char *caller_func); +void cds_print_external_threads(void); int cds_get_gfp_flags(void); /** diff --git a/core/cds/src/cds_sched.c b/core/cds/src/cds_sched.c index 4c5cb2dae13b..1b1748675146 100644 --- a/core/cds/src/cds_sched.c +++ b/core/cds/src/cds_sched.c @@ -855,12 +855,17 @@ QDF_STATUS cds_sched_close(void *p_cds_context) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, "%s: invoked", __func__); + if (gp_cds_sched_context == NULL) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: gp_cds_sched_context == NULL", __func__); return QDF_STATUS_E_FAILURE; } + #ifdef QCA_CONFIG_SMP + if (!gp_cds_sched_context->ol_rx_thread) + return QDF_STATUS_SUCCESS; + /* Shut down Tlshim Rx thread */ set_bit(RX_SHUTDOWN_EVENT, &gp_cds_sched_context->ol_rx_event_flag); set_bit(RX_POST_EVENT, &gp_cds_sched_context->ol_rx_event_flag); @@ -918,8 +923,7 @@ void cds_ssr_protect_init(void) * Return: * void */ - -static void cds_print_external_threads(void) +void cds_print_external_threads(void) { int i = 0; unsigned long irq_flags; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index dca5fbb955d5..d5337e9eb47f 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -8754,6 +8754,9 @@ int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx) QDF_STATUS qdf_status; int ret = 0; p_cds_sched_context cds_sched_context = NULL; + bool is_idle_stop = !cds_is_driver_unloading() && + !cds_is_driver_recovering(); + int active_threads; ENTER(); @@ -8773,14 +8776,19 @@ int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx) mutex_lock(&hdd_ctx->iface_change_lock); hdd_ctx->stop_modules_in_progress = true; - if (cds_return_external_threads_count() || hdd_ctx->isWiphySuspended) { - mutex_unlock(&hdd_ctx->iface_change_lock); + active_threads = cds_return_external_threads_count(); + if (active_threads > 0 || hdd_ctx->isWiphySuspended) { hdd_warn("External threads %d wiphy suspend %d", - cds_return_external_threads_count(), - hdd_ctx->isWiphySuspended); - qdf_mc_timer_start(&hdd_ctx->iface_change_timer, - hdd_ctx->config->iface_change_wait_time); - return 0; + active_threads, hdd_ctx->isWiphySuspended); + + cds_print_external_threads(); + + if (is_idle_stop) { + mutex_unlock(&hdd_ctx->iface_change_lock); + qdf_mc_timer_start(&hdd_ctx->iface_change_timer, + hdd_ctx->config->iface_change_wait_time); + return 0; + } } hdd_info("Present Driver Status: %d", hdd_ctx->driver_status); @@ -8837,7 +8845,7 @@ int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx) ol_cds_free(); - if (!cds_is_driver_recovering() && !cds_is_driver_unloading()) { + if (is_idle_stop) { ret = pld_power_off(qdf_ctx->dev); if (ret) hdd_err("CNSS power down failed put device into Low power mode:%d",