*BSD News Article 22435


Return to BSD News archive

Xref: sserve comp.os.386bsd.development:1311 comp.os.386bsd.bugs:1604 comp.os.386bsd.questions:5971
Newsgroups: comp.os.386bsd.development,comp.os.386bsd.bugs,comp.os.386bsd.questions
Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!agate!howland.reston.ans.net!pipex!sunic!news.chalmers.se!cs.chalmers.se!augustss
From: augustss@cs.chalmers.se (Lennart Augustsson)
Subject: NetBSD 0.9 silo overflow fix
Message-ID: <1993Oct15.122522.8764@cs.chalmers.se>
Sender: news@cs.chalmers.se (News Account)
Organization: Dept. of CS, Chalmers, Sweden
Date: Fri, 15 Oct 1993 12:25:22 GMT
Lines: 406


Silo overflow fix
=================

Here's a fix for those of you that don't have UARTs with fifo.
It uses Bruce Evans wonderful fast interrupts to be able to
service the interrupts at once.  It's not as elaborate
as the sio driver but it works for me (I've transferred a
total of over 50M with 38400 SLIP without a single overrun error).

The patch is for NetBSD-current, but it should work for
NetBSD 0.9 as well.


Do the following:

1) Apply the patch below (patch < thisfile).  It patches
/sys/arch/i386/isa/com.c, /sys/arch/i386/isa/icu.s, and
/usr/src/usr.sbin/config/mkglue.c.

2) Do a 'make' and 'make install' in /usr/src/usr.sbin/config
to get a new config.

3) Edit your system configuration file.  Add the line
	option	"NSILO=256"
	(or maybe some other number, I haven't tested much)
Also change comintr to fast_comintr.

4) Run config and do a make in your compile directory.

5) Install the new system!

**NOTE**  Do not give the NSILO option in case your UARTs
have a fifo.  I'm pretty sure that will be a disaster.

If you don't include the NSILO option and use comintr instead of
fast_comintr you will get the old com driver back.

	-- Lennart Augustsson


*** /sys/arch/i386/isa/com.c.orig	Wed Sep 29 10:22:57 1993
--- /sys/arch/i386/isa/com.c	Fri Oct 15 12:49:20 1993
***************
*** 81,86 ****
--- 81,100 ----
  short com_addr[NCOM];
  struct	tty *com_tty[NCOM];
  
+ #ifdef NSILO
+ 
+ struct silo {
+ 	unsigned int inp, outp;		/* indicies into the arrays below, counted mod NSILO. inp==out means empty, inp+1==outp means full */
+ 	unsigned int pendbit;		/* interrupt bit to set */
+ 	char overrun;			/* emulated siloo overrun */
+ 	int txrdy;			/* use flag for TXRDY since we don't want to loose it */
+ 	unsigned char iir[NSILO];	/* IIR reg */
+ 	unsigned char data[NSILO];	/* DATA reg */
+ 	unsigned char status[NSILO];	/* LSR or MSR when applicable */
+ } silo[NCOM];
+ 
+ #endif
+ 
  struct speedtab comspeedtab[] = {
  	0,	0,
  	50,	COMBRD(50),
***************
*** 138,143 ****
--- 152,165 ----
  	if (unit == comconsole)
  		DELAY(1000);
  	com_addr[unit] = port;
+ #ifdef NSILO
+ 	silo[unit].inp = 0;
+ 	silo[unit].outp = 0;
+ 	silo[unit].pendbit = isdp->id_irq;
+ 	silo[unit].overrun = 0;
+ 	silo[unit].txrdy = 0;
+ 	printf("com%d: emulated fifo\n", unit);
+ #endif
  	com_active |= 1 << unit;
  	comsoftCAR |= 1 << unit;	/* XXX */
  
***************
*** 286,304 ****
  	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
  }
   
  comintr(unit)
  	register int unit;
  {
  	register com;
  	register u_char code;
  	register struct tty *tp;
  
- 	unit;
  	com = com_addr[unit];
  	while (1) {
! 		code = inb(com+com_iir);
  		switch (code & IIR_IMASK) {
  		case IIR_NOPEND:
  			return (1);
  		case IIR_RXTOUT:
  		case IIR_RXRDY:
--- 308,447 ----
  	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
  }
   
+ #ifdef NSILO
+ /*
+  * When the UART interrupts we enter here at once, not matter what.
+  * This means data structures must be manipulated carefully, so
+  * we only use the silo struct.  All execution here is with
+  * interrupts turned off, so make it quick!
+  */
+ fast_comintr(unit)
+ 	int unit;
+ {
+ 	int com;
+ 	unsigned int iir;
+ 	unsigned int inp, inpn;
+ 	struct silo *s;
+ 	extern int ipending;
+ 
+ 	com = com_addr[unit];
+ 	s = &silo[unit];
+ 	ipending |= s->pendbit;		/* schedule the soft intr */
+ 	while(1) {
+ 		inp = s->inp;
+ 		iir = inb(com+com_iir);	/* get cause */
+ 		switch(iir & IIR_IMASK) {
+ 		case IIR_NOPEND:
+ 			return;
+ 		case IIR_RLS:
+ 			s->status[inp] = inb(com+com_lsr);
+ 			/* fall into */
+ 		case IIR_RXTOUT:
+ 		case IIR_RXRDY:
+ 			s->data[inp] = inb(com+com_data);
+ 			break;
+ 		case IIR_TXRDY:
+ 			s->txrdy++;
+ 			break;
+ 		default:
+ 			if (iir & IIR_NOPEND)
+ 				return;
+ 			/* fall through */
+ 		case IIR_MLSC:
+ 			s->status[inp] = inb(com+com_data);
+ 			break;
+ 		}
+ 		/* Increment input pointer if there is room. */
+ 		s->iir[inp] = iir;
+ 		inpn = (inp + 1) % NSILO;
+ 		if (inpn == s->outp)
+ 			s->overrun++;
+ 		else
+ 			s->inp = inpn;
+ 	}
+ }
+ 
+ /*
+  * This routine is run as soon as any soft intr has been scheduled
+  * and it can be serviced.  Scan for an UART with something to do.
+  */
+ softsio1()
+ {
+ 	int i;
+ 	struct silo *s;
+ 
+ 	for(i = 0; i < NCOM; i++) {
+ 		s = &silo[i];
+ 		if (s->inp != s->outp)
+ 			comintr(i);
+ 	}
+ }
+ 
+ static int data, status;
+ 
+ /* Macros to access simulated registers */
+ #define GETDATA data
+ #define GETLSR status
+ #define GETMSR status
+ #define RETSPL splx(oldmask)
+ 
+ #else
+ 
+ #define GETDATA inb(com+com_data)
+ #define GETLSR inb(com+com_lsr)
+ #define GETMSR inb(com+com_msr)
+ #define RETSPL
+ 
+ #endif
+ 
+ /* Soft interrupt routine */
  comintr(unit)
  	register int unit;
  {
  	register com;
  	register u_char code;
  	register struct tty *tp;
+ #ifdef NSILO
+ 	unsigned int outp;
+ 	int oldmask;
+ 	struct silo *s = &silo[unit];
+ extern int ipending,cpl,imen;
+ 
+ 	oldmask = spltty();
+ 	if (s->overrun) {
+ 		printf("com%d: emulated silo full\n", unit);
+ 		s->overrun = 0;
+ 	}
+ 
+ #endif
  
  	com = com_addr[unit];
  	while (1) {
! #ifdef NSILO
! 		/*
! 		 * You might think that we need to turn off interrupts here,
! 		 * but the silo has been design to make this unnecessary.
! 		 */
! 		if (s->txrdy > 0) {
! 			s->txrdy--;
! 			code = IIR_TXRDY;
! 		} else {
! 		        outp = s->outp;
! 			if (outp == s->inp) {		/* empty */
! 				RETSPL;
! 				return 1;
! 			}
! 			code = s->iir[outp];
! 			data = s->data[outp];
! 			status = s->status[outp];
! 			s->outp = (outp + 1) % NSILO; /* update outp when we've fetched the relevant data */
! 		}
! #else
! 	        code = GETDATA;
! #endif
  		switch (code & IIR_IMASK) {
  		case IIR_NOPEND:
+ 			RETSPL;
  			return (1);
  		case IIR_RXTOUT:
  		case IIR_RXRDY:
***************
*** 308,314 ****
   */
  #ifdef KGDB
  #define	RCVBYTE() \
! 			code = inb(com+com_data); \
  			if ((tp->t_state & TS_ISOPEN) == 0) { \
  				if (kgdb_dev == makedev(commajor, unit) && \
  				    code == FRAME_END) \
--- 451,457 ----
   */
  #ifdef KGDB
  #define	RCVBYTE() \
! 			code = GETDATA; \
  			if ((tp->t_state & TS_ISOPEN) == 0) { \
  				if (kgdb_dev == makedev(commajor, unit) && \
  				    code == FRAME_END) \
***************
*** 317,323 ****
  				(*linesw[tp->t_line].l_rint)(code, tp)
  #else
  #define	RCVBYTE() \
! 			code = inb(com+com_data); \
  			if (tp->t_state & TS_ISOPEN) \
  				(*linesw[tp->t_line].l_rint)(code, tp)
  #endif
--- 460,466 ----
  				(*linesw[tp->t_line].l_rint)(code, tp)
  #else
  #define	RCVBYTE() \
! 			code = GETDATA; \
  			if (tp->t_state & TS_ISOPEN) \
  				(*linesw[tp->t_line].l_rint)(code, tp)
  #endif
***************
*** 341,351 ****
  				comstart(tp);
  			break;
  		case IIR_RLS:
! 			comeint(unit, inb(com+com_lsr), com);
  			break;
  		default:
! 			if (code & IIR_NOPEND)
  				return (1);
  			log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
  			    unit, code);
  			/* fall through */
--- 484,496 ----
  				comstart(tp);
  			break;
  		case IIR_RLS:
! 			comeint(unit, GETLSR, com);
  			break;
  		default:
! 			if (code & IIR_NOPEND) {
! 				RETSPL;
  				return (1);
+ 			}
  			log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
  			    unit, code);
  			/* fall through */
***************
*** 364,370 ****
  	register int c;
  
  	tp = com_tty[unit];
! 	c = inb(com+com_data);
  	if ((tp->t_state & TS_ISOPEN) == 0) {
  #ifdef KGDB
  		/* we don't care about parity errors */
--- 509,515 ----
  	register int c;
  
  	tp = com_tty[unit];
! 	c = GETDATA;
  	if ((tp->t_state & TS_ISOPEN) == 0) {
  #ifdef KGDB
  		/* we don't care about parity errors */
***************
*** 393,399 ****
  	register int stat;
  
  	tp = com_tty[unit];
! 	stat = inb(com+com_msr);
  	if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
  		if (stat & MSR_DCD)
  			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
--- 538,544 ----
  	register int stat;
  
  	tp = com_tty[unit];
! 	stat = GETMSR;
  	if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
  		if (stat & MSR_DCD)
  			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
***************
*** 755,757 ****
--- 900,903 ----
  }
  
  #endif
+ 
*** /sys/arch/i386/isa/icu.s.orig	Fri Jul 16 11:12:02 1993
--- /sys/arch/i386/isa/icu.s	Thu Oct 14 23:45:34 1993
***************
*** 123,129 ****
   * XXX - must be some fastintr, need to register those too.
   */
  INTRLOCAL(noresume):
! #if NSIO > 0
  	call    _softsio1
  #endif
  INTRLOCAL(unpend_v_next):
--- 123,129 ----
   * XXX - must be some fastintr, need to register those too.
   */
  INTRLOCAL(noresume):
! #if NSIO > 0 || defined(NSILO)
  	call    _softsio1
  #endif
  INTRLOCAL(unpend_v_next):
***************
*** 338,344 ****
   * XXX - must be some fastintr, need to register those too.
   */
  INTRLOCAL(noresumeV):
! #if NSIO > 0
  	call    _softsio1
  #endif
  INTRLOCAL(unpend_V_next):
--- 338,344 ----
   * XXX - must be some fastintr, need to register those too.
   */
  INTRLOCAL(noresumeV):
! #if NSIO > 0 || defined(NSILO)
  	call    _softsio1
  #endif
  INTRLOCAL(unpend_V_next):
*** /usr/src/usr.sbin/config/mkglue.c.orig	Wed Aug 25 13:06:55 1993
--- /usr/src/usr.sbin/config/mkglue.c	Thu Oct 14 23:45:40 1993
***************
*** 386,392 ****
  	int offset;
  {
  	fprintf(fp, "\tBUILD_%sVECTOR(%s%d, %d,%d,%d",
! 		strcmp(dp->d_name, "sio") == 0 ? "FAST_" : "",
  		dp->d_name, dp->d_unit, dp->d_unit, dp->d_irq, offset);
  	if (eq(dp->d_mask, "null"))
  		fprintf(fp, ", _%s%dmask,", dp->d_name, dp->d_unit);
--- 386,392 ----
  	int offset;
  {
  	fprintf(fp, "\tBUILD_%sVECTOR(%s%d, %d,%d,%d",
! 		strcmp(dp->d_name, "sio") == 0 || strncmp(id->id, "fast_", 5) == 0 ? "FAST_" : "",
  		dp->d_name, dp->d_unit, dp->d_unit, dp->d_irq, offset);
  	if (eq(dp->d_mask, "null"))
  		fprintf(fp, ", _%s%dmask,", dp->d_name, dp->d_unit);
-- 

	-- Lennart Augustsson
[This signature is intentionally left blank.]