xref: /openbmc/linux/arch/um/drivers/harddog_kern.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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