xref: /netbsd-src/sys/arch/next68k/dev/nextdma.c (revision bada23909e740596d0a3785a73bd3583a9807fb8)
1 /*	$NetBSD: nextdma.c,v 1.15 1999/03/14 10:31:05 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 _GENERIC_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   /* @@@ for debugging */
68 struct nextdma_config *debugernd;
69 struct nextdma_config *debugexnd;
70 
71 void next_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
72                        bus_size_t, int));
73 int next_dma_continue __P((struct nextdma_config *));
74 void next_dma_rotate __P((struct nextdma_config *));
75 
76 void next_dma_setup_cont_regs __P((struct nextdma_config *));
77 void next_dma_setup_curr_regs __P((struct nextdma_config *));
78 
79 void
80 nextdma_config(nd)
81 	struct nextdma_config *nd;
82 {
83 	/* Initialize the dma_tag. As a hack, we currently
84 	 * put the dma tag in the structure itself.  It shouldn't be there.
85 	 */
86 
87 	{
88 		bus_dma_tag_t t;
89 		t = &nd->_nd_dmat;
90 		t->_cookie = nd;
91 		t->_get_tag = NULL;           /* lose */
92 		t->_dmamap_create = _bus_dmamap_create;
93 		t->_dmamap_destroy = _bus_dmamap_destroy;
94 		t->_dmamap_load = _bus_dmamap_load_direct;
95 		t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
96 		t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
97 		t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
98 		t->_dmamap_unload = _bus_dmamap_unload;
99 		t->_dmamap_sync = next_dmamap_sync;
100 
101 		t->_dmamem_alloc = _bus_dmamem_alloc;
102 		t->_dmamem_free = _bus_dmamem_free;
103 		t->_dmamem_map = _bus_dmamem_map;
104 		t->_dmamem_unmap = _bus_dmamem_unmap;
105 		t->_dmamem_mmap = _bus_dmamem_mmap;
106 
107 		nd->nd_dmat = t;
108 	}
109 
110   /* @@@ for debugging */
111 	if (nd->nd_intr == NEXT_I_ENETR_DMA) {
112 		debugernd = nd;
113 	}
114 	if (nd->nd_intr == NEXT_I_ENETX_DMA) {
115 		debugexnd = nd;
116 	}
117 
118 	nextdma_init(nd);
119 
120 	isrlink_autovec(nextdma_intr, nd, NEXT_I_IPL(nd->nd_intr), 10);
121 	INTR_ENABLE(nd->nd_intr);
122 }
123 
124 void
125 nextdma_init(nd)
126 	struct nextdma_config *nd;
127 {
128   DPRINTF(("DMA init ipl (%ld) intr(0x%b)\n",
129 			NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
130 
131 	/* @@@ should probably check and free these maps */
132 	nd->_nd_map = NULL;
133 	nd->_nd_idx = 0;
134 	nd->_nd_map_cont = NULL;
135 	nd->_nd_idx_cont = 0;
136 
137 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 0);
138 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
139 			DMACSR_INITBUF | DMACSR_CLRCOMPLETE | DMACSR_RESET);
140 
141 	next_dma_setup_curr_regs(nd);
142 	next_dma_setup_cont_regs(nd);
143 
144 #if 0 && defined(DIAGNOSTIC)
145 	/* Today, my computer (mourning) appears to fail this test.
146 	 * yesterday, another NeXT (milo) didn't have this problem
147 	 * Darrin B. Jewell <jewell@mit.edu>  Mon May 25 07:53:05 1998
148 	 */
149 	{
150 		u_long state;
151 		state = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR);
152 		state = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR);
153     state &= (DMACSR_BUSEXC | DMACSR_COMPLETE |
154               DMACSR_SUPDATE | DMACSR_ENABLE);
155 
156 		if (state) {
157 			next_dma_print(nd);
158 			panic("DMA did not reset\n");
159 		}
160 	}
161 #endif
162 }
163 
164 
165 void
166 nextdma_reset(nd)
167 	struct nextdma_config *nd;
168 {
169 	int s;
170 	s = spldma();									/* @@@ should this be splimp()? */
171 
172 	DPRINTF(("DMA reset\n"));
173 
174 #if (defined(ND_DEBUG))
175 	if (nextdma_debug) next_dma_print(nd);
176 #endif
177 
178 	nextdma_init(nd);
179 	splx(s);
180 }
181 
182 /****************************************************************/
183 
184 /* If the next had multiple busses, this should probably
185  * go elsewhere, but it is here anyway */
186 void
187 next_dmamap_sync(t, map, offset, len, ops)
188      bus_dma_tag_t t;
189      bus_dmamap_t map;
190      bus_addr_t offset;
191      bus_size_t len;
192      int ops;
193 {
194 	/* flush/purge the cache.
195 	 * assumes pointers are aligned
196 	 * @@@ should probably be fixed to use offset and len args.
197 	 * should also optimize this to work on pages for larger regions?
198 	 */
199 
200 	if ((ops & BUS_DMASYNC_PREWRITE) ||
201 			(ops & BUS_DMASYNC_PREREAD)) {
202 		int i;
203 		for(i=0;i<map->dm_nsegs;i++) {
204 			bus_addr_t p = map->dm_segs[i].ds_addr;
205 			bus_addr_t e = p+map->dm_segs[i].ds_len;
206 #ifdef DIAGNOSTIC
207 			if ((p % 16) || (e % 16)) {
208 				panic("unaligned address in next_dmamap_sync while flushing.\n"
209 						"address=0x%08x, length=0x%08x, ops=0x%x",
210 						p,e,ops);
211 			}
212 #endif
213 			while(p<e) {
214 				DCFL(p);								/* flush */
215 				p += 16;								/* cache line length */
216 			}
217 		}
218 	}
219 
220 	if ((ops & BUS_DMASYNC_POSTREAD) ||
221 			(ops & BUS_DMASYNC_POSTWRITE)) {
222 		int i;
223 		for(i=0;i<map->dm_nsegs;i++) {
224 			bus_addr_t p = map->dm_segs[i].ds_addr;
225 			bus_addr_t e = p+map->dm_segs[i].ds_len;
226 #ifdef DIAGNOSTIC
227 			/* We don't check the end address for alignment since if the
228 			 * dma operation stops short, the end address may be modified.
229 			 */
230 			if (p % 16) {
231 				panic("unaligned address in next_dmamap_sync while purging.\n"
232 						"address=0x%08x, length=0x%08x, ops=0x%x",
233 						p,e,ops);
234 			}
235 #endif
236 			while(p<e) {
237 				DCPL(p);								/* purge */
238 				p += 16;								/* cache line length */
239 			}
240 		}
241 	}
242 }
243 
244 /****************************************************************/
245 
246 
247 /* Call the completed and continue callbacks to try to fill
248  * in the dma continue buffers.
249  */
250 void
251 next_dma_rotate(nd)
252 	struct nextdma_config *nd;
253 {
254 
255 	DPRINTF(("DMA next_dma_rotate()\n"));
256 
257 	/* If we've reached the end of the current map, then inform
258 	 * that we've completed that map.
259 	 */
260 	if (nd->_nd_map && ((nd->_nd_idx+1) == nd->_nd_map->dm_nsegs)) {
261 		if (nd->nd_completed_cb)
262 			(*nd->nd_completed_cb)(nd->_nd_map, nd->nd_cb_arg);
263 	}
264 
265 	/* Rotate the continue map into the current map */
266 	nd->_nd_map = nd->_nd_map_cont;
267 	nd->_nd_idx = nd->_nd_idx_cont;
268 
269 	if ((!nd->_nd_map_cont) ||
270 			((nd->_nd_map_cont) &&
271 					(++nd->_nd_idx_cont >= nd->_nd_map_cont->dm_nsegs))) {
272 		if (nd->nd_continue_cb) {
273 			nd->_nd_map_cont = (*nd->nd_continue_cb)(nd->nd_cb_arg);
274 		} else {
275 			nd->_nd_map_cont = 0;
276 		}
277 		nd->_nd_idx_cont = 0;
278 	}
279 
280 #ifdef DIAGNOSTIC
281 	if (nd->_nd_map_cont) {
282 		if (!DMA_BEGINALIGNED(nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr)) {
283 			next_dma_print(nd);
284 			panic("DMA request unaligned at start\n");
285 		}
286 		if (!DMA_ENDALIGNED(nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr +
287 				nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len)) {
288 			next_dma_print(nd);
289 			panic("DMA request unaligned at end\n");
290 		}
291 	}
292 #endif
293 
294 }
295 
296 void
297 next_dma_setup_cont_regs(nd)
298 	struct nextdma_config *nd;
299 {
300 	DPRINTF(("DMA next_dma_setup_regs()\n"));
301 
302 	if (nd->_nd_map_cont) {
303 
304 		if (nd->nd_intr == NEXT_I_ENETX_DMA) {
305 			/* Ethernet transmit needs secret magic */
306 
307 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_START,
308 					nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr);
309 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_STOP,
310 					((nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr +
311 							nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len)
312 							+ 0x0) | 0x80000000);
313 
314 		}
315 #ifdef NEXTDMA_SCSI_HACK
316 		else if ((nd->nd_intr == NEXT_I_SCSI_DMA) && (nd->_nd_dmadir == DMACSR_WRITE)) {
317 
318 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_START,
319 					nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr);
320 
321 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_STOP,
322 					((nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr +
323 							nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len)
324 							+ 0x20));
325     }
326 #endif
327 		else {
328 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_START,
329 					nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr);
330 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_STOP,
331 					nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr +
332 					nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len);
333 		}
334 
335 	} else {
336 
337 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_START, 0xdeadbeef);
338 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_STOP, 0xdeadbeef);
339 	}
340 
341 #if 1 /* 0xfeedbeef in these registers leads to instability.  it will
342 			 * panic after a short while with 0xfeedbeef in the DD_START and DD_STOP
343 			 * registers.  I suspect that an unexpected hardware restart
344 			 * is cycling the bogus values into the active registers.  Until
345 			 * that is understood, we seed these with the same as DD_START and DD_STOP
346 			 */
347 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START,
348 			bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_START));
349 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP,
350 			bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_STOP));
351 #else
352 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START, 0xfeedbeef);
353 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP, 0xfeedbeef);
354 #endif
355 
356 }
357 
358 void
359 next_dma_setup_curr_regs(nd)
360 	struct nextdma_config *nd;
361 {
362 	DPRINTF(("DMA next_dma_setup_curr_regs()\n"));
363 
364 
365 	if (nd->_nd_map) {
366 
367 		if (nd->nd_intr == NEXT_I_ENETX_DMA) {
368 			/* Ethernet transmit needs secret magic */
369 
370 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF,
371 					nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr);
372 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT,
373 					((nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr +
374 							nd->_nd_map->dm_segs[nd->_nd_idx].ds_len)
375 							+ 0x0) | 0x80000000);
376 
377 		}
378 #ifdef NEXTDMA_SCSI_HACK
379 		else if ((nd->nd_intr == NEXT_I_SCSI_DMA) && (nd->_nd_dmadir == DMACSR_WRITE)) {
380 			/* SCSI needs secret magic */
381 
382 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF,
383 					nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr);
384 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT,
385 					((nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr +
386 							nd->_nd_map->dm_segs[nd->_nd_idx].ds_len)
387 							+ 0x20));
388 
389 		}
390 #endif
391 		else {
392 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF,
393 					nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr);
394 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT,
395 					nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr +
396 					nd->_nd_map->dm_segs[nd->_nd_idx].ds_len);
397 		}
398 
399 	} else {
400 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF,0xdeadbeef);
401 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT, 0xdeadbeef);
402 	}
403 
404 #if 1  /* See comment in next_dma_setup_cont_regs() above */
405 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT,
406 				bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF));
407 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT,
408 				bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT));
409 #else
410 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT, 0xfeedbeef);
411 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT, 0xfeedbeef);
412 #endif
413 
414 }
415 
416 
417 /* This routine is used for debugging */
418 
419 void
420 next_dma_print(nd)
421 	struct nextdma_config *nd;
422 {
423 	u_long dd_csr;
424 	u_long dd_next;
425 	u_long dd_next_initbuf;
426 	u_long dd_limit;
427 	u_long dd_start;
428 	u_long dd_stop;
429 	u_long dd_saved_next;
430 	u_long dd_saved_limit;
431 	u_long dd_saved_start;
432 	u_long dd_saved_stop;
433 
434   /* Read all of the registers before we print anything out,
435 	 * in case something changes
436 	 */
437 	dd_csr          = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR);
438 	dd_next         = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT);
439 	dd_next_initbuf = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF);
440 	dd_limit        = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT);
441 	dd_start        = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_START);
442 	dd_stop         = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_STOP);
443 	dd_saved_next   = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT);
444 	dd_saved_limit  = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT);
445 	dd_saved_start  = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START);
446 	dd_saved_stop   = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP);
447 
448 	/* NDMAP is Next DMA Print (really!) */
449 
450 	printf("NDMAP: nd->_nd_dmadir = 0x%08x\n",nd->_nd_dmadir);
451 
452 	if (nd->_nd_map) {
453 		printf("NDMAP: nd->_nd_map->dm_mapsize = %d\n",
454 				nd->_nd_map->dm_mapsize);
455 		printf("NDMAP: nd->_nd_map->dm_nsegs = %d\n",
456 				nd->_nd_map->dm_nsegs);
457 		printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_addr = 0x%08lx\n",
458 				nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr);
459 		printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_len = %d\n",
460 				nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_len);
461 	} else {
462 		printf("NDMAP: nd->_nd_map = NULL\n");
463 	}
464 	if (nd->_nd_map_cont) {
465 		printf("NDMAP: nd->_nd_map_cont->dm_mapsize = %d\n",
466 				nd->_nd_map_cont->dm_mapsize);
467 		printf("NDMAP: nd->_nd_map_cont->dm_nsegs = %d\n",
468 				nd->_nd_map_cont->dm_nsegs);
469 		printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_addr = 0x%08lx\n",
470 				nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr);
471 		printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_len = %d\n",
472 				nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len);
473 	} else {
474 		printf("NDMAP: nd->_nd_map_cont = NULL\n");
475 	}
476 
477 	printf("NDMAP: dd->dd_csr          = 0x%b\n",   dd_csr,   DMACSR_BITS);
478 	printf("NDMAP: dd->dd_saved_next   = 0x%08x\n", dd_saved_next);
479 	printf("NDMAP: dd->dd_saved_limit  = 0x%08x\n", dd_saved_limit);
480 	printf("NDMAP: dd->dd_saved_start  = 0x%08x\n", dd_saved_start);
481 	printf("NDMAP: dd->dd_saved_stop   = 0x%08x\n", dd_saved_stop);
482 	printf("NDMAP: dd->dd_next         = 0x%08x\n", dd_next);
483 	printf("NDMAP: dd->dd_next_initbuf = 0x%08x\n", dd_next_initbuf);
484 	printf("NDMAP: dd->dd_limit        = 0x%08x\n", dd_limit);
485 	printf("NDMAP: dd->dd_start        = 0x%08x\n", dd_start);
486 	printf("NDMAP: dd->dd_stop         = 0x%08x\n", dd_stop);
487 
488 	printf("NDMAP: interrupt ipl (%ld) intr(0x%b)\n",
489 			NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS);
490 }
491 
492 /****************************************************************/
493 
494 int
495 nextdma_intr(arg)
496      void *arg;
497 {
498   struct nextdma_config *nd = arg;
499 
500   /* @@@ This is bogus, we can't be certain of arg's type
501 	 * unless the interrupt is for us
502 	 */
503 
504   if (!INTR_OCCURRED(nd->nd_intr)) return 0;
505   /* Handle dma interrupts */
506 
507 #ifdef DIAGNOSTIC
508 	if (nd->nd_intr == NEXT_I_ENETR_DMA) {
509 		if (debugernd != nd) {
510 			panic("DMA incorrect handling of rx nd->nd_intr");
511 		}
512 	}
513 	if (nd->nd_intr == NEXT_I_ENETX_DMA) {
514 		if (debugexnd != nd) {
515 			panic("DMA incorrect handling of tx nd->nd_intr");
516 		}
517 	}
518 #endif
519 
520   DPRINTF(("DMA interrupt ipl (%ld) intr(0x%b)\n",
521           NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
522 
523 #ifdef DIAGNOSTIC
524 	if (!nd->_nd_map) {
525 		next_dma_print(nd);
526 		panic("DMA missing current map in interrupt!\n");
527 	}
528 #endif
529 
530   {
531     int state = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR);
532 
533 #ifdef DIAGNOSTIC
534 		if (!(state & DMACSR_COMPLETE)) {
535 			next_dma_print(nd);
536 			printf("DEBUG: state = 0x%b\n", state,DMACSR_BITS);
537 			panic("DMA  ipl (%ld) intr(0x%b), DMACSR_COMPLETE not set in intr\n",
538 					NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS);
539 		}
540 #endif
541 
542 #if 0 /* This bit gets set sometimes & I don't know why. */
543 #ifdef DIAGNOSTIC
544 		if (state & DMACSR_BUSEXC) {
545 			next_dma_print(nd);
546 			printf("DEBUG: state = 0x%b\n", state,DMACSR_BITS);
547 			panic("DMA  ipl (%ld) intr(0x%b), DMACSR_COMPLETE not set in intr\n",
548 					NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS);
549 		}
550 #endif
551 #endif
552 
553 		/* Check to see if we are expecting dma to shut down */
554 		if (!nd->_nd_map_cont) {
555 
556 #ifdef DIAGNOSTIC
557 #if 1 /* Sometimes the DMA registers have totally bogus values when read.
558 			 * Until that's understood, we skip this check
559 			 */
560 
561 			/* Verify that the registers are laid out as expected */
562 			{
563 				bus_addr_t next;
564 				bus_addr_t limit;
565 				bus_addr_t expected_limit;
566 				expected_limit =
567 						nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr +
568 						nd->_nd_map->dm_segs[nd->_nd_idx].ds_len;
569 
570 				if (nd->nd_intr == NEXT_I_ENETX_DMA) {
571 					next  = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF);
572 					limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT) & ~0x80000000;
573 				}
574 #ifdef NEXTDMA_SCSI_HACK
575 				else if ((nd->nd_intr == NEXT_I_SCSI_DMA) && (nd->_nd_dmadir == DMACSR_WRITE)) {
576 					next  = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT) - 0x20;
577 					limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT) - 0x20;
578 				}
579 #endif
580 				else {
581 					next  = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT);
582 					limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT);
583 				}
584 
585 				if ((next != limit) || (limit != expected_limit)) {
586 					next_dma_print(nd);
587 					printf("DEBUG: state = 0x%b\n", state,DMACSR_BITS);
588 					panic("unexpected DMA limit at shutdown 0x%08x, 0x%08x, 0x%08x",
589 							next,limit,expected_limit);
590 				}
591 			}
592 #endif
593 #endif
594 
595 #if 1
596 #ifdef DIAGNOSTIC
597 			if (state & (DMACSR_SUPDATE|DMACSR_ENABLE)) {
598 				next_dma_print(nd);
599 				panic("DMA: unexpected bits set in DMA state at shutdown (0x%b)\n",
600 						state,DMACSR_BITS);
601 			}
602 #endif
603 #endif
604 
605 			if ((nd->_nd_idx+1) == nd->_nd_map->dm_nsegs) {
606 				if (nd->nd_completed_cb)
607 					(*nd->nd_completed_cb)(nd->_nd_map, nd->nd_cb_arg);
608 			}
609 			nd->_nd_map = 0;
610 			nd->_nd_idx = 0;
611 
612 			bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
613 					DMACSR_CLRCOMPLETE | DMACSR_RESET);
614 
615 			DPRINTF(("DMA: a normal and expected shutdown occurred\n"));
616 			if (nd->nd_shutdown_cb) (*nd->nd_shutdown_cb)(nd->nd_cb_arg);
617 
618 			return(1);
619 		}
620 
621 #if 0
622 #ifdef DIAGNOSTIC
623 		if (!(state & DMACSR_SUPDATE)) {
624 			next_dma_print(nd);
625 			printf("DEBUG: state = 0x%b\n", state,DMACSR_BITS);
626 			panic("SUPDATE not set with continuing DMA");
627 		}
628 #endif
629 #endif
630 
631 		/* Check that the buffer we are interrupted for is the one we expect.
632 		 * Shorten the buffer if the dma completed with a short buffer
633 		 */
634 		{
635 			bus_addr_t next;
636 			bus_addr_t limit;
637 			bus_addr_t expected_next;
638 			bus_addr_t expected_limit;
639 
640 			expected_next = nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr;
641 			expected_limit = expected_next + nd->_nd_map->dm_segs[nd->_nd_idx].ds_len;
642 
643 #if 0 /* for some unknown reason, somtimes DD_SAVED_NEXT has value from
644 			 * nd->_nd_map and sometimes it has value from nd->_nd_map_cont.
645 			 * Somtimes, it has a completely different unknown value.
646 			 * Until that's understood, we won't sanity check the expected_next value.
647 			 */
648 			next  = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT);
649 #else
650 			next  = expected_next;
651 #endif
652 			limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT);
653 
654 			if (nd->nd_intr == NEXT_I_ENETX_DMA) {
655 				limit &= ~0x80000000;
656 			}
657 #ifdef NEXTDMA_SCSI_HACK
658 			else if ((nd->nd_intr == NEXT_I_SCSI_DMA) && (nd->_nd_dmadir == DMACSR_WRITE)) {
659 				limit -= 0x20;
660 			}
661 #endif
662 
663 			if ((limit-next < 0) ||
664 					(limit-next >= expected_limit-expected_next)) {
665 #ifdef DIAGNOSTIC
666 #if 0 /* Sometimes, (under load I think) even DD_SAVED_LIMIT has
667 			 * a bogus value.  Until that's understood, we don't panic
668 			 * here.
669 			 */
670 				next_dma_print(nd);
671 				printf("DEBUG: state = 0x%b\n", state,DMACSR_BITS);
672 				panic("Unexpected saved registers values.");
673 #endif
674 #endif
675 			} else {
676 				/* Set the length of the segment to match actual length.
677 				 * @@@ is it okay to resize dma segments here?
678 				 * i should probably ask jason about this.
679 				 */
680 				nd->_nd_map->dm_segs[nd->_nd_idx].ds_len = limit-next;
681 				expected_limit = expected_next + nd->_nd_map->dm_segs[nd->_nd_idx].ds_len;
682 			}
683 
684 #if 0 /* these checks are turned off until the above mentioned weirdness is fixed. */
685 #ifdef DIAGNOSTIC
686 			if (next != expected_next) {
687 				next_dma_print(nd);
688 				printf("DEBUG: state = 0x%b\n", state,DMACSR_BITS);
689 				panic("unexpected DMA next buffer in interrupt (found 0x%08x, expected 0x%08x)",
690 						next,expected_next);
691 			}
692 			if (limit != expected_limit) {
693 				next_dma_print(nd);
694 				printf("DEBUG: state = 0x%b\n", state,DMACSR_BITS);
695 				panic("unexpected DMA limit buffer in interrupt (found 0x%08x, expected 0x%08x)",
696 						limit,expected_limit);
697 			}
698 #endif
699 #endif
700 		}
701 
702 		next_dma_rotate(nd);
703 		next_dma_setup_cont_regs(nd);
704 
705 		if (!(state & DMACSR_ENABLE)) {
706 
707 			DPRINTF(("Unexpected DMA shutdown, restarting\n"));
708 
709 			if (nd->_nd_map_cont) {
710 				bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
711 						DMACSR_SETSUPDATE | DMACSR_SETENABLE | nd->_nd_dmadir);
712 			} else {
713 				bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
714 						DMACSR_SETENABLE | nd->_nd_dmadir);
715 			}
716 
717 		} else {
718 
719 			if (nd->_nd_map_cont) {
720 				bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
721 						DMACSR_SETSUPDATE | DMACSR_CLRCOMPLETE | nd->_nd_dmadir);
722 			} else {
723 				bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
724 						DMACSR_CLRCOMPLETE | nd->_nd_dmadir);
725 			}
726 		}
727 
728 	}
729 
730   DPRINTF(("DMA exiting interrupt ipl (%ld) intr(0x%b)\n",
731           NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
732 
733   return(1);
734 }
735 
736 /*
737  * Check to see if dma has finished for a channel */
738 int
739 nextdma_finished(nd)
740 	struct nextdma_config *nd;
741 {
742 	int r;
743 	int s;
744 	s = spldma();									/* @@@ should this be splimp()? */
745 	r = (nd->_nd_map == NULL) && (nd->_nd_map_cont == NULL);
746 	splx(s);
747 	return(r);
748 }
749 
750 void
751 nextdma_start(nd, dmadir)
752 	struct nextdma_config *nd;
753 	u_long dmadir;								/* 	DMACSR_READ or DMACSR_WRITE */
754 {
755 
756 #ifdef DIAGNOSTIC
757 	if (!nextdma_finished(nd)) {
758 		panic("DMA trying to start before previous finished on intr(0x%b)\n",
759 				NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS);
760 	}
761 #endif
762 
763   DPRINTF(("DMA start (%ld) intr(0x%b)\n",
764           NEXT_I_IPL(nd->nd_intr), NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
765 
766 #ifdef DIAGNOSTIC
767 	if (nd->_nd_map) {
768 		next_dma_print(nd);
769 		panic("DMA: nextdma_start() with non null map\n");
770 	}
771 	if (nd->_nd_map_cont) {
772 		next_dma_print(nd);
773 		panic("DMA: nextdma_start() with non null continue map\n");
774 	}
775 #endif
776 
777 #ifdef DIAGNOSTIC
778 	if ((dmadir != DMACSR_READ) && (dmadir != DMACSR_WRITE)) {
779 		panic("DMA: nextdma_start(), dmadir arg must be DMACSR_READ or DMACSR_WRITE\n");
780 	}
781 #endif
782 
783 	nd->_nd_dmadir = dmadir;
784 
785 	/* preload both the current and the continue maps */
786 	next_dma_rotate(nd);
787 
788 #ifdef DIAGNOSTIC
789 	if (!nd->_nd_map_cont) {
790 		panic("No map available in nextdma_start()");
791 	}
792 #endif
793 
794 	next_dma_rotate(nd);
795 
796 	DPRINTF(("DMA initiating DMA %s of %d segments on intr(0x%b)\n",
797 			(nd->_nd_dmadir == DMACSR_READ ? "read" : "write"), nd->_nd_map->dm_nsegs,
798 			NEXT_I_BIT(nd->nd_intr),NEXT_INTR_BITS));
799 
800 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 0);
801 	bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
802 			DMACSR_INITBUF | DMACSR_RESET | nd->_nd_dmadir);
803 
804 	next_dma_setup_curr_regs(nd);
805 	next_dma_setup_cont_regs(nd);
806 
807 #if (defined(ND_DEBUG))
808 	if (nextdma_debug) next_dma_print(nd);
809 #endif
810 
811 	if (nd->_nd_map_cont) {
812 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
813 				DMACSR_SETSUPDATE | DMACSR_SETENABLE | nd->_nd_dmadir);
814 	} else {
815 		bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR,
816 				DMACSR_SETENABLE | nd->_nd_dmadir);
817 	}
818 
819 }
820