xref: /csrg-svn/sys/hp300/dev/dma.c (revision 45788)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1982, 1990 The Regents of the University of California.
341480Smckusick  * All rights reserved.
441480Smckusick  *
541480Smckusick  * %sccs.include.redist.c%
641480Smckusick  *
7*45788Sbostic  *	@(#)dma.c	7.3 (Berkeley) 12/16/90
841480Smckusick  */
941480Smckusick 
1041480Smckusick /*
1141480Smckusick  * DMA driver
1241480Smckusick  */
1341480Smckusick 
14*45788Sbostic #include "sys/param.h"
15*45788Sbostic #include "sys/systm.h"
16*45788Sbostic #include "sys/time.h"
17*45788Sbostic #include "sys/kernel.h"
18*45788Sbostic #include "sys/proc.h"
1941480Smckusick #include "dmareg.h"
2041480Smckusick #include "dmavar.h"
2141480Smckusick #include "device.h"
2241480Smckusick 
23*45788Sbostic #include "../include/cpu.h"
24*45788Sbostic #include "../hp300/isr.h"
2541480Smckusick 
2641480Smckusick extern void isrlink();
2741480Smckusick extern void printf();
2841480Smckusick extern void panic();
2941480Smckusick extern void _insque();
3041480Smckusick extern void _remque();
3141480Smckusick extern void timeout();
3241480Smckusick extern int splbio();
3341480Smckusick extern void splx();
3441480Smckusick extern u_int kvtop();
3541480Smckusick extern void PCIA();
3641480Smckusick 
3741480Smckusick /*
3841480Smckusick  * The largest single request will be MAXPHYS bytes which will require
3941480Smckusick  * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
4041480Smckusick  * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
4141480Smckusick  * buffer is not page aligned (+1).
4241480Smckusick  */
4341480Smckusick #define	DMAMAXIO	(MAXPHYS/NBPG+1)
4441480Smckusick 
4545750Smckusick struct	dma_chain {
4645750Smckusick 	int	dc_count;
4745750Smckusick 	char	*dc_addr;
4845750Smckusick };
4941480Smckusick 
5041480Smckusick struct	dma_softc {
5145750Smckusick 	struct	dmadevice *sc_hwaddr;
5245750Smckusick 	struct	dmaBdevice *sc_Bhwaddr;
5345750Smckusick 	char	sc_type;
5445750Smckusick 	char	sc_flags;
5545750Smckusick 	u_short	sc_cmd;
5645750Smckusick 	struct	dma_chain *sc_cur;
5745750Smckusick 	struct	dma_chain *sc_last;
5845750Smckusick 	struct	dma_chain sc_chain[DMAMAXIO];
5941480Smckusick } dma_softc[NDMA];
6041480Smckusick 
6141480Smckusick /* types */
6241480Smckusick #define	DMA_B	0
6341480Smckusick #define DMA_C	1
6441480Smckusick 
6545750Smckusick /* flags */
6645750Smckusick #define DMAF_PCFLUSH	0x01
6745750Smckusick #define DMAF_VCFLUSH	0x02
6845750Smckusick #define DMAF_NOINTR	0x04
6945750Smckusick 
7041480Smckusick struct	devqueue dmachan[NDMA + 1];
7141480Smckusick int	dmaintr();
7241480Smckusick 
7341480Smckusick #ifdef DEBUG
7441480Smckusick int	dmadebug = 0;
7541480Smckusick #define DDB_WORD	0x01	/* same as DMAGO_WORD */
7641480Smckusick #define DDB_LWORD	0x02	/* same as DMAGO_LWORD */
7741480Smckusick #define	DDB_FOLLOW	0x04
7841480Smckusick #define DDB_IO		0x08
7941480Smckusick 
8045750Smckusick void	dmatimeout();
8145750Smckusick int	dmatimo[NDMA];
8245750Smckusick 
8341480Smckusick long	dmahits[NDMA];
8441480Smckusick long	dmamisses[NDMA];
8541480Smckusick long	dmabyte[NDMA];
8641480Smckusick long	dmaword[NDMA];
8741480Smckusick long	dmalword[NDMA];
8841480Smckusick #endif
8941480Smckusick 
9041480Smckusick void
9141480Smckusick dmainit()
9241480Smckusick {
9341480Smckusick 	register struct dmareg *dma = (struct dmareg *)DMA_BASE;
9441480Smckusick 	register struct dma_softc *dc;
9541480Smckusick 	register int i;
9641480Smckusick 	char rev;
9741480Smckusick 
9841480Smckusick 	/*
9941480Smckusick 	 * Determine the DMA type.
10041480Smckusick 	 * Don't know how to easily differentiate the A and B cards,
10141480Smckusick 	 * so we just hope nobody has an A card (A cards will work if
10241480Smckusick 	 * DMAINTLVL is set to 3).
10341480Smckusick 	 */
10441480Smckusick 	if (!badbaddr((char *)&dma->dma_id[2]))
10541480Smckusick 		rev = dma->dma_id[2];
10641480Smckusick 	else {
10741480Smckusick 		rev = 'B';
10841480Smckusick #if !defined(HP320)
10941480Smckusick 		panic("dmainit: DMA card requires hp320 support");
11041480Smckusick #endif
11141480Smckusick 	}
11241480Smckusick 
11341480Smckusick 	dc = &dma_softc[0];
11441480Smckusick 	for (i = 0; i < NDMA; i++) {
11541480Smckusick 		dc->sc_hwaddr = (i & 1) ? &dma->dma_chan1 : &dma->dma_chan0;
11641480Smckusick 		dc->sc_Bhwaddr = (i & 1) ? &dma->dma_Bchan1 : &dma->dma_Bchan0;
11741480Smckusick 		dc->sc_type = rev == 'B' ? DMA_B : DMA_C;
11841480Smckusick 		dc++;
11941480Smckusick 		dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
12041480Smckusick 	}
12141480Smckusick 	dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
12245750Smckusick #ifdef DEBUG
12345750Smckusick 	/* make sure timeout is really not needed */
12445750Smckusick 	timeout(dmatimeout, 0, 30 * hz);
12545750Smckusick #endif
12641480Smckusick 
12741480Smckusick 	printf("dma: 98620%c with 2 channels, %d bit DMA\n",
12841480Smckusick 	       rev, rev == 'B' ? 16 : 32);
12941480Smckusick }
13041480Smckusick 
13141480Smckusick int
13241480Smckusick dmareq(dq)
13341480Smckusick 	register struct devqueue *dq;
13441480Smckusick {
13541480Smckusick 	register int i;
13641480Smckusick 	register int chan;
13741480Smckusick 	register int s = splbio();
13841480Smckusick 
13941480Smckusick 	chan = dq->dq_ctlr;
14041480Smckusick 	i = NDMA;
14141480Smckusick 	while (--i >= 0) {
14241480Smckusick 		if ((chan & (1 << i)) == 0)
14341480Smckusick 			continue;
14441480Smckusick 		if (dmachan[i].dq_forw != &dmachan[i])
14541480Smckusick 			continue;
14641480Smckusick 		insque(dq, &dmachan[i]);
14741480Smckusick 		dq->dq_ctlr = i;
14841480Smckusick 		splx(s);
14941480Smckusick 		return(1);
15041480Smckusick 	}
15141480Smckusick 	insque(dq, dmachan[NDMA].dq_back);
15241480Smckusick 	splx(s);
15341480Smckusick 	return(0);
15441480Smckusick }
15541480Smckusick 
15641480Smckusick void
15741480Smckusick dmafree(dq)
15841480Smckusick 	register struct devqueue *dq;
15941480Smckusick {
16041480Smckusick 	int unit = dq->dq_ctlr;
16141480Smckusick 	register struct dma_softc *dc = &dma_softc[unit];
16241480Smckusick 	register struct devqueue *dn;
16341480Smckusick 	register int chan, s;
16441480Smckusick 
16541480Smckusick 	s = splbio();
16645750Smckusick #ifdef DEBUG
16745750Smckusick 	dmatimo[unit] = 0;
16845750Smckusick #endif
16941480Smckusick 	DMA_CLEAR(dc);
17045750Smckusick 	/*
17145750Smckusick 	 * XXX we may not always go thru the flush code in dmastop()
17245750Smckusick 	 */
17345750Smckusick #if defined(HP360) || defined(HP370)
17445750Smckusick 	if (dc->sc_flags & DMAF_PCFLUSH) {
17545750Smckusick 		PCIA();
17645750Smckusick 		dc->sc_flags &= ~DMAF_PCFLUSH;
17745750Smckusick 	}
17845750Smckusick #endif
17945750Smckusick #if defined(HP320) || defined(HP350)
18045750Smckusick 	if (dc->sc_flags & DMAF_VCFLUSH) {
18145750Smckusick 		/*
18245750Smckusick 		 * 320/350s have VACs that may also need flushing.
18345750Smckusick 		 * In our case we only flush the supervisor side
18445750Smckusick 		 * because we know that if we are DMAing to user
18545750Smckusick 		 * space, the physical pages will also be mapped
18645750Smckusick 		 * in kernel space (via vmapbuf) and hence cache-
18745750Smckusick 		 * inhibited by the pmap module due to the multiple
18845750Smckusick 		 * mapping.
18945750Smckusick 		 */
19045750Smckusick 		DCIS();
19145750Smckusick 		dc->sc_flags &= ~DMAF_VCFLUSH;
19245750Smckusick 	}
19345750Smckusick #endif
19441480Smckusick 	remque(dq);
19541480Smckusick 	chan = 1 << unit;
19641480Smckusick 	for (dn = dmachan[NDMA].dq_forw;
19741480Smckusick 	     dn != &dmachan[NDMA]; dn = dn->dq_forw) {
19841480Smckusick 		if (dn->dq_ctlr & chan) {
19941480Smckusick 			remque((caddr_t)dn);
20041480Smckusick 			insque((caddr_t)dn, (caddr_t)dq->dq_back);
20141480Smckusick 			splx(s);
20241480Smckusick 			dn->dq_ctlr = dq->dq_ctlr;
20341480Smckusick 			(dn->dq_driver->d_start)(dn->dq_unit);
20441480Smckusick 			return;
20541480Smckusick 		}
20641480Smckusick 	}
20741480Smckusick 	splx(s);
20841480Smckusick }
20941480Smckusick 
21041480Smckusick void
21141480Smckusick dmago(unit, addr, count, flags)
21241480Smckusick 	int unit;
21341480Smckusick 	register char *addr;
21441480Smckusick 	register int count;
21541480Smckusick 	register int flags;
21641480Smckusick {
21741480Smckusick 	register struct dma_softc *dc = &dma_softc[unit];
21845750Smckusick 	register struct dma_chain *dcp;
21941480Smckusick 	register char *dmaend = NULL;
22045750Smckusick 	register int tcount;
22141480Smckusick 
22245750Smckusick 	if (count > MAXPHYS)
22345750Smckusick 		panic("dmago: count > MAXPHYS");
22445750Smckusick #if defined(HP320)
22545750Smckusick 	if (dc->sc_type == DMA_B && (flags & DMAGO_LWORD))
22645750Smckusick 		panic("dmago: no can do 32-bit DMA");
22745750Smckusick #endif
22841480Smckusick #ifdef DEBUG
22941480Smckusick 	if (dmadebug & DDB_FOLLOW)
23041480Smckusick 		printf("dmago(%d, %x, %x, %x)\n",
23141480Smckusick 		       unit, addr, count, flags);
23241480Smckusick 	if (flags & DMAGO_LWORD)
23341480Smckusick 		dmalword[unit]++;
23441480Smckusick 	else if (flags & DMAGO_WORD)
23541480Smckusick 		dmaword[unit]++;
23641480Smckusick 	else
23741480Smckusick 		dmabyte[unit]++;
23841480Smckusick #endif
23941480Smckusick 	/*
24041480Smckusick 	 * Build the DMA chain
24141480Smckusick 	 */
24245750Smckusick 	for (dcp = dc->sc_chain; count > 0; dcp++) {
24345750Smckusick 		dcp->dc_addr = (char *) kvtop(addr);
24445750Smckusick 		if (count < (tcount = NBPG - ((int)addr & PGOFSET)))
24545750Smckusick 			tcount = count;
24645750Smckusick 		dcp->dc_count = tcount;
24745750Smckusick 		addr += tcount;
24841480Smckusick 		count -= tcount;
24945750Smckusick 		if (flags & DMAGO_LWORD)
25045750Smckusick 			tcount >>= 2;
25145750Smckusick 		else if (flags & DMAGO_WORD)
25245750Smckusick 			tcount >>= 1;
25345750Smckusick 		if (dcp->dc_addr == dmaend
25441480Smckusick #if defined(HP320)
25541480Smckusick 		    /* only 16-bit count on 98620B */
25641480Smckusick 		    && (dc->sc_type != DMA_B ||
25745750Smckusick 			(dcp-1)->dc_count + tcount <= 65536)
25841480Smckusick #endif
25941480Smckusick 		) {
26041480Smckusick #ifdef DEBUG
26141480Smckusick 			dmahits[unit]++;
26241480Smckusick #endif
26345750Smckusick 			dmaend += dcp->dc_count;
26445750Smckusick 			(--dcp)->dc_count += tcount;
26541480Smckusick 		} else {
26641480Smckusick #ifdef DEBUG
26741480Smckusick 			dmamisses[unit]++;
26841480Smckusick #endif
26945750Smckusick 			dmaend = dcp->dc_addr + dcp->dc_count;
27045750Smckusick 			dcp->dc_count = tcount;
27141480Smckusick 		}
27241480Smckusick 	}
27345750Smckusick 	dc->sc_cur = dc->sc_chain;
27445750Smckusick 	dc->sc_last = --dcp;
27545750Smckusick 	dc->sc_flags = 0;
27641480Smckusick 	/*
27741480Smckusick 	 * Set up the command word based on flags
27841480Smckusick 	 */
27941480Smckusick 	dc->sc_cmd = DMA_ENAB | DMA_IPL(DMAINTLVL) | DMA_START;
28041480Smckusick 	if ((flags & DMAGO_READ) == 0)
28141480Smckusick 		dc->sc_cmd |= DMA_WRT;
28241480Smckusick 	if (flags & DMAGO_LWORD)
28341480Smckusick 		dc->sc_cmd |= DMA_LWORD;
28441480Smckusick 	else if (flags & DMAGO_WORD)
28541480Smckusick 		dc->sc_cmd |= DMA_WORD;
28641480Smckusick 	if (flags & DMAGO_PRI)
28741480Smckusick 		dc->sc_cmd |= DMA_PRI;
28845750Smckusick #if defined(HP360) || defined(HP370)
28941480Smckusick 	/*
29045750Smckusick 	 * Remember if we need to flush external physical cache when
29145750Smckusick 	 * DMA is done.  We only do this if we are reading (writing memory).
29241480Smckusick 	 */
29345750Smckusick 	if (ectype == EC_PHYS && (flags & DMAGO_READ))
29445750Smckusick 		dc->sc_flags |= DMAF_PCFLUSH;
29541480Smckusick #endif
29645750Smckusick #if defined(HP320) || defined(HP350)
29745750Smckusick 	if (ectype == EC_VIRT && (flags & DMAGO_READ))
29845750Smckusick 		dc->sc_flags |= DMAF_VCFLUSH;
29945750Smckusick #endif
30045750Smckusick 	/*
30145750Smckusick 	 * Remember if we can skip the dma completion interrupt on
30245750Smckusick 	 * the last segment in the chain.
30345750Smckusick 	 */
30445750Smckusick 	if (flags & DMAGO_NOINT) {
30545750Smckusick 		if (dc->sc_cur == dc->sc_last)
30645750Smckusick 			dc->sc_cmd &= ~DMA_ENAB;
30745750Smckusick 		else
30845750Smckusick 			dc->sc_flags |= DMAF_NOINTR;
30945750Smckusick 	}
31041480Smckusick #ifdef DEBUG
31141480Smckusick 	if (dmadebug & DDB_IO)
31241480Smckusick 		if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
31341480Smckusick 		    (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD)) {
31445750Smckusick 			printf("dmago: cmd %x, flags %x\n",
31545750Smckusick 			       dc->sc_cmd, dc->sc_flags);
31645750Smckusick 			for (dcp = dc->sc_chain; dcp <= dc->sc_last; dcp++)
31745750Smckusick 				printf("  %d: %d@%x\n", dcp-dc->sc_chain,
31845750Smckusick 				       dcp->dc_count, dcp->dc_addr);
31941480Smckusick 		}
32045750Smckusick 	dmatimo[unit] = 1;
32141480Smckusick #endif
322*45788Sbostic 	DMA_ARM(dc, "KIRK, MISSING AN ARG");
32341480Smckusick }
32441480Smckusick 
32541480Smckusick void
32641480Smckusick dmastop(unit)
32741480Smckusick 	register int unit;
32841480Smckusick {
32941480Smckusick 	register struct dma_softc *dc = &dma_softc[unit];
33041480Smckusick 	register struct devqueue *dq;
33141480Smckusick 
33241480Smckusick #ifdef DEBUG
33341480Smckusick 	if (dmadebug & DDB_FOLLOW)
33441480Smckusick 		printf("dmastop(%d)\n", unit);
33545750Smckusick 	dmatimo[unit] = 0;
33641480Smckusick #endif
33741480Smckusick 	DMA_CLEAR(dc);
33845750Smckusick #if defined(HP360) || defined(HP370)
33945750Smckusick 	if (dc->sc_flags & DMAF_PCFLUSH) {
34045750Smckusick 		PCIA();
34145750Smckusick 		dc->sc_flags &= ~DMAF_PCFLUSH;
34245750Smckusick 	}
34345750Smckusick #endif
34445750Smckusick #if defined(HP320) || defined(HP350)
34545750Smckusick 	if (dc->sc_flags & DMAF_VCFLUSH) {
34645750Smckusick 		/*
34745750Smckusick 		 * 320/350s have VACs that may also need flushing.
34845750Smckusick 		 * In our case we only flush the supervisor side
34945750Smckusick 		 * because we know that if we are DMAing to user
35045750Smckusick 		 * space, the physical pages will also be mapped
35145750Smckusick 		 * in kernel space (via vmapbuf) and hence cache-
35245750Smckusick 		 * inhibited by the pmap module due to the multiple
35345750Smckusick 		 * mapping.
35445750Smckusick 		 */
35545750Smckusick 		DCIS();
35645750Smckusick 		dc->sc_flags &= ~DMAF_VCFLUSH;
35745750Smckusick 	}
35845750Smckusick #endif
35941480Smckusick 	/*
36041480Smckusick 	 * We may get this interrupt after a device service routine
36141480Smckusick 	 * has freed the dma channel.  So, ignore the intr if there's
36241480Smckusick 	 * nothing on the queue.
36341480Smckusick 	 */
36441480Smckusick 	dq = dmachan[unit].dq_forw;
36545750Smckusick 	if (dq != &dmachan[unit])
36641480Smckusick 		(dq->dq_driver->d_done)(dq->dq_unit);
36741480Smckusick }
36841480Smckusick 
36941480Smckusick int
37041480Smckusick dmaintr()
37141480Smckusick {
37241480Smckusick 	register struct dma_softc *dc;
37345750Smckusick 	register int i, stat;
37441480Smckusick 	int found = 0;
37541480Smckusick 
37641480Smckusick #ifdef DEBUG
37741480Smckusick 	if (dmadebug & DDB_FOLLOW)
37841480Smckusick 		printf("dmaintr\n");
37941480Smckusick #endif
38041480Smckusick 	for (i = 0, dc = dma_softc; i < NDMA; i++, dc++) {
38141480Smckusick 		stat = DMA_STAT(dc);
38241480Smckusick 		if ((stat & DMA_INTR) == 0)
38341480Smckusick 			continue;
38441480Smckusick 		found++;
38541480Smckusick #ifdef DEBUG
38641480Smckusick 		if (dmadebug & DDB_IO) {
38741480Smckusick 			if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
38841480Smckusick 			    (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD))
38941480Smckusick 				printf("dmaintr: unit %d stat %x next %d\n",
39045750Smckusick 				       i, stat, (dc->sc_cur-dc->sc_chain)+1);
39141480Smckusick 		}
39241480Smckusick 		if (stat & DMA_ARMED)
39341480Smckusick 			printf("dma%d: intr when armed\n", i);
39441480Smckusick #endif
39545750Smckusick 		if (++dc->sc_cur <= dc->sc_last) {
39645750Smckusick #ifdef DEBUG
39745750Smckusick 			dmatimo[i] = 1;
39845750Smckusick #endif
39945750Smckusick 			/*
40045750Smckusick 			 * Last chain segment, disable DMA interrupt.
40145750Smckusick 			 */
40245750Smckusick 			if (dc->sc_cur == dc->sc_last &&
40345750Smckusick 			    (dc->sc_flags & DMAF_NOINTR))
40445750Smckusick 				dc->sc_cmd &= ~DMA_ENAB;
40541480Smckusick 			DMA_CLEAR(dc);
406*45788Sbostic 			DMA_ARM(dc, "KIRK, MISSING AN ARG");
40741480Smckusick 		} else
40841480Smckusick 			dmastop(i);
40941480Smckusick 	}
41041480Smckusick 	return(found);
41141480Smckusick }
41241480Smckusick 
41345750Smckusick #ifdef DEBUG
41441480Smckusick void
41545750Smckusick dmatimeout()
41641480Smckusick {
41741480Smckusick 	register int i, s;
41841480Smckusick 
41945750Smckusick 	for (i = 0; i < NDMA; i++) {
42041480Smckusick 		s = splbio();
42145750Smckusick 		if (dmatimo[i]) {
42245750Smckusick 			if (dmatimo[i] > 1)
42345750Smckusick 				printf("dma%d: timeout #%d\n",
42445750Smckusick 				       i, dmatimo[i]-1);
42545750Smckusick 			dmatimo[i]++;
42641480Smckusick 		}
42741480Smckusick 		splx(s);
42841480Smckusick 	}
42945750Smckusick 	timeout(dmatimeout, (caddr_t)0, 30 * hz);
43041480Smckusick }
43145750Smckusick #endif
432