24 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26 #include <linux/module.h>
28 #include <linux/types.h>
30 #include <linux/watchdog.h>
33 #include <linux/pci.h>
43 #define TCO_VERSION "0.01"
44 #define TCO_MODULE_NAME "NV_TCO"
45 #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
48 static unsigned int tcobase;
50 static unsigned long timer_alive;
51 static char tco_expect_close;
58 #define WATCHDOG_HEARTBEAT 30
72 static inline unsigned char seconds_to_ticks(
int seconds)
76 return (seconds * 10) / 6;
79 static void tco_timer_start(
void)
88 spin_unlock_irqrestore(&tco_lock, flags);
91 static void tco_timer_stop(
void)
100 spin_unlock_irqrestore(&tco_lock, flags);
103 static void tco_timer_keepalive(
void)
109 spin_unlock_irqrestore(&tco_lock, flags);
112 static int tco_timer_set_heartbeat(
int t)
115 unsigned char tmrval;
124 if (t < 0 || t > 0x3f)
126 tmrval = seconds_to_ticks(t);
129 if (tmrval > 0x3f || tmrval < 0x04)
140 if ((val & 0x3f) != tmrval)
142 spin_unlock_irqrestore(&tco_lock, flags);
162 tco_timer_keepalive();
167 static int nv_tco_release(
struct inode *inode,
struct file *file)
170 if (tco_expect_close == 42) {
173 pr_crit(
"Unexpected close, not stopping watchdog!\n");
174 tco_timer_keepalive();
177 tco_expect_close = 0;
181 static ssize_t nv_tco_write(
struct file *file,
const char __user *
data,
182 size_t len, loff_t *ppos)
193 tco_expect_close = 0;
199 for (i = 0; i != len; i++) {
204 tco_expect_close = 42;
209 tco_timer_keepalive();
214 static long nv_tco_ioctl(
struct file *file,
unsigned int cmd,
225 .firmware_version = 0,
243 tco_timer_keepalive();
249 tco_timer_keepalive();
254 if (tco_timer_set_heartbeat(new_heartbeat))
256 tco_timer_keepalive();
272 .write = nv_tco_write,
273 .unlocked_ioctl = nv_tco_ioctl,
275 .release = nv_tco_release,
281 .fops = &nv_tco_fops,
305 static unsigned char __devinit nv_tco_getdevice(
void)
322 pci_read_config_dword(tco_pci, 0x64, &val);
324 if (val == 0x0001 || val == 0x0000) {
326 pr_err(
"failed to get tcobase address\n");
330 tcobase = val + 0x40;
333 pr_err(
"I/O address 0x%04x already in use\n", tcobase);
338 tco_timer_set_heartbeat(30);
344 tco_timer_keepalive();
349 pr_err(
"I/O address 0x%04x already in use\n",
359 pr_err(
"Could not disable SMI caused by TCO\n");
369 pr_err(
"failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
384 if (!nv_tco_getdevice())
388 pr_info(
"Watchdog reboot %sdetected\n",
398 if (tco_timer_set_heartbeat(
heartbeat)) {
401 pr_info(
"heartbeat value must be 2<heartbeat<39, using %d\n",
407 pr_err(
"cannot register miscdev on minor=%d (err=%d)\n",
416 pr_info(
"initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
426 static void __devexit nv_tco_cleanup(
void)
440 pr_crit(
"Couldn't unset REBOOT bit. Machine may soon reset\n");
470 .probe = nv_tco_init,
472 .shutdown = nv_tco_shutdown,
479 static int __init nv_tco_init_module(
void)
489 nv_tco_platform_device = platform_device_register_simple(
491 if (IS_ERR(nv_tco_platform_device)) {
492 err = PTR_ERR(nv_tco_platform_device);
493 goto unreg_platform_driver;
498 unreg_platform_driver:
503 static void __exit nv_tco_cleanup_module(
void)
507 pr_info(
"NV TCO Watchdog Module Unloaded\n");