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/config.h> 11 #include <linux/module.h> 12 #include <linux/types.h> 13 #include <linux/cpumask.h> 14 #include <linux/smp.h> 15 #include <linux/init.h> 16 #include <asm/atomic.h> 17 #include <asm/ptrace.h> 18 #include <asm/sigp.h> 19 20 #include "sclp.h" 21 22 23 #ifdef CONFIG_SMP 24 /* Signal completion of shutdown process. All CPUs except the first to enter 25 * this function: go to stopped state. First CPU: wait until all other 26 * CPUs are in stopped or check stop state. Afterwards, load special PSW 27 * to indicate completion. */ 28 static void 29 do_load_quiesce_psw(void * __unused) 30 { 31 static atomic_t cpuid = ATOMIC_INIT(-1); 32 psw_t quiesce_psw; 33 int cpu; 34 35 if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) 36 signal_processor(smp_processor_id(), sigp_stop); 37 /* Wait for all other cpus to enter stopped state */ 38 for_each_online_cpu(cpu) { 39 if (cpu == smp_processor_id()) 40 continue; 41 while(!smp_cpu_not_running(cpu)) 42 cpu_relax(); 43 } 44 /* Quiesce the last cpu with the special psw */ 45 quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; 46 quiesce_psw.addr = 0xfff; 47 __load_psw(quiesce_psw); 48 } 49 50 /* Shutdown handler. Perform shutdown function on all CPUs. */ 51 static void 52 do_machine_quiesce(void) 53 { 54 on_each_cpu(do_load_quiesce_psw, NULL, 0, 0); 55 } 56 #else 57 /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ 58 static void 59 do_machine_quiesce(void) 60 { 61 psw_t quiesce_psw; 62 63 quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; 64 quiesce_psw.addr = 0xfff; 65 __load_psw(quiesce_psw); 66 } 67 #endif 68 69 extern void ctrl_alt_del(void); 70 71 /* Handler for quiesce event. Start shutdown procedure. */ 72 static void 73 sclp_quiesce_handler(struct evbuf_header *evbuf) 74 { 75 _machine_restart = (void *) do_machine_quiesce; 76 _machine_halt = do_machine_quiesce; 77 _machine_power_off = do_machine_quiesce; 78 ctrl_alt_del(); 79 } 80 81 static struct sclp_register sclp_quiesce_event = { 82 .receive_mask = EvTyp_SigQuiesce_Mask, 83 .receiver_fn = sclp_quiesce_handler 84 }; 85 86 /* Initialize quiesce driver. */ 87 static int __init 88 sclp_quiesce_init(void) 89 { 90 int rc; 91 92 rc = sclp_register(&sclp_quiesce_event); 93 if (rc) 94 printk(KERN_WARNING "sclp: could not register quiesce handler " 95 "(rc=%d)\n", rc); 96 return rc; 97 } 98 99 module_init(sclp_quiesce_init); 100