aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/char/sclp.c69
-rw-r--r--drivers/s390/char/sclp.h6
-rw-r--r--drivers/s390/char/sclp_con.c31
-rw-r--r--drivers/s390/char/sclp_vt220.c39
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 */
51static DECLARE_COMPLETION(sclp_request_queue_flushed); 51static DECLARE_COMPLETION(sclp_request_queue_flushed);
52 52
53/* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */
54int sclp_console_pages = SCLP_CONSOLE_PAGES;
55/* Flag to indicate if buffer pages are dropped on buffer full condition */
56int sclp_console_drop = 0;
57/* Number of times the console dropped buffer pages */
58unsigned long sclp_console_full;
59
53static void sclp_suspend_req_cb(struct sclp_req *req, void *data) 60static 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
65static 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
77static 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
58static struct sclp_req sclp_suspend_req; 89static 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
1047static ssize_t sclp_show_console_pages(struct device_driver *dev, char *buf)
1048{
1049 return sprintf(buf, "%i\n", sclp_console_pages);
1050}
1051
1052static DRIVER_ATTR(con_pages, S_IRUSR, sclp_show_console_pages, NULL);
1053
1054static ssize_t sclp_show_con_drop(struct device_driver *dev, char *buf)
1055{
1056 return sprintf(buf, "%i\n", sclp_console_drop);
1057}
1058
1059static DRIVER_ATTR(con_drop, S_IRUSR, sclp_show_con_drop, NULL);
1060
1061static ssize_t sclp_show_console_full(struct device_driver *dev, char *buf)
1062{
1063 return sprintf(buf, "%lu\n", sclp_console_full);
1064}
1065
1066static DRIVER_ATTR(con_full, S_IRUSR, sclp_show_console_full, NULL);
1067
1068static 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};
1074static struct attribute_group sclp_drv_attr_group = {
1075 .attrs = sclp_drv_attrs,
1076};
1077static const struct attribute_group *sclp_drv_attr_groups[] = {
1078 &sclp_drv_attr_group,
1079 NULL,
1080};
1081
1016static struct platform_driver sclp_pdrv = { 1082static 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);
175int sclp_sdias_init(void); 175int sclp_sdias_init(void);
176void sclp_sdias_exit(void); 176void sclp_sdias_exit(void);
177 177
178extern int sclp_console_pages;
179extern int sclp_console_drop;
180extern 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 */
135static int
136sclp_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 */
135static void 160static 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 */
368static int
369sclp_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);
432out: 460out:
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 */