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