summary refs log tree commit diff
path: root/drivers/s390/char/sclp_quiesce.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char/sclp_quiesce.c')
-rw-r--r--drivers/s390/char/sclp_quiesce.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index 84c191c1cd62..05909a7df8b3 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -20,9 +20,12 @@
 
 #include "sclp.h"
 
+static void (*old_machine_restart)(char *);
+static void (*old_machine_halt)(void);
+static void (*old_machine_power_off)(void);
+
 /* 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;
 
@@ -33,23 +36,48 @@ do_machine_quiesce(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
+	.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)
 {
 	return sclp_register(&sclp_quiesce_event);
 }