1/* 2 * Industrial Computer Source WDT500/501 driver for Linux 2.1.x 3 * 4 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved. 5 * http://www.redhat.com 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 <alan@lxorguk.ukuu.org.uk> 17 * 18 * Release 0.08. 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 cleanup 28 * Parameterized timeout 29 * Tigran Aivazian : Restructured wdt_init() to handle failures 30 * Joel Becker : Added WDIOC_GET/SETTIMEOUT 31 * Matt Domsch : Added nowayout module option 32 */ 33 34#include <linux/config.h> 35#include <linux/module.h> 36#include <linux/version.h> 37#include <linux/types.h> 38#include <linux/errno.h> 39#include <linux/kernel.h> 40#include <linux/sched.h> 41#include <linux/smp_lock.h> 42#include <linux/miscdevice.h> 43#include <linux/watchdog.h> 44#include "wd501p.h" 45#include <linux/slab.h> 46#include <linux/ioport.h> 47#include <linux/fcntl.h> 48#include <asm/io.h> 49#include <asm/uaccess.h> 50#include <asm/system.h> 51#include <linux/notifier.h> 52#include <linux/reboot.h> 53#include <linux/init.h> 54 55static unsigned long wdt_is_open; 56static int expect_close; 57 58/* 59 * You must set these - there is no sane way to probe for this board. 60 * You can use wdt=x,y to set these now. 61 */ 62 63static int io=0x240; 64static int irq=11; 65 66/* Default margin */ 67#define WD_TIMO (100*60) /* 1 minute */ 68 69static int wd_margin = WD_TIMO; 70 71#ifdef CONFIG_WATCHDOG_NOWAYOUT 72static int nowayout = 1; 73#else 74static int nowayout = 0; 75#endif 76 77MODULE_PARM(nowayout,"i"); 78MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); 79 80#ifndef MODULE 81 82/** 83 * wdt_setup: 84 * @str: command line string 85 * 86 * Setup options. The board isn't really probe-able so we have to 87 * get the user to tell us the configuration. Sane people build it 88 * modular but the others come here. 89 */ 90 91static int __init wdt_setup(char *str) 92{ 93 int ints[4]; 94 95 str = get_options (str, ARRAY_SIZE(ints), ints); 96 97 if (ints[0] > 0) 98 { 99 io = ints[1]; 100 if(ints[0] > 1) 101 irq = ints[2]; 102 } 103 104 return 1; 105} 106 107__setup("wdt=", wdt_setup); 108 109#endif /* !MODULE */ 110 111MODULE_PARM(io, "i"); 112MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); 113MODULE_PARM(irq, "i"); 114MODULE_PARM_DESC(irq, "WDT irq (default=11)"); 115 116/* 117 * Programming support 118 */ 119 120static void wdt_ctr_mode(int ctr, int mode) 121{ 122 ctr<<=6; 123 ctr|=0x30; 124 ctr|=(mode<<1); 125 outb_p(ctr, WDT_CR); 126} 127 128static void wdt_ctr_load(int ctr, int val) 129{ 130 outb_p(val&0xFF, WDT_COUNT0+ctr); 131 outb_p(val>>8, WDT_COUNT0+ctr); 132} 133 134/* 135 * Kernel methods. 136 */ 137 138 139/** 140 * wdt_status: 141 * 142 * Extract the status information from a WDT watchdog device. There are 143 * several board variants so we have to know which bits are valid. Some 144 * bits default to one and some to zero in order to be maximally painful. 145 * 146 * we then map the bits onto the status ioctl flags. 147 */ 148 149static int wdt_status(void) 150{ 151 /* 152 * Status register to bit flags 153 */ 154 155 int flag=0; 156 unsigned char status=inb_p(WDT_SR); 157 status|=FEATUREMAP1; 158 status&=~FEATUREMAP2; 159 160 if(!(status&WDC_SR_TGOOD)) 161 flag|=WDIOF_OVERHEAT; 162 if(!(status&WDC_SR_PSUOVER)) 163 flag|=WDIOF_POWEROVER; 164 if(!(status&WDC_SR_PSUUNDR)) 165 flag|=WDIOF_POWERUNDER; 166 if(!(status&WDC_SR_FANGOOD)) 167 flag|=WDIOF_FANFAULT; 168 if(status&WDC_SR_ISOI0) 169 flag|=WDIOF_EXTERN1; 170 if(status&WDC_SR_ISII1) 171 flag|=WDIOF_EXTERN2; 172 return flag; 173} 174 175/** 176 * wdt_interrupt: 177 * @irq: Interrupt number 178 * @dev_id: Unused as we don't allow multiple devices. 179 * @regs: Unused. 180 * 181 * Handle an interrupt from the board. These are raised when the status 182 * map changes in what the board considers an interesting way. That means 183 * a failure condition occuring. 184 */ 185 186void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs) 187{ 188 /* 189 * Read the status register see what is up and 190 * then printk it. 191 */ 192 193 unsigned char status=inb_p(WDT_SR); 194 195 status|=FEATUREMAP1; 196 status&=~FEATUREMAP2; 197 198 printk(KERN_CRIT "WDT status %d\n", status); 199 200 if(!(status&WDC_SR_TGOOD)) 201 printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); 202 if(!(status&WDC_SR_PSUOVER)) 203 printk(KERN_CRIT "PSU over voltage.\n"); 204 if(!(status&WDC_SR_PSUUNDR)) 205 printk(KERN_CRIT "PSU under voltage.\n"); 206 if(!(status&WDC_SR_FANGOOD)) 207 printk(KERN_CRIT "Possible fan fault.\n"); 208 if(!(status&WDC_SR_WCCR)) 209#ifdef SOFTWARE_REBOOT 210#ifdef ONLY_TESTING 211 printk(KERN_CRIT "Would Reboot.\n"); 212#else 213 printk(KERN_CRIT "Initiating system reboot.\n"); 214 machine_restart(NULL); 215#endif 216#else 217 printk(KERN_CRIT "Reset in 5ms.\n"); 218#endif 219} 220 221 222/** 223 * wdt_ping: 224 * 225 * Reload counter one with the watchdog timeout. We don't bother reloading 226 * the cascade counter. 227 */ 228 229static void wdt_ping(void) 230{ 231 /* Write a watchdog value */ 232 inb_p(WDT_DC); 233 wdt_ctr_mode(1,2); 234 wdt_ctr_load(1,wd_margin); /* Timeout */ 235 outb_p(0, WDT_DC); 236} 237 238/** 239 * wdt_write: 240 * @file: file handle to the watchdog 241 * @buf: buffer to write (unused as data does not matter here 242 * @count: count of bytes 243 * @ppos: pointer to the position to write. No seeks allowed 244 * 245 * A write to a watchdog device is defined as a keepalive signal. Any 246 * write of data will do, as we we don't define content meaning. 247 */ 248 249static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) 250{ 251 /* Can't seek (pwrite) on this device */ 252 if (ppos != &file->f_pos) 253 return -ESPIPE; 254 255 if(count) 256 { 257 if (!nowayout) { 258 size_t i; 259 260 /* In case it was set long ago */ 261 expect_close = 0; 262 263 for (i = 0; i != count; i++) { 264 char c; 265 if (get_user(c, buf + i)) 266 return -EFAULT; 267 if (c == 'V') 268 expect_close = 1; 269 } 270 } 271 wdt_ping(); 272 return 1; 273 } 274 return 0; 275} 276 277/** 278 * wdt_read: 279 * @file: file handle to the watchdog board 280 * @buf: buffer to write 1 byte into 281 * @count: length of buffer 282 * @ptr: offset (no seek allowed) 283 * 284 * Read reports the temperature in degrees Fahrenheit. The API is in 285 * farenheit. It was designed by an imperial measurement luddite. 286 */ 287 288static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *ptr) 289{ 290 unsigned short c=inb_p(WDT_RT); 291 unsigned char cp; 292 293 /* Can't seek (pread) on this device */ 294 if (ptr != &file->f_pos) 295 return -ESPIPE; 296 297 switch(MINOR(file->f_dentry->d_inode->i_rdev)) 298 { 299 case TEMP_MINOR: 300 c*=11; 301 c/=15; 302 cp=c+7; 303 if(copy_to_user(buf,&cp,1)) 304 return -EFAULT; 305 return 1; 306 default: 307 return -EINVAL; 308 } 309} 310 311/** 312 * wdt_ioctl: 313 * @inode: inode of the device 314 * @file: file handle to the device 315 * @cmd: watchdog command 316 * @arg: argument pointer 317 * 318 * The watchdog API defines a common set of functions for all watchdogs 319 * according to their available features. We only actually usefully support 320 * querying capabilities and current status. 321 */ 322 323static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 324 unsigned long arg) 325{ 326 int new_margin; 327 328 static struct watchdog_info ident= 329 { 330 WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER 331 |WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT 332 |WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE, 333 1, 334 "WDT500/501" 335 }; 336 337 ident.options&=WDT_OPTION_MASK; /* Mask down to the card we have */ 338 switch(cmd) 339 { 340 default: 341 return -ENOTTY; 342 case WDIOC_GETSUPPORT: 343 return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; 344 345 case WDIOC_GETSTATUS: 346 return put_user(wdt_status(),(int *)arg); 347 case WDIOC_GETBOOTSTATUS: 348 return put_user(0, (int *)arg); 349 case WDIOC_KEEPALIVE: 350 wdt_ping(); 351 return 0; 352 case WDIOC_SETTIMEOUT: 353 if (get_user(new_margin, (int *)arg)) 354 return -EFAULT; 355 /* Arbitrary, can't find the card's limits */ 356 if ((new_margin < 0) || (new_margin > 60)) 357 return -EINVAL; 358 wd_margin = new_margin * 100; 359 wdt_ping(); 360 /* Fall */ 361 case WDIOC_GETTIMEOUT: 362 return put_user(wd_margin / 100, (int *)arg); 363 } 364} 365 366/** 367 * wdt_open: 368 * @inode: inode of device 369 * @file: file handle to device 370 * 371 * One of our two misc devices has been opened. The watchdog device is 372 * single open and on opening we load the counters. Counter zero is a 373 * 100Hz cascade, into counter 1 which downcounts to reboot. When the 374 * counter triggers counter 2 downcounts the length of the reset pulse 375 * which set set to be as long as possible. 376 */ 377 378static int wdt_open(struct inode *inode, struct file *file) 379{ 380 switch(MINOR(inode->i_rdev)) 381 { 382 case WATCHDOG_MINOR: 383 if(test_and_set_bit(0, &wdt_is_open)) 384 return -EBUSY; 385 /* 386 * Activate 387 */ 388 389 wdt_is_open=1; 390 inb_p(WDT_DC); /* Disable */ 391 wdt_ctr_mode(0,3); 392 wdt_ctr_mode(1,2); 393 wdt_ctr_mode(2,0); 394 wdt_ctr_load(0, 8948); /* count at 100Hz */ 395 wdt_ctr_load(1,wd_margin); /* Timeout 120 seconds */ 396 wdt_ctr_load(2,65535); 397 outb_p(0, WDT_DC); /* Enable */ 398 return 0; 399 case TEMP_MINOR: 400 return 0; 401 default: 402 return -ENODEV; 403 } 404} 405 406/** 407 * wdt_close: 408 * @inode: inode to board 409 * @file: file handle to board 410 * 411 * The watchdog has a configurable API. There is a religious dispute 412 * between people who want their watchdog to be able to shut down and 413 * those who want to be sure if the watchdog manager dies the machine 414 * reboots. In the former case we disable the counters, in the latter 415 * case you have to open it again very soon. 416 */ 417 418static int wdt_release(struct inode *inode, struct file *file) 419{ 420 if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) 421 { 422 if (expect_close) { 423 inb_p(WDT_DC); /* Disable counters */ 424 wdt_ctr_load(2,0); /* 0 length reset pulses now */ 425 } else { 426 printk(KERN_CRIT "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); 427 } 428 clear_bit(0, &wdt_is_open); 429 } 430 return 0; 431} 432 433/** 434 * notify_sys: 435 * @this: our notifier block 436 * @code: the event being reported 437 * @unused: unused 438 * 439 * Our notifier is called on system shutdowns. We want to turn the card 440 * off at reboot otherwise the machine will reboot again during memory 441 * test or worse yet during the following fsck. This would suck, in fact 442 * trust me - if it happens it does suck. 443 */ 444 445static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 446 void *unused) 447{ 448 if(code==SYS_DOWN || code==SYS_HALT) 449 { 450 /* Turn the card off */ 451 inb_p(WDT_DC); 452 wdt_ctr_load(2,0); 453 } 454 return NOTIFY_DONE; 455} 456 457/* 458 * Kernel Interfaces 459 */ 460 461 462static struct file_operations wdt_fops = { 463 owner: THIS_MODULE, 464 llseek: no_llseek, 465 read: wdt_read, 466 write: wdt_write, 467 ioctl: wdt_ioctl, 468 open: wdt_open, 469 release: wdt_release, 470}; 471 472static struct miscdevice wdt_miscdev= 473{ 474 WATCHDOG_MINOR, 475 "watchdog", 476 &wdt_fops 477}; 478 479#ifdef CONFIG_WDT_501 480static struct miscdevice temp_miscdev= 481{ 482 TEMP_MINOR, 483 "temperature", 484 &wdt_fops 485}; 486#endif 487 488/* 489 * The WDT card needs to learn about soft shutdowns in order to 490 * turn the timebomb registers off. 491 */ 492 493static struct notifier_block wdt_notifier= 494{ 495 wdt_notify_sys, 496 NULL, 497 0 498}; 499 500/** 501 * cleanup_module: 502 * 503 * Unload the watchdog. You cannot do this with any file handles open. 504 * If your watchdog is set to continue ticking on close and you unload 505 * it, well it keeps ticking. We won't get the interrupt but the board 506 * will not touch PC memory so all is fine. You just have to load a new 507 * module in 60 seconds or reboot. 508 */ 509 510static void __exit wdt_exit(void) 511{ 512 misc_deregister(&wdt_miscdev); 513#ifdef CONFIG_WDT_501 514 misc_deregister(&temp_miscdev); 515#endif 516 unregister_reboot_notifier(&wdt_notifier); 517 release_region(io,8); 518 free_irq(irq, NULL); 519} 520 521/** 522 * wdt_init: 523 * 524 * Set up the WDT watchdog board. All we have to do is grab the 525 * resources we require and bitch if anyone beat us to them. 526 * The open() function will actually kick the board off. 527 */ 528 529static int __init wdt_init(void) 530{ 531 int ret; 532 533 ret = misc_register(&wdt_miscdev); 534 if (ret) { 535 printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR); 536 goto out; 537 } 538 ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL); 539 if(ret) { 540 printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); 541 goto outmisc; 542 } 543 if (!request_region(io, 8, "wdt501p")) { 544 printk(KERN_ERR "wdt: IO %X is not free.\n", io); 545 ret = -EBUSY; 546 goto outirq; 547 } 548 ret = register_reboot_notifier(&wdt_notifier); 549 if(ret) { 550 printk(KERN_ERR "wdt: can't register reboot notifier (err=%d)\n", ret); 551 goto outreg; 552 } 553 554#ifdef CONFIG_WDT_501 555 ret = misc_register(&temp_miscdev); 556 if (ret) { 557 printk(KERN_ERR "wdt: can't misc_register (temp) on minor=%d\n", TEMP_MINOR); 558 goto outrbt; 559 } 560#endif 561 562 ret = 0; 563 printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io, irq); 564out: 565 return ret; 566 567#ifdef CONFIG_WDT_501 568outrbt: 569 unregister_reboot_notifier(&wdt_notifier); 570#endif 571 572outreg: 573 release_region(io,8); 574outirq: 575 free_irq(irq, NULL); 576outmisc: 577 misc_deregister(&wdt_miscdev); 578 goto out; 579} 580 581module_init(wdt_init); 582module_exit(wdt_exit); 583 584MODULE_AUTHOR("Alan Cox"); 585MODULE_DESCRIPTION("Driver for ISA ICS watchdog cards (WDT500/501)"); 586MODULE_LICENSE("GPL"); 587EXPORT_NO_SYMBOLS; 588