Commit f91a3715 authored by Alan Cox's avatar Alan Cox Committed by Russell King

[SERIAL] 8250 serial console fixes

This patch resolves most of the problems with an SMP serial console race
with output via the tty path. At the end of the serial console print we
force enable the tx int in case we clobbered the tx interrupt status
racing between the console and tty output. That way the extra tx
interrupt causes the transmit path to restart not hang.

It also makes the serial console printk use the FIFO. This is neccessary
because some remote management devices fake serial console with FIFO and
are confused into sending one packet per character over ethernet when we
stall rather than filling the FIFO.

In order to preserve existing reliability semantics the function waits
for the serial queue to completely empty before returning.

Both of these problems were identified by a Red Hat partner.
Signed-off-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 3ee68c4a
...@@ -2164,7 +2164,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) ...@@ -2164,7 +2164,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
/* /*
* Wait for transmitter & holding register to empty * Wait for transmitter & holding register to empty
*/ */
static inline void wait_for_xmitr(struct uart_8250_port *up) static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
{ {
unsigned int status, tmout = 10000; unsigned int status, tmout = 10000;
...@@ -2178,7 +2178,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up) ...@@ -2178,7 +2178,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up)
if (--tmout == 0) if (--tmout == 0)
break; break;
udelay(1); udelay(1);
} while ((status & BOTH_EMPTY) != BOTH_EMPTY); } while ((status & bits) != bits);
/* Wait up to 1s for flow control if necessary */ /* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) { if (up->port.flags & UPF_CONS_FLOW) {
...@@ -2218,7 +2218,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) ...@@ -2218,7 +2218,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
* Now, do each character * Now, do each character
*/ */
for (i = 0; i < count; i++, s++) { for (i = 0; i < count; i++, s++) {
wait_for_xmitr(up); wait_for_xmitr(up, UART_LSR_THRE);
/* /*
* Send the character out. * Send the character out.
...@@ -2226,7 +2226,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) ...@@ -2226,7 +2226,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
*/ */
serial_out(up, UART_TX, *s); serial_out(up, UART_TX, *s);
if (*s == 10) { if (*s == 10) {
wait_for_xmitr(up); wait_for_xmitr(up, UART_LSR_THRE);
serial_out(up, UART_TX, 13); serial_out(up, UART_TX, 13);
} }
} }
...@@ -2235,8 +2235,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) ...@@ -2235,8 +2235,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
* Finally, wait for transmitter to become empty * Finally, wait for transmitter to become empty
* and restore the IER * and restore the IER
*/ */
wait_for_xmitr(up); wait_for_xmitr(up, BOTH_EMPTY);
serial_out(up, UART_IER, ier); serial_out(up, UART_IER, ier | UART_IER_THRI);
} }
static int serial8250_console_setup(struct console *co, char *options) static int serial8250_console_setup(struct console *co, char *options)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment