Subject: port-i386/1047: rs232c/ns16450 hang up problem & fix
To: None <gnats-admin@sun-lamp.cs.berkeley.edu>
From: Noriyuki Soda <soda@sra.co.jp>
List: netbsd-bugs
Date: 05/14/1995 08:20:04
>Number:         1047
>Category:       port-i386
>Synopsis:       rs232c/ns16450 hang up problem & fix
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun May 14 08:20:02 1995
>Originator:     Noriyuki Soda
>Organization:
	Software Research Associates, Inc.
>Release:        1.0A
>Environment:
System: NetBSD james 1.0A NetBSD 1.0A (JAMES) #0: Sat Mar  4 08:21:18 JST 1995 soda@james:/usr/src/sys/arch/i386/compile/JAMES i386

Machine:
	486DX2/66MHz, 8MB RAM, IDE 520MB disk, NS16450 serial chip.
	
	com1 at isa0 port 0x2f8-0x2ff irq 3: ns82450 or ns16450, no fifo

>Description:

	When using PPPD or TIP, RS-232 is sometimes stopped up, and it
	doesn't recover until rebooting NetBSD.
	When hangs on PPPD, "ps agxl" shows WCHAR="ttyout".
	Note: my serial chip is NS16450.
	
>How-To-Repeat:

	% find / -print >& /dev/null &
	% ping -s 1400 ppp-peer-address

>Fix:

  After applying following patch, problem goes away, with following message.
   ->	May 14 20:11:35 james /netbsd: com1: lost tx interrupt
	May 14 20:12:20 james /netbsd: com1: 2 silo overflows
	May 14 20:13:26 james /netbsd: com1: 1 silo overflow
   ->	May 14 20:14:55 james /netbsd: com1: lost tx interrupt
 (This patch is based on NetBSD-current 1995/05/13)

----------------------------------------------------------------------------
--- 1.1.1.1	1995/05/13 10:25:50
+++ com.c	1995/05/14 09:48:45
@@ -62,6 +62,9 @@
 #include <dev/isa/comreg.h>
 #include <dev/ic/ns16550.h>
 
+#define COM_DETECT_LOST_TXINTR
+#define	COM_TX_TIMEOUT	2	/* should be > 1 */
+
 struct com_softc {
 	struct device sc_dev;
 	void *sc_ih;
@@ -79,6 +82,10 @@
 #define	COM_SW_CRTSCTS	0x04
 #define	COM_SW_MDMBUF	0x08
 	u_char sc_msr, sc_mcr;
+#ifdef COM_DETECT_LOST_TXINTR
+	int32_t	sc_transmit_time;
+	u_char sc_txintr_pending;
+#endif
 };
 
 int comprobe __P((struct device *, void *, void *));
@@ -86,6 +93,9 @@
 int comopen __P((dev_t, int, int, struct proc *));
 int comclose __P((dev_t, int, int, struct proc *));
 void comdiag __P((void *));
+#ifdef COM_DETECT_LOST_TXINTR
+void comwatchdog __P((void *));
+#endif
 int comintr __P((void *));
 int comparam __P((struct tty *, struct termios *));
 void comstart __P((struct tty *));
@@ -295,6 +305,13 @@
 			outb(iobase + com_fifo,
 			    FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST |
 			    (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8));
+#ifdef COM_DETECT_LOST_TXINTR
+		else {
+			/* for buggy chip */
+			sc->sc_txintr_pending = 0;
+			timeout(comwatchdog, sc, hz);
+		}
+#endif
 		/* flush any pending I/O */
 		(void) inb(iobase + com_lsr);
 		(void) inb(iobase + com_data);
@@ -359,6 +376,12 @@
 		    (sc->sc_swflags & COM_SW_SOFTCAR) == 0)
 			/* XXX perhaps only clear DTR */
 			outb(iobase + com_mcr, 0);
+#ifdef COM_DETECT_LOST_TXINTR
+		if ((sc->sc_hwflags & COM_HW_FIFO) == 0) {
+			sc->sc_txintr_pending = 0;
+			untimeout(comwatchdog, sc);
+		}
+#endif
 	}
 	ttyclose(tp);
 #ifdef notyet /* XXXX */
@@ -674,6 +697,10 @@
 		} while (--n);
 	} else
 		outb(iobase + com_data, getc(&tp->t_outq));
+#ifdef COM_DETECT_LOST_TXINTR
+	sc->sc_txintr_pending = 1;
+	sc->sc_transmit_time = time.tv_sec;
+#endif
 out:
 	splx(s);
 }
@@ -778,6 +805,46 @@
 		    sc->sc_dev.dv_xname, overflows, overflows == 1 ? "" : "s");
 }
 
+static inline void
+comtint(sc)
+	struct com_softc *sc;
+{
+	struct tty *tp = tp = sc->sc_tty;
+
+#ifdef COM_DETECT_LOST_TXINTR
+	sc->sc_txintr_pending = 0;
+#endif
+	tp->t_state &= ~TS_BUSY;
+	if (tp->t_state & TS_FLUSH)
+		tp->t_state &= ~TS_FLUSH;
+	else if (tp->t_line)
+		(*linesw[tp->t_line].l_start)(tp);
+	else
+		comstart(tp);
+}
+
+#ifdef COM_DETECT_LOST_TXINTR
+void
+comwatchdog(arg)
+	void *arg;
+{
+	struct com_softc *sc = arg;
+	int iobase = sc->sc_iobase;
+	int s;
+
+	if (sc->sc_txintr_pending &&
+	    time.tv_sec - sc->sc_transmit_time >= COM_TX_TIMEOUT &&
+	    (inb(iobase + com_lsr) & LSR_TXRDY)) {
+		s = spltty();
+		comtint(sc);
+		splx(s);
+		log(LOG_WARNING, "%s: lost tx interrupt\n", 
+			sc->sc_dev.dv_xname);
+	}
+	timeout(comwatchdog, sc, hz);
+}
+#endif
+
 int
 comintr(arg)
 	void *arg;
@@ -811,15 +878,7 @@
 					comeint(sc, code);
 			}
 		} else if (code == IIR_TXRDY) {
-			tp = sc->sc_tty;
-			tp->t_state &= ~TS_BUSY;
-			if (tp->t_state & TS_FLUSH)
-				tp->t_state &= ~TS_FLUSH;
-			else
-				if (tp->t_line)
-					(*linesw[tp->t_line].l_start)(tp);
-				else
-					comstart(tp);
+			comtint(sc);
 		} else if (code == IIR_MLSC) {
 			commint(sc);
 		} else {
----------------------------------------------------------------------------

P.S.
Sorry for my poor English.
--
soda@sra.co.jp		Software Research Associates, Inc., Japan
(Noriyuki Soda)		   software tools and technology group
>Audit-Trail:
>Unformatted: