xref: /openbmc/linux/drivers/s390/char/sclp_con.c (revision b627b4ed)
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