[S390] Cleanup sclp printk messages.
[linux-2.6] / drivers / s390 / char / sclp_con.c
1 /*
2  *  drivers/s390/char/sclp_con.c
3  *    SCLP line mode console driver
4  *
5  *  S390 version
6  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7  *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
8  *               Martin Schwidefsky <schwidefsky@de.ibm.com>
9  */
10
11 #include <linux/kmod.h>
12 #include <linux/console.h>
13 #include <linux/init.h>
14 #include <linux/timer.h>
15 #include <linux/jiffies.h>
16 #include <linux/bootmem.h>
17 #include <linux/err.h>
18
19 #include "sclp.h"
20 #include "sclp_rw.h"
21 #include "sclp_tty.h"
22
23 #define sclp_console_major 4            /* TTYAUX_MAJOR */
24 #define sclp_console_minor 64
25 #define sclp_console_name  "ttyS"
26
27 /* Lock to guard over changes to global variables */
28 static spinlock_t sclp_con_lock;
29 /* List of free pages that can be used for console output buffering */
30 static struct list_head sclp_con_pages;
31 /* List of full struct sclp_buffer structures ready for output */
32 static struct list_head sclp_con_outqueue;
33 /* Counter how many buffers are emitted (max 1) and how many */
34 /* are on the output queue. */
35 static int sclp_con_buffer_count;
36 /* Pointer to current console buffer */
37 static struct sclp_buffer *sclp_conbuf;
38 /* Timer for delayed output of console messages */
39 static struct timer_list sclp_con_timer;
40
41 /* Output format for console messages */
42 static unsigned short sclp_con_columns;
43 static unsigned short sclp_con_width_htab;
44
45 static void
46 sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
47 {
48         unsigned long flags;
49         void *page;
50
51         do {
52                 page = sclp_unmake_buffer(buffer);
53                 spin_lock_irqsave(&sclp_con_lock, flags);
54                 /* Remove buffer from outqueue */
55                 list_del(&buffer->list);
56                 sclp_con_buffer_count--;
57                 list_add_tail((struct list_head *) page, &sclp_con_pages);
58                 /* Check if there is a pending buffer on the out queue. */
59                 buffer = NULL;
60                 if (!list_empty(&sclp_con_outqueue))
61                         buffer = list_entry(sclp_con_outqueue.next,
62                                             struct sclp_buffer, list);
63                 spin_unlock_irqrestore(&sclp_con_lock, flags);
64         } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
65 }
66
67 static void
68 sclp_conbuf_emit(void)
69 {
70         struct sclp_buffer* buffer;
71         unsigned long flags;
72         int count;
73         int rc;
74
75         spin_lock_irqsave(&sclp_con_lock, flags);
76         buffer = sclp_conbuf;
77         sclp_conbuf = NULL;
78         if (buffer == NULL) {
79                 spin_unlock_irqrestore(&sclp_con_lock, flags);
80                 return;
81         }
82         list_add_tail(&buffer->list, &sclp_con_outqueue);
83         count = sclp_con_buffer_count++;
84         spin_unlock_irqrestore(&sclp_con_lock, flags);
85         if (count)
86                 return;
87         rc = sclp_emit_buffer(buffer, sclp_conbuf_callback);
88         if (rc)
89                 sclp_conbuf_callback(buffer, rc);
90 }
91
92 /*
93  * When this routine is called from the timer then we flush the
94  * temporary write buffer without further waiting on a final new line.
95  */
96 static void
97 sclp_console_timeout(unsigned long data)
98 {
99         sclp_conbuf_emit();
100 }
101
102 /*
103  * Writes the given message to S390 system console
104  */
105 static void
106 sclp_console_write(struct console *console, const char *message,
107                    unsigned int count)
108 {
109         unsigned long flags;
110         void *page;
111         int written;
112
113         if (count == 0)
114                 return;
115         spin_lock_irqsave(&sclp_con_lock, flags);
116         /*
117          * process escape characters, write message into buffer,
118          * send buffer to SCLP
119          */
120         do {
121                 /* make sure we have a console output buffer */
122                 if (sclp_conbuf == NULL) {
123                         while (list_empty(&sclp_con_pages)) {
124                                 spin_unlock_irqrestore(&sclp_con_lock, flags);
125                                 sclp_sync_wait();
126                                 spin_lock_irqsave(&sclp_con_lock, flags);
127                         }
128                         page = sclp_con_pages.next;
129                         list_del((struct list_head *) page);
130                         sclp_conbuf = sclp_make_buffer(page, sclp_con_columns,
131                                                        sclp_con_width_htab);
132                 }
133                 /* try to write the string to the current output buffer */
134                 written = sclp_write(sclp_conbuf, (const unsigned char *)
135                                      message, count);
136                 if (written == count)
137                         break;
138                 /*
139                  * Not all characters could be written to the current
140                  * output buffer. Emit the buffer, create a new buffer
141                  * and then output the rest of the string.
142                  */
143                 spin_unlock_irqrestore(&sclp_con_lock, flags);
144                 sclp_conbuf_emit();
145                 spin_lock_irqsave(&sclp_con_lock, flags);
146                 message += written;
147                 count -= written;
148         } while (count > 0);
149         /* Setup timer to output current console buffer after 1/10 second */
150         if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 &&
151             !timer_pending(&sclp_con_timer)) {
152                 init_timer(&sclp_con_timer);
153                 sclp_con_timer.function = sclp_console_timeout;
154                 sclp_con_timer.data = 0UL;
155                 sclp_con_timer.expires = jiffies + HZ/10;
156                 add_timer(&sclp_con_timer);
157         }
158         spin_unlock_irqrestore(&sclp_con_lock, flags);
159 }
160
161 static struct tty_driver *
162 sclp_console_device(struct console *c, int *index)
163 {
164         *index = c->index;
165         return sclp_tty_driver;
166 }
167
168 /*
169  * This routine is called from panic when the kernel
170  * is going to give up. We have to make sure that all buffers
171  * will be flushed to the SCLP.
172  */
173 static void
174 sclp_console_unblank(void)
175 {
176         unsigned long flags;
177
178         sclp_conbuf_emit();
179         spin_lock_irqsave(&sclp_con_lock, flags);
180         if (timer_pending(&sclp_con_timer))
181                 del_timer(&sclp_con_timer);
182         while (sclp_con_buffer_count > 0) {
183                 spin_unlock_irqrestore(&sclp_con_lock, flags);
184                 sclp_sync_wait();
185                 spin_lock_irqsave(&sclp_con_lock, flags);
186         }
187         spin_unlock_irqrestore(&sclp_con_lock, flags);
188 }
189
190 /*
191  * used to register the SCLP console to the kernel and to
192  * give printk necessary information
193  */
194 static struct console sclp_console =
195 {
196         .name = sclp_console_name,
197         .write = sclp_console_write,
198         .device = sclp_console_device,
199         .unblank = sclp_console_unblank,
200         .flags = CON_PRINTBUFFER,
201         .index = 0 /* ttyS0 */
202 };
203
204 /*
205  * called by console_init() in drivers/char/tty_io.c at boot-time.
206  */
207 static int __init
208 sclp_console_init(void)
209 {
210         void *page;
211         int i;
212         int rc;
213
214         if (!CONSOLE_IS_SCLP)
215                 return 0;
216         rc = sclp_rw_init();
217         if (rc)
218                 return rc;
219         /* Allocate pages for output buffering */
220         INIT_LIST_HEAD(&sclp_con_pages);
221         for (i = 0; i < MAX_CONSOLE_PAGES; i++) {
222                 page = alloc_bootmem_low_pages(PAGE_SIZE);
223                 list_add_tail((struct list_head *) page, &sclp_con_pages);
224         }
225         INIT_LIST_HEAD(&sclp_con_outqueue);
226         spin_lock_init(&sclp_con_lock);
227         sclp_con_buffer_count = 0;
228         sclp_conbuf = NULL;
229         init_timer(&sclp_con_timer);
230
231         /* Set output format */
232         if (MACHINE_IS_VM)
233                 /*
234                  * save 4 characters for the CPU number
235                  * written at start of each line by VM/CP
236                  */
237                 sclp_con_columns = 76;
238         else
239                 sclp_con_columns = 80;
240         sclp_con_width_htab = 8;
241
242         /* enable printk-access to this driver */
243         register_console(&sclp_console);
244         return 0;
245 }
246
247 console_initcall(sclp_console_init);