Home | History | Annotate | Line # | Download | only in dev
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