11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * SCLP line mode console driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Copyright IBM Corp. 1999, 2009 562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Author(s): Martin Peschke <mpeschke@de.ibm.com> 662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Martin Schwidefsky <schwidefsky@de.ibm.com> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kmod.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h> 14095761d28ae43eae7d4504d49b0b952cf02b0188Heiko Carstens#include <linux/termios.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/err.h> 162332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski#include <linux/reboot.h> 175a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sclp.h" 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sclp_rw.h" 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sclp_tty.h" 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sclp_console_major 4 /* TTYAUX_MAJOR */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sclp_console_minor 64 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sclp_console_name "ttyS" 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Lock to guard over changes to global variables */ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic spinlock_t sclp_con_lock; 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* List of free pages that can be used for console output buffering */ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct list_head sclp_con_pages; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* List of full struct sclp_buffer structures ready for output */ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct list_head sclp_con_outqueue; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Pointer to current console buffer */ 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sclp_buffer *sclp_conbuf; 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Timer for delayed output of console messages */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct timer_list sclp_con_timer; 3762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu/* Suspend mode flag */ 3862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheustatic int sclp_con_suspended; 3962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu/* Flag that output queue is currently running */ 4062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheustatic int sclp_con_queue_running; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Output format for console messages */ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short sclp_con_columns; 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short sclp_con_width_htab; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssclp_conbuf_callback(struct sclp_buffer *buffer, int rc) 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *page; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = sclp_unmake_buffer(buffer); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&sclp_con_lock, flags); 5562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remove buffer from outqueue */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&buffer->list); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail((struct list_head *) page, &sclp_con_pages); 5962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if there is a pending buffer on the out queue. */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer = NULL; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!list_empty(&sclp_con_outqueue)) 6362b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu buffer = list_first_entry(&sclp_con_outqueue, 6462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu struct sclp_buffer, list); 6562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu if (!buffer || sclp_con_suspended) { 6662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_con_queue_running = 0; 6762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_unlock_irqrestore(&sclp_con_lock, flags); 6862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu break; 6962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu } 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&sclp_con_lock, flags); 7162b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu } while (sclp_emit_buffer(buffer, sclp_conbuf_callback)); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu/* 7562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Finalize and emit first pending buffer. 7662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu */ 7762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheustatic void sclp_conbuf_emit(void) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sclp_buffer* buffer; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&sclp_con_lock, flags); 8462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu if (sclp_conbuf) 8562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_conbuf = NULL; 8762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu if (sclp_con_queue_running || sclp_con_suspended) 8862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu goto out_unlock; 8962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu if (list_empty(&sclp_con_outqueue)) 9062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu goto out_unlock; 9162b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer, 9262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu list); 9362b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_con_queue_running = 1; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&sclp_con_lock, flags); 9562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_conbuf_callback(buffer, rc); 9962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu return; 10062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheuout_unlock: 10162b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_unlock_irqrestore(&sclp_con_lock, flags); 10262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu} 10362b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 10462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu/* 10562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Wait until out queue is empty 10662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu */ 10762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheustatic void sclp_console_sync_queue(void) 10862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu{ 10962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu unsigned long flags; 11062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 11162b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_lock_irqsave(&sclp_con_lock, flags); 11262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu if (timer_pending(&sclp_con_timer)) 113f3dfa86caa4a54aceb2b235bf28a6f6ad73b2716Michael Holzheu del_timer(&sclp_con_timer); 11462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu while (sclp_con_queue_running) { 11562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_unlock_irqrestore(&sclp_con_lock, flags); 11662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_sync_wait(); 11762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_lock_irqsave(&sclp_con_lock, flags); 11862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu } 11962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_unlock_irqrestore(&sclp_con_lock, flags); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When this routine is called from the timer then we flush the 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * temporary write buffer without further waiting on a final new line. 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssclp_console_timeout(unsigned long data) 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_conbuf_emit(); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Writes the given message to S390 system console 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssclp_console_write(struct console *console, const char *message, 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *page; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int written; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count == 0) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&sclp_con_lock, flags); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * process escape characters, write message into buffer, 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send buffer to SCLP 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make sure we have a console output buffer */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sclp_conbuf == NULL) { 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (list_empty(&sclp_con_pages)) { 15462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu if (sclp_con_suspended) 15562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu goto out; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&sclp_con_lock, flags); 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_sync_wait(); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&sclp_con_lock, flags); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = sclp_con_pages.next; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del((struct list_head *) page); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_conbuf = sclp_make_buffer(page, sclp_con_columns, 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_con_width_htab); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* try to write the string to the current output buffer */ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds written = sclp_write(sclp_conbuf, (const unsigned char *) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds message, count); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (written == count) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Not all characters could be written to the current 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * output buffer. Emit the buffer, create a new buffer 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and then output the rest of the string. 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&sclp_con_lock, flags); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_conbuf_emit(); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&sclp_con_lock, flags); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds message += written; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= written; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (count > 0); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup timer to output current console buffer after 1/10 second */ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 && 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !timer_pending(&sclp_con_timer)) { 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&sclp_con_timer); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_con_timer.function = sclp_console_timeout; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_con_timer.data = 0UL; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_con_timer.expires = jiffies + HZ/10; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&sclp_con_timer); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheuout: 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&sclp_con_lock, flags); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tty_driver * 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssclp_console_device(struct console *c, int *index) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *index = c->index; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sclp_tty_driver; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 20262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Make sure that all buffers will be flushed to the SCLP. 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2052332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinskisclp_console_flush(void) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_conbuf_emit(); 20862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_console_sync_queue(); 20962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu} 21062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 21162b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu/* 21262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Resume console: If there are cached messages, emit them. 21362b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu */ 21462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheustatic void sclp_console_resume(void) 21562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu{ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_lock_irqsave(&sclp_con_lock, flags); 21962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_con_suspended = 0; 22062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu spin_unlock_irqrestore(&sclp_con_lock, flags); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_conbuf_emit(); 22262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu} 22362b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 22462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu/* 22562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * Suspend console: Set suspend flag and flush console 22662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu */ 22762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheustatic void sclp_console_suspend(void) 22862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu{ 22962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu unsigned long flags; 23062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&sclp_con_lock, flags); 23262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_con_suspended = 1; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&sclp_con_lock, flags); 23462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_console_flush(); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheustatic int sclp_console_notify(struct notifier_block *self, 23862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu unsigned long event, void *data) 2392332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski{ 2402332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski sclp_console_flush(); 2412332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski return NOTIFY_OK; 2422332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski} 2432332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski 2442332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinskistatic struct notifier_block on_panic_nb = { 2452332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski .notifier_call = sclp_console_notify, 24662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu .priority = SCLP_PANIC_PRIO_CLIENT, 2472332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski}; 2482332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski 2492332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinskistatic struct notifier_block on_reboot_nb = { 2502332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski .notifier_call = sclp_console_notify, 2512332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski .priority = 1, 2522332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski}; 2532332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * used to register the SCLP console to the kernel and to 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * give printk necessary information 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct console sclp_console = 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = sclp_console_name, 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = sclp_console_write, 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .device = sclp_console_device, 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .flags = CON_PRINTBUFFER, 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .index = 0 /* ttyS0 */ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 26862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu * This function is called for SCLP suspend and resume events. 26962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu */ 27062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheuvoid sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) 27162b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu{ 27262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu switch (sclp_pm_event) { 27362b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu case SCLP_PM_EVENT_FREEZE: 27462b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_console_suspend(); 27562b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu break; 27662b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu case SCLP_PM_EVENT_RESTORE: 27762b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu case SCLP_PM_EVENT_THAW: 27862b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu sclp_console_resume(); 27962b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu break; 28062b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu } 28162b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu} 28262b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu 28362b7494209495847269a6ce0504cbefd23d42eb1Michael Holzheu/* 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * called by console_init() in drivers/char/tty_io.c at boot-time. 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssclp_console_init(void) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *page; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!CONSOLE_IS_SCLP) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = sclp_rw_init(); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate pages for output buffering */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&sclp_con_pages); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_CONSOLE_PAGES; i++) { 3014c8f4794b61e89dd68f96cfc23a9d9b6c25be420Heiko Carstens page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 3024c8f4794b61e89dd68f96cfc23a9d9b6c25be420Heiko Carstens list_add_tail(page, &sclp_con_pages); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&sclp_con_outqueue); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&sclp_con_lock); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_conbuf = NULL; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&sclp_con_timer); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set output format */ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (MACHINE_IS_VM) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * save 4 characters for the CPU number 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * written at start of each line by VM/CP 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_con_columns = 76; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_con_columns = 80; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sclp_con_width_htab = 8; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable printk-access to this driver */ 3212332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); 3222332ce1a97963b7769e0c2d40492a10a124efba5Holger Smolinski register_reboot_notifier(&on_reboot_nb); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register_console(&sclp_console); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsconsole_initcall(sclp_console_init); 328