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