home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!sun-barr!cs.utexas.edu!zaphod.mps.ohio-state.edu!uwm.edu!bionet!ucselx!crash!fpm
- From: fpm@crash.cts.com (Frank Maclachlan)
- Newsgroups: comp.unix.bsd
- Subject: Bugs in DMA code (w/ patch)
- Summary: Bugs in DMA code fixed
- Keywords: DMA, patch
- Message-ID: <1992Aug18.142737.16819@crash>
- Date: 18 Aug 92 21:27:36 GMT
- Followup-To: comp.unix.bsd
- Organization: CTS Network Services (crash, ctsnet), El Cajon, CA
- Lines: 298
-
- I found a few problems in '/usr/src/sys.386bsd/i386/isa/isa.c'.
-
- At line 389 in isa_dmarangecheck(), the automatic variable priorpage
- is used without being initially set to 0. This causes the function
- to flag special handling for virtually all DMA transfer requests.
- Also, no check is made for DMA requests crossing DMA page boundaries
- (64k for DMA chans 0..3, 128k for DMA chans 4..7). This problem is
- masked by priorpage not being initialized - almost all DMA is done
- to/from safe 'bounce' buffers which don't cross DMA page boundaries
- and the data are block moved from/to the user's buffer.
-
- In line 359, nbytes is doubled by shifting it left 1 bit; it
- should instead be divided by 2 by shifting right 1 bit position.
- This occurs when any of the word mode DMA channels (4..7) is used.
-
- The following patch fixes the above problems and makes some cosmetic
- changes to isa_dmacascade() and isa_dmastart():
-
-
- *** isa.c.ORIG Tue Jul 14 12:25:24 1992
- --- isa.c Tue Aug 18 14:12:49 1992
- ***************
- *** 39,44 ****
- --- 39,50 ----
-
- /*
- * code to manage AT bus
- + *
- + * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
- + * Fixed uninitialized variable problem and added code to deal
- + * with DMA page boundaries in isa_dmarangecheck(). Fixed word
- + * mode DMA count compution and reorganized DMA setup code in
- + * isa_dmastart()
- */
-
- #include "param.h"
- ***************
- *** 58,63 ****
- --- 64,85 ----
- #include "i386/isa/ic/i8237.h"
- #include "i386/isa/ic/i8042.h"
-
- + /*
- + ** Register definitions for DMA controller 1 (channels 0..3):
- + */
- + #define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
- + #define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
- + #define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
- + #define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
- +
- + /*
- + ** Register definitions for DMA controller 2 (channels 4..7):
- + */
- + #define DMA2_CHN(c) (IO_DMA1 + 2*(2*(c))) /* addr reg for channel c */
- + #define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
- + #define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
- + #define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
- +
- int config_isadev(struct isa_device *, u_short *);
- #ifdef notyet
- struct rlist *isa_iomem;
- ***************
- *** 278,298 ****
- * external dma control by a board.
- */
- void isa_dmacascade(unsigned chan)
- ! { int modeport;
- !
- if (chan > 7)
- panic("isa_dmacascade: impossible request");
-
- /* set dma channel mode, and set dma channel mode */
- ! if ((chan & 4) == 0)
- ! modeport = IO_DMA1 + 0xb;
- ! else
- ! modeport = IO_DMA2 + 0x16;
- ! outb(modeport, DMA37MD_CASCADE | (chan & 3));
- ! if ((chan & 4) == 0)
- ! outb(modeport - 1, chan & 3);
- ! else
- ! outb(modeport - 2, chan & 3);
- }
-
- /*
- --- 300,317 ----
- * external dma control by a board.
- */
- void isa_dmacascade(unsigned chan)
- ! {
- if (chan > 7)
- panic("isa_dmacascade: impossible request");
-
- /* set dma channel mode, and set dma channel mode */
- ! if ((chan & 4) == 0) {
- ! outb(DMA1_MODE, DMA37MD_CASCADE | chan);
- ! outb(DMA1_SMSK, chan);
- ! } else {
- ! outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
- ! outb(DMA2_SMSK, chan & 3);
- ! }
- }
-
- /*
- ***************
- *** 301,313 ****
- */
- void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
- { vm_offset_t phys;
- ! int modeport, waport, mskport;
- caddr_t newaddr;
-
- ! if (chan > 7 || nbytes > (1<<16))
- panic("isa_dmastart: impossible request");
-
- ! if (isa_dmarangecheck(addr, nbytes)) {
- if (dma_bounce[chan] == 0)
- dma_bounce[chan] =
- /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
- --- 320,334 ----
- */
- void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
- { vm_offset_t phys;
- ! int waport;
- caddr_t newaddr;
-
- ! if ( chan > 7
- ! || (chan < 4 && nbytes > (1<<16))
- ! || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
- panic("isa_dmastart: impossible request");
-
- ! if (isa_dmarangecheck(addr, nbytes, chan)) {
- if (dma_bounce[chan] == 0)
- dma_bounce[chan] =
- /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
- ***************
- *** 325,372 ****
- /* translate to physical */
- phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
-
- - /* set dma channel mode, and reset address ff */
- - if ((chan & 4) == 0)
- - modeport = IO_DMA1 + 0xb;
- - else
- - modeport = IO_DMA2 + 0x16;
- - if (flags & B_READ)
- - outb(modeport, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
- - else
- - outb(modeport, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
- - if ((chan & 4) == 0)
- - outb(modeport + 1, 0);
- - else
- - outb(modeport + 2, 0);
- -
- - /* send start address */
- if ((chan & 4) == 0) {
- ! waport = IO_DMA1 + (chan<<1);
- outb(waport, phys);
- outb(waport, phys>>8);
- ! } else {
- ! waport = IO_DMA2 + ((chan - 4)<<2);
- ! outb(waport, phys>>1);
- ! outb(waport, phys>>9);
- ! }
- ! outb(dmapageport[chan], phys>>16);
-
- ! /* send count */
- ! if ((chan & 4) == 0) {
- outb(waport + 1, --nbytes);
- outb(waport + 1, nbytes>>8);
- } else {
- ! nbytes <<= 1;
- outb(waport + 2, --nbytes);
- outb(waport + 2, nbytes>>8);
- - }
-
- ! /* unmask channel */
- ! if ((chan & 4) == 0)
- ! mskport = IO_DMA1 + 0x0a;
- ! else
- ! mskport = IO_DMA2 + 0x14;
- ! outb(mskport, chan & 3);
- }
-
- void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
- --- 346,401 ----
- /* translate to physical */
- phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
-
- if ((chan & 4) == 0) {
- ! /*
- ! * Program one of DMA channels 0..3. These are
- ! * byte mode channels.
- ! */
- ! /* set dma channel mode, and reset address ff */
- ! if (flags & B_READ)
- ! outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
- ! else
- ! outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
- ! outb(DMA1_FFC, 0);
- !
- ! /* send start address */
- ! waport = DMA1_CHN(chan);
- outb(waport, phys);
- outb(waport, phys>>8);
- ! outb(dmapageport[chan], phys>>16);
-
- ! /* send count */
- outb(waport + 1, --nbytes);
- outb(waport + 1, nbytes>>8);
- +
- + /* unmask channel */
- + outb(DMA1_SMSK, chan);
- } else {
- ! /*
- ! * Program one of DMA channels 4..7. These are
- ! * word mode channels.
- ! */
- ! /* set dma channel mode, and reset address ff */
- ! if (flags & B_READ)
- ! outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
- ! else
- ! outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
- ! outb(DMA2_FFC, 0);
- !
- ! /* send start address */
- ! waport = DMA2_CHN(chan - 4);
- ! outb(waport, phys>>1);
- ! outb(waport, phys>>9);
- ! outb(dmapageport[chan], phys>>16);
- !
- ! /* send count */
- ! nbytes >>= 1;
- outb(waport + 2, --nbytes);
- outb(waport + 2, nbytes>>8);
-
- ! /* unmask channel */
- ! outb(DMA2_SMSK, chan & 3);
- ! }
- }
-
- void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
- ***************
- *** 382,393 ****
-
- /*
- * Check for problems with the address range of a DMA transfer
- ! * (non-contiguous physical pages, outside of bus address space).
- * Return true if special handling needed.
- */
-
- ! isa_dmarangecheck(caddr_t va, unsigned length) {
- ! vm_offset_t phys, priorpage, endva;
-
- endva = (vm_offset_t)round_page(va + length);
- for (; va < (caddr_t) endva ; va += NBPG) {
- --- 411,424 ----
-
- /*
- * Check for problems with the address range of a DMA transfer
- ! * (non-contiguous physical pages, outside of bus address space,
- ! * crossing DMA page boundaries).
- * Return true if special handling needed.
- */
-
- ! isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
- ! vm_offset_t phys, priorpage = 0, endva;
- ! u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
-
- endva = (vm_offset_t)round_page(va + length);
- for (; va < (caddr_t) endva ; va += NBPG) {
- ***************
- *** 397,404 ****
- panic("isa_dmacheck: no physical page present");
- if (phys > ISARAM_END)
- return (1);
- ! if (priorpage && priorpage + NBPG != phys)
- ! return (1);
- priorpage = phys;
- }
- return (0);
- --- 428,440 ----
- panic("isa_dmacheck: no physical page present");
- if (phys > ISARAM_END)
- return (1);
- ! if (priorpage) {
- ! if (priorpage + NBPG != phys)
- ! return (1);
- ! /* check if crossing a DMA page boundary */
- ! if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
- ! return (1);
- ! }
- priorpage = phys;
- }
- return (0);
- --
- UUCP: {hplabs!hp-sdd ucsd nosc}!crash!fpm
- ARPA: crash!fpm@nosc.mil
- INET: fpm@crash.cts.com
-