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: