diff options
-rw-r--r-- | drivers/s390/char/sclp.c | 69 | ||||
-rw-r--r-- | drivers/s390/char/sclp.h | 6 | ||||
-rw-r--r-- | drivers/s390/char/sclp_con.c | 31 | ||||
-rw-r--r-- | drivers/s390/char/sclp_vt220.c | 39 |
4 files changed, 138 insertions, 7 deletions
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index bd6871bf545a..a77febeead1f 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -50,11 +50,42 @@ static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | |||
50 | /* Suspend request */ | 50 | /* Suspend request */ |
51 | static DECLARE_COMPLETION(sclp_request_queue_flushed); | 51 | static DECLARE_COMPLETION(sclp_request_queue_flushed); |
52 | 52 | ||
53 | /* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */ | ||
54 | int sclp_console_pages = SCLP_CONSOLE_PAGES; | ||
55 | /* Flag to indicate if buffer pages are dropped on buffer full condition */ | ||
56 | int sclp_console_drop = 0; | ||
57 | /* Number of times the console dropped buffer pages */ | ||
58 | unsigned long sclp_console_full; | ||
59 | |||
53 | static void sclp_suspend_req_cb(struct sclp_req *req, void *data) | 60 | static void sclp_suspend_req_cb(struct sclp_req *req, void *data) |
54 | { | 61 | { |
55 | complete(&sclp_request_queue_flushed); | 62 | complete(&sclp_request_queue_flushed); |
56 | } | 63 | } |
57 | 64 | ||
65 | static int __init sclp_setup_console_pages(char *str) | ||
66 | { | ||
67 | int pages, rc; | ||
68 | |||
69 | rc = kstrtoint(str, 0, &pages); | ||
70 | if (!rc && pages >= SCLP_CONSOLE_PAGES) | ||
71 | sclp_console_pages = pages; | ||
72 | return 1; | ||
73 | } | ||
74 | |||
75 | __setup("sclp_con_pages=", sclp_setup_console_pages); | ||
76 | |||
77 | static int __init sclp_setup_console_drop(char *str) | ||
78 | { | ||
79 | int drop, rc; | ||
80 | |||
81 | rc = kstrtoint(str, 0, &drop); | ||
82 | if (!rc && drop) | ||
83 | sclp_console_drop = 1; | ||
84 | return 1; | ||
85 | } | ||
86 | |||
87 | __setup("sclp_con_drop=", sclp_setup_console_drop); | ||
88 | |||
58 | static struct sclp_req sclp_suspend_req; | 89 | static struct sclp_req sclp_suspend_req; |
59 | 90 | ||
60 | /* Timer for request retries. */ | 91 | /* Timer for request retries. */ |
@@ -1013,11 +1044,47 @@ static const struct dev_pm_ops sclp_pm_ops = { | |||
1013 | .restore = sclp_restore, | 1044 | .restore = sclp_restore, |
1014 | }; | 1045 | }; |
1015 | 1046 | ||
1047 | static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf) | ||
1048 | { | ||
1049 | return sprintf(buf, "%i\n", sclp_console_pages); | ||
1050 | } | ||
1051 | |||
1052 | static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL); | ||
1053 | |||
1054 | static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf) | ||
1055 | { | ||
1056 | return sprintf(buf, "%i\n", sclp_console_drop); | ||
1057 | } | ||
1058 | |||
1059 | static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL); | ||
1060 | |||
1061 | static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf) | ||
1062 | { | ||
1063 | return sprintf(buf, "%lu\n", sclp_console_full); | ||
1064 | } | ||
1065 | |||
1066 | static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL); | ||
1067 | |||
1068 | static struct attribute *sclp_drv_attrs[] = { | ||
1069 | &driver_attr_con_pages.attr, | ||
1070 | &driver_attr_con_drop.attr, | ||
1071 | &driver_attr_con_full.attr, | ||
1072 | NULL, | ||
1073 | }; | ||
1074 | static struct attribute_group sclp_drv_attr_group = { | ||
1075 | .attrs = sclp_drv_attrs, | ||
1076 | }; | ||
1077 | static const struct attribute_group *sclp_drv_attr_groups[] = { | ||
1078 | &sclp_drv_attr_group, | ||
1079 | NULL, | ||
1080 | }; | ||
1081 | |||
1016 | static struct platform_driver sclp_pdrv = { | 1082 | static struct platform_driver sclp_pdrv = { |
1017 | .driver = { | 1083 | .driver = { |
1018 | .name = "sclp", | 1084 | .name = "sclp", |
1019 | .owner = THIS_MODULE, | 1085 | .owner = THIS_MODULE, |
1020 | .pm = &sclp_pm_ops, | 1086 | .pm = &sclp_pm_ops, |
1087 | .groups = sclp_drv_attr_groups, | ||
1021 | }, | 1088 | }, |
1022 | }; | 1089 | }; |
1023 | 1090 | ||
@@ -1096,10 +1163,12 @@ static __init int sclp_initcall(void) | |||
1096 | rc = platform_driver_register(&sclp_pdrv); | 1163 | rc = platform_driver_register(&sclp_pdrv); |
1097 | if (rc) | 1164 | if (rc) |
1098 | return rc; | 1165 | return rc; |
1166 | |||
1099 | sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); | 1167 | sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); |
1100 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; | 1168 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; |
1101 | if (rc) | 1169 | if (rc) |
1102 | goto fail_platform_driver_unregister; | 1170 | goto fail_platform_driver_unregister; |
1171 | |||
1103 | rc = atomic_notifier_chain_register(&panic_notifier_list, | 1172 | rc = atomic_notifier_chain_register(&panic_notifier_list, |
1104 | &sclp_on_panic_nb); | 1173 | &sclp_on_panic_nb); |
1105 | if (rc) | 1174 | if (rc) |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 25bcd4c0ed82..e11383f5d3d2 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -15,7 +15,7 @@ | |||
15 | 15 | ||
16 | /* maximum number of pages concerning our own memory management */ | 16 | /* maximum number of pages concerning our own memory management */ |
17 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) | 17 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) |
18 | #define MAX_CONSOLE_PAGES 6 | 18 | #define SCLP_CONSOLE_PAGES 6 |
19 | 19 | ||
20 | #define EVTYP_OPCMD 0x01 | 20 | #define EVTYP_OPCMD 0x01 |
21 | #define EVTYP_MSG 0x02 | 21 | #define EVTYP_MSG 0x02 |
@@ -175,6 +175,10 @@ int sclp_service_call(sclp_cmdw_t command, void *sccb); | |||
175 | int sclp_sdias_init(void); | 175 | int sclp_sdias_init(void); |
176 | void sclp_sdias_exit(void); | 176 | void sclp_sdias_exit(void); |
177 | 177 | ||
178 | extern int sclp_console_pages; | ||
179 | extern int sclp_console_drop; | ||
180 | extern unsigned long sclp_console_full; | ||
181 | |||
178 | /* useful inlines */ | 182 | /* useful inlines */ |
179 | 183 | ||
180 | /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ | 184 | /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ |
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index ecf45c54f8c4..5880def98fc1 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c | |||
@@ -130,6 +130,31 @@ sclp_console_timeout(unsigned long data) | |||
130 | } | 130 | } |
131 | 131 | ||
132 | /* | 132 | /* |
133 | * Drop oldest console buffer if sclp_con_drop is set | ||
134 | */ | ||
135 | static int | ||
136 | sclp_console_drop_buffer(void) | ||
137 | { | ||
138 | struct list_head *list; | ||
139 | struct sclp_buffer *buffer; | ||
140 | void *page; | ||
141 | |||
142 | if (!sclp_console_drop) | ||
143 | return 0; | ||
144 | list = sclp_con_outqueue.next; | ||
145 | if (sclp_con_queue_running) | ||
146 | /* The first element is in I/O */ | ||
147 | list = list->next; | ||
148 | if (list == &sclp_con_outqueue) | ||
149 | return 0; | ||
150 | list_del(list); | ||
151 | buffer = list_entry(list, struct sclp_buffer, list); | ||
152 | page = sclp_unmake_buffer(buffer); | ||
153 | list_add_tail((struct list_head *) page, &sclp_con_pages); | ||
154 | return 1; | ||
155 | } | ||
156 | |||
157 | /* | ||
133 | * Writes the given message to S390 system console | 158 | * Writes the given message to S390 system console |
134 | */ | 159 | */ |
135 | static void | 160 | static void |
@@ -150,9 +175,13 @@ sclp_console_write(struct console *console, const char *message, | |||
150 | do { | 175 | do { |
151 | /* make sure we have a console output buffer */ | 176 | /* make sure we have a console output buffer */ |
152 | if (sclp_conbuf == NULL) { | 177 | if (sclp_conbuf == NULL) { |
178 | if (list_empty(&sclp_con_pages)) | ||
179 | sclp_console_full++; | ||
153 | while (list_empty(&sclp_con_pages)) { | 180 | while (list_empty(&sclp_con_pages)) { |
154 | if (sclp_con_suspended) | 181 | if (sclp_con_suspended) |
155 | goto out; | 182 | goto out; |
183 | if (sclp_console_drop_buffer()) | ||
184 | break; | ||
156 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 185 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
157 | sclp_sync_wait(); | 186 | sclp_sync_wait(); |
158 | spin_lock_irqsave(&sclp_con_lock, flags); | 187 | spin_lock_irqsave(&sclp_con_lock, flags); |
@@ -297,7 +326,7 @@ sclp_console_init(void) | |||
297 | return rc; | 326 | return rc; |
298 | /* Allocate pages for output buffering */ | 327 | /* Allocate pages for output buffering */ |
299 | INIT_LIST_HEAD(&sclp_con_pages); | 328 | INIT_LIST_HEAD(&sclp_con_pages); |
300 | for (i = 0; i < MAX_CONSOLE_PAGES; i++) { | 329 | for (i = 0; i < sclp_console_pages; i++) { |
301 | page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | 330 | page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); |
302 | list_add_tail(page, &sclp_con_pages); | 331 | list_add_tail(page, &sclp_con_pages); |
303 | } | 332 | } |
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 5aaaa2ec8df4..4eed38cd0af6 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
@@ -362,6 +362,31 @@ sclp_vt220_timeout(unsigned long data) | |||
362 | 362 | ||
363 | #define BUFFER_MAX_DELAY HZ/20 | 363 | #define BUFFER_MAX_DELAY HZ/20 |
364 | 364 | ||
365 | /* | ||
366 | * Drop oldest console buffer if sclp_con_drop is set | ||
367 | */ | ||
368 | static int | ||
369 | sclp_vt220_drop_buffer(void) | ||
370 | { | ||
371 | struct list_head *list; | ||
372 | struct sclp_vt220_request *request; | ||
373 | void *page; | ||
374 | |||
375 | if (!sclp_console_drop) | ||
376 | return 0; | ||
377 | list = sclp_vt220_outqueue.next; | ||
378 | if (sclp_vt220_queue_running) | ||
379 | /* The first element is in I/O */ | ||
380 | list = list->next; | ||
381 | if (list == &sclp_vt220_outqueue) | ||
382 | return 0; | ||
383 | list_del(list); | ||
384 | request = list_entry(list, struct sclp_vt220_request, list); | ||
385 | page = request->sclp_req.sccb; | ||
386 | list_add_tail((struct list_head *) page, &sclp_vt220_empty); | ||
387 | return 1; | ||
388 | } | ||
389 | |||
365 | /* | 390 | /* |
366 | * Internal implementation of the write function. Write COUNT bytes of data | 391 | * Internal implementation of the write function. Write COUNT bytes of data |
367 | * from memory at BUF | 392 | * from memory at BUF |
@@ -390,12 +415,16 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
390 | do { | 415 | do { |
391 | /* Create an sclp output buffer if none exists yet */ | 416 | /* Create an sclp output buffer if none exists yet */ |
392 | if (sclp_vt220_current_request == NULL) { | 417 | if (sclp_vt220_current_request == NULL) { |
418 | if (list_empty(&sclp_vt220_empty)) | ||
419 | sclp_console_full++; | ||
393 | while (list_empty(&sclp_vt220_empty)) { | 420 | while (list_empty(&sclp_vt220_empty)) { |
394 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
395 | if (may_fail || sclp_vt220_suspended) | 421 | if (may_fail || sclp_vt220_suspended) |
396 | goto out; | 422 | goto out; |
397 | else | 423 | if (sclp_vt220_drop_buffer()) |
398 | sclp_sync_wait(); | 424 | break; |
425 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
426 | |||
427 | sclp_sync_wait(); | ||
399 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 428 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
400 | } | 429 | } |
401 | page = (void *) sclp_vt220_empty.next; | 430 | page = (void *) sclp_vt220_empty.next; |
@@ -428,8 +457,8 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
428 | sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY; | 457 | sclp_vt220_timer.expires = jiffies + BUFFER_MAX_DELAY; |
429 | add_timer(&sclp_vt220_timer); | 458 | add_timer(&sclp_vt220_timer); |
430 | } | 459 | } |
431 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
432 | out: | 460 | out: |
461 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
433 | return overall_written; | 462 | return overall_written; |
434 | } | 463 | } |
435 | 464 | ||
@@ -803,7 +832,7 @@ sclp_vt220_con_init(void) | |||
803 | 832 | ||
804 | if (!CONSOLE_IS_SCLP) | 833 | if (!CONSOLE_IS_SCLP) |
805 | return 0; | 834 | return 0; |
806 | rc = __sclp_vt220_init(MAX_CONSOLE_PAGES); | 835 | rc = __sclp_vt220_init(sclp_console_pages); |
807 | if (rc) | 836 | if (rc) |
808 | return rc; | 837 | return rc; |
809 | /* Attach linux console */ | 838 | /* Attach linux console */ |