linux-bk/drivers/char/watchdog/ixp2000_wdt.c
<<
>>
Prefs
   1/*
   2 * drivers/watchdog/ixp2000_wdt.c
   3 *
   4 * Watchdog driver for Intel IXP2000 network processors
   5 *
   6 * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
   7 * The original version carries these notices:
   8 *
   9 * Author: Deepak Saxena <dsaxena@plexity.net>
  10 *
  11 * Copyright 2004 (c) MontaVista, Software, Inc.
  12 * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
  13 *
  14 * This file is licensed under  the terms of the GNU General Public
  15 * License version 2. This program is licensed "as is" without any
  16 * warranty of any kind, whether express or implied.
  17 */
  18
  19#include <linux/config.h>
  20#include <linux/module.h>
  21#include <linux/moduleparam.h>
  22#include <linux/types.h>
  23#include <linux/kernel.h>
  24#include <linux/fs.h>
  25#include <linux/miscdevice.h>
  26#include <linux/watchdog.h>
  27#include <linux/init.h>
  28#include <linux/bitops.h>
  29
  30#include <asm/hardware.h>
  31#include <asm/uaccess.h>
  32
  33#ifdef CONFIG_WATCHDOG_NOWAYOUT
  34static int nowayout = 1;
  35#else
  36static int nowayout = 0;
  37#endif
  38static unsigned int heartbeat = 60;     /* (secs) Default is 1 minute */
  39static unsigned long wdt_status;
  40
  41#define WDT_IN_USE              0
  42#define WDT_OK_TO_CLOSE         1
  43
  44static unsigned long wdt_tick_rate;
  45
  46static void
  47wdt_enable(void)
  48{
  49        ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
  50        ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
  51        ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
  52        ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
  53}
  54
  55static void
  56wdt_disable(void)
  57{
  58        ixp2000_reg_write(IXP2000_T4_CTL, 0);
  59}
  60
  61static void
  62wdt_keepalive(void)
  63{
  64        ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
  65}
  66
  67static int
  68ixp2000_wdt_open(struct inode *inode, struct file *file)
  69{
  70        if (test_and_set_bit(WDT_IN_USE, &wdt_status))
  71                return -EBUSY;
  72
  73        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  74
  75        wdt_enable();
  76
  77        return nonseekable_open(inode, file);
  78}
  79
  80static ssize_t
  81ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
  82{
  83        if (len) {
  84                if (!nowayout) {
  85                        size_t i;
  86
  87                        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  88
  89                        for (i = 0; i != len; i++) {
  90                                char c;
  91
  92                                if (get_user(c, data + i))
  93                                        return -EFAULT;
  94                                if (c == 'V')
  95                                        set_bit(WDT_OK_TO_CLOSE, &wdt_status);
  96                        }
  97                }
  98                wdt_keepalive();
  99        }
 100
 101        return len;
 102}
 103
 104
 105static struct watchdog_info ident = {
 106        .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
 107                                WDIOF_KEEPALIVEPING,
 108        .identity       = "IXP2000 Watchdog",
 109};
 110
 111static int
 112ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 113                        unsigned long arg)
 114{
 115        int ret = -ENOIOCTLCMD;
 116        int time;
 117
 118        switch (cmd) {
 119        case WDIOC_GETSUPPORT:
 120                ret = copy_to_user((struct watchdog_info *)arg, &ident,
 121                                   sizeof(ident)) ? -EFAULT : 0;
 122                break;
 123
 124        case WDIOC_GETSTATUS:
 125                ret = put_user(0, (int *)arg);
 126                break;
 127
 128        case WDIOC_GETBOOTSTATUS:
 129                ret = put_user(0, (int *)arg);
 130                break;
 131
 132        case WDIOC_SETTIMEOUT:
 133                ret = get_user(time, (int *)arg);
 134                if (ret)
 135                        break;
 136
 137                if (time <= 0 || time > 60) {
 138                        ret = -EINVAL;
 139                        break;
 140                }
 141
 142                heartbeat = time;
 143                wdt_keepalive();
 144                /* Fall through */
 145
 146        case WDIOC_GETTIMEOUT:
 147                ret = put_user(heartbeat, (int *)arg);
 148                break;
 149
 150        case WDIOC_KEEPALIVE:
 151                wdt_enable();
 152                ret = 0;
 153                break;
 154        }
 155
 156        return ret;
 157}
 158
 159static int
 160ixp2000_wdt_release(struct inode *inode, struct file *file)
 161{
 162        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
 163                wdt_disable();
 164        } else {
 165                printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
 166                                        "timer will not stop\n");
 167        }
 168
 169        clear_bit(WDT_IN_USE, &wdt_status);
 170        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 171
 172        return 0;
 173}
 174
 175
 176static struct file_operations ixp2000_wdt_fops =
 177{
 178        .owner          = THIS_MODULE,
 179        .llseek         = no_llseek,
 180        .write          = ixp2000_wdt_write,
 181        .ioctl          = ixp2000_wdt_ioctl,
 182        .open           = ixp2000_wdt_open,
 183        .release        = ixp2000_wdt_release,
 184};
 185
 186static struct miscdevice ixp2000_wdt_miscdev =
 187{
 188        .minor          = WATCHDOG_MINOR,
 189        .name           = "IXP2000 Watchdog",
 190        .fops           = &ixp2000_wdt_fops,
 191};
 192
 193static int __init ixp2000_wdt_init(void)
 194{
 195        wdt_tick_rate = (*IXP2000_T1_CLD * HZ)/ 256;;
 196
 197        return misc_register(&ixp2000_wdt_miscdev);
 198}
 199
 200static void __exit ixp2000_wdt_exit(void)
 201{
 202        misc_deregister(&ixp2000_wdt_miscdev);
 203}
 204
 205module_init(ixp2000_wdt_init);
 206module_exit(ixp2000_wdt_exit);
 207
 208MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">);
 209MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
 210
 211module_param(heartbeat, int, 0);
 212MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
 213
 214module_param(nowayout, int, 0);
 215MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 216
 217MODULE_LICENSE("GPL");
 218MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 219
 220
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.