From: Aristeu Rozanski <arozansk@redhat.com> Date: Tue, 29 Jul 2008 10:17:52 -0400 Subject: [misc] serial: fix break handling for i82571 over LAN Message-id: 20080729141752.GA19753@redhat.com O-Subject: [RHEL5.3 PATCH] serial: fix break handling for i82571 serial over LAN Bugzilla: 440018 RH-Acked-by: Brian Maly <bmaly@redhat.com> https://bugzilla.redhat.com/show_bug.cgi?id=440018 Intel 82571 has a "Serial Over LAN" feature that doesn't properly implements the receiving of break characters. When a break is received, it doesn't set UART_LSR_DR and unless another character is received, the break won't be received by the application. This patch also initializes lsr_break_flag on serial8250_startup(), which is an indirect backport of ad4c2aa6354fad5316565b1cff57f80db0e04db8, where lsr_saved_flags is initialized instead. Tested by the customer on the hardware and by me on a regular port for regressions. Upstream: 7500b1f602aad75901774a67a687ee985d85893f ad4c2aa6354fad5316565b1cff57f80db0e04db8 diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 96eec5c..ce6dede 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1199,7 +1199,17 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) char flag; do { - ch = serial_inp(up, UART_RX); + if (likely(lsr & UART_LSR_DR)) + ch = serial_inp(up, UART_RX); + else + /* + * Intel 82571 has a Serial Over Lan device that will set BI + * without setting UART_LSR_DR. To avoid reading from the + * receive buffer without UART_LSR_DR bit set, we just force + * the read character to be 0 + */ + ch = 0; + flag = TTY_NORMAL; up->port.icount.rx++; @@ -1256,7 +1266,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) ignore_char: lsr = serial_inp(up, UART_LSR); - } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); spin_lock(&up->port.lock); @@ -1337,7 +1347,7 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) DEBUG_INTR("status = %x...", status); - if (status & UART_LSR_DR) + if (status & (UART_LSR_DR | UART_LSR_BI)) receive_chars(up, &status, regs); check_modem_status(up); if (status & UART_LSR_THRE) @@ -1829,6 +1839,7 @@ static int serial8250_startup(struct uart_port *port) (void) serial_inp(up, UART_RX); (void) serial_inp(up, UART_IIR); (void) serial_inp(up, UART_MSR); + up->lsr_break_flag = 0; return 0; }