trace: ess: change reset policy after panic occurred
authorHyunki Koo <hyunki00.koo@samsung.com>
Sun, 9 Aug 2015 07:20:49 +0000 (16:20 +0900)
committerJaehyoung Choi <jkkkkk.choi@samsung.com>
Wed, 9 May 2018 11:27:47 +0000 (20:27 +0900)
In 4.9 kernel porting,
I excluded 'exynos-ss.c' file from this patch.

This patch changes the reset policy in exynos-snapshot after kernel
panic occurred. It is changed from watchdog reset to s/w reset, but
if hardlockup is detection at any cores, watchdog reset should be
used to get the information from cores.

This reset policy is only applied when EXYNOS_SNAPSHOT_WATCHDOG_RESET
enabled. Exynos-snapshot supports adding for more action in pre/post
panic function.

Change-Id: I21cbae6281c6db5482a52af5478143a524854aff
Signed-off-by: Hosung Kim <hosung0.kim@samsung.com>
Signed-off-by: Hyunki Koo <hyunki00.koo@samsung.com>
Signed-off-by: Choi Jaehyoung <jkkkkk.choi@samsung.com>
drivers/watchdog/s3c2410_wdt.c

index cf507b4862042e55c01a4a9d9099cd1cac47e2d4..1c1fe16bdbe635d72b0a193e16655e6f9074d2a1 100644 (file)
@@ -131,6 +131,8 @@ struct s3c2410_wdt {
        struct regmap *pmureg;
 };
 
+static struct s3c2410_wdt *s3c_wdt;
+
 static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
        .quirks = 0
 };
@@ -561,6 +563,46 @@ s3c2410_get_wdt_drv_data(struct platform_device *pdev)
        return variant;
 }
 
+int s3c2410wdt_set_emergency_stop(void)
+{
+       struct s3c2410_wdt *wdt = s3c_wdt;
+       if (!s3c_wdt)
+               return -ENODEV;
+
+       /* stop watchdog */
+       pr_emerg("%s: watchdog is stopped\n", __func__);
+       s3c2410wdt_stop(&wdt->wdt_device);
+       return 0;
+}
+
+#ifdef CONFIG_EXYNOS_SNAPSHOT_WATCHDOG_RESET
+static int s3c2410wdt_panic_handler(struct notifier_block *nb,
+                                  unsigned long l, void *buf)
+{
+       struct s3c2410_wdt *wdt = s3c_wdt;
+
+       if (!s3c_wdt)
+               return -ENODEV;
+
+       /* We assumed that num_online_cpus() > 1 status is abnormal */
+       if (exynos_ss_get_hardlockup() || num_online_cpus() > 1) {
+
+               pr_emerg("%s: watchdog reset is started on panic after 5secs\n", __func__);
+
+               /* set watchdog timer is started and  set by 5 seconds*/
+               s3c2410wdt_start(&wdt->wdt_device);
+               s3c2410wdt_set_heartbeat(&wdt->wdt_device, 5);
+               s3c2410wdt_keepalive(&wdt->wdt_device);
+       }
+
+       return 0;
+}
+
+static struct notifier_block nb_panic_block = {
+       .notifier_call = s3c2410wdt_panic_handler,
+};
+#endif
+
 static int s3c2410wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -578,6 +620,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        wdt->dev = dev;
        spin_lock_init(&wdt->lock);
        wdt->wdt_device = s3c2410_wdd;
+       s3c_wdt = wdt;
 
        wdt->drv_data = s3c2410_get_wdt_drv_data(pdev);
        if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
@@ -692,6 +735,10 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
        wtcon = readl(wdt->reg_base + S3C2410_WTCON);
 
+#ifdef CONFIG_EXYNOS_SNAPSHOT_WATCHDOG_RESET
+       /* register panic handler for watchdog reset */
+       atomic_notifier_chain_register(&panic_notifier_list, &nb_panic_block);
+#endif
        dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
                 (wtcon & S3C2410_WTCON_ENABLE) ?  "" : "in",
                 (wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis",