OSDN Git Service

watchdog: stmp3xxx: Stop the watchdog on system halt
authorHarald Geyer <harald@ccbib.org>
Sat, 12 Dec 2015 14:32:15 +0000 (14:32 +0000)
committerWim Van Sebroeck <wim@iguana.be>
Sun, 27 Dec 2015 19:56:40 +0000 (20:56 +0100)
This allows the system to actually halt even if userspace forgot to
disable the watchdog first. Old behaviour was that the watchdog forced
the system to boot again.

Signed-off-by: Harald Geyer <harald@ccbib.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
drivers/watchdog/stmp3xxx_rtc_wdt.c

index 3ee6128..dbe0372 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
 #include <linux/stmp3xxx_rtc_wdt.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 
 #define WDOG_TICK_RATE 1000 /* 1 kHz clock */
 #define STMP3XXX_DEFAULT_TIMEOUT 19
@@ -69,6 +71,28 @@ static struct watchdog_device stmp3xxx_wdd = {
        .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
 };
 
+static int wdt_notify_sys(struct notifier_block *nb, unsigned long code,
+                         void *unused)
+{
+       struct device *dev = watchdog_get_drvdata(&stmp3xxx_wdd);
+       struct stmp3xxx_wdt_pdata *pdata = dev_get_platdata(dev);
+
+       switch (code) {
+       case SYS_DOWN:  /* keep enabled, system might crash while going down */
+               break;
+       case SYS_HALT:  /* allow the system to actually halt */
+       case SYS_POWER_OFF:
+               wdt_stop(&stmp3xxx_wdd);
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block wdt_notifier = {
+       .notifier_call = wdt_notify_sys,
+};
+
 static int stmp3xxx_wdt_probe(struct platform_device *pdev)
 {
        int ret;
@@ -84,6 +108,9 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev)
                return ret;
        }
 
+       if (register_reboot_notifier(&wdt_notifier))
+               dev_warn(&pdev->dev, "cannot register reboot notifier\n");
+
        dev_info(&pdev->dev, "initialized watchdog with heartbeat %ds\n",
                        stmp3xxx_wdd.timeout);
        return 0;
@@ -91,6 +118,7 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev)
 
 static int stmp3xxx_wdt_remove(struct platform_device *pdev)
 {
+       unregister_reboot_notifier(&wdt_notifier);
        watchdog_unregister_device(&stmp3xxx_wdd);
        return 0;
 }