aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-10 16:38:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-10 16:38:02 -0400
commit93834c6419bccf102a17971c6b114826597a61c5 (patch)
tree9fd665b797b0fe258f19c9ef0674564b1a4356f6 /drivers/watchdog
parentc798360cd1438090d51eeaa8e67985da11362eba (diff)
parent6cd6d94d96d9b1cd8a62da91aac44cf56e301e75 (diff)
Merge tag 'restart-handler-for-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull restart handler infrastructure from Guenter Roeck: "This series was supposed to be pulled through various trees using it, and I did not plan to send a separate pull request. As it turns out, the pinctrl tree did not merge with it, is now upstream, and uses it, meaning there are now build failures. Please pull this series directly to fix those build failures" * tag 'restart-handler-for-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: arm/arm64: unexport restart handlers watchdog: sunxi: register restart handler with kernel restart handler watchdog: alim7101: register restart handler with kernel restart handler watchdog: moxart: register restart handler with kernel restart handler arm: support restart through restart handler call chain arm64: support restart through restart handler call chain power/restart: call machine_restart instead of arm_pm_restart kernel: add support for kernel restart handler call chain
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/alim7101_wdt.c42
-rw-r--r--drivers/watchdog/moxart_wdt.c32
-rw-r--r--drivers/watchdog/sunxi_wdt.c31
3 files changed, 72 insertions, 33 deletions
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 996b2f7d330e..665e0e7dfe1e 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -301,6 +301,28 @@ static struct miscdevice wdt_miscdev = {
301 .fops = &wdt_fops, 301 .fops = &wdt_fops,
302}; 302};
303 303
304static int wdt_restart_handle(struct notifier_block *this, unsigned long mode,
305 void *cmd)
306{
307 /*
308 * Cobalt devices have no way of rebooting themselves other
309 * than getting the watchdog to pull reset, so we restart the
310 * watchdog on reboot with no heartbeat.
311 */
312 wdt_change(WDT_ENABLE);
313
314 /* loop until the watchdog fires */
315 while (true)
316 ;
317
318 return NOTIFY_DONE;
319}
320
321static struct notifier_block wdt_restart_handler = {
322 .notifier_call = wdt_restart_handle,
323 .priority = 128,
324};
325
304/* 326/*
305 * Notifier for system down 327 * Notifier for system down
306 */ 328 */
@@ -311,15 +333,6 @@ static int wdt_notify_sys(struct notifier_block *this,
311 if (code == SYS_DOWN || code == SYS_HALT) 333 if (code == SYS_DOWN || code == SYS_HALT)
312 wdt_turnoff(); 334 wdt_turnoff();
313 335
314 if (code == SYS_RESTART) {
315 /*
316 * Cobalt devices have no way of rebooting themselves other
317 * than getting the watchdog to pull reset, so we restart the
318 * watchdog on reboot with no heartbeat
319 */
320 wdt_change(WDT_ENABLE);
321 pr_info("Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second\n");
322 }
323 return NOTIFY_DONE; 336 return NOTIFY_DONE;
324} 337}
325 338
@@ -338,6 +351,7 @@ static void __exit alim7101_wdt_unload(void)
338 /* Deregister */ 351 /* Deregister */
339 misc_deregister(&wdt_miscdev); 352 misc_deregister(&wdt_miscdev);
340 unregister_reboot_notifier(&wdt_notifier); 353 unregister_reboot_notifier(&wdt_notifier);
354 unregister_restart_handler(&wdt_restart_handler);
341 pci_dev_put(alim7101_pmu); 355 pci_dev_put(alim7101_pmu);
342} 356}
343 357
@@ -390,11 +404,17 @@ static int __init alim7101_wdt_init(void)
390 goto err_out; 404 goto err_out;
391 } 405 }
392 406
407 rc = register_restart_handler(&wdt_restart_handler);
408 if (rc) {
409 pr_err("cannot register restart handler (err=%d)\n", rc);
410 goto err_out_reboot;
411 }
412
393 rc = misc_register(&wdt_miscdev); 413 rc = misc_register(&wdt_miscdev);
394 if (rc) { 414 if (rc) {
395 pr_err("cannot register miscdev on minor=%d (err=%d)\n", 415 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
396 wdt_miscdev.minor, rc); 416 wdt_miscdev.minor, rc);
397 goto err_out_reboot; 417 goto err_out_restart;
398 } 418 }
399 419
400 if (nowayout) 420 if (nowayout)
@@ -404,6 +424,8 @@ static int __init alim7101_wdt_init(void)
404 timeout, nowayout); 424 timeout, nowayout);
405 return 0; 425 return 0;
406 426
427err_out_restart:
428 unregister_restart_handler(&wdt_restart_handler);
407err_out_reboot: 429err_out_reboot:
408 unregister_reboot_notifier(&wdt_notifier); 430 unregister_reboot_notifier(&wdt_notifier);
409err_out: 431err_out:
diff --git a/drivers/watchdog/moxart_wdt.c b/drivers/watchdog/moxart_wdt.c
index 4aa3a8a876fe..a64405b82596 100644
--- a/drivers/watchdog/moxart_wdt.c
+++ b/drivers/watchdog/moxart_wdt.c
@@ -15,12 +15,12 @@
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/err.h> 16#include <linux/err.h>
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/notifier.h>
18#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/reboot.h>
19#include <linux/watchdog.h> 21#include <linux/watchdog.h>
20#include <linux/moduleparam.h> 22#include <linux/moduleparam.h>
21 23
22#include <asm/system_misc.h>
23
24#define REG_COUNT 0x4 24#define REG_COUNT 0x4
25#define REG_MODE 0x8 25#define REG_MODE 0x8
26#define REG_ENABLE 0xC 26#define REG_ENABLE 0xC
@@ -29,17 +29,22 @@ struct moxart_wdt_dev {
29 struct watchdog_device dev; 29 struct watchdog_device dev;
30 void __iomem *base; 30 void __iomem *base;
31 unsigned int clock_frequency; 31 unsigned int clock_frequency;
32 struct notifier_block restart_handler;
32}; 33};
33 34
34static struct moxart_wdt_dev *moxart_restart_ctx;
35
36static int heartbeat; 35static int heartbeat;
37 36
38static void moxart_wdt_restart(enum reboot_mode reboot_mode, const char *cmd) 37static int moxart_restart_handle(struct notifier_block *this,
38 unsigned long mode, void *cmd)
39{ 39{
40 writel(1, moxart_restart_ctx->base + REG_COUNT); 40 struct moxart_wdt_dev *moxart_wdt = container_of(this,
41 writel(0x5ab9, moxart_restart_ctx->base + REG_MODE); 41 struct moxart_wdt_dev,
42 writel(0x03, moxart_restart_ctx->base + REG_ENABLE); 42 restart_handler);
43 writel(1, moxart_wdt->base + REG_COUNT);
44 writel(0x5ab9, moxart_wdt->base + REG_MODE);
45 writel(0x03, moxart_wdt->base + REG_ENABLE);
46
47 return NOTIFY_DONE;
43} 48}
44 49
45static int moxart_wdt_stop(struct watchdog_device *wdt_dev) 50static int moxart_wdt_stop(struct watchdog_device *wdt_dev)
@@ -136,8 +141,12 @@ static int moxart_wdt_probe(struct platform_device *pdev)
136 if (err) 141 if (err)
137 return err; 142 return err;
138 143
139 moxart_restart_ctx = moxart_wdt; 144 moxart_wdt->restart_handler.notifier_call = moxart_restart_handle;
140 arm_pm_restart = moxart_wdt_restart; 145 moxart_wdt->restart_handler.priority = 128;
146 err = register_restart_handler(&moxart_wdt->restart_handler);
147 if (err)
148 dev_err(dev, "cannot register restart notifier (err=%d)\n",
149 err);
141 150
142 dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n", 151 dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n",
143 moxart_wdt->dev.timeout, nowayout); 152 moxart_wdt->dev.timeout, nowayout);
@@ -149,9 +158,8 @@ static int moxart_wdt_remove(struct platform_device *pdev)
149{ 158{
150 struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev); 159 struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev);
151 160
152 arm_pm_restart = NULL; 161 unregister_restart_handler(&moxart_wdt->restart_handler);
153 moxart_wdt_stop(&moxart_wdt->dev); 162 moxart_wdt_stop(&moxart_wdt->dev);
154 watchdog_unregister_device(&moxart_wdt->dev);
155 163
156 return 0; 164 return 0;
157} 165}
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
index 60deb9d304c0..480bb557f353 100644
--- a/drivers/watchdog/sunxi_wdt.c
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -21,14 +21,13 @@
21#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/moduleparam.h> 23#include <linux/moduleparam.h>
24#include <linux/notifier.h>
24#include <linux/of.h> 25#include <linux/of.h>
25#include <linux/platform_device.h> 26#include <linux/platform_device.h>
26#include <linux/reboot.h> 27#include <linux/reboot.h>
27#include <linux/types.h> 28#include <linux/types.h>
28#include <linux/watchdog.h> 29#include <linux/watchdog.h>
29 30
30#include <asm/system_misc.h>
31
32#define WDT_MAX_TIMEOUT 16 31#define WDT_MAX_TIMEOUT 16
33#define WDT_MIN_TIMEOUT 1 32#define WDT_MIN_TIMEOUT 1
34#define WDT_MODE_TIMEOUT(n) ((n) << 3) 33#define WDT_MODE_TIMEOUT(n) ((n) << 3)
@@ -50,6 +49,7 @@ static unsigned int timeout = WDT_MAX_TIMEOUT;
50struct sunxi_wdt_dev { 49struct sunxi_wdt_dev {
51 struct watchdog_device wdt_dev; 50 struct watchdog_device wdt_dev;
52 void __iomem *wdt_base; 51 void __iomem *wdt_base;
52 struct notifier_block restart_handler;
53}; 53};
54 54
55/* 55/*
@@ -74,24 +74,29 @@ static const int wdt_timeout_map[] = {
74 [16] = 0xB, /* 16s */ 74 [16] = 0xB, /* 16s */
75}; 75};
76 76
77static void __iomem *reboot_wdt_base;
78 77
79static void sun4i_wdt_restart(enum reboot_mode mode, const char *cmd) 78static int sunxi_restart_handle(struct notifier_block *this, unsigned long mode,
79 void *cmd)
80{ 80{
81 struct sunxi_wdt_dev *sunxi_wdt = container_of(this,
82 struct sunxi_wdt_dev,
83 restart_handler);
84 void __iomem *wdt_base = sunxi_wdt->wdt_base;
85
81 /* Enable timer and set reset bit in the watchdog */ 86 /* Enable timer and set reset bit in the watchdog */
82 writel(WDT_MODE_EN | WDT_MODE_RST_EN, reboot_wdt_base + WDT_MODE); 87 writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE);
83 88
84 /* 89 /*
85 * Restart the watchdog. The default (and lowest) interval 90 * Restart the watchdog. The default (and lowest) interval
86 * value for the watchdog is 0.5s. 91 * value for the watchdog is 0.5s.
87 */ 92 */
88 writel(WDT_CTRL_RELOAD, reboot_wdt_base + WDT_CTRL); 93 writel(WDT_CTRL_RELOAD, wdt_base + WDT_CTRL);
89 94
90 while (1) { 95 while (1) {
91 mdelay(5); 96 mdelay(5);
92 writel(WDT_MODE_EN | WDT_MODE_RST_EN, 97 writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE);
93 reboot_wdt_base + WDT_MODE);
94 } 98 }
99 return NOTIFY_DONE;
95} 100}
96 101
97static int sunxi_wdt_ping(struct watchdog_device *wdt_dev) 102static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
@@ -205,8 +210,12 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
205 if (unlikely(err)) 210 if (unlikely(err))
206 return err; 211 return err;
207 212
208 reboot_wdt_base = sunxi_wdt->wdt_base; 213 sunxi_wdt->restart_handler.notifier_call = sunxi_restart_handle;
209 arm_pm_restart = sun4i_wdt_restart; 214 sunxi_wdt->restart_handler.priority = 128;
215 err = register_restart_handler(&sunxi_wdt->restart_handler);
216 if (err)
217 dev_err(&pdev->dev,
218 "cannot register restart handler (err=%d)\n", err);
210 219
211 dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", 220 dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
212 sunxi_wdt->wdt_dev.timeout, nowayout); 221 sunxi_wdt->wdt_dev.timeout, nowayout);
@@ -218,7 +227,7 @@ static int sunxi_wdt_remove(struct platform_device *pdev)
218{ 227{
219 struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); 228 struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
220 229
221 arm_pm_restart = NULL; 230 unregister_restart_handler(&sunxi_wdt->restart_handler);
222 231
223 watchdog_unregister_device(&sunxi_wdt->wdt_dev); 232 watchdog_unregister_device(&sunxi_wdt->wdt_dev);
224 watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL); 233 watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);