瀏覽代碼

qcacld-3.0: Add support for SSR within SSR

Add below changes to support SSR within SSR,
1.Add new driver state, CDS_DRIVER_STATE_BAD, which will be set
  on re-init failure and reset on re-init success and if this
  state is set, don't allow any north-bound calls.
2.Don't de-register wiphy/netdev on re-init failure.
3.BUG_ON if re-init or probe fails successively for two times.
4.During driver unload, don't wait for SSR to be completed.

Change-Id: Id05a3e4b592664c9b56c7dd83b965b973f1d5ca5
CRs-Fixed: 2037628
Hanumanth Reddy Pothula 7 年之前
父節點
當前提交
2a8a740a4d

+ 1 - 1
core/bmi/src/ol_fw.c

@@ -623,7 +623,7 @@ void ol_target_failure(void *instance, QDF_STATUS status)
 		return;
 	}
 
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		BMI_ERR("%s: Recovery in progress, ignore!\n", __func__);
 		return;
 	}

+ 28 - 0
core/cds/inc/cds_api.h

@@ -64,6 +64,7 @@
  * CDS_DRIVER_STATE_LOADING: Driver probe is in progress.
  * CDS_DRIVER_STATE_UNLOADING: Driver remove is in progress.
  * CDS_DRIVER_STATE_RECOVERING: Recovery in progress.
+ * CDS_DRIVER_STATE_BAD: Driver in bad state.
  */
 enum cds_driver_state {
 	CDS_DRIVER_STATE_UNINITIALIZED	= 0,
@@ -71,6 +72,7 @@ enum cds_driver_state {
 	CDS_DRIVER_STATE_LOADING	= BIT(1),
 	CDS_DRIVER_STATE_UNLOADING	= BIT(2),
 	CDS_DRIVER_STATE_RECOVERING	= BIT(3),
+	CDS_DRIVER_STATE_BAD		= BIT(4)
 };
 
 #define __CDS_IS_DRIVER_STATE(_state, _mask) (((_state) & (_mask)) == (_mask))
@@ -171,6 +173,18 @@ static inline bool cds_is_driver_recovering(void)
 	return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_RECOVERING);
 }
 
+/**
+ * cds_is_driver_in_bad_state() - is driver in bad state
+ *
+ * Return: true if driver is in bad state and false otherwise.
+ */
+static inline bool cds_is_driver_in_bad_state(void)
+{
+	enum cds_driver_state state = cds_get_driver_state();
+
+	return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_BAD);
+}
+
 /**
  * cds_is_load_or_unload_in_progress() - Is driver load OR unload in progress
  *
@@ -224,6 +238,20 @@ static inline void cds_set_recovery_in_progress(uint8_t value)
 		cds_clear_driver_state(CDS_DRIVER_STATE_RECOVERING);
 }
 
+/**
+ * cds_set_driver_in_bad_state() - Set driver state
+ * @value: value to set
+ *
+ * Return: none
+ */
+static inline void cds_set_driver_in_bad_state(uint8_t value)
+{
+	if (value)
+		cds_set_driver_state(CDS_DRIVER_STATE_BAD);
+	else
+		cds_clear_driver_state(CDS_DRIVER_STATE_BAD);
+}
+
 /**
  * cds_set_load_in_progress() - Set load in progress
  * @value: value to set

+ 5 - 5
core/cds/src/cds_api.c

@@ -1002,8 +1002,8 @@ QDF_STATUS cds_post_disable(void)
 	 * - Clean up CE tasklets.
 	 */
 
-	cds_info("send denint sequence to firmware");
-	if (!cds_is_driver_recovering())
+	cds_info("send deinit sequence to firmware");
+	if (!(cds_is_driver_recovering() || cds_is_driver_in_bad_state()))
 		cds_suspend_target(wma_handle);
 	hif_disable_isr(hif_ctx);
 	hif_reset_soc(hif_ctx);
@@ -1718,7 +1718,7 @@ bool cds_is_packet_log_enabled(void)
 
 static void cds_config_recovery_work(qdf_device_t qdf_ctx)
 {
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
 			"Recovery is in progress, ignore!");
 	} else {
@@ -2118,7 +2118,7 @@ uint32_t cds_get_log_indicator(void)
 	}
 
 	if (cds_is_load_or_unload_in_progress() ||
-	    cds_is_driver_recovering()) {
+	    cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		return WLAN_LOG_INDICATOR_UNUSED;
 	}
 
@@ -2179,7 +2179,7 @@ QDF_STATUS cds_flush_logs(uint32_t is_fatal,
 		return QDF_STATUS_E_FAILURE;
 	}
 	if (cds_is_load_or_unload_in_progress() ||
-	    cds_is_driver_recovering()) {
+	    cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
 				"%s: un/Load/SSR in progress", __func__);
 		return QDF_STATUS_E_FAILURE;

+ 26 - 5
core/hdd/src/wlan_hdd_driver_ops.c

@@ -56,6 +56,9 @@
 
 #define DISABLE_KRAIT_IDLE_PS_VAL      1
 
+#define SSR_MAX_FAIL_CNT 2
+static uint8_t re_init_fail_cnt, probe_fail_cnt;
+
 /*
  * In BMI Phase we are only sending small chunk (256 bytes) of the FW image at
  * a time, and wait for the completion interrupt to start the next transfer.
@@ -349,10 +352,15 @@ static int wlan_hdd_probe(struct device *dev, void *bdev,
 
 	hdd_init_qdf_ctx(dev, bdev, bus_type, (const struct hif_bus_id *)bid);
 
-	if (reinit)
+	if (reinit) {
 		ret = hdd_wlan_re_init();
-	else
+		if (ret)
+			re_init_fail_cnt++;
+	} else {
 		ret = hdd_wlan_startup(dev);
+		if (ret)
+			probe_fail_cnt++;
+	}
 
 	if (ret)
 		goto err_hdd_deinit;
@@ -370,14 +378,27 @@ static int wlan_hdd_probe(struct device *dev, void *bdev,
 
 	cds_set_fw_down(false);
 
+	cds_set_driver_in_bad_state(false);
+	probe_fail_cnt = 0;
+	re_init_fail_cnt = 0;
+
 	return 0;
 
 
 err_hdd_deinit:
-	if (reinit)
+	pr_err("probe/reinit failure counts %hhu/%hhu",
+		probe_fail_cnt, re_init_fail_cnt);
+	if (probe_fail_cnt >= SSR_MAX_FAIL_CNT ||
+	    re_init_fail_cnt >= SSR_MAX_FAIL_CNT)
+		QDF_BUG(0);
+
+	if (reinit) {
+		cds_set_driver_in_bad_state(true);
 		cds_set_recovery_in_progress(false);
+	}
 	else
 		cds_set_load_in_progress(false);
+
 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT);
 	hdd_remove_pm_qos(dev);
 
@@ -404,7 +425,6 @@ static void wlan_hdd_remove(struct device *dev)
 	pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME,
 		QWLAN_VERSIONSTR);
 
-
 	cds_set_driver_loaded(false);
 	cds_set_unload_in_progress(true);
 
@@ -420,6 +440,7 @@ static void wlan_hdd_remove(struct device *dev)
 		__hdd_wlan_exit();
 	}
 
+	cds_set_driver_in_bad_state(false);
 	cds_set_unload_in_progress(false);
 
 	pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME);
@@ -846,7 +867,7 @@ static int __wlan_hdd_bus_resume(void)
 	return 0;
 
 out:
-	if (cds_is_driver_recovering())
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state())
 		return 0;
 
 	QDF_BUG(false);

+ 1 - 1
core/hdd/src/wlan_hdd_ioctl.c

@@ -2304,7 +2304,7 @@ static int wlan_hdd_get_link_status(hdd_adapter_t *adapter)
 		.timeout_ms = WLAN_WAIT_TIME_LINK_STATUS,
 	};
 
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!",
 			 cds_get_driver_state());
 		return 0;

+ 9 - 3
core/hdd/src/wlan_hdd_main.c

@@ -414,7 +414,7 @@ static int __hdd_netdev_notifier_call(struct notifier_block *nb,
 		QDF_ASSERT(0);
 		return NOTIFY_DONE;
 	}
-	if (cds_is_driver_recovering())
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state())
 		return NOTIFY_DONE;
 
 	hdd_debug("%s New Net Device State = %lu",
@@ -627,6 +627,12 @@ int wlan_hdd_validate_context(hdd_context_t *hdd_ctx)
 		return -EAGAIN;
 	}
 
+	if (cds_is_driver_in_bad_state()) {
+		hdd_debug("%pS driver in bad State: 0x%x Ignore!!!",
+			(void *)_RET_IP_, cds_get_driver_state());
+		return -ENODEV;
+	}
+
 	return 0;
 }
 
@@ -1487,7 +1493,7 @@ void hdd_update_tgt_cfg(void *context, void *param)
 		hdd_warn("ini BandCapability not supported by the target");
 	}
 
-	if (!cds_is_driver_recovering()) {
+	if (!cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		hdd_ctx->reg.reg_domain = cfg->reg_domain;
 		hdd_ctx->reg.eeprom_rd_ext = cfg->eeprom_rd_ext;
 	}
@@ -5587,7 +5593,7 @@ static void hdd_wlan_exit(hdd_context_t *hdd_ctx)
 	 */
 	qdf_status = cds_sched_close(p_cds_context);
 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
-		hdd_err("Failed to close CDS Scheduler");
+		hdd_alert("Failed to close CDS Scheduler");
 		QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status));
 	}
 

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

@@ -135,9 +135,6 @@ void hdd_wlan_offload_event(uint8_t type, uint8_t state)
 
 extern struct notifier_block hdd_netdev_notifier;
 
-static struct timer_list ssr_timer;
-static bool ssr_timer_started;
-
 /**
  * hdd_enable_gtk_offload() - enable GTK offload
  * @adapter: pointer to the adapter
@@ -1081,7 +1078,7 @@ hdd_suspend_wlan(void)
 		return -EINVAL;
 	}
 
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!",
 			 cds_get_driver_state());
 		return -EINVAL;
@@ -1140,7 +1137,7 @@ static int hdd_resume_wlan(void)
 		return -EINVAL;
 	}
 
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!",
 			 cds_get_driver_state());
 		return -EINVAL;
@@ -1180,66 +1177,6 @@ next_adapter:
 	return 0;
 }
 
-/**
- * DOC: SSR Timer
- *
- * When SSR is initiated, an SSR timer is started.  Under normal
- * circumstances SSR should complete amd the timer should be deleted
- * before it fires.  If the SSR timer does fire, it indicates SSR has
- * taken too long, and our only recourse is to invoke the QDF_BUG()
- * API which can allow a crashdump to be captured.
- */
-
-/**
- * hdd_ssr_timer_init() - Initialize SSR Timer
- *
- * Return: None.
- */
-static void hdd_ssr_timer_init(void)
-{
-	init_timer(&ssr_timer);
-}
-
-/**
- * hdd_ssr_timer_del() - Delete SSR Timer
- *
- * Return: None.
- */
-static void hdd_ssr_timer_del(void)
-{
-	del_timer(&ssr_timer);
-	ssr_timer_started = false;
-}
-
-/**
- * hdd_ssr_timer_cb() - SSR Timer callback function
- * @data: opaque data registered with timer infrastructure
- *
- * Return: None.
- */
-static void hdd_ssr_timer_cb(unsigned long data)
-{
-	hdd_info("HDD SSR timer expired!");
-	QDF_BUG(0);
-}
-
-/**
- * hdd_ssr_timer_start() - Start SSR Timer
- * @msec: Timer timeout value in milliseconds
- *
- * Return: None.
- */
-static void hdd_ssr_timer_start(int msec)
-{
-	if (ssr_timer_started) {
-		hdd_debug("Trying to start SSR timer when " "it's running!");
-	}
-	ssr_timer.expires = jiffies + msecs_to_jiffies(msec);
-	ssr_timer.function = hdd_ssr_timer_cb;
-	add_timer(&ssr_timer);
-	ssr_timer_started = true;
-}
-
 /**
  * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace
  *
@@ -1312,10 +1249,6 @@ QDF_STATUS hdd_wlan_shutdown(void)
 
 	hdd_info("WLAN driver shutting down!");
 
-	/* If SSR never completes, then do kernel panic. */
-	hdd_ssr_timer_init();
-	hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME);
-
 	/* Get the global CDS context. */
 	p_cds_context = cds_get_global_context();
 	if (!p_cds_context) {
@@ -1459,7 +1392,7 @@ QDF_STATUS hdd_wlan_re_init(void)
 	ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true);
 	if (ret) {
 		hdd_err("Failed to start wlan after error");
-		goto err_wiphy_unregister;
+		goto err_re_init;
 	}
 
 	hdd_wlan_get_version(pHddCtx, NULL, NULL);
@@ -1498,26 +1431,7 @@ QDF_STATUS hdd_wlan_re_init(void)
 err_cds_disable:
 	hdd_wlan_stop_modules(pHddCtx, false);
 
-err_wiphy_unregister:
-	if (bug_on_reinit_failure)
-		QDF_BUG(0);
-
-	if (pHddCtx) {
-		/* Unregister the Notifier's */
-		hdd_unregister_notifiers(pHddCtx);
-		ptt_sock_deactivate_svc();
-		nl_srv_exit();
-
-		hdd_close_all_adapters(pHddCtx, false);
-		wlan_hdd_cfg80211_deinit(pHddCtx->wiphy);
-		hdd_lpass_notify_stop(pHddCtx);
-		wlan_hdd_deinit_tx_rx_histogram(pHddCtx);
-		wiphy_unregister(pHddCtx->wiphy);
-
-	}
-
 err_re_init:
-	hdd_ssr_timer_del();
 	/* Allow the phone to go to sleep */
 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT);
 	if (bug_on_reinit_failure)
@@ -1527,7 +1441,7 @@ err_re_init:
 success:
 	if (pHddCtx->config->sap_internal_restart)
 		hdd_ssr_restart_sap(pHddCtx);
-	hdd_ssr_timer_del();
+
 	hdd_wlan_ssr_reinit_event();
 	return QDF_STATUS_SUCCESS;
 }

+ 2 - 1
core/hdd/src/wlan_hdd_regulatory.c

@@ -696,7 +696,8 @@ void hdd_reg_notifier(struct wiphy *wiphy,
 		return;
 	}
 
-	if (cds_is_driver_unloading() || cds_is_driver_recovering()) {
+	if (cds_is_driver_unloading() || cds_is_driver_recovering() ||
+	    cds_is_driver_in_bad_state()) {
 		hdd_err("%s: unloading or ssr in progress, ignore",
 			__func__);
 		return;

+ 1 - 1
core/hdd/src/wlan_hdd_scan.c

@@ -1958,7 +1958,7 @@ static int __wlan_hdd_cfg80211_sched_scan_stop(struct net_device *dev)
 	 * clean up of the second interface will have the dev pointer corresponding
 	 * to the first one leading to a crash.
 	 */
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		hdd_info("Recovery in Progress. State: 0x%x Ignore!!!",
 			 cds_get_driver_state());
 		return 0;

+ 2 - 2
core/hdd/src/wlan_hdd_softap_tx_rx.c

@@ -262,7 +262,7 @@ static int __hdd_softap_hard_start_xmit(struct sk_buff *skb,
 	 * context may not be reinitialized at this time which may
 	 * lead to a crash.
 	 */
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH,
 			  "%s: Recovery in Progress. Ignore!!!", __func__);
 		goto drop_pkt;
@@ -526,7 +526,7 @@ static void __hdd_softap_tx_timeout(struct net_device *dev)
 	 * recovery here
 	 */
 	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR,
 			 "%s: Recovery in Progress. Ignore!!!", __func__);
 		return;

+ 2 - 1
core/hdd/src/wlan_hdd_tdls.c

@@ -4408,7 +4408,8 @@ static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy,
 			!rc ? "Mgmt Tx Completion timed out" : "Mgmt Tx Completion failed",
 			rc, pAdapter->mgmtTxCompletionStatus);
 
-		if (cds_is_driver_recovering()) {
+		if (cds_is_driver_recovering() ||
+		    cds_is_driver_in_bad_state()) {
 			hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
 				cds_get_driver_state());
 			return -EAGAIN;

+ 1 - 1
core/hdd/src/wlan_hdd_tx_rx.c

@@ -538,7 +538,7 @@ static int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 #endif
 
 	++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled;
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH,
 			"Recovery in progress, dropping the packet");
 		goto drop_pkt;

+ 2 - 2
core/hdd/src/wlan_hdd_wext.c

@@ -3547,7 +3547,7 @@ QDF_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, int8_t *rssi_value)
 		hdd_err("Invalid context, pAdapter");
 		return QDF_STATUS_E_FAULT;
 	}
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		hdd_err("Recovery in Progress. State: 0x%x Ignore!!!",
 			cds_get_driver_state());
 		/* return a cached value */
@@ -6135,7 +6135,7 @@ QDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter)
 		hdd_err("pAdapter is NULL");
 		return QDF_STATUS_E_FAULT;
 	}
-	if (cds_is_driver_recovering()) {
+	if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) {
 		hdd_debug("Recovery in Progress. State: 0x%x Ignore!!!",
 			 cds_get_driver_state());
 		return QDF_STATUS_SUCCESS;

+ 3 - 0
core/wma/src/wma_features.c

@@ -3877,6 +3877,9 @@ static inline void wma_suspend_target_timeout(bool is_self_recovery_enabled)
 	else if (cds_is_driver_recovering())
 		WMA_LOGE("%s: Module recovering; Ignoring suspend timeout",
 			 __func__);
+	else if (cds_is_driver_in_bad_state())
+		WMA_LOGE("%s: Module in bad state; Ignoring suspend timeout",
+			 __func__);
 	else if (is_self_recovery_enabled)
 		cds_trigger_recovery(false);
 	else

+ 11 - 0
core/wma/src/wma_mgmt.c

@@ -3490,6 +3490,17 @@ int wma_form_rx_packet(qdf_nbuf_t buf,
 		return -EINVAL;
 	}
 
+	if (cds_is_driver_in_bad_state()) {
+		limit_prints_recovery++;
+		if (limit_prints_recovery == RATE_LIMIT) {
+			WMA_LOGD(FL("Driver in bad state"));
+			limit_prints_recovery = 0;
+		}
+		qdf_nbuf_free(buf);
+		qdf_mem_free(rx_pkt);
+		return -EINVAL;
+	}
+
 	/*
 	 * Fill in meta information needed by pe/lim
 	 * TODO: Try to maintain rx metainfo as part of skb->data.