summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/Kconfig6
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/alim1535_wdt.c20
-rw-r--r--drivers/watchdog/alim7101_wdt.c18
-rw-r--r--drivers/watchdog/ar7_wdt.c2
-rw-r--r--drivers/watchdog/bfin_wdt.c2
-rw-r--r--drivers/watchdog/it8712f_wdt.c2
-rw-r--r--drivers/watchdog/mpc5200_wdt.c2
-rw-r--r--drivers/watchdog/mtx-1_wdt.c2
-rw-r--r--drivers/watchdog/sbc60xxwdt.c18
-rw-r--r--drivers/watchdog/scx200_wdt.c10
-rw-r--r--drivers/watchdog/txx9wdt.c276
-rw-r--r--drivers/watchdog/w83877f_wdt.c18
-rw-r--r--drivers/watchdog/w83977f_wdt.c18
-rw-r--r--drivers/watchdog/wdt.c30
-rw-r--r--drivers/watchdog/wdt977.c18
16 files changed, 375 insertions, 68 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index fbd61127b9d..899fc13d061 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -639,6 +639,12 @@ config AR7_WDT
help
Hardware driver for the TI AR7 Watchdog Timer.
+config TXX9_WDT
+ tristate "Toshiba TXx9 Watchdog Timer"
+ depends on CPU_TX39XX || CPU_TX49XX
+ help
+ Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
+
# PARISC Architecture
# POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 87483cc6325..ebc21146d40 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
# PARISC Architecture
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index b481cc0e32e..2b1fbdb2fcf 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -413,18 +413,18 @@ static int __init watchdog_init(void)
/* Calculate the watchdog's timeout */
ali_settimer(timeout);
- ret = misc_register(&ali_miscdev);
+ ret = register_reboot_notifier(&ali_notifier);
if (ret != 0) {
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ ret);
goto out;
}
- ret = register_reboot_notifier(&ali_notifier);
+ ret = misc_register(&ali_miscdev);
if (ret != 0) {
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- ret);
- goto unreg_miscdev;
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto unreg_reboot;
}
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
@@ -432,8 +432,8 @@ static int __init watchdog_init(void)
out:
return ret;
-unreg_miscdev:
- misc_deregister(&ali_miscdev);
+unreg_reboot:
+ unregister_reboot_notifier(&ali_notifier);
goto out;
}
@@ -449,8 +449,8 @@ static void __exit watchdog_exit(void)
ali_stop();
/* Deregister */
- unregister_reboot_notifier(&ali_notifier);
misc_deregister(&ali_miscdev);
+ unregister_reboot_notifier(&ali_notifier);
pci_dev_put(ali_pci);
}
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 67aed9f8c36..238273c9865 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -377,18 +377,18 @@ static int __init alim7101_wdt_init(void)
timeout);
}
- rc = misc_register(&wdt_miscdev);
+ rc = register_reboot_notifier(&wdt_notifier);
if (rc) {
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
goto err_out;
}
- rc = register_reboot_notifier(&wdt_notifier);
+ rc = misc_register(&wdt_miscdev);
if (rc) {
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- rc);
- goto err_out_miscdev;
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_reboot;
}
if (nowayout) {
@@ -399,8 +399,8 @@ static int __init alim7101_wdt_init(void)
timeout, nowayout);
return 0;
-err_out_miscdev:
- misc_deregister(&wdt_miscdev);
+err_out_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
err_out:
pci_dev_put(alim7101_pmu);
return rc;
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index cdaab8c3d3d..2eb48c0df32 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -279,7 +279,7 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file,
}
}
-static struct file_operations ar7_wdt_fops = {
+static const struct file_operations ar7_wdt_fops = {
.owner = THIS_MODULE,
.write = ar7_wdt_write,
.ioctl = ar7_wdt_ioctl,
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 31dc7a69e90..472be10f068 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -390,7 +390,7 @@ static struct platform_driver bfin_wdt_driver = {
.resume = bfin_wdt_resume,
};
-static struct file_operations bfin_wdt_fops = {
+static const struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = bfin_wdt_write,
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index 6330fc02464..1b6d7d1b715 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -296,7 +296,7 @@ it8712f_wdt_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations it8712f_wdt_fops = {
+static const struct file_operations it8712f_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = it8712f_wdt_write,
diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c
index 11f6a111e75..80a91d4cea1 100644
--- a/drivers/watchdog/mpc5200_wdt.c
+++ b/drivers/watchdog/mpc5200_wdt.c
@@ -158,7 +158,7 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations mpc5200_wdt_fops = {
+static const struct file_operations mpc5200_wdt_fops = {
.owner = THIS_MODULE,
.write = mpc5200_wdt_write,
.ioctl = mpc5200_wdt_ioctl,
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index dcfd401a7ad..98451747d3c 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -180,7 +180,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count,
return count;
}
-static struct file_operations mtx1_wdt_fops = {
+static const struct file_operations mtx1_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = mtx1_wdt_ioctl,
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
index e4f3cb6090b..ef76f01625e 100644
--- a/drivers/watchdog/sbc60xxwdt.c
+++ b/drivers/watchdog/sbc60xxwdt.c
@@ -359,20 +359,20 @@ static int __init sbc60xxwdt_init(void)
}
}
- rc = misc_register(&wdt_miscdev);
+ rc = register_reboot_notifier(&wdt_notifier);
if (rc)
{
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
goto err_out_region2;
}
- rc = register_reboot_notifier(&wdt_notifier);
+ rc = misc_register(&wdt_miscdev);
if (rc)
{
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- rc);
- goto err_out_miscdev;
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_reboot;
}
printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
@@ -380,8 +380,8 @@ static int __init sbc60xxwdt_init(void)
return 0;
-err_out_miscdev:
- misc_deregister(&wdt_miscdev);
+err_out_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
err_out_region2:
if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
release_region(wdt_stop,1);
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
index d4fd0fa2f17..d55882bca31 100644
--- a/drivers/watchdog/scx200_wdt.c
+++ b/drivers/watchdog/scx200_wdt.c
@@ -231,17 +231,17 @@ static int __init scx200_wdt_init(void)
sema_init(&open_semaphore, 1);
- r = misc_register(&scx200_wdt_miscdev);
+ r = register_reboot_notifier(&scx200_wdt_notifier);
if (r) {
+ printk(KERN_ERR NAME ": unable to register reboot notifier");
release_region(scx200_cb_base + SCx200_WDT_OFFSET,
SCx200_WDT_SIZE);
return r;
}
- r = register_reboot_notifier(&scx200_wdt_notifier);
+ r = misc_register(&scx200_wdt_miscdev);
if (r) {
- printk(KERN_ERR NAME ": unable to register reboot notifier");
- misc_deregister(&scx200_wdt_miscdev);
+ unregister_reboot_notifier(&scx200_wdt_notifier);
release_region(scx200_cb_base + SCx200_WDT_OFFSET,
SCx200_WDT_SIZE);
return r;
@@ -252,8 +252,8 @@ static int __init scx200_wdt_init(void)
static void __exit scx200_wdt_cleanup(void)
{
- unregister_reboot_notifier(&scx200_wdt_notifier);
misc_deregister(&scx200_wdt_miscdev);
+ unregister_reboot_notifier(&scx200_wdt_notifier);
release_region(scx200_cb_base + SCx200_WDT_OFFSET,
SCx200_WDT_SIZE);
}
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
new file mode 100644
index 00000000000..328b3c7211e
--- /dev/null
+++ b/drivers/watchdog/txx9wdt.c
@@ -0,0 +1,276 @@
+/*
+ * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs
+ *
+ * Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <asm/txx9tmr.h>
+
+#define TIMER_MARGIN 60 /* Default is 60 seconds */
+
+static int timeout = TIMER_MARGIN; /* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+ "Watchdog timeout in seconds. "
+ "(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "
+ "default=" __MODULE_STRING(TIMER_MARGIN) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started "
+ "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define WD_TIMER_CCD 7 /* 1/256 */
+#define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
+#define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
+
+static unsigned long txx9wdt_alive;
+static int expect_close;
+static struct txx9_tmr_reg __iomem *txx9wdt_reg;
+static struct clk *txx9_imclk;
+
+static void txx9wdt_ping(void)
+{
+ __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
+}
+
+static void txx9wdt_start(void)
+{
+ __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
+ __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
+ __raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */
+ __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
+ &txx9wdt_reg->tcr);
+ __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
+}
+
+static void txx9wdt_stop(void)
+{
+ __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
+ __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
+ &txx9wdt_reg->tcr);
+}
+
+static int txx9wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &txx9wdt_alive))
+ return -EBUSY;
+
+ if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) {
+ clear_bit(0, &txx9wdt_alive);
+ return -EBUSY;
+ }
+
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ txx9wdt_start();
+ return nonseekable_open(inode, file);
+}
+
+static int txx9wdt_release(struct inode *inode, struct file *file)
+{
+ if (expect_close)
+ txx9wdt_stop();
+ else {
+ printk(KERN_CRIT "txx9wdt: "
+ "Unexpected close, not stopping watchdog!\n");
+ txx9wdt_ping();
+ }
+ clear_bit(0, &txx9wdt_alive);
+ expect_close = 0;
+ return 0;
+}
+
+static ssize_t txx9wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ expect_close = 0;
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 1;
+ }
+ }
+ txx9wdt_ping();
+ }
+ return len;
+}
+
+static int txx9wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_timeout;
+ static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = "Hardware Watchdog for TXx9",
+ };
+
+ switch (cmd) {
+ default:
+ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+ case WDIOC_KEEPALIVE:
+ txx9wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_timeout, p))
+ return -EFAULT;
+ if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT)
+ return -EINVAL;
+ timeout = new_timeout;
+ txx9wdt_stop();
+ txx9wdt_start();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, p);
+ }
+}
+
+static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ txx9wdt_stop();
+ return NOTIFY_DONE;
+}
+
+static const struct file_operations txx9wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = txx9wdt_write,
+ .ioctl = txx9wdt_ioctl,
+ .open = txx9wdt_open,
+ .release = txx9wdt_release,
+};
+
+static struct miscdevice txx9wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &txx9wdt_fops,
+};
+
+static struct notifier_block txx9wdt_notifier = {
+ .notifier_call = txx9wdt_notify_sys
+};
+
+static int __init txx9wdt_probe(struct platform_device *dev)
+{
+ struct resource *res;
+ int ret;
+
+ txx9_imclk = clk_get(NULL, "imbus_clk");
+ if (IS_ERR(txx9_imclk)) {
+ ret = PTR_ERR(txx9_imclk);
+ txx9_imclk = NULL;
+ goto exit;
+ }
+ ret = clk_enable(txx9_imclk);
+ if (ret) {
+ clk_put(txx9_imclk);
+ txx9_imclk = NULL;
+ goto exit;
+ }
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto exit_busy;
+ if (!devm_request_mem_region(&dev->dev,
+ res->start, res->end - res->start + 1,
+ "txx9wdt"))
+ goto exit_busy;
+ txx9wdt_reg = devm_ioremap(&dev->dev,
+ res->start, res->end - res->start + 1);
+ if (!txx9wdt_reg)
+ goto exit_busy;
+
+ ret = register_reboot_notifier(&txx9wdt_notifier);
+ if (ret)
+ goto exit;
+
+ ret = misc_register(&txx9wdt_miscdev);
+ if (ret) {
+ unregister_reboot_notifier(&txx9wdt_notifier);
+ goto exit;
+ }
+
+ printk(KERN_INFO "Hardware Watchdog Timer for TXx9: "
+ "timeout=%d sec (max %ld) (nowayout= %d)\n",
+ timeout, WD_MAX_TIMEOUT, nowayout);
+
+ return 0;
+exit_busy:
+ ret = -EBUSY;
+exit:
+ if (txx9_imclk) {
+ clk_disable(txx9_imclk);
+ clk_put(txx9_imclk);
+ }
+ return ret;
+}
+
+static int __exit txx9wdt_remove(struct platform_device *dev)
+{
+ misc_deregister(&txx9wdt_miscdev);
+ unregister_reboot_notifier(&txx9wdt_notifier);
+ clk_disable(txx9_imclk);
+ clk_put(txx9_imclk);
+ return 0;
+}
+
+static struct platform_driver txx9wdt_driver = {
+ .remove = __exit_p(txx9wdt_remove),
+ .driver = {
+ .name = "txx9wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init watchdog_init(void)
+{
+ return platform_driver_probe(&txx9wdt_driver, txx9wdt_probe);
+}
+
+static void __exit watchdog_exit(void)
+{
+ platform_driver_unregister(&txx9wdt_driver);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_DESCRIPTION("TXx9 Watchdog Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index bcc9d48955d..f510a3a595e 100644
--- a/drivers/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -373,20 +373,20 @@ static int __init w83877f_wdt_init(void)
goto err_out_region1;
}
- rc = misc_register(&wdt_miscdev);
+ rc = register_reboot_notifier(&wdt_notifier);
if (rc)
{
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
goto err_out_region2;
}
- rc = register_reboot_notifier(&wdt_notifier);
+ rc = misc_register(&wdt_miscdev);
if (rc)
{
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- rc);
- goto err_out_miscdev;
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_reboot;
}
printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
@@ -394,8 +394,8 @@ static int __init w83877f_wdt_init(void)
return 0;
-err_out_miscdev:
- misc_deregister(&wdt_miscdev);
+err_out_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
err_out_region2:
release_region(WDT_PING,1);
err_out_region1:
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index b475529d247..b209bcd7f78 100644
--- a/drivers/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -494,20 +494,20 @@ static int __init w83977f_wdt_init(void)
goto err_out;
}
- rc = misc_register(&wdt_miscdev);
+ rc = register_reboot_notifier(&wdt_notifier);
if (rc)
{
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- wdt_miscdev.minor, rc);
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
goto err_out_region;
}
- rc = register_reboot_notifier(&wdt_notifier);
+ rc = misc_register(&wdt_miscdev);
if (rc)
{
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- rc);
- goto err_out_miscdev;
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ wdt_miscdev.minor, rc);
+ goto err_out_reboot;
}
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
@@ -515,8 +515,8 @@ static int __init w83977f_wdt_init(void)
return 0;
-err_out_miscdev:
- misc_deregister(&wdt_miscdev);
+err_out_reboot:
+ unregister_reboot_notifier(&wdt_notifier);
err_out_region:
release_region(IO_INDEX_PORT,2);
err_out:
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 53d0bb410df..756fb15fdce 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
static int io=0x240;
static int irq=11;
+static DEFINE_SPINLOCK(wdt_lock);
+
module_param(io, int, 0);
MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
module_param(irq, int, 0);
@@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val)
static int wdt_start(void)
{
+ unsigned long flags;
+ spin_lock_irqsave(&wdt_lock, flags);
inb_p(WDT_DC); /* Disable watchdog */
wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */
wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */
@@ -117,6 +121,7 @@ static int wdt_start(void)
wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
wdt_ctr_load(2,65535); /* Length of reset pulse */
outb_p(0, WDT_DC); /* Enable watchdog */
+ spin_unlock_irqrestore(&wdt_lock, flags);
return 0;
}
@@ -128,9 +133,12 @@ static int wdt_start(void)
static int wdt_stop (void)
{
+ unsigned long flags;
+ spin_lock_irqsave(&wdt_lock, flags);
/* Turn the card off */
inb_p(WDT_DC); /* Disable watchdog */
wdt_ctr_load(2,0); /* 0 length reset pulses now */
+ spin_unlock_irqrestore(&wdt_lock, flags);
return 0;
}
@@ -143,11 +151,14 @@ static int wdt_stop (void)
static int wdt_ping(void)
{
+ unsigned long flags;
+ spin_lock_irqsave(&wdt_lock, flags);
/* Write a watchdog value */
inb_p(WDT_DC); /* Disable watchdog */
wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */
wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
outb_p(0, WDT_DC); /* Enable watchdog */
+ spin_unlock_irqrestore(&wdt_lock, flags);
return 0;
}
@@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t)
static int wdt_get_status(int *status)
{
- unsigned char new_status=inb_p(WDT_SR);
+ unsigned char new_status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdt_lock, flags);
+ new_status = inb_p(WDT_SR);
+ spin_unlock_irqrestore(&wdt_lock, flags);
*status=0;
if (new_status & WDC_SR_ISOI0)
@@ -214,8 +230,12 @@ static int wdt_get_status(int *status)
static int wdt_get_temperature(int *temperature)
{
- unsigned short c=inb_p(WDT_RT);
+ unsigned short c;
+ unsigned long flags;
+ spin_lock_irqsave(&wdt_lock, flags);
+ c = inb_p(WDT_RT);
+ spin_unlock_irqrestore(&wdt_lock, flags);
*temperature = (c * 11 / 15) + 7;
return 0;
}
@@ -237,7 +257,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
* Read the status register see what is up and
* then printk it.
*/
- unsigned char status=inb_p(WDT_SR);
+ unsigned char status;
+
+ spin_lock(&wdt_lock);
+ status = inb_p(WDT_SR);
printk(KERN_CRIT "WDT status %d\n", status);
@@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
printk(KERN_CRIT "Reset in 5ms.\n");
#endif
}
+ spin_unlock(&wdt_lock);
return IRQ_HANDLED;
}
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index 9b7f6b6edef..fb4b876c9fd 100644
--- a/drivers/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -470,20 +470,20 @@ static int __init wd977_init(void)
}
}
- rc = misc_register(&wdt977_miscdev);
+ rc = register_reboot_notifier(&wdt977_notifier);
if (rc)
{
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- wdt977_miscdev.minor, rc);
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+ rc);
goto err_out_region;
}
- rc = register_reboot_notifier(&wdt977_notifier);
+ rc = misc_register(&wdt977_miscdev);
if (rc)
{
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- rc);
- goto err_out_miscdev;
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ wdt977_miscdev.minor, rc);
+ goto err_out_reboot;
}
printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
@@ -491,8 +491,8 @@ static int __init wd977_init(void)
return 0;
-err_out_miscdev:
- misc_deregister(&wdt977_miscdev);
+err_out_reboot:
+ unregister_reboot_notifier(&wdt977_notifier);
err_out_region:
if (!machine_is_netwinder())
release_region(IO_INDEX_PORT,2);