root/drivers/watchdog/iop_wdt.c

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

DEFINITIONS

This source file includes following definitions.
  1. iop_watchdog_timeout
  2. wdt_supports_disable
  3. wdt_enable
  4. wdt_disable
  5. iop_wdt_open
  6. iop_wdt_write
  7. iop_wdt_ioctl
  8. iop_wdt_release
  9. iop_wdt_init
  10. iop_wdt_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * drivers/char/watchdog/iop_wdt.c
   4  *
   5  * WDT driver for Intel I/O Processors
   6  * Copyright (C) 2005, Intel Corporation.
   7  *
   8  * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
   9  *
  10  *      Curt E Bruns <curt.e.bruns@intel.com>
  11  *      Peter Milne <peter.milne@d-tacq.com>
  12  *      Dan Williams <dan.j.williams@intel.com>
  13  */
  14 
  15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  16 
  17 #include <linux/module.h>
  18 #include <linux/kernel.h>
  19 #include <linux/fs.h>
  20 #include <linux/init.h>
  21 #include <linux/device.h>
  22 #include <linux/miscdevice.h>
  23 #include <linux/watchdog.h>
  24 #include <linux/uaccess.h>
  25 #include <mach/hardware.h>
  26 
  27 static bool nowayout = WATCHDOG_NOWAYOUT;
  28 static unsigned long wdt_status;
  29 static unsigned long boot_status;
  30 static DEFINE_SPINLOCK(wdt_lock);
  31 
  32 #define WDT_IN_USE              0
  33 #define WDT_OK_TO_CLOSE         1
  34 #define WDT_ENABLED             2
  35 
  36 static unsigned long iop_watchdog_timeout(void)
  37 {
  38         return (0xffffffffUL / get_iop_tick_rate());
  39 }
  40 
  41 /**
  42  * wdt_supports_disable - determine if we are accessing a iop13xx watchdog
  43  * or iop3xx by whether it has a disable command
  44  */
  45 static int wdt_supports_disable(void)
  46 {
  47         int can_disable;
  48 
  49         if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
  50                 can_disable = 1;
  51         else
  52                 can_disable = 0;
  53 
  54         return can_disable;
  55 }
  56 
  57 static void wdt_enable(void)
  58 {
  59         /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
  60          * Takes approx. 10.7s to timeout
  61          */
  62         spin_lock(&wdt_lock);
  63         write_wdtcr(IOP_WDTCR_EN_ARM);
  64         write_wdtcr(IOP_WDTCR_EN);
  65         spin_unlock(&wdt_lock);
  66 }
  67 
  68 /* returns 0 if the timer was successfully disabled */
  69 static int wdt_disable(void)
  70 {
  71         /* Stop Counting */
  72         if (wdt_supports_disable()) {
  73                 spin_lock(&wdt_lock);
  74                 write_wdtcr(IOP_WDTCR_DIS_ARM);
  75                 write_wdtcr(IOP_WDTCR_DIS);
  76                 clear_bit(WDT_ENABLED, &wdt_status);
  77                 spin_unlock(&wdt_lock);
  78                 pr_info("Disabled\n");
  79                 return 0;
  80         } else
  81                 return 1;
  82 }
  83 
  84 static int iop_wdt_open(struct inode *inode, struct file *file)
  85 {
  86         if (test_and_set_bit(WDT_IN_USE, &wdt_status))
  87                 return -EBUSY;
  88 
  89         clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  90         wdt_enable();
  91         set_bit(WDT_ENABLED, &wdt_status);
  92         return stream_open(inode, file);
  93 }
  94 
  95 static ssize_t iop_wdt_write(struct file *file, const char *data, size_t len,
  96                   loff_t *ppos)
  97 {
  98         if (len) {
  99                 if (!nowayout) {
 100                         size_t i;
 101 
 102                         clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 103 
 104                         for (i = 0; i != len; i++) {
 105                                 char c;
 106 
 107                                 if (get_user(c, data + i))
 108                                         return -EFAULT;
 109                                 if (c == 'V')
 110                                         set_bit(WDT_OK_TO_CLOSE, &wdt_status);
 111                         }
 112                 }
 113                 wdt_enable();
 114         }
 115         return len;
 116 }
 117 
 118 static const struct watchdog_info ident = {
 119         .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
 120         .identity = "iop watchdog",
 121 };
 122 
 123 static long iop_wdt_ioctl(struct file *file,
 124                                 unsigned int cmd, unsigned long arg)
 125 {
 126         int options;
 127         int ret = -ENOTTY;
 128         int __user *argp = (int __user *)arg;
 129 
 130         switch (cmd) {
 131         case WDIOC_GETSUPPORT:
 132                 if (copy_to_user(argp, &ident, sizeof(ident)))
 133                         ret = -EFAULT;
 134                 else
 135                         ret = 0;
 136                 break;
 137 
 138         case WDIOC_GETSTATUS:
 139                 ret = put_user(0, argp);
 140                 break;
 141 
 142         case WDIOC_GETBOOTSTATUS:
 143                 ret = put_user(boot_status, argp);
 144                 break;
 145 
 146         case WDIOC_SETOPTIONS:
 147                 if (get_user(options, (int *)arg))
 148                         return -EFAULT;
 149 
 150                 if (options & WDIOS_DISABLECARD) {
 151                         if (!nowayout) {
 152                                 if (wdt_disable() == 0) {
 153                                         set_bit(WDT_OK_TO_CLOSE, &wdt_status);
 154                                         ret = 0;
 155                                 } else
 156                                         ret = -ENXIO;
 157                         } else
 158                                 ret = 0;
 159                 }
 160                 if (options & WDIOS_ENABLECARD) {
 161                         wdt_enable();
 162                         ret = 0;
 163                 }
 164                 break;
 165 
 166         case WDIOC_KEEPALIVE:
 167                 wdt_enable();
 168                 ret = 0;
 169                 break;
 170 
 171         case WDIOC_GETTIMEOUT:
 172                 ret = put_user(iop_watchdog_timeout(), argp);
 173                 break;
 174         }
 175         return ret;
 176 }
 177 
 178 static int iop_wdt_release(struct inode *inode, struct file *file)
 179 {
 180         int state = 1;
 181         if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
 182                 if (test_bit(WDT_ENABLED, &wdt_status))
 183                         state = wdt_disable();
 184 
 185         /* if the timer is not disabled reload and notify that we are still
 186          * going down
 187          */
 188         if (state != 0) {
 189                 wdt_enable();
 190                 pr_crit("Device closed unexpectedly - reset in %lu seconds\n",
 191                         iop_watchdog_timeout());
 192         }
 193 
 194         clear_bit(WDT_IN_USE, &wdt_status);
 195         clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
 196 
 197         return 0;
 198 }
 199 
 200 static const struct file_operations iop_wdt_fops = {
 201         .owner = THIS_MODULE,
 202         .llseek = no_llseek,
 203         .write = iop_wdt_write,
 204         .unlocked_ioctl = iop_wdt_ioctl,
 205         .open = iop_wdt_open,
 206         .release = iop_wdt_release,
 207 };
 208 
 209 static struct miscdevice iop_wdt_miscdev = {
 210         .minor = WATCHDOG_MINOR,
 211         .name = "watchdog",
 212         .fops = &iop_wdt_fops,
 213 };
 214 
 215 static int __init iop_wdt_init(void)
 216 {
 217         int ret;
 218 
 219         /* check if the reset was caused by the watchdog timer */
 220         boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
 221 
 222         /* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
 223          * NOTE: An IB Reset will Reset both cores in the IOP342
 224          */
 225         write_wdtsr(IOP13XX_WDTCR_IB_RESET);
 226 
 227         /* Register after we have the device set up so we cannot race
 228            with an open */
 229         ret = misc_register(&iop_wdt_miscdev);
 230         if (ret == 0)
 231                 pr_info("timeout %lu sec\n", iop_watchdog_timeout());
 232 
 233         return ret;
 234 }
 235 
 236 static void __exit iop_wdt_exit(void)
 237 {
 238         misc_deregister(&iop_wdt_miscdev);
 239 }
 240 
 241 module_init(iop_wdt_init);
 242 module_exit(iop_wdt_exit);
 243 
 244 module_param(nowayout, bool, 0);
 245 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 246 
 247 MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
 248 MODULE_DESCRIPTION("iop watchdog timer driver");
 249 MODULE_LICENSE("GPL");

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