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