Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / sys / hp300 / dev / dma.c
CommitLineData
60f56dfc
KM
1/*
2 * Copyright (c) 1982, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
af359dea
C
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.
60f56dfc 20 *
af359dea
C
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
60f56dfc
KM
34 */
35
36/*
37 * DMA driver
38 */
39
af359dea
C
40#include "param.h"
41#include "systm.h"
42#include "time.h"
43#include "kernel.h"
44#include "proc.h"
45
60f56dfc
KM
46#include "dmareg.h"
47#include "dmavar.h"
48#include "device.h"
49
b28b3a13
KB
50#include "../include/cpu.h"
51#include "../hp300/isr.h"
60f56dfc
KM
52
53extern void isrlink();
60f56dfc
KM
54extern void _insque();
55extern void _remque();
56extern void timeout();
60f56dfc
KM
57extern u_int kvtop();
58extern 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
22d09b27
KM
68struct dma_chain {
69 int dc_count;
70 char *dc_addr;
71};
60f56dfc
KM
72
73struct dma_softc {
22d09b27
KM
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];
60f56dfc
KM
82} dma_softc[NDMA];
83
84/* types */
85#define DMA_B 0
86#define DMA_C 1
87
22d09b27
KM
88/* flags */
89#define DMAF_PCFLUSH 0x01
90#define DMAF_VCFLUSH 0x02
91#define DMAF_NOINTR 0x04
92
60f56dfc
KM
93struct devqueue dmachan[NDMA + 1];
94int dmaintr();
60f56dfc
KM
95
96#ifdef DEBUG
97int 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
22d09b27
KM
103void dmatimeout();
104int dmatimo[NDMA];
105
60f56dfc
KM
106long dmahits[NDMA];
107long dmamisses[NDMA];
108long dmabyte[NDMA];
109long dmaword[NDMA];
110long dmalword[NDMA];
111#endif
112
113void
114dmainit()
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];
22d09b27
KM
145#ifdef DEBUG
146 /* make sure timeout is really not needed */
147 timeout(dmatimeout, 0, 30 * hz);
148#endif
60f56dfc
KM
149
150 printf("dma: 98620%c with 2 channels, %d bit DMA\n",
151 rev, rev == 'B' ? 16 : 32);
152}
153
154int
155dmareq(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
179void
180dmafree(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();
22d09b27
KM
189#ifdef DEBUG
190 dmatimo[unit] = 0;
191#endif
60f56dfc 192 DMA_CLEAR(dc);
22d09b27
KM
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
60f56dfc
KM
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
233void
234dmago(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];
22d09b27 241 register struct dma_chain *dcp;
60f56dfc 242 register char *dmaend = NULL;
22d09b27 243 register int tcount;
60f56dfc 244
22d09b27
KM
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
60f56dfc
KM
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]++;
60f56dfc
KM
261#endif
262 /*
263 * Build the DMA chain
264 */
22d09b27
KM
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;
60f56dfc 271 count -= tcount;
22d09b27
KM
272 if (flags & DMAGO_LWORD)
273 tcount >>= 2;
274 else if (flags & DMAGO_WORD)
275 tcount >>= 1;
276 if (dcp->dc_addr == dmaend
60f56dfc
KM
277#if defined(HP320)
278 /* only 16-bit count on 98620B */
279 && (dc->sc_type != DMA_B ||
22d09b27 280 (dcp-1)->dc_count + tcount <= 65536)
60f56dfc
KM
281#endif
282 ) {
283#ifdef DEBUG
284 dmahits[unit]++;
285#endif
22d09b27
KM
286 dmaend += dcp->dc_count;
287 (--dcp)->dc_count += tcount;
60f56dfc
KM
288 } else {
289#ifdef DEBUG
290 dmamisses[unit]++;
291#endif
22d09b27
KM
292 dmaend = dcp->dc_addr + dcp->dc_count;
293 dcp->dc_count = tcount;
60f56dfc
KM
294 }
295 }
22d09b27
KM
296 dc->sc_cur = dc->sc_chain;
297 dc->sc_last = --dcp;
298 dc->sc_flags = 0;
60f56dfc
KM
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;
22d09b27 311#if defined(HP360) || defined(HP370)
60f56dfc 312 /*
22d09b27
KM
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).
60f56dfc 315 */
22d09b27
KM
316 if (ectype == EC_PHYS && (flags & DMAGO_READ))
317 dc->sc_flags |= DMAF_PCFLUSH;
60f56dfc 318#endif
22d09b27
KM
319#if defined(HP320) || defined(HP350)
320 if (ectype == EC_VIRT && (flags & DMAGO_READ))
321 dc->sc_flags |= DMAF_VCFLUSH;
60f56dfc 322#endif
22d09b27
KM
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
60f56dfc
KM
334 if (dmadebug & DDB_IO)
335 if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
336 (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD)) {
22d09b27
KM
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);
60f56dfc 342 }
22d09b27 343 dmatimo[unit] = 1;
60f56dfc 344#endif
99db9dbe 345 DMA_ARM(dc);
60f56dfc
KM
346}
347
348void
349dmastop(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);
22d09b27 358 dmatimo[unit] = 0;
60f56dfc 359#endif
60f56dfc 360 DMA_CLEAR(dc);
22d09b27
KM
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
60f56dfc
KM
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;
22d09b27 388 if (dq != &dmachan[unit])
60f56dfc 389 (dq->dq_driver->d_done)(dq->dq_unit);
60f56dfc
KM
390}
391
392int
393dmaintr()
394{
395 register struct dma_softc *dc;
22d09b27 396 register int i, stat;
60f56dfc
KM
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",
22d09b27 413 i, stat, (dc->sc_cur-dc->sc_chain)+1);
60f56dfc
KM
414 }
415 if (stat & DMA_ARMED)
416 printf("dma%d: intr when armed\n", i);
417#endif
22d09b27
KM
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;
60f56dfc 428 DMA_CLEAR(dc);
99db9dbe 429 DMA_ARM(dc);
60f56dfc
KM
430 } else
431 dmastop(i);
432 }
433 return(found);
434}
435
22d09b27 436#ifdef DEBUG
60f56dfc 437void
22d09b27 438dmatimeout()
60f56dfc
KM
439{
440 register int i, s;
60f56dfc 441
22d09b27 442 for (i = 0; i < NDMA; i++) {
60f56dfc 443 s = splbio();
22d09b27
KM
444 if (dmatimo[i]) {
445 if (dmatimo[i] > 1)
446 printf("dma%d: timeout #%d\n",
447 i, dmatimo[i]-1);
448 dmatimo[i]++;
60f56dfc
KM
449 }
450 splx(s);
451 }
22d09b27 452 timeout(dmatimeout, (caddr_t)0, 30 * hz);
60f56dfc 453}
22d09b27 454#endif