Subject: port-i386/700: i386 dma interface lacks functionality
To: None <gnats-admin@NetBSD.ORG>
From: None <kenh@entropic.com>
List: netbsd-bugs
Date: 01/04/1995 21:05:10
>Number: 700
>Category: port-i386
>Synopsis: The i386 interface to the PC DMA controller lacks functionality
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: gnats-admin (GNATS administrator)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Wed Jan 4 21:05:05 1995
>Originator: Ken Hornstein
>Organization:
" "
>Release: 1.0
>Environment:
System: NetBSD excalibur 1.0 NetBSD 1.0 (EXCALIBUR) #39: Wed Jan 4 23:44:48 EST 1995 kenh@excalibur:/usr/src/sys/arch/i386/compile/EXCALIBUR i386
>Description:
The "flags" argument to isa_dmastart is more than slightly bogus. It uses the
same flags as the kernel buffers to indicate read or write, and doesn't provide
a way to get at some of the more useful features of the DMA controller (like
auto-initialization).
>How-To-Repeat:
Try writing a device driver that requires the DMA controller to use auto-
initialization.
>Fix:
The following patch should solve this problem. Instead of using the kernel
buf flags B_READ and B_WRITE to indicate a DMA read or write, you now use the
flags DMA_READ and DMA_WRITE. You also can specify other flags (for example,
DMA_AUTOINIT, or DMAMODE_BLOCK). This allows the isa_dmastart interface to
be easily extended.
Note - I tested this with the floppy drive, and as far as I can tell, it works
fine; both reads and writes to my floppy drive are ok. Since I don't have
a QIC tape drive, I couldn't test that. I think the changes I made to wt.c
are correct, but I can't be 100% sure. I am pretty sure the changes made to
dma.c are correct, at least.
--- dma.c.orig Wed Jan 4 23:28:01 1995
+++ dma.c Wed Jan 4 23:37:29 1995
@@ -62,6 +62,7 @@
vm_offset_t phys;
int waport;
caddr_t newaddr;
+ int dmaflags;
#ifdef DIAGNOSTIC
if (chan < 0 || chan > 7 ||
@@ -79,7 +80,7 @@
newaddr = dma_bounce[chan];
*(int *) newaddr = 0; /* XXX */
/* copy bounce buffer on write */
- if ((flags & B_READ) == 0)
+ if ((flags & DMA_READ) == 0)
bcopy(addr, newaddr, nbytes);
addr = newaddr;
}
@@ -87,16 +88,27 @@
/* translate to physical */
phys = pmap_extract(kernel_pmap, (vm_offset_t)addr);
+ /* set flags for DMA controller based on what we were given */
+
+ dmaflags = (flags & DMA_READ) ? DMA37MD_WRITE : DMA37MD_READ;
+
+ if (flags & DMAMODE_DEMAND)
+ dmaflags |= DMA37MD_DEMAND;
+ else if (flags & DMAMODE_BLOCK)
+ dmaflags |= DMA37MD_BLOCK;
+ else
+ dmaflags |= DMA37MD_SINGLE;
+
+ if (flags & DMA_AUTOINIT)
+ dmaflags |= DMA37MD_AUTO;
+
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, chan | DMA37MD_SINGLE | DMA37MD_WRITE);
- else
- outb(DMA1_MODE, chan | DMA37MD_SINGLE | DMA37MD_READ);
+ outb(DMA1_MODE, chan | dmaflags);
outb(DMA1_FFC, 0);
/* send start address */
@@ -117,10 +129,7 @@
* word mode channels.
*/
/* set dma channel mode, and reset address ff */
- if (flags & B_READ)
- outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_WRITE);
- else
- outb(DMA2_MODE, (chan & 3) | DMA37MD_SINGLE | DMA37MD_READ);
+ outb(DMA2_MODE, (chan & 3) | dmaflags);
outb(DMA2_FFC, 0);
/* send start address */
--- dmavar.h.orig Wed Jan 4 23:17:25 1995
+++ dmavar.h Wed Jan 4 23:37:24 1995
@@ -2,3 +2,17 @@
void isa_dmastart __P((int, caddr_t, vm_size_t, int));
void isa_dmaabort __P((int));
void isa_dmadone __P((int, caddr_t, vm_size_t, int));
+
+/*
+ * Flags for isa_dmastart. To make old code easier to port, set up single-step
+ * mode as a default and DMA_READ/WRITE like the buf B_READ/WRITE flags
+ */
+
+#define DMA_READ 0x01 /* Device read, memory write */
+#define DMA_WRITE 0x00 /* Device write, memory read */
+
+#define DMAMODE_SINGLE 0x00 /* Single-step mode - the default */
+#define DMAMODE_DEMAND 0x02 /* Demand mode */
+#define DMAMODE_BLOCK 0x04 /* Block mode */
+
+#define DMA_AUTOINIT 0x08 /* Auto-initialization */
--- fd.c.orig Wed Jan 4 23:38:17 1995
+++ fd.c Wed Jan 4 23:39:06 1995
@@ -883,7 +883,7 @@
#endif
}}
#endif
- read = bp->b_flags & B_READ;
+ read = (bp->b_flags & B_READ) ? DMA_READ : DMA_WRITE;
#ifdef NEWCONFIG
at_dma(read, bp->b_data + fd->sc_skip, nblks * FDC_BSIZE,
fdc->sc_drq);
--- wt.c.orig Wed Jan 4 23:55:34 1995
+++ wt.c Wed Jan 4 23:41:51 1995
@@ -648,7 +648,7 @@
/*
* Clean up dma.
*/
- if ((sc->dmaflags & B_READ) &&
+ if ((sc->dmaflags & DMA_READ) &&
(sc->dmatotal - sc->dmacount) < sc->bsize) {
/* If reading short block, copy the internal buffer
* to the user memory. */
@@ -662,7 +662,7 @@
*/
if ((x & sc->NOEXCEP) == 0) {
DEBUG(("i/o exception\n"));
- wtsense(sc, 1, (sc->dmaflags & B_READ) ? TP_WRP : 0);
+ wtsense(sc, 1, (sc->dmaflags & DMA_READ) ? TP_WRP : 0);
if (sc->error & (TP_EOM | TP_FIL))
sc->flags |= TPVOL; /* end of file */
else
@@ -837,7 +837,7 @@
outb(sc->SDMAPORT, 0);
}
- if ((sc->dmaflags & B_READ) &&
+ if ((sc->dmaflags & DMA_READ) &&
(sc->dmatotal - sc->dmacount) < sc->bsize) {
/* Reading short block; do it through the internal buffer. */
isa_dmastart(sc->dmaflags, sc->buf, sc->bsize, sc->chan);
@@ -865,7 +865,7 @@
sc->dmavaddr = vaddr;
sc->dmatotal = len;
sc->dmacount = 0;
- sc->dmaflags = flag;
+ sc->dmaflags = flag & B_READ ? DMA_READ : DMA_WRITE;
wtdma(sc);
return 1;
}
--- ic/i8237.h.orig Wed Jan 4 23:25:02 1995
+++ ic/i8237.h Wed Jan 4 23:27:47 1995
@@ -4,8 +4,11 @@
* $Id: i8237.h,v 1.3 1994/03/01 18:18:07 mycroft Exp $
*/
+#define DMA37MD_DEMAND 0x00 /* demand mode */
#define DMA37MD_SINGLE 0x40 /* single pass mode */
+#define DMA37MD_BLOCK 0x80 /* block mode */
#define DMA37MD_CASCADE 0xc0 /* cascade mode */
+#define DMA37MD_AUTO 0x10 /* autoinit upon completed transfer */
#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */
#define DMA37MD_READ 0x08 /* write the device, read memory operation */
>Audit-Trail:
>Unformatted: