2005-04-17 02:20:36 +04:00
/*
* signal quiesce handler
*
2012-07-20 13:15:04 +04:00
* Copyright IBM Corp . 1999 , 2004
2005-04-17 02:20:36 +04:00
* Author ( s ) : Martin Schwidefsky < schwidefsky @ de . ibm . com >
* Peter Oberparleiter < peter . oberparleiter @ de . ibm . com >
*/
# include <linux/types.h>
# include <linux/cpumask.h>
# include <linux/smp.h>
# include <linux/init.h>
2006-06-25 16:47:41 +04:00
# include <linux/reboot.h>
2011-07-27 03:09:06 +04:00
# include <linux/atomic.h>
2005-04-17 02:20:36 +04:00
# include <asm/ptrace.h>
2007-02-21 12:55:03 +03:00
# include <asm/smp.h>
2005-04-17 02:20:36 +04:00
# include "sclp.h"
2009-11-13 17:43:53 +03:00
static void ( * old_machine_restart ) ( char * ) ;
static void ( * old_machine_halt ) ( void ) ;
static void ( * old_machine_power_off ) ( void ) ;
2005-04-17 02:20:36 +04:00
/* Shutdown handler. Signal completion of shutdown by loading special PSW. */
2009-11-13 17:43:53 +03:00
static void do_machine_quiesce ( void )
2005-04-17 02:20:36 +04:00
{
psw_t quiesce_psw ;
2006-12-04 17:40:33 +03:00
smp_send_stop ( ) ;
2011-10-30 18:16:50 +04:00
quiesce_psw . mask =
PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA | PSW_MASK_WAIT ;
2005-04-17 02:20:36 +04:00
quiesce_psw . addr = 0xfff ;
__load_psw ( quiesce_psw ) ;
}
/* Handler for quiesce event. Start shutdown procedure. */
2009-11-13 17:43:53 +03:00
static void sclp_quiesce_handler ( struct evbuf_header * evbuf )
2005-04-17 02:20:36 +04:00
{
2009-11-13 17:43:53 +03:00
if ( _machine_restart ! = ( void * ) do_machine_quiesce ) {
old_machine_restart = _machine_restart ;
old_machine_halt = _machine_halt ;
old_machine_power_off = _machine_power_off ;
_machine_restart = ( void * ) do_machine_quiesce ;
_machine_halt = do_machine_quiesce ;
_machine_power_off = do_machine_quiesce ;
}
2005-04-17 02:20:36 +04:00
ctrl_alt_del ( ) ;
}
2009-11-13 17:43:53 +03:00
/* Undo machine restart/halt/power_off modification on resume */
static void sclp_quiesce_pm_event ( struct sclp_register * reg ,
enum sclp_pm_event sclp_pm_event )
{
switch ( sclp_pm_event ) {
case SCLP_PM_EVENT_RESTORE :
if ( old_machine_restart ) {
_machine_restart = old_machine_restart ;
_machine_halt = old_machine_halt ;
_machine_power_off = old_machine_power_off ;
old_machine_restart = NULL ;
old_machine_halt = NULL ;
old_machine_power_off = NULL ;
}
break ;
case SCLP_PM_EVENT_FREEZE :
case SCLP_PM_EVENT_THAW :
break ;
}
}
2005-04-17 02:20:36 +04:00
static struct sclp_register sclp_quiesce_event = {
2007-04-27 18:01:53 +04:00
. receive_mask = EVTYP_SIGQUIESCE_MASK ,
2009-11-13 17:43:53 +03:00
. receiver_fn = sclp_quiesce_handler ,
. pm_event_fn = sclp_quiesce_pm_event
2005-04-17 02:20:36 +04:00
} ;
/* Initialize quiesce driver. */
2009-11-13 17:43:53 +03:00
static int __init sclp_quiesce_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-07-14 11:59:28 +04:00
return sclp_register ( & sclp_quiesce_event ) ;
2005-04-17 02:20:36 +04:00
}
2016-10-30 23:37:28 +03:00
device_initcall ( sclp_quiesce_init ) ;