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