aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog')
-rw-r--r--drivers/char/watchdog/Kconfig97
-rw-r--r--drivers/char/watchdog/Makefile8
-rw-r--r--drivers/char/watchdog/alim7101_wdt.c13
-rw-r--r--drivers/char/watchdog/at91rm9200_wdt.c (renamed from drivers/char/watchdog/at91_wdt.c)0
-rw-r--r--drivers/char/watchdog/iTCO_vendor_support.c307
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c48
-rw-r--r--drivers/char/watchdog/pc87413_wdt.c635
-rw-r--r--drivers/char/watchdog/pcwd_usb.c3
-rw-r--r--drivers/char/watchdog/rm9k_wdt.c420
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c5
-rw-r--r--drivers/char/watchdog/sc1200wdt.c9
-rw-r--r--drivers/char/watchdog/smsc37b787_wdt.c627
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c8
-rw-r--r--drivers/char/watchdog/w83697hf_wdt.c450
14 files changed, 2604 insertions, 26 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 89e46d6dfc4e..ea09d0c974ea 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -13,7 +13,7 @@ config WATCHDOG
13 subsequently opening the file and then failing to write to it for 13 subsequently opening the file and then failing to write to it for
14 longer than 1 minute will result in rebooting the machine. This 14 longer than 1 minute will result in rebooting the machine. This
15 could be useful for a networked machine that needs to come back 15 could be useful for a networked machine that needs to come back
16 online as fast as possible after a lock-up. There's both a watchdog 16 on-line as fast as possible after a lock-up. There's both a watchdog
17 implementation entirely in software (which can sometimes fail to 17 implementation entirely in software (which can sometimes fail to
18 reboot the machine) and a driver for hardware watchdog boards, which 18 reboot the machine) and a driver for hardware watchdog boards, which
19 are more robust and can also keep track of the temperature inside 19 are more robust and can also keep track of the temperature inside
@@ -60,7 +60,7 @@ config SOFT_WATCHDOG
60 60
61# ARM Architecture 61# ARM Architecture
62 62
63config AT91_WATCHDOG 63config AT91RM9200_WATCHDOG
64 tristate "AT91RM9200 watchdog" 64 tristate "AT91RM9200 watchdog"
65 depends on WATCHDOG && ARCH_AT91RM9200 65 depends on WATCHDOG && ARCH_AT91RM9200
66 help 66 help
@@ -71,7 +71,7 @@ config 21285_WATCHDOG
71 tristate "DC21285 watchdog" 71 tristate "DC21285 watchdog"
72 depends on WATCHDOG && FOOTBRIDGE 72 depends on WATCHDOG && FOOTBRIDGE
73 help 73 help
74 The Intel Footbridge chip contains a builtin watchdog circuit. Say Y 74 The Intel Footbridge chip contains a built-in watchdog circuit. Say Y
75 here if you wish to use this. Alternatively say M to compile the 75 here if you wish to use this. Alternatively say M to compile the
76 driver as a module, which will be called wdt285. 76 driver as a module, which will be called wdt285.
77 77
@@ -269,11 +269,11 @@ config IB700_WDT
269 Most people will say N. 269 Most people will say N.
270 270
271config IBMASR 271config IBMASR
272 tristate "IBM Automatic Server Restart" 272 tristate "IBM Automatic Server Restart"
273 depends on WATCHDOG && X86 273 depends on WATCHDOG && X86
274 help 274 help
275 This is the driver for the IBM Automatic Server Restart watchdog 275 This is the driver for the IBM Automatic Server Restart watchdog
276 timer builtin into some eServer xSeries machines. 276 timer built-in into some eServer xSeries machines.
277 277
278 To compile this driver as a module, choose M here: the 278 To compile this driver as a module, choose M here: the
279 module will be called ibmasr. 279 module will be called ibmasr.
@@ -316,13 +316,16 @@ config I8XX_TCO
316 To compile this driver as a module, choose M here: the 316 To compile this driver as a module, choose M here: the
317 module will be called i8xx_tco. 317 module will be called i8xx_tco.
318 318
319 Note: This driver will be removed in the near future. Please
320 use the Intel TCO Timer/Watchdog driver.
321
319config ITCO_WDT 322config ITCO_WDT
320 tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)" 323 tristate "Intel TCO Timer/Watchdog"
321 depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL 324 depends on WATCHDOG && (X86 || IA64) && PCI
322 ---help--- 325 ---help---
323 Hardware driver for the intel TCO timer based watchdog devices. 326 Hardware driver for the intel TCO timer based watchdog devices.
324 These drivers are included in the Intel 82801 I/O Controller 327 These drivers are included in the Intel 82801 I/O Controller
325 Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB 328 Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB
326 controller hub. 329 controller hub.
327 330
328 The TCO (Total Cost of Ownership) timer is a watchdog timer 331 The TCO (Total Cost of Ownership) timer is a watchdog timer
@@ -337,6 +340,14 @@ config ITCO_WDT
337 To compile this driver as a module, choose M here: the 340 To compile this driver as a module, choose M here: the
338 module will be called iTCO_wdt. 341 module will be called iTCO_wdt.
339 342
343config ITCO_VENDOR_SUPPORT
344 bool "Intel TCO Timer/Watchdog Specific Vendor Support"
345 depends on ITCO_WDT
346 ---help---
347 Add vendor specific support to the intel TCO timer based watchdog
348 devices. At this moment we only have additional support for some
349 SuperMicro Inc. motherboards.
350
340config SC1200_WDT 351config SC1200_WDT
341 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" 352 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
342 depends on WATCHDOG && X86 353 depends on WATCHDOG && X86
@@ -360,6 +371,20 @@ config SCx200_WDT
360 371
361 If compiled as a module, it will be called scx200_wdt. 372 If compiled as a module, it will be called scx200_wdt.
362 373
374config PC87413_WDT
375 tristate "NS PC87413 watchdog"
376 depends on WATCHDOG && X86
377 ---help---
378 This is the driver for the hardware watchdog on the PC87413 chipset
379 This watchdog simply watches your kernel to make sure it doesn't
380 freeze, and if it does, it reboots your computer after a certain
381 amount of time.
382
383 To compile this driver as a module, choose M here: the
384 module will be called pc87413_wdt.
385
386 Most people will say N.
387
363config 60XX_WDT 388config 60XX_WDT
364 tristate "SBC-60XX Watchdog Timer" 389 tristate "SBC-60XX Watchdog Timer"
365 depends on WATCHDOG && X86 390 depends on WATCHDOG && X86
@@ -395,6 +420,26 @@ config CPU5_WDT
395 To compile this driver as a module, choose M here: the 420 To compile this driver as a module, choose M here: the
396 module will be called cpu5wdt. 421 module will be called cpu5wdt.
397 422
423config SMSC37B787_WDT
424 tristate "Winbond SMsC37B787 Watchdog Timer"
425 depends on WATCHDOG && X86
426 ---help---
427 This is the driver for the hardware watchdog component on the
428 Winbond SMsC37B787 chipset as used on the NetRunner Mainboard
429 from Vision Systems and maybe others.
430
431 This watchdog simply watches your kernel to make sure it doesn't
432 freeze, and if it does, it reboots your computer after a certain
433 amount of time.
434
435 Usually a userspace daemon will notify the kernel WDT driver that
436 userspace is still alive, at regular intervals.
437
438 To compile this driver as a module, choose M here: the
439 module will be called smsc37b787_wdt.
440
441 Most people will say N.
442
398config W83627HF_WDT 443config W83627HF_WDT
399 tristate "W83627HF Watchdog Timer" 444 tristate "W83627HF Watchdog Timer"
400 depends on WATCHDOG && X86 445 depends on WATCHDOG && X86
@@ -410,6 +455,21 @@ config W83627HF_WDT
410 455
411 Most people will say N. 456 Most people will say N.
412 457
458config W83697HF_WDT
459 tristate "W83697HF/W83697HG Watchdog Timer"
460 depends on WATCHDOG && X86
461 ---help---
462 This is the driver for the hardware watchdog on the W83697HF/HG
463 chipset as used in Dedibox/VIA motherboards (and likely others).
464 This watchdog simply watches your kernel to make sure it doesn't
465 freeze, and if it does, it reboots your computer after a certain
466 amount of time.
467
468 To compile this driver as a module, choose M here: the
469 module will be called w83697hf_wdt.
470
471 Most people will say N.
472
413config W83877F_WDT 473config W83877F_WDT
414 tristate "W83877F (EMACS) Watchdog Timer" 474 tristate "W83877F (EMACS) Watchdog Timer"
415 depends on WATCHDOG && X86 475 depends on WATCHDOG && X86
@@ -443,7 +503,7 @@ config MACHZ_WDT
443 depends on WATCHDOG && X86 503 depends on WATCHDOG && X86
444 ---help--- 504 ---help---
445 If you are using a ZF Micro MachZ processor, say Y here, otherwise 505 If you are using a ZF Micro MachZ processor, say Y here, otherwise
446 N. This is the driver for the watchdog timer builtin on that 506 N. This is the driver for the watchdog timer built-in on that
447 processor using ZF-Logic interface. This watchdog simply watches 507 processor using ZF-Logic interface. This watchdog simply watches
448 your kernel to make sure it doesn't freeze, and if it does, it 508 your kernel to make sure it doesn't freeze, and if it does, it
449 reboots your computer after a certain amount of time. 509 reboots your computer after a certain amount of time.
@@ -472,7 +532,6 @@ config SBC_EPX_C3_WATCHDOG
472 To compile this driver as a module, choose M here: the 532 To compile this driver as a module, choose M here: the
473 module will be called sbc_epx_c3. 533 module will be called sbc_epx_c3.
474 534
475
476# PowerPC Architecture 535# PowerPC Architecture
477 536
478config 8xx_WDT 537config 8xx_WDT
@@ -502,7 +561,7 @@ config WATCHDOG_RTAS
502 help 561 help
503 This driver adds watchdog support for the RTAS watchdog. 562 This driver adds watchdog support for the RTAS watchdog.
504 563
505 To compile this driver as a module, choose M here. The module 564 To compile this driver as a module, choose M here. The module
506 will be called wdrtas. 565 will be called wdrtas.
507 566
508# MIPS Architecture 567# MIPS Architecture
@@ -516,6 +575,16 @@ config INDYDOG
516 timer expired and no process has written to /dev/watchdog during 575 timer expired and no process has written to /dev/watchdog during
517 that time. 576 that time.
518 577
578config WDT_RM9K_GPI
579 tristate "RM9000/GPI hardware watchdog"
580 depends on WATCHDOG && CPU_RM9000
581 help
582 Watchdog implementation using the GPI hardware found on
583 PMC-Sierra RM9xxx CPUs.
584
585 To compile this driver as a module, choose M here: the
586 module will be called rm9k_wdt.
587
519# S390 Architecture 588# S390 Architecture
520 589
521config ZVM_WATCHDOG 590config ZVM_WATCHDOG
@@ -556,7 +625,7 @@ config SH_WDT_MMAP
556 help 625 help
557 If you say Y here, user applications will be able to mmap the 626 If you say Y here, user applications will be able to mmap the
558 WDT/CPG registers. 627 WDT/CPG registers.
559# 628
560# SPARC64 Architecture 629# SPARC64 Architecture
561 630
562config WATCHDOG_CP1XXX 631config WATCHDOG_CP1XXX
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 7f70abad465a..2cd8ff8d10ac 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -23,7 +23,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o
23obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o 23obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
24 24
25# ARM Architecture 25# ARM Architecture
26obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o 26obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
27obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o 27obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
28obj-$(CONFIG_21285_WATCHDOG) += wdt285.o 28obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
29obj-$(CONFIG_977_WATCHDOG) += wdt977.o 29obj-$(CONFIG_977_WATCHDOG) += wdt977.o
@@ -47,13 +47,16 @@ obj-$(CONFIG_IBMASR) += ibmasr.o
47obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o 47obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
48obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o 48obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
49obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o 49obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
50obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o 50obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
51obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o 51obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
52obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o 52obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
53obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
53obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o 54obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
54obj-$(CONFIG_SBC8360_WDT) += sbc8360.o 55obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
55obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o 56obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
57obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
56obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o 58obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
59obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
57obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o 60obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
58obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o 61obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
59obj-$(CONFIG_MACHZ_WDT) += machzwd.o 62obj-$(CONFIG_MACHZ_WDT) += machzwd.o
@@ -70,6 +73,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
70 73
71# MIPS Architecture 74# MIPS Architecture
72obj-$(CONFIG_INDYDOG) += indydog.o 75obj-$(CONFIG_INDYDOG) += indydog.o
76obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
73 77
74# S390 Architecture 78# S390 Architecture
75 79
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
index 5948863b592b..bf25d0a55a99 100644
--- a/drivers/char/watchdog/alim7101_wdt.c
+++ b/drivers/char/watchdog/alim7101_wdt.c
@@ -77,7 +77,8 @@ static struct pci_dev *alim7101_pmu;
77 77
78static int nowayout = WATCHDOG_NOWAYOUT; 78static int nowayout = WATCHDOG_NOWAYOUT;
79module_param(nowayout, int, 0); 79module_param(nowayout, int, 0);
80MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); 80MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
81 __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")");
81 82
82/* 83/*
83 * Whack the dog 84 * Whack the dog
@@ -415,6 +416,16 @@ err_out:
415module_init(alim7101_wdt_init); 416module_init(alim7101_wdt_init);
416module_exit(alim7101_wdt_unload); 417module_exit(alim7101_wdt_unload);
417 418
419static struct pci_device_id alim7101_pci_tbl[] __devinitdata = {
420 { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
421 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
422 { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
423 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
424 { }
425};
426
427MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl);
428
418MODULE_AUTHOR("Steve Hill"); 429MODULE_AUTHOR("Steve Hill");
419MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver"); 430MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver");
420MODULE_LICENSE("GPL"); 431MODULE_LICENSE("GPL");
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91rm9200_wdt.c
index 4e7a1145e78f..4e7a1145e78f 100644
--- a/drivers/char/watchdog/at91_wdt.c
+++ b/drivers/char/watchdog/at91rm9200_wdt.c
diff --git a/drivers/char/watchdog/iTCO_vendor_support.c b/drivers/char/watchdog/iTCO_vendor_support.c
new file mode 100644
index 000000000000..415083990097
--- /dev/null
+++ b/drivers/char/watchdog/iTCO_vendor_support.c
@@ -0,0 +1,307 @@
1/*
2 * intel TCO vendor specific watchdog driver support
3 *
4 * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
12 * provide warranty for any of this software. This material is
13 * provided "AS-IS" and at no charge.
14 */
15
16/*
17 * Includes, defines, variables, module parameters, ...
18 */
19
20/* Module and version information */
21#define DRV_NAME "iTCO_vendor_support"
22#define DRV_VERSION "1.01"
23#define DRV_RELDATE "11-Nov-2006"
24#define PFX DRV_NAME ": "
25
26/* Includes */
27#include <linux/module.h> /* For module specific items */
28#include <linux/moduleparam.h> /* For new moduleparam's */
29#include <linux/types.h> /* For standard types (like size_t) */
30#include <linux/errno.h> /* For the -ENODEV/... values */
31#include <linux/kernel.h> /* For printk/panic/... */
32#include <linux/init.h> /* For __init/__exit/... */
33#include <linux/ioport.h> /* For io-port access */
34
35#include <asm/io.h> /* For inb/outb/... */
36
37/* iTCO defines */
38#define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */
39#define TCOBASE acpibase + 0x60 /* TCO base address */
40#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
41
42/* List of vendor support modes */
43#define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
44#define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
45
46static int vendorsupport = 0;
47module_param(vendorsupport, int, 0);
48MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+");
49
50/*
51 * Vendor Specific Support
52 */
53
54/*
55 * Vendor Support: 1
56 * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE
57 * iTCO chipset: ICH2
58 *
59 * Code contributed by: R. Seretny <lkpatches@paypc.com>
60 * Documentation obtained by R. Seretny from SuperMicro Technical Support
61 *
62 * To enable Watchdog function:
63 * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes
64 * This setting enables SMI to clear the watchdog expired flag.
65 * If BIOS or CPU fail which may cause SMI hang, then system will
66 * reboot. When application starts to use watchdog function,
67 * application has to take over the control from SMI.
68 *
69 * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog
70 * function.
71 *
72 * Note: The system will reboot when Expire Flag is set TWICE.
73 * So, if the watchdog timer is 20 seconds, then the maximum hang
74 * time is about 40 seconds, and the minimum hang time is about
75 * 20.6 seconds.
76 */
77
78static void supermicro_old_pre_start(unsigned long acpibase)
79{
80 unsigned long val32;
81
82 val32 = inl(SMI_EN);
83 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
84 outl(val32, SMI_EN); /* Needed to activate watchdog */
85}
86
87static void supermicro_old_pre_stop(unsigned long acpibase)
88{
89 unsigned long val32;
90
91 val32 = inl(SMI_EN);
92 val32 &= 0x00002000; /* Turn on SMI clearing watchdog */
93 outl(val32, SMI_EN); /* Needed to deactivate watchdog */
94}
95
96static void supermicro_old_pre_keepalive(unsigned long acpibase)
97{
98 /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
99 /* Clear "Expire Flag" (Bit 3 of TC01_STS register) */
100 outb(0x08, TCO1_STS);
101}
102
103/*
104 * Vendor Support: 2
105 * Board: Super Micro Computer Inc. P4SBx, P4DPx
106 * iTCO chipset: ICH4
107 *
108 * Code contributed by: R. Seretny <lkpatches@paypc.com>
109 * Documentation obtained by R. Seretny from SuperMicro Technical Support
110 *
111 * To enable Watchdog function:
112 * 1. BIOS
113 * For P4SBx:
114 * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature
115 * For P4DPx:
116 * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog
117 * This setting enables or disables Watchdog function. When enabled, the
118 * default watchdog timer is set to be 5 minutes (about 4’35â€). It is
119 * enough to load and run the OS. The application (service or driver) has
120 * to take over the control once OS is running up and before watchdog
121 * expires.
122 *
123 * 2. JUMPER
124 * For P4SBx: JP39
125 * For P4DPx: JP37
126 * This jumper is used for safety. Closed is enabled. This jumper
127 * prevents user enables watchdog in BIOS by accident.
128 *
129 * To enable Watch Dog function, both BIOS and JUMPER must be enabled.
130 *
131 * The documentation lists motherboards P4SBx and P4DPx series as of
132 * 20-March-2002. However, this code works flawlessly with much newer
133 * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82).
134 *
135 * The original iTCO driver as written does not actually reset the
136 * watchdog timer on these machines, as a result they reboot after five
137 * minutes.
138 *
139 * NOTE: You may leave the Watchdog function disabled in the SuperMicro
140 * BIOS to avoid a "boot-race"... This driver will enable watchdog
141 * functionality even if it's disabled in the BIOS once the /dev/watchdog
142 * file is opened.
143 */
144
145/* I/O Port's */
146#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
147#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
148
149/* Control Register's */
150#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
151#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */
152
153#define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */
154
155#define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */
156
157#define SM_ENDWATCH 0xAA /* Watchdog lock control page */
158
159#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */
160 /* (Bit 3: 0 = seconds, 1 = minutes */
161
162#define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */
163
164#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */
165 /* Bit 6: timer is reset by kbd interrupt */
166 /* Bit 7: timer is reset by mouse interrupt */
167
168static void supermicro_new_unlock_watchdog(void)
169{
170 outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */
171 outb(SM_WATCHPAGE, SM_REGINDEX);
172
173 outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */
174 outb(SM_CTLPAGE, SM_DATAIO);
175}
176
177static void supermicro_new_lock_watchdog(void)
178{
179 outb(SM_ENDWATCH, SM_REGINDEX);
180}
181
182static void supermicro_new_pre_start(unsigned int heartbeat)
183{
184 unsigned int val;
185
186 supermicro_new_unlock_watchdog();
187
188 /* Watchdog timer setting needs to be in seconds*/
189 outb(SM_COUNTMODE, SM_REGINDEX);
190 val = inb(SM_DATAIO);
191 val &= 0xF7;
192 outb(val, SM_DATAIO);
193
194 /* Write heartbeat interval to WDOG */
195 outb (SM_WATCHTIMER, SM_REGINDEX);
196 outb((heartbeat & 255), SM_DATAIO);
197
198 /* Make sure keyboard/mouse interrupts don't interfere */
199 outb(SM_RESETCONTROL, SM_REGINDEX);
200 val = inb(SM_DATAIO);
201 val &= 0x3f;
202 outb(val, SM_DATAIO);
203
204 /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */
205 outb(SM_WATCHENABLE, SM_REGINDEX);
206 val = inb(SM_DATAIO);
207 val |= 0x01;
208 outb(val, SM_DATAIO);
209
210 supermicro_new_lock_watchdog();
211}
212
213static void supermicro_new_pre_stop(void)
214{
215 unsigned int val;
216
217 supermicro_new_unlock_watchdog();
218
219 /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */
220 outb(SM_WATCHENABLE, SM_REGINDEX);
221 val = inb(SM_DATAIO);
222 val &= 0xFE;
223 outb(val, SM_DATAIO);
224
225 supermicro_new_lock_watchdog();
226}
227
228static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
229{
230 supermicro_new_unlock_watchdog();
231
232 /* reset watchdog timeout to heartveat value */
233 outb(SM_WATCHTIMER, SM_REGINDEX);
234 outb((heartbeat & 255), SM_DATAIO);
235
236 supermicro_new_lock_watchdog();
237}
238
239/*
240 * Generic Support Functions
241 */
242
243void iTCO_vendor_pre_start(unsigned long acpibase,
244 unsigned int heartbeat)
245{
246 if (vendorsupport == SUPERMICRO_OLD_BOARD)
247 supermicro_old_pre_start(acpibase);
248 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
249 supermicro_new_pre_start(heartbeat);
250}
251EXPORT_SYMBOL(iTCO_vendor_pre_start);
252
253void iTCO_vendor_pre_stop(unsigned long acpibase)
254{
255 if (vendorsupport == SUPERMICRO_OLD_BOARD)
256 supermicro_old_pre_stop(acpibase);
257 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
258 supermicro_new_pre_stop();
259}
260EXPORT_SYMBOL(iTCO_vendor_pre_stop);
261
262void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
263{
264 if (vendorsupport == SUPERMICRO_OLD_BOARD)
265 supermicro_old_pre_keepalive(acpibase);
266 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
267 supermicro_new_pre_set_heartbeat(heartbeat);
268}
269EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
270
271void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat)
272{
273 if (vendorsupport == SUPERMICRO_NEW_BOARD)
274 supermicro_new_pre_set_heartbeat(heartbeat);
275}
276EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
277
278int iTCO_vendor_check_noreboot_on(void)
279{
280 switch(vendorsupport) {
281 case SUPERMICRO_OLD_BOARD:
282 return 0;
283 default:
284 return 1;
285 }
286}
287EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
288
289static int __init iTCO_vendor_init_module(void)
290{
291 printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
292 return 0;
293}
294
295static void __exit iTCO_vendor_exit_module(void)
296{
297 printk (KERN_INFO PFX "Module Unloaded\n");
298}
299
300module_init(iTCO_vendor_init_module);
301module_exit(iTCO_vendor_exit_module);
302
303MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, R. Seretny <lkpatches@paypc.com>");
304MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
305MODULE_VERSION(DRV_VERSION);
306MODULE_LICENSE("GPL");
307
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
index aaac94db0d8b..7eac922df867 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -35,6 +35,10 @@
35 * 82801GDH (ICH7DH) : document number 307013-002, 307014-009, 35 * 82801GDH (ICH7DH) : document number 307013-002, 307014-009,
36 * 82801GBM (ICH7-M) : document number 307013-002, 307014-009, 36 * 82801GBM (ICH7-M) : document number 307013-002, 307014-009,
37 * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009, 37 * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009,
38 * 82801HB (ICH8) : document number 313056-002, 313057-004,
39 * 82801HR (ICH8R) : document number 313056-002, 313057-004,
40 * 82801HH (ICH8DH) : document number 313056-002, 313057-004,
41 * 82801HO (ICH8DO) : document number 313056-002, 313057-004,
38 * 6300ESB (6300ESB) : document number 300641-003 42 * 6300ESB (6300ESB) : document number 300641-003
39 */ 43 */
40 44
@@ -44,8 +48,8 @@
44 48
45/* Module and version information */ 49/* Module and version information */
46#define DRV_NAME "iTCO_wdt" 50#define DRV_NAME "iTCO_wdt"
47#define DRV_VERSION "1.00" 51#define DRV_VERSION "1.01"
48#define DRV_RELDATE "30-Jul-2006" 52#define DRV_RELDATE "11-Nov-2006"
49#define PFX DRV_NAME ": " 53#define PFX DRV_NAME ": "
50 54
51/* Includes */ 55/* Includes */
@@ -85,6 +89,9 @@ enum iTCO_chipsets {
85 TCO_ICH7, /* ICH7 & ICH7R */ 89 TCO_ICH7, /* ICH7 & ICH7R */
86 TCO_ICH7M, /* ICH7-M */ 90 TCO_ICH7M, /* ICH7-M */
87 TCO_ICH7MDH, /* ICH7-M DH */ 91 TCO_ICH7MDH, /* ICH7-M DH */
92 TCO_ICH8, /* ICH8 & ICH8R */
93 TCO_ICH8DH, /* ICH8DH */
94 TCO_ICH8DO, /* ICH8DO */
88}; 95};
89 96
90static struct { 97static struct {
@@ -108,6 +115,9 @@ static struct {
108 {"ICH7 or ICH7R", 2}, 115 {"ICH7 or ICH7R", 2},
109 {"ICH7-M", 2}, 116 {"ICH7-M", 2},
110 {"ICH7-M DH", 2}, 117 {"ICH7-M DH", 2},
118 {"ICH8 or ICH8R", 2},
119 {"ICH8DH", 2},
120 {"ICH8DO", 2},
111 {NULL,0} 121 {NULL,0}
112}; 122};
113 123
@@ -135,6 +145,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
135 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 }, 145 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 },
136 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M }, 146 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M },
137 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH }, 147 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH },
148 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 },
149 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH },
150 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO },
138 { 0, }, /* End of list */ 151 { 0, }, /* End of list */
139}; 152};
140MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); 153MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
@@ -176,6 +189,21 @@ static int nowayout = WATCHDOG_NOWAYOUT;
176module_param(nowayout, int, 0); 189module_param(nowayout, int, 0);
177MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); 190MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
178 191
192/* iTCO Vendor Specific Support hooks */
193#ifdef CONFIG_ITCO_VENDOR_SUPPORT
194extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
195extern void iTCO_vendor_pre_stop(unsigned long);
196extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
197extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
198extern int iTCO_vendor_check_noreboot_on(void);
199#else
200#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
201#define iTCO_vendor_pre_stop(acpibase) {}
202#define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {}
203#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
204#define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */
205#endif
206
179/* 207/*
180 * Some TCO specific functions 208 * Some TCO specific functions
181 */ 209 */
@@ -236,6 +264,8 @@ static int iTCO_wdt_start(void)
236 264
237 spin_lock(&iTCO_wdt_private.io_lock); 265 spin_lock(&iTCO_wdt_private.io_lock);
238 266
267 iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
268
239 /* disable chipset's NO_REBOOT bit */ 269 /* disable chipset's NO_REBOOT bit */
240 if (iTCO_wdt_unset_NO_REBOOT_bit()) { 270 if (iTCO_wdt_unset_NO_REBOOT_bit()) {
241 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); 271 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
@@ -260,6 +290,8 @@ static int iTCO_wdt_stop(void)
260 290
261 spin_lock(&iTCO_wdt_private.io_lock); 291 spin_lock(&iTCO_wdt_private.io_lock);
262 292
293 iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
294
263 /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ 295 /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
264 val = inw(TCO1_CNT); 296 val = inw(TCO1_CNT);
265 val |= 0x0800; 297 val |= 0x0800;
@@ -280,6 +312,8 @@ static int iTCO_wdt_keepalive(void)
280{ 312{
281 spin_lock(&iTCO_wdt_private.io_lock); 313 spin_lock(&iTCO_wdt_private.io_lock);
282 314
315 iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
316
283 /* Reload the timer by writing to the TCO Timer Counter register */ 317 /* Reload the timer by writing to the TCO Timer Counter register */
284 if (iTCO_wdt_private.iTCO_version == 2) { 318 if (iTCO_wdt_private.iTCO_version == 2) {
285 outw(0x01, TCO_RLD); 319 outw(0x01, TCO_RLD);
@@ -306,6 +340,8 @@ static int iTCO_wdt_set_heartbeat(int t)
306 ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) 340 ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
307 return -EINVAL; 341 return -EINVAL;
308 342
343 iTCO_vendor_pre_set_heartbeat(tmrval);
344
309 /* Write new heartbeat to watchdog */ 345 /* Write new heartbeat to watchdog */
310 if (iTCO_wdt_private.iTCO_version == 2) { 346 if (iTCO_wdt_private.iTCO_version == 2) {
311 spin_lock(&iTCO_wdt_private.io_lock); 347 spin_lock(&iTCO_wdt_private.io_lock);
@@ -355,7 +391,8 @@ static int iTCO_wdt_get_timeleft (int *time_left)
355 spin_unlock(&iTCO_wdt_private.io_lock); 391 spin_unlock(&iTCO_wdt_private.io_lock);
356 392
357 *time_left = (val8 * 6) / 10; 393 *time_left = (val8 * 6) / 10;
358 } 394 } else
395 return -EINVAL;
359 return 0; 396 return 0;
360} 397}
361 398
@@ -426,7 +463,6 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
426{ 463{
427 int new_options, retval = -EINVAL; 464 int new_options, retval = -EINVAL;
428 int new_heartbeat; 465 int new_heartbeat;
429 int time_left;
430 void __user *argp = (void __user *)arg; 466 void __user *argp = (void __user *)arg;
431 int __user *p = argp; 467 int __user *p = argp;
432 static struct watchdog_info ident = { 468 static struct watchdog_info ident = {
@@ -486,6 +522,8 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
486 522
487 case WDIOC_GETTIMELEFT: 523 case WDIOC_GETTIMELEFT:
488 { 524 {
525 int time_left;
526
489 if (iTCO_wdt_get_timeleft(&time_left)) 527 if (iTCO_wdt_get_timeleft(&time_left))
490 return -EINVAL; 528 return -EINVAL;
491 529
@@ -554,7 +592,7 @@ static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent,
554 } 592 }
555 593
556 /* Check chipset's NO_REBOOT bit */ 594 /* Check chipset's NO_REBOOT bit */
557 if (iTCO_wdt_unset_NO_REBOOT_bit()) { 595 if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
558 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n"); 596 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
559 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ 597 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
560 goto out; 598 goto out;
diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c
new file mode 100644
index 000000000000..1d447e32af41
--- /dev/null
+++ b/drivers/char/watchdog/pc87413_wdt.c
@@ -0,0 +1,635 @@
1/*
2 * NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x
3 *
4 * This code is based on wdt.c with original copyright.
5 *
6 * (C) Copyright 2006 Sven Anders, <anders@anduras.de>
7 * and Marcus Junker, <junker@anduras.de>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Neither Sven Anders, Marcus Junker nor ANDURAS AG
15 * admit liability nor provide warranty for any of this software.
16 * This material is provided "AS-IS" and at no charge.
17 *
18 * Release 1.1
19 */
20
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/miscdevice.h>
24#include <linux/watchdog.h>
25#include <linux/ioport.h>
26#include <linux/delay.h>
27#include <linux/notifier.h>
28#include <linux/fs.h>
29#include <linux/reboot.h>
30#include <linux/init.h>
31#include <linux/spinlock.h>
32#include <linux/moduleparam.h>
33#include <linux/version.h>
34
35#include <asm/io.h>
36#include <asm/uaccess.h>
37#include <asm/system.h>
38
39/* #define DEBUG 1 */
40
41#define DEFAULT_TIMEOUT 1 /* 1 minute */
42#define MAX_TIMEOUT 255
43
44#define VERSION "1.1"
45#define MODNAME "pc87413 WDT"
46#define PFX MODNAME ": "
47#define DPFX MODNAME " - DEBUG: "
48
49#define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */
50#define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1)
51#define SWC_LDN 0x04
52#define SIOCFG2 0x22 /* Serial IO register */
53#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */
54#define WDTO 0x11 /* Watchdog timeout register */
55#define WDCFG 0x12 /* Watchdog config register */
56
57static int io = 0x2E; /* Address used on Portwell Boards */
58
59static int timeout = DEFAULT_TIMEOUT; /* timeout value */
60static unsigned long timer_enabled = 0; /* is the timer enabled? */
61
62static char expect_close; /* is the close expected? */
63
64static spinlock_t io_lock; /* to guard the watchdog from io races */
65
66static int nowayout = WATCHDOG_NOWAYOUT;
67
68/* -- Low level function ----------------------------------------*/
69
70/* Select pins for Watchdog output */
71
72static inline void pc87413_select_wdt_out (void)
73{
74 unsigned int cr_data = 0;
75
76 /* Step 1: Select multiple pin,pin55,as WDT output */
77
78 outb_p(SIOCFG2, WDT_INDEX_IO_PORT);
79
80 cr_data = inb (WDT_DATA_IO_PORT);
81
82 cr_data |= 0x80; /* Set Bit7 to 1*/
83 outb_p(SIOCFG2, WDT_INDEX_IO_PORT);
84
85 outb_p(cr_data, WDT_DATA_IO_PORT);
86
87#ifdef DEBUG
88 printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:"
89 " Bit7 to 1: %d\n", cr_data);
90#endif
91}
92
93/* Enable SWC functions */
94
95static inline void pc87413_enable_swc(void)
96{
97 unsigned int cr_data=0;
98
99 /* Step 2: Enable SWC functions */
100
101 outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */
102 outb_p(SWC_LDN, WDT_DATA_IO_PORT);
103
104 outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */
105 cr_data = inb(WDT_DATA_IO_PORT);
106 cr_data |= 0x01; /* Set Bit0 to 1 */
107 outb_p(0x30, WDT_INDEX_IO_PORT);
108 outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */
109
110#ifdef DEBUG
111 printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n");
112#endif
113}
114
115/* Read SWC I/O base address */
116
117static inline unsigned int pc87413_get_swc_base(void)
118{
119 unsigned int swc_base_addr = 0;
120 unsigned char addr_l, addr_h = 0;
121
122 /* Step 3: Read SWC I/O Base Address */
123
124 outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */
125 addr_h = inb(WDT_DATA_IO_PORT);
126
127 outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */
128
129 addr_l = inb(WDT_DATA_IO_PORT);
130
131 swc_base_addr = (addr_h << 8) + addr_l;
132
133#ifdef DEBUG
134 printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d,"
135 " res %d\n", addr_l, addr_h, swc_base_addr);
136#endif
137
138 return swc_base_addr;
139}
140
141/* Select Bank 3 of SWC */
142
143static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
144{
145 /* Step 4: Select Bank3 of SWC */
146
147 outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
148
149#ifdef DEBUG
150 printk(KERN_INFO DPFX "Select Bank3 of SWC\n");
151#endif
152}
153
154/* Set watchdog timeout to x minutes */
155
156static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
157 char pc87413_time)
158{
159 /* Step 5: Programm WDTO, Twd. */
160
161 outb_p(pc87413_time, swc_base_addr + WDTO);
162
163#ifdef DEBUG
164 printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);
165#endif
166}
167
168/* Enable WDEN */
169
170static inline void pc87413_enable_wden(unsigned int swc_base_addr)
171{
172 /* Step 6: Enable WDEN */
173
174 outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
175
176#ifdef DEBUG
177 printk(KERN_INFO DPFX "Enable WDEN\n");
178#endif
179}
180
181/* Enable SW_WD_TREN */
182static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
183{
184 /* Enable SW_WD_TREN */
185
186 outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
187
188#ifdef DEBUG
189 printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");
190#endif
191}
192
193/* Disable SW_WD_TREN */
194
195static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
196{
197 /* Disable SW_WD_TREN */
198
199 outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
200
201#ifdef DEBUG
202 printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");
203#endif
204}
205
206/* Enable SW_WD_TRG */
207
208static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
209{
210 /* Enable SW_WD_TRG */
211
212 outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
213
214#ifdef DEBUG
215 printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");
216#endif
217}
218
219/* Disable SW_WD_TRG */
220
221static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
222{
223 /* Disable SW_WD_TRG */
224
225 outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
226
227#ifdef DEBUG
228 printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");
229#endif
230}
231
232/* -- Higher level functions ------------------------------------*/
233
234/* Enable the watchdog */
235
236static void pc87413_enable(void)
237{
238 unsigned int swc_base_addr;
239
240 spin_lock(&io_lock);
241
242 pc87413_select_wdt_out();
243 pc87413_enable_swc();
244 swc_base_addr = pc87413_get_swc_base();
245 pc87413_swc_bank3(swc_base_addr);
246 pc87413_programm_wdto(swc_base_addr, timeout);
247 pc87413_enable_wden(swc_base_addr);
248 pc87413_enable_sw_wd_tren(swc_base_addr);
249 pc87413_enable_sw_wd_trg(swc_base_addr);
250
251 spin_unlock(&io_lock);
252}
253
254/* Disable the watchdog */
255
256static void pc87413_disable(void)
257{
258 unsigned int swc_base_addr;
259
260 spin_lock(&io_lock);
261
262 pc87413_select_wdt_out();
263 pc87413_enable_swc();
264 swc_base_addr = pc87413_get_swc_base();
265 pc87413_swc_bank3(swc_base_addr);
266 pc87413_disable_sw_wd_tren(swc_base_addr);
267 pc87413_disable_sw_wd_trg(swc_base_addr);
268 pc87413_programm_wdto(swc_base_addr, 0);
269
270 spin_unlock(&io_lock);
271}
272
273/* Refresh the watchdog */
274
275static void pc87413_refresh(void)
276{
277 unsigned int swc_base_addr;
278
279 spin_lock(&io_lock);
280
281 pc87413_select_wdt_out();
282 pc87413_enable_swc();
283 swc_base_addr = pc87413_get_swc_base();
284 pc87413_swc_bank3(swc_base_addr);
285 pc87413_disable_sw_wd_tren(swc_base_addr);
286 pc87413_disable_sw_wd_trg(swc_base_addr);
287 pc87413_programm_wdto(swc_base_addr, timeout);
288 pc87413_enable_wden(swc_base_addr);
289 pc87413_enable_sw_wd_tren(swc_base_addr);
290 pc87413_enable_sw_wd_trg(swc_base_addr);
291
292 spin_unlock(&io_lock);
293}
294
295/* -- File operations -------------------------------------------*/
296
297/**
298 * pc87413_open:
299 * @inode: inode of device
300 * @file: file handle to device
301 *
302 */
303
304static int pc87413_open(struct inode *inode, struct file *file)
305{
306 /* /dev/watchdog can only be opened once */
307
308 if (test_and_set_bit(0, &timer_enabled))
309 return -EBUSY;
310
311 if (nowayout)
312 __module_get(THIS_MODULE);
313
314 /* Reload and activate timer */
315 pc87413_refresh();
316
317 printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to"
318 " %d minute(s).\n", timeout);
319
320 return nonseekable_open(inode, file);
321}
322
323/**
324 * pc87413_release:
325 * @inode: inode to board
326 * @file: file handle to board
327 *
328 * The watchdog has a configurable API. There is a religious dispute
329 * between people who want their watchdog to be able to shut down and
330 * those who want to be sure if the watchdog manager dies the machine
331 * reboots. In the former case we disable the counters, in the latter
332 * case you have to open it again very soon.
333 */
334
335static int pc87413_release(struct inode *inode, struct file *file)
336{
337 /* Shut off the timer. */
338
339 if (expect_close == 42) {
340 pc87413_disable();
341 printk(KERN_INFO MODNAME "Watchdog disabled,"
342 " sleeping again...\n");
343 } else {
344 printk(KERN_CRIT MODNAME "Unexpected close, not stopping"
345 " watchdog!\n");
346 pc87413_refresh();
347 }
348
349 clear_bit(0, &timer_enabled);
350 expect_close = 0;
351
352 return 0;
353}
354
355/**
356 * pc87413_status:
357 *
358 * return, if the watchdog is enabled (timeout is set...)
359 */
360
361
362static int pc87413_status(void)
363{
364 return 0; /* currently not supported */
365}
366
367/**
368 * pc87413_write:
369 * @file: file handle to the watchdog
370 * @data: data buffer to write
371 * @len: length in bytes
372 * @ppos: pointer to the position to write. No seeks allowed
373 *
374 * A write to a watchdog device is defined as a keepalive signal. Any
375 * write of data will do, as we we don't define content meaning.
376 */
377
378static ssize_t pc87413_write(struct file *file, const char __user *data,
379 size_t len, loff_t *ppos)
380{
381 /* See if we got the magic character 'V' and reload the timer */
382 if (len) {
383 if (!nowayout) {
384 size_t i;
385
386 /* reset expect flag */
387 expect_close = 0;
388
389 /* scan to see whether or not we got the magic character */
390 for (i = 0; i != len; i++) {
391 char c;
392 if (get_user(c, data+i))
393 return -EFAULT;
394 if (c == 'V')
395 expect_close = 42;
396 }
397 }
398
399 /* someone wrote to us, we should reload the timer */
400 pc87413_refresh();
401 }
402 return len;
403}
404
405/**
406 * pc87413_ioctl:
407 * @inode: inode of the device
408 * @file: file handle to the device
409 * @cmd: watchdog command
410 * @arg: argument pointer
411 *
412 * The watchdog API defines a common set of functions for all watchdogs
413 * according to their available features. We only actually usefully support
414 * querying capabilities and current status.
415 */
416
417static int pc87413_ioctl(struct inode *inode, struct file *file,
418 unsigned int cmd, unsigned long arg)
419{
420 int new_timeout;
421
422 union {
423 struct watchdog_info __user *ident;
424 int __user *i;
425 } uarg;
426
427 static struct watchdog_info ident = {
428 .options = WDIOF_KEEPALIVEPING |
429 WDIOF_SETTIMEOUT |
430 WDIOF_MAGICCLOSE,
431 .firmware_version = 1,
432 .identity = "PC87413(HF/F) watchdog"
433 };
434
435 uarg.i = (int __user *)arg;
436
437 switch(cmd) {
438 default:
439 return -ENOTTY;
440
441 case WDIOC_GETSUPPORT:
442 return copy_to_user(uarg.ident, &ident,
443 sizeof(ident)) ? -EFAULT : 0;
444
445 case WDIOC_GETSTATUS:
446 return put_user(pc87413_status(), uarg.i);
447
448 case WDIOC_GETBOOTSTATUS:
449 return put_user(0, uarg.i);
450
451 case WDIOC_KEEPALIVE:
452 pc87413_refresh();
453#ifdef DEBUG
454 printk(KERN_INFO DPFX "keepalive\n");
455#endif
456 return 0;
457
458 case WDIOC_SETTIMEOUT:
459 if (get_user(new_timeout, uarg.i))
460 return -EFAULT;
461
462 // the API states this is given in secs
463 new_timeout /= 60;
464
465 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
466 return -EINVAL;
467
468 timeout = new_timeout;
469 pc87413_refresh();
470
471 // fall through and return the new timeout...
472
473 case WDIOC_GETTIMEOUT:
474
475 new_timeout = timeout * 60;
476
477 return put_user(new_timeout, uarg.i);
478
479 case WDIOC_SETOPTIONS:
480 {
481 int options, retval = -EINVAL;
482
483 if (get_user(options, uarg.i))
484 return -EFAULT;
485
486 if (options & WDIOS_DISABLECARD) {
487 pc87413_disable();
488 retval = 0;
489 }
490
491 if (options & WDIOS_ENABLECARD) {
492 pc87413_enable();
493 retval = 0;
494 }
495
496 return retval;
497 }
498 }
499}
500
501/* -- Notifier funtions -----------------------------------------*/
502
503/**
504 * notify_sys:
505 * @this: our notifier block
506 * @code: the event being reported
507 * @unused: unused
508 *
509 * Our notifier is called on system shutdowns. We want to turn the card
510 * off at reboot otherwise the machine will reboot again during memory
511 * test or worse yet during the following fsck. This would suck, in fact
512 * trust me - if it happens it does suck.
513 */
514
515static int pc87413_notify_sys(struct notifier_block *this,
516 unsigned long code,
517 void *unused)
518{
519 if (code == SYS_DOWN || code == SYS_HALT)
520 {
521 /* Turn the card off */
522 pc87413_disable();
523 }
524 return NOTIFY_DONE;
525}
526
527/* -- Module's structures ---------------------------------------*/
528
529static struct file_operations pc87413_fops = {
530 .owner = THIS_MODULE,
531 .llseek = no_llseek,
532 .write = pc87413_write,
533 .ioctl = pc87413_ioctl,
534 .open = pc87413_open,
535 .release = pc87413_release,
536};
537
538static struct notifier_block pc87413_notifier =
539{
540 .notifier_call = pc87413_notify_sys,
541};
542
543static struct miscdevice pc87413_miscdev=
544{
545 .minor = WATCHDOG_MINOR,
546 .name = "watchdog",
547 .fops = &pc87413_fops
548};
549
550/* -- Module init functions -------------------------------------*/
551
552/**
553 * pc87413_init: module's "constructor"
554 *
555 * Set up the WDT watchdog board. All we have to do is grab the
556 * resources we require and bitch if anyone beat us to them.
557 * The open() function will actually kick the board off.
558 */
559
560static int __init pc87413_init(void)
561{
562 int ret;
563
564 spin_lock_init(&io_lock);
565
566 printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT);
567
568 /* request_region(io, 2, "pc87413"); */
569
570 ret = register_reboot_notifier(&pc87413_notifier);
571 if (ret != 0) {
572 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
573 ret);
574 }
575
576 ret = misc_register(&pc87413_miscdev);
577
578 if (ret != 0) {
579 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
580 WATCHDOG_MINOR, ret);
581 unregister_reboot_notifier(&pc87413_notifier);
582 return ret;
583 }
584
585 printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
586
587 pc87413_enable();
588
589 return 0;
590}
591
592/**
593 * pc87413_exit: module's "destructor"
594 *
595 * Unload the watchdog. You cannot do this with any file handles open.
596 * If your watchdog is set to continue ticking on close and you unload
597 * it, well it keeps ticking. We won't get the interrupt but the board
598 * will not touch PC memory so all is fine. You just have to load a new
599 * module in 60 seconds or reboot.
600 */
601
602static void __exit pc87413_exit(void)
603{
604 /* Stop the timer before we leave */
605 if (!nowayout)
606 {
607 pc87413_disable();
608 printk(KERN_INFO MODNAME "Watchdog disabled.\n");
609 }
610
611 misc_deregister(&pc87413_miscdev);
612 unregister_reboot_notifier(&pc87413_notifier);
613 /* release_region(io,2); */
614
615 printk(MODNAME " watchdog component driver removed.\n");
616}
617
618module_init(pc87413_init);
619module_exit(pc87413_exit);
620
621MODULE_AUTHOR("Sven Anders <anders@anduras.de>, Marcus Junker <junker@anduras.de>,");
622MODULE_DESCRIPTION("PC87413 WDT driver");
623MODULE_LICENSE("GPL");
624
625MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
626
627module_param(io, int, 0);
628MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ").");
629
630module_param(timeout, int, 0);
631MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ").");
632
633module_param(nowayout, int, 0);
634MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
635
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index bda45334d802..e275dd4a705d 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -561,8 +561,7 @@ static struct notifier_block usb_pcwd_notifier = {
561 */ 561 */
562static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) 562static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd)
563{ 563{
564 if (usb_pcwd->intr_urb != NULL) 564 usb_free_urb(usb_pcwd->intr_urb);
565 usb_free_urb (usb_pcwd->intr_urb);
566 if (usb_pcwd->intr_buffer != NULL) 565 if (usb_pcwd->intr_buffer != NULL)
567 usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, 566 usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size,
568 usb_pcwd->intr_buffer, usb_pcwd->intr_dma); 567 usb_pcwd->intr_buffer, usb_pcwd->intr_dma);
diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c
new file mode 100644
index 000000000000..ec3909371c21
--- /dev/null
+++ b/drivers/char/watchdog/rm9k_wdt.c
@@ -0,0 +1,420 @@
1/*
2 * Watchdog implementation for GPI h/w found on PMC-Sierra RM9xxx
3 * chips.
4 *
5 * Copyright (C) 2004 by Basler Vision Technologies AG
6 * Author: Thomas Koeller <thomas.koeller@baslerweb.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/platform_device.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/interrupt.h>
27#include <linux/fs.h>
28#include <linux/reboot.h>
29#include <linux/notifier.h>
30#include <linux/miscdevice.h>
31#include <linux/watchdog.h>
32#include <asm/io.h>
33#include <asm/atomic.h>
34#include <asm/processor.h>
35#include <asm/uaccess.h>
36#include <asm/system.h>
37#include <asm/rm9k-ocd.h>
38
39#include <rm9k_wdt.h>
40
41
42#define CLOCK 125000000
43#define MAX_TIMEOUT_SECONDS 32
44#define CPCCR 0x0080
45#define CPGIG1SR 0x0044
46#define CPGIG1ER 0x0054
47
48
49/* Function prototypes */
50static irqreturn_t wdt_gpi_irqhdl(int, void *, struct pt_regs *);
51static void wdt_gpi_start(void);
52static void wdt_gpi_stop(void);
53static void wdt_gpi_set_timeout(unsigned int);
54static int wdt_gpi_open(struct inode *, struct file *);
55static int wdt_gpi_release(struct inode *, struct file *);
56static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *);
57static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long);
58static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *);
59static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int);
60static int __init wdt_gpi_probe(struct device *);
61static int __exit wdt_gpi_remove(struct device *);
62
63
64static const char wdt_gpi_name[] = "wdt_gpi";
65static atomic_t opencnt;
66static int expect_close;
67static int locked;
68
69
70/* These are set from device resources */
71static void __iomem * wd_regs;
72static unsigned int wd_irq, wd_ctr;
73
74
75/* Module arguments */
76static int timeout = MAX_TIMEOUT_SECONDS;
77module_param(timeout, int, 0444);
78MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
79
80static unsigned long resetaddr = 0xbffdc200;
81module_param(resetaddr, ulong, 0444);
82MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset");
83
84static unsigned long flagaddr = 0xbffdc104;
85module_param(flagaddr, ulong, 0444);
86MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to");
87
88static int powercycle;
89module_param(powercycle, bool, 0444);
90MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires");
91
92static int nowayout = WATCHDOG_NOWAYOUT;
93module_param(nowayout, bool, 0444);
94MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started");
95
96
97/* Interrupt handler */
98static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt, struct pt_regs *regs)
99{
100 if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1))
101 return IRQ_NONE;
102 __raw_writel(0x1, wd_regs + 0x0008);
103
104
105 printk(KERN_CRIT "%s: watchdog expired - resetting system\n",
106 wdt_gpi_name);
107
108 *(volatile char *) flagaddr |= 0x01;
109 *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2;
110 iob();
111 while (1)
112 cpu_relax();
113}
114
115
116/* Watchdog functions */
117static void wdt_gpi_start(void)
118{
119 u32 reg;
120
121 lock_titan_regs();
122 reg = titan_readl(CPGIG1ER);
123 titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER);
124 iob();
125 unlock_titan_regs();
126}
127
128static void wdt_gpi_stop(void)
129{
130 u32 reg;
131
132 lock_titan_regs();
133 reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4));
134 titan_writel(reg, CPCCR);
135 reg = titan_readl(CPGIG1ER);
136 titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER);
137 iob();
138 unlock_titan_regs();
139}
140
141static void wdt_gpi_set_timeout(unsigned int to)
142{
143 u32 reg;
144 const u32 wdval = (to * CLOCK) & ~0x0000000f;
145
146 lock_titan_regs();
147 reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4));
148 titan_writel(reg, CPCCR);
149 wmb();
150 __raw_writel(wdval, wd_regs + 0x0000);
151 wmb();
152 titan_writel(reg | (0x2 << (wd_ctr * 4)), CPCCR);
153 wmb();
154 titan_writel(reg | (0x5 << (wd_ctr * 4)), CPCCR);
155 iob();
156 unlock_titan_regs();
157}
158
159
160/* /dev/watchdog operations */
161static int wdt_gpi_open(struct inode *inode, struct file *file)
162{
163 int res;
164
165 if (unlikely(atomic_dec_if_positive(&opencnt) < 0))
166 return -EBUSY;
167
168 expect_close = 0;
169 if (locked) {
170 module_put(THIS_MODULE);
171 free_irq(wd_irq, &miscdev);
172 locked = 0;
173 }
174
175 res = request_irq(wd_irq, wdt_gpi_irqhdl, SA_SHIRQ | SA_INTERRUPT,
176 wdt_gpi_name, &miscdev);
177 if (unlikely(res))
178 return res;
179
180 wdt_gpi_set_timeout(timeout);
181 wdt_gpi_start();
182
183 printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n",
184 wdt_gpi_name, timeout);
185 return nonseekable_open(inode, file);
186}
187
188static int wdt_gpi_release(struct inode *inode, struct file *file)
189{
190 if (nowayout) {
191 printk(KERN_INFO "%s: no way out - watchdog left running\n",
192 wdt_gpi_name);
193 __module_get(THIS_MODULE);
194 locked = 1;
195 } else {
196 if (expect_close) {
197 wdt_gpi_stop();
198 free_irq(wd_irq, &miscdev);
199 printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name);
200 } else {
201 printk(KERN_CRIT "%s: unexpected close() -"
202 " watchdog left running\n",
203 wdt_gpi_name);
204 wdt_gpi_set_timeout(timeout);
205 __module_get(THIS_MODULE);
206 locked = 1;
207 }
208 }
209
210 atomic_inc(&opencnt);
211 return 0;
212}
213
214static ssize_t
215wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o)
216{
217 char val;
218
219 wdt_gpi_set_timeout(timeout);
220 expect_close = (s > 0) && !get_user(val, d) && (val == 'V');
221 return s ? 1 : 0;
222}
223
224static long
225wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
226{
227 long res = -ENOTTY;
228 const long size = _IOC_SIZE(cmd);
229 int stat;
230 void __user *argp = (void __user *)arg;
231 static struct watchdog_info wdinfo = {
232 .identity = "RM9xxx/GPI watchdog",
233 .firmware_version = 0,
234 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
235 };
236
237 if (unlikely(_IOC_TYPE(cmd) != WATCHDOG_IOCTL_BASE))
238 return -ENOTTY;
239
240 if ((_IOC_DIR(cmd) & _IOC_READ)
241 && !access_ok(VERIFY_WRITE, arg, size))
242 return -EFAULT;
243
244 if ((_IOC_DIR(cmd) & _IOC_WRITE)
245 && !access_ok(VERIFY_READ, arg, size))
246 return -EFAULT;
247
248 expect_close = 0;
249
250 switch (cmd) {
251 case WDIOC_GETSUPPORT:
252 wdinfo.options = nowayout ?
253 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING :
254 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE;
255 res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size;
256 break;
257
258 case WDIOC_GETSTATUS:
259 break;
260
261 case WDIOC_GETBOOTSTATUS:
262 stat = (*(volatile char *) flagaddr & 0x01)
263 ? WDIOF_CARDRESET : 0;
264 res = __copy_to_user(argp, &stat, size) ?
265 -EFAULT : size;
266 break;
267
268 case WDIOC_SETOPTIONS:
269 break;
270
271 case WDIOC_KEEPALIVE:
272 wdt_gpi_set_timeout(timeout);
273 res = size;
274 break;
275
276 case WDIOC_SETTIMEOUT:
277 {
278 int val;
279 if (unlikely(__copy_from_user(&val, argp, size))) {
280 res = -EFAULT;
281 break;
282 }
283
284 if (val > MAX_TIMEOUT_SECONDS)
285 val = MAX_TIMEOUT_SECONDS;
286 timeout = val;
287 wdt_gpi_set_timeout(val);
288 res = size;
289 printk(KERN_INFO "%s: timeout set to %u seconds\n",
290 wdt_gpi_name, timeout);
291 }
292 break;
293
294 case WDIOC_GETTIMEOUT:
295 res = __copy_to_user(argp, &timeout, size) ?
296 -EFAULT : size;
297 break;
298 }
299
300 return res;
301}
302
303
304/* Shutdown notifier */
305static int
306wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused)
307{
308 if (code == SYS_DOWN || code == SYS_HALT)
309 wdt_gpi_stop();
310
311 return NOTIFY_DONE;
312}
313
314
315/* Kernel interfaces */
316static struct file_operations fops = {
317 .owner = THIS_MODULE,
318 .open = wdt_gpi_open,
319 .release = wdt_gpi_release,
320 .write = wdt_gpi_write,
321 .unlocked_ioctl = wdt_gpi_ioctl,
322};
323
324static struct miscdevice miscdev = {
325 .minor = WATCHDOG_MINOR,
326 .name = wdt_gpi_name,
327 .fops = &fops,
328};
329
330static struct notifier_block wdt_gpi_shutdown = {
331 .notifier_call = wdt_gpi_notify,
332};
333
334
335/* Init & exit procedures */
336static const struct resource *
337wdt_gpi_get_resource(struct platform_device *pdv, const char *name,
338 unsigned int type)
339{
340 char buf[80];
341 if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf)
342 return NULL;
343 return platform_get_resource_byname(pdv, type, buf);
344}
345
346/* No hotplugging on the platform bus - use __init */
347static int __init wdt_gpi_probe(struct device *dev)
348{
349 int res;
350 struct platform_device * const pdv = to_platform_device(dev);
351 const struct resource
352 * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS,
353 IORESOURCE_MEM),
354 * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ,
355 IORESOURCE_IRQ),
356 * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER,
357 0);
358
359 if (unlikely(!rr || !ri || !rc))
360 return -ENXIO;
361
362 wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start);
363 if (unlikely(!wd_regs))
364 return -ENOMEM;
365 wd_irq = ri->start;
366 wd_ctr = rc->start;
367 res = misc_register(&miscdev);
368 if (res)
369 iounmap(wd_regs);
370 else
371 register_reboot_notifier(&wdt_gpi_shutdown);
372 return res;
373}
374
375static int __exit wdt_gpi_remove(struct device *dev)
376{
377 int res;
378
379 unregister_reboot_notifier(&wdt_gpi_shutdown);
380 res = misc_deregister(&miscdev);
381 iounmap(wd_regs);
382 wd_regs = NULL;
383 return res;
384}
385
386
387/* Device driver init & exit */
388static struct device_driver wdt_gpi_driver = {
389 .name = (char *) wdt_gpi_name,
390 .bus = &platform_bus_type,
391 .owner = THIS_MODULE,
392 .probe = wdt_gpi_probe,
393 .remove = __exit_p(wdt_gpi_remove),
394 .shutdown = NULL,
395 .suspend = NULL,
396 .resume = NULL,
397};
398
399static int __init wdt_gpi_init_module(void)
400{
401 atomic_set(&opencnt, 1);
402 if (timeout > MAX_TIMEOUT_SECONDS)
403 timeout = MAX_TIMEOUT_SECONDS;
404 return driver_register(&wdt_gpi_driver);
405}
406
407static void __exit wdt_gpi_cleanup_module(void)
408{
409 driver_unregister(&wdt_gpi_driver);
410}
411
412module_init(wdt_gpi_init_module);
413module_exit(wdt_gpi_cleanup_module);
414
415MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
416MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices");
417MODULE_VERSION("0.1");
418MODULE_LICENSE("GPL");
419MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
420
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 68b1ca976d53..18cb050c3862 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -380,18 +380,21 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
380 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 380 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
381 if (res == NULL) { 381 if (res == NULL) {
382 printk(KERN_INFO PFX "failed to get irq resource\n"); 382 printk(KERN_INFO PFX "failed to get irq resource\n");
383 iounmap(wdt_base);
383 return -ENOENT; 384 return -ENOENT;
384 } 385 }
385 386
386 ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev); 387 ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
387 if (ret != 0) { 388 if (ret != 0) {
388 printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); 389 printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
390 iounmap(wdt_base);
389 return ret; 391 return ret;
390 } 392 }
391 393
392 wdt_clock = clk_get(&pdev->dev, "watchdog"); 394 wdt_clock = clk_get(&pdev->dev, "watchdog");
393 if (wdt_clock == NULL) { 395 if (wdt_clock == NULL) {
394 printk(KERN_INFO PFX "failed to find watchdog clock source\n"); 396 printk(KERN_INFO PFX "failed to find watchdog clock source\n");
397 iounmap(wdt_base);
395 return -ENOENT; 398 return -ENOENT;
396 } 399 }
397 400
@@ -415,6 +418,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
415 if (ret) { 418 if (ret) {
416 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", 419 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
417 WATCHDOG_MINOR, ret); 420 WATCHDOG_MINOR, ret);
421 iounmap(wdt_base);
418 return ret; 422 return ret;
419 } 423 }
420 424
@@ -451,6 +455,7 @@ static int s3c2410wdt_remove(struct platform_device *dev)
451 wdt_clock = NULL; 455 wdt_clock = NULL;
452 } 456 }
453 457
458 iounmap(wdt_base);
454 misc_deregister(&s3c2410wdt_miscdev); 459 misc_deregister(&s3c2410wdt_miscdev);
455 return 0; 460 return 0;
456} 461}
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index d8d0f28e0acf..e3239833e4b0 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -392,7 +392,7 @@ static int __init sc1200wdt_init(void)
392 if (io == -1) { 392 if (io == -1) {
393 printk(KERN_ERR PFX "io parameter must be specified\n"); 393 printk(KERN_ERR PFX "io parameter must be specified\n");
394 ret = -EINVAL; 394 ret = -EINVAL;
395 goto out_clean; 395 goto out_pnp;
396 } 396 }
397 397
398#if defined CONFIG_PNP 398#if defined CONFIG_PNP
@@ -405,7 +405,7 @@ static int __init sc1200wdt_init(void)
405 if (!request_region(io, io_len, SC1200_MODULE_NAME)) { 405 if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
406 printk(KERN_ERR PFX "Unable to register IO port %#x\n", io); 406 printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
407 ret = -EBUSY; 407 ret = -EBUSY;
408 goto out_clean; 408 goto out_pnp;
409 } 409 }
410 410
411 ret = sc1200wdt_probe(); 411 ret = sc1200wdt_probe();
@@ -435,6 +435,11 @@ out_rbt:
435out_io: 435out_io:
436 release_region(io, io_len); 436 release_region(io, io_len);
437 437
438out_pnp:
439#if defined CONFIG_PNP
440 if (isapnp)
441 pnp_unregister_driver(&scl200wdt_pnp_driver);
442#endif
438 goto out_clean; 443 goto out_clean;
439} 444}
440 445
diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c
new file mode 100644
index 000000000000..9f56913b484f
--- /dev/null
+++ b/drivers/char/watchdog/smsc37b787_wdt.c
@@ -0,0 +1,627 @@
1/*
2 * SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x
3 *
4 * Based on acquirewdt.c by Alan Cox <alan@redhat.com>
5 * and some other existing drivers
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * The authors do NOT admit liability nor provide warranty for
13 * any of this software. This material is provided "AS-IS" in
14 * the hope that it may be useful for others.
15 *
16 * (C) Copyright 2003-2006 Sven Anders <anders@anduras.de>
17 *
18 * History:
19 * 2003 - Created version 1.0 for Linux 2.4.x.
20 * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE
21 * features. Released version 1.1
22 *
23 * Theory of operation:
24 *
25 * A Watchdog Timer (WDT) is a hardware circuit that can
26 * reset the computer system in case of a software fault.
27 * You probably knew that already.
28 *
29 * Usually a userspace daemon will notify the kernel WDT driver
30 * via the /dev/watchdog special device file that userspace is
31 * still alive, at regular intervals. When such a notification
32 * occurs, the driver will usually tell the hardware watchdog
33 * that everything is in order, and that the watchdog should wait
34 * for yet another little while to reset the system.
35 * If userspace fails (RAM error, kernel bug, whatever), the
36 * notifications cease to occur, and the hardware watchdog will
37 * reset the system (causing a reboot) after the timeout occurs.
38 *
39 * Create device with:
40 * mknod /dev/watchdog c 10 130
41 *
42 * For an example userspace keep-alive daemon, see:
43 * Documentation/watchdog/watchdog.txt
44 */
45
46#include <linux/module.h>
47#include <linux/moduleparam.h>
48#include <linux/types.h>
49#include <linux/miscdevice.h>
50#include <linux/watchdog.h>
51#include <linux/delay.h>
52#include <linux/fs.h>
53#include <linux/ioport.h>
54#include <linux/notifier.h>
55#include <linux/reboot.h>
56#include <linux/init.h>
57#include <linux/spinlock.h>
58
59#include <asm/io.h>
60#include <asm/uaccess.h>
61#include <asm/system.h>
62
63/* enable support for minutes as units? */
64/* (does not always work correctly, so disabled by default!) */
65#define SMSC_SUPPORT_MINUTES
66#undef SMSC_SUPPORT_MINUTES
67
68#define MAX_TIMEOUT 255
69
70#define UNIT_SECOND 0
71#define UNIT_MINUTE 1
72
73#define MODNAME "smsc37b787_wdt: "
74#define VERSION "1.1"
75
76#define IOPORT 0x3F0
77#define IOPORT_SIZE 2
78#define IODEV_NO 8
79
80static int unit = UNIT_SECOND; /* timer's unit */
81static int timeout = 60; /* timeout value: default is 60 "units" */
82static unsigned long timer_enabled = 0; /* is the timer enabled? */
83
84static char expect_close; /* is the close expected? */
85
86static spinlock_t io_lock; /* to guard the watchdog from io races */
87
88static int nowayout = WATCHDOG_NOWAYOUT;
89
90/* -- Low level function ----------------------------------------*/
91
92/* unlock the IO chip */
93
94static inline void open_io_config(void)
95{
96 outb(0x55, IOPORT);
97 mdelay(1);
98 outb(0x55, IOPORT);
99}
100
101/* lock the IO chip */
102static inline void close_io_config(void)
103{
104 outb(0xAA, IOPORT);
105}
106
107/* select the IO device */
108static inline void select_io_device(unsigned char devno)
109{
110 outb(0x07, IOPORT);
111 outb(devno, IOPORT+1);
112}
113
114/* write to the control register */
115static inline void write_io_cr(unsigned char reg, unsigned char data)
116{
117 outb(reg, IOPORT);
118 outb(data, IOPORT+1);
119}
120
121/* read from the control register */
122static inline char read_io_cr(unsigned char reg)
123{
124 outb(reg, IOPORT);
125 return inb(IOPORT+1);
126}
127
128/* -- Medium level functions ------------------------------------*/
129
130static inline void gpio_bit12(unsigned char reg)
131{
132 // -- General Purpose I/O Bit 1.2 --
133 // Bit 0, In/Out: 0 = Output, 1 = Input
134 // Bit 1, Polarity: 0 = No Invert, 1 = Invert
135 // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
136 // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
137 // 11 = Either Edge Triggered Intr. 2
138 // Bit 5/6 (Reserved)
139 // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
140 write_io_cr(0xE2, reg);
141}
142
143static inline void gpio_bit13(unsigned char reg)
144{
145 // -- General Purpose I/O Bit 1.3 --
146 // Bit 0, In/Out: 0 = Output, 1 = Input
147 // Bit 1, Polarity: 0 = No Invert, 1 = Invert
148 // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
149 // Bit 3, Function select: 0 = GPI/O, 1 = LED
150 // Bit 4-6 (Reserved)
151 // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
152 write_io_cr(0xE3, reg);
153}
154
155static inline void wdt_timer_units(unsigned char new_units)
156{
157 // -- Watchdog timer units --
158 // Bit 0-6 (Reserved)
159 // Bit 7, WDT Time-out Value Units Select
160 // (0 = Minutes, 1 = Seconds)
161 write_io_cr(0xF1, new_units);
162}
163
164static inline void wdt_timeout_value(unsigned char new_timeout)
165{
166 // -- Watchdog Timer Time-out Value --
167 // Bit 0-7 Binary coded units (0=Disabled, 1..255)
168 write_io_cr(0xF2, new_timeout);
169}
170
171static inline void wdt_timer_conf(unsigned char conf)
172{
173 // -- Watchdog timer configuration --
174 // Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O
175 // Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
176 // Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr.
177 // Bit 3 Reset the timer
178 // (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled)
179 // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,
180 // 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)
181 write_io_cr(0xF3, conf);
182}
183
184static inline void wdt_timer_ctrl(unsigned char reg)
185{
186 // -- Watchdog timer control --
187 // Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured
188 // Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz
189 // Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning)
190 // Bit 3 P20 Force Timeout enabled:
191 // 0 = P20 activity does not generate the WD timeout event
192 // 1 = P20 Allows rising edge of P20, from the keyboard
193 // controller, to force the WD timeout event.
194 // Bit 4 (Reserved)
195 // -- Soft power management --
196 // Bit 5 Stop Counter: 1 = Stop software power down counter
197 // set via register 0xB8, (self-cleaning)
198 // (Upon read: 0 = Counter running, 1 = Counter stopped)
199 // Bit 6 Restart Counter: 1 = Restart software power down counter
200 // set via register 0xB8, (self-cleaning)
201 // Bit 7 SPOFF: 1 = Force software power down (self-cleaning)
202
203 write_io_cr(0xF4, reg);
204}
205
206/* -- Higher level functions ------------------------------------*/
207
208/* initialize watchdog */
209
210static void wb_smsc_wdt_initialize(void)
211{
212 unsigned char old;
213
214 spin_lock(&io_lock);
215 open_io_config();
216 select_io_device(IODEV_NO);
217
218 // enable the watchdog
219 gpio_bit13(0x08); // Select pin 80 = LED not GPIO
220 gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert
221
222 // disable the timeout
223 wdt_timeout_value(0);
224
225 // reset control register
226 wdt_timer_ctrl(0x00);
227
228 // reset configuration register
229 wdt_timer_conf(0x00);
230
231 // read old (timer units) register
232 old = read_io_cr(0xF1) & 0x7F;
233 if (unit == UNIT_SECOND) old |= 0x80; // set to seconds
234
235 // set the watchdog timer units
236 wdt_timer_units(old);
237
238 close_io_config();
239 spin_unlock(&io_lock);
240}
241
242/* shutdown the watchdog */
243
244static void wb_smsc_wdt_shutdown(void)
245{
246 spin_lock(&io_lock);
247 open_io_config();
248 select_io_device(IODEV_NO);
249
250 // disable the watchdog
251 gpio_bit13(0x09);
252 gpio_bit12(0x09);
253
254 // reset watchdog config register
255 wdt_timer_conf(0x00);
256
257 // reset watchdog control register
258 wdt_timer_ctrl(0x00);
259
260 // disable timeout
261 wdt_timeout_value(0x00);
262
263 close_io_config();
264 spin_unlock(&io_lock);
265}
266
267/* set timeout => enable watchdog */
268
269static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
270{
271 spin_lock(&io_lock);
272 open_io_config();
273 select_io_device(IODEV_NO);
274
275 // set Power LED to blink, if we enable the timeout
276 wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
277
278 // set timeout value
279 wdt_timeout_value(new_timeout);
280
281 close_io_config();
282 spin_unlock(&io_lock);
283}
284
285/* get timeout */
286
287static unsigned char wb_smsc_wdt_get_timeout(void)
288{
289 unsigned char set_timeout;
290
291 spin_lock(&io_lock);
292 open_io_config();
293 select_io_device(IODEV_NO);
294 set_timeout = read_io_cr(0xF2);
295 close_io_config();
296 spin_unlock(&io_lock);
297
298 return set_timeout;
299}
300
301/* disable watchdog */
302
303static void wb_smsc_wdt_disable(void)
304{
305 // set the timeout to 0 to disable the watchdog
306 wb_smsc_wdt_set_timeout(0);
307}
308
309/* enable watchdog by setting the current timeout */
310
311static void wb_smsc_wdt_enable(void)
312{
313 // set the current timeout...
314 wb_smsc_wdt_set_timeout(timeout);
315}
316
317/* reset the timer */
318
319static void wb_smsc_wdt_reset_timer(void)
320{
321 spin_lock(&io_lock);
322 open_io_config();
323 select_io_device(IODEV_NO);
324
325 // reset the timer
326 wdt_timeout_value(timeout);
327 wdt_timer_conf(0x08);
328
329 close_io_config();
330 spin_unlock(&io_lock);
331}
332
333/* return, if the watchdog is enabled (timeout is set...) */
334
335static int wb_smsc_wdt_status(void)
336{
337 return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING;
338}
339
340
341/* -- File operations -------------------------------------------*/
342
343/* open => enable watchdog and set initial timeout */
344
345static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
346{
347 /* /dev/watchdog can only be opened once */
348
349 if (test_and_set_bit(0, &timer_enabled))
350 return -EBUSY;
351
352 if (nowayout)
353 __module_get(THIS_MODULE);
354
355 /* Reload and activate timer */
356 wb_smsc_wdt_enable();
357
358 printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
359
360 return nonseekable_open(inode, file);
361}
362
363/* close => shut off the timer */
364
365static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
366{
367 /* Shut off the timer. */
368
369 if (expect_close == 42) {
370 wb_smsc_wdt_disable();
371 printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n");
372 } else {
373 printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n");
374 wb_smsc_wdt_reset_timer();
375 }
376
377 clear_bit(0, &timer_enabled);
378 expect_close = 0;
379 return 0;
380}
381
382/* write => update the timer to keep the machine alive */
383
384static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
385 size_t len, loff_t *ppos)
386{
387 /* See if we got the magic character 'V' and reload the timer */
388 if (len) {
389 if (!nowayout) {
390 size_t i;
391
392 /* reset expect flag */
393 expect_close = 0;
394
395 /* scan to see whether or not we got the magic character */
396 for (i = 0; i != len; i++) {
397 char c;
398 if (get_user(c, data+i))
399 return -EFAULT;
400 if (c == 'V')
401 expect_close = 42;
402 }
403 }
404
405 /* someone wrote to us, we should reload the timer */
406 wb_smsc_wdt_reset_timer();
407 }
408 return len;
409}
410
411/* ioctl => control interface */
412
413static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
414 unsigned int cmd, unsigned long arg)
415{
416 int new_timeout;
417
418 union {
419 struct watchdog_info __user *ident;
420 int __user *i;
421 } uarg;
422
423 static struct watchdog_info ident = {
424 .options = WDIOF_KEEPALIVEPING |
425 WDIOF_SETTIMEOUT |
426 WDIOF_MAGICCLOSE,
427 .firmware_version = 0,
428 .identity = "SMsC 37B787 Watchdog"
429 };
430
431 uarg.i = (int __user *)arg;
432
433 switch (cmd) {
434 default:
435 return -ENOTTY;
436
437 case WDIOC_GETSUPPORT:
438 return copy_to_user(uarg.ident, &ident,
439 sizeof(ident)) ? -EFAULT : 0;
440
441 case WDIOC_GETSTATUS:
442 return put_user(wb_smsc_wdt_status(), uarg.i);
443
444 case WDIOC_GETBOOTSTATUS:
445 return put_user(0, uarg.i);
446
447 case WDIOC_KEEPALIVE:
448 wb_smsc_wdt_reset_timer();
449 return 0;
450
451 case WDIOC_SETTIMEOUT:
452 if (get_user(new_timeout, uarg.i))
453 return -EFAULT;
454
455 // the API states this is given in secs
456 if (unit == UNIT_MINUTE)
457 new_timeout /= 60;
458
459 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
460 return -EINVAL;
461
462 timeout = new_timeout;
463 wb_smsc_wdt_set_timeout(timeout);
464
465 // fall through and return the new timeout...
466
467 case WDIOC_GETTIMEOUT:
468
469 new_timeout = timeout;
470
471 if (unit == UNIT_MINUTE)
472 new_timeout *= 60;
473
474 return put_user(new_timeout, uarg.i);
475
476 case WDIOC_SETOPTIONS:
477 {
478 int options, retval = -EINVAL;
479
480 if (get_user(options, uarg.i))
481 return -EFAULT;
482
483 if (options & WDIOS_DISABLECARD) {
484 wb_smsc_wdt_disable();
485 retval = 0;
486 }
487
488 if (options & WDIOS_ENABLECARD) {
489 wb_smsc_wdt_enable();
490 retval = 0;
491 }
492
493 return retval;
494 }
495 }
496}
497
498/* -- Notifier funtions -----------------------------------------*/
499
500static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
501{
502 if (code == SYS_DOWN || code == SYS_HALT)
503 {
504 // set timeout to 0, to avoid possible race-condition
505 timeout = 0;
506 wb_smsc_wdt_disable();
507 }
508 return NOTIFY_DONE;
509}
510
511/* -- Module's structures ---------------------------------------*/
512
513static struct file_operations wb_smsc_wdt_fops =
514{
515 .owner = THIS_MODULE,
516 .llseek = no_llseek,
517 .write = wb_smsc_wdt_write,
518 .ioctl = wb_smsc_wdt_ioctl,
519 .open = wb_smsc_wdt_open,
520 .release = wb_smsc_wdt_release,
521};
522
523static struct notifier_block wb_smsc_wdt_notifier =
524{
525 .notifier_call = wb_smsc_wdt_notify_sys,
526};
527
528static struct miscdevice wb_smsc_wdt_miscdev =
529{
530 .minor = WATCHDOG_MINOR,
531 .name = "watchdog",
532 .fops = &wb_smsc_wdt_fops,
533};
534
535/* -- Module init functions -------------------------------------*/
536
537/* module's "constructor" */
538
539static int __init wb_smsc_wdt_init(void)
540{
541 int ret;
542
543 spin_lock_init(&io_lock);
544
545 printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n");
546
547 if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
548 printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT);
549 ret = -EBUSY;
550 goto out_pnp;
551 }
552
553 // set new maximum, if it's too big
554 if (timeout > MAX_TIMEOUT)
555 timeout = MAX_TIMEOUT;
556
557 // init the watchdog timer
558 wb_smsc_wdt_initialize();
559
560 ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
561 if (ret) {
562 printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret);
563 goto out_io;
564 }
565
566 ret = misc_register(&wb_smsc_wdt_miscdev);
567 if (ret) {
568 printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
569 goto out_rbt;
570 }
571
572 // output info
573 printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
574 printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout);
575
576 // ret = 0
577
578out_clean:
579 return ret;
580
581out_rbt:
582 unregister_reboot_notifier(&wb_smsc_wdt_notifier);
583
584out_io:
585 release_region(IOPORT, IOPORT_SIZE);
586
587out_pnp:
588 goto out_clean;
589}
590
591/* module's "destructor" */
592
593static void __exit wb_smsc_wdt_exit(void)
594{
595 /* Stop the timer before we leave */
596 if (!nowayout)
597 {
598 wb_smsc_wdt_shutdown();
599 printk(KERN_INFO MODNAME "Watchdog disabled.\n");
600 }
601
602 misc_deregister(&wb_smsc_wdt_miscdev);
603 unregister_reboot_notifier(&wb_smsc_wdt_notifier);
604 release_region(IOPORT, IOPORT_SIZE);
605
606 printk("SMsC 37B787 watchdog component driver removed.\n");
607}
608
609module_init(wb_smsc_wdt_init);
610module_exit(wb_smsc_wdt_exit);
611
612MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
613MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")");
614MODULE_LICENSE("GPL");
615
616MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
617
618#ifdef SMSC_SUPPORT_MINUTES
619module_param(unit, int, 0);
620MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0");
621#endif
622
623module_param(timeout, int, 0);
624MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
625
626module_param(nowayout, int, 0);
627MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index b4adc527e687..07d4bff27226 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -33,6 +33,7 @@
33#include <linux/notifier.h> 33#include <linux/notifier.h>
34#include <linux/reboot.h> 34#include <linux/reboot.h>
35#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/spinlock.h>
36 37
37#include <asm/io.h> 38#include <asm/io.h>
38#include <asm/uaccess.h> 39#include <asm/uaccess.h>
@@ -44,6 +45,7 @@
44 45
45static unsigned long wdt_is_open; 46static unsigned long wdt_is_open;
46static char expect_close; 47static char expect_close;
48static spinlock_t io_lock;
47 49
48/* You must set this - there is no sane way to probe for this board. */ 50/* You must set this - there is no sane way to probe for this board. */
49static int wdt_io = 0x2E; 51static int wdt_io = 0x2E;
@@ -110,12 +112,16 @@ w83627hf_init(void)
110static void 112static void
111wdt_ctrl(int timeout) 113wdt_ctrl(int timeout)
112{ 114{
115 spin_lock(&io_lock);
116
113 w83627hf_select_wd_register(); 117 w83627hf_select_wd_register();
114 118
115 outb_p(0xF6, WDT_EFER); /* Select CRF6 */ 119 outb_p(0xF6, WDT_EFER); /* Select CRF6 */
116 outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */ 120 outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */
117 121
118 w83627hf_unselect_wd_register(); 122 w83627hf_unselect_wd_register();
123
124 spin_unlock(&io_lock);
119} 125}
120 126
121static int 127static int
@@ -303,6 +309,8 @@ wdt_init(void)
303{ 309{
304 int ret; 310 int ret;
305 311
312 spin_lock_init(&io_lock);
313
306 printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); 314 printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n");
307 315
308 if (wdt_set_heartbeat(timeout)) { 316 if (wdt_set_heartbeat(timeout)) {
diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/char/watchdog/w83697hf_wdt.c
new file mode 100644
index 000000000000..7768b55487c8
--- /dev/null
+++ b/drivers/char/watchdog/w83697hf_wdt.c
@@ -0,0 +1,450 @@
1/*
2 * w83697hf/hg WDT driver
3 *
4 * (c) Copyright 2006 Samuel Tardieu <sam@rfc1149.net>
5 * (c) Copyright 2006 Marcus Junker <junker@anduras.de>
6 *
7 * Based on w83627hf_wdt.c which is based on advantechwdt.c
8 * which is based on wdt.c.
9 * Original copyright messages:
10 *
11 * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
12 *
13 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
14 *
15 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
16 * http://www.redhat.com
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version
21 * 2 of the License, or (at your option) any later version.
22 *
23 * Neither Marcus Junker nor ANDURAS AG admit liability nor provide
24 * warranty for any of this software. This material is provided
25 * "AS-IS" and at no charge.
26 */
27
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/types.h>
31#include <linux/miscdevice.h>
32#include <linux/watchdog.h>
33#include <linux/fs.h>
34#include <linux/ioport.h>
35#include <linux/notifier.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/spinlock.h>
39
40#include <asm/io.h>
41#include <asm/uaccess.h>
42#include <asm/system.h>
43
44#define WATCHDOG_NAME "w83697hf/hg WDT"
45#define PFX WATCHDOG_NAME ": "
46#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
47
48static unsigned long wdt_is_open;
49static char expect_close;
50static spinlock_t io_lock;
51
52/* You must set this - there is no sane way to probe for this board. */
53static int wdt_io = 0x2e;
54module_param(wdt_io, int, 0);
55MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)");
56
57static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
58module_param(timeout, int, 0);
59MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
60
61static int nowayout = WATCHDOG_NOWAYOUT;
62module_param(nowayout, int, 0);
63MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
64
65/*
66 * Kernel methods.
67 */
68
69#define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */
70#define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */
71#define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */
72
73static inline void
74w83697hf_unlock(void)
75{
76 outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */
77 outb_p(0x87, W83697HF_EFER); /* Again according to manual */
78}
79
80static inline void
81w83697hf_lock(void)
82{
83 outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */
84}
85
86/*
87 * The three functions w83697hf_get_reg(), w83697hf_set_reg() and
88 * w83697hf_write_timeout() must be called with the device unlocked.
89 */
90
91static unsigned char
92w83697hf_get_reg(unsigned char reg)
93{
94 outb_p(reg, W83697HF_EFIR);
95 return inb_p(W83697HF_EFDR);
96}
97
98static void
99w83697hf_set_reg(unsigned char reg, unsigned char data)
100{
101 outb_p(reg, W83697HF_EFIR);
102 outb_p(data, W83697HF_EFDR);
103}
104
105static void
106w83697hf_write_timeout(int timeout)
107{
108 w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */
109}
110
111static void
112w83697hf_select_wdt(void)
113{
114 w83697hf_unlock();
115 w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */
116}
117
118static inline void
119w83697hf_deselect_wdt(void)
120{
121 w83697hf_lock();
122}
123
124static void
125w83697hf_init(void)
126{
127 unsigned char bbuf;
128
129 w83697hf_select_wdt();
130
131 bbuf = w83697hf_get_reg(0x29);
132 bbuf &= ~0x60;
133 bbuf |= 0x20;
134 w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
135
136 bbuf = w83697hf_get_reg(0xF3);
137 bbuf &= ~0x04;
138 w83697hf_set_reg(0xF3, bbuf); /* Count mode is seconds */
139
140 w83697hf_deselect_wdt();
141}
142
143static int
144wdt_ping(void)
145{
146 spin_lock(&io_lock);
147 w83697hf_select_wdt();
148
149 w83697hf_write_timeout(timeout);
150
151 w83697hf_deselect_wdt();
152 spin_unlock(&io_lock);
153 return 0;
154}
155
156static int
157wdt_enable(void)
158{
159 spin_lock(&io_lock);
160 w83697hf_select_wdt();
161
162 w83697hf_write_timeout(timeout);
163 w83697hf_set_reg(0x30, 1); /* Enable timer */
164
165 w83697hf_deselect_wdt();
166 spin_unlock(&io_lock);
167 return 0;
168}
169
170static int
171wdt_disable(void)
172{
173 spin_lock(&io_lock);
174 w83697hf_select_wdt();
175
176 w83697hf_set_reg(0x30, 0); /* Disable timer */
177 w83697hf_write_timeout(0);
178
179 w83697hf_deselect_wdt();
180 spin_unlock(&io_lock);
181 return 0;
182}
183
184static int
185wdt_set_heartbeat(int t)
186{
187 if ((t < 1) || (t > 255))
188 return -EINVAL;
189
190 timeout = t;
191 return 0;
192}
193
194static ssize_t
195wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
196{
197 if (count) {
198 if (!nowayout) {
199 size_t i;
200
201 expect_close = 0;
202
203 for (i = 0; i != count; i++) {
204 char c;
205 if (get_user(c, buf+i))
206 return -EFAULT;
207 if (c == 'V')
208 expect_close = 42;
209 }
210 }
211 wdt_ping();
212 }
213 return count;
214}
215
216static int
217wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
218 unsigned long arg)
219{
220 void __user *argp = (void __user *)arg;
221 int __user *p = argp;
222 int new_timeout;
223 static struct watchdog_info ident = {
224 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
225 .firmware_version = 1,
226 .identity = "W83697HF WDT",
227 };
228
229 switch (cmd) {
230 case WDIOC_GETSUPPORT:
231 if (copy_to_user(argp, &ident, sizeof(ident)))
232 return -EFAULT;
233 break;
234
235 case WDIOC_GETSTATUS:
236 case WDIOC_GETBOOTSTATUS:
237 return put_user(0, p);
238
239 case WDIOC_KEEPALIVE:
240 wdt_ping();
241 break;
242
243 case WDIOC_SETTIMEOUT:
244 if (get_user(new_timeout, p))
245 return -EFAULT;
246 if (wdt_set_heartbeat(new_timeout))
247 return -EINVAL;
248 wdt_ping();
249 /* Fall */
250
251 case WDIOC_GETTIMEOUT:
252 return put_user(timeout, p);
253
254 case WDIOC_SETOPTIONS:
255 {
256 int options, retval = -EINVAL;
257
258 if (get_user(options, p))
259 return -EFAULT;
260
261 if (options & WDIOS_DISABLECARD) {
262 wdt_disable();
263 retval = 0;
264 }
265
266 if (options & WDIOS_ENABLECARD) {
267 wdt_enable();
268 retval = 0;
269 }
270
271 return retval;
272 }
273
274 default:
275 return -ENOTTY;
276 }
277 return 0;
278}
279
280static int
281wdt_open(struct inode *inode, struct file *file)
282{
283 if (test_and_set_bit(0, &wdt_is_open))
284 return -EBUSY;
285 /*
286 * Activate
287 */
288
289 wdt_enable();
290 return nonseekable_open(inode, file);
291}
292
293static int
294wdt_close(struct inode *inode, struct file *file)
295{
296 if (expect_close == 42) {
297 wdt_disable();
298 } else {
299 printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
300 wdt_ping();
301 }
302 expect_close = 0;
303 clear_bit(0, &wdt_is_open);
304 return 0;
305}
306
307/*
308 * Notifier for system down
309 */
310
311static int
312wdt_notify_sys(struct notifier_block *this, unsigned long code,
313 void *unused)
314{
315 if (code == SYS_DOWN || code == SYS_HALT) {
316 /* Turn the WDT off */
317 wdt_disable();
318 }
319 return NOTIFY_DONE;
320}
321
322/*
323 * Kernel Interfaces
324 */
325
326static struct file_operations wdt_fops = {
327 .owner = THIS_MODULE,
328 .llseek = no_llseek,
329 .write = wdt_write,
330 .ioctl = wdt_ioctl,
331 .open = wdt_open,
332 .release = wdt_close,
333};
334
335static struct miscdevice wdt_miscdev = {
336 .minor = WATCHDOG_MINOR,
337 .name = "watchdog",
338 .fops = &wdt_fops,
339};
340
341/*
342 * The WDT needs to learn about soft shutdowns in order to
343 * turn the timebomb registers off.
344 */
345
346static struct notifier_block wdt_notifier = {
347 .notifier_call = wdt_notify_sys,
348};
349
350static int
351w83697hf_check_wdt(void)
352{
353 if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
354 printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io);
355 return -EIO;
356 }
357
358 printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io);
359 w83697hf_unlock();
360 if (w83697hf_get_reg(0x20) == 0x60) {
361 printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io);
362 w83697hf_lock();
363 return 0;
364 }
365 w83697hf_lock(); /* Reprotect in case it was a compatible device */
366
367 printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io);
368 release_region(wdt_io, 2);
369 return -EIO;
370}
371
372static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 };
373
374static int __init
375wdt_init(void)
376{
377 int ret, i, found = 0;
378
379 spin_lock_init(&io_lock);
380
381 printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
382
383 if (wdt_io == 0) {
384 /* we will autodetect the W83697HF/HG watchdog */
385 for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) {
386 wdt_io = w83697hf_ioports[i];
387 if (!w83697hf_check_wdt())
388 found++;
389 }
390 } else {
391 if (!w83697hf_check_wdt())
392 found++;
393 }
394
395 if (!found) {
396 printk (KERN_ERR PFX "No W83697HF/HG could be found\n");
397 ret = -EIO;
398 goto out;
399 }
400
401 w83697hf_init();
402 wdt_disable(); /* Disable watchdog until first use */
403
404 if (wdt_set_heartbeat(timeout)) {
405 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
406 printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
407 WATCHDOG_TIMEOUT);
408 }
409
410 ret = register_reboot_notifier(&wdt_notifier);
411 if (ret != 0) {
412 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
413 ret);
414 goto unreg_regions;
415 }
416
417 ret = misc_register(&wdt_miscdev);
418 if (ret != 0) {
419 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
420 WATCHDOG_MINOR, ret);
421 goto unreg_reboot;
422 }
423
424 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
425 timeout, nowayout);
426
427out:
428 return ret;
429unreg_reboot:
430 unregister_reboot_notifier(&wdt_notifier);
431unreg_regions:
432 release_region(wdt_io, 2);
433 goto out;
434}
435
436static void __exit
437wdt_exit(void)
438{
439 misc_deregister(&wdt_miscdev);
440 unregister_reboot_notifier(&wdt_notifier);
441 release_region(wdt_io, 2);
442}
443
444module_init(wdt_init);
445module_exit(wdt_exit);
446
447MODULE_LICENSE("GPL");
448MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, Samuel Tardieu <sam@rfc1149.net>");
449MODULE_DESCRIPTION("w83697hf/hg WDT driver");
450MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);