diff options
Diffstat (limited to 'drivers/s390/char/sclp_quiesce.c')
| -rw-r--r-- | drivers/s390/char/sclp_quiesce.c | 107 |
1 files changed, 46 insertions, 61 deletions
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c index 56fa6916889..475e470d976 100644 --- a/drivers/s390/char/sclp_quiesce.c +++ b/drivers/s390/char/sclp_quiesce.c @@ -1,99 +1,84 @@ /* - * drivers/s390/char/sclp_quiesce.c * signal quiesce handler * - * (C) Copyright IBM Corp. 1999,2004 + * Copyright IBM Corp. 1999, 2004 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/cpumask.h> #include <linux/smp.h> #include <linux/init.h> -#include <asm/atomic.h> +#include <linux/reboot.h> +#include <linux/atomic.h> #include <asm/ptrace.h> -#include <asm/sigp.h> +#include <asm/smp.h> #include "sclp.h" +static void (*old_machine_restart)(char *); +static void (*old_machine_halt)(void); +static void (*old_machine_power_off)(void); -#ifdef CONFIG_SMP -/* Signal completion of shutdown process. All CPUs except the first to enter - * this function: go to stopped state. First CPU: wait until all other - * CPUs are in stopped or check stop state. Afterwards, load special PSW - * to indicate completion. */ -static void -do_load_quiesce_psw(void * __unused) -{ - static atomic_t cpuid = ATOMIC_INIT(-1); - psw_t quiesce_psw; - int cpu; - - if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) - signal_processor(smp_processor_id(), sigp_stop); - /* Wait for all other cpus to enter stopped state */ - for_each_online_cpu(cpu) { - if (cpu == smp_processor_id()) - continue; - while(!smp_cpu_not_running(cpu)) - cpu_relax(); - } - /* Quiesce the last cpu with the special psw */ - quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; - quiesce_psw.addr = 0xfff; - __load_psw(quiesce_psw); -} - -/* Shutdown handler. Perform shutdown function on all CPUs. */ -static void -do_machine_quiesce(void) -{ - on_each_cpu(do_load_quiesce_psw, NULL, 0, 0); -} -#else /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ -static void -do_machine_quiesce(void) +static void do_machine_quiesce(void) { psw_t quiesce_psw; - quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; + smp_send_stop(); + quiesce_psw.mask = + PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA | PSW_MASK_WAIT; quiesce_psw.addr = 0xfff; __load_psw(quiesce_psw); } -#endif - -extern void ctrl_alt_del(void); /* Handler for quiesce event. Start shutdown procedure. */ -static void -sclp_quiesce_handler(struct evbuf_header *evbuf) +static void sclp_quiesce_handler(struct evbuf_header *evbuf) { - _machine_restart = (void *) do_machine_quiesce; - _machine_halt = do_machine_quiesce; - _machine_power_off = do_machine_quiesce; + 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; + } ctrl_alt_del(); } +/* 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; + } +} + static struct sclp_register sclp_quiesce_event = { - .receive_mask = EvTyp_SigQuiesce_Mask, - .receiver_fn = sclp_quiesce_handler + .receive_mask = EVTYP_SIGQUIESCE_MASK, + .receiver_fn = sclp_quiesce_handler, + .pm_event_fn = sclp_quiesce_pm_event }; /* Initialize quiesce driver. */ -static int __init -sclp_quiesce_init(void) +static int __init sclp_quiesce_init(void) { - int rc; - - rc = sclp_register(&sclp_quiesce_event); - if (rc) - printk(KERN_WARNING "sclp: could not register quiesce handler " - "(rc=%d)\n", rc); - return rc; + return sclp_register(&sclp_quiesce_event); } module_init(sclp_quiesce_init); |
