aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 13:24:52 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 13:24:52 -0500
commit67b5ad9a63caa2ce56ddd2b22b802dae00d72c13 (patch)
treef2ba8bda2e62efedf6009ab74e9e65a097f6e24d /drivers
parent174a86dff2f3c72ef55d994b1e7faa7099d3f844 (diff)
parent88cce427626070f7d7eb33994e3ff7b4db3292c5 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: watchdog: Add MCF548x watchdog driver. watchdog: add driver for the Atheros AR71XX/AR724X/AR913X SoCs watchdog: Add TCO support for nVidia chipsets watchdog: Add support for sp5100 chipset TCO watchdog: f71808e_wdt: add F71862FG, F71869 to Kconfig watchdog: iTCO_wdt: TCO Watchdog patch for Intel DH89xxCC PCH watchdog: iTCO_wdt: TCO Watchdog patch for Intel NM10 DeviceIDs watchdog: ks8695_wdt: include mach/hardware.h instead of mach/timex.h. watchdog: Propagate Book E WDT period changes to all cores watchdog: add CONFIG_WATCHDOG_NOWAYOUT support to PowerPC Book-E watchdog driver watchdog: alim7101_wdt: fix compiler warning on alim7101_pci_tbl watchdog: alim1535_wdt: fix compiler warning on ali_pci_tbl watchdog: Fix reboot on W83627ehf chipset. watchdog: Add watchdog support for W83627DHG chip watchdog: f71808e_wdt: Add Fintek F71869 watchdog watchdog: add f71862fg support watchdog: clean-up f71808e_wdt.c
Diffstat (limited to 'drivers')
-rw-r--r--drivers/watchdog/Kconfig56
-rw-r--r--drivers/watchdog/Makefile6
-rw-r--r--drivers/watchdog/alim1535_wdt.c2
-rw-r--r--drivers/watchdog/alim7101_wdt.c2
-rw-r--r--drivers/watchdog/ath79_wdt.c305
-rw-r--r--drivers/watchdog/booke_wdt.c35
-rw-r--r--drivers/watchdog/f71808e_wdt.c78
-rw-r--r--drivers/watchdog/iTCO_wdt.c12
-rw-r--r--drivers/watchdog/ks8695_wdt.c2
-rw-r--r--drivers/watchdog/m548x_wdt.c227
-rw-r--r--drivers/watchdog/nv_tco.c512
-rw-r--r--drivers/watchdog/nv_tco.h64
-rw-r--r--drivers/watchdog/sp5100_tco.c480
-rw-r--r--drivers/watchdog/sp5100_tco.h41
-rw-r--r--drivers/watchdog/w83627hf_wdt.c8
15 files changed, 1796 insertions, 34 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index a5ad77ef426..2e2400e7322 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -409,15 +409,26 @@ config ALIM7101_WDT
409 Most people will say N. 409 Most people will say N.
410 410
411config F71808E_WDT 411config F71808E_WDT
412 tristate "Fintek F71808E, F71882FG and F71889FG Watchdog" 412 tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
413 depends on X86 && EXPERIMENTAL 413 depends on X86 && EXPERIMENTAL
414 help 414 help
415 This is the driver for the hardware watchdog on the Fintek 415 This is the driver for the hardware watchdog on the Fintek
416 F71808E, F71882FG and F71889FG Super I/O controllers. 416 F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
417 417
418 You can compile this driver directly into the kernel, or use 418 You can compile this driver directly into the kernel, or use
419 it as a module. The module will be called f71808e_wdt. 419 it as a module. The module will be called f71808e_wdt.
420 420
421config SP5100_TCO
422 tristate "AMD/ATI SP5100 TCO Timer/Watchdog"
423 depends on X86 && PCI
424 ---help---
425 Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO
426 (Total Cost of Ownership) timer is a watchdog timer that will reboot
427 the machine after its expiration. The expiration time can be
428 configured with the "heartbeat" parameter.
429
430 To compile this driver as a module, choose M here: the
431 module will be called sp5100_tco.
421 432
422config GEODE_WDT 433config GEODE_WDT
423 tristate "AMD Geode CS5535/CS5536 Watchdog" 434 tristate "AMD Geode CS5535/CS5536 Watchdog"
@@ -631,6 +642,24 @@ config PC87413_WDT
631 642
632 Most people will say N. 643 Most people will say N.
633 644
645config NV_TCO
646 tristate "nVidia TCO Timer/Watchdog"
647 depends on X86 && PCI
648 ---help---
649 Hardware driver for the TCO timer built into the nVidia Hub family
650 (such as the MCP51). The TCO (Total Cost of Ownership) timer is a
651 watchdog timer that will reboot the machine after its second
652 expiration. The expiration time can be configured with the
653 "heartbeat" parameter.
654
655 On some motherboards the driver may fail to reset the chipset's
656 NO_REBOOT flag which prevents the watchdog from rebooting the
657 machine. If this is the case you will get a kernel message like
658 "failed to reset NO_REBOOT flag, reboot disabled by hardware".
659
660 To compile this driver as a module, choose M here: the
661 module will be called nv_tco.
662
634config RDC321X_WDT 663config RDC321X_WDT
635 tristate "RDC R-321x SoC watchdog" 664 tristate "RDC R-321x SoC watchdog"
636 depends on X86_RDC321X 665 depends on X86_RDC321X
@@ -722,14 +751,15 @@ config SMSC37B787_WDT
722 Most people will say N. 751 Most people will say N.
723 752
724config W83627HF_WDT 753config W83627HF_WDT
725 tristate "W83627HF Watchdog Timer" 754 tristate "W83627HF/W83627DHG Watchdog Timer"
726 depends on X86 755 depends on X86
727 ---help--- 756 ---help---
728 This is the driver for the hardware watchdog on the W83627HF chipset 757 This is the driver for the hardware watchdog on the W83627HF chipset
729 as used in Advantech PC-9578 and Tyan S2721-533 motherboards 758 as used in Advantech PC-9578 and Tyan S2721-533 motherboards
730 (and likely others). This watchdog simply watches your kernel to 759 (and likely others). The driver also supports the W83627DHG chip.
731 make sure it doesn't freeze, and if it does, it reboots your computer 760 This watchdog simply watches your kernel to make sure it doesn't
732 after a certain amount of time. 761 freeze, and if it does, it reboots your computer after a certain
762 amount of time.
733 763
734 To compile this driver as a module, choose M here: the 764 To compile this driver as a module, choose M here: the
735 module will be called w83627hf_wdt. 765 module will be called w83627hf_wdt.
@@ -832,10 +862,22 @@ config SBC_EPX_C3_WATCHDOG
832 862
833# M68K Architecture 863# M68K Architecture
834 864
835# M68KNOMMU Architecture 865config M548x_WATCHDOG
866 tristate "MCF548x watchdog support"
867 depends on M548x
868 help
869 To compile this driver as a module, choose M here: the
870 module will be called m548x_wdt.
836 871
837# MIPS Architecture 872# MIPS Architecture
838 873
874config ATH79_WDT
875 tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog"
876 depends on ATH79
877 help
878 Hardware driver for the built-in watchdog timer on the Atheros
879 AR71XX/AR724X/AR913X SoCs.
880
839config BCM47XX_WDT 881config BCM47XX_WDT
840 tristate "Broadcom BCM47xx Watchdog Timer" 882 tristate "Broadcom BCM47xx Watchdog Timer"
841 depends on BCM47XX 883 depends on BCM47XX
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 4b0ef386229..dd776651917 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
68obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o 68obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
69obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o 69obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
70obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o 70obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
71obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o
71obj-$(CONFIG_GEODE_WDT) += geodewdt.o 72obj-$(CONFIG_GEODE_WDT) += geodewdt.o
72obj-$(CONFIG_SC520_WDT) += sc520_wdt.o 73obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
73obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o 74obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o
@@ -86,6 +87,7 @@ obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
86obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o 87obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
87obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o 88obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
88obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o 89obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
90obj-$(CONFIG_NV_TCO) += nv_tco.o
89obj-$(CONFIG_RDC321X_WDT) += rdc321x_wdt.o 91obj-$(CONFIG_RDC321X_WDT) += rdc321x_wdt.o
90obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o 92obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
91obj-$(CONFIG_SBC8360_WDT) += sbc8360.o 93obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
@@ -104,10 +106,10 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
104# M32R Architecture 106# M32R Architecture
105 107
106# M68K Architecture 108# M68K Architecture
107 109obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o
108# M68KNOMMU Architecture
109 110
110# MIPS Architecture 111# MIPS Architecture
112obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
111obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o 113obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
112obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o 114obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o
113obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o 115obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index 1e9caea8ff8..fa4d3603355 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
301 * want to register another driver on the same PCI id. 301 * want to register another driver on the same PCI id.
302 */ 302 */
303 303
304static struct pci_device_id ali_pci_tbl[] = { 304static struct pci_device_id ali_pci_tbl[] __used = {
305 { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,}, 305 { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
306 { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, 306 { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
307 { 0, }, 307 { 0, },
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index d8d4da9a483..4b7a2b4138e 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -430,7 +430,7 @@ err_out:
430module_init(alim7101_wdt_init); 430module_init(alim7101_wdt_init);
431module_exit(alim7101_wdt_unload); 431module_exit(alim7101_wdt_unload);
432 432
433static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { 433static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = {
434 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) }, 434 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
435 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, 435 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
436 { } 436 { }
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
new file mode 100644
index 00000000000..725c84bfdd7
--- /dev/null
+++ b/drivers/watchdog/ath79_wdt.c
@@ -0,0 +1,305 @@
1/*
2 * Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer.
3 *
4 * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
6 *
7 * This driver was based on: drivers/watchdog/ixp4xx_wdt.c
8 * Author: Deepak Saxena <dsaxena@plexity.net>
9 * Copyright 2004 (c) MontaVista, Software, Inc.
10 *
11 * which again was based on sa1100 driver,
12 * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License version 2 as published
16 * by the Free Software Foundation.
17 *
18 */
19
20#include <linux/bitops.h>
21#include <linux/errno.h>
22#include <linux/fs.h>
23#include <linux/init.h>
24#include <linux/kernel.h>
25#include <linux/miscdevice.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/platform_device.h>
29#include <linux/types.h>
30#include <linux/watchdog.h>
31#include <linux/clk.h>
32#include <linux/err.h>
33
34#include <asm/mach-ath79/ath79.h>
35#include <asm/mach-ath79/ar71xx_regs.h>
36
37#define DRIVER_NAME "ath79-wdt"
38
39#define WDT_TIMEOUT 15 /* seconds */
40
41#define WDOG_CTRL_LAST_RESET BIT(31)
42#define WDOG_CTRL_ACTION_MASK 3
43#define WDOG_CTRL_ACTION_NONE 0 /* no action */
44#define WDOG_CTRL_ACTION_GPI 1 /* general purpose interrupt */
45#define WDOG_CTRL_ACTION_NMI 2 /* NMI */
46#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */
47
48static int nowayout = WATCHDOG_NOWAYOUT;
49module_param(nowayout, int, 0);
50MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
51 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
52
53static int timeout = WDT_TIMEOUT;
54module_param(timeout, int, 0);
55MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds "
56 "(default=" __MODULE_STRING(WDT_TIMEOUT) "s)");
57
58static unsigned long wdt_flags;
59
60#define WDT_FLAGS_BUSY 0
61#define WDT_FLAGS_EXPECT_CLOSE 1
62
63static struct clk *wdt_clk;
64static unsigned long wdt_freq;
65static int boot_status;
66static int max_timeout;
67
68static inline void ath79_wdt_keepalive(void)
69{
70 ath79_reset_wr(AR71XX_RESET_REG_WDOG, wdt_freq * timeout);
71}
72
73static inline void ath79_wdt_enable(void)
74{
75 ath79_wdt_keepalive();
76 ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR);
77}
78
79static inline void ath79_wdt_disable(void)
80{
81 ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE);
82}
83
84static int ath79_wdt_set_timeout(int val)
85{
86 if (val < 1 || val > max_timeout)
87 return -EINVAL;
88
89 timeout = val;
90 ath79_wdt_keepalive();
91
92 return 0;
93}
94
95static int ath79_wdt_open(struct inode *inode, struct file *file)
96{
97 if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags))
98 return -EBUSY;
99
100 clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
101 ath79_wdt_enable();
102
103 return nonseekable_open(inode, file);
104}
105
106static int ath79_wdt_release(struct inode *inode, struct file *file)
107{
108 if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags))
109 ath79_wdt_disable();
110 else {
111 pr_crit(DRIVER_NAME ": device closed unexpectedly, "
112 "watchdog timer will not stop!\n");
113 ath79_wdt_keepalive();
114 }
115
116 clear_bit(WDT_FLAGS_BUSY, &wdt_flags);
117 clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
118
119 return 0;
120}
121
122static ssize_t ath79_wdt_write(struct file *file, const char *data,
123 size_t len, loff_t *ppos)
124{
125 if (len) {
126 if (!nowayout) {
127 size_t i;
128
129 clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
130
131 for (i = 0; i != len; i++) {
132 char c;
133
134 if (get_user(c, data + i))
135 return -EFAULT;
136
137 if (c == 'V')
138 set_bit(WDT_FLAGS_EXPECT_CLOSE,
139 &wdt_flags);
140 }
141 }
142
143 ath79_wdt_keepalive();
144 }
145
146 return len;
147}
148
149static const struct watchdog_info ath79_wdt_info = {
150 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
151 WDIOF_MAGICCLOSE | WDIOF_CARDRESET,
152 .firmware_version = 0,
153 .identity = "ATH79 watchdog",
154};
155
156static long ath79_wdt_ioctl(struct file *file, unsigned int cmd,
157 unsigned long arg)
158{
159 void __user *argp = (void __user *)arg;
160 int __user *p = argp;
161 int err;
162 int t;
163
164 switch (cmd) {
165 case WDIOC_GETSUPPORT:
166 err = copy_to_user(argp, &ath79_wdt_info,
167 sizeof(ath79_wdt_info)) ? -EFAULT : 0;
168 break;
169
170 case WDIOC_GETSTATUS:
171 err = put_user(0, p);
172 break;
173
174 case WDIOC_GETBOOTSTATUS:
175 err = put_user(boot_status, p);
176 break;
177
178 case WDIOC_KEEPALIVE:
179 ath79_wdt_keepalive();
180 err = 0;
181 break;
182
183 case WDIOC_SETTIMEOUT:
184 err = get_user(t, p);
185 if (err)
186 break;
187
188 err = ath79_wdt_set_timeout(t);
189 if (err)
190 break;
191
192 /* fallthrough */
193 case WDIOC_GETTIMEOUT:
194 err = put_user(timeout, p);
195 break;
196
197 default:
198 err = -ENOTTY;
199 break;
200 }
201
202 return err;
203}
204
205static const struct file_operations ath79_wdt_fops = {
206 .owner = THIS_MODULE,
207 .llseek = no_llseek,
208 .write = ath79_wdt_write,
209 .unlocked_ioctl = ath79_wdt_ioctl,
210 .open = ath79_wdt_open,
211 .release = ath79_wdt_release,
212};
213
214static struct miscdevice ath79_wdt_miscdev = {
215 .minor = WATCHDOG_MINOR,
216 .name = "watchdog",
217 .fops = &ath79_wdt_fops,
218};
219
220static int __devinit ath79_wdt_probe(struct platform_device *pdev)
221{
222 u32 ctrl;
223 int err;
224
225 wdt_clk = clk_get(&pdev->dev, "wdt");
226 if (IS_ERR(wdt_clk))
227 return PTR_ERR(wdt_clk);
228
229 err = clk_enable(wdt_clk);
230 if (err)
231 goto err_clk_put;
232
233 wdt_freq = clk_get_rate(wdt_clk);
234 if (!wdt_freq) {
235 err = -EINVAL;
236 goto err_clk_disable;
237 }
238
239 max_timeout = (0xfffffffful / wdt_freq);
240 if (timeout < 1 || timeout > max_timeout) {
241 timeout = max_timeout;
242 dev_info(&pdev->dev,
243 "timeout value must be 0 < timeout < %d, using %d\n",
244 max_timeout, timeout);
245 }
246
247 ctrl = ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL);
248 boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0;
249
250 err = misc_register(&ath79_wdt_miscdev);
251 if (err) {
252 dev_err(&pdev->dev,
253 "unable to register misc device, err=%d\n", err);
254 goto err_clk_disable;
255 }
256
257 return 0;
258
259err_clk_disable:
260 clk_disable(wdt_clk);
261err_clk_put:
262 clk_put(wdt_clk);
263 return err;
264}
265
266static int __devexit ath79_wdt_remove(struct platform_device *pdev)
267{
268 misc_deregister(&ath79_wdt_miscdev);
269 clk_disable(wdt_clk);
270 clk_put(wdt_clk);
271 return 0;
272}
273
274static void ath97_wdt_shutdown(struct platform_device *pdev)
275{
276 ath79_wdt_disable();
277}
278
279static struct platform_driver ath79_wdt_driver = {
280 .remove = __devexit_p(ath79_wdt_remove),
281 .shutdown = ath97_wdt_shutdown,
282 .driver = {
283 .name = DRIVER_NAME,
284 .owner = THIS_MODULE,
285 },
286};
287
288static int __init ath79_wdt_init(void)
289{
290 return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
291}
292module_init(ath79_wdt_init);
293
294static void __exit ath79_wdt_exit(void)
295{
296 platform_driver_unregister(&ath79_wdt_driver);
297}
298module_exit(ath79_wdt_exit);
299
300MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
301MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
302MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org");
303MODULE_LICENSE("GPL v2");
304MODULE_ALIAS("platform:" DRIVER_NAME);
305MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index d11ffb091b0..7e7ec9c35b6 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -85,6 +85,22 @@ static unsigned int sec_to_period(unsigned int secs)
85 return 0; 85 return 0;
86} 86}
87 87
88static void __booke_wdt_set(void *data)
89{
90 u32 val;
91
92 val = mfspr(SPRN_TCR);
93 val &= ~WDTP_MASK;
94 val |= WDTP(booke_wdt_period);
95
96 mtspr(SPRN_TCR, val);
97}
98
99static void booke_wdt_set(void)
100{
101 on_each_cpu(__booke_wdt_set, NULL, 0);
102}
103
88static void __booke_wdt_ping(void *data) 104static void __booke_wdt_ping(void *data)
89{ 105{
90 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); 106 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
@@ -181,8 +197,7 @@ static long booke_wdt_ioctl(struct file *file,
181#else 197#else
182 booke_wdt_period = tmp; 198 booke_wdt_period = tmp;
183#endif 199#endif
184 mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP_MASK) | 200 booke_wdt_set();
185 WDTP(booke_wdt_period));
186 return 0; 201 return 0;
187 case WDIOC_GETTIMEOUT: 202 case WDIOC_GETTIMEOUT:
188 return put_user(booke_wdt_period, p); 203 return put_user(booke_wdt_period, p);
@@ -193,8 +208,15 @@ static long booke_wdt_ioctl(struct file *file,
193 return 0; 208 return 0;
194} 209}
195 210
211/* wdt_is_active stores wether or not the /dev/watchdog device is opened */
212static unsigned long wdt_is_active;
213
196static int booke_wdt_open(struct inode *inode, struct file *file) 214static int booke_wdt_open(struct inode *inode, struct file *file)
197{ 215{
216 /* /dev/watchdog can only be opened once */
217 if (test_and_set_bit(0, &wdt_is_active))
218 return -EBUSY;
219
198 spin_lock(&booke_wdt_lock); 220 spin_lock(&booke_wdt_lock);
199 if (booke_wdt_enabled == 0) { 221 if (booke_wdt_enabled == 0) {
200 booke_wdt_enabled = 1; 222 booke_wdt_enabled = 1;
@@ -210,8 +232,17 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
210 232
211static int booke_wdt_release(struct inode *inode, struct file *file) 233static int booke_wdt_release(struct inode *inode, struct file *file)
212{ 234{
235#ifndef CONFIG_WATCHDOG_NOWAYOUT
236 /* Normally, the watchdog is disabled when /dev/watchdog is closed, but
237 * if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the
238 * watchdog should remain enabled. So we disable it only if
239 * CONFIG_WATCHDOG_NOWAYOUT is not defined.
240 */
213 on_each_cpu(__booke_wdt_disable, NULL, 0); 241 on_each_cpu(__booke_wdt_disable, NULL, 0);
214 booke_wdt_enabled = 0; 242 booke_wdt_enabled = 0;
243#endif
244
245 clear_bit(0, &wdt_is_active);
215 246
216 return 0; 247 return 0;
217} 248}
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index 65e579635db..d4d8d1fdccc 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -42,18 +42,21 @@
42#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ 42#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
43#define SIO_REG_DEVREV 0x22 /* Device revision */ 43#define SIO_REG_DEVREV 0x22 /* Device revision */
44#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ 44#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
45#define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */
46#define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */
47#define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */
48#define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */
45#define SIO_REG_ENABLE 0x30 /* Logical device enable */ 49#define SIO_REG_ENABLE 0x30 /* Logical device enable */
46#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ 50#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
47 51
48#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ 52#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
49#define SIO_F71808_ID 0x0901 /* Chipset ID */ 53#define SIO_F71808_ID 0x0901 /* Chipset ID */
50#define SIO_F71858_ID 0x0507 /* Chipset ID */ 54#define SIO_F71858_ID 0x0507 /* Chipset ID */
51#define SIO_F71862_ID 0x0601 /* Chipset ID */ 55#define SIO_F71862_ID 0x0601 /* Chipset ID */
56#define SIO_F71869_ID 0x0814 /* Chipset ID */
52#define SIO_F71882_ID 0x0541 /* Chipset ID */ 57#define SIO_F71882_ID 0x0541 /* Chipset ID */
53#define SIO_F71889_ID 0x0723 /* Chipset ID */ 58#define SIO_F71889_ID 0x0723 /* Chipset ID */
54 59
55#define F71882FG_REG_START 0x01
56
57#define F71808FG_REG_WDO_CONF 0xf0 60#define F71808FG_REG_WDO_CONF 0xf0
58#define F71808FG_REG_WDT_CONF 0xf5 61#define F71808FG_REG_WDT_CONF 0xf5
59#define F71808FG_REG_WD_TIME 0xf6 62#define F71808FG_REG_WD_TIME 0xf6
@@ -70,13 +73,15 @@
70#define WATCHDOG_MAX_TIMEOUT (60 * 255) 73#define WATCHDOG_MAX_TIMEOUT (60 * 255)
71#define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for 74#define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for
72 watchdog signal */ 75 watchdog signal */
76#define WATCHDOG_F71862FG_PIN 63 /* default watchdog reset output
77 pin number 63 */
73 78
74static unsigned short force_id; 79static unsigned short force_id;
75module_param(force_id, ushort, 0); 80module_param(force_id, ushort, 0);
76MODULE_PARM_DESC(force_id, "Override the detected device ID"); 81MODULE_PARM_DESC(force_id, "Override the detected device ID");
77 82
78static const int max_timeout = WATCHDOG_MAX_TIMEOUT; 83static const int max_timeout = WATCHDOG_MAX_TIMEOUT;
79static int timeout = 60; /* default timeout in seconds */ 84static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */
80module_param(timeout, int, 0); 85module_param(timeout, int, 0);
81MODULE_PARM_DESC(timeout, 86MODULE_PARM_DESC(timeout,
82 "Watchdog timeout in seconds. 1<= timeout <=" 87 "Watchdog timeout in seconds. 1<= timeout <="
@@ -89,6 +94,12 @@ MODULE_PARM_DESC(pulse_width,
89 "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms" 94 "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms"
90 " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")"); 95 " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
91 96
97static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
98module_param(f71862fg_pin, uint, 0);
99MODULE_PARM_DESC(f71862fg_pin,
100 "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
101 " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
102
92static int nowayout = WATCHDOG_NOWAYOUT; 103static int nowayout = WATCHDOG_NOWAYOUT;
93module_param(nowayout, bool, 0444); 104module_param(nowayout, bool, 0444);
94MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); 105MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
@@ -98,12 +109,13 @@ module_param(start_withtimeout, uint, 0);
98MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" 109MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
99 " given initial timeout. Zero (default) disables this feature."); 110 " given initial timeout. Zero (default) disables this feature.");
100 111
101enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg }; 112enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg };
102 113
103static const char *f71808e_names[] = { 114static const char *f71808e_names[] = {
104 "f71808fg", 115 "f71808fg",
105 "f71858fg", 116 "f71858fg",
106 "f71862fg", 117 "f71862fg",
118 "f71869",
107 "f71882fg", 119 "f71882fg",
108 "f71889fg", 120 "f71889fg",
109}; 121};
@@ -282,6 +294,28 @@ exit_unlock:
282 return err; 294 return err;
283} 295}
284 296
297static int f71862fg_pin_configure(unsigned short ioaddr)
298{
299 /* When ioaddr is non-zero the calling function has to take care of
300 mutex handling and superio preparation! */
301
302 if (f71862fg_pin == 63) {
303 if (ioaddr) {
304 /* SPI must be disabled first to use this pin! */
305 superio_clear_bit(ioaddr, SIO_REG_ROM_ADDR_SEL, 6);
306 superio_set_bit(ioaddr, SIO_REG_MFUNCT3, 4);
307 }
308 } else if (f71862fg_pin == 56) {
309 if (ioaddr)
310 superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1);
311 } else {
312 printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n",
313 f71862fg_pin);
314 return -EINVAL;
315 }
316 return 0;
317}
318
285static int watchdog_start(void) 319static int watchdog_start(void)
286{ 320{
287 /* Make sure we don't die as soon as the watchdog is enabled below */ 321 /* Make sure we don't die as soon as the watchdog is enabled below */
@@ -299,19 +333,30 @@ static int watchdog_start(void)
299 switch (watchdog.type) { 333 switch (watchdog.type) {
300 case f71808fg: 334 case f71808fg:
301 /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */ 335 /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
302 superio_clear_bit(watchdog.sioaddr, 0x2a, 3); 336 superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT2, 3);
303 superio_clear_bit(watchdog.sioaddr, 0x2b, 3); 337 superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 3);
338 break;
339
340 case f71862fg:
341 err = f71862fg_pin_configure(watchdog.sioaddr);
342 if (err)
343 goto exit_superio;
344 break;
345
346 case f71869:
347 /* GPIO14 --> WDTRST# */
348 superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4);
304 break; 349 break;
305 350
306 case f71882fg: 351 case f71882fg:
307 /* Set pin 56 to WDTRST# */ 352 /* Set pin 56 to WDTRST# */
308 superio_set_bit(watchdog.sioaddr, 0x29, 1); 353 superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1);
309 break; 354 break;
310 355
311 case f71889fg: 356 case f71889fg:
312 /* set pin 40 to WDTRST# */ 357 /* set pin 40 to WDTRST# */
313 superio_outb(watchdog.sioaddr, 0x2b, 358 superio_outb(watchdog.sioaddr, SIO_REG_MFUNCT3,
314 superio_inb(watchdog.sioaddr, 0x2b) & 0xcf); 359 superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf);
315 break; 360 break;
316 361
317 default: 362 default:
@@ -711,16 +756,19 @@ static int __init f71808e_find(int sioaddr)
711 case SIO_F71808_ID: 756 case SIO_F71808_ID:
712 watchdog.type = f71808fg; 757 watchdog.type = f71808fg;
713 break; 758 break;
759 case SIO_F71862_ID:
760 watchdog.type = f71862fg;
761 err = f71862fg_pin_configure(0); /* validate module parameter */
762 break;
763 case SIO_F71869_ID:
764 watchdog.type = f71869;
765 break;
714 case SIO_F71882_ID: 766 case SIO_F71882_ID:
715 watchdog.type = f71882fg; 767 watchdog.type = f71882fg;
716 break; 768 break;
717 case SIO_F71889_ID: 769 case SIO_F71889_ID:
718 watchdog.type = f71889fg; 770 watchdog.type = f71889fg;
719 break; 771 break;
720 case SIO_F71862_ID:
721 /* These have a watchdog, though it isn't implemented (yet). */
722 err = -ENOSYS;
723 goto exit;
724 case SIO_F71858_ID: 772 case SIO_F71858_ID:
725 /* Confirmed (by datasheet) not to have a watchdog. */ 773 /* Confirmed (by datasheet) not to have a watchdog. */
726 err = -ENODEV; 774 err = -ENODEV;
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index b8838d2c67a..2c6c2b4ad8b 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * intel TCO Watchdog Driver 2 * intel TCO Watchdog Driver
3 * 3 *
4 * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. 4 * (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>.
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
@@ -26,13 +26,15 @@
26 * document number 301473-002, 301474-026: 82801F (ICH6) 26 * document number 301473-002, 301474-026: 82801F (ICH6)
27 * document number 313082-001, 313075-006: 631xESB, 632xESB 27 * document number 313082-001, 313075-006: 631xESB, 632xESB
28 * document number 307013-003, 307014-024: 82801G (ICH7) 28 * document number 307013-003, 307014-024: 82801G (ICH7)
29 * document number 322896-001, 322897-001: NM10
29 * document number 313056-003, 313057-017: 82801H (ICH8) 30 * document number 313056-003, 313057-017: 82801H (ICH8)
30 * document number 316972-004, 316973-012: 82801I (ICH9) 31 * document number 316972-004, 316973-012: 82801I (ICH9)
31 * document number 319973-002, 319974-002: 82801J (ICH10) 32 * document number 319973-002, 319974-002: 82801J (ICH10)
32 * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) 33 * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
33 * document number 320066-003, 320257-008: EP80597 (IICH) 34 * document number 320066-003, 320257-008: EP80597 (IICH)
34 * document number TBD : Cougar Point (CPT) 35 * document number 324645-001, 324646-001: Cougar Point (CPT)
35 * document number TBD : Patsburg (PBG) 36 * document number TBD : Patsburg (PBG)
37 * document number TBD : DH89xxCC
36 */ 38 */
37 39
38/* 40/*
@@ -85,6 +87,7 @@ enum iTCO_chipsets {
85 TCO_ICH7DH, /* ICH7DH */ 87 TCO_ICH7DH, /* ICH7DH */
86 TCO_ICH7M, /* ICH7-M & ICH7-U */ 88 TCO_ICH7M, /* ICH7-M & ICH7-U */
87 TCO_ICH7MDH, /* ICH7-M DH */ 89 TCO_ICH7MDH, /* ICH7-M DH */
90 TCO_NM10, /* NM10 */
88 TCO_ICH8, /* ICH8 & ICH8R */ 91 TCO_ICH8, /* ICH8 & ICH8R */
89 TCO_ICH8DH, /* ICH8DH */ 92 TCO_ICH8DH, /* ICH8DH */
90 TCO_ICH8DO, /* ICH8DO */ 93 TCO_ICH8DO, /* ICH8DO */
@@ -149,6 +152,7 @@ enum iTCO_chipsets {
149 TCO_CPT31, /* Cougar Point */ 152 TCO_CPT31, /* Cougar Point */
150 TCO_PBG1, /* Patsburg */ 153 TCO_PBG1, /* Patsburg */
151 TCO_PBG2, /* Patsburg */ 154 TCO_PBG2, /* Patsburg */
155 TCO_DH89XXCC, /* DH89xxCC */
152}; 156};
153 157
154static struct { 158static struct {
@@ -174,6 +178,7 @@ static struct {
174 {"ICH7DH", 2}, 178 {"ICH7DH", 2},
175 {"ICH7-M or ICH7-U", 2}, 179 {"ICH7-M or ICH7-U", 2},
176 {"ICH7-M DH", 2}, 180 {"ICH7-M DH", 2},
181 {"NM10", 2},
177 {"ICH8 or ICH8R", 2}, 182 {"ICH8 or ICH8R", 2},
178 {"ICH8DH", 2}, 183 {"ICH8DH", 2},
179 {"ICH8DO", 2}, 184 {"ICH8DO", 2},
@@ -238,6 +243,7 @@ static struct {
238 {"Cougar Point", 2}, 243 {"Cougar Point", 2},
239 {"Patsburg", 2}, 244 {"Patsburg", 2},
240 {"Patsburg", 2}, 245 {"Patsburg", 2},
246 {"DH89xxCC", 2},
241 {NULL, 0} 247 {NULL, 0}
242}; 248};
243 249
@@ -291,6 +297,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
291 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)}, 297 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)},
292 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)}, 298 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)},
293 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, 299 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)},
300 { ITCO_PCI_DEVICE(0x27bc, TCO_NM10)},
294 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)}, 301 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)},
295 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)}, 302 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)},
296 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)}, 303 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)},
@@ -355,6 +362,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
355 { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, 362 { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)},
356 { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, 363 { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)},
357 { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, 364 { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)},
365 { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)},
358 { 0, }, /* End of list */ 366 { 0, }, /* End of list */
359}; 367};
360MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); 368MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 2852bb2e3fd..811471903e8 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -21,7 +21,7 @@
21#include <linux/watchdog.h> 21#include <linux/watchdog.h>
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/uaccess.h> 23#include <linux/uaccess.h>
24#include <mach/timex.h> 24#include <mach/hardware.h>
25#include <mach/regs-timer.h> 25#include <mach/regs-timer.h>
26 26
27#define WDT_DEFAULT_TIME 5 /* seconds */ 27#define WDT_DEFAULT_TIME 5 /* seconds */
diff --git a/drivers/watchdog/m548x_wdt.c b/drivers/watchdog/m548x_wdt.c
new file mode 100644
index 00000000000..cabbcfe1c84
--- /dev/null
+++ b/drivers/watchdog/m548x_wdt.c
@@ -0,0 +1,227 @@
1/*
2 * drivers/watchdog/m548x_wdt.c
3 *
4 * Watchdog driver for ColdFire MCF548x processors
5 * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be>
6 *
7 * Adapted from the IXP4xx watchdog driver, which carries these notices:
8 *
9 * Author: Deepak Saxena <dsaxena@plexity.net>
10 *
11 * Copyright 2004 (c) MontaVista, Software, Inc.
12 * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
13 *
14 * This file is licensed under the terms of the GNU General Public
15 * License version 2. This program is licensed "as is" without any
16 * warranty of any kind, whether express or implied.
17 */
18
19#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/fs.h>
24#include <linux/miscdevice.h>
25#include <linux/watchdog.h>
26#include <linux/init.h>
27#include <linux/bitops.h>
28#include <linux/ioport.h>
29#include <linux/uaccess.h>
30
31#include <asm/coldfire.h>
32#include <asm/m548xsim.h>
33#include <asm/m548xgpt.h>
34
35static int nowayout = WATCHDOG_NOWAYOUT;
36static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */
37static unsigned long wdt_status;
38
39#define WDT_IN_USE 0
40#define WDT_OK_TO_CLOSE 1
41
42static void wdt_enable(void)
43{
44 unsigned int gms0;
45
46 /* preserve GPIO usage, if any */
47 gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
48 if (gms0 & MCF_GPT_GMS_TMS_GPIO)
49 gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK
50 | MCF_GPT_GMS_OD);
51 else
52 gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD;
53 __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
54 __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) |
55 MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0);
56 gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE;
57 __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
58}
59
60static void wdt_disable(void)
61{
62 unsigned int gms0;
63
64 /* disable watchdog */
65 gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
66 gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE);
67 __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
68}
69
70static void wdt_keepalive(void)
71{
72 unsigned int gms0;
73
74 gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0);
75 gms0 |= MCF_GPT_GMS_OCPW(0xA5);
76 __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0);
77}
78
79static int m548x_wdt_open(struct inode *inode, struct file *file)
80{
81 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
82 return -EBUSY;
83
84 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
85 wdt_enable();
86 return nonseekable_open(inode, file);
87}
88
89static ssize_t m548x_wdt_write(struct file *file, const char *data,
90 size_t len, loff_t *ppos)
91{
92 if (len) {
93 if (!nowayout) {
94 size_t i;
95
96 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
97
98 for (i = 0; i != len; i++) {
99 char c;
100
101 if (get_user(c, data + i))
102 return -EFAULT;
103 if (c == 'V')
104 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
105 }
106 }
107 wdt_keepalive();
108 }
109 return len;
110}
111
112static const struct watchdog_info ident = {
113 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
114 WDIOF_KEEPALIVEPING,
115 .identity = "Coldfire M548x Watchdog",
116};
117
118static long m548x_wdt_ioctl(struct file *file, unsigned int cmd,
119 unsigned long arg)
120{
121 int ret = -ENOTTY;
122 int time;
123
124 switch (cmd) {
125 case WDIOC_GETSUPPORT:
126 ret = copy_to_user((struct watchdog_info *)arg, &ident,
127 sizeof(ident)) ? -EFAULT : 0;
128 break;
129
130 case WDIOC_GETSTATUS:
131 ret = put_user(0, (int *)arg);
132 break;
133
134 case WDIOC_GETBOOTSTATUS:
135 ret = put_user(0, (int *)arg);
136 break;
137
138 case WDIOC_KEEPALIVE:
139 wdt_keepalive();
140 ret = 0;
141 break;
142
143 case WDIOC_SETTIMEOUT:
144 ret = get_user(time, (int *)arg);
145 if (ret)
146 break;
147
148 if (time <= 0 || time > 30) {
149 ret = -EINVAL;
150 break;
151 }
152
153 heartbeat = time;
154 wdt_enable();
155 /* Fall through */
156
157 case WDIOC_GETTIMEOUT:
158 ret = put_user(heartbeat, (int *)arg);
159 break;
160 }
161 return ret;
162}
163
164static int m548x_wdt_release(struct inode *inode, struct file *file)
165{
166 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
167 wdt_disable();
168 else {
169 printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
170 "timer will not stop\n");
171 wdt_keepalive();
172 }
173 clear_bit(WDT_IN_USE, &wdt_status);
174 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
175
176 return 0;
177}
178
179
180static const struct file_operations m548x_wdt_fops = {
181 .owner = THIS_MODULE,
182 .llseek = no_llseek,
183 .write = m548x_wdt_write,
184 .unlocked_ioctl = m548x_wdt_ioctl,
185 .open = m548x_wdt_open,
186 .release = m548x_wdt_release,
187};
188
189static struct miscdevice m548x_wdt_miscdev = {
190 .minor = WATCHDOG_MINOR,
191 .name = "watchdog",
192 .fops = &m548x_wdt_fops,
193};
194
195static int __init m548x_wdt_init(void)
196{
197 if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4,
198 "Coldfire M548x Watchdog")) {
199 printk(KERN_WARNING
200 "Coldfire M548x Watchdog : I/O region busy\n");
201 return -EBUSY;
202 }
203 printk(KERN_INFO "ColdFire watchdog driver is loaded.\n");
204
205 return misc_register(&m548x_wdt_miscdev);
206}
207
208static void __exit m548x_wdt_exit(void)
209{
210 misc_deregister(&m548x_wdt_miscdev);
211 release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4);
212}
213
214module_init(m548x_wdt_init);
215module_exit(m548x_wdt_exit);
216
217MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>");
218MODULE_DESCRIPTION("Coldfire M548x Watchdog");
219
220module_param(heartbeat, int, 0);
221MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)");
222
223module_param(nowayout, int, 0);
224MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
225
226MODULE_LICENSE("GPL");
227MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c
new file mode 100644
index 00000000000..1a50aa7079b
--- /dev/null
+++ b/drivers/watchdog/nv_tco.c
@@ -0,0 +1,512 @@
1/*
2 * nv_tco 0.01: TCO timer driver for NV chipsets
3 *
4 * (c) Copyright 2005 Google Inc., All Rights Reserved.
5 *
6 * Based off i8xx_tco.c:
7 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights
8 * Reserved.
9 * http://www.kernelconcepts.de
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 * TCO timer driver for NV chipsets
17 * based on softdog.c by Alan Cox <alan@redhat.com>
18 */
19
20/*
21 * Includes, defines, variables, module parameters, ...
22 */
23
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/types.h>
27#include <linux/miscdevice.h>
28#include <linux/watchdog.h>
29#include <linux/init.h>
30#include <linux/fs.h>
31#include <linux/pci.h>
32#include <linux/ioport.h>
33#include <linux/jiffies.h>
34#include <linux/platform_device.h>
35#include <linux/uaccess.h>
36#include <linux/io.h>
37
38#include "nv_tco.h"
39
40/* Module and version information */
41#define TCO_VERSION "0.01"
42#define TCO_MODULE_NAME "NV_TCO"
43#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
44#define PFX TCO_MODULE_NAME ": "
45
46/* internal variables */
47static unsigned int tcobase;
48static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */
49static unsigned long timer_alive;
50static char tco_expect_close;
51static struct pci_dev *tco_pci;
52
53/* the watchdog platform device */
54static struct platform_device *nv_tco_platform_device;
55
56/* module parameters */
57#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (2<heartbeat<39) */
58static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
59module_param(heartbeat, int, 0);
60MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, "
61 "default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
62
63static int nowayout = WATCHDOG_NOWAYOUT;
64module_param(nowayout, int, 0);
65MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
66 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
67
68/*
69 * Some TCO specific functions
70 */
71static inline unsigned char seconds_to_ticks(int seconds)
72{
73 /* the internal timer is stored as ticks which decrement
74 * every 0.6 seconds */
75 return (seconds * 10) / 6;
76}
77
78static void tco_timer_start(void)
79{
80 u32 val;
81 unsigned long flags;
82
83 spin_lock_irqsave(&tco_lock, flags);
84 val = inl(TCO_CNT(tcobase));
85 val &= ~TCO_CNT_TCOHALT;
86 outl(val, TCO_CNT(tcobase));
87 spin_unlock_irqrestore(&tco_lock, flags);
88}
89
90static void tco_timer_stop(void)
91{
92 u32 val;
93 unsigned long flags;
94
95 spin_lock_irqsave(&tco_lock, flags);
96 val = inl(TCO_CNT(tcobase));
97 val |= TCO_CNT_TCOHALT;
98 outl(val, TCO_CNT(tcobase));
99 spin_unlock_irqrestore(&tco_lock, flags);
100}
101
102static void tco_timer_keepalive(void)
103{
104 unsigned long flags;
105
106 spin_lock_irqsave(&tco_lock, flags);
107 outb(0x01, TCO_RLD(tcobase));
108 spin_unlock_irqrestore(&tco_lock, flags);
109}
110
111static int tco_timer_set_heartbeat(int t)
112{
113 int ret = 0;
114 unsigned char tmrval;
115 unsigned long flags;
116 u8 val;
117
118 /*
119 * note seconds_to_ticks(t) > t, so if t > 0x3f, so is
120 * tmrval=seconds_to_ticks(t). Check that the count in seconds isn't
121 * out of range on it's own (to avoid overflow in tmrval).
122 */
123 if (t < 0 || t > 0x3f)
124 return -EINVAL;
125 tmrval = seconds_to_ticks(t);
126
127 /* "Values of 0h-3h are ignored and should not be attempted" */
128 if (tmrval > 0x3f || tmrval < 0x04)
129 return -EINVAL;
130
131 /* Write new heartbeat to watchdog */
132 spin_lock_irqsave(&tco_lock, flags);
133 val = inb(TCO_TMR(tcobase));
134 val &= 0xc0;
135 val |= tmrval;
136 outb(val, TCO_TMR(tcobase));
137 val = inb(TCO_TMR(tcobase));
138
139 if ((val & 0x3f) != tmrval)
140 ret = -EINVAL;
141 spin_unlock_irqrestore(&tco_lock, flags);
142
143 if (ret)
144 return ret;
145
146 heartbeat = t;
147 return 0;
148}
149
150/*
151 * /dev/watchdog handling
152 */
153
154static int nv_tco_open(struct inode *inode, struct file *file)
155{
156 /* /dev/watchdog can only be opened once */
157 if (test_and_set_bit(0, &timer_alive))
158 return -EBUSY;
159
160 /* Reload and activate timer */
161 tco_timer_keepalive();
162 tco_timer_start();
163 return nonseekable_open(inode, file);
164}
165
166static int nv_tco_release(struct inode *inode, struct file *file)
167{
168 /* Shut off the timer */
169 if (tco_expect_close == 42) {
170 tco_timer_stop();
171 } else {
172 printk(KERN_CRIT PFX "Unexpected close, not stopping "
173 "watchdog!\n");
174 tco_timer_keepalive();
175 }
176 clear_bit(0, &timer_alive);
177 tco_expect_close = 0;
178 return 0;
179}
180
181static ssize_t nv_tco_write(struct file *file, const char __user *data,
182 size_t len, loff_t *ppos)
183{
184 /* See if we got the magic character 'V' and reload the timer */
185 if (len) {
186 if (!nowayout) {
187 size_t i;
188
189 /*
190 * note: just in case someone wrote the magic character
191 * five months ago...
192 */
193 tco_expect_close = 0;
194
195 /*
196 * scan to see whether or not we got the magic
197 * character
198 */
199 for (i = 0; i != len; i++) {
200 char c;
201 if (get_user(c, data + i))
202 return -EFAULT;
203 if (c == 'V')
204 tco_expect_close = 42;
205 }
206 }
207
208 /* someone wrote to us, we should reload the timer */
209 tco_timer_keepalive();
210 }
211 return len;
212}
213
214static long nv_tco_ioctl(struct file *file, unsigned int cmd,
215 unsigned long arg)
216{
217 int new_options, retval = -EINVAL;
218 int new_heartbeat;
219 void __user *argp = (void __user *)arg;
220 int __user *p = argp;
221 static const struct watchdog_info ident = {
222 .options = WDIOF_SETTIMEOUT |
223 WDIOF_KEEPALIVEPING |
224 WDIOF_MAGICCLOSE,
225 .firmware_version = 0,
226 .identity = TCO_MODULE_NAME,
227 };
228
229 switch (cmd) {
230 case WDIOC_GETSUPPORT:
231 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
232 case WDIOC_GETSTATUS:
233 case WDIOC_GETBOOTSTATUS:
234 return put_user(0, p);
235 case WDIOC_SETOPTIONS:
236 if (get_user(new_options, p))
237 return -EFAULT;
238 if (new_options & WDIOS_DISABLECARD) {
239 tco_timer_stop();
240 retval = 0;
241 }
242 if (new_options & WDIOS_ENABLECARD) {
243 tco_timer_keepalive();
244 tco_timer_start();
245 retval = 0;
246 }
247 return retval;
248 case WDIOC_KEEPALIVE:
249 tco_timer_keepalive();
250 return 0;
251 case WDIOC_SETTIMEOUT:
252 if (get_user(new_heartbeat, p))
253 return -EFAULT;
254 if (tco_timer_set_heartbeat(new_heartbeat))
255 return -EINVAL;
256 tco_timer_keepalive();
257 /* Fall through */
258 case WDIOC_GETTIMEOUT:
259 return put_user(heartbeat, p);
260 default:
261 return -ENOTTY;
262 }
263}
264
265/*
266 * Kernel Interfaces
267 */
268
269static const struct file_operations nv_tco_fops = {
270 .owner = THIS_MODULE,
271 .llseek = no_llseek,
272 .write = nv_tco_write,
273 .unlocked_ioctl = nv_tco_ioctl,
274 .open = nv_tco_open,
275 .release = nv_tco_release,
276};
277
278static struct miscdevice nv_tco_miscdev = {
279 .minor = WATCHDOG_MINOR,
280 .name = "watchdog",
281 .fops = &nv_tco_fops,
282};
283
284/*
285 * Data for PCI driver interface
286 *
287 * This data only exists for exporting the supported
288 * PCI ids via MODULE_DEVICE_TABLE. We do not actually
289 * register a pci_driver, because someone else might one day
290 * want to register another driver on the same PCI id.
291 */
292static struct pci_device_id tco_pci_tbl[] = {
293 { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
294 PCI_ANY_ID, PCI_ANY_ID, },
295 { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
296 PCI_ANY_ID, PCI_ANY_ID, },
297 { 0, }, /* End of list */
298};
299MODULE_DEVICE_TABLE(pci, tco_pci_tbl);
300
301/*
302 * Init & exit routines
303 */
304
305static unsigned char __init nv_tco_getdevice(void)
306{
307 struct pci_dev *dev = NULL;
308 u32 val;
309
310 /* Find the PCI device */
311 for_each_pci_dev(dev) {
312 if (pci_match_id(tco_pci_tbl, dev) != NULL) {
313 tco_pci = dev;
314 break;
315 }
316 }
317
318 if (!tco_pci)
319 return 0;
320
321 /* Find the base io port */
322 pci_read_config_dword(tco_pci, 0x64, &val);
323 val &= 0xffff;
324 if (val == 0x0001 || val == 0x0000) {
325 /* Something is wrong here, bar isn't setup */
326 printk(KERN_ERR PFX "failed to get tcobase address\n");
327 return 0;
328 }
329 val &= 0xff00;
330 tcobase = val + 0x40;
331
332 if (!request_region(tcobase, 0x10, "NV TCO")) {
333 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
334 tcobase);
335 return 0;
336 }
337
338 /* Set a reasonable heartbeat before we stop the timer */
339 tco_timer_set_heartbeat(30);
340
341 /*
342 * Stop the TCO before we change anything so we don't race with
343 * a zeroed timer.
344 */
345 tco_timer_keepalive();
346 tco_timer_stop();
347
348 /* Disable SMI caused by TCO */
349 if (!request_region(MCP51_SMI_EN(tcobase), 4, "NV TCO")) {
350 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
351 MCP51_SMI_EN(tcobase));
352 goto out;
353 }
354 val = inl(MCP51_SMI_EN(tcobase));
355 val &= ~MCP51_SMI_EN_TCO;
356 outl(val, MCP51_SMI_EN(tcobase));
357 val = inl(MCP51_SMI_EN(tcobase));
358 release_region(MCP51_SMI_EN(tcobase), 4);
359 if (val & MCP51_SMI_EN_TCO) {
360 printk(KERN_ERR PFX "Could not disable SMI caused by TCO\n");
361 goto out;
362 }
363
364 /* Check chipset's NO_REBOOT bit */
365 pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
366 val |= MCP51_SMBUS_SETUP_B_TCO_REBOOT;
367 pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
368 pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
369 if (!(val & MCP51_SMBUS_SETUP_B_TCO_REBOOT)) {
370 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot "
371 "disabled by hardware\n");
372 goto out;
373 }
374
375 return 1;
376out:
377 release_region(tcobase, 0x10);
378 return 0;
379}
380
381static int __devinit nv_tco_init(struct platform_device *dev)
382{
383 int ret;
384
385 /* Check whether or not the hardware watchdog is there */
386 if (!nv_tco_getdevice())
387 return -ENODEV;
388
389 /* Check to see if last reboot was due to watchdog timeout */
390 printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
391 inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not ");
392
393 /* Clear out the old status */
394 outl(TCO_STS_RESET, TCO_STS(tcobase));
395
396 /*
397 * Check that the heartbeat value is within it's range.
398 * If not, reset to the default.
399 */
400 if (tco_timer_set_heartbeat(heartbeat)) {
401 heartbeat = WATCHDOG_HEARTBEAT;
402 tco_timer_set_heartbeat(heartbeat);
403 printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, "
404 "using %d\n", heartbeat);
405 }
406
407 ret = misc_register(&nv_tco_miscdev);
408 if (ret != 0) {
409 printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
410 "(err=%d)\n", WATCHDOG_MINOR, ret);
411 goto unreg_region;
412 }
413
414 clear_bit(0, &timer_alive);
415
416 tco_timer_stop();
417
418 printk(KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec "
419 "(nowayout=%d)\n", tcobase, heartbeat, nowayout);
420
421 return 0;
422
423unreg_region:
424 release_region(tcobase, 0x10);
425 return ret;
426}
427
428static void __devexit nv_tco_cleanup(void)
429{
430 u32 val;
431
432 /* Stop the timer before we leave */
433 if (!nowayout)
434 tco_timer_stop();
435
436 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
437 pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
438 val &= ~MCP51_SMBUS_SETUP_B_TCO_REBOOT;
439 pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val);
440 pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val);
441 if (val & MCP51_SMBUS_SETUP_B_TCO_REBOOT) {
442 printk(KERN_CRIT PFX "Couldn't unset REBOOT bit. Machine may "
443 "soon reset\n");
444 }
445
446 /* Deregister */
447 misc_deregister(&nv_tco_miscdev);
448 release_region(tcobase, 0x10);
449}
450
451static int __devexit nv_tco_remove(struct platform_device *dev)
452{
453 if (tcobase)
454 nv_tco_cleanup();
455
456 return 0;
457}
458
459static void nv_tco_shutdown(struct platform_device *dev)
460{
461 tco_timer_stop();
462}
463
464static struct platform_driver nv_tco_driver = {
465 .probe = nv_tco_init,
466 .remove = __devexit_p(nv_tco_remove),
467 .shutdown = nv_tco_shutdown,
468 .driver = {
469 .owner = THIS_MODULE,
470 .name = TCO_MODULE_NAME,
471 },
472};
473
474static int __init nv_tco_init_module(void)
475{
476 int err;
477
478 printk(KERN_INFO PFX "NV TCO WatchDog Timer Driver v%s\n",
479 TCO_VERSION);
480
481 err = platform_driver_register(&nv_tco_driver);
482 if (err)
483 return err;
484
485 nv_tco_platform_device = platform_device_register_simple(
486 TCO_MODULE_NAME, -1, NULL, 0);
487 if (IS_ERR(nv_tco_platform_device)) {
488 err = PTR_ERR(nv_tco_platform_device);
489 goto unreg_platform_driver;
490 }
491
492 return 0;
493
494unreg_platform_driver:
495 platform_driver_unregister(&nv_tco_driver);
496 return err;
497}
498
499static void __exit nv_tco_cleanup_module(void)
500{
501 platform_device_unregister(nv_tco_platform_device);
502 platform_driver_unregister(&nv_tco_driver);
503 printk(KERN_INFO PFX "NV TCO Watchdog Module Unloaded.\n");
504}
505
506module_init(nv_tco_init_module);
507module_exit(nv_tco_cleanup_module);
508
509MODULE_AUTHOR("Mike Waychison");
510MODULE_DESCRIPTION("TCO timer driver for NV chipsets");
511MODULE_LICENSE("GPL");
512MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/nv_tco.h b/drivers/watchdog/nv_tco.h
new file mode 100644
index 00000000000..c2d1d04e055
--- /dev/null
+++ b/drivers/watchdog/nv_tco.h
@@ -0,0 +1,64 @@
1/*
2 * nv_tco: TCO timer driver for nVidia chipsets.
3 *
4 * (c) Copyright 2005 Google Inc., All Rights Reserved.
5 *
6 * Supported Chipsets:
7 * - MCP51/MCP55
8 *
9 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights
10 * Reserved.
11 * http://www.kernelconcepts.de
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
17 *
18 * Neither kernel concepts nor Nils Faerber admit liability nor provide
19 * warranty for any of this software. This material is provided
20 * "AS-IS" and at no charge.
21 *
22 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
23 * developed for
24 * Jentro AG, Haar/Munich (Germany)
25 *
26 * TCO timer driver for NV chipsets
27 * based on softdog.c by Alan Cox <alan@redhat.com>
28 */
29
30/*
31 * Some address definitions for the TCO
32 */
33
34#define TCO_RLD(base) ((base) + 0x00) /* TCO Timer Reload and Current Value */
35#define TCO_TMR(base) ((base) + 0x01) /* TCO Timer Initial Value */
36
37#define TCO_STS(base) ((base) + 0x04) /* TCO Status Register */
38/*
39 * TCO Boot Status bit: set on TCO reset, reset by software or standby
40 * power-good (survives reboots), unfortunately this bit is never
41 * set.
42 */
43# define TCO_STS_BOOT_STS (1 << 9)
44/*
45 * first and 2nd timeout status bits, these also survive a warm boot,
46 * and they work, so we use them.
47 */
48# define TCO_STS_TCO_INT_STS (1 << 1)
49# define TCO_STS_TCO2TO_STS (1 << 10)
50# define TCO_STS_RESET (TCO_STS_BOOT_STS | TCO_STS_TCO2TO_STS | \
51 TCO_STS_TCO_INT_STS)
52
53#define TCO_CNT(base) ((base) + 0x08) /* TCO Control Register */
54# define TCO_CNT_TCOHALT (1 << 12)
55
56#define MCP51_SMBUS_SETUP_B 0xe8
57# define MCP51_SMBUS_SETUP_B_TCO_REBOOT (1 << 25)
58
59/*
60 * The SMI_EN register is at the base io address + 0x04,
61 * while TCOBASE is + 0x40.
62 */
63#define MCP51_SMI_EN(base) ((base) - 0x40 + 0x04)
64# define MCP51_SMI_EN_TCO ((1 << 4) | (1 << 5))
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
new file mode 100644
index 00000000000..808372883e8
--- /dev/null
+++ b/drivers/watchdog/sp5100_tco.c
@@ -0,0 +1,480 @@
1/*
2 * sp5100_tco : TCO timer driver for sp5100 chipsets
3 *
4 * (c) Copyright 2009 Google Inc., All Rights Reserved.
5 *
6 * Based on i8xx_tco.c:
7 * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights
8 * Reserved.
9 * http://www.kernelconcepts.de
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide"
17 */
18
19/*
20 * Includes, defines, variables, module parameters, ...
21 */
22
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/types.h>
26#include <linux/miscdevice.h>
27#include <linux/watchdog.h>
28#include <linux/init.h>
29#include <linux/fs.h>
30#include <linux/pci.h>
31#include <linux/ioport.h>
32#include <linux/platform_device.h>
33#include <linux/uaccess.h>
34#include <linux/io.h>
35
36#include "sp5100_tco.h"
37
38/* Module and version information */
39#define TCO_VERSION "0.01"
40#define TCO_MODULE_NAME "SP5100 TCO timer"
41#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
42#define PFX TCO_MODULE_NAME ": "
43
44/* internal variables */
45static void __iomem *tcobase;
46static unsigned int pm_iobase;
47static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */
48static unsigned long timer_alive;
49static char tco_expect_close;
50static struct pci_dev *sp5100_tco_pci;
51
52/* the watchdog platform device */
53static struct platform_device *sp5100_tco_platform_device;
54
55/* module parameters */
56
57#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat. */
58static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
59module_param(heartbeat, int, 0);
60MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
61 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
62
63static int nowayout = WATCHDOG_NOWAYOUT;
64module_param(nowayout, int, 0);
65MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
66 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
67
68/*
69 * Some TCO specific functions
70 */
71static void tco_timer_start(void)
72{
73 u32 val;
74 unsigned long flags;
75
76 spin_lock_irqsave(&tco_lock, flags);
77 val = readl(SP5100_WDT_CONTROL(tcobase));
78 val |= SP5100_WDT_START_STOP_BIT;
79 writel(val, SP5100_WDT_CONTROL(tcobase));
80 spin_unlock_irqrestore(&tco_lock, flags);
81}
82
83static void tco_timer_stop(void)
84{
85 u32 val;
86 unsigned long flags;
87
88 spin_lock_irqsave(&tco_lock, flags);
89 val = readl(SP5100_WDT_CONTROL(tcobase));
90 val &= ~SP5100_WDT_START_STOP_BIT;
91 writel(val, SP5100_WDT_CONTROL(tcobase));
92 spin_unlock_irqrestore(&tco_lock, flags);
93}
94
95static void tco_timer_keepalive(void)
96{
97 u32 val;
98 unsigned long flags;
99
100 spin_lock_irqsave(&tco_lock, flags);
101 val = readl(SP5100_WDT_CONTROL(tcobase));
102 val |= SP5100_WDT_TRIGGER_BIT;
103 writel(val, SP5100_WDT_CONTROL(tcobase));
104 spin_unlock_irqrestore(&tco_lock, flags);
105}
106
107static int tco_timer_set_heartbeat(int t)
108{
109 unsigned long flags;
110
111 if (t < 0 || t > 0xffff)
112 return -EINVAL;
113
114 /* Write new heartbeat to watchdog */
115 spin_lock_irqsave(&tco_lock, flags);
116 writel(t, SP5100_WDT_COUNT(tcobase));
117 spin_unlock_irqrestore(&tco_lock, flags);
118
119 heartbeat = t;
120 return 0;
121}
122
123/*
124 * /dev/watchdog handling
125 */
126
127static int sp5100_tco_open(struct inode *inode, struct file *file)
128{
129 /* /dev/watchdog can only be opened once */
130 if (test_and_set_bit(0, &timer_alive))
131 return -EBUSY;
132
133 /* Reload and activate timer */
134 tco_timer_start();
135 tco_timer_keepalive();
136 return nonseekable_open(inode, file);
137}
138
139static int sp5100_tco_release(struct inode *inode, struct file *file)
140{
141 /* Shut off the timer. */
142 if (tco_expect_close == 42) {
143 tco_timer_stop();
144 } else {
145 printk(KERN_CRIT PFX
146 "Unexpected close, not stopping watchdog!\n");
147 tco_timer_keepalive();
148 }
149 clear_bit(0, &timer_alive);
150 tco_expect_close = 0;
151 return 0;
152}
153
154static ssize_t sp5100_tco_write(struct file *file, const char __user *data,
155 size_t len, loff_t *ppos)
156{
157 /* See if we got the magic character 'V' and reload the timer */
158 if (len) {
159 if (!nowayout) {
160 size_t i;
161
162 /* note: just in case someone wrote the magic character
163 * five months ago... */
164 tco_expect_close = 0;
165
166 /* scan to see whether or not we got the magic character
167 */
168 for (i = 0; i != len; i++) {
169 char c;
170 if (get_user(c, data + i))
171 return -EFAULT;
172 if (c == 'V')
173 tco_expect_close = 42;
174 }
175 }
176
177 /* someone wrote to us, we should reload the timer */
178 tco_timer_keepalive();
179 }
180 return len;
181}
182
183static long sp5100_tco_ioctl(struct file *file, unsigned int cmd,
184 unsigned long arg)
185{
186 int new_options, retval = -EINVAL;
187 int new_heartbeat;
188 void __user *argp = (void __user *)arg;
189 int __user *p = argp;
190 static const struct watchdog_info ident = {
191 .options = WDIOF_SETTIMEOUT |
192 WDIOF_KEEPALIVEPING |
193 WDIOF_MAGICCLOSE,
194 .firmware_version = 0,
195 .identity = TCO_MODULE_NAME,
196 };
197
198 switch (cmd) {
199 case WDIOC_GETSUPPORT:
200 return copy_to_user(argp, &ident,
201 sizeof(ident)) ? -EFAULT : 0;
202 case WDIOC_GETSTATUS:
203 case WDIOC_GETBOOTSTATUS:
204 return put_user(0, p);
205 case WDIOC_SETOPTIONS:
206 if (get_user(new_options, p))
207 return -EFAULT;
208 if (new_options & WDIOS_DISABLECARD) {
209 tco_timer_stop();
210 retval = 0;
211 }
212 if (new_options & WDIOS_ENABLECARD) {
213 tco_timer_start();
214 tco_timer_keepalive();
215 retval = 0;
216 }
217 return retval;
218 case WDIOC_KEEPALIVE:
219 tco_timer_keepalive();
220 return 0;
221 case WDIOC_SETTIMEOUT:
222 if (get_user(new_heartbeat, p))
223 return -EFAULT;
224 if (tco_timer_set_heartbeat(new_heartbeat))
225 return -EINVAL;
226 tco_timer_keepalive();
227 /* Fall through */
228 case WDIOC_GETTIMEOUT:
229 return put_user(heartbeat, p);
230 default:
231 return -ENOTTY;
232 }
233}
234
235/*
236 * Kernel Interfaces
237 */
238
239static const struct file_operations sp5100_tco_fops = {
240 .owner = THIS_MODULE,
241 .llseek = no_llseek,
242 .write = sp5100_tco_write,
243 .unlocked_ioctl = sp5100_tco_ioctl,
244 .open = sp5100_tco_open,
245 .release = sp5100_tco_release,
246};
247
248static struct miscdevice sp5100_tco_miscdev = {
249 .minor = WATCHDOG_MINOR,
250 .name = "watchdog",
251 .fops = &sp5100_tco_fops,
252};
253
254/*
255 * Data for PCI driver interface
256 *
257 * This data only exists for exporting the supported
258 * PCI ids via MODULE_DEVICE_TABLE. We do not actually
259 * register a pci_driver, because someone else might
260 * want to register another driver on the same PCI id.
261 */
262static struct pci_device_id sp5100_tco_pci_tbl[] = {
263 { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
264 PCI_ANY_ID, },
265 { 0, }, /* End of list */
266};
267MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl);
268
269/*
270 * Init & exit routines
271 */
272
273static unsigned char __devinit sp5100_tco_setupdevice(void)
274{
275 struct pci_dev *dev = NULL;
276 u32 val;
277
278 /* Match the PCI device */
279 for_each_pci_dev(dev) {
280 if (pci_match_id(sp5100_tco_pci_tbl, dev) != NULL) {
281 sp5100_tco_pci = dev;
282 break;
283 }
284 }
285
286 if (!sp5100_tco_pci)
287 return 0;
288
289 /* Request the IO ports used by this driver */
290 pm_iobase = SP5100_IO_PM_INDEX_REG;
291 if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) {
292 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
293 pm_iobase);
294 goto exit;
295 }
296
297 /* Find the watchdog base address. */
298 outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG);
299 val = inb(SP5100_IO_PM_DATA_REG);
300 outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG);
301 val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
302 outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG);
303 val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
304 outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG);
305 /* Low three bits of BASE0 are reserved. */
306 val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8);
307
308 tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
309 if (tcobase == 0) {
310 printk(KERN_ERR PFX "failed to get tcobase address\n");
311 goto unreg_region;
312 }
313
314 /* Enable watchdog decode bit */
315 pci_read_config_dword(sp5100_tco_pci,
316 SP5100_PCI_WATCHDOG_MISC_REG,
317 &val);
318
319 val |= SP5100_PCI_WATCHDOG_DECODE_EN;
320
321 pci_write_config_dword(sp5100_tco_pci,
322 SP5100_PCI_WATCHDOG_MISC_REG,
323 val);
324
325 /* Enable Watchdog timer and set the resolution to 1 sec. */
326 outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
327 val = inb(SP5100_IO_PM_DATA_REG);
328 val |= SP5100_PM_WATCHDOG_SECOND_RES;
329 val &= ~SP5100_PM_WATCHDOG_DISABLE;
330 outb(val, SP5100_IO_PM_DATA_REG);
331
332 /* Check that the watchdog action is set to reset the system. */
333 val = readl(SP5100_WDT_CONTROL(tcobase));
334 val &= ~SP5100_PM_WATCHDOG_ACTION_RESET;
335 writel(val, SP5100_WDT_CONTROL(tcobase));
336
337 /* Set a reasonable heartbeat before we stop the timer */
338 tco_timer_set_heartbeat(heartbeat);
339
340 /*
341 * Stop the TCO before we change anything so we don't race with
342 * a zeroed timer.
343 */
344 tco_timer_stop();
345
346 /* Done */
347 return 1;
348
349 iounmap(tcobase);
350unreg_region:
351 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
352exit:
353 return 0;
354}
355
356static int __devinit sp5100_tco_init(struct platform_device *dev)
357{
358 int ret;
359 u32 val;
360
361 /* Check whether or not the hardware watchdog is there. If found, then
362 * set it up.
363 */
364 if (!sp5100_tco_setupdevice())
365 return -ENODEV;
366
367 /* Check to see if last reboot was due to watchdog timeout */
368 printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n",
369 readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
370 "" : "not ");
371
372 /* Clear out the old status */
373 val = readl(SP5100_WDT_CONTROL(tcobase));
374 val &= ~SP5100_PM_WATCHDOG_FIRED;
375 writel(val, SP5100_WDT_CONTROL(tcobase));
376
377 /*
378 * Check that the heartbeat value is within it's range.
379 * If not, reset to the default.
380 */
381 if (tco_timer_set_heartbeat(heartbeat)) {
382 heartbeat = WATCHDOG_HEARTBEAT;
383 tco_timer_set_heartbeat(heartbeat);
384 }
385
386 ret = misc_register(&sp5100_tco_miscdev);
387 if (ret != 0) {
388 printk(KERN_ERR PFX "cannot register miscdev on minor="
389 "%d (err=%d)\n",
390 WATCHDOG_MINOR, ret);
391 goto exit;
392 }
393
394 clear_bit(0, &timer_alive);
395
396 printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec"
397 " (nowayout=%d)\n",
398 tcobase, heartbeat, nowayout);
399
400 return 0;
401
402exit:
403 iounmap(tcobase);
404 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
405 return ret;
406}
407
408static void __devexit sp5100_tco_cleanup(void)
409{
410 /* Stop the timer before we leave */
411 if (!nowayout)
412 tco_timer_stop();
413
414 /* Deregister */
415 misc_deregister(&sp5100_tco_miscdev);
416 iounmap(tcobase);
417 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
418}
419
420static int __devexit sp5100_tco_remove(struct platform_device *dev)
421{
422 if (tcobase)
423 sp5100_tco_cleanup();
424 return 0;
425}
426
427static void sp5100_tco_shutdown(struct platform_device *dev)
428{
429 tco_timer_stop();
430}
431
432static struct platform_driver sp5100_tco_driver = {
433 .probe = sp5100_tco_init,
434 .remove = __devexit_p(sp5100_tco_remove),
435 .shutdown = sp5100_tco_shutdown,
436 .driver = {
437 .owner = THIS_MODULE,
438 .name = TCO_MODULE_NAME,
439 },
440};
441
442static int __init sp5100_tco_init_module(void)
443{
444 int err;
445
446 printk(KERN_INFO PFX "SP5100 TCO WatchDog Timer Driver v%s\n",
447 TCO_VERSION);
448
449 err = platform_driver_register(&sp5100_tco_driver);
450 if (err)
451 return err;
452
453 sp5100_tco_platform_device = platform_device_register_simple(
454 TCO_MODULE_NAME, -1, NULL, 0);
455 if (IS_ERR(sp5100_tco_platform_device)) {
456 err = PTR_ERR(sp5100_tco_platform_device);
457 goto unreg_platform_driver;
458 }
459
460 return 0;
461
462unreg_platform_driver:
463 platform_driver_unregister(&sp5100_tco_driver);
464 return err;
465}
466
467static void __exit sp5100_tco_cleanup_module(void)
468{
469 platform_device_unregister(sp5100_tco_platform_device);
470 platform_driver_unregister(&sp5100_tco_driver);
471 printk(KERN_INFO PFX "SP5100 TCO Watchdog Module Unloaded.\n");
472}
473
474module_init(sp5100_tco_init_module);
475module_exit(sp5100_tco_cleanup_module);
476
477MODULE_AUTHOR("Priyanka Gupta");
478MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset");
479MODULE_LICENSE("GPL");
480MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h
new file mode 100644
index 00000000000..a5a16cc90a3
--- /dev/null
+++ b/drivers/watchdog/sp5100_tco.h
@@ -0,0 +1,41 @@
1/*
2 * sp5100_tco: TCO timer driver for sp5100 chipsets.
3 *
4 * (c) Copyright 2009 Google Inc., All Rights Reserved.
5 *
6 * TCO timer driver for sp5100 chipsets
7 */
8
9/*
10 * Some address definitions for the Watchdog
11 */
12
13#define SP5100_WDT_MEM_MAP_SIZE 0x08
14#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */
15#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */
16
17#define SP5100_WDT_START_STOP_BIT 1
18#define SP5100_WDT_TRIGGER_BIT (1 << 7)
19
20#define SP5100_PCI_WATCHDOG_MISC_REG 0x41
21#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
22
23#define SP5100_PM_IOPORTS_SIZE 0x02
24
25/* These two IO registers are hardcoded and there doesn't seem to be a way to
26 * read them from a register.
27 */
28#define SP5100_IO_PM_INDEX_REG 0xCD6
29#define SP5100_IO_PM_DATA_REG 0xCD7
30
31#define SP5100_PM_WATCHDOG_CONTROL 0x69
32#define SP5100_PM_WATCHDOG_BASE0 0x6C
33#define SP5100_PM_WATCHDOG_BASE1 0x6D
34#define SP5100_PM_WATCHDOG_BASE2 0x6E
35#define SP5100_PM_WATCHDOG_BASE3 0x6F
36
37#define SP5100_PM_WATCHDOG_FIRED (1 << 1)
38#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2)
39
40#define SP5100_PM_WATCHDOG_DISABLE 1
41#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1)
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 0f5288df009..e5c91d4404e 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -42,7 +42,7 @@
42 42
43#include <asm/system.h> 43#include <asm/system.h>
44 44
45#define WATCHDOG_NAME "w83627hf/thf/hg WDT" 45#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
46#define PFX WATCHDOG_NAME ": " 46#define PFX WATCHDOG_NAME ": "
47#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ 47#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
48 48
@@ -89,7 +89,7 @@ static void w83627hf_select_wd_register(void)
89 c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ 89 c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
90 outb_p(0x2b, WDT_EFER); 90 outb_p(0x2b, WDT_EFER);
91 outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */ 91 outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */
92 } else if (c == 0x88) { /* W83627EHF */ 92 } else if (c == 0x88 || c == 0xa0) { /* W83627EHF / W83627DHG */
93 outb_p(0x2d, WDT_EFER); /* select GPIO5 */ 93 outb_p(0x2d, WDT_EFER); /* select GPIO5 */
94 c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */ 94 c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */
95 outb_p(0x2d, WDT_EFER); 95 outb_p(0x2d, WDT_EFER);
@@ -129,6 +129,8 @@ static void w83627hf_init(void)
129 t = inb_p(WDT_EFDR); /* read CRF5 */ 129 t = inb_p(WDT_EFDR); /* read CRF5 */
130 t &= ~0x0C; /* set second mode & disable keyboard 130 t &= ~0x0C; /* set second mode & disable keyboard
131 turning off watchdog */ 131 turning off watchdog */
132 t |= 0x02; /* enable the WDTO# output low pulse
133 to the KBRST# pin (PIN60) */
132 outb_p(t, WDT_EFDR); /* Write back to CRF5 */ 134 outb_p(t, WDT_EFDR); /* Write back to CRF5 */
133 135
134 outb_p(0xF7, WDT_EFER); /* Select CRF7 */ 136 outb_p(0xF7, WDT_EFER); /* Select CRF7 */
@@ -321,7 +323,7 @@ static int __init wdt_init(void)
321{ 323{
322 int ret; 324 int ret;
323 325
324 printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n"); 326 printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n");
325 327
326 if (wdt_set_heartbeat(timeout)) { 328 if (wdt_set_heartbeat(timeout)) {
327 wdt_set_heartbeat(WATCHDOG_TIMEOUT); 329 wdt_set_heartbeat(WATCHDOG_TIMEOUT);