1 /*
2  *	intel TCO vendor specific watchdog driver support
3  *
4  *	(c) Copyright 2006-2009 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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21 
22 /* Module and version information */
23 #define DRV_NAME	"iTCO_vendor_support"
24 #define DRV_VERSION	"1.04"
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 #include <linux/io.h>			/* For inb/outb/... */
35 
36 #include "iTCO_vendor.h"
37 
38 /* List of vendor support modes */
39 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
40 #define SUPERMICRO_OLD_BOARD	1
41 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems - no longer supported */
42 #define SUPERMICRO_NEW_BOARD	2
43 /* Broken BIOS */
44 #define BROKEN_BIOS		911
45 
46 static int vendorsupport;
47 module_param(vendorsupport, int, 0);
48 MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
49 			"0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS");
50 
51 /*
52  *	Vendor Specific Support
53  */
54 
55 /*
56  *	Vendor Support: 1
57  *	Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE
58  *	iTCO chipset: ICH2
59  *
60  *	Code contributed by: R. Seretny <lkpatches@paypc.com>
61  *	Documentation obtained by R. Seretny from SuperMicro Technical Support
62  *
63  *	To enable Watchdog function:
64  *	    BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes
65  *	    This setting enables SMI to clear the watchdog expired flag.
66  *	    If BIOS or CPU fail which may cause SMI hang, then system will
67  *	    reboot. When application starts to use watchdog function,
68  *	    application has to take over the control from SMI.
69  *
70  *	    For P3TSSE, J36 jumper needs to be removed to enable the Watchdog
71  *	    function.
72  *
73  *	    Note: The system will reboot when Expire Flag is set TWICE.
74  *	    So, if the watchdog timer is 20 seconds, then the maximum hang
75  *	    time is about 40 seconds, and the minimum hang time is about
76  *	    20.6 seconds.
77  */
78 
79 static void supermicro_old_pre_start(struct resource *smires)
80 {
81 	unsigned long val32;
82 
83 	/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
84 	val32 = inl(smires->start);
85 	val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
86 	outl(val32, smires->start);	/* Needed to activate watchdog */
87 }
88 
89 static void supermicro_old_pre_stop(struct resource *smires)
90 {
91 	unsigned long val32;
92 
93 	/* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
94 	val32 = inl(smires->start);
95 	val32 |= 0x00002000;	/* Turn on SMI clearing watchdog */
96 	outl(val32, smires->start);	/* Needed to deactivate watchdog */
97 }
98 
99 /*
100  *	Vendor Support: 911
101  *	Board: Some Intel ICHx based motherboards
102  *	iTCO chipset: ICH7+
103  *
104  *	Some Intel motherboards have a broken BIOS implementation: i.e.
105  *	the SMI handler clear's the TIMEOUT bit in the TC01_STS register
106  *	and does not reload the time. Thus the TCO watchdog does not reboot
107  *	the system.
108  *
109  *	These are the conclusions of Andriy Gapon <avg@icyb.net.ua> after
110  *	debugging: the SMI handler is quite simple - it tests value in
111  *	TCO1_CNT against 0x800, i.e. checks TCO_TMR_HLT. If the bit is set
112  *	the handler goes into an infinite loop, apparently to allow the
113  *	second timeout and reboot. Otherwise it simply clears TIMEOUT bit
114  *	in TCO1_STS and that's it.
115  *	So the logic seems to be reversed, because it is hard to see how
116  *	TIMEOUT can get set to 1 and SMI generated when TCO_TMR_HLT is set
117  *	(other than a transitional effect).
118  *
119  *	The only fix found to get the motherboard(s) to reboot is to put
120  *	the glb_smi_en bit to 0. This is a dirty hack that bypasses the
121  *	broken code by disabling Global SMI.
122  *
123  *	WARNING: globally disabling SMI could possibly lead to dramatic
124  *	problems, especially on laptops! I.e. various ACPI things where
125  *	SMI is used for communication between OS and firmware.
126  *
127  *	Don't use this fix if you don't need to!!!
128  */
129 
130 static void broken_bios_start(struct resource *smires)
131 {
132 	unsigned long val32;
133 
134 	val32 = inl(smires->start);
135 	/* Bit 13: TCO_EN     -> 0 = Disables TCO logic generating an SMI#
136 	   Bit  0: GBL_SMI_EN -> 0 = No SMI# will be generated by ICH. */
137 	val32 &= 0xffffdffe;
138 	outl(val32, smires->start);
139 }
140 
141 static void broken_bios_stop(struct resource *smires)
142 {
143 	unsigned long val32;
144 
145 	val32 = inl(smires->start);
146 	/* Bit 13: TCO_EN     -> 1 = Enables TCO logic generating an SMI#
147 	   Bit  0: GBL_SMI_EN -> 1 = Turn global SMI on again. */
148 	val32 |= 0x00002001;
149 	outl(val32, smires->start);
150 }
151 
152 /*
153  *	Generic Support Functions
154  */
155 
156 void iTCO_vendor_pre_start(struct resource *smires,
157 			   unsigned int heartbeat)
158 {
159 	switch (vendorsupport) {
160 	case SUPERMICRO_OLD_BOARD:
161 		supermicro_old_pre_start(smires);
162 		break;
163 	case BROKEN_BIOS:
164 		broken_bios_start(smires);
165 		break;
166 	}
167 }
168 EXPORT_SYMBOL(iTCO_vendor_pre_start);
169 
170 void iTCO_vendor_pre_stop(struct resource *smires)
171 {
172 	switch (vendorsupport) {
173 	case SUPERMICRO_OLD_BOARD:
174 		supermicro_old_pre_stop(smires);
175 		break;
176 	case BROKEN_BIOS:
177 		broken_bios_stop(smires);
178 		break;
179 	}
180 }
181 EXPORT_SYMBOL(iTCO_vendor_pre_stop);
182 
183 int iTCO_vendor_check_noreboot_on(void)
184 {
185 	switch (vendorsupport) {
186 	case SUPERMICRO_OLD_BOARD:
187 		return 0;
188 	default:
189 		return 1;
190 	}
191 }
192 EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
193 
194 static int __init iTCO_vendor_init_module(void)
195 {
196 	if (vendorsupport == SUPERMICRO_NEW_BOARD) {
197 		pr_warn("Option vendorsupport=%d is no longer supported, "
198 			"please use the w83627hf_wdt driver instead\n",
199 			SUPERMICRO_NEW_BOARD);
200 		return -EINVAL;
201 	}
202 	pr_info("vendor-support=%d\n", vendorsupport);
203 	return 0;
204 }
205 
206 static void __exit iTCO_vendor_exit_module(void)
207 {
208 	pr_info("Module Unloaded\n");
209 }
210 
211 module_init(iTCO_vendor_init_module);
212 module_exit(iTCO_vendor_exit_module);
213 
214 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, "
215 		"R. Seretny <lkpatches@paypc.com>");
216 MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
217 MODULE_VERSION(DRV_VERSION);
218 MODULE_LICENSE("GPL");
219 
220