muller@sdcc7.ucsd.EDU (Keith Muller) (08/02/86)
Since a lot of people seem to have problems with emulex dmf's, enclosed is diffs from the june 86 release of 4.3 for a dmf driver that works with emulex cs11 and cs21's. NOTE: make sure you get prom upgrades from emulex if you have an OLD board. The old microcode will wedge your system while doing dma output (or all 8 ports on a dmf will stop working). If you have questions comments etc pleas contact me. Keith muller University of California, San Diego muller@sdcsvax.ucsd.edu muller@nprdc.arpa *** vaxuba/dmf.c Thu Jun 5 01:07:44 1986 --- local/dmf.c Thu Jun 19 10:54:55 1986 *************** *** 68,75 **** struct uba_driver dmfdriver = { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo }; ! int dmf_timeout = 10; /* silo timeout, in ms */ ! int dmf_mindma = 4; /* don't dma below this point */ /* * Local variables for the driver --- 68,75 ---- struct uba_driver dmfdriver = { dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo }; ! int dmf_timeout = 4; /* silo timeout, in ms */ ! int dmf_mindma = 3; /* don't dma below this point */ /* * Local variables for the driver *************** *** 122,129 **** int dmf_ubinfo[NUBA]; /* info about allocated unibus map */ int cbase[NUBA]; /* base address in unibus map */ #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) - char dmf_dma[NDMF*8]; /* * Routine for configuration to set dmf interrupt. */ --- 122,137 ---- int dmf_ubinfo[NUBA]; /* info about allocated unibus map */ int cbase[NUBA]; /* base address in unibus map */ #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) + struct dmfa_softc { + int dmfa_state; + int dmfa_count; + } dmfa_softc[NDMF * 8]; + + #define ST_TXOFF (0x01) /* tx turned off */ + #define ST_DMA (0x02) /* tx doing dma output */ + #define ST_INBUSY (0x04) /* tx off while in TS_BUSY */ + /* * Routine for configuration to set dmf interrupt. */ *************** *** 275,280 **** --- 283,289 ---- #ifndef PORTSELECTOR } #endif PORTSELECTOR + dmfa_softc[unit].dmfa_state = 0; dmfparam(unit); } /* *************** *** 566,572 **** register struct dmfdevice *addr; register struct uba_device *ui; register int t; ! short cntr; ui = dmfinfo[dmf]; addr = (struct dmfdevice *)ui->ui_addr; --- 575,582 ---- register struct dmfdevice *addr; register struct uba_device *ui; register int t; ! struct dmfa_softc *sc0 = &dmfa_softc[unit0]; ! register struct dmfa_softc *sc; ui = dmfinfo[dmf]; addr = (struct dmfdevice *)ui->ui_addr; *************** *** 573,594 **** while ((t = addr->dmfcsr) & DMF_TI) { if (t & DMF_NXM) /* SHOULD RESTART OR SOMETHING... */ ! printf("dmf%d: NXM line %d\n", dmf, t >> 8 & 7); t = t >> 8 & 7; tp = tp0 + t; ! tp->t_state &= ~TS_BUSY; ! if (tp->t_state&TS_FLUSH) tp->t_state &= ~TS_FLUSH; ! else if (dmf_dma[unit0 + t]) { ! /* ! * Do arithmetic in a short to make up ! * for lost 16&17 bits. ! */ ! addr->dmfcsr = DMFIR_TBA | DMF_IE | t; ! cntr = addr->dmftba - ! UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); ! ndflush(&tp->t_outq, (int)cntr); ! } if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); else --- 583,600 ---- while ((t = addr->dmfcsr) & DMF_TI) { if (t & DMF_NXM) /* SHOULD RESTART OR SOMETHING... */ ! log(LOG_WARNING, "dmf%d: NXM line %d\n", dmf, t >> 8 & 7); t = t >> 8 & 7; tp = tp0 + t; ! sc = sc0 + t; ! if (tp->t_state&TS_FLUSH) { tp->t_state &= ~TS_FLUSH; ! addr->dmfcsr = DMF_IE | DMFIR_LCR | t; ! addr->dmflctms = addr->dmflctms | DMF_TE; ! } else if (sc->dmfa_state & ST_DMA) ! ndflush(&tp->t_outq, sc->dmfa_count); ! sc->dmfa_state = 0; ! tp->t_state &= ~TS_BUSY; if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); else *************** *** 604,614 **** --- 610,622 ---- { register struct dmfdevice *addr; register int unit, nch; + register struct dmfa_softc *sc; int s; register int dmf; unit = minor(tp->t_dev); dmf = unit >> 3; + sc = &dmfa_softc[unit]; unit &= 07; addr = (struct dmfdevice *)tp->t_addr; *************** *** 623,637 **** if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) goto out; /* ! * If there are still characters in the silo, ! * just reenable the transmitter. */ ! addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; ! if (addr->dmftsc) { addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; addr->dmflctms = addr->dmflctms | DMF_TE; - tp->t_state |= TS_BUSY; - goto out; } /* * If there are sleepers, and output has drained below low --- 631,651 ---- if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) goto out; /* ! * If tx off, turn on. If tx was turned off while TS_BUSY (before ! * the interrupt), reset TS_BUSY and wait for interrupt. Otherwise ! * turn on tx and start a new transmission. */ ! if (sc->dmfa_state & ST_TXOFF) { ! sc->dmfa_state &= ~ST_TXOFF; ! if (sc->dmfa_state & ST_INBUSY) { ! sc->dmfa_state &= ~ST_INBUSY; ! tp->t_state |= TS_BUSY; ! addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; ! addr->dmflctms = addr->dmflctms | DMF_TE; ! goto out; ! } addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; addr->dmflctms = addr->dmflctms | DMF_TE; } /* * If there are sleepers, and output has drained below low *************** *** 673,699 **** if (nch >= dmf_mindma) { register car; ! dmf_dma[minor(tp->t_dev)] = 1; addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; addr->dmflctms = addr->dmflctms | DMF_TE; car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; addr->dmftba = car; addr->dmftcc = ((car >> 2) & 0xc000) | nch; - tp->t_state |= TS_BUSY; } else if (nch) { register char *cp = tp->t_outq.c_cf; register int i; ! dmf_dma[minor(tp->t_dev)] = 0; nch = MIN(nch, DMF_SILOCNT); addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; addr->dmflctms = addr->dmflctms | DMF_TE; addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; for (i = 0; i < nch; i++) addr->dmftbuf = *cp++; ndflush(&tp->t_outq, nch); - tp->t_state |= TS_BUSY; } out: splx(s); --- 687,714 ---- if (nch >= dmf_mindma) { register car; ! tp->t_state |= TS_BUSY; addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; addr->dmflctms = addr->dmflctms | DMF_TE; car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum); + sc->dmfa_count = nch; + sc->dmfa_state |= ST_DMA; addr->dmfcsr = DMF_IE | DMFIR_TBA | unit; addr->dmftba = car; addr->dmftcc = ((car >> 2) & 0xc000) | nch; } else if (nch) { register char *cp = tp->t_outq.c_cf; register int i; ! tp->t_state |= TS_BUSY; nch = MIN(nch, DMF_SILOCNT); addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; addr->dmflctms = addr->dmflctms | DMF_TE; + sc->dmfa_state &= ~ST_DMA; addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; for (i = 0; i < nch; i++) addr->dmftbuf = *cp++; ndflush(&tp->t_outq, nch); } out: splx(s); *************** *** 707,713 **** register struct tty *tp; { register struct dmfdevice *addr; ! register unit = minor(tp->t_dev) & 7; int s; addr = (struct dmfdevice *)tp->t_addr; --- 722,729 ---- register struct tty *tp; { register struct dmfdevice *addr; ! register unit = minor(tp->t_dev); ! register struct dmfa_softc *sc = &dmfa_softc[unit]; int s; addr = (struct dmfdevice *)tp->t_addr; *************** *** 715,745 **** * Block input/output interrupts while messing with state. */ s = spltty(); if (flag) { ! addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit; ! if (addr->dmftsc) { ! /* ! * Flush regardless of whether we're transmitting ! * (TS_BUSY), if the silo contains untransmitted ! * characters. ! */ ! addr->dmfcsr = DMFIR_LCR | unit | DMF_IE; ! addr->dmflctms = addr->dmflctms | DMF_TE | DMF_FLUSH; ! /* this will interrupt so let dmfxint handle the rest */ ! tp->t_state |= TS_FLUSH|TS_BUSY; ! } ! } else { ! if (tp->t_state & TS_BUSY) { ! /* ! * Stop transmission by disabling ! * the transmitter. We'll pick up where we ! * left off by reenabling in dmfstart. ! */ ! addr->dmfcsr = DMFIR_LCR | unit | DMF_IE; ! addr->dmflctms = addr->dmflctms &~ DMF_TE; ! /* no interrupt here */ ! tp->t_state &= ~TS_BUSY; ! } } splx(s); } --- 731,747 ---- * Block input/output interrupts while messing with state. */ s = spltty(); + addr->dmfcsr = DMFIR_LCR | (unit & 07) | DMF_IE; + addr->dmflctms = addr->dmflctms &~ DMF_TE; + sc->dmfa_state |= ST_TXOFF; if (flag) { ! tp->t_state |= TS_FLUSH|TS_BUSY; ! addr->dmflctms = addr->dmflctms | DMF_FLUSH; ! /* this will interrupt so let dmfxint handle the rest */ ! } else if (tp->t_state & TS_BUSY) { ! sc->dmfa_state |= ST_INBUSY; ! tp->t_state &= ~TS_BUSY; ! /* no interrupt here reenable in dmfstart */ } splx(s); } *************** *** 819,824 **** --- 821,827 ---- addr->dmfrsp = dmf_timeout; unit = dmf * 8; for (i = 0; i < 8; i++) { + dmfa_softc[unit].dmfa_state = 0; tp = &dmf_tty[unit]; if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { dmfparam(unit);
mel@rocky2.UUCP (Melvin Ferentz) (08/08/86)
While waiting for the updated proms from Emulex, the following one line
hack will work.
dmf.c
72c72
< int dmf_mindma = 4; /* don't dma below this point */
---
> int dmf_mindma = 20000; /* HACK FOR NO DMA don't dma below this point */
The driver then works like the 4.2bsd driver, i.e. no dma.
mel@rockefeller.arpa
@rockvax.bitnet
@rocky2.uucp