Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
wdt.c
Go to the documentation of this file.
1 /*
2  * Industrial Computer Source WDT501 driver
3  *
4  * (c) Copyright 1996-1997 Alan Cox <[email protected]>,
5  * All Rights Reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version
10  * 2 of the License, or (at your option) any later version.
11  *
12  * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13  * warranty for any of this software. This material is provided
14  * "AS-IS" and at no charge.
15  *
16  * (c) Copyright 1995 Alan Cox <[email protected]>
17  *
18  * Release 0.10.
19  *
20  * Fixes
21  * Dave Gregorich : Modularisation and minor bugs
22  * Alan Cox : Added the watchdog ioctl() stuff
23  * Alan Cox : Fixed the reboot problem (as noted by
24  * Matt Crocker).
25  * Alan Cox : Added wdt= boot option
26  * Alan Cox : Cleaned up copy/user stuff
27  * Tim Hockin : Added insmod parameters, comment
28  * cleanup, parameterized timeout
29  * Tigran Aivazian : Restructured wdt_init() to handle
30  * failures
31  * Joel Becker : Added WDIOC_GET/SETTIMEOUT
32  * Matt Domsch : Added nowayout module option
33  */
34 
35 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
36 
37 #include <linux/interrupt.h>
38 #include <linux/module.h>
39 #include <linux/moduleparam.h>
40 #include <linux/types.h>
41 #include <linux/miscdevice.h>
42 #include <linux/watchdog.h>
43 #include <linux/fs.h>
44 #include <linux/ioport.h>
45 #include <linux/notifier.h>
46 #include <linux/reboot.h>
47 #include <linux/init.h>
48 #include <linux/io.h>
49 #include <linux/uaccess.h>
50 
51 #include "wd501p.h"
52 
53 static unsigned long wdt_is_open;
54 static char expect_close;
55 
56 /*
57  * Module parameters
58  */
59 
60 #define WD_TIMO 60 /* Default heartbeat = 60 seconds */
61 
62 static int heartbeat = WD_TIMO;
63 static int wd_heartbeat;
64 module_param(heartbeat, int, 0);
66  "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
68 
69 static bool nowayout = WATCHDOG_NOWAYOUT;
70 module_param(nowayout, bool, 0);
71 MODULE_PARM_DESC(nowayout,
72  "Watchdog cannot be stopped once started (default="
74 
75 /* You must set these - there is no sane way to probe for this board. */
76 static int io = 0x240;
77 static int irq = 11;
78 
79 static DEFINE_SPINLOCK(wdt_lock);
80 
81 module_param(io, int, 0);
82 MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
83 module_param(irq, int, 0);
84 MODULE_PARM_DESC(irq, "WDT irq (default=11)");
85 
86 /* Support for the Fan Tachometer on the WDT501-P */
87 static int tachometer;
88 module_param(tachometer, int, 0);
89 MODULE_PARM_DESC(tachometer,
90  "WDT501-P Fan Tachometer support (0=disable, default=0)");
91 
92 static int type = 500;
93 module_param(type, int, 0);
94 MODULE_PARM_DESC(type,
95  "WDT501-P Card type (500 or 501, default=500)");
96 
97 /*
98  * Programming support
99  */
100 
101 static void wdt_ctr_mode(int ctr, int mode)
102 {
103  ctr <<= 6;
104  ctr |= 0x30;
105  ctr |= (mode << 1);
106  outb_p(ctr, WDT_CR);
107 }
108 
109 static void wdt_ctr_load(int ctr, int val)
110 {
111  outb_p(val&0xFF, WDT_COUNT0+ctr);
112  outb_p(val>>8, WDT_COUNT0+ctr);
113 }
114 
121 static int wdt_start(void)
122 {
123  unsigned long flags;
124  spin_lock_irqsave(&wdt_lock, flags);
125  inb_p(WDT_DC); /* Disable watchdog */
126  wdt_ctr_mode(0, 3); /* Program CTR0 for Mode 3:
127  Square Wave Generator */
128  wdt_ctr_mode(1, 2); /* Program CTR1 for Mode 2:
129  Rate Generator */
130  wdt_ctr_mode(2, 0); /* Program CTR2 for Mode 0:
131  Pulse on Terminal Count */
132  wdt_ctr_load(0, 8948); /* Count at 100Hz */
133  wdt_ctr_load(1, wd_heartbeat); /* Heartbeat */
134  wdt_ctr_load(2, 65535); /* Length of reset pulse */
135  outb_p(0, WDT_DC); /* Enable watchdog */
136  spin_unlock_irqrestore(&wdt_lock, flags);
137  return 0;
138 }
139 
146 static int wdt_stop(void)
147 {
148  unsigned long flags;
149  spin_lock_irqsave(&wdt_lock, flags);
150  /* Turn the card off */
151  inb_p(WDT_DC); /* Disable watchdog */
152  wdt_ctr_load(2, 0); /* 0 length reset pulses now */
153  spin_unlock_irqrestore(&wdt_lock, flags);
154  return 0;
155 }
156 
164 static void wdt_ping(void)
165 {
166  unsigned long flags;
167  spin_lock_irqsave(&wdt_lock, flags);
168  /* Write a watchdog value */
169  inb_p(WDT_DC); /* Disable watchdog */
170  wdt_ctr_mode(1, 2); /* Re-Program CTR1 for Mode 2:
171  Rate Generator */
172  wdt_ctr_load(1, wd_heartbeat); /* Heartbeat */
173  outb_p(0, WDT_DC); /* Enable watchdog */
174  spin_unlock_irqrestore(&wdt_lock, flags);
175 }
176 
186 static int wdt_set_heartbeat(int t)
187 {
188  if (t < 1 || t > 65535)
189  return -EINVAL;
190 
191  heartbeat = t;
192  wd_heartbeat = t * 100;
193  return 0;
194 }
195 
206 static int wdt_get_status(void)
207 {
208  unsigned char new_status;
209  int status = 0;
210  unsigned long flags;
211 
212  spin_lock_irqsave(&wdt_lock, flags);
213  new_status = inb_p(WDT_SR);
214  spin_unlock_irqrestore(&wdt_lock, flags);
215 
216  if (new_status & WDC_SR_ISOI0)
217  status |= WDIOF_EXTERN1;
218  if (new_status & WDC_SR_ISII1)
219  status |= WDIOF_EXTERN2;
220  if (type == 501) {
221  if (!(new_status & WDC_SR_TGOOD))
222  status |= WDIOF_OVERHEAT;
223  if (!(new_status & WDC_SR_PSUOVER))
224  status |= WDIOF_POWEROVER;
225  if (!(new_status & WDC_SR_PSUUNDR))
226  status |= WDIOF_POWERUNDER;
227  if (tachometer) {
228  if (!(new_status & WDC_SR_FANGOOD))
229  status |= WDIOF_FANFAULT;
230  }
231  }
232  return status;
233 }
234 
242 static int wdt_get_temperature(void)
243 {
244  unsigned short c;
245  unsigned long flags;
246 
247  spin_lock_irqsave(&wdt_lock, flags);
248  c = inb_p(WDT_RT);
249  spin_unlock_irqrestore(&wdt_lock, flags);
250  return (c * 11 / 15) + 7;
251 }
252 
253 static void wdt_decode_501(int status)
254 {
255  if (!(status & WDC_SR_TGOOD))
256  pr_crit("Overheat alarm (%d)\n", inb_p(WDT_RT));
257  if (!(status & WDC_SR_PSUOVER))
258  pr_crit("PSU over voltage\n");
259  if (!(status & WDC_SR_PSUUNDR))
260  pr_crit("PSU under voltage\n");
261 }
262 
273 static irqreturn_t wdt_interrupt(int irq, void *dev_id)
274 {
275  /*
276  * Read the status register see what is up and
277  * then printk it.
278  */
279  unsigned char status;
280 
281  spin_lock(&wdt_lock);
282  status = inb_p(WDT_SR);
283 
284  pr_crit("WDT status %d\n", status);
285 
286  if (type == 501) {
287  wdt_decode_501(status);
288  if (tachometer) {
289  if (!(status & WDC_SR_FANGOOD))
290  pr_crit("Possible fan fault\n");
291  }
292  }
293  if (!(status & WDC_SR_WCCR)) {
294 #ifdef SOFTWARE_REBOOT
295 #ifdef ONLY_TESTING
296  pr_crit("Would Reboot\n");
297 #else
298  pr_crit("Initiating system reboot\n");
300 #endif
301 #else
302  pr_crit("Reset in 5ms\n");
303 #endif
304  }
305  spin_unlock(&wdt_lock);
306  return IRQ_HANDLED;
307 }
308 
309 
321 static ssize_t wdt_write(struct file *file, const char __user *buf,
322  size_t count, loff_t *ppos)
323 {
324  if (count) {
325  if (!nowayout) {
326  size_t i;
327 
328  /* In case it was set long ago */
329  expect_close = 0;
330 
331  for (i = 0; i != count; i++) {
332  char c;
333  if (get_user(c, buf + i))
334  return -EFAULT;
335  if (c == 'V')
336  expect_close = 42;
337  }
338  }
339  wdt_ping();
340  }
341  return count;
342 }
343 
355 static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
356 {
357  void __user *argp = (void __user *)arg;
358  int __user *p = argp;
359  int new_heartbeat;
360  int status;
361 
362  struct watchdog_info ident = {
363  .options = WDIOF_SETTIMEOUT|
366  .firmware_version = 1,
367  .identity = "WDT500/501",
368  };
369 
370  /* Add options according to the card we have */
372  if (type == 501) {
375  if (tachometer)
376  ident.options |= WDIOF_FANFAULT;
377  }
378 
379  switch (cmd) {
380  case WDIOC_GETSUPPORT:
381  return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
382  case WDIOC_GETSTATUS:
383  status = wdt_get_status();
384  return put_user(status, p);
385  case WDIOC_GETBOOTSTATUS:
386  return put_user(0, p);
387  case WDIOC_KEEPALIVE:
388  wdt_ping();
389  return 0;
390  case WDIOC_SETTIMEOUT:
391  if (get_user(new_heartbeat, p))
392  return -EFAULT;
393  if (wdt_set_heartbeat(new_heartbeat))
394  return -EINVAL;
395  wdt_ping();
396  /* Fall */
397  case WDIOC_GETTIMEOUT:
398  return put_user(heartbeat, p);
399  default:
400  return -ENOTTY;
401  }
402 }
403 
416 static int wdt_open(struct inode *inode, struct file *file)
417 {
418  if (test_and_set_bit(0, &wdt_is_open))
419  return -EBUSY;
420  /*
421  * Activate
422  */
423  wdt_start();
424  return nonseekable_open(inode, file);
425 }
426 
439 static int wdt_release(struct inode *inode, struct file *file)
440 {
441  if (expect_close == 42) {
442  wdt_stop();
443  clear_bit(0, &wdt_is_open);
444  } else {
445  pr_crit("WDT device closed unexpectedly. WDT will not stop!\n");
446  wdt_ping();
447  }
448  expect_close = 0;
449  return 0;
450 }
451 
463 static ssize_t wdt_temp_read(struct file *file, char __user *buf,
464  size_t count, loff_t *ptr)
465 {
466  int temperature = wdt_get_temperature();
467 
468  if (copy_to_user(buf, &temperature, 1))
469  return -EFAULT;
470 
471  return 1;
472 }
473 
482 static int wdt_temp_open(struct inode *inode, struct file *file)
483 {
484  return nonseekable_open(inode, file);
485 }
486 
495 static int wdt_temp_release(struct inode *inode, struct file *file)
496 {
497  return 0;
498 }
499 
512 static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
513  void *unused)
514 {
515  if (code == SYS_DOWN || code == SYS_HALT)
516  wdt_stop();
517  return NOTIFY_DONE;
518 }
519 
520 /*
521  * Kernel Interfaces
522  */
523 
524 
525 static const struct file_operations wdt_fops = {
526  .owner = THIS_MODULE,
527  .llseek = no_llseek,
528  .write = wdt_write,
529  .unlocked_ioctl = wdt_ioctl,
530  .open = wdt_open,
531  .release = wdt_release,
532 };
533 
534 static struct miscdevice wdt_miscdev = {
536  .name = "watchdog",
537  .fops = &wdt_fops,
538 };
539 
540 static const struct file_operations wdt_temp_fops = {
541  .owner = THIS_MODULE,
542  .llseek = no_llseek,
543  .read = wdt_temp_read,
544  .open = wdt_temp_open,
545  .release = wdt_temp_release,
546 };
547 
548 static struct miscdevice temp_miscdev = {
549  .minor = TEMP_MINOR,
550  .name = "temperature",
551  .fops = &wdt_temp_fops,
552 };
553 
554 /*
555  * The WDT card needs to learn about soft shutdowns in order to
556  * turn the timebomb registers off.
557  */
558 
559 static struct notifier_block wdt_notifier = {
560  .notifier_call = wdt_notify_sys,
561 };
562 
573 static void __exit wdt_exit(void)
574 {
575  misc_deregister(&wdt_miscdev);
576  if (type == 501)
577  misc_deregister(&temp_miscdev);
578  unregister_reboot_notifier(&wdt_notifier);
579  free_irq(irq, NULL);
580  release_region(io, 8);
581 }
582 
591 static int __init wdt_init(void)
592 {
593  int ret;
594 
595  if (type != 500 && type != 501) {
596  pr_err("unknown card type '%d'\n", type);
597  return -ENODEV;
598  }
599 
600  /* Check that the heartbeat value is within it's range;
601  if not reset to the default */
602  if (wdt_set_heartbeat(heartbeat)) {
603  wdt_set_heartbeat(WD_TIMO);
604  pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
605  WD_TIMO);
606  }
607 
608  if (!request_region(io, 8, "wdt501p")) {
609  pr_err("I/O address 0x%04x already in use\n", io);
610  ret = -EBUSY;
611  goto out;
612  }
613 
614  ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL);
615  if (ret) {
616  pr_err("IRQ %d is not free\n", irq);
617  goto outreg;
618  }
619 
620  ret = register_reboot_notifier(&wdt_notifier);
621  if (ret) {
622  pr_err("cannot register reboot notifier (err=%d)\n", ret);
623  goto outirq;
624  }
625 
626  if (type == 501) {
627  ret = misc_register(&temp_miscdev);
628  if (ret) {
629  pr_err("cannot register miscdev on minor=%d (err=%d)\n",
630  TEMP_MINOR, ret);
631  goto outrbt;
632  }
633  }
634 
635  ret = misc_register(&wdt_miscdev);
636  if (ret) {
637  pr_err("cannot register miscdev on minor=%d (err=%d)\n",
638  WATCHDOG_MINOR, ret);
639  goto outmisc;
640  }
641 
642  pr_info("WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
643  io, irq, heartbeat, nowayout);
644  if (type == 501)
645  pr_info("Fan Tachometer is %s\n",
646  tachometer ? "Enabled" : "Disabled");
647  return 0;
648 
649 outmisc:
650  if (type == 501)
651  misc_deregister(&temp_miscdev);
652 outrbt:
653  unregister_reboot_notifier(&wdt_notifier);
654 outirq:
655  free_irq(irq, NULL);
656 outreg:
657  release_region(io, 8);
658 out:
659  return ret;
660 }
661 
663 module_exit(wdt_exit);
664 
665 MODULE_AUTHOR("Alan Cox");
666 MODULE_DESCRIPTION("Driver for ISA ICS watchdog cards (WDT500/501)");
669 MODULE_LICENSE("GPL");