Subject: kern/9029: elinkxl [ex] Ethernet driver appears to fail to acknowledge an interrupt
To: None <>
From: None <>
List: netbsd-bugs
Date: 12/19/1999 11:15:39
>Number:         9029
>Category:       kern
>Synopsis:       The elinkxl driver appears to not acknowedge an interrupt at times.
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Dec 19 11:15:00 1999
>Originator:     Michael L. Hitch
	Montana State University
>Release:        <NetBSD-current source date> December 4, 1999
System: NetBSD 1.4P NetBSD 1.4P (PC164) #991204-7: Sat Dec 18 10:47:03 MST 1999 alpha

	On my PC164, the 3Com 3c905B and 3c980 Ethernet cards would stop working after
	relatively heavy network traffic.  This would usually happen when I was
	running xscreensaver on the PC164 and displaying on my Amiga.  After finally
	noticing a "stray interrupt" log message, I found that the alpha interrupt
	handler was disabling the interrupt when no driver handled that interrupt.
	Further investigation showed that the Ethernet cards appeared to be
	generating an interrupt, and only the S_INTR_LATCH was set in the status
	register (which was not considered an interrupt condition).
	Install a 3Com 3c980 or 3c905B Ethernet card in an Alpha PC164, run lots
	of network traffic over that adapter for a while, and wait for the driver
	to stop functioning because the interrupt gets disabled.	
	Possibly include the S_INTR_LATCH in interrupt status bits, since that
	status bit appears to be abled to be cleared by the software.

	The following patch separately checks for the S_INTR_LATCH status bit being
	set when no other interrupt status was present, displays a console message,
	clears the S_INTR_LATCH status, and indicates the driver handled the interrupt.
	The interfaces now periodically report this message, and continue to function.

--- elinkxl.c.orig	Sun Dec 19 11:51:06 1999
+++ elinkxl.c	Sun Dec 19 12:09:38 1999
@@ -1109,8 +1116,15 @@
 	for (;;) {
 		stat = bus_space_read_2(iot, ioh, ELINK_STATUS);
-		if (!(stat & S_MASK))
+		if (!(stat & S_MASK)) {
+			if (ret == 0 && (stat & S_INTR_LATCH) != 0) {
+				printf("%s: %x intr_latch set, clearing\n",
+				    sc->sc_dev.dv_xname, stat);
+				bus_space_write_2(iot, ioh, ELINK_COMMAND, C_INTR_LATCH);
+				ret = 1;
+			}
+		}
 		 * Acknowledge interrupts.