Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  *  Eurotech CPU-1220/1410/1420 on board WDT driver
0004  *
0005  *  (c) Copyright 2001 Ascensit <support@ascensit.com>
0006  *  (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
0007  *  (c) Copyright 2002 Rob Radez <rob@osinvestor.com>
0008  *
0009  *  Based on wdt.c.
0010  *  Original copyright messages:
0011  *
0012  *  (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
0013  *                      All Rights Reserved.
0014  *
0015  *  Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
0016  *  warranty for any of this software. This material is provided
0017  *  "AS-IS" and at no charge.
0018  *
0019  *  (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>*
0020  */
0021 
0022 /* Changelog:
0023  *
0024  * 2001 - Rodolfo Giometti
0025  *  Initial release
0026  *
0027  * 2002/04/25 - Rob Radez
0028  *  clean up #includes
0029  *  clean up locking
0030  *  make __setup param unique
0031  *  proper options in watchdog_info
0032  *  add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls
0033  *  add expect_close support
0034  *
0035  * 2002.05.30 - Joel Becker <joel.becker@oracle.com>
0036  *  Added Matt Domsch's nowayout module option.
0037  */
0038 
0039 /*
0040  *  The eurotech CPU-1220/1410/1420's watchdog is a part
0041  *  of the on-board SUPER I/O device SMSC FDC 37B782.
0042  */
0043 
0044 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0045 
0046 #include <linux/interrupt.h>
0047 #include <linux/module.h>
0048 #include <linux/moduleparam.h>
0049 #include <linux/types.h>
0050 #include <linux/miscdevice.h>
0051 #include <linux/watchdog.h>
0052 #include <linux/fs.h>
0053 #include <linux/ioport.h>
0054 #include <linux/notifier.h>
0055 #include <linux/reboot.h>
0056 #include <linux/init.h>
0057 #include <linux/io.h>
0058 #include <linux/uaccess.h>
0059 
0060 
0061 static unsigned long eurwdt_is_open;
0062 static int eurwdt_timeout;
0063 static char eur_expect_close;
0064 static DEFINE_SPINLOCK(eurwdt_lock);
0065 
0066 /*
0067  * You must set these - there is no sane way to probe for this board.
0068  */
0069 
0070 static int io = 0x3f0;
0071 static int irq = 10;
0072 static char *ev = "int";
0073 
0074 #define WDT_TIMEOUT     60                /* 1 minute */
0075 
0076 static bool nowayout = WATCHDOG_NOWAYOUT;
0077 module_param(nowayout, bool, 0);
0078 MODULE_PARM_DESC(nowayout,
0079         "Watchdog cannot be stopped once started (default="
0080                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0081 
0082 /*
0083  * Some symbolic names
0084  */
0085 
0086 #define WDT_CTRL_REG        0x30
0087 #define WDT_OUTPIN_CFG      0xe2
0088 #define WDT_EVENT_INT       0x00
0089 #define WDT_EVENT_REBOOT    0x08
0090 #define WDT_UNIT_SEL        0xf1
0091 #define WDT_UNIT_SECS       0x80
0092 #define WDT_TIMEOUT_VAL     0xf2
0093 #define WDT_TIMER_CFG       0xf3
0094 
0095 
0096 module_param_hw(io, int, ioport, 0);
0097 MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)");
0098 module_param_hw(irq, int, irq, 0);
0099 MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)");
0100 module_param(ev, charp, 0);
0101 MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `int')");
0102 
0103 
0104 /*
0105  * Programming support
0106  */
0107 
0108 static inline void eurwdt_write_reg(u8 index, u8 data)
0109 {
0110     outb(index, io);
0111     outb(data, io+1);
0112 }
0113 
0114 static inline void eurwdt_lock_chip(void)
0115 {
0116     outb(0xaa, io);
0117 }
0118 
0119 static inline void eurwdt_unlock_chip(void)
0120 {
0121     outb(0x55, io);
0122     eurwdt_write_reg(0x07, 0x08);   /* set the logical device */
0123 }
0124 
0125 static inline void eurwdt_set_timeout(int timeout)
0126 {
0127     eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout);
0128 }
0129 
0130 static inline void eurwdt_disable_timer(void)
0131 {
0132     eurwdt_set_timeout(0);
0133 }
0134 
0135 static void eurwdt_activate_timer(void)
0136 {
0137     eurwdt_disable_timer();
0138     eurwdt_write_reg(WDT_CTRL_REG, 0x01);   /* activate the WDT */
0139     eurwdt_write_reg(WDT_OUTPIN_CFG,
0140         !strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT);
0141 
0142     /* Setting interrupt line */
0143     if (irq == 2 || irq > 15 || irq < 0) {
0144         pr_err("invalid irq number\n");
0145         irq = 0;    /* if invalid we disable interrupt */
0146     }
0147     if (irq == 0)
0148         pr_info("interrupt disabled\n");
0149 
0150     eurwdt_write_reg(WDT_TIMER_CFG, irq << 4);
0151 
0152     eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS);  /* we use seconds */
0153     eurwdt_set_timeout(0);  /* the default timeout */
0154 }
0155 
0156 
0157 /*
0158  * Kernel methods.
0159  */
0160 
0161 static irqreturn_t eurwdt_interrupt(int irq, void *dev_id)
0162 {
0163     pr_crit("timeout WDT timeout\n");
0164 
0165 #ifdef ONLY_TESTING
0166     pr_crit("Would Reboot\n");
0167 #else
0168     pr_crit("Initiating system reboot\n");
0169     emergency_restart();
0170 #endif
0171     return IRQ_HANDLED;
0172 }
0173 
0174 
0175 /**
0176  * eurwdt_ping:
0177  *
0178  * Reload counter one with the watchdog timeout.
0179  */
0180 
0181 static void eurwdt_ping(void)
0182 {
0183     /* Write the watchdog default value */
0184     eurwdt_set_timeout(eurwdt_timeout);
0185 }
0186 
0187 /**
0188  * eurwdt_write:
0189  * @file: file handle to the watchdog
0190  * @buf: buffer to write (unused as data does not matter here
0191  * @count: count of bytes
0192  * @ppos: pointer to the position to write. No seeks allowed
0193  *
0194  * A write to a watchdog device is defined as a keepalive signal. Any
0195  * write of data will do, as we we don't define content meaning.
0196  */
0197 
0198 static ssize_t eurwdt_write(struct file *file, const char __user *buf,
0199 size_t count, loff_t *ppos)
0200 {
0201     if (count) {
0202         if (!nowayout) {
0203             size_t i;
0204 
0205             eur_expect_close = 0;
0206 
0207             for (i = 0; i != count; i++) {
0208                 char c;
0209                 if (get_user(c, buf + i))
0210                     return -EFAULT;
0211                 if (c == 'V')
0212                     eur_expect_close = 42;
0213             }
0214         }
0215         spin_lock(&eurwdt_lock);
0216         eurwdt_ping();  /* the default timeout */
0217         spin_unlock(&eurwdt_lock);
0218     }
0219     return count;
0220 }
0221 
0222 /**
0223  * eurwdt_ioctl:
0224  * @file: file handle to the device
0225  * @cmd: watchdog command
0226  * @arg: argument pointer
0227  *
0228  * The watchdog API defines a common set of functions for all watchdogs
0229  * according to their available features.
0230  */
0231 
0232 static long eurwdt_ioctl(struct file *file,
0233                     unsigned int cmd, unsigned long arg)
0234 {
0235     void __user *argp = (void __user *)arg;
0236     int __user *p = argp;
0237     static const struct watchdog_info ident = {
0238         .options      = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
0239                             | WDIOF_MAGICCLOSE,
0240         .firmware_version = 1,
0241         .identity     = "WDT Eurotech CPU-1220/1410",
0242     };
0243 
0244     int time;
0245     int options, retval = -EINVAL;
0246 
0247     switch (cmd) {
0248     case WDIOC_GETSUPPORT:
0249         return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
0250 
0251     case WDIOC_GETSTATUS:
0252     case WDIOC_GETBOOTSTATUS:
0253         return put_user(0, p);
0254 
0255     case WDIOC_SETOPTIONS:
0256         if (get_user(options, p))
0257             return -EFAULT;
0258         spin_lock(&eurwdt_lock);
0259         if (options & WDIOS_DISABLECARD) {
0260             eurwdt_disable_timer();
0261             retval = 0;
0262         }
0263         if (options & WDIOS_ENABLECARD) {
0264             eurwdt_activate_timer();
0265             eurwdt_ping();
0266             retval = 0;
0267         }
0268         spin_unlock(&eurwdt_lock);
0269         return retval;
0270 
0271     case WDIOC_KEEPALIVE:
0272         spin_lock(&eurwdt_lock);
0273         eurwdt_ping();
0274         spin_unlock(&eurwdt_lock);
0275         return 0;
0276 
0277     case WDIOC_SETTIMEOUT:
0278         if (copy_from_user(&time, p, sizeof(int)))
0279             return -EFAULT;
0280 
0281         /* Sanity check */
0282         if (time < 0 || time > 255)
0283             return -EINVAL;
0284 
0285         spin_lock(&eurwdt_lock);
0286         eurwdt_timeout = time;
0287         eurwdt_set_timeout(time);
0288         spin_unlock(&eurwdt_lock);
0289         fallthrough;
0290 
0291     case WDIOC_GETTIMEOUT:
0292         return put_user(eurwdt_timeout, p);
0293 
0294     default:
0295         return -ENOTTY;
0296     }
0297 }
0298 
0299 /**
0300  * eurwdt_open:
0301  * @inode: inode of device
0302  * @file: file handle to device
0303  *
0304  * The misc device has been opened. The watchdog device is single
0305  * open and on opening we load the counter.
0306  */
0307 
0308 static int eurwdt_open(struct inode *inode, struct file *file)
0309 {
0310     if (test_and_set_bit(0, &eurwdt_is_open))
0311         return -EBUSY;
0312     eurwdt_timeout = WDT_TIMEOUT;   /* initial timeout */
0313     /* Activate the WDT */
0314     eurwdt_activate_timer();
0315     return stream_open(inode, file);
0316 }
0317 
0318 /**
0319  * eurwdt_release:
0320  * @inode: inode to board
0321  * @file: file handle to board
0322  *
0323  * The watchdog has a configurable API. There is a religious dispute
0324  * between people who want their watchdog to be able to shut down and
0325  * those who want to be sure if the watchdog manager dies the machine
0326  * reboots. In the former case we disable the counters, in the latter
0327  * case you have to open it again very soon.
0328  */
0329 
0330 static int eurwdt_release(struct inode *inode, struct file *file)
0331 {
0332     if (eur_expect_close == 42)
0333         eurwdt_disable_timer();
0334     else {
0335         pr_crit("Unexpected close, not stopping watchdog!\n");
0336         eurwdt_ping();
0337     }
0338     clear_bit(0, &eurwdt_is_open);
0339     eur_expect_close = 0;
0340     return 0;
0341 }
0342 
0343 /**
0344  * eurwdt_notify_sys:
0345  * @this: our notifier block
0346  * @code: the event being reported
0347  * @unused: unused
0348  *
0349  * Our notifier is called on system shutdowns. We want to turn the card
0350  * off at reboot otherwise the machine will reboot again during memory
0351  * test or worse yet during the following fsck. This would suck, in fact
0352  * trust me - if it happens it does suck.
0353  */
0354 
0355 static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
0356     void *unused)
0357 {
0358     if (code == SYS_DOWN || code == SYS_HALT)
0359         eurwdt_disable_timer(); /* Turn the card off */
0360 
0361     return NOTIFY_DONE;
0362 }
0363 
0364 /*
0365  * Kernel Interfaces
0366  */
0367 
0368 
0369 static const struct file_operations eurwdt_fops = {
0370     .owner      = THIS_MODULE,
0371     .llseek     = no_llseek,
0372     .write      = eurwdt_write,
0373     .unlocked_ioctl = eurwdt_ioctl,
0374     .compat_ioctl   = compat_ptr_ioctl,
0375     .open       = eurwdt_open,
0376     .release    = eurwdt_release,
0377 };
0378 
0379 static struct miscdevice eurwdt_miscdev = {
0380     .minor  = WATCHDOG_MINOR,
0381     .name   = "watchdog",
0382     .fops   = &eurwdt_fops,
0383 };
0384 
0385 /*
0386  * The WDT card needs to learn about soft shutdowns in order to
0387  * turn the timebomb registers off.
0388  */
0389 
0390 static struct notifier_block eurwdt_notifier = {
0391     .notifier_call = eurwdt_notify_sys,
0392 };
0393 
0394 /**
0395  * eurwdt_exit:
0396  *
0397  * Unload the watchdog. You cannot do this with any file handles open.
0398  * If your watchdog is set to continue ticking on close and you unload
0399  * it, well it keeps ticking. We won't get the interrupt but the board
0400  * will not touch PC memory so all is fine. You just have to load a new
0401  * module in 60 seconds or reboot.
0402  */
0403 
0404 static void __exit eurwdt_exit(void)
0405 {
0406     eurwdt_lock_chip();
0407 
0408     misc_deregister(&eurwdt_miscdev);
0409 
0410     unregister_reboot_notifier(&eurwdt_notifier);
0411     release_region(io, 2);
0412     free_irq(irq, NULL);
0413 }
0414 
0415 /**
0416  * eurwdt_init:
0417  *
0418  * Set up the WDT watchdog board. After grabbing the resources
0419  * we require we need also to unlock the device.
0420  * The open() function will actually kick the board off.
0421  */
0422 
0423 static int __init eurwdt_init(void)
0424 {
0425     int ret;
0426 
0427     ret = request_irq(irq, eurwdt_interrupt, 0, "eurwdt", NULL);
0428     if (ret) {
0429         pr_err("IRQ %d is not free\n", irq);
0430         goto out;
0431     }
0432 
0433     if (!request_region(io, 2, "eurwdt")) {
0434         pr_err("IO %X is not free\n", io);
0435         ret = -EBUSY;
0436         goto outirq;
0437     }
0438 
0439     ret = register_reboot_notifier(&eurwdt_notifier);
0440     if (ret) {
0441         pr_err("can't register reboot notifier (err=%d)\n", ret);
0442         goto outreg;
0443     }
0444 
0445     ret = misc_register(&eurwdt_miscdev);
0446     if (ret) {
0447         pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
0448         goto outreboot;
0449     }
0450 
0451     eurwdt_unlock_chip();
0452 
0453     ret = 0;
0454     pr_info("Eurotech WDT driver 0.01 at %X (Interrupt %d) - timeout event: %s\n",
0455         io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
0456 
0457 out:
0458     return ret;
0459 
0460 outreboot:
0461     unregister_reboot_notifier(&eurwdt_notifier);
0462 
0463 outreg:
0464     release_region(io, 2);
0465 
0466 outirq:
0467     free_irq(irq, NULL);
0468     goto out;
0469 }
0470 
0471 module_init(eurwdt_init);
0472 module_exit(eurwdt_exit);
0473 
0474 MODULE_AUTHOR("Rodolfo Giometti");
0475 MODULE_DESCRIPTION("Driver for Eurotech CPU-1220/1410 on board watchdog");
0476 MODULE_LICENSE("GPL");