root/drivers/watchdog/machzwd.c

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

DEFINITIONS

This source file includes following definitions.
  1. zf_readw
  2. zf_set_status
  3. zf_get_control
  4. zf_set_control
  5. zf_set_timer
  6. zf_timer_off
  7. zf_timer_on
  8. zf_ping
  9. zf_write
  10. zf_ioctl
  11. zf_open
  12. zf_close
  13. zf_notify_sys
  14. zf_show_action
  15. zf_init
  16. zf_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  MachZ ZF-Logic Watchdog Timer driver for Linux
   4  *
   5  *  The author does NOT admit liability nor provide warranty for
   6  *  any of this software. This material is provided "AS-IS" in
   7  *  the hope that it may be useful for others.
   8  *
   9  *  Author: Fernando Fuganti <fuganti@conectiva.com.br>
  10  *
  11  *  Based on sbc60xxwdt.c by Jakob Oestergaard
  12  *
  13  *  We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the
  14  *  following periods:
  15  *      wd#1 - 2 seconds;
  16  *      wd#2 - 7.2 ms;
  17  *  After the expiration of wd#1, it can generate a NMI, SCI, SMI, or
  18  *  a system RESET and it starts wd#2 that unconditionally will RESET
  19  *  the system when the counter reaches zero.
  20  *
  21  *  14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
  22  *      Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  23  */
  24 
  25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  26 
  27 #include <linux/module.h>
  28 #include <linux/moduleparam.h>
  29 #include <linux/types.h>
  30 #include <linux/timer.h>
  31 #include <linux/jiffies.h>
  32 #include <linux/miscdevice.h>
  33 #include <linux/watchdog.h>
  34 #include <linux/fs.h>
  35 #include <linux/ioport.h>
  36 #include <linux/notifier.h>
  37 #include <linux/reboot.h>
  38 #include <linux/init.h>
  39 #include <linux/io.h>
  40 #include <linux/uaccess.h>
  41 
  42 
  43 /* ports */
  44 #define ZF_IOBASE       0x218
  45 #define INDEX           0x218
  46 #define DATA_B          0x219
  47 #define DATA_W          0x21A
  48 #define DATA_D          0x21A
  49 
  50 /* indexes */                   /* size */
  51 #define ZFL_VERSION     0x02    /* 16   */
  52 #define CONTROL         0x10    /* 16   */
  53 #define STATUS          0x12    /* 8    */
  54 #define COUNTER_1       0x0C    /* 16   */
  55 #define COUNTER_2       0x0E    /* 8    */
  56 #define PULSE_LEN       0x0F    /* 8    */
  57 
  58 /* controls */
  59 #define ENABLE_WD1      0x0001
  60 #define ENABLE_WD2      0x0002
  61 #define RESET_WD1       0x0010
  62 #define RESET_WD2       0x0020
  63 #define GEN_SCI         0x0100
  64 #define GEN_NMI         0x0200
  65 #define GEN_SMI         0x0400
  66 #define GEN_RESET       0x0800
  67 
  68 
  69 /* utilities */
  70 
  71 #define WD1     0
  72 #define WD2     1
  73 
  74 #define zf_writew(port, data)  { outb(port, INDEX); outw(data, DATA_W); }
  75 #define zf_writeb(port, data)  { outb(port, INDEX); outb(data, DATA_B); }
  76 #define zf_get_ZFL_version()   zf_readw(ZFL_VERSION)
  77 
  78 
  79 static unsigned short zf_readw(unsigned char port)
  80 {
  81         outb(port, INDEX);
  82         return inw(DATA_W);
  83 }
  84 
  85 
  86 MODULE_AUTHOR("Fernando Fuganti <fuganti@conectiva.com.br>");
  87 MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
  88 MODULE_LICENSE("GPL");
  89 
  90 static bool nowayout = WATCHDOG_NOWAYOUT;
  91 module_param(nowayout, bool, 0);
  92 MODULE_PARM_DESC(nowayout,
  93                 "Watchdog cannot be stopped once started (default="
  94                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  95 
  96 #define PFX "machzwd"
  97 
  98 static const struct watchdog_info zf_info = {
  99         .options                = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 100         .firmware_version       = 1,
 101         .identity               = "ZF-Logic watchdog",
 102 };
 103 
 104 
 105 /*
 106  * action refers to action taken when watchdog resets
 107  * 0 = GEN_RESET
 108  * 1 = GEN_SMI
 109  * 2 = GEN_NMI
 110  * 3 = GEN_SCI
 111  * defaults to GEN_RESET (0)
 112  */
 113 static int action;
 114 module_param(action, int, 0);
 115 MODULE_PARM_DESC(action, "after watchdog resets, generate: "
 116                                 "0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI");
 117 
 118 static void zf_ping(struct timer_list *unused);
 119 
 120 static int zf_action = GEN_RESET;
 121 static unsigned long zf_is_open;
 122 static char zf_expect_close;
 123 static DEFINE_SPINLOCK(zf_port_lock);
 124 static DEFINE_TIMER(zf_timer, zf_ping);
 125 static unsigned long next_heartbeat;
 126 
 127 
 128 /* timeout for user land heart beat (10 seconds) */
 129 #define ZF_USER_TIMEO (HZ*10)
 130 
 131 /* timeout for hardware watchdog (~500ms) */
 132 #define ZF_HW_TIMEO (HZ/2)
 133 
 134 /* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */
 135 #define ZF_CTIMEOUT 0xffff
 136 
 137 #ifndef ZF_DEBUG
 138 #define dprintk(format, args...)
 139 #else
 140 #define dprintk(format, args...)                                        \
 141         pr_debug(":%s:%d: " format, __func__, __LINE__ , ## args)
 142 #endif
 143 
 144 
 145 static inline void zf_set_status(unsigned char new)
 146 {
 147         zf_writeb(STATUS, new);
 148 }
 149 
 150 
 151 /* CONTROL register functions */
 152 
 153 static inline unsigned short zf_get_control(void)
 154 {
 155         return zf_readw(CONTROL);
 156 }
 157 
 158 static inline void zf_set_control(unsigned short new)
 159 {
 160         zf_writew(CONTROL, new);
 161 }
 162 
 163 
 164 /* WD#? counter functions */
 165 /*
 166  *      Just set counter value
 167  */
 168 
 169 static inline void zf_set_timer(unsigned short new, unsigned char n)
 170 {
 171         switch (n) {
 172         case WD1:
 173                 zf_writew(COUNTER_1, new);
 174                 /* fall through */
 175         case WD2:
 176                 zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
 177         default:
 178                 return;
 179         }
 180 }
 181 
 182 /*
 183  * stop hardware timer
 184  */
 185 static void zf_timer_off(void)
 186 {
 187         unsigned int ctrl_reg = 0;
 188         unsigned long flags;
 189 
 190         /* stop internal ping */
 191         del_timer_sync(&zf_timer);
 192 
 193         spin_lock_irqsave(&zf_port_lock, flags);
 194         /* stop watchdog timer */
 195         ctrl_reg = zf_get_control();
 196         ctrl_reg |= (ENABLE_WD1|ENABLE_WD2);    /* disable wd1 and wd2 */
 197         ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2);
 198         zf_set_control(ctrl_reg);
 199         spin_unlock_irqrestore(&zf_port_lock, flags);
 200 
 201         pr_info("Watchdog timer is now disabled\n");
 202 }
 203 
 204 
 205 /*
 206  * start hardware timer
 207  */
 208 static void zf_timer_on(void)
 209 {
 210         unsigned int ctrl_reg = 0;
 211         unsigned long flags;
 212 
 213         spin_lock_irqsave(&zf_port_lock, flags);
 214 
 215         zf_writeb(PULSE_LEN, 0xff);
 216 
 217         zf_set_timer(ZF_CTIMEOUT, WD1);
 218 
 219         /* user land ping */
 220         next_heartbeat = jiffies + ZF_USER_TIMEO;
 221 
 222         /* start the timer for internal ping */
 223         mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
 224 
 225         /* start watchdog timer */
 226         ctrl_reg = zf_get_control();
 227         ctrl_reg |= (ENABLE_WD1|zf_action);
 228         zf_set_control(ctrl_reg);
 229         spin_unlock_irqrestore(&zf_port_lock, flags);
 230 
 231         pr_info("Watchdog timer is now enabled\n");
 232 }
 233 
 234 
 235 static void zf_ping(struct timer_list *unused)
 236 {
 237         unsigned int ctrl_reg = 0;
 238         unsigned long flags;
 239 
 240         zf_writeb(COUNTER_2, 0xff);
 241 
 242         if (time_before(jiffies, next_heartbeat)) {
 243                 dprintk("time_before: %ld\n", next_heartbeat - jiffies);
 244                 /*
 245                  * reset event is activated by transition from 0 to 1 on
 246                  * RESET_WD1 bit and we assume that it is already zero...
 247                  */
 248 
 249                 spin_lock_irqsave(&zf_port_lock, flags);
 250                 ctrl_reg = zf_get_control();
 251                 ctrl_reg |= RESET_WD1;
 252                 zf_set_control(ctrl_reg);
 253 
 254                 /* ...and nothing changes until here */
 255                 ctrl_reg &= ~(RESET_WD1);
 256                 zf_set_control(ctrl_reg);
 257                 spin_unlock_irqrestore(&zf_port_lock, flags);
 258 
 259                 mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
 260         } else
 261                 pr_crit("I will reset your machine\n");
 262 }
 263 
 264 static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
 265                                                                 loff_t *ppos)
 266 {
 267         /* See if we got the magic character */
 268         if (count) {
 269                 /*
 270                  * no need to check for close confirmation
 271                  * no way to disable watchdog ;)
 272                  */
 273                 if (!nowayout) {
 274                         size_t ofs;
 275                         /*
 276                          * note: just in case someone wrote the magic character
 277                          * five months ago...
 278                          */
 279                         zf_expect_close = 0;
 280 
 281                         /* now scan */
 282                         for (ofs = 0; ofs != count; ofs++) {
 283                                 char c;
 284                                 if (get_user(c, buf + ofs))
 285                                         return -EFAULT;
 286                                 if (c == 'V') {
 287                                         zf_expect_close = 42;
 288                                         dprintk("zf_expect_close = 42\n");
 289                                 }
 290                         }
 291                 }
 292 
 293                 /*
 294                  * Well, anyhow someone wrote to us,
 295                  * we should return that favour
 296                  */
 297                 next_heartbeat = jiffies + ZF_USER_TIMEO;
 298                 dprintk("user ping at %ld\n", jiffies);
 299         }
 300         return count;
 301 }
 302 
 303 static long zf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 304 {
 305         void __user *argp = (void __user *)arg;
 306         int __user *p = argp;
 307         switch (cmd) {
 308         case WDIOC_GETSUPPORT:
 309                 if (copy_to_user(argp, &zf_info, sizeof(zf_info)))
 310                         return -EFAULT;
 311                 break;
 312         case WDIOC_GETSTATUS:
 313         case WDIOC_GETBOOTSTATUS:
 314                 return put_user(0, p);
 315         case WDIOC_KEEPALIVE:
 316                 zf_ping(NULL);
 317                 break;
 318         default:
 319                 return -ENOTTY;
 320         }
 321         return 0;
 322 }
 323 
 324 static int zf_open(struct inode *inode, struct file *file)
 325 {
 326         if (test_and_set_bit(0, &zf_is_open))
 327                 return -EBUSY;
 328         if (nowayout)
 329                 __module_get(THIS_MODULE);
 330         zf_timer_on();
 331         return stream_open(inode, file);
 332 }
 333 
 334 static int zf_close(struct inode *inode, struct file *file)
 335 {
 336         if (zf_expect_close == 42)
 337                 zf_timer_off();
 338         else {
 339                 del_timer(&zf_timer);
 340                 pr_err("device file closed unexpectedly. Will not stop the WDT!\n");
 341         }
 342         clear_bit(0, &zf_is_open);
 343         zf_expect_close = 0;
 344         return 0;
 345 }
 346 
 347 /*
 348  * Notifier for system down
 349  */
 350 
 351 static int zf_notify_sys(struct notifier_block *this, unsigned long code,
 352                                                                 void *unused)
 353 {
 354         if (code == SYS_DOWN || code == SYS_HALT)
 355                 zf_timer_off();
 356         return NOTIFY_DONE;
 357 }
 358 
 359 static const struct file_operations zf_fops = {
 360         .owner          = THIS_MODULE,
 361         .llseek         = no_llseek,
 362         .write          = zf_write,
 363         .unlocked_ioctl = zf_ioctl,
 364         .open           = zf_open,
 365         .release        = zf_close,
 366 };
 367 
 368 static struct miscdevice zf_miscdev = {
 369         .minor = WATCHDOG_MINOR,
 370         .name = "watchdog",
 371         .fops = &zf_fops,
 372 };
 373 
 374 
 375 /*
 376  * The device needs to learn about soft shutdowns in order to
 377  * turn the timebomb registers off.
 378  */
 379 static struct notifier_block zf_notifier = {
 380         .notifier_call = zf_notify_sys,
 381 };
 382 
 383 static void __init zf_show_action(int act)
 384 {
 385         static const char * const str[] = { "RESET", "SMI", "NMI", "SCI" };
 386 
 387         pr_info("Watchdog using action = %s\n", str[act]);
 388 }
 389 
 390 static int __init zf_init(void)
 391 {
 392         int ret;
 393 
 394         pr_info("MachZ ZF-Logic Watchdog driver initializing\n");
 395 
 396         ret = zf_get_ZFL_version();
 397         if (!ret || ret == 0xffff) {
 398                 pr_warn("no ZF-Logic found\n");
 399                 return -ENODEV;
 400         }
 401 
 402         if (action <= 3 && action >= 0)
 403                 zf_action = zf_action >> action;
 404         else
 405                 action = 0;
 406 
 407         zf_show_action(action);
 408 
 409         if (!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")) {
 410                 pr_err("cannot reserve I/O ports at %d\n", ZF_IOBASE);
 411                 ret = -EBUSY;
 412                 goto no_region;
 413         }
 414 
 415         ret = register_reboot_notifier(&zf_notifier);
 416         if (ret) {
 417                 pr_err("can't register reboot notifier (err=%d)\n", ret);
 418                 goto no_reboot;
 419         }
 420 
 421         ret = misc_register(&zf_miscdev);
 422         if (ret) {
 423                 pr_err("can't misc_register on minor=%d\n", WATCHDOG_MINOR);
 424                 goto no_misc;
 425         }
 426 
 427         zf_set_status(0);
 428         zf_set_control(0);
 429 
 430         return 0;
 431 
 432 no_misc:
 433         unregister_reboot_notifier(&zf_notifier);
 434 no_reboot:
 435         release_region(ZF_IOBASE, 3);
 436 no_region:
 437         return ret;
 438 }
 439 
 440 
 441 static void __exit zf_exit(void)
 442 {
 443         zf_timer_off();
 444 
 445         misc_deregister(&zf_miscdev);
 446         unregister_reboot_notifier(&zf_notifier);
 447         release_region(ZF_IOBASE, 3);
 448 }
 449 
 450 module_init(zf_init);
 451 module_exit(zf_exit);

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