Home | History | Annotate | Line # | Download | only in dev
nextdma.c revision 1.15
      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 (at) 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