root/drivers/watchdog/ixp4xx_wdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wdt_enable
  2. wdt_disable
  3. ixp4xx_wdt_open
  4. ixp4xx_wdt_write
  5. ixp4xx_wdt_ioctl
  6. ixp4xx_wdt_release
  7. ixp4xx_wdt_init
  8. ixp4xx_wdt_exit

   1 /*
   2  * drivers/char/watchdog/ixp4xx_wdt.c
   3  *
   4  * Watchdog driver for Intel IXP4xx network processors
   5  *
   6  * Author: Deepak Saxena <dsaxena@plexity.net>
   7  *
   8  * Copyright 2004 (c) MontaVista, Software, Inc.
   9  * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
  10  *
  11  * This file is licensed under  the terms of the GNU General Public
  12  * License version 2. This program is licensed "as is" without any
  13  * warranty of any kind, whether express or implied.
  14  */
  15 
  16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  17 
  18 #include <linux/module.h>
  19 #include <linux/moduleparam.h>
  20 #include <linux/types.h>
  21 #include <linux/kernel.h>
  22 #include <linux/fs.h>
  23 #include <linux/miscdevice.h>
  24 #include <linux/of.h>
  25 #include <linux/watchdog.h>
  26 #include <linux/init.h>
  27 #include <linux/bitops.h>
  28 #include <linux/uaccess.h>
  29 #include <mach/hardware.h>
  30 
  31 static bool nowayout = WATCHDOG_NOWAYOUT;
  32 static int heartbeat = 60;      /* (secs) Default is 1 minute */
  33 static unsigned long wdt_status;
  34 static unsigned long boot_status;
  35 static DEFINE_SPINLOCK(wdt_lock);
  36 
  37 #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
  38 
  39 #define WDT_IN_USE              0
  40 #define WDT_OK_TO_CLOSE         1
  41 
  42 static void wdt_enable(void)
  43 {
  44         spin_lock(&wdt_lock);
  45         *IXP4XX_OSWK = IXP4XX_WDT_KEY;
  46         *IXP4XX_OSWE = 0;
  47         *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
  48         *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
  49         *IXP4XX_OSWK = 0;
  50         spin_unlock(&wdt_lock);
  51 }
  52 
  53 static void wdt_disable(void)
  54 {
  55         spin_lock(&wdt_lock);
  56         *IXP4XX_OSWK = IXP4XX_WDT_KEY;
  57         *IXP4XX_OSWE = 0;
  58         *IXP4XX_OSWK = 0;
  59         spin_unlock(&wdt_lock);
  60 }
  61 
  62 static int ixp4xx_wdt_open(struct inode *inode, struct file *file)
  63 {
  64         if (test_and_set_bit(WDT_IN_USE, &wdt_status))
  65                 return -EBUSY;
  66 
  67         clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  68         wdt_enable();
  69         return stream_open(inode, file);
  70 }
  71 
  72 static ssize_t
  73 ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
  74 {
  75         if (len) {
  76                 if (!nowayout) {
  77                         size_t i;
  78 
  79                         clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  80 
  81                         for (i = 0; i != len; i++) {
  82                                 char c;
  83 
  84                                 if (get_user(c, data + i))
  85                                         return -EFAULT;
  86                                 if (c == 'V')
  87                                         set_bit(WDT_OK_TO_CLOSE, &wdt_status);
  88                         }
  89                 }
  90                 wdt_enable();
  91         }
  92         return len;
  93 }
  94 
  95 static const struct watchdog_info ident = {
  96         .options        = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
  97                           WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
  98         .identity       = "IXP4xx Watchdog",
  99 };
 100 
 101 
 102 static long ixp4xx_wdt_ioctl(struct file *file, unsigned int cmd,
 103                                                         unsigned long arg)
 104 {
 105         int ret = -ENOTTY;
 106         int time;
 107 
 108         switch (cmd) {
 109         case WDIOC_GETSUPPORT:
 110                 ret = copy_to_user((struct watchdog_info *)arg, &ident,
 111                                    sizeof(ident)) ? -EFAULT : 0;
 112                 break;
 113 
 114         case WDIOC_GETSTATUS:
 115                 ret = put_user(0, (int *)arg);
 116                 break;
 117 
 118         case WDIOC_GETBOOTSTATUS:
 119                 ret = put_user(boot_status, (int *)arg);
 120                 break;
 121 
 122         case WDIOC_KEEPALIVE:
 123                 wdt_enable();
 124                 ret = 0;
 125                 break;
 126 
 127         case WDIOC_SETTIMEOUT:
 128                 ret = get_user(time, (int *)arg);
 129                 if (ret)
 130                         break;
 131 
 132                 if (time <= 0 || time > 60) {
 133                         ret = -EINVAL;
 134                         break;
 135                 }
 136 
 137                 heartbeat = time;
 138                 wdt_enable();
 139                 /* Fall through */
 140 
 141         case WDIOC_GETTIMEOUT:
 142                 ret = put_user(heartbeat, (int *)arg);
 143                 break;
 144         }
 145         return ret;
 146 }
 147 
 148 static int ixp4xx_wdt_release(struct inode *inode, struct file *file)
 149 {
 150         if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
 151                 wdt_disable();
 152         else
 153                 pr_crit("Device closed unexpectedly - timer will not stop\n");
 154         clear_bit(WDT_IN_USE, &wdt_status);
 155         clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 156 
 157         return 0;
 158 }
 159 
 160 
 161 static const struct file_operations ixp4xx_wdt_fops = {
 162         .owner          = THIS_MODULE,
 163         .llseek         = no_llseek,
 164         .write          = ixp4xx_wdt_write,
 165         .unlocked_ioctl = ixp4xx_wdt_ioctl,
 166         .open           = ixp4xx_wdt_open,
 167         .release        = ixp4xx_wdt_release,
 168 };
 169 
 170 static struct miscdevice ixp4xx_wdt_miscdev = {
 171         .minor          = WATCHDOG_MINOR,
 172         .name           = "watchdog",
 173         .fops           = &ixp4xx_wdt_fops,
 174 };
 175 
 176 static int __init ixp4xx_wdt_init(void)
 177 {
 178         int ret;
 179 
 180         /*
 181          * FIXME: we bail out on device tree boot but this really needs
 182          * to be fixed in a nicer way: this registers the MDIO bus before
 183          * even matching the driver infrastructure, we should only probe
 184          * detected hardware.
 185          */
 186         if (of_have_populated_dt())
 187                 return -ENODEV;
 188         if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
 189                 pr_err("Rev. A0 IXP42x CPU detected - watchdog disabled\n");
 190 
 191                 return -ENODEV;
 192         }
 193         boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
 194                         WDIOF_CARDRESET : 0;
 195         ret = misc_register(&ixp4xx_wdt_miscdev);
 196         if (ret == 0)
 197                 pr_info("timer heartbeat %d sec\n", heartbeat);
 198         return ret;
 199 }
 200 
 201 static void __exit ixp4xx_wdt_exit(void)
 202 {
 203         misc_deregister(&ixp4xx_wdt_miscdev);
 204 }
 205 
 206 
 207 module_init(ixp4xx_wdt_init);
 208 module_exit(ixp4xx_wdt_exit);
 209 
 210 MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
 211 MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
 212 
 213 module_param(heartbeat, int, 0);
 214 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
 215 
 216 module_param(nowayout, bool, 0);
 217 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 218 
 219 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */