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

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 лет назад
Родитель
Сommit
7011182571
3 измененных файлов с 23 добавлено и 10 удалено
  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_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);
 
 /**

+ 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,
 		  "%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;

+ 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;
 	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",