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