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