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