aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/char
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@de.ibm.com>2009-06-16 04:30:40 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-06-16 04:31:16 -0400
commit62b7494209495847269a6ce0504cbefd23d42eb1 (patch)
tree6318661837ddd250dc86b48a94f44fa2d1ae9421 /drivers/s390/char
parent3ef32e62cb55785f6f1b5ad7290744f74bdadaf0 (diff)
[S390] pm: power management support for SCLP drivers.
The SCLP base driver defines a new notifier call back for all upper level SCLP drivers, like the SCLP console, etc. This guarantees that in suspend first the upper level drivers are suspended and afterwards the SCLP base driver. For resume it is the other way round. The SCLP base driver itself registers a new platform device at the platform bus and gets PM notifications via the dev_pm_ops. In suspend, the SCLP base driver switches off the receiver and sender mask This is done in sclp_deactivate(). After suspend all new requests will be rejected with -EIO and no more interrupts will be received, because the masks are switched off. For resume the sender and receiver masks are reset in the sclp_reactivate() function. When the SCLP console is suspended, all new messages are cached in the sclp console buffers. In resume, all the cached messages are written to the console. In addition to that we have an early resume function that removes the cached messages from the suspend image. Signed-off-by: Michael Holzheu <holzheu@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/char')
-rw-r--r--drivers/s390/char/sclp.c248
-rw-r--r--drivers/s390/char/sclp.h23
-rw-r--r--drivers/s390/char/sclp_con.c139
-rw-r--r--drivers/s390/char/sclp_rw.c20
-rw-r--r--drivers/s390/char/sclp_rw.h12
-rw-r--r--drivers/s390/char/sclp_vt220.c118
6 files changed, 432 insertions, 128 deletions
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 4377e93a43d7..a983f5086788 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -1,11 +1,10 @@
1/* 1/*
2 * drivers/s390/char/sclp.c 2 * core function to access sclp interface
3 * core function to access sclp interface
4 * 3 *
5 * S390 version 4 * Copyright IBM Corp. 1999, 2009
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 *
7 * Author(s): Martin Peschke <mpeschke@de.ibm.com> 6 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
8 * Martin Schwidefsky <schwidefsky@de.ibm.com> 7 * Martin Schwidefsky <schwidefsky@de.ibm.com>
9 */ 8 */
10 9
11#include <linux/module.h> 10#include <linux/module.h>
@@ -16,6 +15,9 @@
16#include <linux/reboot.h> 15#include <linux/reboot.h>
17#include <linux/jiffies.h> 16#include <linux/jiffies.h>
18#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/suspend.h>
19#include <linux/completion.h>
20#include <linux/platform_device.h>
19#include <asm/types.h> 21#include <asm/types.h>
20#include <asm/s390_ext.h> 22#include <asm/s390_ext.h>
21 23
@@ -47,6 +49,16 @@ static struct sclp_req sclp_init_req;
47static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); 49static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
48static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); 50static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
49 51
52/* Suspend request */
53static DECLARE_COMPLETION(sclp_request_queue_flushed);
54
55static void sclp_suspend_req_cb(struct sclp_req *req, void *data)
56{
57 complete(&sclp_request_queue_flushed);
58}
59
60static struct sclp_req sclp_suspend_req;
61
50/* Timer for request retries. */ 62/* Timer for request retries. */
51static struct timer_list sclp_request_timer; 63static struct timer_list sclp_request_timer;
52 64
@@ -84,6 +96,12 @@ static volatile enum sclp_mask_state_t {
84 sclp_mask_state_initializing 96 sclp_mask_state_initializing
85} sclp_mask_state = sclp_mask_state_idle; 97} sclp_mask_state = sclp_mask_state_idle;
86 98
99/* Internal state: is the driver suspended? */
100static enum sclp_suspend_state_t {
101 sclp_suspend_state_running,
102 sclp_suspend_state_suspended,
103} sclp_suspend_state = sclp_suspend_state_running;
104
87/* Maximum retry counts */ 105/* Maximum retry counts */
88#define SCLP_INIT_RETRY 3 106#define SCLP_INIT_RETRY 3
89#define SCLP_MASK_RETRY 3 107#define SCLP_MASK_RETRY 3
@@ -211,6 +229,8 @@ sclp_process_queue(void)
211 del_timer(&sclp_request_timer); 229 del_timer(&sclp_request_timer);
212 while (!list_empty(&sclp_req_queue)) { 230 while (!list_empty(&sclp_req_queue)) {
213 req = list_entry(sclp_req_queue.next, struct sclp_req, list); 231 req = list_entry(sclp_req_queue.next, struct sclp_req, list);
232 if (!req->sccb)
233 goto do_post;
214 rc = __sclp_start_request(req); 234 rc = __sclp_start_request(req);
215 if (rc == 0) 235 if (rc == 0)
216 break; 236 break;
@@ -222,6 +242,7 @@ sclp_process_queue(void)
222 sclp_request_timeout, 0); 242 sclp_request_timeout, 0);
223 break; 243 break;
224 } 244 }
245do_post:
225 /* Post-processing for aborted request */ 246 /* Post-processing for aborted request */
226 list_del(&req->list); 247 list_del(&req->list);
227 if (req->callback) { 248 if (req->callback) {
@@ -233,6 +254,19 @@ sclp_process_queue(void)
233 spin_unlock_irqrestore(&sclp_lock, flags); 254 spin_unlock_irqrestore(&sclp_lock, flags);
234} 255}
235 256
257static int __sclp_can_add_request(struct sclp_req *req)
258{
259 if (req == &sclp_suspend_req || req == &sclp_init_req)
260 return 1;
261 if (sclp_suspend_state != sclp_suspend_state_running)
262 return 0;
263 if (sclp_init_state != sclp_init_state_initialized)
264 return 0;
265 if (sclp_activation_state != sclp_activation_state_active)
266 return 0;
267 return 1;
268}
269
236/* Queue a new request. Return zero on success, non-zero otherwise. */ 270/* Queue a new request. Return zero on success, non-zero otherwise. */
237int 271int
238sclp_add_request(struct sclp_req *req) 272sclp_add_request(struct sclp_req *req)
@@ -241,9 +275,7 @@ sclp_add_request(struct sclp_req *req)
241 int rc; 275 int rc;
242 276
243 spin_lock_irqsave(&sclp_lock, flags); 277 spin_lock_irqsave(&sclp_lock, flags);
244 if ((sclp_init_state != sclp_init_state_initialized || 278 if (!__sclp_can_add_request(req)) {
245 sclp_activation_state != sclp_activation_state_active) &&
246 req != &sclp_init_req) {
247 spin_unlock_irqrestore(&sclp_lock, flags); 279 spin_unlock_irqrestore(&sclp_lock, flags);
248 return -EIO; 280 return -EIO;
249 } 281 }
@@ -254,10 +286,16 @@ sclp_add_request(struct sclp_req *req)
254 /* Start if request is first in list */ 286 /* Start if request is first in list */
255 if (sclp_running_state == sclp_running_state_idle && 287 if (sclp_running_state == sclp_running_state_idle &&
256 req->list.prev == &sclp_req_queue) { 288 req->list.prev == &sclp_req_queue) {
289 if (!req->sccb) {
290 list_del(&req->list);
291 rc = -ENODATA;
292 goto out;
293 }
257 rc = __sclp_start_request(req); 294 rc = __sclp_start_request(req);
258 if (rc) 295 if (rc)
259 list_del(&req->list); 296 list_del(&req->list);
260 } 297 }
298out:
261 spin_unlock_irqrestore(&sclp_lock, flags); 299 spin_unlock_irqrestore(&sclp_lock, flags);
262 return rc; 300 return rc;
263} 301}
@@ -560,6 +598,7 @@ sclp_register(struct sclp_register *reg)
560 /* Trigger initial state change callback */ 598 /* Trigger initial state change callback */
561 reg->sclp_receive_mask = 0; 599 reg->sclp_receive_mask = 0;
562 reg->sclp_send_mask = 0; 600 reg->sclp_send_mask = 0;
601 reg->pm_event_posted = 0;
563 list_add(&reg->list, &sclp_reg_list); 602 list_add(&reg->list, &sclp_reg_list);
564 spin_unlock_irqrestore(&sclp_lock, flags); 603 spin_unlock_irqrestore(&sclp_lock, flags);
565 rc = sclp_init_mask(1); 604 rc = sclp_init_mask(1);
@@ -880,20 +919,134 @@ static struct notifier_block sclp_reboot_notifier = {
880 .notifier_call = sclp_reboot_event 919 .notifier_call = sclp_reboot_event
881}; 920};
882 921
922/*
923 * Suspend/resume SCLP notifier implementation
924 */
925
926static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback)
927{
928 struct sclp_register *reg;
929 unsigned long flags;
930
931 if (!rollback) {
932 spin_lock_irqsave(&sclp_lock, flags);
933 list_for_each_entry(reg, &sclp_reg_list, list)
934 reg->pm_event_posted = 0;
935 spin_unlock_irqrestore(&sclp_lock, flags);
936 }
937 do {
938 spin_lock_irqsave(&sclp_lock, flags);
939 list_for_each_entry(reg, &sclp_reg_list, list) {
940 if (rollback && reg->pm_event_posted)
941 goto found;
942 if (!rollback && !reg->pm_event_posted)
943 goto found;
944 }
945 spin_unlock_irqrestore(&sclp_lock, flags);
946 return;
947found:
948 spin_unlock_irqrestore(&sclp_lock, flags);
949 if (reg->pm_event_fn)
950 reg->pm_event_fn(reg, sclp_pm_event);
951 reg->pm_event_posted = rollback ? 0 : 1;
952 } while (1);
953}
954
955/*
956 * Susend/resume callbacks for platform device
957 */
958
959static int sclp_freeze(struct device *dev)
960{
961 unsigned long flags;
962 int rc;
963
964 sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0);
965
966 spin_lock_irqsave(&sclp_lock, flags);
967 sclp_suspend_state = sclp_suspend_state_suspended;
968 spin_unlock_irqrestore(&sclp_lock, flags);
969
970 /* Init supend data */
971 memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req));
972 sclp_suspend_req.callback = sclp_suspend_req_cb;
973 sclp_suspend_req.status = SCLP_REQ_FILLED;
974 init_completion(&sclp_request_queue_flushed);
975
976 rc = sclp_add_request(&sclp_suspend_req);
977 if (rc == 0)
978 wait_for_completion(&sclp_request_queue_flushed);
979 else if (rc != -ENODATA)
980 goto fail_thaw;
981
982 rc = sclp_deactivate();
983 if (rc)
984 goto fail_thaw;
985 return 0;
986
987fail_thaw:
988 spin_lock_irqsave(&sclp_lock, flags);
989 sclp_suspend_state = sclp_suspend_state_running;
990 spin_unlock_irqrestore(&sclp_lock, flags);
991 sclp_pm_event(SCLP_PM_EVENT_THAW, 1);
992 return rc;
993}
994
995static int sclp_undo_suspend(enum sclp_pm_event event)
996{
997 unsigned long flags;
998 int rc;
999
1000 rc = sclp_reactivate();
1001 if (rc)
1002 return rc;
1003
1004 spin_lock_irqsave(&sclp_lock, flags);
1005 sclp_suspend_state = sclp_suspend_state_running;
1006 spin_unlock_irqrestore(&sclp_lock, flags);
1007
1008 sclp_pm_event(event, 0);
1009 return 0;
1010}
1011
1012static int sclp_thaw(struct device *dev)
1013{
1014 return sclp_undo_suspend(SCLP_PM_EVENT_THAW);
1015}
1016
1017static int sclp_restore(struct device *dev)
1018{
1019 return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE);
1020}
1021
1022static struct dev_pm_ops sclp_pm_ops = {
1023 .freeze = sclp_freeze,
1024 .thaw = sclp_thaw,
1025 .restore = sclp_restore,
1026};
1027
1028static struct platform_driver sclp_pdrv = {
1029 .driver = {
1030 .name = "sclp",
1031 .owner = THIS_MODULE,
1032 .pm = &sclp_pm_ops,
1033 },
1034};
1035
1036static struct platform_device *sclp_pdev;
1037
883/* Initialize SCLP driver. Return zero if driver is operational, non-zero 1038/* Initialize SCLP driver. Return zero if driver is operational, non-zero
884 * otherwise. */ 1039 * otherwise. */
885static int 1040static int
886sclp_init(void) 1041sclp_init(void)
887{ 1042{
888 unsigned long flags; 1043 unsigned long flags;
889 int rc; 1044 int rc = 0;
890 1045
891 spin_lock_irqsave(&sclp_lock, flags); 1046 spin_lock_irqsave(&sclp_lock, flags);
892 /* Check for previous or running initialization */ 1047 /* Check for previous or running initialization */
893 if (sclp_init_state != sclp_init_state_uninitialized) { 1048 if (sclp_init_state != sclp_init_state_uninitialized)
894 spin_unlock_irqrestore(&sclp_lock, flags); 1049 goto fail_unlock;
895 return 0;
896 }
897 sclp_init_state = sclp_init_state_initializing; 1050 sclp_init_state = sclp_init_state_initializing;
898 /* Set up variables */ 1051 /* Set up variables */
899 INIT_LIST_HEAD(&sclp_req_queue); 1052 INIT_LIST_HEAD(&sclp_req_queue);
@@ -904,27 +1057,17 @@ sclp_init(void)
904 spin_unlock_irqrestore(&sclp_lock, flags); 1057 spin_unlock_irqrestore(&sclp_lock, flags);
905 rc = sclp_check_interface(); 1058 rc = sclp_check_interface();
906 spin_lock_irqsave(&sclp_lock, flags); 1059 spin_lock_irqsave(&sclp_lock, flags);
907 if (rc) { 1060 if (rc)
908 sclp_init_state = sclp_init_state_uninitialized; 1061 goto fail_init_state_uninitialized;
909 spin_unlock_irqrestore(&sclp_lock, flags);
910 return rc;
911 }
912 /* Register reboot handler */ 1062 /* Register reboot handler */
913 rc = register_reboot_notifier(&sclp_reboot_notifier); 1063 rc = register_reboot_notifier(&sclp_reboot_notifier);
914 if (rc) { 1064 if (rc)
915 sclp_init_state = sclp_init_state_uninitialized; 1065 goto fail_init_state_uninitialized;
916 spin_unlock_irqrestore(&sclp_lock, flags);
917 return rc;
918 }
919 /* Register interrupt handler */ 1066 /* Register interrupt handler */
920 rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, 1067 rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler,
921 &ext_int_info_hwc); 1068 &ext_int_info_hwc);
922 if (rc) { 1069 if (rc)
923 unregister_reboot_notifier(&sclp_reboot_notifier); 1070 goto fail_unregister_reboot_notifier;
924 sclp_init_state = sclp_init_state_uninitialized;
925 spin_unlock_irqrestore(&sclp_lock, flags);
926 return rc;
927 }
928 sclp_init_state = sclp_init_state_initialized; 1071 sclp_init_state = sclp_init_state_initialized;
929 spin_unlock_irqrestore(&sclp_lock, flags); 1072 spin_unlock_irqrestore(&sclp_lock, flags);
930 /* Enable service-signal external interruption - needs to happen with 1073 /* Enable service-signal external interruption - needs to happen with
@@ -932,11 +1075,56 @@ sclp_init(void)
932 ctl_set_bit(0, 9); 1075 ctl_set_bit(0, 9);
933 sclp_init_mask(1); 1076 sclp_init_mask(1);
934 return 0; 1077 return 0;
1078
1079fail_unregister_reboot_notifier:
1080 unregister_reboot_notifier(&sclp_reboot_notifier);
1081fail_init_state_uninitialized:
1082 sclp_init_state = sclp_init_state_uninitialized;
1083fail_unlock:
1084 spin_unlock_irqrestore(&sclp_lock, flags);
1085 return rc;
935} 1086}
936 1087
1088/*
1089 * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able
1090 * to print the panic message.
1091 */
1092static int sclp_panic_notify(struct notifier_block *self,
1093 unsigned long event, void *data)
1094{
1095 if (sclp_suspend_state == sclp_suspend_state_suspended)
1096 sclp_undo_suspend(SCLP_PM_EVENT_THAW);
1097 return NOTIFY_OK;
1098}
1099
1100static struct notifier_block sclp_on_panic_nb = {
1101 .notifier_call = sclp_panic_notify,
1102 .priority = SCLP_PANIC_PRIO,
1103};
1104
937static __init int sclp_initcall(void) 1105static __init int sclp_initcall(void)
938{ 1106{
1107 int rc;
1108
1109 rc = platform_driver_register(&sclp_pdrv);
1110 if (rc)
1111 return rc;
1112 sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0);
1113 rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
1114 if (rc)
1115 goto fail_platform_driver_unregister;
1116 rc = atomic_notifier_chain_register(&panic_notifier_list,
1117 &sclp_on_panic_nb);
1118 if (rc)
1119 goto fail_platform_device_unregister;
1120
939 return sclp_init(); 1121 return sclp_init();
1122
1123fail_platform_device_unregister:
1124 platform_device_unregister(sclp_pdev);
1125fail_platform_driver_unregister:
1126 platform_driver_unregister(&sclp_pdrv);
1127 return rc;
940} 1128}
941 1129
942arch_initcall(sclp_initcall); 1130arch_initcall(sclp_initcall);
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index bac80e856f97..60e7cb07095b 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -1,10 +1,8 @@
1/* 1/*
2 * drivers/s390/char/sclp.h 2 * Copyright IBM Corp. 1999, 2009
3 * 3 *
4 * S390 version 4 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
5 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 * Martin Schwidefsky <schwidefsky@de.ibm.com>
6 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
7 * Martin Schwidefsky <schwidefsky@de.ibm.com>
8 */ 6 */
9 7
10#ifndef __SCLP_H__ 8#ifndef __SCLP_H__
@@ -17,7 +15,7 @@
17 15
18/* maximum number of pages concerning our own memory management */ 16/* maximum number of pages concerning our own memory management */
19#define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) 17#define MAX_KMEM_PAGES (sizeof(unsigned long) << 3)
20#define MAX_CONSOLE_PAGES 4 18#define MAX_CONSOLE_PAGES 6
21 19
22#define EVTYP_OPCMD 0x01 20#define EVTYP_OPCMD 0x01
23#define EVTYP_MSG 0x02 21#define EVTYP_MSG 0x02
@@ -68,6 +66,15 @@ typedef unsigned int sclp_cmdw_t;
68 66
69#define GDS_KEY_SELFDEFTEXTMSG 0x31 67#define GDS_KEY_SELFDEFTEXTMSG 0x31
70 68
69enum sclp_pm_event {
70 SCLP_PM_EVENT_FREEZE,
71 SCLP_PM_EVENT_THAW,
72 SCLP_PM_EVENT_RESTORE,
73};
74
75#define SCLP_PANIC_PRIO 1
76#define SCLP_PANIC_PRIO_CLIENT 0
77
71typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ 78typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */
72 79
73struct sccb_header { 80struct sccb_header {
@@ -134,6 +141,10 @@ struct sclp_register {
134 void (*state_change_fn)(struct sclp_register *); 141 void (*state_change_fn)(struct sclp_register *);
135 /* called for events in cp_receive_mask/sclp_receive_mask */ 142 /* called for events in cp_receive_mask/sclp_receive_mask */
136 void (*receiver_fn)(struct evbuf_header *); 143 void (*receiver_fn)(struct evbuf_header *);
144 /* called for power management events */
145 void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event);
146 /* pm event posted flag */
147 int pm_event_posted;
137}; 148};
138 149
139/* externals from sclp.c */ 150/* externals from sclp.c */
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 9a25c4bd1421..336811a77672 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -1,11 +1,9 @@
1/* 1/*
2 * drivers/s390/char/sclp_con.c 2 * SCLP line mode console driver
3 * SCLP line mode console driver
4 * 3 *
5 * S390 version 4 * Copyright IBM Corp. 1999, 2009
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
7 * Author(s): Martin Peschke <mpeschke@de.ibm.com> 6 * Martin Schwidefsky <schwidefsky@de.ibm.com>
8 * Martin Schwidefsky <schwidefsky@de.ibm.com>
9 */ 7 */
10 8
11#include <linux/kmod.h> 9#include <linux/kmod.h>
@@ -32,13 +30,14 @@ static spinlock_t sclp_con_lock;
32static struct list_head sclp_con_pages; 30static struct list_head sclp_con_pages;
33/* List of full struct sclp_buffer structures ready for output */ 31/* List of full struct sclp_buffer structures ready for output */
34static struct list_head sclp_con_outqueue; 32static struct list_head sclp_con_outqueue;
35/* Counter how many buffers are emitted (max 1) and how many */
36/* are on the output queue. */
37static int sclp_con_buffer_count;
38/* Pointer to current console buffer */ 33/* Pointer to current console buffer */
39static struct sclp_buffer *sclp_conbuf; 34static struct sclp_buffer *sclp_conbuf;
40/* Timer for delayed output of console messages */ 35/* Timer for delayed output of console messages */
41static struct timer_list sclp_con_timer; 36static struct timer_list sclp_con_timer;
37/* Suspend mode flag */
38static int sclp_con_suspended;
39/* Flag that output queue is currently running */
40static int sclp_con_queue_running;
42 41
43/* Output format for console messages */ 42/* Output format for console messages */
44static unsigned short sclp_con_columns; 43static unsigned short sclp_con_columns;
@@ -53,42 +52,71 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
53 do { 52 do {
54 page = sclp_unmake_buffer(buffer); 53 page = sclp_unmake_buffer(buffer);
55 spin_lock_irqsave(&sclp_con_lock, flags); 54 spin_lock_irqsave(&sclp_con_lock, flags);
55
56 /* Remove buffer from outqueue */ 56 /* Remove buffer from outqueue */
57 list_del(&buffer->list); 57 list_del(&buffer->list);
58 sclp_con_buffer_count--;
59 list_add_tail((struct list_head *) page, &sclp_con_pages); 58 list_add_tail((struct list_head *) page, &sclp_con_pages);
59
60 /* Check if there is a pending buffer on the out queue. */ 60 /* Check if there is a pending buffer on the out queue. */
61 buffer = NULL; 61 buffer = NULL;
62 if (!list_empty(&sclp_con_outqueue)) 62 if (!list_empty(&sclp_con_outqueue))
63 buffer = list_entry(sclp_con_outqueue.next, 63 buffer = list_first_entry(&sclp_con_outqueue,
64 struct sclp_buffer, list); 64 struct sclp_buffer, list);
65 if (!buffer || sclp_con_suspended) {
66 sclp_con_queue_running = 0;
67 spin_unlock_irqrestore(&sclp_con_lock, flags);
68 break;
69 }
65 spin_unlock_irqrestore(&sclp_con_lock, flags); 70 spin_unlock_irqrestore(&sclp_con_lock, flags);
66 } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); 71 } while (sclp_emit_buffer(buffer, sclp_conbuf_callback));
67} 72}
68 73
69static void 74/*
70sclp_conbuf_emit(void) 75 * Finalize and emit first pending buffer.
76 */
77static void sclp_conbuf_emit(void)
71{ 78{
72 struct sclp_buffer* buffer; 79 struct sclp_buffer* buffer;
73 unsigned long flags; 80 unsigned long flags;
74 int count;
75 int rc; 81 int rc;
76 82
77 spin_lock_irqsave(&sclp_con_lock, flags); 83 spin_lock_irqsave(&sclp_con_lock, flags);
78 buffer = sclp_conbuf; 84 if (sclp_conbuf)
85 list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue);
79 sclp_conbuf = NULL; 86 sclp_conbuf = NULL;
80 if (buffer == NULL) { 87 if (sclp_con_queue_running || sclp_con_suspended)
81 spin_unlock_irqrestore(&sclp_con_lock, flags); 88 goto out_unlock;
82 return; 89 if (list_empty(&sclp_con_outqueue))
83 } 90 goto out_unlock;
84 list_add_tail(&buffer->list, &sclp_con_outqueue); 91 buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer,
85 count = sclp_con_buffer_count++; 92 list);
93 sclp_con_queue_running = 1;
86 spin_unlock_irqrestore(&sclp_con_lock, flags); 94 spin_unlock_irqrestore(&sclp_con_lock, flags);
87 if (count) 95
88 return;
89 rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); 96 rc = sclp_emit_buffer(buffer, sclp_conbuf_callback);
90 if (rc) 97 if (rc)
91 sclp_conbuf_callback(buffer, rc); 98 sclp_conbuf_callback(buffer, rc);
99 return;
100out_unlock:
101 spin_unlock_irqrestore(&sclp_con_lock, flags);
102}
103
104/*
105 * Wait until out queue is empty
106 */
107static void sclp_console_sync_queue(void)
108{
109 unsigned long flags;
110
111 spin_lock_irqsave(&sclp_con_lock, flags);
112 if (timer_pending(&sclp_con_timer))
113 del_timer_sync(&sclp_con_timer);
114 while (sclp_con_queue_running) {
115 spin_unlock_irqrestore(&sclp_con_lock, flags);
116 sclp_sync_wait();
117 spin_lock_irqsave(&sclp_con_lock, flags);
118 }
119 spin_unlock_irqrestore(&sclp_con_lock, flags);
92} 120}
93 121
94/* 122/*
@@ -123,6 +151,8 @@ sclp_console_write(struct console *console, const char *message,
123 /* make sure we have a console output buffer */ 151 /* make sure we have a console output buffer */
124 if (sclp_conbuf == NULL) { 152 if (sclp_conbuf == NULL) {
125 while (list_empty(&sclp_con_pages)) { 153 while (list_empty(&sclp_con_pages)) {
154 if (sclp_con_suspended)
155 goto out;
126 spin_unlock_irqrestore(&sclp_con_lock, flags); 156 spin_unlock_irqrestore(&sclp_con_lock, flags);
127 sclp_sync_wait(); 157 sclp_sync_wait();
128 spin_lock_irqsave(&sclp_con_lock, flags); 158 spin_lock_irqsave(&sclp_con_lock, flags);
@@ -157,6 +187,7 @@ sclp_console_write(struct console *console, const char *message,
157 sclp_con_timer.expires = jiffies + HZ/10; 187 sclp_con_timer.expires = jiffies + HZ/10;
158 add_timer(&sclp_con_timer); 188 add_timer(&sclp_con_timer);
159 } 189 }
190out:
160 spin_unlock_irqrestore(&sclp_con_lock, flags); 191 spin_unlock_irqrestore(&sclp_con_lock, flags);
161} 192}
162 193
@@ -168,30 +199,43 @@ sclp_console_device(struct console *c, int *index)
168} 199}
169 200
170/* 201/*
171 * This routine is called from panic when the kernel 202 * Make sure that all buffers will be flushed to the SCLP.
172 * is going to give up. We have to make sure that all buffers
173 * will be flushed to the SCLP.
174 */ 203 */
175static void 204static void
176sclp_console_flush(void) 205sclp_console_flush(void)
177{ 206{
207 sclp_conbuf_emit();
208 sclp_console_sync_queue();
209}
210
211/*
212 * Resume console: If there are cached messages, emit them.
213 */
214static void sclp_console_resume(void)
215{
178 unsigned long flags; 216 unsigned long flags;
179 217
218 spin_lock_irqsave(&sclp_con_lock, flags);
219 sclp_con_suspended = 0;
220 spin_unlock_irqrestore(&sclp_con_lock, flags);
180 sclp_conbuf_emit(); 221 sclp_conbuf_emit();
222}
223
224/*
225 * Suspend console: Set suspend flag and flush console
226 */
227static void sclp_console_suspend(void)
228{
229 unsigned long flags;
230
181 spin_lock_irqsave(&sclp_con_lock, flags); 231 spin_lock_irqsave(&sclp_con_lock, flags);
182 if (timer_pending(&sclp_con_timer)) 232 sclp_con_suspended = 1;
183 del_timer(&sclp_con_timer);
184 while (sclp_con_buffer_count > 0) {
185 spin_unlock_irqrestore(&sclp_con_lock, flags);
186 sclp_sync_wait();
187 spin_lock_irqsave(&sclp_con_lock, flags);
188 }
189 spin_unlock_irqrestore(&sclp_con_lock, flags); 233 spin_unlock_irqrestore(&sclp_con_lock, flags);
234 sclp_console_flush();
190} 235}
191 236
192static int 237static int sclp_console_notify(struct notifier_block *self,
193sclp_console_notify(struct notifier_block *self, 238 unsigned long event, void *data)
194 unsigned long event, void *data)
195{ 239{
196 sclp_console_flush(); 240 sclp_console_flush();
197 return NOTIFY_OK; 241 return NOTIFY_OK;
@@ -199,7 +243,7 @@ sclp_console_notify(struct notifier_block *self,
199 243
200static struct notifier_block on_panic_nb = { 244static struct notifier_block on_panic_nb = {
201 .notifier_call = sclp_console_notify, 245 .notifier_call = sclp_console_notify,
202 .priority = 1, 246 .priority = SCLP_PANIC_PRIO_CLIENT,
203}; 247};
204 248
205static struct notifier_block on_reboot_nb = { 249static struct notifier_block on_reboot_nb = {
@@ -221,6 +265,22 @@ static struct console sclp_console =
221}; 265};
222 266
223/* 267/*
268 * This function is called for SCLP suspend and resume events.
269 */
270void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event)
271{
272 switch (sclp_pm_event) {
273 case SCLP_PM_EVENT_FREEZE:
274 sclp_console_suspend();
275 break;
276 case SCLP_PM_EVENT_RESTORE:
277 case SCLP_PM_EVENT_THAW:
278 sclp_console_resume();
279 break;
280 }
281}
282
283/*
224 * called by console_init() in drivers/char/tty_io.c at boot-time. 284 * called by console_init() in drivers/char/tty_io.c at boot-time.
225 */ 285 */
226static int __init 286static int __init
@@ -243,7 +303,6 @@ sclp_console_init(void)
243 } 303 }
244 INIT_LIST_HEAD(&sclp_con_outqueue); 304 INIT_LIST_HEAD(&sclp_con_outqueue);
245 spin_lock_init(&sclp_con_lock); 305 spin_lock_init(&sclp_con_lock);
246 sclp_con_buffer_count = 0;
247 sclp_conbuf = NULL; 306 sclp_conbuf = NULL;
248 init_timer(&sclp_con_timer); 307 init_timer(&sclp_con_timer);
249 308
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 710af42603f8..4be63be73445 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -1,11 +1,10 @@
1/* 1/*
2 * drivers/s390/char/sclp_rw.c 2 * driver: reading from and writing to system console on S/390 via SCLP
3 * driver: reading from and writing to system console on S/390 via SCLP
4 * 3 *
5 * S390 version 4 * Copyright IBM Corp. 1999, 2009
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 *
7 * Author(s): Martin Peschke <mpeschke@de.ibm.com> 6 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
8 * Martin Schwidefsky <schwidefsky@de.ibm.com> 7 * Martin Schwidefsky <schwidefsky@de.ibm.com>
9 */ 8 */
10 9
11#include <linux/kmod.h> 10#include <linux/kmod.h>
@@ -26,9 +25,16 @@
26 */ 25 */
27#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) 26#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
28 27
28static void sclp_rw_pm_event(struct sclp_register *reg,
29 enum sclp_pm_event sclp_pm_event)
30{
31 sclp_console_pm_event(sclp_pm_event);
32}
33
29/* Event type structure for write message and write priority message */ 34/* Event type structure for write message and write priority message */
30static struct sclp_register sclp_rw_event = { 35static struct sclp_register sclp_rw_event = {
31 .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK 36 .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK,
37 .pm_event_fn = sclp_rw_pm_event,
32}; 38};
33 39
34/* 40/*
diff --git a/drivers/s390/char/sclp_rw.h b/drivers/s390/char/sclp_rw.h
index 6aa7a6948bc9..85f491ea929c 100644
--- a/drivers/s390/char/sclp_rw.h
+++ b/drivers/s390/char/sclp_rw.h
@@ -1,11 +1,10 @@
1/* 1/*
2 * drivers/s390/char/sclp_rw.h 2 * interface to the SCLP-read/write driver
3 * interface to the SCLP-read/write driver
4 * 3 *
5 * S390 version 4 * Copyright IBM Corporation 1999, 2009
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 *
7 * Author(s): Martin Peschke <mpeschke@de.ibm.com> 6 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
8 * Martin Schwidefsky <schwidefsky@de.ibm.com> 7 * Martin Schwidefsky <schwidefsky@de.ibm.com>
9 */ 8 */
10 9
11#ifndef __SCLP_RW_H__ 10#ifndef __SCLP_RW_H__
@@ -93,4 +92,5 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short);
93void sclp_set_htab(struct sclp_buffer *, unsigned short); 92void sclp_set_htab(struct sclp_buffer *, unsigned short);
94int sclp_chars_in_buffer(struct sclp_buffer *); 93int sclp_chars_in_buffer(struct sclp_buffer *);
95 94
95void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event);
96#endif /* __SCLP_RW_H__ */ 96#endif /* __SCLP_RW_H__ */
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index a839aa531d7c..5518e24946aa 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -1,10 +1,9 @@
1/* 1/*
2 * drivers/s390/char/sclp_vt220.c 2 * SCLP VT220 terminal driver.
3 * SCLP VT220 terminal driver.
4 * 3 *
5 * S390 version 4 * Copyright IBM Corp. 2003, 2009
6 * Copyright IBM Corp. 2003,2008 5 *
7 * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com> 6 * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
8 */ 7 */
9 8
10#include <linux/module.h> 9#include <linux/module.h>
@@ -69,8 +68,11 @@ static struct list_head sclp_vt220_empty;
69/* List of pending requests */ 68/* List of pending requests */
70static struct list_head sclp_vt220_outqueue; 69static struct list_head sclp_vt220_outqueue;
71 70
72/* Number of requests in outqueue */ 71/* Suspend mode flag */
73static int sclp_vt220_outqueue_count; 72static int sclp_vt220_suspended;
73
74/* Flag that output queue is currently running */
75static int sclp_vt220_queue_running;
74 76
75/* Timer used for delaying write requests to merge subsequent messages into 77/* Timer used for delaying write requests to merge subsequent messages into
76 * a single buffer */ 78 * a single buffer */
@@ -92,6 +94,8 @@ static int __initdata sclp_vt220_init_count;
92static int sclp_vt220_flush_later; 94static int sclp_vt220_flush_later;
93 95
94static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); 96static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf);
97static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
98 enum sclp_pm_event sclp_pm_event);
95static int __sclp_vt220_emit(struct sclp_vt220_request *request); 99static int __sclp_vt220_emit(struct sclp_vt220_request *request);
96static void sclp_vt220_emit_current(void); 100static void sclp_vt220_emit_current(void);
97 101
@@ -100,7 +104,8 @@ static struct sclp_register sclp_vt220_register = {
100 .send_mask = EVTYP_VT220MSG_MASK, 104 .send_mask = EVTYP_VT220MSG_MASK,
101 .receive_mask = EVTYP_VT220MSG_MASK, 105 .receive_mask = EVTYP_VT220MSG_MASK,
102 .state_change_fn = NULL, 106 .state_change_fn = NULL,
103 .receiver_fn = sclp_vt220_receiver_fn 107 .receiver_fn = sclp_vt220_receiver_fn,
108 .pm_event_fn = sclp_vt220_pm_event_fn,
104}; 109};
105 110
106 111
@@ -120,15 +125,19 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
120 spin_lock_irqsave(&sclp_vt220_lock, flags); 125 spin_lock_irqsave(&sclp_vt220_lock, flags);
121 /* Move request from outqueue to empty queue */ 126 /* Move request from outqueue to empty queue */
122 list_del(&request->list); 127 list_del(&request->list);
123 sclp_vt220_outqueue_count--;
124 list_add_tail((struct list_head *) page, &sclp_vt220_empty); 128 list_add_tail((struct list_head *) page, &sclp_vt220_empty);
125 /* Check if there is a pending buffer on the out queue. */ 129 /* Check if there is a pending buffer on the out queue. */
126 request = NULL; 130 request = NULL;
127 if (!list_empty(&sclp_vt220_outqueue)) 131 if (!list_empty(&sclp_vt220_outqueue))
128 request = list_entry(sclp_vt220_outqueue.next, 132 request = list_entry(sclp_vt220_outqueue.next,
129 struct sclp_vt220_request, list); 133 struct sclp_vt220_request, list);
134 if (!request || sclp_vt220_suspended) {
135 sclp_vt220_queue_running = 0;
136 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
137 break;
138 }
130 spin_unlock_irqrestore(&sclp_vt220_lock, flags); 139 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
131 } while (request && __sclp_vt220_emit(request)); 140 } while (__sclp_vt220_emit(request));
132 if (request == NULL && sclp_vt220_flush_later) 141 if (request == NULL && sclp_vt220_flush_later)
133 sclp_vt220_emit_current(); 142 sclp_vt220_emit_current();
134 /* Check if the tty needs a wake up call */ 143 /* Check if the tty needs a wake up call */
@@ -212,26 +221,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request)
212} 221}
213 222
214/* 223/*
215 * Queue and emit given request. 224 * Queue and emit current request.
216 */
217static void
218sclp_vt220_emit(struct sclp_vt220_request *request)
219{
220 unsigned long flags;
221 int count;
222
223 spin_lock_irqsave(&sclp_vt220_lock, flags);
224 list_add_tail(&request->list, &sclp_vt220_outqueue);
225 count = sclp_vt220_outqueue_count++;
226 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
227 /* Emit only the first buffer immediately - callback takes care of
228 * the rest */
229 if (count == 0 && __sclp_vt220_emit(request))
230 sclp_vt220_process_queue(request);
231}
232
233/*
234 * Queue and emit current request. Return zero on success, non-zero otherwise.
235 */ 225 */
236static void 226static void
237sclp_vt220_emit_current(void) 227sclp_vt220_emit_current(void)
@@ -241,22 +231,33 @@ sclp_vt220_emit_current(void)
241 struct sclp_vt220_sccb *sccb; 231 struct sclp_vt220_sccb *sccb;
242 232
243 spin_lock_irqsave(&sclp_vt220_lock, flags); 233 spin_lock_irqsave(&sclp_vt220_lock, flags);
244 request = NULL; 234 if (sclp_vt220_current_request) {
245 if (sclp_vt220_current_request != NULL) {
246 sccb = (struct sclp_vt220_sccb *) 235 sccb = (struct sclp_vt220_sccb *)
247 sclp_vt220_current_request->sclp_req.sccb; 236 sclp_vt220_current_request->sclp_req.sccb;
248 /* Only emit buffers with content */ 237 /* Only emit buffers with content */
249 if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) { 238 if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) {
250 request = sclp_vt220_current_request; 239 list_add_tail(&sclp_vt220_current_request->list,
240 &sclp_vt220_outqueue);
251 sclp_vt220_current_request = NULL; 241 sclp_vt220_current_request = NULL;
252 if (timer_pending(&sclp_vt220_timer)) 242 if (timer_pending(&sclp_vt220_timer))
253 del_timer(&sclp_vt220_timer); 243 del_timer(&sclp_vt220_timer);
254 } 244 }
255 sclp_vt220_flush_later = 0; 245 sclp_vt220_flush_later = 0;
256 } 246 }
247 if (sclp_vt220_queue_running || sclp_vt220_suspended)
248 goto out_unlock;
249 if (list_empty(&sclp_vt220_outqueue))
250 goto out_unlock;
251 request = list_first_entry(&sclp_vt220_outqueue,
252 struct sclp_vt220_request, list);
253 sclp_vt220_queue_running = 1;
254 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
255
256 if (__sclp_vt220_emit(request))
257 sclp_vt220_process_queue(request);
258 return;
259out_unlock:
257 spin_unlock_irqrestore(&sclp_vt220_lock, flags); 260 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
258 if (request != NULL)
259 sclp_vt220_emit(request);
260} 261}
261 262
262#define SCLP_NORMAL_WRITE 0x00 263#define SCLP_NORMAL_WRITE 0x00
@@ -396,7 +397,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
396 if (sclp_vt220_current_request == NULL) { 397 if (sclp_vt220_current_request == NULL) {
397 while (list_empty(&sclp_vt220_empty)) { 398 while (list_empty(&sclp_vt220_empty)) {
398 spin_unlock_irqrestore(&sclp_vt220_lock, flags); 399 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
399 if (may_fail) 400 if (may_fail || sclp_vt220_suspended)
400 goto out; 401 goto out;
401 else 402 else
402 sclp_sync_wait(); 403 sclp_sync_wait();
@@ -531,7 +532,7 @@ sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
531static void 532static void
532sclp_vt220_flush_chars(struct tty_struct *tty) 533sclp_vt220_flush_chars(struct tty_struct *tty)
533{ 534{
534 if (sclp_vt220_outqueue_count == 0) 535 if (!sclp_vt220_queue_running)
535 sclp_vt220_emit_current(); 536 sclp_vt220_emit_current();
536 else 537 else
537 sclp_vt220_flush_later = 1; 538 sclp_vt220_flush_later = 1;
@@ -635,7 +636,6 @@ static int __init __sclp_vt220_init(int num_pages)
635 init_timer(&sclp_vt220_timer); 636 init_timer(&sclp_vt220_timer);
636 sclp_vt220_current_request = NULL; 637 sclp_vt220_current_request = NULL;
637 sclp_vt220_buffered_chars = 0; 638 sclp_vt220_buffered_chars = 0;
638 sclp_vt220_outqueue_count = 0;
639 sclp_vt220_tty = NULL; 639 sclp_vt220_tty = NULL;
640 sclp_vt220_flush_later = 0; 640 sclp_vt220_flush_later = 0;
641 641
@@ -736,7 +736,7 @@ static void __sclp_vt220_flush_buffer(void)
736 spin_lock_irqsave(&sclp_vt220_lock, flags); 736 spin_lock_irqsave(&sclp_vt220_lock, flags);
737 if (timer_pending(&sclp_vt220_timer)) 737 if (timer_pending(&sclp_vt220_timer))
738 del_timer(&sclp_vt220_timer); 738 del_timer(&sclp_vt220_timer);
739 while (sclp_vt220_outqueue_count > 0) { 739 while (sclp_vt220_queue_running) {
740 spin_unlock_irqrestore(&sclp_vt220_lock, flags); 740 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
741 sclp_sync_wait(); 741 sclp_sync_wait();
742 spin_lock_irqsave(&sclp_vt220_lock, flags); 742 spin_lock_irqsave(&sclp_vt220_lock, flags);
@@ -744,6 +744,46 @@ static void __sclp_vt220_flush_buffer(void)
744 spin_unlock_irqrestore(&sclp_vt220_lock, flags); 744 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
745} 745}
746 746
747/*
748 * Resume console: If there are cached messages, emit them.
749 */
750static void sclp_vt220_resume(void)
751{
752 unsigned long flags;
753
754 spin_lock_irqsave(&sclp_vt220_lock, flags);
755 sclp_vt220_suspended = 0;
756 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
757 sclp_vt220_emit_current();
758}
759
760/*
761 * Suspend console: Set suspend flag and flush console
762 */
763static void sclp_vt220_suspend(void)
764{
765 unsigned long flags;
766
767 spin_lock_irqsave(&sclp_vt220_lock, flags);
768 sclp_vt220_suspended = 1;
769 spin_unlock_irqrestore(&sclp_vt220_lock, flags);
770 __sclp_vt220_flush_buffer();
771}
772
773static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
774 enum sclp_pm_event sclp_pm_event)
775{
776 switch (sclp_pm_event) {
777 case SCLP_PM_EVENT_FREEZE:
778 sclp_vt220_suspend();
779 break;
780 case SCLP_PM_EVENT_RESTORE:
781 case SCLP_PM_EVENT_THAW:
782 sclp_vt220_resume();
783 break;
784 }
785}
786
747static int 787static int
748sclp_vt220_notify(struct notifier_block *self, 788sclp_vt220_notify(struct notifier_block *self,
749 unsigned long event, void *data) 789 unsigned long event, void *data)