18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *     signal quiesce handler
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright IBM Corp. 1999, 2004
68c2ecf20Sopenharmony_ci *  Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
78c2ecf20Sopenharmony_ci *             Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
128c2ecf20Sopenharmony_ci#include <linux/smp.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/reboot.h>
158c2ecf20Sopenharmony_ci#include <linux/atomic.h>
168c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
178c2ecf20Sopenharmony_ci#include <asm/smp.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "sclp.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic void (*old_machine_restart)(char *);
228c2ecf20Sopenharmony_cistatic void (*old_machine_halt)(void);
238c2ecf20Sopenharmony_cistatic void (*old_machine_power_off)(void);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* Shutdown handler. Signal completion of shutdown by loading special PSW. */
268c2ecf20Sopenharmony_cistatic void do_machine_quiesce(void)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	psw_t quiesce_psw;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	smp_send_stop();
318c2ecf20Sopenharmony_ci	quiesce_psw.mask =
328c2ecf20Sopenharmony_ci		PSW_MASK_BASE | PSW_MASK_EA | PSW_MASK_BA | PSW_MASK_WAIT;
338c2ecf20Sopenharmony_ci	quiesce_psw.addr = 0xfff;
348c2ecf20Sopenharmony_ci	__load_psw(quiesce_psw);
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* Handler for quiesce event. Start shutdown procedure. */
388c2ecf20Sopenharmony_cistatic void sclp_quiesce_handler(struct evbuf_header *evbuf)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	if (_machine_restart != (void *) do_machine_quiesce) {
418c2ecf20Sopenharmony_ci		old_machine_restart = _machine_restart;
428c2ecf20Sopenharmony_ci		old_machine_halt = _machine_halt;
438c2ecf20Sopenharmony_ci		old_machine_power_off = _machine_power_off;
448c2ecf20Sopenharmony_ci		_machine_restart = (void *) do_machine_quiesce;
458c2ecf20Sopenharmony_ci		_machine_halt = do_machine_quiesce;
468c2ecf20Sopenharmony_ci		_machine_power_off = do_machine_quiesce;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci	ctrl_alt_del();
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Undo machine restart/halt/power_off modification on resume */
528c2ecf20Sopenharmony_cistatic void sclp_quiesce_pm_event(struct sclp_register *reg,
538c2ecf20Sopenharmony_ci				  enum sclp_pm_event sclp_pm_event)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	switch (sclp_pm_event) {
568c2ecf20Sopenharmony_ci	case SCLP_PM_EVENT_RESTORE:
578c2ecf20Sopenharmony_ci		if (old_machine_restart) {
588c2ecf20Sopenharmony_ci			_machine_restart = old_machine_restart;
598c2ecf20Sopenharmony_ci			_machine_halt = old_machine_halt;
608c2ecf20Sopenharmony_ci			_machine_power_off = old_machine_power_off;
618c2ecf20Sopenharmony_ci			old_machine_restart = NULL;
628c2ecf20Sopenharmony_ci			old_machine_halt = NULL;
638c2ecf20Sopenharmony_ci			old_machine_power_off = NULL;
648c2ecf20Sopenharmony_ci		}
658c2ecf20Sopenharmony_ci		break;
668c2ecf20Sopenharmony_ci	case SCLP_PM_EVENT_FREEZE:
678c2ecf20Sopenharmony_ci	case SCLP_PM_EVENT_THAW:
688c2ecf20Sopenharmony_ci		break;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic struct sclp_register sclp_quiesce_event = {
738c2ecf20Sopenharmony_ci	.receive_mask = EVTYP_SIGQUIESCE_MASK,
748c2ecf20Sopenharmony_ci	.receiver_fn = sclp_quiesce_handler,
758c2ecf20Sopenharmony_ci	.pm_event_fn = sclp_quiesce_pm_event
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* Initialize quiesce driver. */
798c2ecf20Sopenharmony_cistatic int __init sclp_quiesce_init(void)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	return sclp_register(&sclp_quiesce_event);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_cidevice_initcall(sclp_quiesce_init);
84