2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
* IndyDog 0.3 A Hardware Watchdog Device for SGI IP22
*
2008-05-19 17:06:08 +04:00
* ( c ) Copyright 2002 Guido Guenther < agx @ sigxcpu . org > ,
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2008-10-27 18:17:56 +03:00
* based on softdog . c by Alan Cox < alan @ lxorguk . ukuu . org . uk >
2005-04-17 02:20:36 +04:00
*/
2012-02-16 03:06:19 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/fs.h>
# include <linux/mm.h>
# include <linux/miscdevice.h>
# include <linux/watchdog.h>
# include <linux/notifier.h>
# include <linux/reboot.h>
# include <linux/init.h>
2008-05-19 17:06:08 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/sgi/mc.h>
2008-05-19 17:06:08 +04:00
static unsigned long indydog_alive ;
2011-11-29 09:54:01 +04:00
static DEFINE_SPINLOCK ( indydog_lock ) ;
2005-04-17 02:20:36 +04:00
# define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
2012-03-05 19:51:11 +04:00
static bool nowayout = WATCHDOG_NOWAYOUT ;
module_param ( nowayout , bool , 0 ) ;
2008-05-19 17:06:08 +04:00
MODULE_PARM_DESC ( nowayout ,
" Watchdog cannot be stopped once started (default= "
__MODULE_STRING ( WATCHDOG_NOWAYOUT ) " ) " ) ;
2005-04-17 02:20:36 +04:00
static void indydog_start ( void )
{
2008-05-19 17:06:08 +04:00
spin_lock ( & indydog_lock ) ;
2014-02-15 13:21:51 +04:00
sgimc - > cpuctrl0 | = SGIMC_CCTRL0_WDOG ;
2008-05-19 17:06:08 +04:00
spin_unlock ( & indydog_lock ) ;
2005-04-17 02:20:36 +04:00
}
static void indydog_stop ( void )
{
2008-05-19 17:06:08 +04:00
spin_lock ( & indydog_lock ) ;
2014-02-15 13:21:51 +04:00
sgimc - > cpuctrl0 & = ~ SGIMC_CCTRL0_WDOG ;
2008-05-19 17:06:08 +04:00
spin_unlock ( & indydog_lock ) ;
2005-04-17 02:20:36 +04:00
2012-02-16 03:06:19 +04:00
pr_info ( " Stopped watchdog timer \n " ) ;
2005-04-17 02:20:36 +04:00
}
static void indydog_ping ( void )
{
sgimc - > watchdogt = 0 ;
}
/*
* Allow only one person to hold it open
*/
static int indydog_open ( struct inode * inode , struct file * file )
{
2008-05-19 17:06:08 +04:00
if ( test_and_set_bit ( 0 , & indydog_alive ) )
2005-04-17 02:20:36 +04:00
return - EBUSY ;
if ( nowayout )
__module_get ( THIS_MODULE ) ;
/* Activate timer */
indydog_start ( ) ;
indydog_ping ( ) ;
2012-02-16 03:06:19 +04:00
pr_info ( " Started watchdog timer \n " ) ;
2005-04-17 02:20:36 +04:00
2019-03-26 23:51:19 +03:00
return stream_open ( inode , file ) ;
2005-04-17 02:20:36 +04:00
}
static int indydog_release ( struct inode * inode , struct file * file )
{
/* Shut off the timer.
* Lock it in if it ' s a module and we defined . . . NOWAYOUT */
if ( ! nowayout )
indydog_stop ( ) ; /* Turn the WDT off */
2008-05-19 17:06:08 +04:00
clear_bit ( 0 , & indydog_alive ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-05-19 17:06:08 +04:00
static ssize_t indydog_write ( struct file * file , const char * data ,
size_t len , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
/* Refresh the timer. */
2008-05-19 17:06:08 +04:00
if ( len )
2005-04-17 02:20:36 +04:00
indydog_ping ( ) ;
return len ;
}
2008-05-19 17:06:08 +04:00
static long indydog_ioctl ( struct file * file , unsigned int cmd ,
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
int options , retval = - EINVAL ;
2009-12-26 21:55:22 +03:00
static const struct watchdog_info ident = {
2009-05-11 22:33:00 +04:00
. options = WDIOF_KEEPALIVEPING ,
2005-04-17 02:20:36 +04:00
. firmware_version = 0 ,
. identity = " Hardware Watchdog for SGI IP22 " ,
} ;
switch ( cmd ) {
2008-05-19 17:06:08 +04:00
case WDIOC_GETSUPPORT :
if ( copy_to_user ( ( struct watchdog_info * ) arg ,
& ident , sizeof ( ident ) ) )
return - EFAULT ;
return 0 ;
case WDIOC_GETSTATUS :
case WDIOC_GETBOOTSTATUS :
return put_user ( 0 , ( int * ) arg ) ;
case WDIOC_SETOPTIONS :
{
if ( get_user ( options , ( int * ) arg ) )
return - EFAULT ;
if ( options & WDIOS_DISABLECARD ) {
indydog_stop ( ) ;
retval = 0 ;
}
if ( options & WDIOS_ENABLECARD ) {
indydog_start ( ) ;
retval = 0 ;
2005-04-17 02:20:36 +04:00
}
2008-05-19 17:06:08 +04:00
return retval ;
}
2008-07-18 15:41:17 +04:00
case WDIOC_KEEPALIVE :
indydog_ping ( ) ;
return 0 ;
case WDIOC_GETTIMEOUT :
return put_user ( WATCHDOG_TIMEOUT , ( int * ) arg ) ;
2008-05-19 17:06:08 +04:00
default :
return - ENOTTY ;
2005-04-17 02:20:36 +04:00
}
}
2008-05-19 17:06:08 +04:00
static int indydog_notify_sys ( struct notifier_block * this ,
unsigned long code , void * unused )
2005-04-17 02:20:36 +04:00
{
if ( code = = SYS_DOWN | | code = = SYS_HALT )
indydog_stop ( ) ; /* Turn the WDT off */
return NOTIFY_DONE ;
}
2006-07-03 11:24:21 +04:00
static const struct file_operations indydog_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. llseek = no_llseek ,
. write = indydog_write ,
2008-05-19 17:06:08 +04:00
. unlocked_ioctl = indydog_ioctl ,
2005-04-17 02:20:36 +04:00
. open = indydog_open ,
. release = indydog_release ,
} ;
static struct miscdevice indydog_miscdev = {
. minor = WATCHDOG_MINOR ,
. name = " watchdog " ,
. fops = & indydog_fops ,
} ;
static struct notifier_block indydog_notifier = {
. notifier_call = indydog_notify_sys ,
} ;
static int __init watchdog_init ( void )
{
int ret ;
ret = register_reboot_notifier ( & indydog_notifier ) ;
if ( ret ) {
2012-02-16 03:06:19 +04:00
pr_err ( " cannot register reboot notifier (err=%d) \n " , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
ret = misc_register ( & indydog_miscdev ) ;
if ( ret ) {
2012-02-16 03:06:19 +04:00
pr_err ( " cannot register miscdev on minor=%d (err=%d) \n " ,
WATCHDOG_MINOR , ret ) ;
2005-04-17 02:20:36 +04:00
unregister_reboot_notifier ( & indydog_notifier ) ;
return ret ;
}
2012-02-16 03:06:19 +04:00
pr_info ( " Hardware Watchdog Timer for SGI IP22: 0.3 \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void __exit watchdog_exit ( void )
{
misc_deregister ( & indydog_miscdev ) ;
unregister_reboot_notifier ( & indydog_notifier ) ;
}
module_init ( watchdog_init ) ;
module_exit ( watchdog_exit ) ;
MODULE_AUTHOR ( " Guido Guenther <agx@sigxcpu.org> " ) ;
MODULE_DESCRIPTION ( " Hardware Watchdog Device for SGI IP22 " ) ;
MODULE_LICENSE ( " GPL " ) ;