1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#define DRV_NAME "iTCO_vendor_support"
22#define DRV_VERSION "1.03"
23#define PFX DRV_NAME ": "
24
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/types.h>
29#include <linux/errno.h>
30#include <linux/kernel.h>
31#include <linux/init.h>
32#include <linux/ioport.h>
33#include <linux/io.h>
34
35#include "iTCO_vendor.h"
36
37
38#define SMI_EN acpibase + 0x30
39#define TCOBASE acpibase + 0x60
40#define TCO1_STS TCOBASE + 0x04
41
42
43
44#define SUPERMICRO_OLD_BOARD 1
45
46#define SUPERMICRO_NEW_BOARD 2
47
48static int vendorsupport;
49module_param(vendorsupport, int, 0);
50MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
51 "0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+");
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81static void supermicro_old_pre_start(unsigned long acpibase)
82{
83 unsigned long val32;
84
85
86 val32 = inl(SMI_EN);
87 val32 &= 0xffffdfff;
88 outl(val32, SMI_EN);
89}
90
91static void supermicro_old_pre_stop(unsigned long acpibase)
92{
93 unsigned long val32;
94
95
96 val32 = inl(SMI_EN);
97 val32 |= 0x00002000;
98 outl(val32, SMI_EN);
99}
100
101static void supermicro_old_pre_keepalive(unsigned long acpibase)
102{
103
104
105 outb(0x08, TCO1_STS);
106}
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151#define SM_REGINDEX 0x2e
152#define SM_DATAIO 0x2f
153
154
155#define SM_CTLPAGESW 0x07
156#define SM_CTLPAGE 0x08
157
158#define SM_WATCHENABLE 0x30
159
160#define SM_WATCHPAGE 0x87
161
162#define SM_ENDWATCH 0xAA
163
164#define SM_COUNTMODE 0xf5
165
166
167#define SM_WATCHTIMER 0xf6
168
169#define SM_RESETCONTROL 0xf7
170
171
172
173static void supermicro_new_unlock_watchdog(void)
174{
175
176 outb(SM_WATCHPAGE, SM_REGINDEX);
177 outb(SM_WATCHPAGE, SM_REGINDEX);
178
179 outb(SM_CTLPAGESW, SM_REGINDEX);
180 outb(SM_CTLPAGE, SM_DATAIO);
181}
182
183static void supermicro_new_lock_watchdog(void)
184{
185 outb(SM_ENDWATCH, SM_REGINDEX);
186}
187
188static void supermicro_new_pre_start(unsigned int heartbeat)
189{
190 unsigned int val;
191
192 supermicro_new_unlock_watchdog();
193
194
195 outb(SM_COUNTMODE, SM_REGINDEX);
196 val = inb(SM_DATAIO);
197 val &= 0xF7;
198 outb(val, SM_DATAIO);
199
200
201 outb(SM_WATCHTIMER, SM_REGINDEX);
202 outb((heartbeat & 255), SM_DATAIO);
203
204
205 outb(SM_RESETCONTROL, SM_REGINDEX);
206 val = inb(SM_DATAIO);
207 val &= 0x3f;
208 outb(val, SM_DATAIO);
209
210
211 outb(SM_WATCHENABLE, SM_REGINDEX);
212 val = inb(SM_DATAIO);
213 val |= 0x01;
214 outb(val, SM_DATAIO);
215
216 supermicro_new_lock_watchdog();
217}
218
219static void supermicro_new_pre_stop(void)
220{
221 unsigned int val;
222
223 supermicro_new_unlock_watchdog();
224
225
226 outb(SM_WATCHENABLE, SM_REGINDEX);
227 val = inb(SM_DATAIO);
228 val &= 0xFE;
229 outb(val, SM_DATAIO);
230
231 supermicro_new_lock_watchdog();
232}
233
234static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
235{
236 supermicro_new_unlock_watchdog();
237
238
239 outb(SM_WATCHTIMER, SM_REGINDEX);
240 outb((heartbeat & 255), SM_DATAIO);
241
242 supermicro_new_lock_watchdog();
243}
244
245
246
247
248
249void iTCO_vendor_pre_start(unsigned long acpibase,
250 unsigned int heartbeat)
251{
252 if (vendorsupport == SUPERMICRO_OLD_BOARD)
253 supermicro_old_pre_start(acpibase);
254 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
255 supermicro_new_pre_start(heartbeat);
256}
257EXPORT_SYMBOL(iTCO_vendor_pre_start);
258
259void iTCO_vendor_pre_stop(unsigned long acpibase)
260{
261 if (vendorsupport == SUPERMICRO_OLD_BOARD)
262 supermicro_old_pre_stop(acpibase);
263 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
264 supermicro_new_pre_stop();
265}
266EXPORT_SYMBOL(iTCO_vendor_pre_stop);
267
268void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
269{
270 if (vendorsupport == SUPERMICRO_OLD_BOARD)
271 supermicro_old_pre_keepalive(acpibase);
272 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
273 supermicro_new_pre_set_heartbeat(heartbeat);
274}
275EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
276
277void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat)
278{
279 if (vendorsupport == SUPERMICRO_NEW_BOARD)
280 supermicro_new_pre_set_heartbeat(heartbeat);
281}
282EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
283
284int iTCO_vendor_check_noreboot_on(void)
285{
286 switch (vendorsupport) {
287 case SUPERMICRO_OLD_BOARD:
288 return 0;
289 default:
290 return 1;
291 }
292}
293EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
294
295static int __init iTCO_vendor_init_module(void)
296{
297 printk(KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
298 return 0;
299}
300
301static void __exit iTCO_vendor_exit_module(void)
302{
303 printk(KERN_INFO PFX "Module Unloaded\n");
304}
305
306module_init(iTCO_vendor_init_module);
307module_exit(iTCO_vendor_exit_module);
308
309MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, "
310 "R. Seretny <lkpatches@paypc.com>");
311MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
312MODULE_VERSION(DRV_VERSION);
313MODULE_LICENSE("GPL");
314
315