--- linux-2.4.20-20.7/drivers/char/serial.c.orig Mon Aug 18 11:33:18 2003 +++ linux-2.4.20-20.7/drivers/char/serial.c Wed Nov 12 11:27:31 2003 @@ -797,6 +797,23 @@ } } +/* + * Returns != 0 (true) if UART is ready for more transmit data. + * This function contains a work-around for a silicon bug in the UARTs + * of the AMD Elan microcontroller. The LSR THRE bit is set late and + * may be missed by the interrupt routine, so an IIR THRI status is also + * treated as an LSR THRE status. This causes xmit data loss on 16C654 + * UARTs (and perhaps others) so the work-around is applied only to + * ports detected as generic UART types 8250, 16450, 16550 and 16550A. + */ +static _INLINE_ int uart_transmit_ready(struct async_struct *info, + int status, int iir) +{ + return (status & UART_LSR_THRE) || + ((info->state->type <= PORT_16550A) && + ((iir & UART_IIR_ID) == UART_IIR_THRI)); +} + #ifdef CONFIG_SERIAL_SHARE_IRQ /* * This is the serial driver's generic interrupt routine @@ -919,9 +936,7 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if ((status & UART_LSR_THRE) || - /* For buggy ELAN processors */ - ((iir & UART_IIR_ID) == UART_IIR_THRI)) + if (uart_transmit_ready(info, status, iir)) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { #if SERIAL_DEBUG_INTR