Sophie

Sophie

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

kernel-2.6.18-238.el5.src.rpm

From: Simon McGrath <smcgrath@redhat.com>
Date: Sat, 12 Apr 2008 00:43:40 -0400
Subject: [misc] ttyS1 loses interrupt and stops transmitting
Message-id: 48003DFC.9000801@redhat.com
O-Subject: Re: [Stratus 5.2] ttyS1 lost interrupt and it stops transmitting: - Last minute patch, PLEASE REVIEW
Bugzilla: 440121

Description:
------------

Writes to /dev/ttyS1 frequently stall.  Analysis shows the 8250 driver
incorrectly detects the device as a 16550A with the UART_BUG_TXEN bug.  Only
on SMP systems is this bug is exposed.  When we boot with maxcpus=1 the problem
does not occur.

The patch fixes SMP races between the 8250 interrupt service routine (ISR)
and non-ISR code when they access the IIR register of the UART.

RHBZ#:
------
440121

RHEL Version Found:
------------------
RHEL 5.2

kABI Status:
------------
No symbols are implicated

Test Status:
-------------
Stratus tested using kernel-2.6.18-87.el5 modified to take the irq_info lock
during the quick test for UART_BUG_TXEN.  This ran overnight and that change (shown
below) fixed our problem, plus we did not see any "irq %d nobody cared"
messages.
---------------------------------------------------------------

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index f7c9f23..85d29a1 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -1779,11 +1779,17 @@ static int serial8250_startup(struct uart_port *port)
 	 * Do a quick test to see if we receive an
 	 * interrupt when we enable the TX irq.
 	 */
+	if (is_real_interrupt(up->port.irq))
+		spin_lock(&irq_lists[up->port.irq].lock);
+
 	serial_outp(up, UART_IER, UART_IER_THRI);
 	lsr = serial_in(up, UART_LSR);
 	iir = serial_in(up, UART_IIR);
 	serial_outp(up, UART_IER, 0);
 
+	if (is_real_interrupt(up->port.irq))
+		spin_unlock(&irq_lists[up->port.irq].lock);
+
 	if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
 		if (!(up->bugs & UART_BUG_TXEN)) {
 			up->bugs |= UART_BUG_TXEN;