18c2ecf20Sopenharmony_ci/* UML hardware watchdog, shamelessly stolen from: 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * SoftDog 0.05: A Software Watchdog Device 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. 68c2ecf20Sopenharmony_ci * http://www.redhat.com 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 98c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License 108c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version 118c2ecf20Sopenharmony_ci * 2 of the License, or (at your option) any later version. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 148c2ecf20Sopenharmony_ci * warranty for any of this software. This material is provided 158c2ecf20Sopenharmony_ci * "AS-IS" and at no charge. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Software only watchdog driver. Unlike its big brother the WDT501P 208c2ecf20Sopenharmony_ci * driver this won't always recover a failed machine. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> : 238c2ecf20Sopenharmony_ci * Modularised. 248c2ecf20Sopenharmony_ci * Added soft_margin; use upon insmod to change the timer delay. 258c2ecf20Sopenharmony_ci * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate 268c2ecf20Sopenharmony_ci * minors. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * 19980911 Alan Cox 298c2ecf20Sopenharmony_ci * Made SMP safe for 2.3.x 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * 20011127 Joel Becker (jlbec@evilplan.org> 328c2ecf20Sopenharmony_ci * Added soft_noboot; Allows testing the softdog trigger without 338c2ecf20Sopenharmony_ci * requiring a recompile. 348c2ecf20Sopenharmony_ci * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/module.h> 388c2ecf20Sopenharmony_ci#include <linux/types.h> 398c2ecf20Sopenharmony_ci#include <linux/kernel.h> 408c2ecf20Sopenharmony_ci#include <linux/fs.h> 418c2ecf20Sopenharmony_ci#include <linux/mm.h> 428c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 438c2ecf20Sopenharmony_ci#include <linux/watchdog.h> 448c2ecf20Sopenharmony_ci#include <linux/reboot.h> 458c2ecf20Sopenharmony_ci#include <linux/mutex.h> 468c2ecf20Sopenharmony_ci#include <linux/init.h> 478c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 488c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 498c2ecf20Sopenharmony_ci#include "mconsole.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(harddog_mutex); 548c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(lock); 558c2ecf20Sopenharmony_cistatic int timer_alive; 568c2ecf20Sopenharmony_cistatic int harddog_in_fd = -1; 578c2ecf20Sopenharmony_cistatic int harddog_out_fd = -1; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* 608c2ecf20Sopenharmony_ci * Allow only one person to hold it open 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciextern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int harddog_open(struct inode *inode, struct file *file) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci int err = -EBUSY; 688c2ecf20Sopenharmony_ci char *sock = NULL; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci mutex_lock(&harddog_mutex); 718c2ecf20Sopenharmony_ci spin_lock(&lock); 728c2ecf20Sopenharmony_ci if(timer_alive) 738c2ecf20Sopenharmony_ci goto err; 748c2ecf20Sopenharmony_ci#ifdef CONFIG_WATCHDOG_NOWAYOUT 758c2ecf20Sopenharmony_ci __module_get(THIS_MODULE); 768c2ecf20Sopenharmony_ci#endif 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#ifdef CONFIG_MCONSOLE 798c2ecf20Sopenharmony_ci sock = mconsole_notify_socket(); 808c2ecf20Sopenharmony_ci#endif 818c2ecf20Sopenharmony_ci err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock); 828c2ecf20Sopenharmony_ci if(err) 838c2ecf20Sopenharmony_ci goto err; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci timer_alive = 1; 868c2ecf20Sopenharmony_ci spin_unlock(&lock); 878c2ecf20Sopenharmony_ci mutex_unlock(&harddog_mutex); 888c2ecf20Sopenharmony_ci return stream_open(inode, file); 898c2ecf20Sopenharmony_cierr: 908c2ecf20Sopenharmony_ci spin_unlock(&lock); 918c2ecf20Sopenharmony_ci mutex_unlock(&harddog_mutex); 928c2ecf20Sopenharmony_ci return err; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciextern void stop_watchdog(int in_fd, int out_fd); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int harddog_release(struct inode *inode, struct file *file) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci /* 1008c2ecf20Sopenharmony_ci * Shut off the timer. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci spin_lock(&lock); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci stop_watchdog(harddog_in_fd, harddog_out_fd); 1068c2ecf20Sopenharmony_ci harddog_in_fd = -1; 1078c2ecf20Sopenharmony_ci harddog_out_fd = -1; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci timer_alive=0; 1108c2ecf20Sopenharmony_ci spin_unlock(&lock); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciextern int ping_watchdog(int fd); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic ssize_t harddog_write(struct file *file, const char __user *data, size_t len, 1188c2ecf20Sopenharmony_ci loff_t *ppos) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * Refresh the timer. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if(len) 1248c2ecf20Sopenharmony_ci return ping_watchdog(harddog_out_fd); 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int harddog_ioctl_unlocked(struct file *file, 1298c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci void __user *argp= (void __user *)arg; 1328c2ecf20Sopenharmony_ci static struct watchdog_info ident = { 1338c2ecf20Sopenharmony_ci WDIOC_SETTIMEOUT, 1348c2ecf20Sopenharmony_ci 0, 1358c2ecf20Sopenharmony_ci "UML Hardware Watchdog" 1368c2ecf20Sopenharmony_ci }; 1378c2ecf20Sopenharmony_ci switch (cmd) { 1388c2ecf20Sopenharmony_ci default: 1398c2ecf20Sopenharmony_ci return -ENOTTY; 1408c2ecf20Sopenharmony_ci case WDIOC_GETSUPPORT: 1418c2ecf20Sopenharmony_ci if(copy_to_user(argp, &ident, sizeof(ident))) 1428c2ecf20Sopenharmony_ci return -EFAULT; 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci case WDIOC_GETSTATUS: 1458c2ecf20Sopenharmony_ci case WDIOC_GETBOOTSTATUS: 1468c2ecf20Sopenharmony_ci return put_user(0,(int __user *)argp); 1478c2ecf20Sopenharmony_ci case WDIOC_KEEPALIVE: 1488c2ecf20Sopenharmony_ci return ping_watchdog(harddog_out_fd); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic long harddog_ioctl(struct file *file, 1538c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci long ret; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci mutex_lock(&harddog_mutex); 1588c2ecf20Sopenharmony_ci ret = harddog_ioctl_unlocked(file, cmd, arg); 1598c2ecf20Sopenharmony_ci mutex_unlock(&harddog_mutex); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic const struct file_operations harddog_fops = { 1658c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1668c2ecf20Sopenharmony_ci .write = harddog_write, 1678c2ecf20Sopenharmony_ci .unlocked_ioctl = harddog_ioctl, 1688c2ecf20Sopenharmony_ci .compat_ioctl = compat_ptr_ioctl, 1698c2ecf20Sopenharmony_ci .open = harddog_open, 1708c2ecf20Sopenharmony_ci .release = harddog_release, 1718c2ecf20Sopenharmony_ci .llseek = no_llseek, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic struct miscdevice harddog_miscdev = { 1758c2ecf20Sopenharmony_ci .minor = WATCHDOG_MINOR, 1768c2ecf20Sopenharmony_ci .name = "watchdog", 1778c2ecf20Sopenharmony_ci .fops = &harddog_fops, 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_cimodule_misc_device(harddog_miscdev); 180