11da177e4SLinus Torvalds /* UML hardware watchdog, shamelessly stolen from:
21da177e4SLinus Torvalds *
31da177e4SLinus Torvalds * SoftDog 0.05: A Software Watchdog Device
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
61da177e4SLinus Torvalds * http://www.redhat.com
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or
91da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License
101da177e4SLinus Torvalds * as published by the Free Software Foundation; either version
111da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version.
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
141da177e4SLinus Torvalds * warranty for any of this software. This material is provided
151da177e4SLinus Torvalds * "AS-IS" and at no charge.
161da177e4SLinus Torvalds *
171da177e4SLinus Torvalds * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
181da177e4SLinus Torvalds *
191da177e4SLinus Torvalds * Software only watchdog driver. Unlike its big brother the WDT501P
201da177e4SLinus Torvalds * driver this won't always recover a failed machine.
211da177e4SLinus Torvalds *
221da177e4SLinus Torvalds * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
231da177e4SLinus Torvalds * Modularised.
241da177e4SLinus Torvalds * Added soft_margin; use upon insmod to change the timer delay.
251da177e4SLinus Torvalds * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
261da177e4SLinus Torvalds * minors.
271da177e4SLinus Torvalds *
281da177e4SLinus Torvalds * 19980911 Alan Cox
291da177e4SLinus Torvalds * Made SMP safe for 2.3.x
301da177e4SLinus Torvalds *
311da177e4SLinus Torvalds * 20011127 Joel Becker (jlbec@evilplan.org>
321da177e4SLinus Torvalds * Added soft_noboot; Allows testing the softdog trigger without
331da177e4SLinus Torvalds * requiring a recompile.
341da177e4SLinus Torvalds * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
351da177e4SLinus Torvalds */
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds #include <linux/module.h>
381da177e4SLinus Torvalds #include <linux/types.h>
391da177e4SLinus Torvalds #include <linux/kernel.h>
401da177e4SLinus Torvalds #include <linux/fs.h>
411da177e4SLinus Torvalds #include <linux/mm.h>
421da177e4SLinus Torvalds #include <linux/miscdevice.h>
431da177e4SLinus Torvalds #include <linux/watchdog.h>
441da177e4SLinus Torvalds #include <linux/reboot.h>
459a181c58SArnd Bergmann #include <linux/mutex.h>
461da177e4SLinus Torvalds #include <linux/init.h>
4742d36115SJeff Dike #include <linux/spinlock.h>
487c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
491da177e4SLinus Torvalds #include "mconsole.h"
50*73a23d77SJohannes Berg #include "harddog.h"
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds MODULE_LICENSE("GPL");
531da177e4SLinus Torvalds
549a181c58SArnd Bergmann static DEFINE_MUTEX(harddog_mutex);
5542d36115SJeff Dike static DEFINE_SPINLOCK(lock);
561da177e4SLinus Torvalds static int timer_alive;
571da177e4SLinus Torvalds static int harddog_in_fd = -1;
581da177e4SLinus Torvalds static int harddog_out_fd = -1;
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds /*
611da177e4SLinus Torvalds * Allow only one person to hold it open
621da177e4SLinus Torvalds */
631da177e4SLinus Torvalds
harddog_open(struct inode * inode,struct file * file)641da177e4SLinus Torvalds static int harddog_open(struct inode *inode, struct file *file)
651da177e4SLinus Torvalds {
6642d36115SJeff Dike int err = -EBUSY;
671da177e4SLinus Torvalds char *sock = NULL;
681da177e4SLinus Torvalds
699a181c58SArnd Bergmann mutex_lock(&harddog_mutex);
7042d36115SJeff Dike spin_lock(&lock);
711da177e4SLinus Torvalds if(timer_alive)
7242d36115SJeff Dike goto err;
738d820760SJeff Dike #ifdef CONFIG_WATCHDOG_NOWAYOUT
741da177e4SLinus Torvalds __module_get(THIS_MODULE);
751da177e4SLinus Torvalds #endif
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds #ifdef CONFIG_MCONSOLE
781da177e4SLinus Torvalds sock = mconsole_notify_socket();
791da177e4SLinus Torvalds #endif
801da177e4SLinus Torvalds err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock);
8142d36115SJeff Dike if(err)
8242d36115SJeff Dike goto err;
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds timer_alive = 1;
8542d36115SJeff Dike spin_unlock(&lock);
869a181c58SArnd Bergmann mutex_unlock(&harddog_mutex);
87c5bf68feSKirill Smelkov return stream_open(inode, file);
8842d36115SJeff Dike err:
8942d36115SJeff Dike spin_unlock(&lock);
909a181c58SArnd Bergmann mutex_unlock(&harddog_mutex);
9142d36115SJeff Dike return err;
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds
harddog_release(struct inode * inode,struct file * file)941da177e4SLinus Torvalds static int harddog_release(struct inode *inode, struct file *file)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds /*
971da177e4SLinus Torvalds * Shut off the timer.
981da177e4SLinus Torvalds */
9942d36115SJeff Dike
10042d36115SJeff Dike spin_lock(&lock);
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds stop_watchdog(harddog_in_fd, harddog_out_fd);
1031da177e4SLinus Torvalds harddog_in_fd = -1;
1041da177e4SLinus Torvalds harddog_out_fd = -1;
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds timer_alive=0;
10742d36115SJeff Dike spin_unlock(&lock);
10842d36115SJeff Dike
1091da177e4SLinus Torvalds return 0;
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds
harddog_write(struct file * file,const char __user * data,size_t len,loff_t * ppos)1124d338e1aSAl Viro static ssize_t harddog_write(struct file *file, const char __user *data, size_t len,
1131da177e4SLinus Torvalds loff_t *ppos)
1141da177e4SLinus Torvalds {
1151da177e4SLinus Torvalds /*
1161da177e4SLinus Torvalds * Refresh the timer.
1171da177e4SLinus Torvalds */
1181da177e4SLinus Torvalds if(len)
1195bbcbecaSJeff Dike return ping_watchdog(harddog_out_fd);
1201da177e4SLinus Torvalds return 0;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds
harddog_ioctl_unlocked(struct file * file,unsigned int cmd,unsigned long arg)1239f37af65SFrederic Weisbecker static int harddog_ioctl_unlocked(struct file *file,
1241da177e4SLinus Torvalds unsigned int cmd, unsigned long arg)
1251da177e4SLinus Torvalds {
1264d338e1aSAl Viro void __user *argp= (void __user *)arg;
1271da177e4SLinus Torvalds static struct watchdog_info ident = {
1281da177e4SLinus Torvalds WDIOC_SETTIMEOUT,
1291da177e4SLinus Torvalds 0,
1301da177e4SLinus Torvalds "UML Hardware Watchdog"
1311da177e4SLinus Torvalds };
1321da177e4SLinus Torvalds switch (cmd) {
1331da177e4SLinus Torvalds default:
1341da177e4SLinus Torvalds return -ENOTTY;
1351da177e4SLinus Torvalds case WDIOC_GETSUPPORT:
1364d338e1aSAl Viro if(copy_to_user(argp, &ident, sizeof(ident)))
1371da177e4SLinus Torvalds return -EFAULT;
1381da177e4SLinus Torvalds return 0;
1391da177e4SLinus Torvalds case WDIOC_GETSTATUS:
1401da177e4SLinus Torvalds case WDIOC_GETBOOTSTATUS:
1414d338e1aSAl Viro return put_user(0,(int __user *)argp);
1421da177e4SLinus Torvalds case WDIOC_KEEPALIVE:
1435bbcbecaSJeff Dike return ping_watchdog(harddog_out_fd);
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds
harddog_ioctl(struct file * file,unsigned int cmd,unsigned long arg)1479f37af65SFrederic Weisbecker static long harddog_ioctl(struct file *file,
1489f37af65SFrederic Weisbecker unsigned int cmd, unsigned long arg)
1499f37af65SFrederic Weisbecker {
1509f37af65SFrederic Weisbecker long ret;
1519f37af65SFrederic Weisbecker
1529a181c58SArnd Bergmann mutex_lock(&harddog_mutex);
1539f37af65SFrederic Weisbecker ret = harddog_ioctl_unlocked(file, cmd, arg);
1549a181c58SArnd Bergmann mutex_unlock(&harddog_mutex);
1559f37af65SFrederic Weisbecker
1569f37af65SFrederic Weisbecker return ret;
1579f37af65SFrederic Weisbecker }
1589f37af65SFrederic Weisbecker
1595dfe4c96SArjan van de Ven static const struct file_operations harddog_fops = {
1601da177e4SLinus Torvalds .owner = THIS_MODULE,
1611da177e4SLinus Torvalds .write = harddog_write,
1629f37af65SFrederic Weisbecker .unlocked_ioctl = harddog_ioctl,
163b6dfb247SArnd Bergmann .compat_ioctl = compat_ptr_ioctl,
1641da177e4SLinus Torvalds .open = harddog_open,
1651da177e4SLinus Torvalds .release = harddog_release,
1666038f373SArnd Bergmann .llseek = no_llseek,
1671da177e4SLinus Torvalds };
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds static struct miscdevice harddog_miscdev = {
1701da177e4SLinus Torvalds .minor = WATCHDOG_MINOR,
1711da177e4SLinus Torvalds .name = "watchdog",
1721da177e4SLinus Torvalds .fops = &harddog_fops,
1731da177e4SLinus Torvalds };
174d6a38c0bSPrasannaKumar Muralidharan module_misc_device(harddog_miscdev);
175