root/drivers/watchdog/wdt285.c

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

DEFINITIONS

This source file includes following definitions.
  1. watchdog_fire
  2. watchdog_ping
  3. watchdog_open
  4. watchdog_release
  5. watchdog_write
  6. watchdog_ioctl
  7. footbridge_watchdog_init
  8. footbridge_watchdog_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *      Intel 21285 watchdog driver
   4  *      Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998
   5  *
   6  *      based on
   7  *
   8  *      SoftDog 0.05:   A Software Watchdog Device
   9  *
  10  *      (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  11  *                                              All Rights Reserved.
  12  */
  13 
  14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15 
  16 #include <linux/module.h>
  17 #include <linux/moduleparam.h>
  18 #include <linux/types.h>
  19 #include <linux/kernel.h>
  20 #include <linux/fs.h>
  21 #include <linux/mm.h>
  22 #include <linux/miscdevice.h>
  23 #include <linux/watchdog.h>
  24 #include <linux/reboot.h>
  25 #include <linux/init.h>
  26 #include <linux/interrupt.h>
  27 #include <linux/uaccess.h>
  28 #include <linux/irq.h>
  29 #include <mach/hardware.h>
  30 
  31 #include <asm/mach-types.h>
  32 #include <asm/system_info.h>
  33 #include <asm/hardware/dec21285.h>
  34 
  35 /*
  36  * Define this to stop the watchdog actually rebooting the machine.
  37  */
  38 #undef ONLY_TESTING
  39 
  40 static unsigned int soft_margin = 60;           /* in seconds */
  41 static unsigned int reload;
  42 static unsigned long timer_alive;
  43 
  44 #ifdef ONLY_TESTING
  45 /*
  46  *      If the timer expires..
  47  */
  48 static void watchdog_fire(int irq, void *dev_id)
  49 {
  50         pr_crit("Would Reboot\n");
  51         *CSR_TIMER4_CNTL = 0;
  52         *CSR_TIMER4_CLR = 0;
  53 }
  54 #endif
  55 
  56 /*
  57  *      Refresh the timer.
  58  */
  59 static void watchdog_ping(void)
  60 {
  61         *CSR_TIMER4_LOAD = reload;
  62 }
  63 
  64 /*
  65  *      Allow only one person to hold it open
  66  */
  67 static int watchdog_open(struct inode *inode, struct file *file)
  68 {
  69         int ret;
  70 
  71         if (*CSR_SA110_CNTL & (1 << 13))
  72                 return -EBUSY;
  73 
  74         if (test_and_set_bit(1, &timer_alive))
  75                 return -EBUSY;
  76 
  77         reload = soft_margin * (mem_fclk_21285 / 256);
  78 
  79         *CSR_TIMER4_CLR = 0;
  80         watchdog_ping();
  81         *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD
  82                 | TIMER_CNTL_DIV256;
  83 
  84 #ifdef ONLY_TESTING
  85         ret = request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL);
  86         if (ret) {
  87                 *CSR_TIMER4_CNTL = 0;
  88                 clear_bit(1, &timer_alive);
  89         }
  90 #else
  91         /*
  92          * Setting this bit is irreversible; once enabled, there is
  93          * no way to disable the watchdog.
  94          */
  95         *CSR_SA110_CNTL |= 1 << 13;
  96 
  97         ret = 0;
  98 #endif
  99         stream_open(inode, file);
 100         return ret;
 101 }
 102 
 103 /*
 104  *      Shut off the timer.
 105  *      Note: if we really have enabled the watchdog, there
 106  *      is no way to turn off.
 107  */
 108 static int watchdog_release(struct inode *inode, struct file *file)
 109 {
 110 #ifdef ONLY_TESTING
 111         free_irq(IRQ_TIMER4, NULL);
 112         clear_bit(1, &timer_alive);
 113 #endif
 114         return 0;
 115 }
 116 
 117 static ssize_t watchdog_write(struct file *file, const char __user *data,
 118                               size_t len, loff_t *ppos)
 119 {
 120         /*
 121          *      Refresh the timer.
 122          */
 123         if (len)
 124                 watchdog_ping();
 125 
 126         return len;
 127 }
 128 
 129 static const struct watchdog_info ident = {
 130         .options        = WDIOF_SETTIMEOUT,
 131         .identity       = "Footbridge Watchdog",
 132 };
 133 
 134 static long watchdog_ioctl(struct file *file, unsigned int cmd,
 135                            unsigned long arg)
 136 {
 137         int __user *int_arg = (int __user *)arg;
 138         int new_margin, ret = -ENOTTY;
 139 
 140         switch (cmd) {
 141         case WDIOC_GETSUPPORT:
 142                 ret = 0;
 143                 if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
 144                         ret = -EFAULT;
 145                 break;
 146 
 147         case WDIOC_GETSTATUS:
 148         case WDIOC_GETBOOTSTATUS:
 149                 ret = put_user(0, int_arg);
 150                 break;
 151 
 152         case WDIOC_KEEPALIVE:
 153                 watchdog_ping();
 154                 ret = 0;
 155                 break;
 156 
 157         case WDIOC_SETTIMEOUT:
 158                 ret = get_user(new_margin, int_arg);
 159                 if (ret)
 160                         break;
 161 
 162                 /* Arbitrary, can't find the card's limits */
 163                 if (new_margin < 0 || new_margin > 60) {
 164                         ret = -EINVAL;
 165                         break;
 166                 }
 167 
 168                 soft_margin = new_margin;
 169                 reload = soft_margin * (mem_fclk_21285 / 256);
 170                 watchdog_ping();
 171                 /* Fall through */
 172         case WDIOC_GETTIMEOUT:
 173                 ret = put_user(soft_margin, int_arg);
 174                 break;
 175         }
 176         return ret;
 177 }
 178 
 179 static const struct file_operations watchdog_fops = {
 180         .owner          = THIS_MODULE,
 181         .llseek         = no_llseek,
 182         .write          = watchdog_write,
 183         .unlocked_ioctl = watchdog_ioctl,
 184         .open           = watchdog_open,
 185         .release        = watchdog_release,
 186 };
 187 
 188 static struct miscdevice watchdog_miscdev = {
 189         .minor          = WATCHDOG_MINOR,
 190         .name           = "watchdog",
 191         .fops           = &watchdog_fops,
 192 };
 193 
 194 static int __init footbridge_watchdog_init(void)
 195 {
 196         int retval;
 197 
 198         if (machine_is_netwinder())
 199                 return -ENODEV;
 200 
 201         retval = misc_register(&watchdog_miscdev);
 202         if (retval < 0)
 203                 return retval;
 204 
 205         pr_info("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
 206                 soft_margin);
 207 
 208         if (machine_is_cats())
 209                 pr_warn("Warning: Watchdog reset may not work on this machine\n");
 210         return 0;
 211 }
 212 
 213 static void __exit footbridge_watchdog_exit(void)
 214 {
 215         misc_deregister(&watchdog_miscdev);
 216 }
 217 
 218 MODULE_AUTHOR("Phil Blundell <pb@nexus.co.uk>");
 219 MODULE_DESCRIPTION("Footbridge watchdog driver");
 220 MODULE_LICENSE("GPL");
 221 
 222 module_param(soft_margin, int, 0);
 223 MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
 224 
 225 module_init(footbridge_watchdog_init);
 226 module_exit(footbridge_watchdog_exit);

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