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); 327