msm: modem-8960: Check if the modem is alive after restarting it
The modem is expected to enable its watchdog shortly after
it is booted up. Wait for 10 seconds after powering up
the modem and check if the modem watchdog has been enabled.
If not, restart the modem.
Change-Id: Iaeb2cb016a7a104f3370d8d589ff59c31c1fb1c8
Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 9a1e565..4922007 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -36,6 +36,8 @@
static int crash_shutdown;
#define MAX_SSR_REASON_LEN 81U
+#define Q6_FW_WDOG_ENABLE 0x08882024
+#define Q6_SW_WDOG_ENABLE 0x08982024
static void log_modem_sfr(void)
{
@@ -61,6 +63,27 @@
wmb();
}
+static void modem_wdog_check(struct work_struct *work)
+{
+ void __iomem *q6_sw_wdog_addr;
+ u32 regval;
+
+ q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4);
+ if (!q6_sw_wdog_addr)
+ panic("Unable to check modem watchdog status.\n");
+
+ regval = readl_relaxed(q6_sw_wdog_addr);
+ if (!regval) {
+ pr_err("modem-8960: Modem watchdog wasn't activated!. Restarting the modem now.\n");
+ log_modem_sfr();
+ subsystem_restart("modem");
+ }
+
+ iounmap(q6_sw_wdog_addr);
+}
+
+static DECLARE_DELAYED_WORK(modem_wdog_check_work, modem_wdog_check);
+
static void modem_sw_fatal_fn(struct work_struct *work)
{
uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
@@ -115,14 +138,18 @@
}
}
-#define Q6_FW_WDOG_ENABLE 0x08882024
-#define Q6_SW_WDOG_ENABLE 0x08982024
static int modem_shutdown(const struct subsys_data *subsys)
{
void __iomem *q6_fw_wdog_addr;
void __iomem *q6_sw_wdog_addr;
/*
+ * Cancel any pending wdog_check work items, since we're shutting
+ * down anyway.
+ */
+ cancel_delayed_work(&modem_wdog_check_work);
+
+ /*
* Disable the modem watchdog since it keeps running even after the
* modem is shutdown.
*/
@@ -150,12 +177,16 @@
return 0;
}
+#define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
+
static int modem_powerup(const struct subsys_data *subsys)
{
pil_force_boot("modem_fw");
pil_force_boot("modem");
enable_irq(Q6FW_WDOG_EXPIRED_IRQ);
enable_irq(Q6SW_WDOG_EXPIRED_IRQ);
+ schedule_delayed_work(&modem_wdog_check_work,
+ msecs_to_jiffies(MODEM_WDOG_CHECK_TIMEOUT_MS));
return 0;
}