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.]