linux/drivers/s390/char/sclp_quiesce.c
<<
>>
Prefs
   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 <asm/atomic.h>
  17#include <asm/ptrace.h>
  18#include <asm/sigp.h>
  19#include <asm/smp.h>
  20
  21#include "sclp.h"
  22
  23static void (*old_machine_restart)(char *);
  24static void (*old_machine_halt)(void);
  25static void (*old_machine_power_off)(void);
  26
  27/* Shutdown handler. Signal completion of shutdown by loading special PSW. */
  28static void do_machine_quiesce(void)
  29{
  30        psw_t quiesce_psw;
  31
  32        smp_send_stop();
  33        quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT;
  34        quiesce_psw.addr = 0xfff;
  35        __load_psw(quiesce_psw);
  36}
  37
  38/* Handler for quiesce event. Start shutdown procedure. */
  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 */
  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
  73static 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. */
  80static int __init sclp_quiesce_init(void)
  81{
  82        return sclp_register(&sclp_quiesce_event);
  83}
  84
  85module_init(sclp_quiesce_init);
  86