[SERIAL] 8250 serial console fixes
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Sat, 21 Jan 2006 14:59:12 +0000 (14:59 +0000)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 21 Jan 2006 14:59:12 +0000 (14:59 +0000)
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: Alan Cox <alan@redhat.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
drivers/serial/8250.c

index bc36edff205805517a489e945826edce91943640..ff2f931c67151483d0c40541abf1ceec39077448 100644 (file)
@@ -2164,7 +2164,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 /*
  *     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;
 
@@ -2178,7 +2178,7 @@ static inline void wait_for_xmitr(struct uart_8250_port *up)
                if (--tmout == 0)
                        break;
                udelay(1);
-       } while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+       } while ((status & bits) != bits);
 
        /* Wait up to 1s for flow control if necessary */
        if (up->port.flags & UPF_CONS_FLOW) {
@@ -2218,7 +2218,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
         *      Now, do each character
         */
        for (i = 0; i < count; i++, s++) {
-               wait_for_xmitr(up);
+               wait_for_xmitr(up, UART_LSR_THRE);
 
                /*
                 *      Send the character out.
@@ -2226,7 +2226,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
                 */
                serial_out(up, UART_TX, *s);
                if (*s == 10) {
-                       wait_for_xmitr(up);
+                       wait_for_xmitr(up, UART_LSR_THRE);
                        serial_out(up, UART_TX, 13);
                }
        }
@@ -2235,8 +2235,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
         *      Finally, wait for transmitter to become empty
         *      and restore the IER
         */
-       wait_for_xmitr(up);
-       serial_out(up, UART_IER, ier);
+       wait_for_xmitr(up, BOTH_EMPTY);
+       serial_out(up, UART_IER, ier | UART_IER_THRI);
 }
 
 static int serial8250_console_setup(struct console *co, char *options)