Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2097

kernel-2.6.18-238.el5.src.rpm

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;
 }