diff --git a/icnss2/main.c b/icnss2/main.c index 72f3de7898..22aa75767b 100644 --- a/icnss2/main.c +++ b/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) { diff --git a/icnss2/main.h b/icnss2/main.h index c862781da8..1a09894946 100644 --- a/icnss2/main.h +++ b/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