Subject: kern/1042: Some serial cards hang on first open if data is in FIFO
To: None <gnats-admin@sun-lamp.cs.berkeley.edu>
From: Scott Reynolds <scottr@Plexus.COM>
List: netbsd-bugs
Date: 05/11/1995 14:20:05
>Number:         1042
>Category:       kern
>Synopsis:       Some serial cards hang on first open if data is in FIFO
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu May 11 14:20:04 1995
>Originator:     Scott Reynolds
>Organization:
>Release:        NetBSD-current 08-May-95
>Environment:
	Micronics JX30GC motherboard, on-board 16550-compatible UARTs
System: NetBSD aqua 1.0A NetBSD 1.0A (TGI) #46: Wed May 10 16:41:54 CDT 1995 scottr@aqua:/a/src/sys/arch/i386/compile/TGI i386


>Description:
	If there is data in the FIFO when the port is first opened, such
	as after a cold boot or after a warm boot from Win 3.x/NT 3.5, a
	race condition will occur when calling splx() right before
	returning from comopen().  This appears with at least some
	SMC UARTs.

>How-To-Repeat:
	Cold boot with some device that shoves characters into the serial
	port after reset, such as a Logitech Mouseman CR-32.  If you have
	the affected serial chip, the machine will hang on the first open
	of the port (e.g. in /etc/rc when 'ttyflags -a' is run).

>Fix:
	This method was gleaned from the FreeBSD sio.c driver and mangled
	appropriately.  The comment comes primarily from sio.c.

*** com.c.orig	Fri Apr 28 05:26:11 1995
--- com.c	Thu May 11 09:41:01 1995
***************
*** 290,300 ****
  		ttsetwater(tp);
  
  		iobase = sc->sc_iobase;
! 		/* Set the FIFO threshold based on the receive speed. */
! 		if (sc->sc_hwflags & COM_HW_FIFO)
! 			outb(iobase + com_fifo,
! 			    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
! 			    (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
  		/* flush any pending I/O */
  		(void) inb(iobase + com_lsr);
  		(void) inb(iobase + com_data);
--- 290,319 ----
  		ttsetwater(tp);
  
  		iobase = sc->sc_iobase;
! 		if (sc->sc_hwflags & COM_HW_FIFO) {
! 			/*
! 			 * (Re)enable and drain FIFOs.
! 			 *
! 			 * Certain SMC chips cause problems if the FIFOs are
! 			 * enabled while input is ready.  Turn off the FIFO
! 			 * if necessary to clear the input.  Test the input
! 			 * ready bit after enabling the FIFOs to handle races
! 			 * between enabling and fresh input.
! 			 *
! 			 * Set the FIFO threshold based on the receive speed.
! 			 */
! 			for (;;) {
! 				outb(iobase + com_fifo,
! 				    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
! 				    (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
! 				delay(100);
! 				if ((inb(iobase + com_lsr) & LSR_RXRDY) == 0)
! 					break;
! 				outb(iobase + com_fifo, 0);
! 				delay(100);
! 				(void) inb(iobase + com_data);
! 			}
! 		}
  		/* flush any pending I/O */
  		(void) inb(iobase + com_lsr);
  		(void) inb(iobase + com_data);
>Audit-Trail:
>Unformatted: