|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)dma.c 7.5 (Berkeley) 5/4/91
34: */
35:
36: /*
37: * DMA driver
38: */
39:
40: #include "param.h"
41: #include "systm.h"
42: #include "time.h"
43: #include "kernel.h"
44: #include "proc.h"
45:
46: #include "dmareg.h"
47: #include "dmavar.h"
48: #include "device.h"
49:
50: #include "../include/cpu.h"
51: #include "../hp300/isr.h"
52:
53: extern void isrlink();
54: extern void _insque();
55: extern void _remque();
56: extern void timeout();
57: extern u_int kvtop();
58: extern void PCIA();
59:
60: /*
61: * The largest single request will be MAXPHYS bytes which will require
62: * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
63: * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
64: * buffer is not page aligned (+1).
65: */
66: #define DMAMAXIO (MAXPHYS/NBPG+1)
67:
68: struct dma_chain {
69: int dc_count;
70: char *dc_addr;
71: };
72:
73: struct dma_softc {
74: struct dmadevice *sc_hwaddr;
75: struct dmaBdevice *sc_Bhwaddr;
76: char sc_type;
77: char sc_flags;
78: u_short sc_cmd;
79: struct dma_chain *sc_cur;
80: struct dma_chain *sc_last;
81: struct dma_chain sc_chain[DMAMAXIO];
82: } dma_softc[NDMA];
83:
84: /* types */
85: #define DMA_B 0
86: #define DMA_C 1
87:
88: /* flags */
89: #define DMAF_PCFLUSH 0x01
90: #define DMAF_VCFLUSH 0x02
91: #define DMAF_NOINTR 0x04
92:
93: struct devqueue dmachan[NDMA + 1];
94: int dmaintr();
95:
96: #ifdef DEBUG
97: int dmadebug = 0;
98: #define DDB_WORD 0x01 /* same as DMAGO_WORD */
99: #define DDB_LWORD 0x02 /* same as DMAGO_LWORD */
100: #define DDB_FOLLOW 0x04
101: #define DDB_IO 0x08
102:
103: void dmatimeout();
104: int dmatimo[NDMA];
105:
106: long dmahits[NDMA];
107: long dmamisses[NDMA];
108: long dmabyte[NDMA];
109: long dmaword[NDMA];
110: long dmalword[NDMA];
111: #endif
112:
113: void
114: dmainit()
115: {
116: register struct dmareg *dma = (struct dmareg *)DMA_BASE;
117: register struct dma_softc *dc;
118: register int i;
119: char rev;
120:
121: /*
122: * Determine the DMA type.
123: * Don't know how to easily differentiate the A and B cards,
124: * so we just hope nobody has an A card (A cards will work if
125: * DMAINTLVL is set to 3).
126: */
127: if (!badbaddr((char *)&dma->dma_id[2]))
128: rev = dma->dma_id[2];
129: else {
130: rev = 'B';
131: #if !defined(HP320)
132: panic("dmainit: DMA card requires hp320 support");
133: #endif
134: }
135:
136: dc = &dma_softc[0];
137: for (i = 0; i < NDMA; i++) {
138: dc->sc_hwaddr = (i & 1) ? &dma->dma_chan1 : &dma->dma_chan0;
139: dc->sc_Bhwaddr = (i & 1) ? &dma->dma_Bchan1 : &dma->dma_Bchan0;
140: dc->sc_type = rev == 'B' ? DMA_B : DMA_C;
141: dc++;
142: dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
143: }
144: dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
145: #ifdef DEBUG
146: /* make sure timeout is really not needed */
147: timeout(dmatimeout, 0, 30 * hz);
148: #endif
149:
150: printf("dma: 98620%c with 2 channels, %d bit DMA\n",
151: rev, rev == 'B' ? 16 : 32);
152: }
153:
154: int
155: dmareq(dq)
156: register struct devqueue *dq;
157: {
158: register int i;
159: register int chan;
160: register int s = splbio();
161:
162: chan = dq->dq_ctlr;
163: i = NDMA;
164: while (--i >= 0) {
165: if ((chan & (1 << i)) == 0)
166: continue;
167: if (dmachan[i].dq_forw != &dmachan[i])
168: continue;
169: insque(dq, &dmachan[i]);
170: dq->dq_ctlr = i;
171: splx(s);
172: return(1);
173: }
174: insque(dq, dmachan[NDMA].dq_back);
175: splx(s);
176: return(0);
177: }
178:
179: void
180: dmafree(dq)
181: register struct devqueue *dq;
182: {
183: int unit = dq->dq_ctlr;
184: register struct dma_softc *dc = &dma_softc[unit];
185: register struct devqueue *dn;
186: register int chan, s;
187:
188: s = splbio();
189: #ifdef DEBUG
190: dmatimo[unit] = 0;
191: #endif
192: DMA_CLEAR(dc);
193: /*
194: * XXX we may not always go thru the flush code in dmastop()
195: */
196: #if defined(HP360) || defined(HP370)
197: if (dc->sc_flags & DMAF_PCFLUSH) {
198: PCIA();
199: dc->sc_flags &= ~DMAF_PCFLUSH;
200: }
201: #endif
202: #if defined(HP320) || defined(HP350)
203: if (dc->sc_flags & DMAF_VCFLUSH) {
204: /*
205: * 320/350s have VACs that may also need flushing.
206: * In our case we only flush the supervisor side
207: * because we know that if we are DMAing to user
208: * space, the physical pages will also be mapped
209: * in kernel space (via vmapbuf) and hence cache-
210: * inhibited by the pmap module due to the multiple
211: * mapping.
212: */
213: DCIS();
214: dc->sc_flags &= ~DMAF_VCFLUSH;
215: }
216: #endif
217: remque(dq);
218: chan = 1 << unit;
219: for (dn = dmachan[NDMA].dq_forw;
220: dn != &dmachan[NDMA]; dn = dn->dq_forw) {
221: if (dn->dq_ctlr & chan) {
222: remque((caddr_t)dn);
223: insque((caddr_t)dn, (caddr_t)dq->dq_back);
224: splx(s);
225: dn->dq_ctlr = dq->dq_ctlr;
226: (dn->dq_driver->d_start)(dn->dq_unit);
227: return;
228: }
229: }
230: splx(s);
231: }
232:
233: void
234: dmago(unit, addr, count, flags)
235: int unit;
236: register char *addr;
237: register int count;
238: register int flags;
239: {
240: register struct dma_softc *dc = &dma_softc[unit];
241: register struct dma_chain *dcp;
242: register char *dmaend = NULL;
243: register int tcount;
244:
245: if (count > MAXPHYS)
246: panic("dmago: count > MAXPHYS");
247: #if defined(HP320)
248: if (dc->sc_type == DMA_B && (flags & DMAGO_LWORD))
249: panic("dmago: no can do 32-bit DMA");
250: #endif
251: #ifdef DEBUG
252: if (dmadebug & DDB_FOLLOW)
253: printf("dmago(%d, %x, %x, %x)\n",
254: unit, addr, count, flags);
255: if (flags & DMAGO_LWORD)
256: dmalword[unit]++;
257: else if (flags & DMAGO_WORD)
258: dmaword[unit]++;
259: else
260: dmabyte[unit]++;
261: #endif
262: /*
263: * Build the DMA chain
264: */
265: for (dcp = dc->sc_chain; count > 0; dcp++) {
266: dcp->dc_addr = (char *) kvtop(addr);
267: if (count < (tcount = NBPG - ((int)addr & PGOFSET)))
268: tcount = count;
269: dcp->dc_count = tcount;
270: addr += tcount;
271: count -= tcount;
272: if (flags & DMAGO_LWORD)
273: tcount >>= 2;
274: else if (flags & DMAGO_WORD)
275: tcount >>= 1;
276: if (dcp->dc_addr == dmaend
277: #if defined(HP320)
278: /* only 16-bit count on 98620B */
279: && (dc->sc_type != DMA_B ||
280: (dcp-1)->dc_count + tcount <= 65536)
281: #endif
282: ) {
283: #ifdef DEBUG
284: dmahits[unit]++;
285: #endif
286: dmaend += dcp->dc_count;
287: (--dcp)->dc_count += tcount;
288: } else {
289: #ifdef DEBUG
290: dmamisses[unit]++;
291: #endif
292: dmaend = dcp->dc_addr + dcp->dc_count;
293: dcp->dc_count = tcount;
294: }
295: }
296: dc->sc_cur = dc->sc_chain;
297: dc->sc_last = --dcp;
298: dc->sc_flags = 0;
299: /*
300: * Set up the command word based on flags
301: */
302: dc->sc_cmd = DMA_ENAB | DMA_IPL(DMAINTLVL) | DMA_START;
303: if ((flags & DMAGO_READ) == 0)
304: dc->sc_cmd |= DMA_WRT;
305: if (flags & DMAGO_LWORD)
306: dc->sc_cmd |= DMA_LWORD;
307: else if (flags & DMAGO_WORD)
308: dc->sc_cmd |= DMA_WORD;
309: if (flags & DMAGO_PRI)
310: dc->sc_cmd |= DMA_PRI;
311: #if defined(HP360) || defined(HP370)
312: /*
313: * Remember if we need to flush external physical cache when
314: * DMA is done. We only do this if we are reading (writing memory).
315: */
316: if (ectype == EC_PHYS && (flags & DMAGO_READ))
317: dc->sc_flags |= DMAF_PCFLUSH;
318: #endif
319: #if defined(HP320) || defined(HP350)
320: if (ectype == EC_VIRT && (flags & DMAGO_READ))
321: dc->sc_flags |= DMAF_VCFLUSH;
322: #endif
323: /*
324: * Remember if we can skip the dma completion interrupt on
325: * the last segment in the chain.
326: */
327: if (flags & DMAGO_NOINT) {
328: if (dc->sc_cur == dc->sc_last)
329: dc->sc_cmd &= ~DMA_ENAB;
330: else
331: dc->sc_flags |= DMAF_NOINTR;
332: }
333: #ifdef DEBUG
334: if (dmadebug & DDB_IO)
335: if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
336: (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD)) {
337: printf("dmago: cmd %x, flags %x\n",
338: dc->sc_cmd, dc->sc_flags);
339: for (dcp = dc->sc_chain; dcp <= dc->sc_last; dcp++)
340: printf(" %d: %d@%x\n", dcp-dc->sc_chain,
341: dcp->dc_count, dcp->dc_addr);
342: }
343: dmatimo[unit] = 1;
344: #endif
345: DMA_ARM(dc);
346: }
347:
348: void
349: dmastop(unit)
350: register int unit;
351: {
352: register struct dma_softc *dc = &dma_softc[unit];
353: register struct devqueue *dq;
354:
355: #ifdef DEBUG
356: if (dmadebug & DDB_FOLLOW)
357: printf("dmastop(%d)\n", unit);
358: dmatimo[unit] = 0;
359: #endif
360: DMA_CLEAR(dc);
361: #if defined(HP360) || defined(HP370)
362: if (dc->sc_flags & DMAF_PCFLUSH) {
363: PCIA();
364: dc->sc_flags &= ~DMAF_PCFLUSH;
365: }
366: #endif
367: #if defined(HP320) || defined(HP350)
368: if (dc->sc_flags & DMAF_VCFLUSH) {
369: /*
370: * 320/350s have VACs that may also need flushing.
371: * In our case we only flush the supervisor side
372: * because we know that if we are DMAing to user
373: * space, the physical pages will also be mapped
374: * in kernel space (via vmapbuf) and hence cache-
375: * inhibited by the pmap module due to the multiple
376: * mapping.
377: */
378: DCIS();
379: dc->sc_flags &= ~DMAF_VCFLUSH;
380: }
381: #endif
382: /*
383: * We may get this interrupt after a device service routine
384: * has freed the dma channel. So, ignore the intr if there's
385: * nothing on the queue.
386: */
387: dq = dmachan[unit].dq_forw;
388: if (dq != &dmachan[unit])
389: (dq->dq_driver->d_done)(dq->dq_unit);
390: }
391:
392: int
393: dmaintr()
394: {
395: register struct dma_softc *dc;
396: register int i, stat;
397: int found = 0;
398:
399: #ifdef DEBUG
400: if (dmadebug & DDB_FOLLOW)
401: printf("dmaintr\n");
402: #endif
403: for (i = 0, dc = dma_softc; i < NDMA; i++, dc++) {
404: stat = DMA_STAT(dc);
405: if ((stat & DMA_INTR) == 0)
406: continue;
407: found++;
408: #ifdef DEBUG
409: if (dmadebug & DDB_IO) {
410: if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
411: (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD))
412: printf("dmaintr: unit %d stat %x next %d\n",
413: i, stat, (dc->sc_cur-dc->sc_chain)+1);
414: }
415: if (stat & DMA_ARMED)
416: printf("dma%d: intr when armed\n", i);
417: #endif
418: if (++dc->sc_cur <= dc->sc_last) {
419: #ifdef DEBUG
420: dmatimo[i] = 1;
421: #endif
422: /*
423: * Last chain segment, disable DMA interrupt.
424: */
425: if (dc->sc_cur == dc->sc_last &&
426: (dc->sc_flags & DMAF_NOINTR))
427: dc->sc_cmd &= ~DMA_ENAB;
428: DMA_CLEAR(dc);
429: DMA_ARM(dc);
430: } else
431: dmastop(i);
432: }
433: return(found);
434: }
435:
436: #ifdef DEBUG
437: void
438: dmatimeout()
439: {
440: register int i, s;
441:
442: for (i = 0; i < NDMA; i++) {
443: s = splbio();
444: if (dmatimo[i]) {
445: if (dmatimo[i] > 1)
446: printf("dma%d: timeout #%d\n",
447: i, dmatimo[i]-1);
448: dmatimo[i]++;
449: }
450: splx(s);
451: }
452: timeout(dmatimeout, (caddr_t)0, 30 * hz);
453: }
454: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.