|
|
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
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 "vm/vm.h"
47: #include "vm/vm_kern.h"
48: #include "vm/vm_page.h"
49: #include "vm/vm_statistics.h"
50: #include "machine/pmap.h"
51:
52: #include "device.h"
53: #include "dmareg.h"
54: #include "dmavar.h"
55:
56: #include "../include/cpu.h"
57:
58: extern void isrlink();
59: extern void _insque();
60: extern void _remque();
61: extern void timeout();
62: extern u_int kvtop();
63:
64: /*
65: * The largest single request will be MAXPHYS bytes which will require
66: * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
67: * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
68: * buffer is not page aligned (+1).
69: */
70: #define DMAMAXIO (MAXPHYS/NBPG+1)
71:
72: struct dma_chain {
73: int dc_count;
74: char *dc_addr;
75: };
76:
77: struct dma_softc {
78: struct sdmac *sc_hwaddr;
79: char sc_dmaflags;
80: u_short sc_cmd;
81: struct dma_chain *sc_cur;
82: struct dma_chain *sc_last;
83: struct dma_chain sc_chain[DMAMAXIO];
84: } dma_softc;
85:
86: #define DMAF_NOINTR 0x01
87:
88: struct devqueue dmachan[NDMA + 1];
89: int dmaintr();
90:
91: /* because keybord and dma share same interrupt priority... */
92: int dma_initialized = 0;
93: /* if not in int-mode, don't pay attention for possible scsi interrupts */
94: int scsi_int_mode = 0;
95:
96: #ifdef DEBUG
97: #define DDB_FOLLOW 0x04
98: #define DDB_IO 0x08
99: int dmadebug = 0;
100:
101: void dmatimeout();
102: int dmatimo;
103:
104: long dmahits;
105: long dmamisses;
106: long dmabyte;
107: long dmaword;
108: long dmalword;
109: #endif
110:
111: /* This setup function is also used by the SCSI driver, as it shares
112: the same chip */
113:
114: struct sdmac *SDMAC_address = 0;
115: volatile void *SCSI_address = 0;
116:
117: void
118: SDMAC_setup ()
119: {
120: if (! SDMAC_address)
121: {
122: extern u_int SCSIADDR; /* setup in amiga_init.c. Should really be mapped here... */
123: SDMAC_address = (struct sdmac *) SCSIADDR;
124: SCSI_address = &SDMAC_address->SASR;
125: }
126: }
127:
128:
129: void
130: dmainit()
131: {
132: register struct sdmac *dma;
133: register int i;
134: char rev;
135:
136: SDMAC_setup ();
137: dma = SDMAC_address;
138:
139: /* make sure interrupts are disabled while we later on reset the scsi-chip */
140: dma->CNTR = CNTR_PDMD;
141: dma->DAWR = DAWR_A3000;
142: dma_softc.sc_dmaflags = 0;
143: dma_softc.sc_cmd = 0;
144: dma_softc.sc_hwaddr = dma;
145: dmachan[0].dq_forw = dmachan[0].dq_back = &dmachan[0];
146: dmachan[1].dq_forw = dmachan[1].dq_back = &dmachan[1];
147: #ifdef DEBUG
148: /* make sure timeout is really not needed */
149: timeout(dmatimeout, 0, 30 * hz);
150: #endif
151:
152: printf("dma: A3000 %d bit DMA\n", 32); /* XXX */
153: dma_initialized = 1;
154: }
155:
156: int
157: dmareq(dq)
158: register struct devqueue *dq;
159: {
160: register int s = splbio();
161:
162: if (dmachan[0].dq_forw == &dmachan[0])
163: {
164: insque(dq, &dmachan[0]);
165: dq->dq_ctlr = 0;
166: splx(s);
167: return 1;
168: }
169:
170: insque (dq, dmachan[1].dq_back);
171: splx(s);
172: return(0);
173: }
174:
175: void
176: dmafree(dq)
177: register struct devqueue *dq;
178: {
179: register struct dma_softc *dc = &dma_softc;
180: register struct devqueue *dn;
181: register int s;
182:
183: s = splbio();
184: #ifdef DEBUG
185: dmatimo = 0;
186: #endif
187: if (dc->sc_cmd)
188: {
189: if ((dc->sc_cmd & (CNTR_TCEN | CNTR_DDIR)) == 0)
190: {
191: /* only FLUSH if terminal count not enabled, and reading from peripheral */
192: dc->sc_hwaddr->FLUSH = 1;
193: while (! (dc->sc_hwaddr->ISTR & ISTR_FE_FLG)) ;
194: }
195: dc->sc_hwaddr->CINT = 1; /* clear possible interrupt */
196: dc->sc_hwaddr->SP_DMA = 1; /* stop dma */
197: dc->sc_cmd = 0;
198: }
199: dc->sc_hwaddr->CNTR = CNTR_PDMD; /* disable interrupts from dma/scsi */
200: scsi_int_mode = 0;
201:
202: remque(dq);
203: for (dn = dmachan[1].dq_forw;
204: dn != &dmachan[1];
205: dn = dn->dq_forw)
206: {
207: remque ((caddr_t) dn);
208: insque ((caddr_t) dn, (caddr_t) dq->dq_back);
209: splx(s);
210: dn->dq_ctlr = dq->dq_ctlr;
211: (dn->dq_driver->d_start)(0);
212: return;
213: }
214:
215: splx(s);
216: }
217:
218: int
219: dmago(addr, count, flags)
220: register char *addr;
221: register int count;
222: register int flags;
223: {
224: register struct dma_softc *dc = &dma_softc;
225: register struct dma_chain *dcp;
226: register char *dmaend = NULL;
227: register int tcount;
228:
229: if (count > MAXPHYS)
230: panic("dmago: count > MAXPHYS");
231: #ifdef DEBUG
232: if (dmadebug & DDB_FOLLOW)
233: printf("dmago(%x, %x, %x)\n", addr, count, flags);
234: #endif
235: /*
236: * Build the DMA chain
237: */
238: for (dcp = dc->sc_chain; count > 0; dcp++)
239: {
240: #ifdef DEBUG
241: if (! pmap_extract(pmap_kernel(), (vm_offset_t)addr))
242: panic ("dmago: no physical page for address!");
243: #endif
244:
245: dcp->dc_addr = (char *) kvtop(addr);
246: if (count < (tcount = NBPG - ((int)addr & PGOFSET)))
247: tcount = count;
248: dcp->dc_count = tcount;
249: addr += tcount;
250: count -= tcount;
251: tcount >>= 1; /* number of words (the sdmac wants 16bit values here) */
252: if (dcp->dc_addr == dmaend)
253: {
254: #ifdef DEBUG
255: dmahits++;
256: #endif
257: dmaend += dcp->dc_count;
258: (--dcp)->dc_count += tcount;
259: }
260: else
261: {
262: #ifdef DEBUG
263: dmamisses++;
264: #endif
265: dmaend = dcp->dc_addr + dcp->dc_count;
266: dcp->dc_count = tcount;
267: }
268: }
269:
270: dc->sc_cur = dc->sc_chain;
271: dc->sc_last = --dcp;
272: dc->sc_dmaflags = 0;
273: /*
274: * Set up the command word based on flags
275: */
276: dc->sc_cmd = CNTR_PDMD | CNTR_INTEN;
277: if ((flags & DMAGO_READ) == 0)
278: dc->sc_cmd |= CNTR_DDIR;
279: #ifdef DEBUG
280: if (dmadebug & DDB_IO)
281: {
282: printf("dmago: cmd %x, flags %x\n",
283: dc->sc_cmd, dc->sc_dmaflags);
284: for (dcp = dc->sc_chain; dcp <= dc->sc_last; dcp++)
285: printf(" %d: %d@%x\n", dcp-dc->sc_chain,
286: dcp->dc_count, dcp->dc_addr);
287: }
288: dmatimo = 1;
289: #endif
290:
291: dc->sc_hwaddr->CNTR = dc->sc_cmd;
292: scsi_int_mode = 1;
293: dc->sc_hwaddr->ACR = (u_int) dc->sc_cur->dc_addr;
294: dc->sc_hwaddr->ST_DMA = 1;
295:
296: return dc->sc_cur->dc_count << 1;
297: }
298:
299: void
300: dmastop()
301: {
302: register struct dma_softc *dc = &dma_softc;
303: register struct devqueue *dq;
304: int s;
305:
306: #ifdef DEBUG
307: if (dmadebug & DDB_FOLLOW)
308: printf("dmastop()\n");
309: dmatimo = 0;
310: #endif
311: if (dc->sc_cmd)
312: {
313: s = splbio ();
314: if ((dc->sc_cmd & (CNTR_TCEN | CNTR_DDIR)) == 0)
315: {
316: /* only FLUSH if terminal count not enabled, and reading from peripheral */
317: dc->sc_hwaddr->FLUSH = 1;
318: while (! (dc->sc_hwaddr->ISTR & ISTR_FE_FLG)) ;
319: }
320: dc->sc_hwaddr->CINT = 1; /* clear possible interrupt */
321: dc->sc_hwaddr->SP_DMA = 1; /* stop dma */
322: dc->sc_cmd = 0;
323: splx (s);
324: }
325:
326: /*
327: * We may get this interrupt after a device service routine
328: * has freed the dma channel. So, ignore the intr if there's
329: * nothing on the queue.
330: */
331: dq = dmachan[0].dq_forw;
332: if (dq != &dmachan[0])
333: (dq->dq_driver->d_done)(0);
334: }
335:
336: int
337: dmaintr()
338: {
339: register struct dma_softc *dc;
340: register int i, stat;
341: int found = 0;
342:
343: if (! dma_initialized)
344: return 0;
345:
346: dc = &dma_softc;
347: stat = dc->sc_hwaddr->ISTR;
348:
349: /* if no interrupt from this device, return quickly */
350: if (! (stat & (ISTR_INT_F|ISTR_INT_P)))
351: return 0;
352:
353: #ifdef DEBUG
354: if (dmadebug & DDB_FOLLOW)
355: printf("dmaintr (0x%x)\n", stat);
356: #endif
357:
358: /* both, SCSI and DMA interrupts arrive here. I chose arbitrarily that
359: DMA interrupts should have higher precedence than SCSI interrupts. */
360:
361: if (stat & ISTR_E_INT)
362: {
363: found++;
364:
365: printf ("DMAINTR should no longer be entered!!\n");
366:
367:
368: /* End-of-process interrupt, means the DMA Terminal Counter reached
369: 0, and we have to reload it. SCSI transfer should not be interrupted
370: by this event (we'll see..) */
371:
372: #ifdef DEBUG
373: if (dmadebug & DDB_IO)
374: {
375: printf("dmaintr: stat %x next %d\n",
376: stat, (dc->sc_cur-dc->sc_chain)+1);
377: }
378: #endif
379: if (++dc->sc_cur <= dc->sc_last)
380: {
381: #ifdef DEBUG
382: dmatimo = 1;
383: #endif
384: /*
385: * Last chain segment, disable DMA interrupt.
386: */
387: if (dc->sc_cur == dc->sc_last && (dc->sc_dmaflags & DMAF_NOINTR))
388: dc->sc_cmd &= ~CNTR_TCEN;
389:
390: dc->sc_hwaddr->CINT = 1; /* clear possible interrupt */
391: dc->sc_hwaddr->CNTR = dc->sc_cmd;
392: dc->sc_hwaddr->ACR = (u_int) dc->sc_cur->dc_addr;
393: #ifndef DONT_WTC
394: if (dc->sc_cmd & CNTR_TCEN)
395: dc->sc_hwaddr->WTC = dc->sc_cur->dc_count;
396: #endif
397: dc->sc_hwaddr->ST_DMA = 1;
398: }
399: else
400: dmastop ();
401:
402: /* check for SCSI ints in the same go and eventually save an interrupt */
403: }
404:
405: if (scsi_int_mode && (stat & ISTR_INTS))
406: return found + scsiintr (0);
407:
408: return found;
409: }
410:
411:
412: int
413: dmanext ()
414: {
415: register struct dma_softc *dc;
416: register int i, stat;
417: int found = 0;
418:
419: dc = &dma_softc;
420:
421: #ifdef DEBUG
422: if (dmadebug & DDB_IO)
423: {
424: printf("dmanext: next %d\n", (dc->sc_cur-dc->sc_chain)+1);
425: }
426: #endif
427: if (++dc->sc_cur <= dc->sc_last)
428: {
429: #ifdef DEBUG
430: dmatimo = 1;
431: #endif
432: if ((dc->sc_cmd & (CNTR_TCEN | CNTR_DDIR)) == 0)
433: {
434: /* only FLUSH if terminal count not enabled, and reading from peripheral */
435: dc->sc_hwaddr->FLUSH = 1;
436: while (! (dc->sc_hwaddr->ISTR & ISTR_FE_FLG)) ;
437: }
438: dc->sc_hwaddr->CINT = 1; /* clear possible interrupt */
439: dc->sc_hwaddr->SP_DMA = 1; /* stop dma */
440: dc->sc_hwaddr->CNTR = dc->sc_cmd;
441: dc->sc_hwaddr->ACR = (u_int) dc->sc_cur->dc_addr;
442: dc->sc_hwaddr->ST_DMA = 1;
443:
444: return dc->sc_cur->dc_count << 1;
445: }
446: else
447: {
448: /* shouldn't happen !! */
449: printf ("dmanext at end !!!\n");
450: dmastop ();
451: return 0;
452: }
453: }
454:
455:
456:
457:
458: #ifdef DEBUG
459: void
460: dmatimeout()
461: {
462: register int s;
463:
464: s = splbio();
465: if (dmatimo)
466: {
467: if (dmatimo > 1)
468: printf("dma: timeout #%d\n", dmatimo-1);
469: dmatimo++;
470: }
471: splx(s);
472: timeout (dmatimeout, (caddr_t)0, 30 * hz);
473: }
474: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.