Path: utzoo!utgpu!water!watmath!clyde!rutgers!sri-spam!ames!pasteur!ucbvax!decvax!decwrl!sun!pitstop!sundc!seismo!uunet!mcvax!inria!ehrlich From: ehrlich@inria.UUCP (Robert Ehrlich) Newsgroups: comp.unix.wizards Subject: Re: 4.3 + dmf + Emulex >= Problems (Repost) Summary: I just fell on the problem and I think I solved it. Keywords: dmf driver problem Message-ID: <608@inria.UUCP> Date: 24 Jan 88 13:43:06 GMT References: <4653@pollux.UUCP> Organization: INRIA, Rocquencourt. France Lines: 71 It seems that the cause of the character loss is an improper emulation on the Emulex board of the "dmftba" register. This register is used by the driver for computing the number of characters which must be taken off from the output queue, as they have just been transmitted by the board. The count is computed as the difference between the value of the dmftba register and the value which was loaded into it at the initiation of the dma output. It seems that in some cases the dmftba register in the Emulex board is incremented once more that normal. A simple fix is to keep in software the real count at transfert initiation and to use it at interrupt instead of the wrong computed value. I used the flag dmf_dma for that purpose, since the count cannot exceed 60 (size of a cblock), instead of having a binary values (0 or 1) indicating if dma was or not used for the last operation, it now contains the character count of the last dma operation, zero if it was not a dma operation. After the fix I have run /usr/games/worms which is a good test for character loss and all seems to work fine. For people who don't have a source licence there is a way to bypass the problem: seting (using adb /vmunix /dev/kmem) the variable dmf_mindma in the kernel to the value 64 (or more). Since you will never have 64 contiguous character in the ouput queue, the diver will never use dma. But in this case you will loose the benefit of the dma feature of your board. Here follows a context diff of the original driver and the modified one *************** *** 579,592 **** 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) --- 579,585 ---- tp->t_state &= ~TS_BUSY; if (tp->t_state&TS_FLUSH) tp->t_state &= ~TS_FLUSH; ! else if (cntr= (unsigned)dmf_dma[unit0 + t]) { ndflush(&tp->t_outq, (int)cntr); } if (tp->t_line) *************** *** 673,679 **** 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); --- 666,672 ---- if (nch >= dmf_mindma) { register car; ! dmf_dma[minor(tp->t_dev)] = nch; addr->dmfcsr = DMF_IE | DMFIR_LCR | unit; addr->dmflctms = addr->dmflctms | DMF_TE; car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);