Subject: kern/19011: Interrupt from serial device is sometimes lost
To: None <gnats-bugs@gnats.netbsd.org>
From: None <umezawa@iij.ad.jp>
List: netbsd-bugs
Date: 11/10/2002 23:28:33
>Number: 19011
>Category: kern
>Synopsis: Interrupt from serial device is sometimes lost
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Nov 10 23:29:00 PST 2002
>Closed-Date:
>Last-Modified:
>Originator: UMEZAWA Takeshi
>Release: 1.5.3
>Organization:
Internet Initiative Japan (IIJ)
>Environment:
NetBSD netbsdtest 1.5.3 NetBSD 1.5.3 (GENERIC) #34: Mon Jul 1 21:36:06 CEST 2002
he@hamster.urc.uninett.no:/usr/src/sys/arch/i386/compile/GENERIC i386
>Description:
On certain machine and certain condition, an interrupt from a serial device is lost.
Once lost, that serial device seems to be hung up. But if the kernel itself output a message to the serial console device (that is hung up), this situation is corrected and the device works normally.
>How-To-Repeat:
1. Boot with serial console.
2. Repeat plugging/unplugging serial cable some times.
3. You will find that serial console is hung up. If not, that machine does not cause this problem.
>Fix:
Apply following patch (against NetBSD 1.5.3).
If applied, comintr() is periodically called in order to recover lost interrupt(s). Recovery interval is COM_INTR_RECOVERY_INTERVAL second(s), and it is defiend as 1 (second).
Similar workaround is found in /usr/src/sys/dev/sio/sio.c of FreeBSD.
*** comvar.h- Mon Nov 11 15:26:02 2002
--- comvar.h Mon Nov 11 15:26:23 2002
***************
*** 125,130 ****
--- 125,132 ----
#if NRND > 0 && defined(RND_COM)
rndsource_element_t rnd_source;
#endif
+
+ struct callout sc_intr_recover_callout;
};
/* Macros to clear/set/test flags. */
*** com.c- Mon Nov 11 15:25:50 2002
--- com.c Mon Nov 11 15:26:23 2002
***************
*** 168,173 ****
--- 168,174 ----
integrate void com_stsoft __P((struct com_softc *, struct tty *));
integrate void com_schedrx __P((struct com_softc *));
void comdiag __P((void *));
+ void comintr_recover __P((void *));
extern struct cfdriver com_cd;
***************
*** 228,233 ****
--- 229,238 ----
#define BW BUS_SPACE_BARRIER_WRITE
#define COM_BARRIER(t, h, f) bus_space_barrier((t), (h), 0, COM_NPORTS, (f))
+ /* interval (in seconds) to recover lost interrupts */
+ #define COM_INTR_RECOVERY_INTERVAL 1
+
+
int
comspeed(speed, frequency)
long speed, frequency;
***************
*** 399,404 ****
--- 404,410 ----
#endif
callout_init(&sc->sc_diag_callout);
+ callout_init(&sc->sc_intr_recover_callout);
/* Disable interrupts before configuring the device. */
sc->sc_ier = 0;
***************
*** 556,561 ****
--- 562,570 ----
com_config(sc);
SET(sc->sc_hwflags, COM_HW_DEV_OK);
+
+ callout_reset(&sc->sc_intr_recover_callout,
+ hz*COM_INTR_RECOVERY_INTERVAL, comintr_recover, sc);
}
void
***************
*** 626,631 ****
--- 635,642 ----
struct com_softc *sc = (struct com_softc *)self;
int maj, mn;
+ callout_stop(&sc->sc_intr_recover_callout);
+
/* locate the major number */
for (maj = 0; maj < nchrdev; maj++)
if (cdevsw[maj].d_open == comopen)
***************
*** 2145,2150 ****
--- 2156,2173 ----
return (1);
}
+
+ void
+ comintr_recover(arg)
+ void * arg;
+ {
+ struct com_softc *sc = arg;
+
+ comintr(sc);
+ callout_reset(&sc->sc_intr_recover_callout,
+ hz*COM_INTR_RECOVERY_INTERVAL, comintr_recover, arg);
+ }
+
/*
* The following functions are polled getc and putc routines, shared
>Release-Note:
>Audit-Trail:
>Unformatted: