MFi386: revision 199104
Make isa_dma functions MPSAFE by introducing its own private lock.
This commit is contained in:
parent
8956df833c
commit
24de8d2d59
@ -72,6 +72,8 @@ static u_int8_t dma_bounced = 0;
|
||||
static u_int8_t dma_busy = 0; /* Used in isa_dmastart() */
|
||||
static u_int8_t dma_inuse = 0; /* User for acquire/release */
|
||||
static u_int8_t dma_auto_mode = 0;
|
||||
static struct mtx isa_dma_lock;
|
||||
MTX_SYSINIT(isa_dma_lock, &isa_dma_lock, "isa DMA lock", MTX_DEF);
|
||||
|
||||
#define VALID_DMA_MASK (3)
|
||||
|
||||
@ -93,22 +95,31 @@ isa_dma_init(int chan, u_int bouncebufsize, int flag)
|
||||
panic("isa_dma_init: impossible request");
|
||||
#endif
|
||||
|
||||
dma_bouncebufsize[chan] = bouncebufsize;
|
||||
|
||||
/* Try malloc() first. It works better if it works. */
|
||||
buf = malloc(bouncebufsize, M_DEVBUF, flag);
|
||||
if (buf != NULL) {
|
||||
if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) {
|
||||
dma_bouncebuf[chan] = buf;
|
||||
return (0);
|
||||
if (isa_dmarangecheck(buf, bouncebufsize, chan) != 0) {
|
||||
free(buf, M_DEVBUF);
|
||||
buf = NULL;
|
||||
}
|
||||
free(buf, M_DEVBUF);
|
||||
}
|
||||
buf = contigmalloc(bouncebufsize, M_DEVBUF, flag, 0ul, 0xfffffful,
|
||||
|
||||
if (buf == NULL) {
|
||||
buf = contigmalloc(bouncebufsize, M_DEVBUF, flag, 0ul, 0xfffffful,
|
||||
1ul, chan & 4 ? 0x20000ul : 0x10000ul);
|
||||
}
|
||||
|
||||
if (buf == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
mtx_lock(&isa_dma_lock);
|
||||
|
||||
dma_bouncebufsize[chan] = bouncebufsize;
|
||||
dma_bouncebuf[chan] = buf;
|
||||
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -125,12 +136,15 @@ isa_dma_acquire(chan)
|
||||
panic("isa_dma_acquire: channel out of range");
|
||||
#endif
|
||||
|
||||
mtx_lock(&isa_dma_lock);
|
||||
if (dma_inuse & (1 << chan)) {
|
||||
printf("isa_dma_acquire: channel %d already in use\n", chan);
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
return (EBUSY);
|
||||
}
|
||||
dma_inuse |= (1 << chan);
|
||||
dma_auto_mode &= ~(1 << chan);
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -147,8 +161,11 @@ isa_dma_release(chan)
|
||||
if (chan & ~VALID_DMA_MASK)
|
||||
panic("isa_dma_release: channel out of range");
|
||||
|
||||
mtx_lock(&isa_dma_lock);
|
||||
if ((dma_inuse & (1 << chan)) == 0)
|
||||
printf("isa_dma_release: channel %d not in use\n", chan);
|
||||
#else
|
||||
mtx_lock(&isa_dma_lock);
|
||||
#endif
|
||||
|
||||
if (dma_busy & (1 << chan)) {
|
||||
@ -163,6 +180,8 @@ isa_dma_release(chan)
|
||||
|
||||
dma_inuse &= ~(1 << chan);
|
||||
dma_auto_mode &= ~(1 << chan);
|
||||
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -175,8 +194,11 @@ isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
|
||||
vm_paddr_t phys;
|
||||
int waport;
|
||||
caddr_t newaddr;
|
||||
int dma_range_checked;
|
||||
|
||||
GIANT_REQUIRED;
|
||||
/* translate to physical */
|
||||
phys = pmap_extract(kernel_pmap, (vm_offset_t)addr);
|
||||
dma_range_checked = isa_dmarangecheck(addr, nbytes, chan);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (chan & ~VALID_DMA_MASK)
|
||||
@ -186,8 +208,11 @@ isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
|
||||
|| (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
|
||||
panic("isa_dmastart: impossible request");
|
||||
|
||||
mtx_lock(&isa_dma_lock);
|
||||
if ((dma_inuse & (1 << chan)) == 0)
|
||||
printf("isa_dmastart: channel %d not acquired\n", chan);
|
||||
#else
|
||||
mtx_lock(&isa_dma_lock);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
@ -202,7 +227,7 @@ isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
|
||||
|
||||
dma_busy |= (1 << chan);
|
||||
|
||||
if (isa_dmarangecheck(addr, nbytes, chan)) {
|
||||
if (dma_range_checked) {
|
||||
if (dma_bouncebuf[chan] == NULL
|
||||
|| dma_bouncebufsize[chan] < nbytes)
|
||||
panic("isa_dmastart: bad bounce buffer");
|
||||
@ -215,9 +240,6 @@ isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
|
||||
addr = newaddr;
|
||||
}
|
||||
|
||||
/* translate to physical */
|
||||
phys = pmap_extract(kernel_pmap, (vm_offset_t)addr);
|
||||
|
||||
if (flags & ISADMA_RAW) {
|
||||
dma_auto_mode |= (1 << chan);
|
||||
} else {
|
||||
@ -255,6 +277,8 @@ isa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan)
|
||||
|
||||
/* unmask channel */
|
||||
outb(DMA1_SMSK, chan);
|
||||
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
}
|
||||
|
||||
void
|
||||
@ -275,6 +299,7 @@ isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
|
||||
printf("isa_dmadone: channel %d not acquired\n", chan);
|
||||
#endif
|
||||
|
||||
mtx_lock(&isa_dma_lock);
|
||||
if (((dma_busy & (1 << chan)) == 0) &&
|
||||
(dma_auto_mode & (1 << chan)) == 0 )
|
||||
printf("isa_dmadone: channel %d not busy\n", chan);
|
||||
@ -290,6 +315,7 @@ isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
|
||||
dma_bounced &= ~(1 << chan);
|
||||
}
|
||||
dma_busy &= ~(1 << chan);
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -306,8 +332,6 @@ isa_dmarangecheck(caddr_t va, u_int length, int chan)
|
||||
vm_offset_t endva;
|
||||
u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
|
||||
|
||||
GIANT_REQUIRED;
|
||||
|
||||
endva = (vm_offset_t)round_page((vm_offset_t)va + length);
|
||||
for (; va < (caddr_t) endva ; va += PAGE_SIZE) {
|
||||
phys = trunc_page(pmap_extract(kernel_pmap, (vm_offset_t)va));
|
||||
@ -364,13 +388,15 @@ isa_dmarangecheck(caddr_t va, u_int length, int chan)
|
||||
* or -1 if the channel requested is not active.
|
||||
*
|
||||
*/
|
||||
int
|
||||
isa_dmastatus(int chan)
|
||||
static int
|
||||
isa_dmastatus_locked(int chan)
|
||||
{
|
||||
u_long cnt = 0;
|
||||
int ffport, waport;
|
||||
u_long low1, high1, low2, high2;
|
||||
|
||||
mtx_assert(&isa_dma_lock, MA_OWNED);
|
||||
|
||||
/* channel active? */
|
||||
if ((dma_inuse & (1 << chan)) == 0) {
|
||||
printf("isa_dmastatus: channel %d not active\n", chan);
|
||||
@ -411,6 +437,18 @@ isa_dmastatus(int chan)
|
||||
return(cnt);
|
||||
}
|
||||
|
||||
int
|
||||
isa_dmastatus(int chan)
|
||||
{
|
||||
int status;
|
||||
|
||||
mtx_lock(&isa_dma_lock);
|
||||
status = isa_dmastatus_locked(chan);
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reached terminal count yet ?
|
||||
*/
|
||||
@ -427,19 +465,27 @@ isa_dmatc(int chan)
|
||||
int
|
||||
isa_dmastop(int chan)
|
||||
{
|
||||
int status;
|
||||
|
||||
mtx_lock(&isa_dma_lock);
|
||||
if ((dma_inuse & (1 << chan)) == 0)
|
||||
printf("isa_dmastop: channel %d not acquired\n", chan);
|
||||
|
||||
if (((dma_busy & (1 << chan)) == 0) &&
|
||||
((dma_auto_mode & (1 << chan)) == 0)) {
|
||||
printf("chan %d not busy\n", chan);
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
return -2 ;
|
||||
}
|
||||
|
||||
if ((chan & 4) == 0)
|
||||
outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */);
|
||||
|
||||
return(isa_dmastatus(chan));
|
||||
status = isa_dmastatus_locked(chan);
|
||||
|
||||
mtx_unlock(&isa_dma_lock);
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user