1 /* 2 * drivers/s390/char/sclp_quiesce.c 3 * signal quiesce handler 4 * 5 * (C) Copyright IBM Corp. 1999,2004 6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 7 * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/types.h> 12 #include <linux/cpumask.h> 13 #include <linux/smp.h> 14 #include <linux/init.h> 15 #include <linux/reboot.h> 16 #include <linux/atomic.h> 17 #include <asm/ptrace.h> 18 #include <asm/smp.h> 19 20 #include "sclp.h" 21 22 static void (*old_machine_restart)(char *); 23 static void (*old_machine_halt)(void); 24 static void (*old_machine_power_off)(void); 25 26 /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ do_machine_quiesce(void)27static void do_machine_quiesce(void) 28 { 29 psw_t quiesce_psw; 30 31 smp_send_stop(); 32 quiesce_psw.mask = 33 PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA | PSW_MASK_WAIT; 34 quiesce_psw.addr = 0xfff; 35 __load_psw(quiesce_psw); 36 } 37 38 /* Handler for quiesce event. Start shutdown procedure. */ sclp_quiesce_handler(struct evbuf_header * evbuf)39static void sclp_quiesce_handler(struct evbuf_header *evbuf) 40 { 41 if (_machine_restart != (void *) do_machine_quiesce) { 42 old_machine_restart = _machine_restart; 43 old_machine_halt = _machine_halt; 44 old_machine_power_off = _machine_power_off; 45 _machine_restart = (void *) do_machine_quiesce; 46 _machine_halt = do_machine_quiesce; 47 _machine_power_off = do_machine_quiesce; 48 } 49 ctrl_alt_del(); 50 } 51 52 /* Undo machine restart/halt/power_off modification on resume */ sclp_quiesce_pm_event(struct sclp_register * reg,enum sclp_pm_event sclp_pm_event)53static void sclp_quiesce_pm_event(struct sclp_register *reg, 54 enum sclp_pm_event sclp_pm_event) 55 { 56 switch (sclp_pm_event) { 57 case SCLP_PM_EVENT_RESTORE: 58 if (old_machine_restart) { 59 _machine_restart = old_machine_restart; 60 _machine_halt = old_machine_halt; 61 _machine_power_off = old_machine_power_off; 62 old_machine_restart = NULL; 63 old_machine_halt = NULL; 64 old_machine_power_off = NULL; 65 } 66 break; 67 case SCLP_PM_EVENT_FREEZE: 68 case SCLP_PM_EVENT_THAW: 69 break; 70 } 71 } 72 73 static struct sclp_register sclp_quiesce_event = { 74 .receive_mask = EVTYP_SIGQUIESCE_MASK, 75 .receiver_fn = sclp_quiesce_handler, 76 .pm_event_fn = sclp_quiesce_pm_event 77 }; 78 79 /* Initialize quiesce driver. */ sclp_quiesce_init(void)80static int __init sclp_quiesce_init(void) 81 { 82 return sclp_register(&sclp_quiesce_event); 83 } 84 85 module_init(sclp_quiesce_init); 86