Commit 7e6811daa662fc4eb87ddfb3ea0ea9d782044157

Authored by Pádraig Brady
Committed by Wim Van Sebroeck
1 parent bb6f36070c

iTCO_wdt: fix TCO V1 timeout values and limits

For TCO V1 devices the programmed timeout was twice too long
because the fact that the TCO V1 timer needs to count down
twice before triggering the watchdog, wasn't accounted for.
Also the timeout values in the module description and error
message were clarified. And the _STS registers are 16 bit
instead of 8 bit.

Signed-off-by: Pádraig Brady <P@draigBrady.com>
Tested-by: Simon Kagstrom <simon.kagstrom@netinsight.se>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

Showing 2 changed files with 21 additions and 19 deletions Inline Diff

drivers/watchdog/iTCO_vendor_support.c
1 /* 1 /*
2 * intel TCO vendor specific watchdog driver support 2 * intel TCO vendor specific watchdog driver support
3 * 3 *
4 * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. 4 * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 * 10 *
11 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor 11 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
12 * provide warranty for any of this software. This material is 12 * provide warranty for any of this software. This material is
13 * provided "AS-IS" and at no charge. 13 * provided "AS-IS" and at no charge.
14 */ 14 */
15 15
16 /* 16 /*
17 * Includes, defines, variables, module parameters, ... 17 * Includes, defines, variables, module parameters, ...
18 */ 18 */
19 19
20 /* Module and version information */ 20 /* Module and version information */
21 #define DRV_NAME "iTCO_vendor_support" 21 #define DRV_NAME "iTCO_vendor_support"
22 #define DRV_VERSION "1.04" 22 #define DRV_VERSION "1.04"
23 #define PFX DRV_NAME ": " 23 #define PFX DRV_NAME ": "
24 24
25 /* Includes */ 25 /* Includes */
26 #include <linux/module.h> /* For module specific items */ 26 #include <linux/module.h> /* For module specific items */
27 #include <linux/moduleparam.h> /* For new moduleparam's */ 27 #include <linux/moduleparam.h> /* For new moduleparam's */
28 #include <linux/types.h> /* For standard types (like size_t) */ 28 #include <linux/types.h> /* For standard types (like size_t) */
29 #include <linux/errno.h> /* For the -ENODEV/... values */ 29 #include <linux/errno.h> /* For the -ENODEV/... values */
30 #include <linux/kernel.h> /* For printk/panic/... */ 30 #include <linux/kernel.h> /* For printk/panic/... */
31 #include <linux/init.h> /* For __init/__exit/... */ 31 #include <linux/init.h> /* For __init/__exit/... */
32 #include <linux/ioport.h> /* For io-port access */ 32 #include <linux/ioport.h> /* For io-port access */
33 #include <linux/io.h> /* For inb/outb/... */ 33 #include <linux/io.h> /* For inb/outb/... */
34 34
35 #include "iTCO_vendor.h" 35 #include "iTCO_vendor.h"
36 36
37 /* iTCO defines */ 37 /* iTCO defines */
38 #define SMI_EN (acpibase + 0x30) /* SMI Control and Enable Register */ 38 #define SMI_EN (acpibase + 0x30) /* SMI Control and Enable Register */
39 #define TCOBASE (acpibase + 0x60) /* TCO base address */ 39 #define TCOBASE (acpibase + 0x60) /* TCO base address */
40 #define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */ 40 #define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */
41 41
42 /* List of vendor support modes */ 42 /* List of vendor support modes */
43 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */ 43 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
44 #define SUPERMICRO_OLD_BOARD 1 44 #define SUPERMICRO_OLD_BOARD 1
45 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */ 45 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
46 #define SUPERMICRO_NEW_BOARD 2 46 #define SUPERMICRO_NEW_BOARD 2
47 /* Broken BIOS */ 47 /* Broken BIOS */
48 #define BROKEN_BIOS 911 48 #define BROKEN_BIOS 911
49 49
50 static int vendorsupport; 50 static int vendorsupport;
51 module_param(vendorsupport, int, 0); 51 module_param(vendorsupport, int, 0);
52 MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=" 52 MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
53 "0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+, " 53 "0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+, "
54 "911=Broken SMI BIOS"); 54 "911=Broken SMI BIOS");
55 55
56 /* 56 /*
57 * Vendor Specific Support 57 * Vendor Specific Support
58 */ 58 */
59 59
60 /* 60 /*
61 * Vendor Support: 1 61 * Vendor Support: 1
62 * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE 62 * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE
63 * iTCO chipset: ICH2 63 * iTCO chipset: ICH2
64 * 64 *
65 * Code contributed by: R. Seretny <lkpatches@paypc.com> 65 * Code contributed by: R. Seretny <lkpatches@paypc.com>
66 * Documentation obtained by R. Seretny from SuperMicro Technical Support 66 * Documentation obtained by R. Seretny from SuperMicro Technical Support
67 * 67 *
68 * To enable Watchdog function: 68 * To enable Watchdog function:
69 * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes 69 * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes
70 * This setting enables SMI to clear the watchdog expired flag. 70 * This setting enables SMI to clear the watchdog expired flag.
71 * If BIOS or CPU fail which may cause SMI hang, then system will 71 * If BIOS or CPU fail which may cause SMI hang, then system will
72 * reboot. When application starts to use watchdog function, 72 * reboot. When application starts to use watchdog function,
73 * application has to take over the control from SMI. 73 * application has to take over the control from SMI.
74 * 74 *
75 * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog 75 * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog
76 * function. 76 * function.
77 * 77 *
78 * Note: The system will reboot when Expire Flag is set TWICE. 78 * Note: The system will reboot when Expire Flag is set TWICE.
79 * So, if the watchdog timer is 20 seconds, then the maximum hang 79 * So, if the watchdog timer is 20 seconds, then the maximum hang
80 * time is about 40 seconds, and the minimum hang time is about 80 * time is about 40 seconds, and the minimum hang time is about
81 * 20.6 seconds. 81 * 20.6 seconds.
82 */ 82 */
83 83
84 static void supermicro_old_pre_start(unsigned long acpibase) 84 static void supermicro_old_pre_start(unsigned long acpibase)
85 { 85 {
86 unsigned long val32; 86 unsigned long val32;
87 87
88 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ 88 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
89 val32 = inl(SMI_EN); 89 val32 = inl(SMI_EN);
90 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ 90 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
91 outl(val32, SMI_EN); /* Needed to activate watchdog */ 91 outl(val32, SMI_EN); /* Needed to activate watchdog */
92 } 92 }
93 93
94 static void supermicro_old_pre_stop(unsigned long acpibase) 94 static void supermicro_old_pre_stop(unsigned long acpibase)
95 { 95 {
96 unsigned long val32; 96 unsigned long val32;
97 97
98 /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */ 98 /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
99 val32 = inl(SMI_EN); 99 val32 = inl(SMI_EN);
100 val32 |= 0x00002000; /* Turn on SMI clearing watchdog */ 100 val32 |= 0x00002000; /* Turn on SMI clearing watchdog */
101 outl(val32, SMI_EN); /* Needed to deactivate watchdog */ 101 outl(val32, SMI_EN); /* Needed to deactivate watchdog */
102 } 102 }
103 103
104 static void supermicro_old_pre_keepalive(unsigned long acpibase)
105 {
106 /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
107 /* Clear "Expire Flag" (Bit 3 of TC01_STS register) */
108 outb(0x08, TCO1_STS);
109 }
110
111 /* 104 /*
112 * Vendor Support: 2 105 * Vendor Support: 2
113 * Board: Super Micro Computer Inc. P4SBx, P4DPx 106 * Board: Super Micro Computer Inc. P4SBx, P4DPx
114 * iTCO chipset: ICH4 107 * iTCO chipset: ICH4
115 * 108 *
116 * Code contributed by: R. Seretny <lkpatches@paypc.com> 109 * Code contributed by: R. Seretny <lkpatches@paypc.com>
117 * Documentation obtained by R. Seretny from SuperMicro Technical Support 110 * Documentation obtained by R. Seretny from SuperMicro Technical Support
118 * 111 *
119 * To enable Watchdog function: 112 * To enable Watchdog function:
120 * 1. BIOS 113 * 1. BIOS
121 * For P4SBx: 114 * For P4SBx:
122 * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature 115 * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature
123 * For P4DPx: 116 * For P4DPx:
124 * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog 117 * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog
125 * This setting enables or disables Watchdog function. When enabled, the 118 * This setting enables or disables Watchdog function. When enabled, the
126 * default watchdog timer is set to be 5 minutes (about 4m35s). It is 119 * default watchdog timer is set to be 5 minutes (about 4m35s). It is
127 * enough to load and run the OS. The application (service or driver) has 120 * enough to load and run the OS. The application (service or driver) has
128 * to take over the control once OS is running up and before watchdog 121 * to take over the control once OS is running up and before watchdog
129 * expires. 122 * expires.
130 * 123 *
131 * 2. JUMPER 124 * 2. JUMPER
132 * For P4SBx: JP39 125 * For P4SBx: JP39
133 * For P4DPx: JP37 126 * For P4DPx: JP37
134 * This jumper is used for safety. Closed is enabled. This jumper 127 * This jumper is used for safety. Closed is enabled. This jumper
135 * prevents user enables watchdog in BIOS by accident. 128 * prevents user enables watchdog in BIOS by accident.
136 * 129 *
137 * To enable Watch Dog function, both BIOS and JUMPER must be enabled. 130 * To enable Watch Dog function, both BIOS and JUMPER must be enabled.
138 * 131 *
139 * The documentation lists motherboards P4SBx and P4DPx series as of 132 * The documentation lists motherboards P4SBx and P4DPx series as of
140 * 20-March-2002. However, this code works flawlessly with much newer 133 * 20-March-2002. However, this code works flawlessly with much newer
141 * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82). 134 * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82).
142 * 135 *
143 * The original iTCO driver as written does not actually reset the 136 * The original iTCO driver as written does not actually reset the
144 * watchdog timer on these machines, as a result they reboot after five 137 * watchdog timer on these machines, as a result they reboot after five
145 * minutes. 138 * minutes.
146 * 139 *
147 * NOTE: You may leave the Watchdog function disabled in the SuperMicro 140 * NOTE: You may leave the Watchdog function disabled in the SuperMicro
148 * BIOS to avoid a "boot-race"... This driver will enable watchdog 141 * BIOS to avoid a "boot-race"... This driver will enable watchdog
149 * functionality even if it's disabled in the BIOS once the /dev/watchdog 142 * functionality even if it's disabled in the BIOS once the /dev/watchdog
150 * file is opened. 143 * file is opened.
151 */ 144 */
152 145
153 /* I/O Port's */ 146 /* I/O Port's */
154 #define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */ 147 #define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
155 #define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */ 148 #define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
156 149
157 /* Control Register's */ 150 /* Control Register's */
158 #define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */ 151 #define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
159 #define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */ 152 #define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */
160 153
161 #define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */ 154 #define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */
162 155
163 #define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */ 156 #define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */
164 157
165 #define SM_ENDWATCH 0xAA /* Watchdog lock control page */ 158 #define SM_ENDWATCH 0xAA /* Watchdog lock control page */
166 159
167 #define SM_COUNTMODE 0xf5 /* Watchdog count mode select */ 160 #define SM_COUNTMODE 0xf5 /* Watchdog count mode select */
168 /* (Bit 3: 0 = seconds, 1 = minutes */ 161 /* (Bit 3: 0 = seconds, 1 = minutes */
169 162
170 #define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */ 163 #define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */
171 164
172 #define SM_RESETCONTROL 0xf7 /* Watchdog reset control */ 165 #define SM_RESETCONTROL 0xf7 /* Watchdog reset control */
173 /* Bit 6: timer is reset by kbd interrupt */ 166 /* Bit 6: timer is reset by kbd interrupt */
174 /* Bit 7: timer is reset by mouse interrupt */ 167 /* Bit 7: timer is reset by mouse interrupt */
175 168
176 static void supermicro_new_unlock_watchdog(void) 169 static void supermicro_new_unlock_watchdog(void)
177 { 170 {
178 /* Write 0x87 to port 0x2e twice */ 171 /* Write 0x87 to port 0x2e twice */
179 outb(SM_WATCHPAGE, SM_REGINDEX); 172 outb(SM_WATCHPAGE, SM_REGINDEX);
180 outb(SM_WATCHPAGE, SM_REGINDEX); 173 outb(SM_WATCHPAGE, SM_REGINDEX);
181 /* Switch to watchdog control page */ 174 /* Switch to watchdog control page */
182 outb(SM_CTLPAGESW, SM_REGINDEX); 175 outb(SM_CTLPAGESW, SM_REGINDEX);
183 outb(SM_CTLPAGE, SM_DATAIO); 176 outb(SM_CTLPAGE, SM_DATAIO);
184 } 177 }
185 178
186 static void supermicro_new_lock_watchdog(void) 179 static void supermicro_new_lock_watchdog(void)
187 { 180 {
188 outb(SM_ENDWATCH, SM_REGINDEX); 181 outb(SM_ENDWATCH, SM_REGINDEX);
189 } 182 }
190 183
191 static void supermicro_new_pre_start(unsigned int heartbeat) 184 static void supermicro_new_pre_start(unsigned int heartbeat)
192 { 185 {
193 unsigned int val; 186 unsigned int val;
194 187
195 supermicro_new_unlock_watchdog(); 188 supermicro_new_unlock_watchdog();
196 189
197 /* Watchdog timer setting needs to be in seconds*/ 190 /* Watchdog timer setting needs to be in seconds*/
198 outb(SM_COUNTMODE, SM_REGINDEX); 191 outb(SM_COUNTMODE, SM_REGINDEX);
199 val = inb(SM_DATAIO); 192 val = inb(SM_DATAIO);
200 val &= 0xF7; 193 val &= 0xF7;
201 outb(val, SM_DATAIO); 194 outb(val, SM_DATAIO);
202 195
203 /* Write heartbeat interval to WDOG */ 196 /* Write heartbeat interval to WDOG */
204 outb(SM_WATCHTIMER, SM_REGINDEX); 197 outb(SM_WATCHTIMER, SM_REGINDEX);
205 outb((heartbeat & 255), SM_DATAIO); 198 outb((heartbeat & 255), SM_DATAIO);
206 199
207 /* Make sure keyboard/mouse interrupts don't interfere */ 200 /* Make sure keyboard/mouse interrupts don't interfere */
208 outb(SM_RESETCONTROL, SM_REGINDEX); 201 outb(SM_RESETCONTROL, SM_REGINDEX);
209 val = inb(SM_DATAIO); 202 val = inb(SM_DATAIO);
210 val &= 0x3f; 203 val &= 0x3f;
211 outb(val, SM_DATAIO); 204 outb(val, SM_DATAIO);
212 205
213 /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */ 206 /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */
214 outb(SM_WATCHENABLE, SM_REGINDEX); 207 outb(SM_WATCHENABLE, SM_REGINDEX);
215 val = inb(SM_DATAIO); 208 val = inb(SM_DATAIO);
216 val |= 0x01; 209 val |= 0x01;
217 outb(val, SM_DATAIO); 210 outb(val, SM_DATAIO);
218 211
219 supermicro_new_lock_watchdog(); 212 supermicro_new_lock_watchdog();
220 } 213 }
221 214
222 static void supermicro_new_pre_stop(void) 215 static void supermicro_new_pre_stop(void)
223 { 216 {
224 unsigned int val; 217 unsigned int val;
225 218
226 supermicro_new_unlock_watchdog(); 219 supermicro_new_unlock_watchdog();
227 220
228 /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */ 221 /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */
229 outb(SM_WATCHENABLE, SM_REGINDEX); 222 outb(SM_WATCHENABLE, SM_REGINDEX);
230 val = inb(SM_DATAIO); 223 val = inb(SM_DATAIO);
231 val &= 0xFE; 224 val &= 0xFE;
232 outb(val, SM_DATAIO); 225 outb(val, SM_DATAIO);
233 226
234 supermicro_new_lock_watchdog(); 227 supermicro_new_lock_watchdog();
235 } 228 }
236 229
237 static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat) 230 static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
238 { 231 {
239 supermicro_new_unlock_watchdog(); 232 supermicro_new_unlock_watchdog();
240 233
241 /* reset watchdog timeout to heartveat value */ 234 /* reset watchdog timeout to heartveat value */
242 outb(SM_WATCHTIMER, SM_REGINDEX); 235 outb(SM_WATCHTIMER, SM_REGINDEX);
243 outb((heartbeat & 255), SM_DATAIO); 236 outb((heartbeat & 255), SM_DATAIO);
244 237
245 supermicro_new_lock_watchdog(); 238 supermicro_new_lock_watchdog();
246 } 239 }
247 240
248 /* 241 /*
249 * Vendor Support: 911 242 * Vendor Support: 911
250 * Board: Some Intel ICHx based motherboards 243 * Board: Some Intel ICHx based motherboards
251 * iTCO chipset: ICH7+ 244 * iTCO chipset: ICH7+
252 * 245 *
253 * Some Intel motherboards have a broken BIOS implementation: i.e. 246 * Some Intel motherboards have a broken BIOS implementation: i.e.
254 * the SMI handler clear's the TIMEOUT bit in the TC01_STS register 247 * the SMI handler clear's the TIMEOUT bit in the TC01_STS register
255 * and does not reload the time. Thus the TCO watchdog does not reboot 248 * and does not reload the time. Thus the TCO watchdog does not reboot
256 * the system. 249 * the system.
257 * 250 *
258 * These are the conclusions of Andriy Gapon <avg@icyb.net.ua> after 251 * These are the conclusions of Andriy Gapon <avg@icyb.net.ua> after
259 * debugging: the SMI handler is quite simple - it tests value in 252 * debugging: the SMI handler is quite simple - it tests value in
260 * TCO1_CNT against 0x800, i.e. checks TCO_TMR_HLT. If the bit is set 253 * TCO1_CNT against 0x800, i.e. checks TCO_TMR_HLT. If the bit is set
261 * the handler goes into an infinite loop, apparently to allow the 254 * the handler goes into an infinite loop, apparently to allow the
262 * second timeout and reboot. Otherwise it simply clears TIMEOUT bit 255 * second timeout and reboot. Otherwise it simply clears TIMEOUT bit
263 * in TCO1_STS and that's it. 256 * in TCO1_STS and that's it.
264 * So the logic seems to be reversed, because it is hard to see how 257 * So the logic seems to be reversed, because it is hard to see how
265 * TIMEOUT can get set to 1 and SMI generated when TCO_TMR_HLT is set 258 * TIMEOUT can get set to 1 and SMI generated when TCO_TMR_HLT is set
266 * (other than a transitional effect). 259 * (other than a transitional effect).
267 * 260 *
268 * The only fix found to get the motherboard(s) to reboot is to put 261 * The only fix found to get the motherboard(s) to reboot is to put
269 * the glb_smi_en bit to 0. This is a dirty hack that bypasses the 262 * the glb_smi_en bit to 0. This is a dirty hack that bypasses the
270 * broken code by disabling Global SMI. 263 * broken code by disabling Global SMI.
271 * 264 *
272 * WARNING: globally disabling SMI could possibly lead to dramatic 265 * WARNING: globally disabling SMI could possibly lead to dramatic
273 * problems, especially on laptops! I.e. various ACPI things where 266 * problems, especially on laptops! I.e. various ACPI things where
274 * SMI is used for communication between OS and firmware. 267 * SMI is used for communication between OS and firmware.
275 * 268 *
276 * Don't use this fix if you don't need to!!! 269 * Don't use this fix if you don't need to!!!
277 */ 270 */
278 271
279 static void broken_bios_start(unsigned long acpibase) 272 static void broken_bios_start(unsigned long acpibase)
280 { 273 {
281 unsigned long val32; 274 unsigned long val32;
282 275
283 val32 = inl(SMI_EN); 276 val32 = inl(SMI_EN);
284 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# 277 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI#
285 Bit 0: GBL_SMI_EN -> 0 = No SMI# will be generated by ICH. */ 278 Bit 0: GBL_SMI_EN -> 0 = No SMI# will be generated by ICH. */
286 val32 &= 0xffffdffe; 279 val32 &= 0xffffdffe;
287 outl(val32, SMI_EN); 280 outl(val32, SMI_EN);
288 } 281 }
289 282
290 static void broken_bios_stop(unsigned long acpibase) 283 static void broken_bios_stop(unsigned long acpibase)
291 { 284 {
292 unsigned long val32; 285 unsigned long val32;
293 286
294 val32 = inl(SMI_EN); 287 val32 = inl(SMI_EN);
295 /* Bit 13: TCO_EN -> 1 = Enables TCO logic generating an SMI# 288 /* Bit 13: TCO_EN -> 1 = Enables TCO logic generating an SMI#
296 Bit 0: GBL_SMI_EN -> 1 = Turn global SMI on again. */ 289 Bit 0: GBL_SMI_EN -> 1 = Turn global SMI on again. */
297 val32 |= 0x00002001; 290 val32 |= 0x00002001;
298 outl(val32, SMI_EN); 291 outl(val32, SMI_EN);
299 } 292 }
300 293
301 /* 294 /*
302 * Generic Support Functions 295 * Generic Support Functions
303 */ 296 */
304 297
305 void iTCO_vendor_pre_start(unsigned long acpibase, 298 void iTCO_vendor_pre_start(unsigned long acpibase,
306 unsigned int heartbeat) 299 unsigned int heartbeat)
307 { 300 {
308 switch (vendorsupport) { 301 switch (vendorsupport) {
309 case SUPERMICRO_OLD_BOARD: 302 case SUPERMICRO_OLD_BOARD:
310 supermicro_old_pre_start(acpibase); 303 supermicro_old_pre_start(acpibase);
311 break; 304 break;
312 case SUPERMICRO_NEW_BOARD: 305 case SUPERMICRO_NEW_BOARD:
313 supermicro_new_pre_start(heartbeat); 306 supermicro_new_pre_start(heartbeat);
314 break; 307 break;
315 case BROKEN_BIOS: 308 case BROKEN_BIOS:
316 broken_bios_start(acpibase); 309 broken_bios_start(acpibase);
317 break; 310 break;
318 } 311 }
319 } 312 }
320 EXPORT_SYMBOL(iTCO_vendor_pre_start); 313 EXPORT_SYMBOL(iTCO_vendor_pre_start);
321 314
322 void iTCO_vendor_pre_stop(unsigned long acpibase) 315 void iTCO_vendor_pre_stop(unsigned long acpibase)
323 { 316 {
324 switch (vendorsupport) { 317 switch (vendorsupport) {
325 case SUPERMICRO_OLD_BOARD: 318 case SUPERMICRO_OLD_BOARD:
326 supermicro_old_pre_stop(acpibase); 319 supermicro_old_pre_stop(acpibase);
327 break; 320 break;
328 case SUPERMICRO_NEW_BOARD: 321 case SUPERMICRO_NEW_BOARD:
329 supermicro_new_pre_stop(); 322 supermicro_new_pre_stop();
330 break; 323 break;
331 case BROKEN_BIOS: 324 case BROKEN_BIOS:
332 broken_bios_stop(acpibase); 325 broken_bios_stop(acpibase);
333 break; 326 break;
334 } 327 }
335 } 328 }
336 EXPORT_SYMBOL(iTCO_vendor_pre_stop); 329 EXPORT_SYMBOL(iTCO_vendor_pre_stop);
337 330
338 void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat) 331 void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
339 { 332 {
340 if (vendorsupport == SUPERMICRO_OLD_BOARD) 333 if (vendorsupport == SUPERMICRO_NEW_BOARD)
341 supermicro_old_pre_keepalive(acpibase);
342 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
343 supermicro_new_pre_set_heartbeat(heartbeat); 334 supermicro_new_pre_set_heartbeat(heartbeat);
344 } 335 }
345 EXPORT_SYMBOL(iTCO_vendor_pre_keepalive); 336 EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
346 337
347 void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat) 338 void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat)
348 { 339 {
349 if (vendorsupport == SUPERMICRO_NEW_BOARD) 340 if (vendorsupport == SUPERMICRO_NEW_BOARD)
350 supermicro_new_pre_set_heartbeat(heartbeat); 341 supermicro_new_pre_set_heartbeat(heartbeat);
351 } 342 }
352 EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat); 343 EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
353 344
354 int iTCO_vendor_check_noreboot_on(void) 345 int iTCO_vendor_check_noreboot_on(void)
355 { 346 {
356 switch (vendorsupport) { 347 switch (vendorsupport) {
357 case SUPERMICRO_OLD_BOARD: 348 case SUPERMICRO_OLD_BOARD:
358 return 0; 349 return 0;
359 default: 350 default:
360 return 1; 351 return 1;
361 } 352 }
362 } 353 }
363 EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on); 354 EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
364 355
365 static int __init iTCO_vendor_init_module(void) 356 static int __init iTCO_vendor_init_module(void)
366 { 357 {
367 printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport); 358 printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
368 return 0; 359 return 0;
369 } 360 }
370 361
371 static void __exit iTCO_vendor_exit_module(void) 362 static void __exit iTCO_vendor_exit_module(void)
372 { 363 {
373 printk(KERN_INFO PFX "Module Unloaded\n"); 364 printk(KERN_INFO PFX "Module Unloaded\n");
374 } 365 }
375 366
376 module_init(iTCO_vendor_init_module); 367 module_init(iTCO_vendor_init_module);
377 module_exit(iTCO_vendor_exit_module); 368 module_exit(iTCO_vendor_exit_module);
378 369
379 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, " 370 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, "
380 "R. Seretny <lkpatches@paypc.com>"); 371 "R. Seretny <lkpatches@paypc.com>");
381 MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support"); 372 MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
382 MODULE_VERSION(DRV_VERSION); 373 MODULE_VERSION(DRV_VERSION);
383 MODULE_LICENSE("GPL"); 374 MODULE_LICENSE("GPL");
384 375
385 376
drivers/watchdog/iTCO_wdt.c
1 /* 1 /*
2 * intel TCO Watchdog Driver 2 * intel TCO Watchdog Driver
3 * 3 *
4 * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. 4 * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version. 9 * 2 of the License, or (at your option) any later version.
10 * 10 *
11 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor 11 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
12 * provide warranty for any of this software. This material is 12 * provide warranty for any of this software. This material is
13 * provided "AS-IS" and at no charge. 13 * provided "AS-IS" and at no charge.
14 * 14 *
15 * The TCO watchdog is implemented in the following I/O controller hubs: 15 * The TCO watchdog is implemented in the following I/O controller hubs:
16 * (See the intel documentation on http://developer.intel.com.) 16 * (See the intel documentation on http://developer.intel.com.)
17 * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO) 17 * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
18 * document number 290687-002, 298242-027: 82801BA (ICH2) 18 * document number 290687-002, 298242-027: 82801BA (ICH2)
19 * document number 290733-003, 290739-013: 82801CA (ICH3-S) 19 * document number 290733-003, 290739-013: 82801CA (ICH3-S)
20 * document number 290716-001, 290718-007: 82801CAM (ICH3-M) 20 * document number 290716-001, 290718-007: 82801CAM (ICH3-M)
21 * document number 290744-001, 290745-025: 82801DB (ICH4) 21 * document number 290744-001, 290745-025: 82801DB (ICH4)
22 * document number 252337-001, 252663-008: 82801DBM (ICH4-M) 22 * document number 252337-001, 252663-008: 82801DBM (ICH4-M)
23 * document number 273599-001, 273645-002: 82801E (C-ICH) 23 * document number 273599-001, 273645-002: 82801E (C-ICH)
24 * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R) 24 * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R)
25 * document number 300641-004, 300884-013: 6300ESB 25 * document number 300641-004, 300884-013: 6300ESB
26 * document number 301473-002, 301474-026: 82801F (ICH6) 26 * document number 301473-002, 301474-026: 82801F (ICH6)
27 * document number 313082-001, 313075-006: 631xESB, 632xESB 27 * document number 313082-001, 313075-006: 631xESB, 632xESB
28 * document number 307013-003, 307014-024: 82801G (ICH7) 28 * document number 307013-003, 307014-024: 82801G (ICH7)
29 * document number 313056-003, 313057-017: 82801H (ICH8) 29 * document number 313056-003, 313057-017: 82801H (ICH8)
30 * document number 316972-004, 316973-012: 82801I (ICH9) 30 * document number 316972-004, 316973-012: 82801I (ICH9)
31 * document number 319973-002, 319974-002: 82801J (ICH10) 31 * document number 319973-002, 319974-002: 82801J (ICH10)
32 * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) 32 * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
33 * document number 320066-003, 320257-008: EP80597 (IICH) 33 * document number 320066-003, 320257-008: EP80597 (IICH)
34 * document number TBD : Cougar Point (CPT) 34 * document number TBD : Cougar Point (CPT)
35 */ 35 */
36 36
37 /* 37 /*
38 * Includes, defines, variables, module parameters, ... 38 * Includes, defines, variables, module parameters, ...
39 */ 39 */
40 40
41 /* Module and version information */ 41 /* Module and version information */
42 #define DRV_NAME "iTCO_wdt" 42 #define DRV_NAME "iTCO_wdt"
43 #define DRV_VERSION "1.05" 43 #define DRV_VERSION "1.06"
44 #define PFX DRV_NAME ": " 44 #define PFX DRV_NAME ": "
45 45
46 /* Includes */ 46 /* Includes */
47 #include <linux/module.h> /* For module specific items */ 47 #include <linux/module.h> /* For module specific items */
48 #include <linux/moduleparam.h> /* For new moduleparam's */ 48 #include <linux/moduleparam.h> /* For new moduleparam's */
49 #include <linux/types.h> /* For standard types (like size_t) */ 49 #include <linux/types.h> /* For standard types (like size_t) */
50 #include <linux/errno.h> /* For the -ENODEV/... values */ 50 #include <linux/errno.h> /* For the -ENODEV/... values */
51 #include <linux/kernel.h> /* For printk/panic/... */ 51 #include <linux/kernel.h> /* For printk/panic/... */
52 #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV 52 #include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV
53 (WATCHDOG_MINOR) */ 53 (WATCHDOG_MINOR) */
54 #include <linux/watchdog.h> /* For the watchdog specific items */ 54 #include <linux/watchdog.h> /* For the watchdog specific items */
55 #include <linux/init.h> /* For __init/__exit/... */ 55 #include <linux/init.h> /* For __init/__exit/... */
56 #include <linux/fs.h> /* For file operations */ 56 #include <linux/fs.h> /* For file operations */
57 #include <linux/platform_device.h> /* For platform_driver framework */ 57 #include <linux/platform_device.h> /* For platform_driver framework */
58 #include <linux/pci.h> /* For pci functions */ 58 #include <linux/pci.h> /* For pci functions */
59 #include <linux/ioport.h> /* For io-port access */ 59 #include <linux/ioport.h> /* For io-port access */
60 #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ 60 #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
61 #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ 61 #include <linux/uaccess.h> /* For copy_to_user/put_user/... */
62 #include <linux/io.h> /* For inb/outb/... */ 62 #include <linux/io.h> /* For inb/outb/... */
63 63
64 #include "iTCO_vendor.h" 64 #include "iTCO_vendor.h"
65 65
66 /* TCO related info */ 66 /* TCO related info */
67 enum iTCO_chipsets { 67 enum iTCO_chipsets {
68 TCO_ICH = 0, /* ICH */ 68 TCO_ICH = 0, /* ICH */
69 TCO_ICH0, /* ICH0 */ 69 TCO_ICH0, /* ICH0 */
70 TCO_ICH2, /* ICH2 */ 70 TCO_ICH2, /* ICH2 */
71 TCO_ICH2M, /* ICH2-M */ 71 TCO_ICH2M, /* ICH2-M */
72 TCO_ICH3, /* ICH3-S */ 72 TCO_ICH3, /* ICH3-S */
73 TCO_ICH3M, /* ICH3-M */ 73 TCO_ICH3M, /* ICH3-M */
74 TCO_ICH4, /* ICH4 */ 74 TCO_ICH4, /* ICH4 */
75 TCO_ICH4M, /* ICH4-M */ 75 TCO_ICH4M, /* ICH4-M */
76 TCO_CICH, /* C-ICH */ 76 TCO_CICH, /* C-ICH */
77 TCO_ICH5, /* ICH5 & ICH5R */ 77 TCO_ICH5, /* ICH5 & ICH5R */
78 TCO_6300ESB, /* 6300ESB */ 78 TCO_6300ESB, /* 6300ESB */
79 TCO_ICH6, /* ICH6 & ICH6R */ 79 TCO_ICH6, /* ICH6 & ICH6R */
80 TCO_ICH6M, /* ICH6-M */ 80 TCO_ICH6M, /* ICH6-M */
81 TCO_ICH6W, /* ICH6W & ICH6RW */ 81 TCO_ICH6W, /* ICH6W & ICH6RW */
82 TCO_631XESB, /* 631xESB/632xESB */ 82 TCO_631XESB, /* 631xESB/632xESB */
83 TCO_ICH7, /* ICH7 & ICH7R */ 83 TCO_ICH7, /* ICH7 & ICH7R */
84 TCO_ICH7DH, /* ICH7DH */ 84 TCO_ICH7DH, /* ICH7DH */
85 TCO_ICH7M, /* ICH7-M & ICH7-U */ 85 TCO_ICH7M, /* ICH7-M & ICH7-U */
86 TCO_ICH7MDH, /* ICH7-M DH */ 86 TCO_ICH7MDH, /* ICH7-M DH */
87 TCO_ICH8, /* ICH8 & ICH8R */ 87 TCO_ICH8, /* ICH8 & ICH8R */
88 TCO_ICH8DH, /* ICH8DH */ 88 TCO_ICH8DH, /* ICH8DH */
89 TCO_ICH8DO, /* ICH8DO */ 89 TCO_ICH8DO, /* ICH8DO */
90 TCO_ICH8M, /* ICH8M */ 90 TCO_ICH8M, /* ICH8M */
91 TCO_ICH8ME, /* ICH8M-E */ 91 TCO_ICH8ME, /* ICH8M-E */
92 TCO_ICH9, /* ICH9 */ 92 TCO_ICH9, /* ICH9 */
93 TCO_ICH9R, /* ICH9R */ 93 TCO_ICH9R, /* ICH9R */
94 TCO_ICH9DH, /* ICH9DH */ 94 TCO_ICH9DH, /* ICH9DH */
95 TCO_ICH9DO, /* ICH9DO */ 95 TCO_ICH9DO, /* ICH9DO */
96 TCO_ICH9M, /* ICH9M */ 96 TCO_ICH9M, /* ICH9M */
97 TCO_ICH9ME, /* ICH9M-E */ 97 TCO_ICH9ME, /* ICH9M-E */
98 TCO_ICH10, /* ICH10 */ 98 TCO_ICH10, /* ICH10 */
99 TCO_ICH10R, /* ICH10R */ 99 TCO_ICH10R, /* ICH10R */
100 TCO_ICH10D, /* ICH10D */ 100 TCO_ICH10D, /* ICH10D */
101 TCO_ICH10DO, /* ICH10DO */ 101 TCO_ICH10DO, /* ICH10DO */
102 TCO_PCH, /* PCH Desktop Full Featured */ 102 TCO_PCH, /* PCH Desktop Full Featured */
103 TCO_PCHM, /* PCH Mobile Full Featured */ 103 TCO_PCHM, /* PCH Mobile Full Featured */
104 TCO_P55, /* P55 */ 104 TCO_P55, /* P55 */
105 TCO_PM55, /* PM55 */ 105 TCO_PM55, /* PM55 */
106 TCO_H55, /* H55 */ 106 TCO_H55, /* H55 */
107 TCO_QM57, /* QM57 */ 107 TCO_QM57, /* QM57 */
108 TCO_H57, /* H57 */ 108 TCO_H57, /* H57 */
109 TCO_HM55, /* HM55 */ 109 TCO_HM55, /* HM55 */
110 TCO_Q57, /* Q57 */ 110 TCO_Q57, /* Q57 */
111 TCO_HM57, /* HM57 */ 111 TCO_HM57, /* HM57 */
112 TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */ 112 TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */
113 TCO_QS57, /* QS57 */ 113 TCO_QS57, /* QS57 */
114 TCO_3400, /* 3400 */ 114 TCO_3400, /* 3400 */
115 TCO_3420, /* 3420 */ 115 TCO_3420, /* 3420 */
116 TCO_3450, /* 3450 */ 116 TCO_3450, /* 3450 */
117 TCO_EP80579, /* EP80579 */ 117 TCO_EP80579, /* EP80579 */
118 TCO_CPT1, /* Cougar Point */ 118 TCO_CPT1, /* Cougar Point */
119 TCO_CPT2, /* Cougar Point Desktop */ 119 TCO_CPT2, /* Cougar Point Desktop */
120 TCO_CPT3, /* Cougar Point Mobile */ 120 TCO_CPT3, /* Cougar Point Mobile */
121 TCO_CPT4, /* Cougar Point */ 121 TCO_CPT4, /* Cougar Point */
122 TCO_CPT5, /* Cougar Point */ 122 TCO_CPT5, /* Cougar Point */
123 TCO_CPT6, /* Cougar Point */ 123 TCO_CPT6, /* Cougar Point */
124 TCO_CPT7, /* Cougar Point */ 124 TCO_CPT7, /* Cougar Point */
125 TCO_CPT8, /* Cougar Point */ 125 TCO_CPT8, /* Cougar Point */
126 TCO_CPT9, /* Cougar Point */ 126 TCO_CPT9, /* Cougar Point */
127 TCO_CPT10, /* Cougar Point */ 127 TCO_CPT10, /* Cougar Point */
128 TCO_CPT11, /* Cougar Point */ 128 TCO_CPT11, /* Cougar Point */
129 TCO_CPT12, /* Cougar Point */ 129 TCO_CPT12, /* Cougar Point */
130 TCO_CPT13, /* Cougar Point */ 130 TCO_CPT13, /* Cougar Point */
131 TCO_CPT14, /* Cougar Point */ 131 TCO_CPT14, /* Cougar Point */
132 TCO_CPT15, /* Cougar Point */ 132 TCO_CPT15, /* Cougar Point */
133 TCO_CPT16, /* Cougar Point */ 133 TCO_CPT16, /* Cougar Point */
134 TCO_CPT17, /* Cougar Point */ 134 TCO_CPT17, /* Cougar Point */
135 TCO_CPT18, /* Cougar Point */ 135 TCO_CPT18, /* Cougar Point */
136 TCO_CPT19, /* Cougar Point */ 136 TCO_CPT19, /* Cougar Point */
137 TCO_CPT20, /* Cougar Point */ 137 TCO_CPT20, /* Cougar Point */
138 TCO_CPT21, /* Cougar Point */ 138 TCO_CPT21, /* Cougar Point */
139 TCO_CPT22, /* Cougar Point */ 139 TCO_CPT22, /* Cougar Point */
140 TCO_CPT23, /* Cougar Point */ 140 TCO_CPT23, /* Cougar Point */
141 TCO_CPT24, /* Cougar Point */ 141 TCO_CPT24, /* Cougar Point */
142 TCO_CPT25, /* Cougar Point */ 142 TCO_CPT25, /* Cougar Point */
143 TCO_CPT26, /* Cougar Point */ 143 TCO_CPT26, /* Cougar Point */
144 TCO_CPT27, /* Cougar Point */ 144 TCO_CPT27, /* Cougar Point */
145 TCO_CPT28, /* Cougar Point */ 145 TCO_CPT28, /* Cougar Point */
146 TCO_CPT29, /* Cougar Point */ 146 TCO_CPT29, /* Cougar Point */
147 TCO_CPT30, /* Cougar Point */ 147 TCO_CPT30, /* Cougar Point */
148 TCO_CPT31, /* Cougar Point */ 148 TCO_CPT31, /* Cougar Point */
149 }; 149 };
150 150
151 static struct { 151 static struct {
152 char *name; 152 char *name;
153 unsigned int iTCO_version; 153 unsigned int iTCO_version;
154 } iTCO_chipset_info[] __devinitdata = { 154 } iTCO_chipset_info[] __devinitdata = {
155 {"ICH", 1}, 155 {"ICH", 1},
156 {"ICH0", 1}, 156 {"ICH0", 1},
157 {"ICH2", 1}, 157 {"ICH2", 1},
158 {"ICH2-M", 1}, 158 {"ICH2-M", 1},
159 {"ICH3-S", 1}, 159 {"ICH3-S", 1},
160 {"ICH3-M", 1}, 160 {"ICH3-M", 1},
161 {"ICH4", 1}, 161 {"ICH4", 1},
162 {"ICH4-M", 1}, 162 {"ICH4-M", 1},
163 {"C-ICH", 1}, 163 {"C-ICH", 1},
164 {"ICH5 or ICH5R", 1}, 164 {"ICH5 or ICH5R", 1},
165 {"6300ESB", 1}, 165 {"6300ESB", 1},
166 {"ICH6 or ICH6R", 2}, 166 {"ICH6 or ICH6R", 2},
167 {"ICH6-M", 2}, 167 {"ICH6-M", 2},
168 {"ICH6W or ICH6RW", 2}, 168 {"ICH6W or ICH6RW", 2},
169 {"631xESB/632xESB", 2}, 169 {"631xESB/632xESB", 2},
170 {"ICH7 or ICH7R", 2}, 170 {"ICH7 or ICH7R", 2},
171 {"ICH7DH", 2}, 171 {"ICH7DH", 2},
172 {"ICH7-M or ICH7-U", 2}, 172 {"ICH7-M or ICH7-U", 2},
173 {"ICH7-M DH", 2}, 173 {"ICH7-M DH", 2},
174 {"ICH8 or ICH8R", 2}, 174 {"ICH8 or ICH8R", 2},
175 {"ICH8DH", 2}, 175 {"ICH8DH", 2},
176 {"ICH8DO", 2}, 176 {"ICH8DO", 2},
177 {"ICH8M", 2}, 177 {"ICH8M", 2},
178 {"ICH8M-E", 2}, 178 {"ICH8M-E", 2},
179 {"ICH9", 2}, 179 {"ICH9", 2},
180 {"ICH9R", 2}, 180 {"ICH9R", 2},
181 {"ICH9DH", 2}, 181 {"ICH9DH", 2},
182 {"ICH9DO", 2}, 182 {"ICH9DO", 2},
183 {"ICH9M", 2}, 183 {"ICH9M", 2},
184 {"ICH9M-E", 2}, 184 {"ICH9M-E", 2},
185 {"ICH10", 2}, 185 {"ICH10", 2},
186 {"ICH10R", 2}, 186 {"ICH10R", 2},
187 {"ICH10D", 2}, 187 {"ICH10D", 2},
188 {"ICH10DO", 2}, 188 {"ICH10DO", 2},
189 {"PCH Desktop Full Featured", 2}, 189 {"PCH Desktop Full Featured", 2},
190 {"PCH Mobile Full Featured", 2}, 190 {"PCH Mobile Full Featured", 2},
191 {"P55", 2}, 191 {"P55", 2},
192 {"PM55", 2}, 192 {"PM55", 2},
193 {"H55", 2}, 193 {"H55", 2},
194 {"QM57", 2}, 194 {"QM57", 2},
195 {"H57", 2}, 195 {"H57", 2},
196 {"HM55", 2}, 196 {"HM55", 2},
197 {"Q57", 2}, 197 {"Q57", 2},
198 {"HM57", 2}, 198 {"HM57", 2},
199 {"PCH Mobile SFF Full Featured", 2}, 199 {"PCH Mobile SFF Full Featured", 2},
200 {"QS57", 2}, 200 {"QS57", 2},
201 {"3400", 2}, 201 {"3400", 2},
202 {"3420", 2}, 202 {"3420", 2},
203 {"3450", 2}, 203 {"3450", 2},
204 {"EP80579", 2}, 204 {"EP80579", 2},
205 {"Cougar Point", 2}, 205 {"Cougar Point", 2},
206 {"Cougar Point", 2}, 206 {"Cougar Point", 2},
207 {"Cougar Point", 2}, 207 {"Cougar Point", 2},
208 {"Cougar Point", 2}, 208 {"Cougar Point", 2},
209 {"Cougar Point", 2}, 209 {"Cougar Point", 2},
210 {"Cougar Point", 2}, 210 {"Cougar Point", 2},
211 {"Cougar Point", 2}, 211 {"Cougar Point", 2},
212 {"Cougar Point", 2}, 212 {"Cougar Point", 2},
213 {"Cougar Point", 2}, 213 {"Cougar Point", 2},
214 {"Cougar Point", 2}, 214 {"Cougar Point", 2},
215 {"Cougar Point", 2}, 215 {"Cougar Point", 2},
216 {"Cougar Point", 2}, 216 {"Cougar Point", 2},
217 {"Cougar Point", 2}, 217 {"Cougar Point", 2},
218 {"Cougar Point", 2}, 218 {"Cougar Point", 2},
219 {"Cougar Point", 2}, 219 {"Cougar Point", 2},
220 {"Cougar Point", 2}, 220 {"Cougar Point", 2},
221 {"Cougar Point", 2}, 221 {"Cougar Point", 2},
222 {"Cougar Point", 2}, 222 {"Cougar Point", 2},
223 {"Cougar Point", 2}, 223 {"Cougar Point", 2},
224 {"Cougar Point", 2}, 224 {"Cougar Point", 2},
225 {"Cougar Point", 2}, 225 {"Cougar Point", 2},
226 {"Cougar Point", 2}, 226 {"Cougar Point", 2},
227 {"Cougar Point", 2}, 227 {"Cougar Point", 2},
228 {"Cougar Point", 2}, 228 {"Cougar Point", 2},
229 {"Cougar Point", 2}, 229 {"Cougar Point", 2},
230 {"Cougar Point", 2}, 230 {"Cougar Point", 2},
231 {"Cougar Point", 2}, 231 {"Cougar Point", 2},
232 {"Cougar Point", 2}, 232 {"Cougar Point", 2},
233 {"Cougar Point", 2}, 233 {"Cougar Point", 2},
234 {"Cougar Point", 2}, 234 {"Cougar Point", 2},
235 {"Cougar Point", 2}, 235 {"Cougar Point", 2},
236 {NULL, 0} 236 {NULL, 0}
237 }; 237 };
238 238
239 #define ITCO_PCI_DEVICE(dev, data) \ 239 #define ITCO_PCI_DEVICE(dev, data) \
240 .vendor = PCI_VENDOR_ID_INTEL, \ 240 .vendor = PCI_VENDOR_ID_INTEL, \
241 .device = dev, \ 241 .device = dev, \
242 .subvendor = PCI_ANY_ID, \ 242 .subvendor = PCI_ANY_ID, \
243 .subdevice = PCI_ANY_ID, \ 243 .subdevice = PCI_ANY_ID, \
244 .class = 0, \ 244 .class = 0, \
245 .class_mask = 0, \ 245 .class_mask = 0, \
246 .driver_data = data 246 .driver_data = data
247 247
248 /* 248 /*
249 * This data only exists for exporting the supported PCI ids 249 * This data only exists for exporting the supported PCI ids
250 * via MODULE_DEVICE_TABLE. We do not actually register a 250 * via MODULE_DEVICE_TABLE. We do not actually register a
251 * pci_driver, because the I/O Controller Hub has also other 251 * pci_driver, because the I/O Controller Hub has also other
252 * functions that probably will be registered by other drivers. 252 * functions that probably will be registered by other drivers.
253 */ 253 */
254 static struct pci_device_id iTCO_wdt_pci_tbl[] = { 254 static struct pci_device_id iTCO_wdt_pci_tbl[] = {
255 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)}, 255 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)},
256 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)}, 256 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)},
257 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)}, 257 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)},
258 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M)}, 258 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M)},
259 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3)}, 259 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3)},
260 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M)}, 260 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M)},
261 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4)}, 261 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4)},
262 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M)}, 262 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M)},
263 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH)}, 263 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH)},
264 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5)}, 264 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5)},
265 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)}, 265 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)},
266 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6)}, 266 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6)},
267 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M)}, 267 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M)},
268 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W)}, 268 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W)},
269 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)}, 269 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)},
270 { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)}, 270 { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)},
271 { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)}, 271 { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)},
272 { ITCO_PCI_DEVICE(0x2673, TCO_631XESB)}, 272 { ITCO_PCI_DEVICE(0x2673, TCO_631XESB)},
273 { ITCO_PCI_DEVICE(0x2674, TCO_631XESB)}, 273 { ITCO_PCI_DEVICE(0x2674, TCO_631XESB)},
274 { ITCO_PCI_DEVICE(0x2675, TCO_631XESB)}, 274 { ITCO_PCI_DEVICE(0x2675, TCO_631XESB)},
275 { ITCO_PCI_DEVICE(0x2676, TCO_631XESB)}, 275 { ITCO_PCI_DEVICE(0x2676, TCO_631XESB)},
276 { ITCO_PCI_DEVICE(0x2677, TCO_631XESB)}, 276 { ITCO_PCI_DEVICE(0x2677, TCO_631XESB)},
277 { ITCO_PCI_DEVICE(0x2678, TCO_631XESB)}, 277 { ITCO_PCI_DEVICE(0x2678, TCO_631XESB)},
278 { ITCO_PCI_DEVICE(0x2679, TCO_631XESB)}, 278 { ITCO_PCI_DEVICE(0x2679, TCO_631XESB)},
279 { ITCO_PCI_DEVICE(0x267a, TCO_631XESB)}, 279 { ITCO_PCI_DEVICE(0x267a, TCO_631XESB)},
280 { ITCO_PCI_DEVICE(0x267b, TCO_631XESB)}, 280 { ITCO_PCI_DEVICE(0x267b, TCO_631XESB)},
281 { ITCO_PCI_DEVICE(0x267c, TCO_631XESB)}, 281 { ITCO_PCI_DEVICE(0x267c, TCO_631XESB)},
282 { ITCO_PCI_DEVICE(0x267d, TCO_631XESB)}, 282 { ITCO_PCI_DEVICE(0x267d, TCO_631XESB)},
283 { ITCO_PCI_DEVICE(0x267e, TCO_631XESB)}, 283 { ITCO_PCI_DEVICE(0x267e, TCO_631XESB)},
284 { ITCO_PCI_DEVICE(0x267f, TCO_631XESB)}, 284 { ITCO_PCI_DEVICE(0x267f, TCO_631XESB)},
285 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7)}, 285 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7)},
286 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)}, 286 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)},
287 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)}, 287 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)},
288 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, 288 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)},
289 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)}, 289 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)},
290 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)}, 290 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)},
291 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)}, 291 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)},
292 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M)}, 292 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M)},
293 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME)}, 293 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME)},
294 { ITCO_PCI_DEVICE(0x2918, TCO_ICH9)}, 294 { ITCO_PCI_DEVICE(0x2918, TCO_ICH9)},
295 { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R)}, 295 { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R)},
296 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH)}, 296 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH)},
297 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO)}, 297 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO)},
298 { ITCO_PCI_DEVICE(0x2919, TCO_ICH9M)}, 298 { ITCO_PCI_DEVICE(0x2919, TCO_ICH9M)},
299 { ITCO_PCI_DEVICE(0x2917, TCO_ICH9ME)}, 299 { ITCO_PCI_DEVICE(0x2917, TCO_ICH9ME)},
300 { ITCO_PCI_DEVICE(0x3a18, TCO_ICH10)}, 300 { ITCO_PCI_DEVICE(0x3a18, TCO_ICH10)},
301 { ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)}, 301 { ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)},
302 { ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)}, 302 { ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)},
303 { ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)}, 303 { ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)},
304 { ITCO_PCI_DEVICE(0x3b00, TCO_PCH)}, 304 { ITCO_PCI_DEVICE(0x3b00, TCO_PCH)},
305 { ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)}, 305 { ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)},
306 { ITCO_PCI_DEVICE(0x3b02, TCO_P55)}, 306 { ITCO_PCI_DEVICE(0x3b02, TCO_P55)},
307 { ITCO_PCI_DEVICE(0x3b03, TCO_PM55)}, 307 { ITCO_PCI_DEVICE(0x3b03, TCO_PM55)},
308 { ITCO_PCI_DEVICE(0x3b06, TCO_H55)}, 308 { ITCO_PCI_DEVICE(0x3b06, TCO_H55)},
309 { ITCO_PCI_DEVICE(0x3b07, TCO_QM57)}, 309 { ITCO_PCI_DEVICE(0x3b07, TCO_QM57)},
310 { ITCO_PCI_DEVICE(0x3b08, TCO_H57)}, 310 { ITCO_PCI_DEVICE(0x3b08, TCO_H57)},
311 { ITCO_PCI_DEVICE(0x3b09, TCO_HM55)}, 311 { ITCO_PCI_DEVICE(0x3b09, TCO_HM55)},
312 { ITCO_PCI_DEVICE(0x3b0a, TCO_Q57)}, 312 { ITCO_PCI_DEVICE(0x3b0a, TCO_Q57)},
313 { ITCO_PCI_DEVICE(0x3b0b, TCO_HM57)}, 313 { ITCO_PCI_DEVICE(0x3b0b, TCO_HM57)},
314 { ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)}, 314 { ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)},
315 { ITCO_PCI_DEVICE(0x3b0f, TCO_QS57)}, 315 { ITCO_PCI_DEVICE(0x3b0f, TCO_QS57)},
316 { ITCO_PCI_DEVICE(0x3b12, TCO_3400)}, 316 { ITCO_PCI_DEVICE(0x3b12, TCO_3400)},
317 { ITCO_PCI_DEVICE(0x3b14, TCO_3420)}, 317 { ITCO_PCI_DEVICE(0x3b14, TCO_3420)},
318 { ITCO_PCI_DEVICE(0x3b16, TCO_3450)}, 318 { ITCO_PCI_DEVICE(0x3b16, TCO_3450)},
319 { ITCO_PCI_DEVICE(0x5031, TCO_EP80579)}, 319 { ITCO_PCI_DEVICE(0x5031, TCO_EP80579)},
320 { ITCO_PCI_DEVICE(0x1c41, TCO_CPT1)}, 320 { ITCO_PCI_DEVICE(0x1c41, TCO_CPT1)},
321 { ITCO_PCI_DEVICE(0x1c42, TCO_CPT2)}, 321 { ITCO_PCI_DEVICE(0x1c42, TCO_CPT2)},
322 { ITCO_PCI_DEVICE(0x1c43, TCO_CPT3)}, 322 { ITCO_PCI_DEVICE(0x1c43, TCO_CPT3)},
323 { ITCO_PCI_DEVICE(0x1c44, TCO_CPT4)}, 323 { ITCO_PCI_DEVICE(0x1c44, TCO_CPT4)},
324 { ITCO_PCI_DEVICE(0x1c45, TCO_CPT5)}, 324 { ITCO_PCI_DEVICE(0x1c45, TCO_CPT5)},
325 { ITCO_PCI_DEVICE(0x1c46, TCO_CPT6)}, 325 { ITCO_PCI_DEVICE(0x1c46, TCO_CPT6)},
326 { ITCO_PCI_DEVICE(0x1c47, TCO_CPT7)}, 326 { ITCO_PCI_DEVICE(0x1c47, TCO_CPT7)},
327 { ITCO_PCI_DEVICE(0x1c48, TCO_CPT8)}, 327 { ITCO_PCI_DEVICE(0x1c48, TCO_CPT8)},
328 { ITCO_PCI_DEVICE(0x1c49, TCO_CPT9)}, 328 { ITCO_PCI_DEVICE(0x1c49, TCO_CPT9)},
329 { ITCO_PCI_DEVICE(0x1c4a, TCO_CPT10)}, 329 { ITCO_PCI_DEVICE(0x1c4a, TCO_CPT10)},
330 { ITCO_PCI_DEVICE(0x1c4b, TCO_CPT11)}, 330 { ITCO_PCI_DEVICE(0x1c4b, TCO_CPT11)},
331 { ITCO_PCI_DEVICE(0x1c4c, TCO_CPT12)}, 331 { ITCO_PCI_DEVICE(0x1c4c, TCO_CPT12)},
332 { ITCO_PCI_DEVICE(0x1c4d, TCO_CPT13)}, 332 { ITCO_PCI_DEVICE(0x1c4d, TCO_CPT13)},
333 { ITCO_PCI_DEVICE(0x1c4e, TCO_CPT14)}, 333 { ITCO_PCI_DEVICE(0x1c4e, TCO_CPT14)},
334 { ITCO_PCI_DEVICE(0x1c4f, TCO_CPT15)}, 334 { ITCO_PCI_DEVICE(0x1c4f, TCO_CPT15)},
335 { ITCO_PCI_DEVICE(0x1c50, TCO_CPT16)}, 335 { ITCO_PCI_DEVICE(0x1c50, TCO_CPT16)},
336 { ITCO_PCI_DEVICE(0x1c51, TCO_CPT17)}, 336 { ITCO_PCI_DEVICE(0x1c51, TCO_CPT17)},
337 { ITCO_PCI_DEVICE(0x1c52, TCO_CPT18)}, 337 { ITCO_PCI_DEVICE(0x1c52, TCO_CPT18)},
338 { ITCO_PCI_DEVICE(0x1c53, TCO_CPT19)}, 338 { ITCO_PCI_DEVICE(0x1c53, TCO_CPT19)},
339 { ITCO_PCI_DEVICE(0x1c54, TCO_CPT20)}, 339 { ITCO_PCI_DEVICE(0x1c54, TCO_CPT20)},
340 { ITCO_PCI_DEVICE(0x1c55, TCO_CPT21)}, 340 { ITCO_PCI_DEVICE(0x1c55, TCO_CPT21)},
341 { ITCO_PCI_DEVICE(0x1c56, TCO_CPT22)}, 341 { ITCO_PCI_DEVICE(0x1c56, TCO_CPT22)},
342 { ITCO_PCI_DEVICE(0x1c57, TCO_CPT23)}, 342 { ITCO_PCI_DEVICE(0x1c57, TCO_CPT23)},
343 { ITCO_PCI_DEVICE(0x1c58, TCO_CPT24)}, 343 { ITCO_PCI_DEVICE(0x1c58, TCO_CPT24)},
344 { ITCO_PCI_DEVICE(0x1c59, TCO_CPT25)}, 344 { ITCO_PCI_DEVICE(0x1c59, TCO_CPT25)},
345 { ITCO_PCI_DEVICE(0x1c5a, TCO_CPT26)}, 345 { ITCO_PCI_DEVICE(0x1c5a, TCO_CPT26)},
346 { ITCO_PCI_DEVICE(0x1c5b, TCO_CPT27)}, 346 { ITCO_PCI_DEVICE(0x1c5b, TCO_CPT27)},
347 { ITCO_PCI_DEVICE(0x1c5c, TCO_CPT28)}, 347 { ITCO_PCI_DEVICE(0x1c5c, TCO_CPT28)},
348 { ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)}, 348 { ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)},
349 { ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)}, 349 { ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)},
350 { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, 350 { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)},
351 { 0, }, /* End of list */ 351 { 0, }, /* End of list */
352 }; 352 };
353 MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); 353 MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
354 354
355 /* Address definitions for the TCO */ 355 /* Address definitions for the TCO */
356 /* TCO base address */ 356 /* TCO base address */
357 #define TCOBASE (iTCO_wdt_private.ACPIBASE + 0x60) 357 #define TCOBASE (iTCO_wdt_private.ACPIBASE + 0x60)
358 /* SMI Control and Enable Register */ 358 /* SMI Control and Enable Register */
359 #define SMI_EN (iTCO_wdt_private.ACPIBASE + 0x30) 359 #define SMI_EN (iTCO_wdt_private.ACPIBASE + 0x30)
360 360
361 #define TCO_RLD (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */ 361 #define TCO_RLD (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */
362 #define TCOv1_TMR (TCOBASE + 0x01) /* TCOv1 Timer Initial Value */ 362 #define TCOv1_TMR (TCOBASE + 0x01) /* TCOv1 Timer Initial Value */
363 #define TCO_DAT_IN (TCOBASE + 0x02) /* TCO Data In Register */ 363 #define TCO_DAT_IN (TCOBASE + 0x02) /* TCO Data In Register */
364 #define TCO_DAT_OUT (TCOBASE + 0x03) /* TCO Data Out Register */ 364 #define TCO_DAT_OUT (TCOBASE + 0x03) /* TCO Data Out Register */
365 #define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */ 365 #define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */
366 #define TCO2_STS (TCOBASE + 0x06) /* TCO2 Status Register */ 366 #define TCO2_STS (TCOBASE + 0x06) /* TCO2 Status Register */
367 #define TCO1_CNT (TCOBASE + 0x08) /* TCO1 Control Register */ 367 #define TCO1_CNT (TCOBASE + 0x08) /* TCO1 Control Register */
368 #define TCO2_CNT (TCOBASE + 0x0a) /* TCO2 Control Register */ 368 #define TCO2_CNT (TCOBASE + 0x0a) /* TCO2 Control Register */
369 #define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */ 369 #define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */
370 370
371 /* internal variables */ 371 /* internal variables */
372 static unsigned long is_active; 372 static unsigned long is_active;
373 static char expect_release; 373 static char expect_release;
374 static struct { /* this is private data for the iTCO_wdt device */ 374 static struct { /* this is private data for the iTCO_wdt device */
375 /* TCO version/generation */ 375 /* TCO version/generation */
376 unsigned int iTCO_version; 376 unsigned int iTCO_version;
377 /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ 377 /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
378 unsigned long ACPIBASE; 378 unsigned long ACPIBASE;
379 /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/ 379 /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
380 unsigned long __iomem *gcs; 380 unsigned long __iomem *gcs;
381 /* the lock for io operations */ 381 /* the lock for io operations */
382 spinlock_t io_lock; 382 spinlock_t io_lock;
383 /* the PCI-device */ 383 /* the PCI-device */
384 struct pci_dev *pdev; 384 struct pci_dev *pdev;
385 } iTCO_wdt_private; 385 } iTCO_wdt_private;
386 386
387 /* the watchdog platform device */ 387 /* the watchdog platform device */
388 static struct platform_device *iTCO_wdt_platform_device; 388 static struct platform_device *iTCO_wdt_platform_device;
389 389
390 /* module parameters */ 390 /* module parameters */
391 #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ 391 #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
392 static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ 392 static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
393 module_param(heartbeat, int, 0); 393 module_param(heartbeat, int, 0);
394 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. " 394 MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
395 "(2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" 395 "5..76 (TCO v1) or 3..614 (TCO v2), default="
396 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); 396 __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
397 397
398 static int nowayout = WATCHDOG_NOWAYOUT; 398 static int nowayout = WATCHDOG_NOWAYOUT;
399 module_param(nowayout, int, 0); 399 module_param(nowayout, int, 0);
400 MODULE_PARM_DESC(nowayout, 400 MODULE_PARM_DESC(nowayout,
401 "Watchdog cannot be stopped once started (default=" 401 "Watchdog cannot be stopped once started (default="
402 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 402 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
403 403
404 /* 404 /*
405 * Some TCO specific functions 405 * Some TCO specific functions
406 */ 406 */
407 407
408 static inline unsigned int seconds_to_ticks(int seconds) 408 static inline unsigned int seconds_to_ticks(int seconds)
409 { 409 {
410 /* the internal timer is stored as ticks which decrement 410 /* the internal timer is stored as ticks which decrement
411 * every 0.6 seconds */ 411 * every 0.6 seconds */
412 return (seconds * 10) / 6; 412 return (seconds * 10) / 6;
413 } 413 }
414 414
415 static void iTCO_wdt_set_NO_REBOOT_bit(void) 415 static void iTCO_wdt_set_NO_REBOOT_bit(void)
416 { 416 {
417 u32 val32; 417 u32 val32;
418 418
419 /* Set the NO_REBOOT bit: this disables reboots */ 419 /* Set the NO_REBOOT bit: this disables reboots */
420 if (iTCO_wdt_private.iTCO_version == 2) { 420 if (iTCO_wdt_private.iTCO_version == 2) {
421 val32 = readl(iTCO_wdt_private.gcs); 421 val32 = readl(iTCO_wdt_private.gcs);
422 val32 |= 0x00000020; 422 val32 |= 0x00000020;
423 writel(val32, iTCO_wdt_private.gcs); 423 writel(val32, iTCO_wdt_private.gcs);
424 } else if (iTCO_wdt_private.iTCO_version == 1) { 424 } else if (iTCO_wdt_private.iTCO_version == 1) {
425 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); 425 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
426 val32 |= 0x00000002; 426 val32 |= 0x00000002;
427 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); 427 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
428 } 428 }
429 } 429 }
430 430
431 static int iTCO_wdt_unset_NO_REBOOT_bit(void) 431 static int iTCO_wdt_unset_NO_REBOOT_bit(void)
432 { 432 {
433 int ret = 0; 433 int ret = 0;
434 u32 val32; 434 u32 val32;
435 435
436 /* Unset the NO_REBOOT bit: this enables reboots */ 436 /* Unset the NO_REBOOT bit: this enables reboots */
437 if (iTCO_wdt_private.iTCO_version == 2) { 437 if (iTCO_wdt_private.iTCO_version == 2) {
438 val32 = readl(iTCO_wdt_private.gcs); 438 val32 = readl(iTCO_wdt_private.gcs);
439 val32 &= 0xffffffdf; 439 val32 &= 0xffffffdf;
440 writel(val32, iTCO_wdt_private.gcs); 440 writel(val32, iTCO_wdt_private.gcs);
441 441
442 val32 = readl(iTCO_wdt_private.gcs); 442 val32 = readl(iTCO_wdt_private.gcs);
443 if (val32 & 0x00000020) 443 if (val32 & 0x00000020)
444 ret = -EIO; 444 ret = -EIO;
445 } else if (iTCO_wdt_private.iTCO_version == 1) { 445 } else if (iTCO_wdt_private.iTCO_version == 1) {
446 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); 446 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
447 val32 &= 0xfffffffd; 447 val32 &= 0xfffffffd;
448 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); 448 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
449 449
450 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); 450 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
451 if (val32 & 0x00000002) 451 if (val32 & 0x00000002)
452 ret = -EIO; 452 ret = -EIO;
453 } 453 }
454 454
455 return ret; /* returns: 0 = OK, -EIO = Error */ 455 return ret; /* returns: 0 = OK, -EIO = Error */
456 } 456 }
457 457
458 static int iTCO_wdt_start(void) 458 static int iTCO_wdt_start(void)
459 { 459 {
460 unsigned int val; 460 unsigned int val;
461 461
462 spin_lock(&iTCO_wdt_private.io_lock); 462 spin_lock(&iTCO_wdt_private.io_lock);
463 463
464 iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat); 464 iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
465 465
466 /* disable chipset's NO_REBOOT bit */ 466 /* disable chipset's NO_REBOOT bit */
467 if (iTCO_wdt_unset_NO_REBOOT_bit()) { 467 if (iTCO_wdt_unset_NO_REBOOT_bit()) {
468 spin_unlock(&iTCO_wdt_private.io_lock); 468 spin_unlock(&iTCO_wdt_private.io_lock);
469 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, " 469 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, "
470 "reboot disabled by hardware\n"); 470 "reboot disabled by hardware\n");
471 return -EIO; 471 return -EIO;
472 } 472 }
473 473
474 /* Force the timer to its reload value by writing to the TCO_RLD 474 /* Force the timer to its reload value by writing to the TCO_RLD
475 register */ 475 register */
476 if (iTCO_wdt_private.iTCO_version == 2) 476 if (iTCO_wdt_private.iTCO_version == 2)
477 outw(0x01, TCO_RLD); 477 outw(0x01, TCO_RLD);
478 else if (iTCO_wdt_private.iTCO_version == 1) 478 else if (iTCO_wdt_private.iTCO_version == 1)
479 outb(0x01, TCO_RLD); 479 outb(0x01, TCO_RLD);
480 480
481 /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ 481 /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
482 val = inw(TCO1_CNT); 482 val = inw(TCO1_CNT);
483 val &= 0xf7ff; 483 val &= 0xf7ff;
484 outw(val, TCO1_CNT); 484 outw(val, TCO1_CNT);
485 val = inw(TCO1_CNT); 485 val = inw(TCO1_CNT);
486 spin_unlock(&iTCO_wdt_private.io_lock); 486 spin_unlock(&iTCO_wdt_private.io_lock);
487 487
488 if (val & 0x0800) 488 if (val & 0x0800)
489 return -1; 489 return -1;
490 return 0; 490 return 0;
491 } 491 }
492 492
493 static int iTCO_wdt_stop(void) 493 static int iTCO_wdt_stop(void)
494 { 494 {
495 unsigned int val; 495 unsigned int val;
496 496
497 spin_lock(&iTCO_wdt_private.io_lock); 497 spin_lock(&iTCO_wdt_private.io_lock);
498 498
499 iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE); 499 iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
500 500
501 /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ 501 /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
502 val = inw(TCO1_CNT); 502 val = inw(TCO1_CNT);
503 val |= 0x0800; 503 val |= 0x0800;
504 outw(val, TCO1_CNT); 504 outw(val, TCO1_CNT);
505 val = inw(TCO1_CNT); 505 val = inw(TCO1_CNT);
506 506
507 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ 507 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
508 iTCO_wdt_set_NO_REBOOT_bit(); 508 iTCO_wdt_set_NO_REBOOT_bit();
509 509
510 spin_unlock(&iTCO_wdt_private.io_lock); 510 spin_unlock(&iTCO_wdt_private.io_lock);
511 511
512 if ((val & 0x0800) == 0) 512 if ((val & 0x0800) == 0)
513 return -1; 513 return -1;
514 return 0; 514 return 0;
515 } 515 }
516 516
517 static int iTCO_wdt_keepalive(void) 517 static int iTCO_wdt_keepalive(void)
518 { 518 {
519 spin_lock(&iTCO_wdt_private.io_lock); 519 spin_lock(&iTCO_wdt_private.io_lock);
520 520
521 iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat); 521 iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
522 522
523 /* Reload the timer by writing to the TCO Timer Counter register */ 523 /* Reload the timer by writing to the TCO Timer Counter register */
524 if (iTCO_wdt_private.iTCO_version == 2) 524 if (iTCO_wdt_private.iTCO_version == 2)
525 outw(0x01, TCO_RLD); 525 outw(0x01, TCO_RLD);
526 else if (iTCO_wdt_private.iTCO_version == 1) 526 else if (iTCO_wdt_private.iTCO_version == 1) {
527 /* Reset the timeout status bit so that the timer
528 * needs to count down twice again before rebooting */
529 outw(0x0008, TCO1_STS); /* write 1 to clear bit */
530
527 outb(0x01, TCO_RLD); 531 outb(0x01, TCO_RLD);
532 }
528 533
529 spin_unlock(&iTCO_wdt_private.io_lock); 534 spin_unlock(&iTCO_wdt_private.io_lock);
530 return 0; 535 return 0;
531 } 536 }
532 537
533 static int iTCO_wdt_set_heartbeat(int t) 538 static int iTCO_wdt_set_heartbeat(int t)
534 { 539 {
535 unsigned int val16; 540 unsigned int val16;
536 unsigned char val8; 541 unsigned char val8;
537 unsigned int tmrval; 542 unsigned int tmrval;
538 543
539 tmrval = seconds_to_ticks(t); 544 tmrval = seconds_to_ticks(t);
545
546 /* For TCO v1 the timer counts down twice before rebooting */
547 if (iTCO_wdt_private.iTCO_version == 1)
548 tmrval /= 2;
549
540 /* from the specs: */ 550 /* from the specs: */
541 /* "Values of 0h-3h are ignored and should not be attempted" */ 551 /* "Values of 0h-3h are ignored and should not be attempted" */
542 if (tmrval < 0x04) 552 if (tmrval < 0x04)
543 return -EINVAL; 553 return -EINVAL;
544 if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) || 554 if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
545 ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) 555 ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
546 return -EINVAL; 556 return -EINVAL;
547 557
548 iTCO_vendor_pre_set_heartbeat(tmrval); 558 iTCO_vendor_pre_set_heartbeat(tmrval);
549 559
550 /* Write new heartbeat to watchdog */ 560 /* Write new heartbeat to watchdog */
551 if (iTCO_wdt_private.iTCO_version == 2) { 561 if (iTCO_wdt_private.iTCO_version == 2) {
552 spin_lock(&iTCO_wdt_private.io_lock); 562 spin_lock(&iTCO_wdt_private.io_lock);
553 val16 = inw(TCOv2_TMR); 563 val16 = inw(TCOv2_TMR);
554 val16 &= 0xfc00; 564 val16 &= 0xfc00;
555 val16 |= tmrval; 565 val16 |= tmrval;
556 outw(val16, TCOv2_TMR); 566 outw(val16, TCOv2_TMR);
557 val16 = inw(TCOv2_TMR); 567 val16 = inw(TCOv2_TMR);
558 spin_unlock(&iTCO_wdt_private.io_lock); 568 spin_unlock(&iTCO_wdt_private.io_lock);
559 569
560 if ((val16 & 0x3ff) != tmrval) 570 if ((val16 & 0x3ff) != tmrval)
561 return -EINVAL; 571 return -EINVAL;
562 } else if (iTCO_wdt_private.iTCO_version == 1) { 572 } else if (iTCO_wdt_private.iTCO_version == 1) {
563 spin_lock(&iTCO_wdt_private.io_lock); 573 spin_lock(&iTCO_wdt_private.io_lock);
564 val8 = inb(TCOv1_TMR); 574 val8 = inb(TCOv1_TMR);
565 val8 &= 0xc0; 575 val8 &= 0xc0;
566 val8 |= (tmrval & 0xff); 576 val8 |= (tmrval & 0xff);
567 outb(val8, TCOv1_TMR); 577 outb(val8, TCOv1_TMR);
568 val8 = inb(TCOv1_TMR); 578 val8 = inb(TCOv1_TMR);
569 spin_unlock(&iTCO_wdt_private.io_lock); 579 spin_unlock(&iTCO_wdt_private.io_lock);
570 580
571 if ((val8 & 0x3f) != tmrval) 581 if ((val8 & 0x3f) != tmrval)
572 return -EINVAL; 582 return -EINVAL;
573 } 583 }
574 584
575 heartbeat = t; 585 heartbeat = t;
576 return 0; 586 return 0;
577 } 587 }
578 588
579 static int iTCO_wdt_get_timeleft(int *time_left) 589 static int iTCO_wdt_get_timeleft(int *time_left)
580 { 590 {
581 unsigned int val16; 591 unsigned int val16;
582 unsigned char val8; 592 unsigned char val8;
583 593
584 /* read the TCO Timer */ 594 /* read the TCO Timer */
585 if (iTCO_wdt_private.iTCO_version == 2) { 595 if (iTCO_wdt_private.iTCO_version == 2) {
586 spin_lock(&iTCO_wdt_private.io_lock); 596 spin_lock(&iTCO_wdt_private.io_lock);
587 val16 = inw(TCO_RLD); 597 val16 = inw(TCO_RLD);
588 val16 &= 0x3ff; 598 val16 &= 0x3ff;
589 spin_unlock(&iTCO_wdt_private.io_lock); 599 spin_unlock(&iTCO_wdt_private.io_lock);
590 600
591 *time_left = (val16 * 6) / 10; 601 *time_left = (val16 * 6) / 10;
592 } else if (iTCO_wdt_private.iTCO_version == 1) { 602 } else if (iTCO_wdt_private.iTCO_version == 1) {
593 spin_lock(&iTCO_wdt_private.io_lock); 603 spin_lock(&iTCO_wdt_private.io_lock);
594 val8 = inb(TCO_RLD); 604 val8 = inb(TCO_RLD);
595 val8 &= 0x3f; 605 val8 &= 0x3f;
606 if (!(inw(TCO1_STS) & 0x0008))
607 val8 += (inb(TCOv1_TMR) & 0x3f);
596 spin_unlock(&iTCO_wdt_private.io_lock); 608 spin_unlock(&iTCO_wdt_private.io_lock);
597 609
598 *time_left = (val8 * 6) / 10; 610 *time_left = (val8 * 6) / 10;
599 } else 611 } else
600 return -EINVAL; 612 return -EINVAL;
601 return 0; 613 return 0;
602 } 614 }
603 615
604 /* 616 /*
605 * /dev/watchdog handling 617 * /dev/watchdog handling
606 */ 618 */
607 619
608 static int iTCO_wdt_open(struct inode *inode, struct file *file) 620 static int iTCO_wdt_open(struct inode *inode, struct file *file)
609 { 621 {
610 /* /dev/watchdog can only be opened once */ 622 /* /dev/watchdog can only be opened once */
611 if (test_and_set_bit(0, &is_active)) 623 if (test_and_set_bit(0, &is_active))
612 return -EBUSY; 624 return -EBUSY;
613 625
614 /* 626 /*
615 * Reload and activate timer 627 * Reload and activate timer
616 */ 628 */
617 iTCO_wdt_start(); 629 iTCO_wdt_start();
618 return nonseekable_open(inode, file); 630 return nonseekable_open(inode, file);
619 } 631 }
620 632
621 static int iTCO_wdt_release(struct inode *inode, struct file *file) 633 static int iTCO_wdt_release(struct inode *inode, struct file *file)
622 { 634 {
623 /* 635 /*
624 * Shut off the timer. 636 * Shut off the timer.
625 */ 637 */
626 if (expect_release == 42) { 638 if (expect_release == 42) {
627 iTCO_wdt_stop(); 639 iTCO_wdt_stop();
628 } else { 640 } else {
629 printk(KERN_CRIT PFX 641 printk(KERN_CRIT PFX
630 "Unexpected close, not stopping watchdog!\n"); 642 "Unexpected close, not stopping watchdog!\n");
631 iTCO_wdt_keepalive(); 643 iTCO_wdt_keepalive();
632 } 644 }
633 clear_bit(0, &is_active); 645 clear_bit(0, &is_active);
634 expect_release = 0; 646 expect_release = 0;
635 return 0; 647 return 0;
636 } 648 }
637 649
638 static ssize_t iTCO_wdt_write(struct file *file, const char __user *data, 650 static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
639 size_t len, loff_t *ppos) 651 size_t len, loff_t *ppos)
640 { 652 {
641 /* See if we got the magic character 'V' and reload the timer */ 653 /* See if we got the magic character 'V' and reload the timer */
642 if (len) { 654 if (len) {
643 if (!nowayout) { 655 if (!nowayout) {
644 size_t i; 656 size_t i;
645 657
646 /* note: just in case someone wrote the magic 658 /* note: just in case someone wrote the magic
647 character five months ago... */ 659 character five months ago... */
648 expect_release = 0; 660 expect_release = 0;
649 661
650 /* scan to see whether or not we got the 662 /* scan to see whether or not we got the
651 magic character */ 663 magic character */
652 for (i = 0; i != len; i++) { 664 for (i = 0; i != len; i++) {
653 char c; 665 char c;
654 if (get_user(c, data + i)) 666 if (get_user(c, data + i))
655 return -EFAULT; 667 return -EFAULT;
656 if (c == 'V') 668 if (c == 'V')
657 expect_release = 42; 669 expect_release = 42;
658 } 670 }
659 } 671 }
660 672
661 /* someone wrote to us, we should reload the timer */ 673 /* someone wrote to us, we should reload the timer */
662 iTCO_wdt_keepalive(); 674 iTCO_wdt_keepalive();
663 } 675 }
664 return len; 676 return len;
665 } 677 }
666 678
667 static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd, 679 static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
668 unsigned long arg) 680 unsigned long arg)
669 { 681 {
670 int new_options, retval = -EINVAL; 682 int new_options, retval = -EINVAL;
671 int new_heartbeat; 683 int new_heartbeat;
672 void __user *argp = (void __user *)arg; 684 void __user *argp = (void __user *)arg;
673 int __user *p = argp; 685 int __user *p = argp;
674 static const struct watchdog_info ident = { 686 static const struct watchdog_info ident = {
675 .options = WDIOF_SETTIMEOUT | 687 .options = WDIOF_SETTIMEOUT |
676 WDIOF_KEEPALIVEPING | 688 WDIOF_KEEPALIVEPING |
677 WDIOF_MAGICCLOSE, 689 WDIOF_MAGICCLOSE,
678 .firmware_version = 0, 690 .firmware_version = 0,
679 .identity = DRV_NAME, 691 .identity = DRV_NAME,
680 }; 692 };
681 693
682 switch (cmd) { 694 switch (cmd) {
683 case WDIOC_GETSUPPORT: 695 case WDIOC_GETSUPPORT:
684 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; 696 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
685 case WDIOC_GETSTATUS: 697 case WDIOC_GETSTATUS:
686 case WDIOC_GETBOOTSTATUS: 698 case WDIOC_GETBOOTSTATUS:
687 return put_user(0, p); 699 return put_user(0, p);
688 700
689 case WDIOC_SETOPTIONS: 701 case WDIOC_SETOPTIONS:
690 { 702 {
691 if (get_user(new_options, p)) 703 if (get_user(new_options, p))
692 return -EFAULT; 704 return -EFAULT;
693 705
694 if (new_options & WDIOS_DISABLECARD) { 706 if (new_options & WDIOS_DISABLECARD) {
695 iTCO_wdt_stop(); 707 iTCO_wdt_stop();
696 retval = 0; 708 retval = 0;
697 } 709 }
698 if (new_options & WDIOS_ENABLECARD) { 710 if (new_options & WDIOS_ENABLECARD) {
699 iTCO_wdt_keepalive(); 711 iTCO_wdt_keepalive();
700 iTCO_wdt_start(); 712 iTCO_wdt_start();
701 retval = 0; 713 retval = 0;
702 } 714 }
703 return retval; 715 return retval;
704 } 716 }
705 case WDIOC_KEEPALIVE: 717 case WDIOC_KEEPALIVE:
706 iTCO_wdt_keepalive(); 718 iTCO_wdt_keepalive();
707 return 0; 719 return 0;
708 720
709 case WDIOC_SETTIMEOUT: 721 case WDIOC_SETTIMEOUT:
710 { 722 {
711 if (get_user(new_heartbeat, p)) 723 if (get_user(new_heartbeat, p))
712 return -EFAULT; 724 return -EFAULT;
713 if (iTCO_wdt_set_heartbeat(new_heartbeat)) 725 if (iTCO_wdt_set_heartbeat(new_heartbeat))
714 return -EINVAL; 726 return -EINVAL;
715 iTCO_wdt_keepalive(); 727 iTCO_wdt_keepalive();
716 /* Fall */ 728 /* Fall */
717 } 729 }
718 case WDIOC_GETTIMEOUT: 730 case WDIOC_GETTIMEOUT:
719 return put_user(heartbeat, p); 731 return put_user(heartbeat, p);
720 case WDIOC_GETTIMELEFT: 732 case WDIOC_GETTIMELEFT:
721 { 733 {
722 int time_left; 734 int time_left;
723 if (iTCO_wdt_get_timeleft(&time_left)) 735 if (iTCO_wdt_get_timeleft(&time_left))
724 return -EINVAL; 736 return -EINVAL;
725 return put_user(time_left, p); 737 return put_user(time_left, p);
726 } 738 }
727 default: 739 default:
728 return -ENOTTY; 740 return -ENOTTY;
729 } 741 }
730 } 742 }
731 743
732 /* 744 /*
733 * Kernel Interfaces 745 * Kernel Interfaces
734 */ 746 */
735 747
736 static const struct file_operations iTCO_wdt_fops = { 748 static const struct file_operations iTCO_wdt_fops = {
737 .owner = THIS_MODULE, 749 .owner = THIS_MODULE,
738 .llseek = no_llseek, 750 .llseek = no_llseek,
739 .write = iTCO_wdt_write, 751 .write = iTCO_wdt_write,
740 .unlocked_ioctl = iTCO_wdt_ioctl, 752 .unlocked_ioctl = iTCO_wdt_ioctl,
741 .open = iTCO_wdt_open, 753 .open = iTCO_wdt_open,
742 .release = iTCO_wdt_release, 754 .release = iTCO_wdt_release,
743 }; 755 };
744 756
745 static struct miscdevice iTCO_wdt_miscdev = { 757 static struct miscdevice iTCO_wdt_miscdev = {
746 .minor = WATCHDOG_MINOR, 758 .minor = WATCHDOG_MINOR,
747 .name = "watchdog", 759 .name = "watchdog",
748 .fops = &iTCO_wdt_fops, 760 .fops = &iTCO_wdt_fops,
749 }; 761 };
750 762
751 /* 763 /*
752 * Init & exit routines 764 * Init & exit routines
753 */ 765 */
754 766
755 static int __devinit iTCO_wdt_init(struct pci_dev *pdev, 767 static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
756 const struct pci_device_id *ent, struct platform_device *dev) 768 const struct pci_device_id *ent, struct platform_device *dev)
757 { 769 {
758 int ret; 770 int ret;
759 u32 base_address; 771 u32 base_address;
760 unsigned long RCBA; 772 unsigned long RCBA;
761 unsigned long val32; 773 unsigned long val32;
762 774
763 /* 775 /*
764 * Find the ACPI/PM base I/O address which is the base 776 * Find the ACPI/PM base I/O address which is the base
765 * for the TCO registers (TCOBASE=ACPIBASE + 0x60) 777 * for the TCO registers (TCOBASE=ACPIBASE + 0x60)
766 * ACPIBASE is bits [15:7] from 0x40-0x43 778 * ACPIBASE is bits [15:7] from 0x40-0x43
767 */ 779 */
768 pci_read_config_dword(pdev, 0x40, &base_address); 780 pci_read_config_dword(pdev, 0x40, &base_address);
769 base_address &= 0x0000ff80; 781 base_address &= 0x0000ff80;
770 if (base_address == 0x00000000) { 782 if (base_address == 0x00000000) {
771 /* Something's wrong here, ACPIBASE has to be set */ 783 /* Something's wrong here, ACPIBASE has to be set */
772 printk(KERN_ERR PFX "failed to get TCOBASE address\n"); 784 printk(KERN_ERR PFX "failed to get TCOBASE address\n");
773 pci_dev_put(pdev); 785 pci_dev_put(pdev);
774 return -ENODEV; 786 return -ENODEV;
775 } 787 }
776 iTCO_wdt_private.iTCO_version = 788 iTCO_wdt_private.iTCO_version =
777 iTCO_chipset_info[ent->driver_data].iTCO_version; 789 iTCO_chipset_info[ent->driver_data].iTCO_version;
778 iTCO_wdt_private.ACPIBASE = base_address; 790 iTCO_wdt_private.ACPIBASE = base_address;
779 iTCO_wdt_private.pdev = pdev; 791 iTCO_wdt_private.pdev = pdev;
780 792
781 /* Get the Memory-Mapped GCS register, we need it for the 793 /* Get the Memory-Mapped GCS register, we need it for the
782 NO_REBOOT flag (TCO v2). To get access to it you have to 794 NO_REBOOT flag (TCO v2). To get access to it you have to
783 read RCBA from PCI Config space 0xf0 and use it as base. 795 read RCBA from PCI Config space 0xf0 and use it as base.
784 GCS = RCBA + ICH6_GCS(0x3410). */ 796 GCS = RCBA + ICH6_GCS(0x3410). */
785 if (iTCO_wdt_private.iTCO_version == 2) { 797 if (iTCO_wdt_private.iTCO_version == 2) {
786 pci_read_config_dword(pdev, 0xf0, &base_address); 798 pci_read_config_dword(pdev, 0xf0, &base_address);
787 if ((base_address & 1) == 0) { 799 if ((base_address & 1) == 0) {
788 printk(KERN_ERR PFX "RCBA is disabled by hardware\n"); 800 printk(KERN_ERR PFX "RCBA is disabled by hardware\n");
789 ret = -ENODEV; 801 ret = -ENODEV;
790 goto out; 802 goto out;
791 } 803 }
792 RCBA = base_address & 0xffffc000; 804 RCBA = base_address & 0xffffc000;
793 iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4); 805 iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4);
794 } 806 }
795 807
796 /* Check chipset's NO_REBOOT bit */ 808 /* Check chipset's NO_REBOOT bit */
797 if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { 809 if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
798 printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, " 810 printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, "
799 "platform may have disabled it\n"); 811 "platform may have disabled it\n");
800 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ 812 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
801 goto out_unmap; 813 goto out_unmap;
802 } 814 }
803 815
804 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ 816 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
805 iTCO_wdt_set_NO_REBOOT_bit(); 817 iTCO_wdt_set_NO_REBOOT_bit();
806 818
807 /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ 819 /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
808 if (!request_region(SMI_EN, 4, "iTCO_wdt")) { 820 if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
809 printk(KERN_ERR PFX 821 printk(KERN_ERR PFX
810 "I/O address 0x%04lx already in use\n", SMI_EN); 822 "I/O address 0x%04lx already in use\n", SMI_EN);
811 ret = -EIO; 823 ret = -EIO;
812 goto out_unmap; 824 goto out_unmap;
813 } 825 }
814 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ 826 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
815 val32 = inl(SMI_EN); 827 val32 = inl(SMI_EN);
816 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ 828 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
817 outl(val32, SMI_EN); 829 outl(val32, SMI_EN);
818 830
819 /* The TCO I/O registers reside in a 32-byte range pointed to 831 /* The TCO I/O registers reside in a 32-byte range pointed to
820 by the TCOBASE value */ 832 by the TCOBASE value */
821 if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) { 833 if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) {
822 printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", 834 printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
823 TCOBASE); 835 TCOBASE);
824 ret = -EIO; 836 ret = -EIO;
825 goto unreg_smi_en; 837 goto unreg_smi_en;
826 } 838 }
827 839
828 printk(KERN_INFO PFX 840 printk(KERN_INFO PFX
829 "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n", 841 "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
830 iTCO_chipset_info[ent->driver_data].name, 842 iTCO_chipset_info[ent->driver_data].name,
831 iTCO_chipset_info[ent->driver_data].iTCO_version, 843 iTCO_chipset_info[ent->driver_data].iTCO_version,
832 TCOBASE); 844 TCOBASE);
833 845
834 /* Clear out the (probably old) status */ 846 /* Clear out the (probably old) status */
835 outb(8, TCO1_STS); /* Clear the Time Out Status bit */ 847 outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
836 outb(2, TCO2_STS); /* Clear SECOND_TO_STS bit */ 848 outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
837 outb(4, TCO2_STS); /* Clear BOOT_STS bit */ 849 outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
838 850
839 /* Make sure the watchdog is not running */ 851 /* Make sure the watchdog is not running */
840 iTCO_wdt_stop(); 852 iTCO_wdt_stop();
841 853
842 /* Check that the heartbeat value is within it's range; 854 /* Check that the heartbeat value is within it's range;
843 if not reset to the default */ 855 if not reset to the default */
844 if (iTCO_wdt_set_heartbeat(heartbeat)) { 856 if (iTCO_wdt_set_heartbeat(heartbeat)) {
845 iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); 857 iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
846 printk(KERN_INFO PFX 858 printk(KERN_INFO PFX
847 "heartbeat value must be 2 < heartbeat < 39 (TCO v1) " 859 "timeout value out of range, using %d\n", heartbeat);
848 "or 613 (TCO v2), using %d\n", heartbeat);
849 } 860 }
850 861
851 ret = misc_register(&iTCO_wdt_miscdev); 862 ret = misc_register(&iTCO_wdt_miscdev);
852 if (ret != 0) { 863 if (ret != 0) {
853 printk(KERN_ERR PFX 864 printk(KERN_ERR PFX
854 "cannot register miscdev on minor=%d (err=%d)\n", 865 "cannot register miscdev on minor=%d (err=%d)\n",
855 WATCHDOG_MINOR, ret); 866 WATCHDOG_MINOR, ret);
856 goto unreg_region; 867 goto unreg_region;
857 } 868 }
858 869
859 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", 870 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
860 heartbeat, nowayout); 871 heartbeat, nowayout);
861 872
862 return 0; 873 return 0;
863 874
864 unreg_region: 875 unreg_region:
865 release_region(TCOBASE, 0x20); 876 release_region(TCOBASE, 0x20);
866 unreg_smi_en: 877 unreg_smi_en:
867 release_region(SMI_EN, 4); 878 release_region(SMI_EN, 4);
868 out_unmap: 879 out_unmap:
869 if (iTCO_wdt_private.iTCO_version == 2) 880 if (iTCO_wdt_private.iTCO_version == 2)
870 iounmap(iTCO_wdt_private.gcs); 881 iounmap(iTCO_wdt_private.gcs);
871 out: 882 out:
872 pci_dev_put(iTCO_wdt_private.pdev); 883 pci_dev_put(iTCO_wdt_private.pdev);
873 iTCO_wdt_private.ACPIBASE = 0; 884 iTCO_wdt_private.ACPIBASE = 0;
874 return ret; 885 return ret;
875 } 886 }
876 887
877 static void __devexit iTCO_wdt_cleanup(void) 888 static void __devexit iTCO_wdt_cleanup(void)
878 { 889 {
879 /* Stop the timer before we leave */ 890 /* Stop the timer before we leave */
880 if (!nowayout) 891 if (!nowayout)
881 iTCO_wdt_stop(); 892 iTCO_wdt_stop();
882 893
883 /* Deregister */ 894 /* Deregister */
884 misc_deregister(&iTCO_wdt_miscdev); 895 misc_deregister(&iTCO_wdt_miscdev);
885 release_region(TCOBASE, 0x20); 896 release_region(TCOBASE, 0x20);
886 release_region(SMI_EN, 4); 897 release_region(SMI_EN, 4);
887 if (iTCO_wdt_private.iTCO_version == 2) 898 if (iTCO_wdt_private.iTCO_version == 2)
888 iounmap(iTCO_wdt_private.gcs); 899 iounmap(iTCO_wdt_private.gcs);
889 pci_dev_put(iTCO_wdt_private.pdev); 900 pci_dev_put(iTCO_wdt_private.pdev);
890 iTCO_wdt_private.ACPIBASE = 0; 901 iTCO_wdt_private.ACPIBASE = 0;
891 } 902 }
892 903
893 static int __devinit iTCO_wdt_probe(struct platform_device *dev) 904 static int __devinit iTCO_wdt_probe(struct platform_device *dev)
894 { 905 {
895 int ret = -ENODEV; 906 int ret = -ENODEV;
896 int found = 0; 907 int found = 0;
897 struct pci_dev *pdev = NULL; 908 struct pci_dev *pdev = NULL;
898 const struct pci_device_id *ent; 909 const struct pci_device_id *ent;
899 910
900 spin_lock_init(&iTCO_wdt_private.io_lock); 911 spin_lock_init(&iTCO_wdt_private.io_lock);
901 912
902 for_each_pci_dev(pdev) { 913 for_each_pci_dev(pdev) {
903 ent = pci_match_id(iTCO_wdt_pci_tbl, pdev); 914 ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
904 if (ent) { 915 if (ent) {
905 found++; 916 found++;
906 ret = iTCO_wdt_init(pdev, ent, dev); 917 ret = iTCO_wdt_init(pdev, ent, dev);
907 if (!ret) 918 if (!ret)
908 break; 919 break;
909 } 920 }
910 } 921 }
911 922
912 if (!found) 923 if (!found)
913 printk(KERN_INFO PFX "No card detected\n"); 924 printk(KERN_INFO PFX "No card detected\n");
914 925
915 return ret; 926 return ret;
916 } 927 }
917 928
918 static int __devexit iTCO_wdt_remove(struct platform_device *dev) 929 static int __devexit iTCO_wdt_remove(struct platform_device *dev)
919 { 930 {
920 if (iTCO_wdt_private.ACPIBASE) 931 if (iTCO_wdt_private.ACPIBASE)
921 iTCO_wdt_cleanup(); 932 iTCO_wdt_cleanup();
922 933
923 return 0; 934 return 0;
924 } 935 }
925 936
926 static void iTCO_wdt_shutdown(struct platform_device *dev) 937 static void iTCO_wdt_shutdown(struct platform_device *dev)
927 { 938 {
928 iTCO_wdt_stop(); 939 iTCO_wdt_stop();
929 } 940 }
930 941
931 #define iTCO_wdt_suspend NULL 942 #define iTCO_wdt_suspend NULL
932 #define iTCO_wdt_resume NULL 943 #define iTCO_wdt_resume NULL
933 944
934 static struct platform_driver iTCO_wdt_driver = { 945 static struct platform_driver iTCO_wdt_driver = {
935 .probe = iTCO_wdt_probe, 946 .probe = iTCO_wdt_probe,
936 .remove = __devexit_p(iTCO_wdt_remove), 947 .remove = __devexit_p(iTCO_wdt_remove),
937 .shutdown = iTCO_wdt_shutdown, 948 .shutdown = iTCO_wdt_shutdown,
938 .suspend = iTCO_wdt_suspend, 949 .suspend = iTCO_wdt_suspend,
939 .resume = iTCO_wdt_resume, 950 .resume = iTCO_wdt_resume,
940 .driver = { 951 .driver = {
941 .owner = THIS_MODULE, 952 .owner = THIS_MODULE,
942 .name = DRV_NAME, 953 .name = DRV_NAME,
943 }, 954 },
944 }; 955 };
945 956
946 static int __init iTCO_wdt_init_module(void) 957 static int __init iTCO_wdt_init_module(void)
947 { 958 {
948 int err; 959 int err;
949 960
950 printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n", 961 printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",
951 DRV_VERSION); 962 DRV_VERSION);
952 963
953 err = platform_driver_register(&iTCO_wdt_driver); 964 err = platform_driver_register(&iTCO_wdt_driver);
954 if (err) 965 if (err)
955 return err; 966 return err;
956 967
957 iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, 968 iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,
958 -1, NULL, 0); 969 -1, NULL, 0);
959 if (IS_ERR(iTCO_wdt_platform_device)) { 970 if (IS_ERR(iTCO_wdt_platform_device)) {
960 err = PTR_ERR(iTCO_wdt_platform_device); 971 err = PTR_ERR(iTCO_wdt_platform_device);
961 goto unreg_platform_driver; 972 goto unreg_platform_driver;
962 } 973 }
963 974
964 return 0; 975 return 0;
965 976
966 unreg_platform_driver: 977 unreg_platform_driver:
967 platform_driver_unregister(&iTCO_wdt_driver); 978 platform_driver_unregister(&iTCO_wdt_driver);
968 return err; 979 return err;
969 } 980 }
970 981
971 static void __exit iTCO_wdt_cleanup_module(void) 982 static void __exit iTCO_wdt_cleanup_module(void)
972 { 983 {
973 platform_device_unregister(iTCO_wdt_platform_device); 984 platform_device_unregister(iTCO_wdt_platform_device);
974 platform_driver_unregister(&iTCO_wdt_driver); 985 platform_driver_unregister(&iTCO_wdt_driver);
975 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); 986 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
976 } 987 }
977 988
978 module_init(iTCO_wdt_init_module); 989 module_init(iTCO_wdt_init_module);
979 module_exit(iTCO_wdt_cleanup_module); 990 module_exit(iTCO_wdt_cleanup_module);
980 991
981 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); 992 MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
982 MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver"); 993 MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
983 MODULE_VERSION(DRV_VERSION); 994 MODULE_VERSION(DRV_VERSION);
984 MODULE_LICENSE("GPL"); 995 MODULE_LICENSE("GPL");
985 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 996 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);