linux/drivers/watchdog/shwdt.c
<<
>>
Prefs
   1/*
   2 * drivers/char/watchdog/shwdt.c
   3 *
   4 * Watchdog driver for integrated watchdog in the SuperH processors.
   5 *
   6 * Copyright (C) 2001, 2002, 2003 Paul Mundt <lethal@linux-sh.org>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License as published by the
  10 * Free Software Foundation; either version 2 of the License, or (at your
  11 * option) any later version.
  12 *
  13 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
  14 *     Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  15 *
  16 * 19-Apr-2002 Rob Radez <rob@osinvestor.com>
  17 *     Added expect close support, made emulated timeout runtime changeable
  18 *     general cleanups, add some ioctls
  19 */
  20#include <linux/module.h>
  21#include <linux/moduleparam.h>
  22#include <linux/init.h>
  23#include <linux/types.h>
  24#include <linux/miscdevice.h>
  25#include <linux/watchdog.h>
  26#include <linux/reboot.h>
  27#include <linux/notifier.h>
  28#include <linux/ioport.h>
  29#include <linux/fs.h>
  30#include <linux/mm.h>
  31#include <linux/io.h>
  32#include <linux/uaccess.h>
  33#include <asm/watchdog.h>
  34
  35#define PFX "shwdt: "
  36
  37/*
  38 * Default clock division ratio is 5.25 msecs. For an additional table of
  39 * values, consult the asm-sh/watchdog.h. Overload this at module load
  40 * time.
  41 *
  42 * In order for this to work reliably we need to have HZ set to 1000 or
  43 * something quite higher than 100 (or we need a proper high-res timer
  44 * implementation that will deal with this properly), otherwise the 10ms
  45 * resolution of a jiffy is enough to trigger the overflow. For things like
  46 * the SH-4 and SH-5, this isn't necessarily that big of a problem, though
  47 * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
  48 * necssary.
  49 *
  50 * As a result of this timing problem, the only modes that are particularly
  51 * feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms
  52 * overflow periods respectively.
  53 *
  54 * Also, since we can't really expect userspace to be responsive enough
  55 * before the overflow happens, we maintain two separate timers .. One in
  56 * the kernel for clearing out WOVF every 2ms or so (again, this depends on
  57 * HZ == 1000), and another for monitoring userspace writes to the WDT device.
  58 *
  59 * As such, we currently use a configurable heartbeat interval which defaults
  60 * to 30s. In this case, the userspace daemon is only responsible for periodic
  61 * writes to the device before the next heartbeat is scheduled. If the daemon
  62 * misses its deadline, the kernel timer will allow the WDT to overflow.
  63 */
  64static int clock_division_ratio = WTCSR_CKS_4096;
  65
  66#define next_ping_period(cks)   msecs_to_jiffies(cks - 4)
  67
  68static void sh_wdt_ping(unsigned long data);
  69
  70static unsigned long shwdt_is_open;
  71static const struct watchdog_info sh_wdt_info;
  72static char shwdt_expect_close;
  73static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0);
  74static unsigned long next_heartbeat;
  75static DEFINE_SPINLOCK(shwdt_lock);
  76
  77#define WATCHDOG_HEARTBEAT 30                   /* 30 sec default heartbeat */
  78static int heartbeat = WATCHDOG_HEARTBEAT;      /* in seconds */
  79
  80static int nowayout = WATCHDOG_NOWAYOUT;
  81
  82/**
  83 *      sh_wdt_start - Start the Watchdog
  84 *
  85 *      Starts the watchdog.
  86 */
  87static void sh_wdt_start(void)
  88{
  89        __u8 csr;
  90        unsigned long flags;
  91
  92        spin_lock_irqsave(&shwdt_lock, flags);
  93
  94        next_heartbeat = jiffies + (heartbeat * HZ);
  95        mod_timer(&timer, next_ping_period(clock_division_ratio));
  96
  97        csr = sh_wdt_read_csr();
  98        csr |= WTCSR_WT | clock_division_ratio;
  99        sh_wdt_write_csr(csr);
 100
 101        sh_wdt_write_cnt(0);
 102
 103        /*
 104         * These processors have a bit of an inconsistent initialization
 105         * process.. starting with SH-3, RSTS was moved to WTCSR, and the
 106         * RSTCSR register was removed.
 107         *
 108         * On the SH-2 however, in addition with bits being in different
 109         * locations, we must deal with RSTCSR outright..
 110         */
 111        csr = sh_wdt_read_csr();
 112        csr |= WTCSR_TME;
 113        csr &= ~WTCSR_RSTS;
 114        sh_wdt_write_csr(csr);
 115
 116#ifdef CONFIG_CPU_SH2
 117        /*
 118         * Whoever came up with the RSTCSR semantics must've been smoking
 119         * some of the good stuff, since in addition to the WTCSR/WTCNT write
 120         * brain-damage, it's managed to fuck things up one step further..
 121         *
 122         * If we need to clear the WOVF bit, the upper byte has to be 0xa5..
 123         * but if we want to touch RSTE or RSTS, the upper byte has to be
 124         * 0x5a..
 125         */
 126        csr = sh_wdt_read_rstcsr();
 127        csr &= ~RSTCSR_RSTS;
 128        sh_wdt_write_rstcsr(csr);
 129#endif
 130        spin_unlock_irqrestore(&shwdt_lock, flags);
 131}
 132
 133/**
 134 *      sh_wdt_stop - Stop the Watchdog
 135 *      Stops the watchdog.
 136 */
 137static void sh_wdt_stop(void)
 138{
 139        __u8 csr;
 140        unsigned long flags;
 141
 142        spin_lock_irqsave(&shwdt_lock, flags);
 143
 144        del_timer(&timer);
 145
 146        csr = sh_wdt_read_csr();
 147        csr &= ~WTCSR_TME;
 148        sh_wdt_write_csr(csr);
 149        spin_unlock_irqrestore(&shwdt_lock, flags);
 150}
 151
 152/**
 153 *      sh_wdt_keepalive - Keep the Userspace Watchdog Alive
 154 *      The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
 155 */
 156static inline void sh_wdt_keepalive(void)
 157{
 158        unsigned long flags;
 159
 160        spin_lock_irqsave(&shwdt_lock, flags);
 161        next_heartbeat = jiffies + (heartbeat * HZ);
 162        spin_unlock_irqrestore(&shwdt_lock, flags);
 163}
 164
 165/**
 166 *      sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
 167 *      Set the Userspace Watchdog heartbeat
 168 */
 169static int sh_wdt_set_heartbeat(int t)
 170{
 171        unsigned long flags;
 172
 173        if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
 174                return -EINVAL;
 175
 176        spin_lock_irqsave(&shwdt_lock, flags);
 177        heartbeat = t;
 178        spin_unlock_irqrestore(&shwdt_lock, flags);
 179        return 0;
 180}
 181
 182/**
 183 *      sh_wdt_ping - Ping the Watchdog
 184 *      @data: Unused
 185 *
 186 *      Clears overflow bit, resets timer counter.
 187 */
 188static void sh_wdt_ping(unsigned long data)
 189{
 190        unsigned long flags;
 191
 192        spin_lock_irqsave(&shwdt_lock, flags);
 193        if (time_before(jiffies, next_heartbeat)) {
 194                __u8 csr;
 195
 196                csr = sh_wdt_read_csr();
 197                csr &= ~WTCSR_IOVF;
 198                sh_wdt_write_csr(csr);
 199
 200                sh_wdt_write_cnt(0);
 201
 202                mod_timer(&timer, next_ping_period(clock_division_ratio));
 203        } else
 204                printk(KERN_WARNING PFX "Heartbeat lost! Will not ping "
 205                       "the watchdog\n");
 206        spin_unlock_irqrestore(&shwdt_lock, flags);
 207}
 208
 209/**
 210 *      sh_wdt_open - Open the Device
 211 *      @inode: inode of device
 212 *      @file: file handle of device
 213 *
 214 *      Watchdog device is opened and started.
 215 */
 216static int sh_wdt_open(struct inode *inode, struct file *file)
 217{
 218        if (test_and_set_bit(0, &shwdt_is_open))
 219                return -EBUSY;
 220        if (nowayout)
 221                __module_get(THIS_MODULE);
 222
 223        sh_wdt_start();
 224
 225        return nonseekable_open(inode, file);
 226}
 227
 228/**
 229 *      sh_wdt_close - Close the Device
 230 *      @inode: inode of device
 231 *      @file: file handle of device
 232 *
 233 *      Watchdog device is closed and stopped.
 234 */
 235static int sh_wdt_close(struct inode *inode, struct file *file)
 236{
 237        if (shwdt_expect_close == 42) {
 238                sh_wdt_stop();
 239        } else {
 240                printk(KERN_CRIT PFX "Unexpected close, not "
 241                       "stopping watchdog!\n");
 242                sh_wdt_keepalive();
 243        }
 244
 245        clear_bit(0, &shwdt_is_open);
 246        shwdt_expect_close = 0;
 247
 248        return 0;
 249}
 250
 251/**
 252 *      sh_wdt_write - Write to Device
 253 *      @file: file handle of device
 254 *      @buf: buffer to write
 255 *      @count: length of buffer
 256 *      @ppos: offset
 257 *
 258 *      Pings the watchdog on write.
 259 */
 260static ssize_t sh_wdt_write(struct file *file, const char *buf,
 261                            size_t count, loff_t *ppos)
 262{
 263        if (count) {
 264                if (!nowayout) {
 265                        size_t i;
 266
 267                        shwdt_expect_close = 0;
 268
 269                        for (i = 0; i != count; i++) {
 270                                char c;
 271                                if (get_user(c, buf + i))
 272                                        return -EFAULT;
 273                                if (c == 'V')
 274                                        shwdt_expect_close = 42;
 275                        }
 276                }
 277                sh_wdt_keepalive();
 278        }
 279
 280        return count;
 281}
 282
 283/**
 284 *      sh_wdt_mmap - map WDT/CPG registers into userspace
 285 *      @file: file structure for the device
 286 *      @vma: VMA to map the registers into
 287 *
 288 *      A simple mmap() implementation for the corner cases where the counter
 289 *      needs to be mapped in userspace directly. Due to the relatively small
 290 *      size of the area, neighbouring registers not necessarily tied to the
 291 *      CPG will also be accessible through the register page, so this remains
 292 *      configurable for users that really know what they're doing.
 293 *
 294 *      Additionaly, the register page maps in the CPG register base relative
 295 *      to the nearest page-aligned boundary, which requires that userspace do
 296 *      the appropriate CPU subtype math for calculating the page offset for
 297 *      the counter value.
 298 */
 299static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma)
 300{
 301        int ret = -ENOSYS;
 302
 303#ifdef CONFIG_SH_WDT_MMAP
 304        unsigned long addr;
 305
 306        /* Only support the simple cases where we map in a register page. */
 307        if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
 308                return -EINVAL;
 309
 310        /*
 311         * Pick WTCNT as the start, it's usually the first register after the
 312         * FRQCR, and neither one are generally page-aligned out of the box.
 313         */
 314        addr = WTCNT & ~(PAGE_SIZE - 1);
 315
 316        vma->vm_flags |= VM_IO;
 317        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 318
 319        if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
 320                               PAGE_SIZE, vma->vm_page_prot)) {
 321                printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n",
 322                       __func__);
 323                return -EAGAIN;
 324        }
 325
 326        ret = 0;
 327#endif
 328
 329        return ret;
 330}
 331
 332/**
 333 *      sh_wdt_ioctl - Query Device
 334 *      @file: file handle of device
 335 *      @cmd: watchdog command
 336 *      @arg: argument
 337 *
 338 *      Query basic information from the device or ping it, as outlined by the
 339 *      watchdog API.
 340 */
 341static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
 342                                                        unsigned long arg)
 343{
 344        int new_heartbeat;
 345        int options, retval = -EINVAL;
 346
 347        switch (cmd) {
 348        case WDIOC_GETSUPPORT:
 349                return copy_to_user((struct watchdog_info *)arg,
 350                          &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
 351        case WDIOC_GETSTATUS:
 352        case WDIOC_GETBOOTSTATUS:
 353                return put_user(0, (int *)arg);
 354        case WDIOC_SETOPTIONS:
 355                if (get_user(options, (int *)arg))
 356                        return -EFAULT;
 357
 358                if (options & WDIOS_DISABLECARD) {
 359                        sh_wdt_stop();
 360                        retval = 0;
 361                }
 362
 363                if (options & WDIOS_ENABLECARD) {
 364                        sh_wdt_start();
 365                        retval = 0;
 366                }
 367
 368                return retval;
 369        case WDIOC_KEEPALIVE:
 370                sh_wdt_keepalive();
 371                return 0;
 372        case WDIOC_SETTIMEOUT:
 373                if (get_user(new_heartbeat, (int *)arg))
 374                        return -EFAULT;
 375
 376                if (sh_wdt_set_heartbeat(new_heartbeat))
 377                        return -EINVAL;
 378
 379                sh_wdt_keepalive();
 380                /* Fall */
 381        case WDIOC_GETTIMEOUT:
 382                return put_user(heartbeat, (int *)arg);
 383        default:
 384                return -ENOTTY;
 385        }
 386        return 0;
 387}
 388
 389/**
 390 *      sh_wdt_notify_sys - Notifier Handler
 391 *      @this: notifier block
 392 *      @code: notifier event
 393 *      @unused: unused
 394 *
 395 *      Handles specific events, such as turning off the watchdog during a
 396 *      shutdown event.
 397 */
 398static int sh_wdt_notify_sys(struct notifier_block *this,
 399                             unsigned long code, void *unused)
 400{
 401        if (code == SYS_DOWN || code == SYS_HALT)
 402                sh_wdt_stop();
 403
 404        return NOTIFY_DONE;
 405}
 406
 407static const struct file_operations sh_wdt_fops = {
 408        .owner          = THIS_MODULE,
 409        .llseek         = no_llseek,
 410        .write          = sh_wdt_write,
 411        .unlocked_ioctl = sh_wdt_ioctl,
 412        .open           = sh_wdt_open,
 413        .release        = sh_wdt_close,
 414        .mmap           = sh_wdt_mmap,
 415};
 416
 417static const struct watchdog_info sh_wdt_info = {
 418        .options                = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
 419                                  WDIOF_MAGICCLOSE,
 420        .firmware_version       = 1,
 421        .identity               = "SH WDT",
 422};
 423
 424static struct notifier_block sh_wdt_notifier = {
 425        .notifier_call          = sh_wdt_notify_sys,
 426};
 427
 428static struct miscdevice sh_wdt_miscdev = {
 429        .minor          = WATCHDOG_MINOR,
 430        .name           = "watchdog",
 431        .fops           = &sh_wdt_fops,
 432};
 433
 434/**
 435 *      sh_wdt_init - Initialize module
 436 *      Registers the device and notifier handler. Actual device
 437 *      initialization is handled by sh_wdt_open().
 438 */
 439static int __init sh_wdt_init(void)
 440{
 441        int rc;
 442
 443        if (clock_division_ratio < 0x5 || clock_division_ratio > 0x7) {
 444                clock_division_ratio = WTCSR_CKS_4096;
 445                printk(KERN_INFO PFX
 446                  "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
 447                                clock_division_ratio);
 448        }
 449
 450        rc = sh_wdt_set_heartbeat(heartbeat);
 451        if (unlikely(rc)) {
 452                heartbeat = WATCHDOG_HEARTBEAT;
 453                printk(KERN_INFO PFX
 454                        "heartbeat value must be 1<=x<=3600, using %d\n",
 455                                                                heartbeat);
 456        }
 457
 458        rc = register_reboot_notifier(&sh_wdt_notifier);
 459        if (unlikely(rc)) {
 460                printk(KERN_ERR PFX
 461                        "Can't register reboot notifier (err=%d)\n", rc);
 462                return rc;
 463        }
 464
 465        rc = misc_register(&sh_wdt_miscdev);
 466        if (unlikely(rc)) {
 467                printk(KERN_ERR PFX
 468                        "Can't register miscdev on minor=%d (err=%d)\n",
 469                                                sh_wdt_miscdev.minor, rc);
 470                unregister_reboot_notifier(&sh_wdt_notifier);
 471                return rc;
 472        }
 473
 474        printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
 475                heartbeat, nowayout);
 476
 477        return 0;
 478}
 479
 480/**
 481 *      sh_wdt_exit - Deinitialize module
 482 *      Unregisters the device and notifier handler. Actual device
 483 *      deinitialization is handled by sh_wdt_close().
 484 */
 485static void __exit sh_wdt_exit(void)
 486{
 487        misc_deregister(&sh_wdt_miscdev);
 488        unregister_reboot_notifier(&sh_wdt_notifier);
 489}
 490
 491MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
 492MODULE_DESCRIPTION("SuperH watchdog driver");
 493MODULE_LICENSE("GPL");
 494MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 495
 496module_param(clock_division_ratio, int, 0);
 497MODULE_PARM_DESC(clock_division_ratio,
 498        "Clock division ratio. Valid ranges are from 0x5 (1.31ms) "
 499        "to 0x7 (5.25ms). (default=" __MODULE_STRING(WTCSR_CKS_4096) ")");
 500
 501module_param(heartbeat, int, 0);
 502MODULE_PARM_DESC(heartbeat,
 503        "Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
 504                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 505
 506module_param(nowayout, int, 0);
 507MODULE_PARM_DESC(nowayout,
 508        "Watchdog cannot be stopped once started (default="
 509                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 510
 511module_init(sh_wdt_init);
 512module_exit(sh_wdt_exit);
 513