update from Mike Hibler
[unix-history] / 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 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)dma.c 7.1 (Berkeley) %G%
8 */
9
10/*
11 * DMA driver
12 */
13
14#include "param.h"
15#include "systm.h"
16#include "time.h"
17#include "kernel.h"
18#include "proc.h"
19#include "dmareg.h"
20#include "dmavar.h"
21#include "device.h"
22
23#include "machine/cpu.h"
24#include "machine/isr.h"
25
26extern void isrlink();
27extern void printf();
28extern void panic();
29extern void _insque();
30extern void _remque();
31extern void timeout();
32extern int splbio();
33extern void splx();
34extern u_int kvtop();
35extern void PCIA();
36
37/*
38 * The largest single request will be MAXPHYS bytes which will require
39 * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
40 * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
41 * buffer is not page aligned (+1).
42 */
43#define DMAMAXIO (MAXPHYS/NBPG+1)
44
45#define DMATIMO 15
46
47struct dma_softc {
48 struct dmadevice *sc_hwaddr;
49 struct dmaBdevice *sc_Bhwaddr;
50 int sc_type;
51 int sc_cur;
52 int sc_cmd;
53 int sc_timo;
54 int sc_count[DMAMAXIO+1];
55 char *sc_addr[DMAMAXIO+1];
56} dma_softc[NDMA];
57
58/* types */
59#define DMA_B 0
60#define DMA_C 1
61
62struct devqueue dmachan[NDMA + 1];
63int dmaintr();
64void dmatimo();
65
66#ifdef DEBUG
67int dmadebug = 0;
68#define DDB_WORD 0x01 /* same as DMAGO_WORD */
69#define DDB_LWORD 0x02 /* same as DMAGO_LWORD */
70#define DDB_FOLLOW 0x04
71#define DDB_IO 0x08
72
73long dmahits[NDMA];
74long dmamisses[NDMA];
75long dmabyte[NDMA];
76long dmaword[NDMA];
77long dmalword[NDMA];
78#endif
79
80void
81dmainit()
82{
83 register struct dmareg *dma = (struct dmareg *)DMA_BASE;
84 register struct dma_softc *dc;
85 register int i;
86 char rev;
87
88 /*
89 * Determine the DMA type.
90 * Don't know how to easily differentiate the A and B cards,
91 * so we just hope nobody has an A card (A cards will work if
92 * DMAINTLVL is set to 3).
93 */
94 if (!badbaddr((char *)&dma->dma_id[2]))
95 rev = dma->dma_id[2];
96 else {
97 rev = 'B';
98#if !defined(HP320)
99 panic("dmainit: DMA card requires hp320 support");
100#endif
101 }
102
103 dc = &dma_softc[0];
104 for (i = 0; i < NDMA; i++) {
105 dc->sc_hwaddr = (i & 1) ? &dma->dma_chan1 : &dma->dma_chan0;
106 dc->sc_Bhwaddr = (i & 1) ? &dma->dma_Bchan1 : &dma->dma_Bchan0;
107 dc->sc_type = rev == 'B' ? DMA_B : DMA_C;
108 dc++;
109 dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
110 }
111 dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i];
112 timeout(dmatimo, (caddr_t)0, DMATIMO * hz);
113
114 printf("dma: 98620%c with 2 channels, %d bit DMA\n",
115 rev, rev == 'B' ? 16 : 32);
116}
117
118int
119dmareq(dq)
120 register struct devqueue *dq;
121{
122 register int i;
123 register int chan;
124 register int s = splbio();
125
126 chan = dq->dq_ctlr;
127 i = NDMA;
128 while (--i >= 0) {
129 if ((chan & (1 << i)) == 0)
130 continue;
131 if (dmachan[i].dq_forw != &dmachan[i])
132 continue;
133 insque(dq, &dmachan[i]);
134 dq->dq_ctlr = i;
135 splx(s);
136 return(1);
137 }
138 insque(dq, dmachan[NDMA].dq_back);
139 splx(s);
140 return(0);
141}
142
143void
144dmafree(dq)
145 register struct devqueue *dq;
146{
147 int unit = dq->dq_ctlr;
148 register struct dma_softc *dc = &dma_softc[unit];
149 register struct devqueue *dn;
150 register int chan, s;
151
152 s = splbio();
153 dc->sc_timo = 0;
154 DMA_CLEAR(dc);
155 remque(dq);
156 chan = 1 << unit;
157 for (dn = dmachan[NDMA].dq_forw;
158 dn != &dmachan[NDMA]; dn = dn->dq_forw) {
159 if (dn->dq_ctlr & chan) {
160 remque((caddr_t)dn);
161 insque((caddr_t)dn, (caddr_t)dq->dq_back);
162 splx(s);
163 dn->dq_ctlr = dq->dq_ctlr;
164 (dn->dq_driver->d_start)(dn->dq_unit);
165 return;
166 }
167 }
168 splx(s);
169}
170
171void
172dmago(unit, addr, count, flags)
173 int unit;
174 register char *addr;
175 register int count;
176 register int flags;
177{
178 register struct dma_softc *dc = &dma_softc[unit];
179 register char *dmaend = NULL;
180 register int tcount, i;
181
182#ifdef DEBUG
183 if (dmadebug & DDB_FOLLOW)
184 printf("dmago(%d, %x, %x, %x)\n",
185 unit, addr, count, flags);
186 if (flags & DMAGO_LWORD)
187 dmalword[unit]++;
188 else if (flags & DMAGO_WORD)
189 dmaword[unit]++;
190 else
191 dmabyte[unit]++;
192#endif
193#if defined(HP320)
194 if (dc->sc_type == DMA_B && (flags & DMAGO_LWORD))
195 panic("dmago: no can do 32-bit DMA");
196#endif
197 /*
198 * Build the DMA chain
199 */
200 for (i = 0; i < DMAMAXIO && count; i++) {
201 dc->sc_addr[i] = (char *)kvtop(addr);
202 tcount = dc->sc_count[i] =
203 MIN(count, NBPG - ((int)addr & PGOFSET));
204 addr += dc->sc_count[i];
205 count -= tcount;
206 if (flags & (DMAGO_WORD|DMAGO_LWORD))
207 tcount >>= (flags & DMAGO_WORD) ? 1 : 2;
208 if (dc->sc_addr[i] == dmaend
209#if defined(HP320)
210 /* only 16-bit count on 98620B */
211 && (dc->sc_type != DMA_B ||
212 dc->sc_count[i-1] + tcount <= 65536)
213#endif
214 ) {
215#ifdef DEBUG
216 dmahits[unit]++;
217#endif
218 dmaend += dc->sc_count[i];
219 dc->sc_count[i-1] += tcount;
220 i--;
221 } else {
222#ifdef DEBUG
223 dmamisses[unit]++;
224#endif
225 dmaend = dc->sc_addr[i] + dc->sc_count[i];
226 dc->sc_count[i] = tcount;
227 }
228 }
229 if (count)
230 panic("dmago maxphys");
231 dc->sc_count[i] = 0;
232 dc->sc_cur = 0;
233 /*
234 * Set up the command word based on flags
235 */
236 dc->sc_cmd = DMA_ENAB | DMA_IPL(DMAINTLVL) | DMA_START;
237 if ((flags & DMAGO_READ) == 0)
238 dc->sc_cmd |= DMA_WRT;
239 if (flags & DMAGO_LWORD)
240 dc->sc_cmd |= DMA_LWORD;
241 else if (flags & DMAGO_WORD)
242 dc->sc_cmd |= DMA_WORD;
243 if (flags & DMAGO_PRI)
244 dc->sc_cmd |= DMA_PRI;
245
246 /*
247 * We should be able to skip the dma completion interrupt
248 * if we only have one segment in the chain since many
249 * devices generate their own completion interrupt.
250 * However, on a 370 we have to take the interrupt on
251 * read transfers to invalidate the external cache.
252 */
253 if ((flags & DMAGO_NOINT) && i == 1
254#if defined(HP370)
255 && ((flags & DMAGO_READ) == 0 || ectype != EC_PHYS)
256#endif
257 )
258 dc->sc_cmd &= ~DMA_ENAB;
259#ifdef DEBUG
260#if defined(HP320)
261 /* would this hurt? */
262 if (dc->sc_type == DMA_B)
263 dc->sc_cmd &= ~DMA_START;
264#endif
265 if (dmadebug & DDB_IO)
266 if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
267 (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD)) {
268 printf("dmago: cmd %x\n", dc->sc_cmd);
269 for (i = 0; dc->sc_count[i]; i++)
270 printf(" %d: %d@%x\n",
271 i, dc->sc_count[i], dc->sc_addr[i]);
272 }
273#endif
274
275 /*
276 * Load and arm the channel
277 */
278 dc->sc_timo = 1;
279 DMA_ARM(dc, 0);
280}
281
282void
283dmastop(unit)
284 register int unit;
285{
286 register struct dma_softc *dc = &dma_softc[unit];
287 register struct devqueue *dq;
288
289#ifdef DEBUG
290 if (dmadebug & DDB_FOLLOW)
291 printf("dmastop(%d)\n", unit);
292#endif
293 dc->sc_timo = 0;
294 DMA_CLEAR(dc);
295
296 /*
297 * We may get this interrupt after a device service routine
298 * has freed the dma channel. So, ignore the intr if there's
299 * nothing on the queue.
300 */
301 dq = dmachan[unit].dq_forw;
302 if (dq != &dmachan[unit]) {
303#if defined(HP370)
304 /*
305 * The 370 has an 64k external physical address cache.
306 * In theory, we should only need to flush it when
307 * DMAing to memory.
308 */
309 if (ectype == EC_PHYS && (dc->sc_cmd & DMA_WRT) == 0)
310 PCIA();
311#endif
312 (dq->dq_driver->d_done)(dq->dq_unit);
313 }
314}
315
316int
317dmaintr()
318{
319 register struct dma_softc *dc;
320 register int i, j, stat;
321 int found = 0;
322
323#ifdef DEBUG
324 if (dmadebug & DDB_FOLLOW)
325 printf("dmaintr\n");
326#endif
327 for (i = 0, dc = dma_softc; i < NDMA; i++, dc++) {
328 stat = DMA_STAT(dc);
329 if ((stat & DMA_INTR) == 0)
330 continue;
331 found++;
332#ifdef DEBUG
333 if (dmadebug & DDB_IO) {
334 if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) ||
335 (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD))
336 printf("dmaintr: unit %d stat %x next %d\n",
337 i, stat, dc->sc_cur+1);
338 }
339 if (stat & DMA_ARMED)
340 printf("dma%d: intr when armed\n", i);
341#endif
342 j = ++dc->sc_cur;
343 if (j < DMAMAXIO && dc->sc_count[j]) {
344 dc->sc_timo = 1;
345 DMA_CLEAR(dc);
346 DMA_ARM(dc, j);
347 } else
348 dmastop(i);
349 }
350 return(found);
351}
352
353void
354dmatimo()
355{
356 register int i, s;
357 register struct dma_softc *dc = &dma_softc[0];
358
359 for (i = 0; i < NDMA; i++, dc++) {
360 s = splbio();
361 if (dc->sc_timo) {
362 if (dc->sc_timo == 1)
363 dc->sc_timo++;
364 else
365 dmastop(i);
366 }
367 splx(s);
368 }
369 timeout(dmatimo, (caddr_t)0, DMATIMO * hz);
370}