Commit | Line | Data |
---|---|---|
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 | ||
26 | extern void isrlink(); | |
27 | extern void printf(); | |
28 | extern void panic(); | |
29 | extern void _insque(); | |
30 | extern void _remque(); | |
31 | extern void timeout(); | |
32 | extern int splbio(); | |
33 | extern void splx(); | |
34 | extern u_int kvtop(); | |
35 | extern 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 | ||
47 | struct 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 | ||
62 | struct devqueue dmachan[NDMA + 1]; | |
63 | int dmaintr(); | |
64 | void dmatimo(); | |
65 | ||
66 | #ifdef DEBUG | |
67 | int 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 | ||
73 | long dmahits[NDMA]; | |
74 | long dmamisses[NDMA]; | |
75 | long dmabyte[NDMA]; | |
76 | long dmaword[NDMA]; | |
77 | long dmalword[NDMA]; | |
78 | #endif | |
79 | ||
80 | void | |
81 | dmainit() | |
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 | ||
118 | int | |
119 | dmareq(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 | ||
143 | void | |
144 | dmafree(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 | ||
171 | void | |
172 | dmago(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 | ||
282 | void | |
283 | dmastop(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 | ||
316 | int | |
317 | dmaintr() | |
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 | ||
353 | void | |
354 | dmatimo() | |
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 | } |