root/drivers/watchdog/indydog.c

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

DEFINITIONS

This source file includes following definitions.
  1. indydog_start
  2. indydog_stop
  3. indydog_ping
  4. indydog_open
  5. indydog_release
  6. indydog_write
  7. indydog_ioctl
  8. indydog_notify_sys
  9. watchdog_init
  10. watchdog_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *      IndyDog 0.3     A Hardware Watchdog Device for SGI IP22
   4  *
   5  *      (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>,
   6  *                                              All Rights Reserved.
   7  *
   8  *      based on softdog.c by Alan Cox <alan@lxorguk.ukuu.org.uk>
   9  */
  10 
  11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12 
  13 #include <linux/module.h>
  14 #include <linux/moduleparam.h>
  15 #include <linux/types.h>
  16 #include <linux/kernel.h>
  17 #include <linux/fs.h>
  18 #include <linux/mm.h>
  19 #include <linux/miscdevice.h>
  20 #include <linux/watchdog.h>
  21 #include <linux/notifier.h>
  22 #include <linux/reboot.h>
  23 #include <linux/init.h>
  24 #include <linux/uaccess.h>
  25 #include <asm/sgi/mc.h>
  26 
  27 static unsigned long indydog_alive;
  28 static DEFINE_SPINLOCK(indydog_lock);
  29 
  30 #define WATCHDOG_TIMEOUT 30             /* 30 sec default timeout */
  31 
  32 static bool nowayout = WATCHDOG_NOWAYOUT;
  33 module_param(nowayout, bool, 0);
  34 MODULE_PARM_DESC(nowayout,
  35                 "Watchdog cannot be stopped once started (default="
  36                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  37 
  38 static void indydog_start(void)
  39 {
  40         spin_lock(&indydog_lock);
  41         sgimc->cpuctrl0 |= SGIMC_CCTRL0_WDOG;
  42         spin_unlock(&indydog_lock);
  43 }
  44 
  45 static void indydog_stop(void)
  46 {
  47         spin_lock(&indydog_lock);
  48         sgimc->cpuctrl0 &= ~SGIMC_CCTRL0_WDOG;
  49         spin_unlock(&indydog_lock);
  50 
  51         pr_info("Stopped watchdog timer\n");
  52 }
  53 
  54 static void indydog_ping(void)
  55 {
  56         sgimc->watchdogt = 0;
  57 }
  58 
  59 /*
  60  *      Allow only one person to hold it open
  61  */
  62 static int indydog_open(struct inode *inode, struct file *file)
  63 {
  64         if (test_and_set_bit(0, &indydog_alive))
  65                 return -EBUSY;
  66 
  67         if (nowayout)
  68                 __module_get(THIS_MODULE);
  69 
  70         /* Activate timer */
  71         indydog_start();
  72         indydog_ping();
  73 
  74         pr_info("Started watchdog timer\n");
  75 
  76         return stream_open(inode, file);
  77 }
  78 
  79 static int indydog_release(struct inode *inode, struct file *file)
  80 {
  81         /* Shut off the timer.
  82          * Lock it in if it's a module and we defined ...NOWAYOUT */
  83         if (!nowayout)
  84                 indydog_stop();         /* Turn the WDT off */
  85         clear_bit(0, &indydog_alive);
  86         return 0;
  87 }
  88 
  89 static ssize_t indydog_write(struct file *file, const char *data,
  90                                                 size_t len, loff_t *ppos)
  91 {
  92         /* Refresh the timer. */
  93         if (len)
  94                 indydog_ping();
  95         return len;
  96 }
  97 
  98 static long indydog_ioctl(struct file *file, unsigned int cmd,
  99                                                         unsigned long arg)
 100 {
 101         int options, retval = -EINVAL;
 102         static const struct watchdog_info ident = {
 103                 .options                = WDIOF_KEEPALIVEPING,
 104                 .firmware_version       = 0,
 105                 .identity               = "Hardware Watchdog for SGI IP22",
 106         };
 107 
 108         switch (cmd) {
 109         case WDIOC_GETSUPPORT:
 110                 if (copy_to_user((struct watchdog_info *)arg,
 111                                  &ident, sizeof(ident)))
 112                         return -EFAULT;
 113                 return 0;
 114         case WDIOC_GETSTATUS:
 115         case WDIOC_GETBOOTSTATUS:
 116                 return put_user(0, (int *)arg);
 117         case WDIOC_SETOPTIONS:
 118         {
 119                 if (get_user(options, (int *)arg))
 120                         return -EFAULT;
 121                 if (options & WDIOS_DISABLECARD) {
 122                         indydog_stop();
 123                         retval = 0;
 124                 }
 125                 if (options & WDIOS_ENABLECARD) {
 126                         indydog_start();
 127                         retval = 0;
 128                 }
 129                 return retval;
 130         }
 131         case WDIOC_KEEPALIVE:
 132                 indydog_ping();
 133                 return 0;
 134         case WDIOC_GETTIMEOUT:
 135                 return put_user(WATCHDOG_TIMEOUT, (int *)arg);
 136         default:
 137                 return -ENOTTY;
 138         }
 139 }
 140 
 141 static int indydog_notify_sys(struct notifier_block *this,
 142                                         unsigned long code, void *unused)
 143 {
 144         if (code == SYS_DOWN || code == SYS_HALT)
 145                 indydog_stop();         /* Turn the WDT off */
 146 
 147         return NOTIFY_DONE;
 148 }
 149 
 150 static const struct file_operations indydog_fops = {
 151         .owner          = THIS_MODULE,
 152         .llseek         = no_llseek,
 153         .write          = indydog_write,
 154         .unlocked_ioctl = indydog_ioctl,
 155         .open           = indydog_open,
 156         .release        = indydog_release,
 157 };
 158 
 159 static struct miscdevice indydog_miscdev = {
 160         .minor          = WATCHDOG_MINOR,
 161         .name           = "watchdog",
 162         .fops           = &indydog_fops,
 163 };
 164 
 165 static struct notifier_block indydog_notifier = {
 166         .notifier_call = indydog_notify_sys,
 167 };
 168 
 169 static int __init watchdog_init(void)
 170 {
 171         int ret;
 172 
 173         ret = register_reboot_notifier(&indydog_notifier);
 174         if (ret) {
 175                 pr_err("cannot register reboot notifier (err=%d)\n", ret);
 176                 return ret;
 177         }
 178 
 179         ret = misc_register(&indydog_miscdev);
 180         if (ret) {
 181                 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
 182                        WATCHDOG_MINOR, ret);
 183                 unregister_reboot_notifier(&indydog_notifier);
 184                 return ret;
 185         }
 186 
 187         pr_info("Hardware Watchdog Timer for SGI IP22: 0.3\n");
 188 
 189         return 0;
 190 }
 191 
 192 static void __exit watchdog_exit(void)
 193 {
 194         misc_deregister(&indydog_miscdev);
 195         unregister_reboot_notifier(&indydog_notifier);
 196 }
 197 
 198 module_init(watchdog_init);
 199 module_exit(watchdog_exit);
 200 
 201 MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
 202 MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
 203 MODULE_LICENSE("GPL");

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