Browse Source

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
Dustin Brown 8 years ago
parent
commit
7011182571
3 changed files with 23 additions and 10 deletions
  1. 1 0
      core/cds/inc/cds_sched.h
  2. 6 2
      core/cds/src/cds_sched.c
  3. 16 8
      core/hdd/src/wlan_hdd_main.c

+ 1 - 0
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_protect(const char *caller_func);
 void cds_ssr_unprotect(const char *caller_func);
 void cds_ssr_unprotect(const char *caller_func);
 bool cds_wait_for_external_threads_completion(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);
 int cds_get_gfp_flags(void);
 
 
 /**
 /**

+ 6 - 2
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,
 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH,
 		  "%s: invoked", __func__);
 		  "%s: invoked", __func__);
+
 	if (gp_cds_sched_context == NULL) {
 	if (gp_cds_sched_context == NULL) {
 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
 			  "%s: gp_cds_sched_context == NULL", __func__);
 			  "%s: gp_cds_sched_context == NULL", __func__);
 		return QDF_STATUS_E_FAILURE;
 		return QDF_STATUS_E_FAILURE;
 	}
 	}
+
 #ifdef QCA_CONFIG_SMP
 #ifdef QCA_CONFIG_SMP
+	if (!gp_cds_sched_context->ol_rx_thread)
+		return QDF_STATUS_SUCCESS;
+
 	/* Shut down Tlshim Rx thread */
 	/* Shut down Tlshim Rx thread */
 	set_bit(RX_SHUTDOWN_EVENT, &gp_cds_sched_context->ol_rx_event_flag);
 	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);
 	set_bit(RX_POST_EVENT, &gp_cds_sched_context->ol_rx_event_flag);
@@ -918,8 +923,7 @@ void cds_ssr_protect_init(void)
  * Return:
  * Return:
  *        void
  *        void
  */
  */
-
-static void cds_print_external_threads(void)
+void cds_print_external_threads(void)
 {
 {
 	int i = 0;
 	int i = 0;
 	unsigned long irq_flags;
 	unsigned long irq_flags;

+ 16 - 8
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;
 	QDF_STATUS qdf_status;
 	int ret = 0;
 	int ret = 0;
 	p_cds_sched_context cds_sched_context = NULL;
 	p_cds_sched_context cds_sched_context = NULL;
+	bool is_idle_stop = !cds_is_driver_unloading() &&
+		!cds_is_driver_recovering();
+	int active_threads;
 
 
 	ENTER();
 	ENTER();
 
 
@@ -8773,14 +8776,19 @@ int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx)
 	mutex_lock(&hdd_ctx->iface_change_lock);
 	mutex_lock(&hdd_ctx->iface_change_lock);
 	hdd_ctx->stop_modules_in_progress = true;
 	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",
 		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);
 	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();
 	ol_cds_free();
 
 
-	if (!cds_is_driver_recovering() && !cds_is_driver_unloading()) {
+	if (is_idle_stop) {
 		ret = pld_power_off(qdf_ctx->dev);
 		ret = pld_power_off(qdf_ctx->dev);
 		if (ret)
 		if (ret)
 			hdd_err("CNSS power down failed put device into Low power mode:%d",
 			hdd_err("CNSS power down failed put device into Low power mode:%d",