1 /* $NetBSD: nextdma.c,v 1.22 2000/08/09 02:26:26 tv 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 #ifdef ND_DEBUG 117 if (nextdma_debug) { 118 char sbuf[256]; 119 120 bitmask_snprintf(NEXT_I_BIT(nd->nd_intr), NEXT_INTR_BITS, 121 sbuf, sizeof(sbuf)); 122 printf("DMA init ipl (%ld) intr(0x%s)\n", 123 NEXT_I_IPL(nd->nd_intr), sbuf); 124 } 125 #endif 126 127 nd->_nd_map = NULL; 128 nd->_nd_idx = 0; 129 nd->_nd_map_cont = NULL; 130 nd->_nd_idx_cont = 0; 131 132 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 0); 133 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 134 DMACSR_RESET | DMACSR_INITBUF); 135 136 next_dma_setup_curr_regs(nd); 137 next_dma_setup_cont_regs(nd); 138 139 #if defined(DIAGNOSTIC) 140 { 141 u_long state; 142 state = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR); 143 144 #if 1 145 /* mourning (a 25Mhz 68040 mono slab) appears to set BUSEXC 146 * milo (a 25Mhz 68040 mono cube) didn't have this problem 147 * Darrin B. Jewell <jewell@mit.edu> Mon May 25 07:53:05 1998 148 */ 149 state &= (DMACSR_COMPLETE | DMACSR_SUPDATE | DMACSR_ENABLE); 150 #else 151 state &= (DMACSR_BUSEXC | DMACSR_COMPLETE | 152 DMACSR_SUPDATE | DMACSR_ENABLE); 153 #endif 154 if (state) { 155 next_dma_print(nd); 156 panic("DMA did not reset"); 157 } 158 } 159 #endif 160 } 161 162 163 void 164 nextdma_reset(nd) 165 struct nextdma_config *nd; 166 { 167 int s; 168 s = spldma(); 169 170 DPRINTF(("DMA reset\n")); 171 172 #if (defined(ND_DEBUG)) 173 if (nextdma_debug) next_dma_print(nd); 174 #endif 175 176 /* @@@ clean up dma maps */ 177 178 nextdma_init(nd); 179 splx(s); 180 } 181 182 /****************************************************************/ 183 184 185 /* Call the completed and continue callbacks to try to fill 186 * in the dma continue buffers. 187 */ 188 void 189 next_dma_rotate(nd) 190 struct nextdma_config *nd; 191 { 192 193 DPRINTF(("DMA next_dma_rotate()\n")); 194 195 /* Rotate the continue map into the current map */ 196 nd->_nd_map = nd->_nd_map_cont; 197 nd->_nd_idx = nd->_nd_idx_cont; 198 199 if ((!nd->_nd_map_cont) || 200 ((nd->_nd_map_cont) && 201 (++nd->_nd_idx_cont >= nd->_nd_map_cont->dm_nsegs))) { 202 if (nd->nd_continue_cb) { 203 nd->_nd_map_cont = (*nd->nd_continue_cb)(nd->nd_cb_arg); 204 } else { 205 nd->_nd_map_cont = 0; 206 } 207 nd->_nd_idx_cont = 0; 208 } 209 210 #ifdef DIAGNOSTIC 211 if (nd->_nd_map) { 212 nd->_nd_map->dm_segs[nd->_nd_idx].ds_xfer_len = 0x1234beef; 213 } 214 #endif 215 216 #ifdef DIAGNOSTIC 217 if (nd->_nd_map_cont) { 218 if (!DMA_BEGINALIGNED(nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr)) { 219 next_dma_print(nd); 220 panic("DMA request unaligned at start\n"); 221 } 222 if (!DMA_ENDALIGNED(nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr + 223 nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len)) { 224 next_dma_print(nd); 225 panic("DMA request unaligned at end\n"); 226 } 227 } 228 #endif 229 230 } 231 232 void 233 next_dma_setup_cont_regs(nd) 234 struct nextdma_config *nd; 235 { 236 bus_addr_t dd_start; 237 bus_addr_t dd_stop; 238 bus_addr_t dd_saved_start; 239 bus_addr_t dd_saved_stop; 240 241 DPRINTF(("DMA next_dma_setup_regs()\n")); 242 243 if (nd->_nd_map_cont) { 244 dd_start = nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr; 245 dd_stop = (nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr + 246 nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len); 247 248 if (nd->nd_intr == NEXT_I_ENETX_DMA) { 249 dd_stop |= 0x80000000; /* Ethernet transmit needs secret magic */ 250 } 251 } else { 252 dd_start = 0xdeadbeef; 253 dd_stop = 0xdeadbeef; 254 } 255 256 dd_saved_start = dd_start; 257 dd_saved_stop = dd_stop; 258 259 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_START, dd_start); 260 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_STOP, dd_stop); 261 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START, dd_saved_start); 262 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP, dd_saved_stop); 263 264 #ifdef DIAGNOSTIC 265 if ((bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_START) != dd_start) || 266 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_STOP) != dd_stop) || 267 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START) != dd_saved_start) || 268 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP) != dd_saved_stop)) { 269 next_dma_print(nd); 270 panic("DMA failure writing to continue regs"); 271 } 272 #endif 273 } 274 275 void 276 next_dma_setup_curr_regs(nd) 277 struct nextdma_config *nd; 278 { 279 bus_addr_t dd_next; 280 bus_addr_t dd_limit; 281 bus_addr_t dd_saved_next; 282 bus_addr_t dd_saved_limit; 283 284 DPRINTF(("DMA next_dma_setup_curr_regs()\n")); 285 286 287 if (nd->_nd_map) { 288 dd_next = nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr; 289 dd_limit = (nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr + 290 nd->_nd_map->dm_segs[nd->_nd_idx].ds_len); 291 if (nd->nd_intr == NEXT_I_ENETX_DMA) { 292 dd_limit |= 0x80000000; /* Ethernet transmit needs secret magic */ 293 } 294 } else { 295 dd_next = 0xdeadbeef; 296 dd_limit = 0xdeadbeef; 297 } 298 299 dd_saved_next = dd_next; 300 dd_saved_limit = dd_limit; 301 302 if (nd->nd_intr == NEXT_I_ENETX_DMA) { 303 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF, dd_next); 304 } else { 305 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_NEXT, dd_next); 306 } 307 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT, dd_limit); 308 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT, dd_saved_next); 309 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT, dd_saved_limit); 310 311 #ifdef DIAGNOSTIC 312 if ((bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF) != dd_next) || 313 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT) != dd_next) || 314 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT) != dd_limit) || 315 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT) != dd_saved_next) || 316 (bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT) != dd_saved_limit)) { 317 next_dma_print(nd); 318 panic("DMA failure writing to current regs"); 319 } 320 #endif 321 } 322 323 324 /* This routine is used for debugging */ 325 326 void 327 next_dma_print(nd) 328 struct nextdma_config *nd; 329 { 330 u_long dd_csr; 331 u_long dd_next; 332 u_long dd_next_initbuf; 333 u_long dd_limit; 334 u_long dd_start; 335 u_long dd_stop; 336 u_long dd_saved_next; 337 u_long dd_saved_limit; 338 u_long dd_saved_start; 339 u_long dd_saved_stop; 340 char sbuf[256]; 341 342 /* Read all of the registers before we print anything out, 343 * in case something changes 344 */ 345 dd_csr = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR); 346 dd_next = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT); 347 dd_next_initbuf = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_NEXT_INITBUF); 348 dd_limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT); 349 dd_start = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_START); 350 dd_stop = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_STOP); 351 dd_saved_next = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_NEXT); 352 dd_saved_limit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT); 353 dd_saved_start = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_START); 354 dd_saved_stop = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_STOP); 355 356 bitmask_snprintf((*(volatile u_long *)IIOV(NEXT_P_INTRSTAT)), 357 NEXT_INTR_BITS, sbuf, sizeof(sbuf)); 358 printf("NDMAP: *intrstat = 0x%s\n", sbuf); 359 360 bitmask_snprintf((*(volatile u_long *)IIOV(NEXT_P_INTRMASK)), 361 NEXT_INTR_BITS, sbuf, sizeof(sbuf)); 362 printf("NDMAP: *intrmask = 0x%s\n", sbuf); 363 364 /* NDMAP is Next DMA Print (really!) */ 365 366 if (nd->_nd_map) { 367 printf("NDMAP: nd->_nd_map->dm_mapsize = %d\n", 368 nd->_nd_map->dm_mapsize); 369 printf("NDMAP: nd->_nd_map->dm_nsegs = %d\n", 370 nd->_nd_map->dm_nsegs); 371 printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_addr = 0x%08lx\n", 372 nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr); 373 printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_len = %d\n", 374 nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_len); 375 printf("NDMAP: nd->_nd_map->dm_segs[%d].ds_xfer_len = %d\n", 376 nd->_nd_idx,nd->_nd_map->dm_segs[nd->_nd_idx].ds_xfer_len); 377 } else { 378 printf("NDMAP: nd->_nd_map = NULL\n"); 379 } 380 if (nd->_nd_map_cont) { 381 printf("NDMAP: nd->_nd_map_cont->dm_mapsize = %d\n", 382 nd->_nd_map_cont->dm_mapsize); 383 printf("NDMAP: nd->_nd_map_cont->dm_nsegs = %d\n", 384 nd->_nd_map_cont->dm_nsegs); 385 printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_addr = 0x%08lx\n", 386 nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_addr); 387 printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_len = %d\n", 388 nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_len); 389 printf("NDMAP: nd->_nd_map_cont->dm_segs[%d].ds_xfer_len = %d\n", 390 nd->_nd_idx_cont,nd->_nd_map_cont->dm_segs[nd->_nd_idx_cont].ds_xfer_len); 391 } else { 392 printf("NDMAP: nd->_nd_map_cont = NULL\n"); 393 } 394 395 bitmask_snprintf(dd_csr, DMACSR_BITS, sbuf, sizeof(sbuf)); 396 printf("NDMAP: dd->dd_csr = 0x%s\n", sbuf); 397 398 printf("NDMAP: dd->dd_saved_next = 0x%08x\n", dd_saved_next); 399 printf("NDMAP: dd->dd_saved_limit = 0x%08x\n", dd_saved_limit); 400 printf("NDMAP: dd->dd_saved_start = 0x%08x\n", dd_saved_start); 401 printf("NDMAP: dd->dd_saved_stop = 0x%08x\n", dd_saved_stop); 402 printf("NDMAP: dd->dd_next = 0x%08x\n", dd_next); 403 printf("NDMAP: dd->dd_next_initbuf = 0x%08x\n", dd_next_initbuf); 404 printf("NDMAP: dd->dd_limit = 0x%08x\n", dd_limit); 405 printf("NDMAP: dd->dd_start = 0x%08x\n", dd_start); 406 printf("NDMAP: dd->dd_stop = 0x%08x\n", dd_stop); 407 408 bitmask_snprintf(NEXT_I_BIT(nd->nd_intr), NEXT_INTR_BITS, 409 sbuf, sizeof(sbuf)); 410 printf("NDMAP: interrupt ipl (%ld) intr(0x%s)\n", 411 NEXT_I_IPL(nd->nd_intr), sbuf); 412 } 413 414 /****************************************************************/ 415 void 416 next_dma_finish_xfer(nd) 417 struct nextdma_config *nd; 418 { 419 bus_addr_t onext; 420 bus_addr_t olimit; 421 bus_addr_t slimit; 422 423 onext = nd->_nd_map->dm_segs[nd->_nd_idx].ds_addr; 424 olimit = onext + nd->_nd_map->dm_segs[nd->_nd_idx].ds_len; 425 426 if ((nd->_nd_map_cont == NULL) && (nd->_nd_idx+1 == nd->_nd_map->dm_nsegs)) { 427 slimit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_LIMIT); 428 } else { 429 slimit = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_SAVED_LIMIT); 430 } 431 432 if (nd->nd_intr == NEXT_I_ENETX_DMA) { 433 slimit &= ~0x80000000; 434 } 435 436 #ifdef DIAGNOSTIC 437 if ((slimit < onext) || (slimit > olimit)) { 438 next_dma_print(nd); 439 panic("DMA: Unexpected registers in finish_xfer\n"); 440 } 441 #endif 442 443 nd->_nd_map->dm_segs[nd->_nd_idx].ds_xfer_len = slimit-onext; 444 445 /* If we've reached the end of the current map, then inform 446 * that we've completed that map. 447 */ 448 if (nd->_nd_map && ((nd->_nd_idx+1) == nd->_nd_map->dm_nsegs)) { 449 if (nd->nd_completed_cb) 450 (*nd->nd_completed_cb)(nd->_nd_map, nd->nd_cb_arg); 451 } 452 nd->_nd_map = 0; 453 nd->_nd_idx = 0; 454 } 455 456 457 int 458 nextdma_intr(arg) 459 void *arg; 460 { 461 /* @@@ This is bogus, we can't be certain of arg's type 462 * unless the interrupt is for us. For now we successfully 463 * cheat because DMA interrupts are the only things invoked 464 * at this interrupt level. 465 */ 466 struct nextdma_config *nd = arg; 467 468 if (!INTR_OCCURRED(nd->nd_intr)) return 0; 469 /* Handle dma interrupts */ 470 471 #ifdef ND_DEBUG 472 if (nextdma_debug) { 473 char sbuf[256]; 474 475 bitmask_snprintf(NEXT_I_BIT(nd->nd_intr), NEXT_INTR_BITS, 476 sbuf, sizeof(sbuf)); 477 printf("DMA interrupt ipl (%ld) intr(0x%s)\n", 478 NEXT_I_IPL(nd->nd_intr), sbuf); 479 } 480 #endif 481 482 #ifdef DIAGNOSTIC 483 if (!nd->_nd_map) { 484 next_dma_print(nd); 485 panic("DMA missing current map in interrupt!\n"); 486 } 487 #endif 488 489 { 490 int state = bus_space_read_4(nd->nd_bst, nd->nd_bsh, DD_CSR); 491 492 #ifdef DIAGNOSTIC 493 if ((!(state & DMACSR_COMPLETE)) || (state & DMACSR_SUPDATE)) { 494 char sbuf[256]; 495 496 next_dma_print(nd); 497 498 bitmask_snprintf(state, DMACSR_BITS, sbuf, sizeof(sbuf)); 499 panic("DMA Unexpected dma state in interrupt (0x%s)", sbuf); 500 } 501 #endif 502 503 next_dma_finish_xfer(nd); 504 505 /* Check to see if we are expecting dma to shut down */ 506 if ((nd->_nd_map == NULL) && (nd->_nd_map_cont == NULL)) { 507 508 #ifdef DIAGNOSTIC 509 if (state & DMACSR_ENABLE) { 510 char sbuf[256]; 511 512 next_dma_print(nd); 513 514 bitmask_snprintf(state, DMACSR_BITS, sbuf, sizeof(sbuf)); 515 panic("DMA: unexpected DMA state at shutdown (0x%s)\n", sbuf); 516 } 517 #endif 518 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 519 DMACSR_CLRCOMPLETE | DMACSR_RESET); 520 521 DPRINTF(("DMA: a normal and expected shutdown occurred\n")); 522 if (nd->nd_shutdown_cb) (*nd->nd_shutdown_cb)(nd->nd_cb_arg); 523 524 return(1); 525 } 526 527 next_dma_rotate(nd); 528 next_dma_setup_cont_regs(nd); 529 530 { 531 u_long dmadir; /* DMACSR_SETREAD or DMACSR_SETWRITE */ 532 533 if (state & DMACSR_READ) { 534 dmadir = DMACSR_SETREAD; 535 } else { 536 dmadir = DMACSR_SETWRITE; 537 } 538 539 /* we used to SETENABLE here only 540 conditionally, but we got burned 541 because DMA sometimes would shut 542 down between when we checked and 543 when we acted upon it. CL19991211 */ 544 if ((nd->_nd_map_cont == NULL) && (nd->_nd_idx+1 == nd->_nd_map->dm_nsegs)) { 545 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 546 DMACSR_CLRCOMPLETE | dmadir | DMACSR_SETENABLE); 547 } else { 548 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 549 DMACSR_CLRCOMPLETE | dmadir | DMACSR_SETSUPDATE | DMACSR_SETENABLE); 550 } 551 552 } 553 554 } 555 556 #ifdef ND_DEBUG 557 if (nextdma_debug) { 558 char sbuf[256]; 559 560 bitmask_snprintf(NEXT_I_BIT(nd->nd_intr), NEXT_INTR_BITS, 561 sbuf, sizeof(sbuf)); 562 printf("DMA exiting interrupt ipl (%ld) intr(0x%s)\n", 563 NEXT_I_IPL(nd->nd_intr), sbuf); 564 } 565 #endif 566 567 return(1); 568 } 569 570 /* 571 * Check to see if dma has finished for a channel */ 572 int 573 nextdma_finished(nd) 574 struct nextdma_config *nd; 575 { 576 int r; 577 int s; 578 s = spldma(); /* @@@ should this be splimp()? */ 579 r = (nd->_nd_map == NULL) && (nd->_nd_map_cont == NULL); 580 splx(s); 581 return(r); 582 } 583 584 void 585 nextdma_start(nd, dmadir) 586 struct nextdma_config *nd; 587 u_long dmadir; /* DMACSR_SETREAD or DMACSR_SETWRITE */ 588 { 589 590 #ifdef DIAGNOSTIC 591 if (!nextdma_finished(nd)) { 592 char sbuf[256]; 593 594 bitmask_snprintf(NEXT_I_BIT(nd->nd_intr), NEXT_INTR_BITS, 595 sbuf, sizeof(sbuf)); 596 panic("DMA trying to start before previous finished on intr(0x%s)\n", sbuf); 597 } 598 #endif 599 600 #ifdef ND_DEBUG 601 if (nextdma_debug) { 602 char sbuf[256]; 603 604 bitmask_snprintf(NEXT_I_BIT(nd->nd_intr), NEXT_INTR_BITS, 605 sbuf, sizeof(sbuf)); 606 printf("DMA start (%ld) intr(0x%s)\n", 607 NEXT_I_IPL(nd->nd_intr), sbuf); 608 } 609 #endif 610 611 #ifdef DIAGNOSTIC 612 if (nd->_nd_map) { 613 next_dma_print(nd); 614 panic("DMA: nextdma_start() with non null map\n"); 615 } 616 if (nd->_nd_map_cont) { 617 next_dma_print(nd); 618 panic("DMA: nextdma_start() with non null continue map\n"); 619 } 620 #endif 621 622 #ifdef DIAGNOSTIC 623 if ((dmadir != DMACSR_SETREAD) && (dmadir != DMACSR_SETWRITE)) { 624 panic("DMA: nextdma_start(), dmadir arg must be DMACSR_SETREAD or DMACSR_SETWRITE\n"); 625 } 626 #endif 627 628 /* preload both the current and the continue maps */ 629 next_dma_rotate(nd); 630 631 #ifdef DIAGNOSTIC 632 if (!nd->_nd_map_cont) { 633 panic("No map available in nextdma_start()"); 634 } 635 #endif 636 637 next_dma_rotate(nd); 638 639 #ifdef ND_DEBUG 640 if (nextdma_debug) { 641 char sbuf[256]; 642 643 bitmask_snprintf(NEXT_I_BIT(nd->nd_intr), NEXT_INTR_BITS, 644 sbuf, sizeof(sbuf)); 645 printf("DMA initiating DMA %s of %d segments on intr(0x%s)\n", 646 (dmadir == DMACSR_SETREAD ? "read" : "write"), nd->_nd_map->dm_nsegs, sbuf); 647 } 648 #endif 649 650 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 0); 651 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 652 DMACSR_INITBUF | DMACSR_RESET | dmadir); 653 654 next_dma_setup_curr_regs(nd); 655 next_dma_setup_cont_regs(nd); 656 657 #if (defined(ND_DEBUG)) 658 if (nextdma_debug) next_dma_print(nd); 659 #endif 660 661 if ((nd->_nd_map_cont == NULL) && (nd->_nd_idx+1 == nd->_nd_map->dm_nsegs)) { 662 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 663 DMACSR_SETENABLE | dmadir); 664 } else { 665 bus_space_write_4(nd->nd_bst, nd->nd_bsh, DD_CSR, 666 DMACSR_SETSUPDATE | DMACSR_SETENABLE | dmadir); 667 } 668 } 669