瀏覽代碼

icnss2: trigger wpss self recovery

Icnss driver receives early crash indication when
fatal error happens in wpss. In few cases rproc
framework didn't receive any notification regarding
wpss fatal crash due to which icnss driver wpss
notfier is not getting called. This prevents wpss ssr
recovery. To recover wpss from this scenerio icnss
driver tries to do self recovery of wpss subystem.

Change-Id: Ie22dfb6a6218aafd1fec84fb14f3efb16c60bf5e
CRs-Fixed: 3265930
Sandeep Singh 2 年之前
父節點
當前提交
172b8aee52
共有 2 個文件被更改,包括 47 次插入0 次删除
  1. 44 0
      icnss2/main.c
  2. 3 0
      icnss2/main.h

+ 44 - 0
icnss2/main.c

@@ -84,10 +84,12 @@ module_param(qmi_timeout, ulong, 0600);
 #endif
 
 #define ICNSS_RECOVERY_TIMEOUT		60000
+#define ICNSS_WPSS_SSR_TIMEOUT          5000
 #define ICNSS_CAL_TIMEOUT		40000
 
 static struct icnss_priv *penv;
 static struct work_struct wpss_loader;
+static struct work_struct wpss_ssr_work;
 uint64_t dynamic_feature_mask = ICNSS_DEFAULT_FEATURE_MASK;
 
 #define ICNSS_EVENT_PENDING			2989
@@ -536,6 +538,10 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
 
 	icnss_pr_err("Received early crash indication from FW\n");
 
+	if (priv->wpss_self_recovery_enabled)
+		mod_timer(&priv->wpss_ssr_timer,
+			  jiffies + msecs_to_jiffies(ICNSS_WPSS_SSR_TIMEOUT));
+
 	if (priv) {
 		set_bit(ICNSS_FW_DOWN, &priv->state);
 		icnss_ignore_fw_timeout(true);
@@ -1778,6 +1784,19 @@ static int icnss_subsys_restart_level(struct icnss_priv *priv, void *data)
 	return ret;
 }
 
+static void icnss_wpss_self_recovery(struct work_struct *wpss_load_work)
+{
+	int ret;
+	struct icnss_priv *priv = icnss_get_plat_priv();
+
+	rproc_shutdown(priv->rproc);
+	ret = rproc_boot(priv->rproc);
+	if (ret) {
+		icnss_pr_err("Failed to self recover wpss rproc, ret: %d", ret);
+		rproc_put(priv->rproc);
+	}
+}
+
 static void icnss_driver_event_work(struct work_struct *work)
 {
 	struct icnss_priv *priv =
@@ -2082,6 +2101,9 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb,
 	if (code != QCOM_SSR_BEFORE_SHUTDOWN)
 		goto out;
 
+	if (priv->wpss_self_recovery_enabled)
+		del_timer(&priv->wpss_ssr_timer);
+
 	priv->is_ssr = true;
 
 	icnss_pr_info("WPSS went down, state: 0x%lx, crashed: %d\n",
@@ -4330,6 +4352,10 @@ static void icnss_read_device_configs(struct icnss_priv *priv)
 				  "wlan-ipa-disabled")) {
 		set_bit(ICNSS_IPA_DISABLED, &priv->device_config);
 	}
+
+	if (of_property_read_bool(priv->pdev->dev.of_node,
+				  "qcom,wpss-self-recovery"))
+		priv->wpss_self_recovery_enabled = true;
 }
 
 static inline void icnss_runtime_pm_init(struct icnss_priv *priv)
@@ -4506,6 +4532,12 @@ static int icnss_probe(struct platform_device *pdev)
 	timer_setup(&priv->recovery_timer,
 		    icnss_recovery_timeout_hdlr, 0);
 
+	if (priv->wpss_self_recovery_enabled) {
+		INIT_WORK(&wpss_ssr_work, icnss_wpss_self_recovery);
+		timer_setup(&priv->wpss_ssr_timer,
+			    icnss_wpss_ssr_timeout_hdlr, 0);
+	}
+
 	INIT_LIST_HEAD(&priv->icnss_tcdev_list);
 
 	icnss_pr_info("Platform driver probed successfully\n");
@@ -4558,6 +4590,9 @@ static int icnss_remove(struct platform_device *pdev)
 
 	del_timer(&priv->recovery_timer);
 
+	if (priv->wpss_self_recovery_enabled)
+		del_timer(&priv->wpss_ssr_timer);
+
 	device_init_wakeup(&priv->pdev->dev, false);
 
 	icnss_debugfs_destroy(priv);
@@ -4624,6 +4659,15 @@ void icnss_recovery_timeout_hdlr(struct timer_list *t)
 	ICNSS_ASSERT(0);
 }
 
+void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t)
+{
+	struct icnss_priv *priv = from_timer(priv, t, wpss_ssr_timer);
+
+	icnss_pr_err("Timeout waiting for WPSS SSR notification 0x%lx\n",
+		      priv->state);
+	schedule_work(&wpss_ssr_work);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int icnss_pm_suspend(struct device *dev)
 {

+ 3 - 0
icnss2/main.h

@@ -503,6 +503,8 @@ struct icnss_priv {
 	u8 is_slate_rfa;
 	struct completion slate_boot_complete;
 	struct timer_list recovery_timer;
+	struct timer_list wpss_ssr_timer;
+	bool wpss_self_recovery_enabled;
 };
 
 struct icnss_reg_info {
@@ -531,5 +533,6 @@ void icnss_add_fw_prefix_name(struct icnss_priv *priv, char *prefix_name,
 			      char *name);
 int icnss_aop_mbox_init(struct icnss_priv *priv);
 void icnss_recovery_timeout_hdlr(struct timer_list *t);
+void icnss_wpss_ssr_timeout_hdlr(struct timer_list *t);
 #endif