diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-11-28 16:15:48 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-11-28 16:15:48 +0000 |
commit | e8819b77bfb041f813ffbf6e8c1ad7f334adc333 (patch) | |
tree | 4588a1939101fc6073ad7467113c123c8b5bb195 /sys/dev/isa/isadma.c | |
parent | c51a554db7b34fa09912603268d0a4464d346076 (diff) |
i386 isa bounce buffers by hannken@eis.cs.tu-bs.de
ultra14f does not bounce properly yet.
Diffstat (limited to 'sys/dev/isa/isadma.c')
-rw-r--r-- | sys/dev/isa/isadma.c | 191 |
1 files changed, 67 insertions, 124 deletions
diff --git a/sys/dev/isa/isadma.c b/sys/dev/isa/isadma.c index bcb72cc085b..cb353a57049 100644 --- a/sys/dev/isa/isadma.c +++ b/sys/dev/isa/isadma.c @@ -16,28 +16,31 @@ #include <dev/isa/isadmavar.h> #include <dev/isa/isadmareg.h> -/* region of physical memory known to be contiguous */ -vm_offset_t isaphysmem; -static caddr_t dma_bounce[8]; /* XXX */ -static char bounced[8]; /* XXX */ -#define MAXDMASZ 512 /* XXX */ +struct dma_info { + int flags; + caddr_t addr; + vm_size_t nbytes; + struct isadma_seg phys[1]; +}; + +static struct dma_info dma_info[8]; /* high byte of address is stored in this port for i-th dma channel */ static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; /* - * isa_dmacascade(): program 8237 DMA controller channel to accept + * isadma_cascade(): program 8237 DMA controller channel to accept * external dma control by a board. */ void -isa_dmacascade(chan) +isadma_cascade(chan) int chan; { #ifdef DIAGNOSTIC if (chan < 0 || chan > 7) - panic("isa_dmacascade: impossible request"); + panic("isadma_cascade: impossible request"); #endif /* set dma channel mode, and set dma channel mode */ @@ -51,43 +54,47 @@ isa_dmacascade(chan) } /* - * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment + * isadma_start(): program 8237 DMA controller channel, avoid page alignment * problems by using a bounce buffer. */ void -isa_dmastart(flags, addr, nbytes, chan) - int flags; +isadma_start(addr, nbytes, chan, flags) caddr_t addr; vm_size_t nbytes; int chan; + int flags; { - vm_offset_t phys; + struct dma_info *di; int waport; - caddr_t newaddr; + int mflags; + vm_size_t size; #ifdef DIAGNOSTIC if (chan < 0 || chan > 7 || + ((flags & ISADMA_START_READ) == 0) == ((flags & ISADMA_START_WRITE) == 0) || ((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) : (nbytes >= (1<<16)))) - panic("isa_dmastart: impossible request"); + panic("isadma_start: impossible request"); #endif - if (isa_dmarangecheck(addr, nbytes, chan)) { - if (dma_bounce[chan] == 0) - dma_bounce[chan] = - /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/ - (caddr_t) isaphysmem + NBPG*chan; - bounced[chan] = 1; - newaddr = dma_bounce[chan]; - *(int *) newaddr = 0; /* XXX */ - /* copy bounce buffer on write */ - if ((flags & B_READ) == 0) - bcopy(addr, newaddr, nbytes); - addr = newaddr; + di = dma_info+chan; + if (di->flags != 0) { + log(LOG_ERR,"isadma_start: old request active on %d\n",chan); + isadma_abort(chan); } - /* translate to physical */ - phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); + di->flags = flags; + di->addr = addr; + di->nbytes = nbytes; + + mflags = ISADMA_MAP_WAITOK | ISADMA_MAP_BOUNCE | ISADMA_MAP_CONTIG; + mflags |= (chan & 4) ? ISADMA_MAP_16BIT : ISADMA_MAP_8BIT; + + if (isadma_map(addr, nbytes, di->phys, mflags) != 1) + panic("isadma_start: cannot map"); + + if ((flags & ISADMA_START_READ) == 0) + isadma_copytobuf(addr, nbytes, 1, di->phys); if ((chan & 4) == 0) { /* @@ -95,7 +102,7 @@ isa_dmastart(flags, addr, nbytes, chan) * byte mode channels. */ /* set dma channel mode, and reset address ff */ - if (flags & B_READ) + if (flags & ISADMA_START_READ) outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_WRITE); else outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_READ); @@ -103,9 +110,9 @@ isa_dmastart(flags, addr, nbytes, chan) /* send start address */ waport = DMA1_CHN(chan); - outb(waport, phys); - outb(waport, phys>>8); - outb(dmapageport[chan], phys>>16); + outb(waport, di->phys[0].addr); + outb(waport, di->phys[0].addr>>8); + outb(dmapageport[chan], di->phys[0].addr>>16); /* send count */ outb(waport + 1, --nbytes); @@ -119,7 +126,7 @@ isa_dmastart(flags, addr, nbytes, chan) * word mode channels. */ /* set dma channel mode, and reset address ff */ - if (flags & B_READ) + if (flags & ISADMA_START_READ) outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_WRITE); else outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_READ); @@ -127,9 +134,9 @@ isa_dmastart(flags, addr, nbytes, chan) /* send start address */ waport = DMA2_CHN(chan & 3); - outb(waport, phys>>1); - outb(waport, phys>>9); - outb(dmapageport[chan], phys>>16); + outb(waport, di->phys[0].addr>>1); + outb(waport, di->phys[0].addr>>9); + outb(dmapageport[chan], di->phys[0].addr>>16); /* send count */ nbytes >>= 1; @@ -142,38 +149,50 @@ isa_dmastart(flags, addr, nbytes, chan) } void -isa_dmaabort(chan) +isadma_abort(chan) int chan; { + struct dma_info *di; #ifdef DIAGNOSTIC if (chan < 0 || chan > 7) - panic("isa_dmaabort: impossible request"); + panic("isadma_abort: impossible request"); #endif - bounced[chan] = 0; + di = dma_info+chan; + if (di->flags == 0) { + log(LOG_ERR,"isadma_abort: no request active on %d\n",chan); + return; + } /* mask channel */ if ((chan & 4) == 0) outb(DMA1_SMSK, DMA37SM_SET | chan); else outb(DMA2_SMSK, DMA37SM_SET | (chan & 3)); + + isadma_unmap(di->addr, di->nbytes, 1, di->phys); + di->flags = 0; } void -isa_dmadone(flags, addr, nbytes, chan) - int flags; - caddr_t addr; - vm_size_t nbytes; +isadma_done(chan) int chan; { + struct dma_info *di; u_char tc; #ifdef DIAGNOSTIC if (chan < 0 || chan > 7) - panic("isa_dmadone: impossible request"); + panic("isadma_done: impossible request"); #endif + di = dma_info+chan; + if (di->flags == 0) { + log(LOG_ERR,"isadma_done: no request active on %d\n",chan); + return; + } + /* check that the terminal count was reached */ if ((chan & 4) == 0) tc = inb(DMA1_SR) & (1 << chan); @@ -189,85 +208,9 @@ isa_dmadone(flags, addr, nbytes, chan) else outb(DMA2_SMSK, DMA37SM_SET | (chan & 3)); - /* copy bounce buffer on read */ - if (bounced[chan]) { - bcopy(dma_bounce[chan], addr, nbytes); - bounced[chan] = 0; - } -} + if (di->flags & ISADMA_START_READ) + isadma_copyfrombuf(di->addr, di->nbytes, 1, di->phys); -/* - * 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. - */ -int -isa_dmarangecheck(va, length, chan) - vm_offset_t va; - u_long length; - int chan; -{ - vm_offset_t phys, priorpage = 0, endva; - u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); - - endva = round_page(va + length); - for (; va < endva ; va += NBPG) { - phys = trunc_page(pmap_extract(pmap_kernel(), va)); - if (phys == 0) - panic("isa_dmacheck: no physical page present"); - if (phys >= (1<<24)) - return 1; - if (priorpage) { - if (priorpage + NBPG != phys) - return 1; - /* check if crossing a DMA page boundary */ - if ((priorpage ^ phys) & dma_pgmsk) - return 1; - } - priorpage = phys; - } - return 0; -} - -/* head of queue waiting for physmem to become available */ -struct buf isa_physmemq; - -/* blocked waiting for resource to become free for exclusive use */ -static isaphysmemflag; -/* if waited for and call requested when free (B_CALL) */ -static void (*isaphysmemunblock)(); /* needs to be a list */ - -/* - * Allocate contiguous physical memory for transfer, returning - * a *virtual* address to region. May block waiting for resource. - * (assumed to be called at splbio()) - */ -caddr_t -isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) { - - isaphysmemunblock = func; - while (isaphysmemflag & B_BUSY) { - isaphysmemflag |= B_WANTED; - sleep((caddr_t)&isaphysmemflag, PRIBIO); - } - isaphysmemflag |= B_BUSY; - - return((caddr_t)isaphysmem); -} - -/* - * Free contiguous physical memory used for transfer. - * (assumed to be called at splbio()) - */ -void -isa_freephysmem(caddr_t va, unsigned length) { - - isaphysmemflag &= ~B_BUSY; - if (isaphysmemflag & B_WANTED) { - isaphysmemflag &= B_WANTED; - wakeup((caddr_t)&isaphysmemflag); - if (isaphysmemunblock) - (*isaphysmemunblock)(); - } + isadma_unmap(di->addr, di->nbytes, 1, di->phys); + di->flags = 0; } |