nextdma.c revision 1.21 1 /* $NetBSD: nextdma.c,v 1.21 2000/01/12 19:18:00 dbj Exp $ */
2 /*
3 * Copyright (c) 1998 Darrin B. Jewell
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Darrin B. Jewell
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/mbuf.h>
35 #include <sys/syslog.h>
36 #include <sys/socket.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/ioctl.h>
40 #include <sys/errno.h>
41
42 #include <machine/autoconf.h>
43 #include <machine/cpu.h>
44 #include <machine/intr.h>
45
46 #include <m68k/cacheops.h>
47
48 #include <next68k/next68k/isr.h>
49
50 #define _NEXT68K_BUS_DMA_PRIVATE
51 #include <machine/bus.h>
52
53 #include "nextdmareg.h"
54 #include "nextdmavar.h"
55
56 #if 1
57 #define ND_DEBUG
58 #endif
59
60 #if defined(ND_DEBUG)
61 int nextdma_debug = 0;
62 #define DPRINTF(x) if (nextdma_debug) printf x;
63 #else
64 #define DPRINTF(x)
65 #endif
66
67 void next_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
68 bus_size_t, int));
69 int next_dma_continue __P((struct nextdma_config *));
70 void next_dma_rotate __P((struct nextdma_config *));
71
72 void next_dma_setup_cont_regs __P((struct nextdma_config *));
73 void next_dma_setup_curr_regs __P((struct nextdma_config *));
74 void next_dma_finish_xfer __P((struct nextdma_config *));
75
76 void
77 nextdma_config(nd)
78 struct nextdma_config *nd;
79 {
80 /* Initialize the dma_tag. As a hack, we currently
81 * put the dma tag in the structure itself. It shouldn't be there.
82 */
83
84 {
85 bus_dma_tag_t t;
86 t = &nd->_nd_dmat;
87 t->_cookie = nd;
88 t->_dmamap_create = _bus_dmamap_create;
89 t->_dmamap_destroy = _bus_dmamap_destroy;
90 t->_dmamap_load = _bus_dmamap_load_direct;
91 t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
92 t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
93 t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
94 t->_dmamap_unload = _bus_dmamap_unload;
95 t->_dmamap_sync = _bus_dmamap_sync;
96
97 t->_dmamem_alloc = _bus_dmamem_alloc;
98 t->_dmamem_free = _bus_dmamem_free;
99 t->_dmamem_map = _bus_dmamem_map;
100 t->_dmamem_unmap = _bus_dmamem_unmap;
101 t->_dmamem_mmap = _bus_dmamem_mmap;
102
103 nd->nd_dmat = t;
104 }
105
106 nextdma_init(nd);
107
108 isrlink_autovec(nextdma_intr, nd, NEXT_I_IPL(nd->nd_intr), 10);
109 INTR_ENABLE(nd->nd_intr);
110 }
111
112 void
113 nextdma_init(nd)
114 struct nextdma_config *nd;
115 {
116 DPRINTF(("DMA init ipl (%ld) intr(0x%b)\n",
117 NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
118
119 nd->_nd_map = NULL;
120 nd->_nd_idx = 0;
121 nd->_nd_map_cont = NULL;
122 nd->_nd_idx_cont = 0;
123
124 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 0);
125 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
126 DMACSR_RESET | DMACSR_INITBUF);
127
128 next_dma_setup_curr_regs(nd);
129 next_dma_setup_cont_regs(nd);
130
131 #if defined(DIAGNOSTIC)
132 {
133 u_long state;
134 state = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR);
135
136 #if 1
137 /* mourning (a 25Mhz 68040 mono slab) appears to set BUSEXC
138 * milo (a 25Mhz 68040 mono cube) didn't have this problem
139 * Darrin B. Jewell <jewell (at) mit.edu> Mon May 25 07:53:05 1998
140 */
141 state &= (DMACSR_COMPLETE | DMACSR_SUPDATE | DMACSR_ENABLE);
142 #else
143 state &= (DMACSR_BUSEXC | DMACSR_COMPLETE |
144 DMACSR_SUPDATE | DMACSR_ENABLE);
145 #endif
146 if (state) {
147 next_dma_print(nd);
148 panic("DMA did not reset");
149 }
150 }
151 #endif
152 }
153
154
155 void
156 nextdma_reset(nd)
157 struct nextdma_config *nd;
158 {
159 int s;
160 s = spldma();
161
162 DPRINTF(("DMA reset\n"));
163
164 #if (defined(ND_DEBUG))
165 if (nextdma_debug) next_dma_print(nd);
166 #endif
167
168 /* @@@ clean up dma maps */
169
170 nextdma_init(nd);
171 splx(s);
172 }
173
174 /****************************************************************/
175
176
177 /* Call the completed and continue callbacks to try to fill
178 * in the dma continue buffers.
179 */
180 void
181 next_dma_rotate(nd)
182 struct nextdma_config *nd;
183 {
184
185 DPRINTF(("DMA next_dma_rotate()\n"));
186
187 /* Rotate the continue map into the current map */
188 nd->_nd_map = nd->_nd_map_cont;
189 nd->_nd_idx = nd->_nd_idx_cont;
190
191 if ((!nd->_nd_map_cont) ||
192 ((nd->_nd_map_cont) &&
193 (++nd->_nd_idx_cont >= nd->_nd_map_cont->dm_nsegs))) {
194 if (nd->nd_continue_cb) {
195 nd->_nd_map_cont = (*nd->nd_continue_cb)(nd->nd_cb_arg);
196 } else {
197 nd->_nd_map_cont = 0;
198 }
199 nd->_nd_idx_cont = 0;
200 }
201
202 #ifdef DIAGNOSTIC
203 if (nd->_nd_map) {
204 nd->_nd_map->dm_segs[nd->_nd_idx].ds_xfer_len = 0x1234beef;
205 }
206 #endif
207
208 #ifdef DIAGNOSTIC
209 if (nd->_nd_map_cont) {
210 if (!DMA_BEGINALIGNED(nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr)) {
211 next_dma_print(nd);
212 panic("DMA request unaligned at start\n");
213 }
214 if (!DMA_ENDALIGNED(nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr +
215 nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len)) {
216 next_dma_print(nd);
217 panic("DMA request unaligned at end\n");
218 }
219 }
220 #endif
221
222 }
223
224 void
225 next_dma_setup_cont_regs(nd)
226 struct nextdma_config *nd;
227 {
228 bus_addr_t dd_start;
229 bus_addr_t dd_stop;
230 bus_addr_t dd_saved_start;
231 bus_addr_t dd_saved_stop;
232
233 DPRINTF(("DMA next_dma_setup_regs()\n"));
234
235 if (nd->_nd_map_cont) {
236 dd_start = nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr;
237 dd_stop = (nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr +
238 nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len);
239
240 if (nd->nd_intr == NEXT_I_ENETX_DMA) {
241 dd_stop |= 0x80000000; /* Ethernet transmit needs secret magic */
242 }
243 } else {
244 dd_start = 0xdeadbeef;
245 dd_stop = 0xdeadbeef;
246 }
247
248 dd_saved_start = dd_start;
249 dd_saved_stop = dd_stop;
250
251 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_START, dd_start);
252 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_STOP, dd_stop);
253 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START, dd_saved_start);
254 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP, dd_saved_stop);
255
256 #ifdef DIAGNOSTIC
257 if ((bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_START) != dd_start) ||
258 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_STOP) != dd_stop) ||
259 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START) != dd_saved_start) ||
260 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP) != dd_saved_stop)) {
261 next_dma_print(nd);
262 panic("DMA failure writing to continue regs");
263 }
264 #endif
265 }
266
267 void
268 next_dma_setup_curr_regs(nd)
269 struct nextdma_config *nd;
270 {
271 bus_addr_t dd_next;
272 bus_addr_t dd_limit;
273 bus_addr_t dd_saved_next;
274 bus_addr_t dd_saved_limit;
275
276 DPRINTF(("DMA next_dma_setup_curr_regs()\n"));
277
278
279 if (nd->_nd_map) {
280 dd_next = nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr;
281 dd_limit = (nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr +
282 nd->_nd_map->dm_segs[nd->_nd_idx].ds_len);
283 if (nd->nd_intr == NEXT_I_ENETX_DMA) {
284 dd_limit |= 0x80000000; /* Ethernet transmit needs secret magic */
285 }
286 } else {
287 dd_next = 0xdeadbeef;
288 dd_limit = 0xdeadbeef;
289 }
290
291 dd_saved_next = dd_next;
292 dd_saved_limit = dd_limit;
293
294 if (nd->nd_intr == NEXT_I_ENETX_DMA) {
295 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF, dd_next);
296 } else {
297 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT, dd_next);
298 }
299 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT, dd_limit);
300 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT, dd_saved_next);
301 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT, dd_saved_limit);
302
303 #ifdef DIAGNOSTIC
304 if ((bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF) != dd_next) ||
305 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT) != dd_next) ||
306 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT) != dd_limit) ||
307 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT) != dd_saved_next) ||
308 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT) != dd_saved_limit)) {
309 next_dma_print(nd);
310 panic("DMA failure writing to current regs");
311 }
312 #endif
313 }
314
315
316 /* This routine is used for debugging */
317
318 void
319 next_dma_print(nd)
320 struct nextdma_config *nd;
321 {
322 u_long dd_csr;
323 u_long dd_next;
324 u_long dd_next_initbuf;
325 u_long dd_limit;
326 u_long dd_start;
327 u_long dd_stop;
328 u_long dd_saved_next;
329 u_long dd_saved_limit;
330 u_long dd_saved_start;
331 u_long dd_saved_stop;
332
333 /* Read all of the registers before we print anything out,
334 * in case something changes
335 */
336 dd_csr = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR);
337 dd_next = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT);
338 dd_next_initbuf = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF);
339 dd_limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT);
340 dd_start = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_START);
341 dd_stop = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_STOP);
342 dd_saved_next = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT);
343 dd_saved_limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT);
344 dd_saved_start = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START);
345 dd_saved_stop = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP);
346
347 printf("NDMAP: *intrstat = 0x%b\n",
348 (*(volatile u_long *)IIOV(NEXT_P_INTRSTAT)),NEXT_INTR_BITS);
349 printf("NDMAP: *intrmask = 0x%b\n",
350 (*(volatile u_long *)IIOV(NEXT_P_INTRMASK)),NEXT_INTR_BITS);
351
352 /* NDMAP is Next DMA Print (really!) */
353
354 if (nd->_nd_map) {
355 printf("NDMAP: nd->_nd_map->dm_mapsize = %d\n",
356 nd->_nd_map->dm_mapsize);
357 printf("NDMAP: nd->_nd_map->dm_nsegs = %d\n",
358 nd->_nd_map->dm_nsegs);
359 printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_addr = 0x%08lx\n",
360 nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr);
361 printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_len = %d\n",
362 nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_len);
363 printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_xfer_len = %d\n",
364 nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_xfer_len);
365 } else {
366 printf("NDMAP: nd->_nd_map = NULL\n");
367 }
368 if (nd->_nd_map_cont) {
369 printf("NDMAP: nd->_nd_map_cont->dm_mapsize = %d\n",
370 nd->_nd_map_cont->dm_mapsize);
371 printf("NDMAP: nd->_nd_map_cont->dm_nsegs = %d\n",
372 nd->_nd_map_cont->dm_nsegs);
373 printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_addr = 0x%08lx\n",
374 nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr);
375 printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_len = %d\n",
376 nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len);
377 printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_xfer_len = %d\n",
378 nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_xfer_len);
379 } else {
380 printf("NDMAP: nd->_nd_map_cont = NULL\n");
381 }
382
383 printf("NDMAP: dd->dd_csr = 0x%b\n", dd_csr, DMACSR_BITS);
384 printf("NDMAP: dd->dd_saved_next = 0x%08x\n", dd_saved_next);
385 printf("NDMAP: dd->dd_saved_limit = 0x%08x\n", dd_saved_limit);
386 printf("NDMAP: dd->dd_saved_start = 0x%08x\n", dd_saved_start);
387 printf("NDMAP: dd->dd_saved_stop = 0x%08x\n", dd_saved_stop);
388 printf("NDMAP: dd->dd_next = 0x%08x\n", dd_next);
389 printf("NDMAP: dd->dd_next_initbuf = 0x%08x\n", dd_next_initbuf);
390 printf("NDMAP: dd->dd_limit = 0x%08x\n", dd_limit);
391 printf("NDMAP: dd->dd_start = 0x%08x\n", dd_start);
392 printf("NDMAP: dd->dd_stop = 0x%08x\n", dd_stop);
393
394 printf("NDMAP: interrupt ipl (%ld) intr(0x%b)\n",
395 NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS);
396 }
397
398 /****************************************************************/
399 void
400 next_dma_finish_xfer(nd)
401 struct nextdma_config *nd;
402 {
403 bus_addr_t onext;
404 bus_addr_t olimit;
405 bus_addr_t slimit;
406
407 onext = nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr;
408 olimit = onext + nd->_nd_map->dm_segs[nd->_nd_idx].ds_len;
409
410 if ((nd->_nd_map_cont == NULL) && (nd->_nd_idx+1 == nd->_nd_map->dm_nsegs)) {
411 slimit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT);
412 } else {
413 slimit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT);
414 }
415
416 if (nd->nd_intr == NEXT_I_ENETX_DMA) {
417 slimit &= ~0x80000000;
418 }
419
420 #ifdef DIAGNOSTIC
421 if ((slimit < onext) || (slimit > olimit)) {
422 next_dma_print(nd);
423 panic("DMA: Unexpected registers in finish_xfer\n");
424 }
425 #endif
426
427 nd->_nd_map->dm_segs[nd->_nd_idx].ds_xfer_len = slimit-onext;
428
429 /* If we've reached the end of the current map, then inform
430 * that we've completed that map.
431 */
432 if (nd->_nd_map && ((nd->_nd_idx+1) == nd->_nd_map->dm_nsegs)) {
433 if (nd->nd_completed_cb)
434 (*nd->nd_completed_cb)(nd->_nd_map, nd->nd_cb_arg);
435 }
436 nd->_nd_map = 0;
437 nd->_nd_idx = 0;
438 }
439
440
441 int
442 nextdma_intr(arg)
443 void *arg;
444 {
445 /* @@@ This is bogus, we can't be certain of arg's type
446 * unless the interrupt is for us. For now we successfully
447 * cheat because DMA interrupts are the only things invoked
448 * at this interrupt level.
449 */
450 struct nextdma_config *nd = arg;
451
452 if (!INTR_OCCURRED(nd->nd_intr)) return 0;
453 /* Handle dma interrupts */
454
455 DPRINTF(("DMA interrupt ipl (%ld) intr(0x%b)\n",
456 NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
457
458 #ifdef DIAGNOSTIC
459 if (!nd->_nd_map) {
460 next_dma_print(nd);
461 panic("DMA missing current map in interrupt!\n");
462 }
463 #endif
464
465 {
466 int state = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR);
467
468 #ifdef DIAGNOSTIC
469 if ((!(state & DMACSR_COMPLETE)) || (state & DMACSR_SUPDATE)) {
470 next_dma_print(nd);
471 panic("DMA Unexpected dma state in interrupt (0x%b)",state,DMACSR_BITS);
472 }
473 #endif
474
475 next_dma_finish_xfer(nd);
476
477 /* Check to see if we are expecting dma to shut down */
478 if ((nd->_nd_map == NULL) && (nd->_nd_map_cont == NULL)) {
479
480 #ifdef DIAGNOSTIC
481 if (state & DMACSR_ENABLE) {
482 next_dma_print(nd);
483 panic("DMA: unexpected DMA state at shutdown (0x%b)\n",
484 state,DMACSR_BITS);
485 }
486 #endif
487 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
488 DMACSR_CLRCOMPLETE | DMACSR_RESET);
489
490 DPRINTF(("DMA: a normal and expected shutdown occurred\n"));
491 if (nd->nd_shutdown_cb) (*nd->nd_shutdown_cb)(nd->nd_cb_arg);
492
493 return(1);
494 }
495
496 next_dma_rotate(nd);
497 next_dma_setup_cont_regs(nd);
498
499 {
500 u_long dmadir; /* DMACSR_SETREAD or DMACSR_SETWRITE */
501
502 if (state & DMACSR_READ) {
503 dmadir = DMACSR_SETREAD;
504 } else {
505 dmadir = DMACSR_SETWRITE;
506 }
507
508 /* we used to SETENABLE here only
509 conditionally, but we got burned
510 because DMA sometimes would shut
511 down between when we checked and
512 when we acted upon it. CL19991211 */
513 if ((nd->_nd_map_cont == NULL) && (nd->_nd_idx+1 == nd->_nd_map->dm_nsegs)) {
514 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
515 DMACSR_CLRCOMPLETE | dmadir | DMACSR_SETENABLE);
516 } else {
517 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
518 DMACSR_CLRCOMPLETE | dmadir | DMACSR_SETSUPDATE | DMACSR_SETENABLE);
519 }
520
521 }
522
523 }
524
525 DPRINTF(("DMA exiting interrupt ipl (%ld) intr(0x%b)\n",
526 NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
527
528 return(1);
529 }
530
531 /*
532 * Check to see if dma has finished for a channel */
533 int
534 nextdma_finished(nd)
535 struct nextdma_config *nd;
536 {
537 int r;
538 int s;
539 s = spldma(); /* @@@ should this be splimp()? */
540 r = (nd->_nd_map == NULL) && (nd->_nd_map_cont == NULL);
541 splx(s);
542 return(r);
543 }
544
545 void
546 nextdma_start(nd, dmadir)
547 struct nextdma_config *nd;
548 u_long dmadir; /* DMACSR_SETREAD or DMACSR_SETWRITE */
549 {
550
551 #ifdef DIAGNOSTIC
552 if (!nextdma_finished(nd)) {
553 panic("DMA trying to start before previous finished on intr(0x%b)\n",
554 NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS);
555 }
556 #endif
557
558 DPRINTF(("DMA start (%ld) intr(0x%b)\n",
559 NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
560
561 #ifdef DIAGNOSTIC
562 if (nd->_nd_map) {
563 next_dma_print(nd);
564 panic("DMA: nextdma_start() with non null map\n");
565 }
566 if (nd->_nd_map_cont) {
567 next_dma_print(nd);
568 panic("DMA: nextdma_start() with non null continue map\n");
569 }
570 #endif
571
572 #ifdef DIAGNOSTIC
573 if ((dmadir != DMACSR_SETREAD) && (dmadir != DMACSR_SETWRITE)) {
574 panic("DMA: nextdma_start(), dmadir arg must be DMACSR_SETREAD or DMACSR_SETWRITE\n");
575 }
576 #endif
577
578 /* preload both the current and the continue maps */
579 next_dma_rotate(nd);
580
581 #ifdef DIAGNOSTIC
582 if (!nd->_nd_map_cont) {
583 panic("No map available in nextdma_start()");
584 }
585 #endif
586
587 next_dma_rotate(nd);
588
589 DPRINTF(("DMA initiating DMA %s of %d segments on intr(0x%b)\n",
590 (dmadir == DMACSR_SETREAD ? "read" : "write"), nd->_nd_map->dm_nsegs,
591 NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
592
593 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 0);
594 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
595 DMACSR_INITBUF | DMACSR_RESET | dmadir);
596
597 next_dma_setup_curr_regs(nd);
598 next_dma_setup_cont_regs(nd);
599
600 #if (defined(ND_DEBUG))
601 if (nextdma_debug) next_dma_print(nd);
602 #endif
603
604 if ((nd->_nd_map_cont == NULL) && (nd->_nd_idx+1 == nd->_nd_map->dm_nsegs)) {
605 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
606 DMACSR_SETENABLE | dmadir);
607 } else {
608 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
609 DMACSR_SETSUPDATE | DMACSR_SETENABLE | dmadir);
610 }
611 }
612