From ad4ce8c7d25d756f4a972f8ba2f505408d870c1e Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Fri, 18 Oct 2019 11:19:58 -0700 Subject: [PATCH] soc: qcom: Add watchdog bite in panic Add watchdog bite in panic by registering a restart handler. Also add support for an earlier watchdog bite in the panic handler itself, which should provide a better context for post-mortem analysis. Change-Id: Ib6530fa754b78fd26a9f7d5a348b1e7ceb3c1f96 Signed-off-by: Elliot Berman --- drivers/power/reset/msm-poweroff.c | 7 ------- drivers/soc/qcom/Kconfig | 12 +++++++++++- drivers/soc/qcom/qcom_watchdog.c | 28 ++++++++++++++++++++++++++++ include/soc/qcom/watchdog.h | 6 ++++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 90ed9c594017..2ed23eb4b888 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -502,13 +502,6 @@ static int do_msm_restart(struct notifier_block *unused, unsigned long action, msm_restart_prepare(cmd); - /* - * Trigger a watchdog bite here and if this fails, - * device will take the usual restart path. - */ - if (WDOG_BITE_ON_PANIC && in_panic) - msm_trigger_wdog_bite(); - qcom_scm_disable_sdi(); qcom_scm_halt_spmi_pmic_arbiter(); deassert_ps_hold(); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 2aa6c77f96d9..bccdb81a0502 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -783,7 +783,7 @@ config QCOM_WATCHDOG not catch any early lockups. config QCOM_FORCE_WDOG_BITE_ON_PANIC - bool "QCOM force watchdog bite" + bool "QCOM force watchdog bite on panic" depends on QCOM_WATCHDOG help This forces a watchdog bite when the device restarts @@ -791,6 +791,16 @@ config QCOM_FORCE_WDOG_BITE_ON_PANIC this provides additional debugging information. +config QCOM_WDOG_BITE_EARLY_PANIC + bool "QCOM early panic watchdog bite" + depends on QCOM_WATCHDOG && QCOM_FORCE_WDOG_BITE_ON_PANIC + help + This forces a watchdog bite early in panic sequence. On certain + MSM SoCs, this provides us additional debugging information at the + context of the crash. If this option is disabled, then bite occurs + later in panic, which permits more of the restart sequence to run + (e.g. more dmesg to flushed to console). + config MSM_SPCOM depends on QCOM_GLINK tristate "Secure Processor Communication over RPMSG" diff --git a/drivers/soc/qcom/qcom_watchdog.c b/drivers/soc/qcom/qcom_watchdog.c index 623450a6dc0e..918274de9ed9 100644 --- a/drivers/soc/qcom/qcom_watchdog.c +++ b/drivers/soc/qcom/qcom_watchdog.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -68,8 +69,10 @@ struct msm_watchdog_data { cpumask_t alive_mask; struct mutex disable_lock; bool irq_ppi; + bool in_panic; struct msm_watchdog_data __percpu **wdog_cpu_dd; struct notifier_block panic_blk; + struct notifier_block restart_blk; bool enabled; bool user_pet_enabled; @@ -168,6 +171,11 @@ static int panic_wdog_handler(struct notifier_block *this, { struct msm_watchdog_data *wdog_dd = container_of(this, struct msm_watchdog_data, panic_blk); + wdog_dd->in_panic = true; + if (WDOG_BITE_EARLY_PANIC) { + pr_info("Triggering early bite\n"); + msm_trigger_wdog_bite(); + } if (panic_timeout == 0) { __raw_writel(0, wdog_dd->base + WDT0_EN); /* Make sure watchdog is enabled before notifying the caller */ @@ -206,6 +214,22 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd) dev_err(wdog_dd->dev, "MSM Apps Watchdog deactivated\n"); } +static int restart_wdog_handler(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct msm_watchdog_data *wdog_dd = container_of(this, + struct msm_watchdog_data, restart_blk); + if (WDOG_BITE_ON_PANIC && wdog_dd->in_panic) { + /* + * Trigger a watchdog bite here and if this fails, + * device will take the usual restart path. + */ + pr_info("Triggering late bite\n"); + msm_trigger_wdog_bite(); + } + return NOTIFY_DONE; +} + static ssize_t wdog_disable_get(struct device *dev, struct device_attribute *attr, char *buf) { @@ -587,9 +611,13 @@ static void init_watchdog_data(struct msm_watchdog_data *wdog_dd) __raw_writel(timeout, wdog_dd->base + WDT0_BARK_TIME); __raw_writel(timeout + 3*WDT_HZ, wdog_dd->base + WDT0_BITE_TIME); + wdog_dd->panic_blk.priority = WDOG_BITE_EARLY_PANIC ? INT_MAX - 1 : 0; wdog_dd->panic_blk.notifier_call = panic_wdog_handler; atomic_notifier_chain_register(&panic_notifier_list, &wdog_dd->panic_blk); + wdog_dd->restart_blk.priority = 255; + wdog_dd->restart_blk.notifier_call = restart_wdog_handler; + register_restart_handler(&wdog_dd->restart_blk); mutex_init(&wdog_dd->disable_lock); init_waitqueue_head(&wdog_dd->pet_complete); wdog_dd->timer_expired = false; diff --git a/include/soc/qcom/watchdog.h b/include/soc/qcom/watchdog.h index 4fa91eedb880..a69ef8b9c7db 100644 --- a/include/soc/qcom/watchdog.h +++ b/include/soc/qcom/watchdog.h @@ -12,6 +12,12 @@ #define WDOG_BITE_ON_PANIC 0 #endif +#ifdef CONFIG_QCOM_WDOG_BITE_EARLY_PANIC +#define WDOG_BITE_EARLY_PANIC 1 +#else +#define WDOG_BITE_EARLY_PANIC 0 +#endif + #if IS_ENABLED(CONFIG_QCOM_WATCHDOG) void msm_trigger_wdog_bite(void); #else