aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog
diff options
context:
space:
mode:
authorWim Van Sebroeck <wim@iguana.be>2006-11-12 12:05:09 -0500
committerWim Van Sebroeck <wim@iguana.be>2006-11-12 12:05:09 -0500
commite033351d5359f348d2913eb83fbb37023d8f21af (patch)
tree0ccb7fd82aa28277ace1cd323e3c040db56ee175 /drivers/char/watchdog
parent58c6570add83e30c0905885171fbffc134441165 (diff)
[WATCHDOG] Add iTCO vendor specific support
Add vendor specific support to the intel TCO timer based watchdog devices. At this moment we only have additional support for some SuperMicro Inc. motherboards. Signed-off-by: Robert Seretny <lkpatches@paypc.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/char/watchdog')
-rw-r--r--drivers/char/watchdog/Kconfig8
-rw-r--r--drivers/char/watchdog/Makefile2
-rw-r--r--drivers/char/watchdog/iTCO_vendor_support.c307
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c29
4 files changed, 342 insertions, 4 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index d3e99982b69a..a52ecad7d56c 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -340,6 +340,14 @@ config ITCO_WDT
340 To compile this driver as a module, choose M here: the 340 To compile this driver as a module, choose M here: the
341 module will be called iTCO_wdt. 341 module will be called iTCO_wdt.
342 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
343config SC1200_WDT 351config SC1200_WDT
344 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" 352 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
345 depends on WATCHDOG && X86 353 depends on WATCHDOG && X86
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index e6a9f6f1d4b7..81abdfa10a07 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -47,7 +47,7 @@ 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_PC87413_WDT) += pc87413_wdt.o
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 b6f29cb8bd39..7eac922df867 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -48,8 +48,8 @@
48 48
49/* Module and version information */ 49/* Module and version information */
50#define DRV_NAME "iTCO_wdt" 50#define DRV_NAME "iTCO_wdt"
51#define DRV_VERSION "1.00" 51#define DRV_VERSION "1.01"
52#define DRV_RELDATE "08-Oct-2006" 52#define DRV_RELDATE "11-Nov-2006"
53#define PFX DRV_NAME ": " 53#define PFX DRV_NAME ": "
54 54
55/* Includes */ 55/* Includes */
@@ -189,6 +189,21 @@ static int nowayout = WATCHDOG_NOWAYOUT;
189module_param(nowayout, int, 0); 189module_param(nowayout, int, 0);
190MODULE_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)");
191 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
192/* 207/*
193 * Some TCO specific functions 208 * Some TCO specific functions
194 */ 209 */
@@ -249,6 +264,8 @@ static int iTCO_wdt_start(void)
249 264
250 spin_lock(&iTCO_wdt_private.io_lock); 265 spin_lock(&iTCO_wdt_private.io_lock);
251 266
267 iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
268
252 /* disable chipset's NO_REBOOT bit */ 269 /* disable chipset's NO_REBOOT bit */
253 if (iTCO_wdt_unset_NO_REBOOT_bit()) { 270 if (iTCO_wdt_unset_NO_REBOOT_bit()) {
254 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");
@@ -273,6 +290,8 @@ static int iTCO_wdt_stop(void)
273 290
274 spin_lock(&iTCO_wdt_private.io_lock); 291 spin_lock(&iTCO_wdt_private.io_lock);
275 292
293 iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
294
276 /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ 295 /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
277 val = inw(TCO1_CNT); 296 val = inw(TCO1_CNT);
278 val |= 0x0800; 297 val |= 0x0800;
@@ -293,6 +312,8 @@ static int iTCO_wdt_keepalive(void)
293{ 312{
294 spin_lock(&iTCO_wdt_private.io_lock); 313 spin_lock(&iTCO_wdt_private.io_lock);
295 314
315 iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
316
296 /* Reload the timer by writing to the TCO Timer Counter register */ 317 /* Reload the timer by writing to the TCO Timer Counter register */
297 if (iTCO_wdt_private.iTCO_version == 2) { 318 if (iTCO_wdt_private.iTCO_version == 2) {
298 outw(0x01, TCO_RLD); 319 outw(0x01, TCO_RLD);
@@ -319,6 +340,8 @@ static int iTCO_wdt_set_heartbeat(int t)
319 ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) 340 ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
320 return -EINVAL; 341 return -EINVAL;
321 342
343 iTCO_vendor_pre_set_heartbeat(tmrval);
344
322 /* Write new heartbeat to watchdog */ 345 /* Write new heartbeat to watchdog */
323 if (iTCO_wdt_private.iTCO_version == 2) { 346 if (iTCO_wdt_private.iTCO_version == 2) {
324 spin_lock(&iTCO_wdt_private.io_lock); 347 spin_lock(&iTCO_wdt_private.io_lock);
@@ -569,7 +592,7 @@ static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent,
569 } 592 }
570 593
571 /* Check chipset's NO_REBOOT bit */ 594 /* Check chipset's NO_REBOOT bit */
572 if (iTCO_wdt_unset_NO_REBOOT_bit()) { 595 if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
573 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");
574 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ 597 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
575 goto out; 598 goto out;