2014-06-05 13:01:43 +04:00
/*
2014-06-05 13:02:36 +04:00
* Watchdog driver for z / VM and LPAR using the diag 288 interface .
2014-06-05 13:01:43 +04:00
*
* Under z / VM , expiration of the watchdog will send a " system restart " command
* to CP .
*
2014-06-05 13:02:36 +04:00
* The command can be altered using the module parameter " cmd " . This is
* not recommended because it ' s only supported on z / VM but not whith LPAR .
*
* On LPAR , the watchdog will always trigger a system restart . the module
* paramter cmd is meaningless here .
*
2014-06-05 13:01:43 +04:00
*
* Copyright IBM Corp . 2004 , 2013
* Author ( s ) : Arnd Bergmann ( arndb @ de . ibm . com )
* Philipp Hachtmann ( phacht @ de . ibm . com )
*
*/
# define KMSG_COMPONENT "diag288_wdt"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/slab.h>
# include <linux/miscdevice.h>
# include <linux/watchdog.h>
# include <linux/suspend.h>
# include <asm/ebcdic.h>
2015-08-20 18:28:44 +03:00
# include <asm/diag.h>
2014-06-05 13:01:43 +04:00
# include <linux/io.h>
# include <linux/uaccess.h>
# define MAX_CMDLEN 240
# define DEFAULT_CMD "SYSTEM RESTART"
# define MIN_INTERVAL 15 /* Minimal time supported by diag88 */
# define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
# define WDT_DEFAULT_TIMEOUT 30
/* Function codes - init, change, cancel */
# define WDT_FUNC_INIT 0
# define WDT_FUNC_CHANGE 1
# define WDT_FUNC_CANCEL 2
# define WDT_FUNC_CONCEAL 0x80000000
2014-06-05 13:02:36 +04:00
/* Action codes for LPAR watchdog */
# define LPARWDT_RESTART 0
2014-06-05 13:01:43 +04:00
static char wdt_cmd [ MAX_CMDLEN ] = DEFAULT_CMD ;
static bool conceal_on ;
static bool nowayout_info = WATCHDOG_NOWAYOUT ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Arnd Bergmann <arndb@de.ibm.com> " ) ;
MODULE_AUTHOR ( " Philipp Hachtmann <phacht@de.ibm.com> " ) ;
MODULE_DESCRIPTION ( " System z diag288 Watchdog Timer " ) ;
module_param_string ( cmd , wdt_cmd , MAX_CMDLEN , 0644 ) ;
MODULE_PARM_DESC ( cmd , " CP command that is run when the watchdog triggers (z/VM only) " ) ;
module_param_named ( conceal , conceal_on , bool , 0644 ) ;
MODULE_PARM_DESC ( conceal , " Enable the CONCEAL CP option while the watchdog is active (z/VM only) " ) ;
module_param_named ( nowayout , nowayout_info , bool , 0444 ) ;
MODULE_PARM_DESC ( nowayout , " Watchdog cannot be stopped once started (default = CONFIG_WATCHDOG_NOWAYOUT) " ) ;
MODULE_ALIAS_MISCDEV ( WATCHDOG_MINOR ) ;
MODULE_ALIAS ( " vmwatchdog " ) ;
static int __diag288 ( unsigned int func , unsigned int timeout ,
unsigned long action , unsigned int len )
{
register unsigned long __func asm ( " 2 " ) = func ;
register unsigned long __timeout asm ( " 3 " ) = timeout ;
register unsigned long __action asm ( " 4 " ) = action ;
register unsigned long __len asm ( " 5 " ) = len ;
int err ;
err = - EINVAL ;
asm volatile (
" diag %1, %3, 0x288 \n "
" 0: la %0, 0 \n "
" 1: \n "
EX_TABLE ( 0 b , 1 b )
: " +d " ( err ) : " d " ( __func ) , " d " ( __timeout ) ,
" d " ( __action ) , " d " ( __len ) : " 1 " , " cc " ) ;
return err ;
}
static int __diag288_vm ( unsigned int func , unsigned int timeout ,
char * cmd , size_t len )
{
2015-08-20 18:28:44 +03:00
diag_stat_inc ( DIAG_STAT_X288 ) ;
2014-06-05 13:01:43 +04:00
return __diag288 ( func , timeout , virt_to_phys ( cmd ) , len ) ;
}
2014-06-05 13:02:36 +04:00
static int __diag288_lpar ( unsigned int func , unsigned int timeout ,
unsigned long action )
{
2015-08-20 18:28:44 +03:00
diag_stat_inc ( DIAG_STAT_X288 ) ;
2014-06-05 13:02:36 +04:00
return __diag288 ( func , timeout , action , 0 ) ;
}
2015-12-26 03:01:41 +03:00
static unsigned long wdt_status ;
# define DIAG_WDOG_BUSY 0
2014-06-05 13:01:43 +04:00
static int wdt_start ( struct watchdog_device * dev )
{
char * ebc_cmd ;
size_t len ;
int ret ;
unsigned int func ;
2015-12-26 03:01:41 +03:00
if ( test_and_set_bit ( DIAG_WDOG_BUSY , & wdt_status ) )
return - EBUSY ;
2014-06-05 13:01:43 +04:00
ret = - ENODEV ;
if ( MACHINE_IS_VM ) {
ebc_cmd = kmalloc ( MAX_CMDLEN , GFP_KERNEL ) ;
2015-12-26 03:01:41 +03:00
if ( ! ebc_cmd ) {
clear_bit ( DIAG_WDOG_BUSY , & wdt_status ) ;
2014-06-05 13:01:43 +04:00
return - ENOMEM ;
2015-12-26 03:01:41 +03:00
}
2014-06-05 13:01:43 +04:00
len = strlcpy ( ebc_cmd , wdt_cmd , MAX_CMDLEN ) ;
ASCEBC ( ebc_cmd , MAX_CMDLEN ) ;
EBC_TOUPPER ( ebc_cmd , MAX_CMDLEN ) ;
func = conceal_on ? ( WDT_FUNC_INIT | WDT_FUNC_CONCEAL )
: WDT_FUNC_INIT ;
ret = __diag288_vm ( func , dev - > timeout , ebc_cmd , len ) ;
WARN_ON ( ret ! = 0 ) ;
kfree ( ebc_cmd ) ;
2015-03-06 11:26:30 +03:00
} else {
2014-06-05 13:02:36 +04:00
ret = __diag288_lpar ( WDT_FUNC_INIT ,
dev - > timeout , LPARWDT_RESTART ) ;
}
2014-06-05 13:01:43 +04:00
if ( ret ) {
pr_err ( " The watchdog cannot be activated \n " ) ;
2015-12-26 03:01:41 +03:00
clear_bit ( DIAG_WDOG_BUSY , & wdt_status ) ;
2014-06-05 13:01:43 +04:00
return ret ;
}
return 0 ;
}
static int wdt_stop ( struct watchdog_device * dev )
{
int ret ;
2015-08-20 18:28:44 +03:00
diag_stat_inc ( DIAG_STAT_X288 ) ;
2014-06-05 13:01:43 +04:00
ret = __diag288 ( WDT_FUNC_CANCEL , 0 , 0 , 0 ) ;
2015-12-26 03:01:41 +03:00
clear_bit ( DIAG_WDOG_BUSY , & wdt_status ) ;
2014-06-05 13:01:43 +04:00
return ret ;
}
static int wdt_ping ( struct watchdog_device * dev )
{
char * ebc_cmd ;
size_t len ;
int ret ;
unsigned int func ;
ret = - ENODEV ;
if ( MACHINE_IS_VM ) {
ebc_cmd = kmalloc ( MAX_CMDLEN , GFP_KERNEL ) ;
if ( ! ebc_cmd )
return - ENOMEM ;
len = strlcpy ( ebc_cmd , wdt_cmd , MAX_CMDLEN ) ;
ASCEBC ( ebc_cmd , MAX_CMDLEN ) ;
EBC_TOUPPER ( ebc_cmd , MAX_CMDLEN ) ;
/*
* It seems to be ok to z / VM to use the init function to
2014-06-05 13:02:36 +04:00
* retrigger the watchdog . On LPAR WDT_FUNC_CHANGE must
* be used when the watchdog is running .
2014-06-05 13:01:43 +04:00
*/
func = conceal_on ? ( WDT_FUNC_INIT | WDT_FUNC_CONCEAL )
: WDT_FUNC_INIT ;
ret = __diag288_vm ( func , dev - > timeout , ebc_cmd , len ) ;
WARN_ON ( ret ! = 0 ) ;
kfree ( ebc_cmd ) ;
2015-03-06 11:26:30 +03:00
} else {
2014-06-05 13:02:36 +04:00
ret = __diag288_lpar ( WDT_FUNC_CHANGE , dev - > timeout , 0 ) ;
2015-03-06 11:26:30 +03:00
}
2014-06-05 13:02:36 +04:00
2014-06-05 13:01:43 +04:00
if ( ret )
pr_err ( " The watchdog timer cannot be started or reset \n " ) ;
return ret ;
}
static int wdt_set_timeout ( struct watchdog_device * dev , unsigned int new_to )
{
dev - > timeout = new_to ;
return wdt_ping ( dev ) ;
}
2017-01-28 10:41:17 +03:00
static const struct watchdog_ops wdt_ops = {
2014-06-05 13:01:43 +04:00
. owner = THIS_MODULE ,
. start = wdt_start ,
. stop = wdt_stop ,
. ping = wdt_ping ,
. set_timeout = wdt_set_timeout ,
} ;
static struct watchdog_info wdt_info = {
2015-03-06 11:26:29 +03:00
. options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE ,
2014-06-05 13:01:43 +04:00
. firmware_version = 0 ,
. identity = " z Watchdog " ,
} ;
static struct watchdog_device wdt_dev = {
. parent = NULL ,
. info = & wdt_info ,
. ops = & wdt_ops ,
. bootstatus = 0 ,
. timeout = WDT_DEFAULT_TIMEOUT ,
. min_timeout = MIN_INTERVAL ,
. max_timeout = MAX_INTERVAL ,
} ;
/*
* It makes no sense to go into suspend while the watchdog is running .
* Depending on the memory size , the watchdog might trigger , while we
* are still saving the memory .
*/
static int wdt_suspend ( void )
{
2015-12-26 03:01:41 +03:00
if ( test_and_set_bit ( DIAG_WDOG_BUSY , & wdt_status ) ) {
2014-06-05 13:01:43 +04:00
pr_err ( " Linux cannot be suspended while the watchdog is in use \n " ) ;
return notifier_from_errno ( - EBUSY ) ;
}
return NOTIFY_DONE ;
}
static int wdt_resume ( void )
{
2015-12-26 03:01:41 +03:00
clear_bit ( DIAG_WDOG_BUSY , & wdt_status ) ;
2014-06-05 13:01:43 +04:00
return NOTIFY_DONE ;
}
static int wdt_power_event ( struct notifier_block * this , unsigned long event ,
void * ptr )
{
switch ( event ) {
case PM_POST_HIBERNATION :
case PM_POST_SUSPEND :
return wdt_resume ( ) ;
case PM_HIBERNATION_PREPARE :
case PM_SUSPEND_PREPARE :
return wdt_suspend ( ) ;
default :
return NOTIFY_DONE ;
}
}
static struct notifier_block wdt_power_notifier = {
. notifier_call = wdt_power_event ,
} ;
static int __init diag288_init ( void )
{
int ret ;
char ebc_begin [ ] = {
194 , 197 , 199 , 201 , 213
} ;
watchdog_set_nowayout ( & wdt_dev , nowayout_info ) ;
if ( MACHINE_IS_VM ) {
if ( __diag288_vm ( WDT_FUNC_INIT , 15 ,
ebc_begin , sizeof ( ebc_begin ) ) ! = 0 ) {
pr_err ( " The watchdog cannot be initialized \n " ) ;
return - EINVAL ;
}
2015-03-06 11:26:30 +03:00
} else {
2014-06-05 13:02:36 +04:00
if ( __diag288_lpar ( WDT_FUNC_INIT , 30 , LPARWDT_RESTART ) ) {
pr_err ( " The watchdog cannot be initialized \n " ) ;
return - EINVAL ;
}
2014-06-05 13:01:43 +04:00
}
2014-06-05 13:02:36 +04:00
if ( __diag288_lpar ( WDT_FUNC_CANCEL , 0 , 0 ) ) {
2014-06-05 13:01:43 +04:00
pr_err ( " The watchdog cannot be deactivated \n " ) ;
return - EINVAL ;
}
ret = register_pm_notifier ( & wdt_power_notifier ) ;
if ( ret )
return ret ;
ret = watchdog_register_device ( & wdt_dev ) ;
if ( ret )
unregister_pm_notifier ( & wdt_power_notifier ) ;
return ret ;
}
static void __exit diag288_exit ( void )
{
watchdog_unregister_device ( & wdt_dev ) ;
unregister_pm_notifier ( & wdt_power_notifier ) ;
}
module_init ( diag288_init ) ;
module_exit ( diag288_exit ) ;