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