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