Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
1da177e4 LT |
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> | |
83cc5ed3 | 15 | #include <linux/reboot.h> |
1da177e4 LT |
16 | #include <asm/atomic.h> |
17 | #include <asm/ptrace.h> | |
18 | #include <asm/sigp.h> | |
188596fa | 19 | #include <asm/smp.h> |
1da177e4 LT |
20 | |
21 | #include "sclp.h" | |
22 | ||
8b94c1ed MS |
23 | static void (*old_machine_restart)(char *); |
24 | static void (*old_machine_halt)(void); | |
25 | static void (*old_machine_power_off)(void); | |
26 | ||
1da177e4 | 27 | /* Shutdown handler. Signal completion of shutdown by loading special PSW. */ |
8b94c1ed | 28 | static void do_machine_quiesce(void) |
1da177e4 LT |
29 | { |
30 | psw_t quiesce_psw; | |
31 | ||
c6b5b847 | 32 | smp_send_stop(); |
1da177e4 LT |
33 | quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; |
34 | quiesce_psw.addr = 0xfff; | |
35 | __load_psw(quiesce_psw); | |
36 | } | |
1da177e4 | 37 | |
1da177e4 | 38 | /* Handler for quiesce event. Start shutdown procedure. */ |
8b94c1ed | 39 | static void sclp_quiesce_handler(struct evbuf_header *evbuf) |
1da177e4 | 40 | { |
8b94c1ed MS |
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 | } | |
1da177e4 LT |
49 | ctrl_alt_del(); |
50 | } | |
51 | ||
8b94c1ed MS |
52 | /* Undo machine restart/halt/power_off modification on resume */ |
53 | static 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 | ||
1da177e4 | 73 | static struct sclp_register sclp_quiesce_event = { |
6d4740c8 | 74 | .receive_mask = EVTYP_SIGQUIESCE_MASK, |
8b94c1ed MS |
75 | .receiver_fn = sclp_quiesce_handler, |
76 | .pm_event_fn = sclp_quiesce_pm_event | |
1da177e4 LT |
77 | }; |
78 | ||
79 | /* Initialize quiesce driver. */ | |
8b94c1ed | 80 | static int __init sclp_quiesce_init(void) |
1da177e4 | 81 | { |
a12c53f4 | 82 | return sclp_register(&sclp_quiesce_event); |
1da177e4 LT |
83 | } |
84 | ||
85 | module_init(sclp_quiesce_init); |