Merge branch 'for-2.6.31' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
[pandora-kernel.git] / drivers / s390 / char / sclp_con.c
1 /*
2  * SCLP line mode console driver
3  *
4  * Copyright IBM Corp. 1999, 2009
5  * Author(s): Martin Peschke <mpeschke@de.ibm.com>
6  *            Martin Schwidefsky <schwidefsky@de.ibm.com>
7  */
8
9 #include <linux/kmod.h>
10 #include <linux/console.h>
11 #include <linux/init.h>
12 #include <linux/timer.h>
13 #include <linux/jiffies.h>
14 #include <linux/termios.h>
15 #include <linux/err.h>
16 #include <linux/reboot.h>
17
18 #include "sclp.h"
19 #include "sclp_rw.h"
20 #include "sclp_tty.h"
21
22 #define sclp_console_major 4            /* TTYAUX_MAJOR */
23 #define sclp_console_minor 64
24 #define sclp_console_name  "ttyS"
25
26 /* Lock to guard over changes to global variables */
27 static spinlock_t sclp_con_lock;
28 /* List of free pages that can be used for console output buffering */
29 static struct list_head sclp_con_pages;
30 /* List of full struct sclp_buffer structures ready for output */
31 static struct list_head sclp_con_outqueue;
32 /* Pointer to current console buffer */
33 static struct sclp_buffer *sclp_conbuf;
34 /* Timer for delayed output of console messages */
35 static struct timer_list sclp_con_timer;
36 /* Suspend mode flag */
37 static int sclp_con_suspended;
38 /* Flag that output queue is currently running */
39 static int sclp_con_queue_running;
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
55                 /* Remove buffer from outqueue */
56                 list_del(&buffer->list);
57                 list_add_tail((struct list_head *) page, &sclp_con_pages);
58
59                 /* Check if there is a pending buffer on the out queue. */
60                 buffer = NULL;
61                 if (!list_empty(&sclp_con_outqueue))
62                         buffer = list_first_entry(&sclp_con_outqueue,
63                                                   struct sclp_buffer, list);
64                 if (!buffer || sclp_con_suspended) {
65                         sclp_con_queue_running = 0;
66                         spin_unlock_irqrestore(&sclp_con_lock, flags);
67                         break;
68                 }
69                 spin_unlock_irqrestore(&sclp_con_lock, flags);
70         } while (sclp_emit_buffer(buffer, sclp_conbuf_callback));
71 }
72
73 /*
74  * Finalize and emit first pending buffer.
75  */
76 static void sclp_conbuf_emit(void)
77 {
78         struct sclp_buffer* buffer;
79         unsigned long flags;
80         int rc;
81
82         spin_lock_irqsave(&sclp_con_lock, flags);
83         if (sclp_conbuf)
84                 list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue);
85         sclp_conbuf = NULL;
86         if (sclp_con_queue_running || sclp_con_suspended)
87                 goto out_unlock;
88         if (list_empty(&sclp_con_outqueue))
89                 goto out_unlock;
90         buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer,
91                                   list);
92         sclp_con_queue_running = 1;
93         spin_unlock_irqrestore(&sclp_con_lock, flags);
94
95         rc = sclp_emit_buffer(buffer, sclp_conbuf_callback);
96         if (rc)
97                 sclp_conbuf_callback(buffer, rc);
98         return;
99 out_unlock:
100         spin_unlock_irqrestore(&sclp_con_lock, flags);
101 }
102
103 /*
104  * Wait until out queue is empty
105  */
106 static void sclp_console_sync_queue(void)
107 {
108         unsigned long flags;
109
110         spin_lock_irqsave(&sclp_con_lock, flags);
111         if (timer_pending(&sclp_con_timer))
112                 del_timer(&sclp_con_timer);
113         while (sclp_con_queue_running) {
114                 spin_unlock_irqrestore(&sclp_con_lock, flags);
115                 sclp_sync_wait();
116                 spin_lock_irqsave(&sclp_con_lock, flags);
117         }
118         spin_unlock_irqrestore(&sclp_con_lock, flags);
119 }
120
121 /*
122  * When this routine is called from the timer then we flush the
123  * temporary write buffer without further waiting on a final new line.
124  */
125 static void
126 sclp_console_timeout(unsigned long data)
127 {
128         sclp_conbuf_emit();
129 }
130
131 /*
132  * Writes the given message to S390 system console
133  */
134 static void
135 sclp_console_write(struct console *console, const char *message,
136                    unsigned int count)
137 {
138         unsigned long flags;
139         void *page;
140         int written;
141
142         if (count == 0)
143                 return;
144         spin_lock_irqsave(&sclp_con_lock, flags);
145         /*
146          * process escape characters, write message into buffer,
147          * send buffer to SCLP
148          */
149         do {
150                 /* make sure we have a console output buffer */
151                 if (sclp_conbuf == NULL) {
152                         while (list_empty(&sclp_con_pages)) {
153                                 if (sclp_con_suspended)
154                                         goto out;
155                                 spin_unlock_irqrestore(&sclp_con_lock, flags);
156                                 sclp_sync_wait();
157                                 spin_lock_irqsave(&sclp_con_lock, flags);
158                         }
159                         page = sclp_con_pages.next;
160                         list_del((struct list_head *) page);
161                         sclp_conbuf = sclp_make_buffer(page, sclp_con_columns,
162                                                        sclp_con_width_htab);
163                 }
164                 /* try to write the string to the current output buffer */
165                 written = sclp_write(sclp_conbuf, (const unsigned char *)
166                                      message, count);
167                 if (written == count)
168                         break;
169                 /*
170                  * Not all characters could be written to the current
171                  * output buffer. Emit the buffer, create a new buffer
172                  * and then output the rest of the string.
173                  */
174                 spin_unlock_irqrestore(&sclp_con_lock, flags);
175                 sclp_conbuf_emit();
176                 spin_lock_irqsave(&sclp_con_lock, flags);
177                 message += written;
178                 count -= written;
179         } while (count > 0);
180         /* Setup timer to output current console buffer after 1/10 second */
181         if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 &&
182             !timer_pending(&sclp_con_timer)) {
183                 init_timer(&sclp_con_timer);
184                 sclp_con_timer.function = sclp_console_timeout;
185                 sclp_con_timer.data = 0UL;
186                 sclp_con_timer.expires = jiffies + HZ/10;
187                 add_timer(&sclp_con_timer);
188         }
189 out:
190         spin_unlock_irqrestore(&sclp_con_lock, flags);
191 }
192
193 static struct tty_driver *
194 sclp_console_device(struct console *c, int *index)
195 {
196         *index = c->index;
197         return sclp_tty_driver;
198 }
199
200 /*
201  * Make sure that all buffers will be flushed to the SCLP.
202  */
203 static void
204 sclp_console_flush(void)
205 {
206         sclp_conbuf_emit();
207         sclp_console_sync_queue();
208 }
209
210 /*
211  * Resume console: If there are cached messages, emit them.
212  */
213 static void sclp_console_resume(void)
214 {
215         unsigned long flags;
216
217         spin_lock_irqsave(&sclp_con_lock, flags);
218         sclp_con_suspended = 0;
219         spin_unlock_irqrestore(&sclp_con_lock, flags);
220         sclp_conbuf_emit();
221 }
222
223 /*
224  * Suspend console: Set suspend flag and flush console
225  */
226 static void sclp_console_suspend(void)
227 {
228         unsigned long flags;
229
230         spin_lock_irqsave(&sclp_con_lock, flags);
231         sclp_con_suspended = 1;
232         spin_unlock_irqrestore(&sclp_con_lock, flags);
233         sclp_console_flush();
234 }
235
236 static int sclp_console_notify(struct notifier_block *self,
237                                unsigned long event, void *data)
238 {
239         sclp_console_flush();
240         return NOTIFY_OK;
241 }
242
243 static struct notifier_block on_panic_nb = {
244         .notifier_call = sclp_console_notify,
245         .priority = SCLP_PANIC_PRIO_CLIENT,
246 };
247
248 static struct notifier_block on_reboot_nb = {
249         .notifier_call = sclp_console_notify,
250         .priority = 1,
251 };
252
253 /*
254  * used to register the SCLP console to the kernel and to
255  * give printk necessary information
256  */
257 static struct console sclp_console =
258 {
259         .name = sclp_console_name,
260         .write = sclp_console_write,
261         .device = sclp_console_device,
262         .flags = CON_PRINTBUFFER,
263         .index = 0 /* ttyS0 */
264 };
265
266 /*
267  * This function is called for SCLP suspend and resume events.
268  */
269 void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event)
270 {
271         switch (sclp_pm_event) {
272         case SCLP_PM_EVENT_FREEZE:
273                 sclp_console_suspend();
274                 break;
275         case SCLP_PM_EVENT_RESTORE:
276         case SCLP_PM_EVENT_THAW:
277                 sclp_console_resume();
278                 break;
279         }
280 }
281
282 /*
283  * called by console_init() in drivers/char/tty_io.c at boot-time.
284  */
285 static int __init
286 sclp_console_init(void)
287 {
288         void *page;
289         int i;
290         int rc;
291
292         if (!CONSOLE_IS_SCLP)
293                 return 0;
294         rc = sclp_rw_init();
295         if (rc)
296                 return rc;
297         /* Allocate pages for output buffering */
298         INIT_LIST_HEAD(&sclp_con_pages);
299         for (i = 0; i < MAX_CONSOLE_PAGES; i++) {
300                 page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
301                 list_add_tail(page, &sclp_con_pages);
302         }
303         INIT_LIST_HEAD(&sclp_con_outqueue);
304         spin_lock_init(&sclp_con_lock);
305         sclp_conbuf = NULL;
306         init_timer(&sclp_con_timer);
307
308         /* Set output format */
309         if (MACHINE_IS_VM)
310                 /*
311                  * save 4 characters for the CPU number
312                  * written at start of each line by VM/CP
313                  */
314                 sclp_con_columns = 76;
315         else
316                 sclp_con_columns = 80;
317         sclp_con_width_htab = 8;
318
319         /* enable printk-access to this driver */
320         atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
321         register_reboot_notifier(&on_reboot_nb);
322         register_console(&sclp_console);
323         return 0;
324 }
325
326 console_initcall(sclp_console_init);