xref: /netbsd/sys/arch/next68k/dev/nextdma.c (revision 5f3aa6aa)
1 /*	$NetBSD: nextdma.c,v 1.51 2023/02/03 23:06:42 tsutsui 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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: nextdma.c,v 1.51 2023/02/03 23:06:42 tsutsui Exp $");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/mbuf.h>
33 #include <sys/syslog.h>
34 #include <sys/socket.h>
35 #include <sys/device.h>
36 #include <sys/malloc.h>
37 #include <sys/ioctl.h>
38 #include <sys/errno.h>
39 
40 #define _M68K_BUS_DMA_PRIVATE
41 #include <machine/autoconf.h>
42 #include <machine/cpu.h>
43 #include <machine/intr.h>
44 
45 #include <m68k/cacheops.h>
46 
47 #include <next68k/next68k/isr.h>
48 #include <next68k/next68k/nextrom.h>
49 
50 #include <next68k/dev/intiovar.h>
51 
52 #include "nextdmareg.h"
53 #include "nextdmavar.h"
54 
55 #include "esp.h"
56 #include "xe.h"
57 
58 #if DEBUG
59 #define ND_DEBUG
60 #endif
61 
62 extern int turbo;
63 
64 #define panic		__asm volatile("trap  #15"); printf
65 
66 #define NEXTDMA_DEBUG nextdma_debug
67 /* (nsc->sc_chan->nd_intr == NEXT_I_SCSI_DMA) && nextdma_debug */
68 #if defined(ND_DEBUG)
69 int nextdma_debug = 0;
70 #define DPRINTF(x) if (NEXTDMA_DEBUG) printf x;
71 int ndtrace_show = 0;
72 char ndtrace_buf[8192+100];
73 size_t ndtrace_len = 0;
74 #define NDTRACEIF(x) if (10) do {x;} while (0)
75 #else
76 #define DPRINTF(x)
77 #define NDTRACEIF(x)
78 #endif
79 #define PRINTF(x) printf x
80 
81 void
ndtrace_printf(const char * fmt,...)82 ndtrace_printf(const char *fmt, ...) {
83 #ifdef ND_DEBUG
84 	int len;
85 	va_list ap;
86 
87 	va_start(ap, fmt);
88 	len = vsnprintf(ndtrace_buf + ndtrace_len, sizeof(ndtrace_buf)
89 	    - ndtrace_len, fmt, ap);
90 	va_end(ap);
91 	ndtrace_len += len;
92 #endif
93 }
94 
95 int
ndtrace_empty(void)96 ndtrace_empty(void) {
97 #ifdef ND_DEBUG
98 	return ndtrace_len == 0;
99 #else
100 	return 1;
101 #endif
102 }
103 
104 void
ndtrace_reset(void)105 ndtrace_reset(void) {
106 #ifdef ND_DEBUG
107 	ndtrace_len = 0;
108 #endif
109 }
110 
111 void
ndtrace_addc(int c)112 ndtrace_addc(int c) {
113 #ifdef ND_DEBUG
114 	if (ndtrace_len < sizeof(ndtrace_buf) - 1) {
115 		ndtrace_buf[ndtrace_len++] = c;
116 		ndtrace_buf[ndtrace_len] = '\0';
117 	}
118 #endif
119 }
120 
121 const char *
ndtrace_get(void)122 ndtrace_get(void) {
123 #ifdef ND_DEBUG
124 	return ndtrace_buf;
125 #else
126 	return NULL;
127 #endif
128 }
129 
130 
131 #if defined(ND_DEBUG)
132 int nextdma_debug_enetr_idx = 0;
133 unsigned int nextdma_debug_enetr_state[100] = { 0 };
134 int nextdma_debug_scsi_idx = 0;
135 unsigned int nextdma_debug_scsi_state[100] = { 0 };
136 
137 void nextdma_debug_initstate(struct nextdma_softc *);
138 void nextdma_debug_savestate(struct nextdma_softc *, unsigned int);
139 void nextdma_debug_scsi_dumpstate(void);
140 void nextdma_debug_enetr_dumpstate(void);
141 #endif
142 
143 
144 int	nextdma_match(device_t, cfdata_t, void *);
145 void	nextdma_attach(device_t, device_t, void *);
146 
147 void nextdmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, bus_size_t, int);
148 int nextdma_continue(struct nextdma_softc *);
149 void nextdma_rotate(struct nextdma_softc *);
150 
151 void nextdma_setup_cont_regs(struct nextdma_softc *);
152 void nextdma_setup_curr_regs(struct nextdma_softc *);
153 
154 #if NESP > 0
155 static int nextdma_esp_intr(void *);
156 #endif
157 #if NXE > 0
158 static int nextdma_enet_intr(void *);
159 #endif
160 
161 #define nd_bsr4(reg) \
162 	bus_space_read_4(nsc->sc_bst, nsc->sc_bsh, (reg))
163 #define nd_bsw4(reg,val) \
164 	bus_space_write_4(nsc->sc_bst, nsc->sc_bsh, (reg), (val))
165 
166 CFATTACH_DECL_NEW(nextdma, sizeof(struct nextdma_softc),
167     nextdma_match, nextdma_attach, NULL, NULL);
168 
169 static struct nextdma_channel nextdma_channel[] = {
170 #if NESP > 0
171 	{
172 		"scsi",
173 		NEXT_P_SCSI_CSR,
174 		DD_SIZE,
175 		NEXT_I_SCSI_DMA,
176 		&nextdma_esp_intr
177 	},
178 #endif
179 #if NXE > 0
180 	{
181 		"enetx",
182 		NEXT_P_ENETX_CSR,
183 		DD_SIZE,
184 		NEXT_I_ENETX_DMA,
185 		&nextdma_enet_intr
186 	},
187 	{
188 		"enetr",
189 		NEXT_P_ENETR_CSR,
190 		DD_SIZE,
191 		NEXT_I_ENETR_DMA,
192 		&nextdma_enet_intr
193 	},
194 #endif
195 };
196 static int nnextdma_channels = __arraycount(nextdma_channel);
197 
198 static int attached = 0;
199 
200 struct nextdma_softc *
nextdma_findchannel(const char * name)201 nextdma_findchannel(const char *name)
202 {
203 	device_t dev;
204 	deviter_t di;
205 
206 	for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST);
207 	     dev != NULL;
208 	     dev = deviter_next(&di)) {
209 		if (strncmp(device_xname(dev), "nextdma", 7) == 0) {
210 			struct nextdma_softc *nsc = device_private(dev);
211 			if (strcmp(nsc->sc_chan->nd_name, name) == 0)
212 				break;
213 		}
214 	}
215 	deviter_release(&di);
216 	if (dev == NULL)
217 		return NULL;
218 	return device_private(dev);
219 }
220 
221 int
nextdma_match(device_t parent,cfdata_t match,void * aux)222 nextdma_match(device_t parent, cfdata_t match, void *aux)
223 {
224 	struct intio_attach_args *ia = (struct intio_attach_args *)aux;
225 
226 	if (attached >= nnextdma_channels)
227 		return 0;
228 
229 	ia->ia_addr = (void *)nextdma_channel[attached].nd_base;
230 
231 	return 1;
232 }
233 
234 void
nextdma_attach(device_t parent,device_t self,void * aux)235 nextdma_attach(device_t parent, device_t self, void *aux)
236 {
237 	struct nextdma_softc *nsc = device_private(self);
238 	struct intio_attach_args *ia = (struct intio_attach_args *)aux;
239 
240 	if (attached >= nnextdma_channels)
241 		return;
242 
243 	nsc->sc_dev = self;
244 	nsc->sc_chan = &nextdma_channel[attached];
245 
246 	nsc->sc_dmat = ia->ia_dmat;
247 	nsc->sc_bst = ia->ia_bst;
248 
249 	if (bus_space_map(nsc->sc_bst, nsc->sc_chan->nd_base,
250 	    nsc->sc_chan->nd_size, 0, &nsc->sc_bsh)) {
251 		panic("%s: can't map DMA registers for channel %s",
252 		    device_xname(self), nsc->sc_chan->nd_name);
253 	}
254 
255 	nextdma_init(nsc);
256 
257 	isrlink_autovec(nsc->sc_chan->nd_intrfunc, nsc,
258 	    NEXT_I_IPL(nsc->sc_chan->nd_intr), 10, NULL);
259 	INTR_ENABLE(nsc->sc_chan->nd_intr);
260 
261 	printf(": channel %d (%s)\n", attached,
262 		nsc->sc_chan->nd_name);
263 	attached++;
264 }
265 
266 void
nextdma_init(struct nextdma_softc * nsc)267 nextdma_init(struct nextdma_softc *nsc)
268 {
269 #ifdef ND_DEBUG
270 	if (NEXTDMA_DEBUG) {
271 		char sbuf[256];
272 
273 		snprintb(sbuf, sizeof(sbuf), NEXT_INTR_BITS,
274 		    NEXT_I_BIT(nsc->sc_chan->nd_intr));
275 		printf("DMA init ipl (%ld) intr(%s)\n",
276 		    NEXT_I_IPL(nsc->sc_chan->nd_intr), sbuf);
277 	}
278 #endif
279 
280 	nsc->sc_stat.nd_map = NULL;
281 	nsc->sc_stat.nd_idx = 0;
282 	nsc->sc_stat.nd_map_cont = NULL;
283 	nsc->sc_stat.nd_idx_cont = 0;
284 	nsc->sc_stat.nd_exception = 0;
285 
286 	nd_bsw4(DD_CSR, DMACSR_RESET | DMACSR_CLRCOMPLETE);
287 	nd_bsw4(DD_CSR, 0);
288 
289 #if 01
290 	nextdma_setup_curr_regs(nsc);
291 	nextdma_setup_cont_regs(nsc);
292 #endif
293 
294 #if defined(DIAGNOSTIC)
295 	{
296 		u_long state;
297 		state = nd_bsr4 (DD_CSR);
298 
299 #if 1
300 		/* mourning (a 25 MHz 68040 mono slab) appears to set BUSEXC
301 		 * milo (a 25 MHz 68040 mono cube) didn't have this problem
302 		 * Darrin B. Jewell <jewell@mit.edu>  Mon May 25 07:53:05 1998
303 		 */
304 		state &= (DMACSR_COMPLETE | DMACSR_SUPDATE | DMACSR_ENABLE);
305 #else
306 		state &= (DMACSR_BUSEXC | DMACSR_COMPLETE |
307 			  DMACSR_SUPDATE | DMACSR_ENABLE);
308 #endif
309 		if (state != 0) {
310 			nextdma_print(nsc);
311 			panic("DMA did not reset");
312 		}
313 	}
314 #endif
315 }
316 
317 void
nextdma_reset(struct nextdma_softc * nsc)318 nextdma_reset(struct nextdma_softc *nsc)
319 {
320 	int s;
321 	struct nextdma_status *stat = &nsc->sc_stat;
322 
323 	s = spldma();
324 
325 	DPRINTF(("DMA reset\n"));
326 
327 #if (defined(ND_DEBUG))
328 	if (NEXTDMA_DEBUG > 1)
329 		nextdma_print(nsc);
330 #endif
331 
332 	nd_bsw4(DD_CSR, DMACSR_CLRCOMPLETE | DMACSR_RESET);
333 	if ((stat->nd_map) || (stat->nd_map_cont)) {
334 		if (stat->nd_map_cont) {
335 			DPRINTF(
336 			    ("DMA: resetting with non null continue map\n"));
337 			if (nsc->sc_conf.nd_completed_cb)
338 				(*nsc->sc_conf.nd_completed_cb)(
339 				    stat->nd_map_cont, nsc->sc_conf.nd_cb_arg);
340 
341 			stat->nd_map_cont = 0;
342 			stat->nd_idx_cont = 0;
343 		}
344 		if (nsc->sc_conf.nd_shutdown_cb)
345 			(*nsc->sc_conf.nd_shutdown_cb)(nsc->sc_conf.nd_cb_arg);
346 		stat->nd_map = 0;
347 		stat->nd_idx = 0;
348 	}
349 
350 	splx(s);
351 }
352 
353 /****************************************************************/
354 
355 
356 /*
357  * Call the completed and continue callbacks to try to fill
358  * in the dma continue buffers.
359  */
360 void
nextdma_rotate(struct nextdma_softc * nsc)361 nextdma_rotate(struct nextdma_softc *nsc)
362 {
363 	struct nextdma_status *stat = &nsc->sc_stat;
364 
365 	NDTRACEIF(ndtrace_addc('r'));
366 	DPRINTF(("DMA nextdma_rotate()\n"));
367 
368 	/* Rotate the continue map into the current map */
369 	stat->nd_map = stat->nd_map_cont;
370 	stat->nd_idx = stat->nd_idx_cont;
371 
372 	if ((stat->nd_map_cont == NULL) ||
373 	    ((++stat->nd_idx_cont >= stat->nd_map_cont->dm_nsegs))) {
374 		if (nsc->sc_conf.nd_continue_cb != NULL) {
375 			stat->nd_map_cont = (*nsc->sc_conf.nd_continue_cb)
376 				(nsc->sc_conf.nd_cb_arg);
377 			if (stat->nd_map_cont != NULL) {
378 				stat->nd_map_cont->dm_xfer_len = 0;
379 			}
380 		} else {
381 			stat->nd_map_cont = 0;
382 		}
383 		stat->nd_idx_cont = 0;
384 	}
385 
386 #if defined(DIAGNOSTIC) && 0
387 	if (stat->nd_map_cont) {
388 		if (!DMA_BEGINALIGNED(
389 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_addr)) {
390 			nextdma_print(nsc);
391 			panic("DMA request unaligned at start");
392 		}
393 		if (!DMA_ENDALIGNED(
394 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_addr +
395 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_len)) {
396 			nextdma_print(nsc);
397 			panic("DMA request unaligned at end");
398 		}
399 	}
400 #endif
401 
402 }
403 
404 void
nextdma_setup_curr_regs(struct nextdma_softc * nsc)405 nextdma_setup_curr_regs(struct nextdma_softc *nsc)
406 {
407 	bus_addr_t dd_next;
408 	bus_addr_t dd_limit;
409 	bus_addr_t dd_saved_next;
410 	bus_addr_t dd_saved_limit;
411 	struct nextdma_status *stat = &nsc->sc_stat;
412 
413 	NDTRACEIF(ndtrace_addc('C'));
414 	DPRINTF(("DMA nextdma_setup_curr_regs()\n"));
415 
416 	if (stat->nd_map != NULL) {
417 		dd_next = stat->nd_map->dm_segs[stat->nd_idx].ds_addr;
418 		dd_limit = (stat->nd_map->dm_segs[stat->nd_idx].ds_addr +
419 			    stat->nd_map->dm_segs[stat->nd_idx].ds_len);
420 
421 		if (!turbo && nsc->sc_chan->nd_intr == NEXT_I_ENETX_DMA) {
422 			/* Ethernet transmit needs secret magic */
423 			dd_limit |= 0x80000000;
424 			dd_limit += 15;
425 		}
426 	} else {
427 		dd_next = turbo ? 0 : 0xdeadbeef;
428 		dd_limit = turbo ? 0 : 0xdeadbeef;
429 	}
430 
431 	dd_saved_next = dd_next;
432 	dd_saved_limit = dd_limit;
433 
434 	NDTRACEIF(if (stat->nd_map) {
435 		ndtrace_printf("%ld",
436 		    stat->nd_map->dm_segs[stat->nd_idx].ds_len);
437 	});
438 
439 	if (!turbo && (nsc->sc_chan->nd_intr == NEXT_I_ENETX_DMA)) {
440 		nd_bsw4(DD_NEXT_INITBUF, dd_next);
441 	} else {
442 		nd_bsw4(DD_NEXT, dd_next);
443 	}
444 	nd_bsw4(DD_LIMIT, dd_limit);
445 	if (!turbo)
446 		nd_bsw4(DD_SAVED_NEXT, dd_saved_next);
447 	if (!turbo)
448 		nd_bsw4(DD_SAVED_LIMIT, dd_saved_limit);
449 
450 #ifdef DIAGNOSTIC
451 	if ((nd_bsr4(DD_NEXT_INITBUF) != dd_next)
452 	    || (nd_bsr4(DD_NEXT) != dd_next)
453 	    || (nd_bsr4(DD_LIMIT) != dd_limit)
454 	    || (!turbo && (nd_bsr4(DD_SAVED_NEXT) != dd_saved_next))
455 	    || (!turbo && (nd_bsr4(DD_SAVED_LIMIT) != dd_saved_limit))
456 		) {
457 		nextdma_print(nsc);
458 		panic("DMA failure writing to current regs");
459 	}
460 #endif
461 }
462 
463 void
nextdma_setup_cont_regs(struct nextdma_softc * nsc)464 nextdma_setup_cont_regs(struct nextdma_softc *nsc)
465 {
466 	bus_addr_t dd_start;
467 	bus_addr_t dd_stop;
468 	bus_addr_t dd_saved_start;
469 	bus_addr_t dd_saved_stop;
470 	struct nextdma_status *stat = &nsc->sc_stat;
471 
472 	NDTRACEIF(ndtrace_addc('c'));
473 	DPRINTF(("DMA nextdma_setup_regs()\n"));
474 
475 	if (stat->nd_map_cont != NULL) {
476 		dd_start =
477 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_addr;
478 		dd_stop  =
479 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_addr +
480 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_len;
481 
482 		if (!turbo && nsc->sc_chan->nd_intr == NEXT_I_ENETX_DMA) {
483 			/* Ethernet transmit needs secret magic */
484 			dd_stop |= 0x80000000;
485 			dd_stop += 15;
486 		}
487 	} else {
488 		dd_start = turbo ? nd_bsr4(DD_NEXT) : 0xdeadbee0;
489 		dd_stop = turbo ? 0 : 0xdeadbee0;
490 	}
491 
492 	dd_saved_start = dd_start;
493 	dd_saved_stop  = dd_stop;
494 
495 	NDTRACEIF(if (stat->nd_map_cont != NULL) {
496 		ndtrace_printf("%ld",
497 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_len);
498 	});
499 
500 	nd_bsw4(DD_START, dd_start);
501 	nd_bsw4(DD_STOP, dd_stop);
502 	if (!turbo)
503 		nd_bsw4(DD_SAVED_START, dd_saved_start);
504 	if (!turbo)
505 		nd_bsw4(DD_SAVED_STOP, dd_saved_stop);
506 	if (turbo && nsc->sc_chan->nd_intr == NEXT_I_ENETR_DMA)
507 		nd_bsw4(DD_STOP - 0x40, dd_start);
508 
509 #ifdef DIAGNOSTIC
510 	if ((nd_bsr4(DD_START) != dd_start)
511 	    || (dd_stop && (nd_bsr4(DD_STOP) != dd_stop))
512 	    || (!turbo && (nd_bsr4(DD_SAVED_START) != dd_saved_start))
513 	    || (!turbo && (nd_bsr4(DD_SAVED_STOP) != dd_saved_stop))
514 		) {
515 		nextdma_print(nsc);
516 		panic("DMA failure writing to continue regs");
517 	}
518 #endif
519 }
520 
521 /****************************************************************/
522 
523 #if NESP > 0
524 static int
nextdma_esp_intr(void * arg)525 nextdma_esp_intr(void *arg)
526 {
527 	/* @@@ This is bogus, we can't be certain of arg's type
528 	 * unless the interrupt is for us.  For now we successfully
529 	 * cheat because DMA interrupts are the only things invoked
530 	 * at this interrupt level.
531 	 */
532 	struct nextdma_softc *nsc = arg;
533 	int esp_dma_int(void *); /* XXX */
534 
535 	if (!INTR_OCCURRED(nsc->sc_chan->nd_intr))
536 		return 0;
537 	/* Handle dma interrupts */
538 
539 	return esp_dma_int(nsc->sc_conf.nd_cb_arg);
540 }
541 #endif
542 
543 #if NXE > 0
544 static int
nextdma_enet_intr(void * arg)545 nextdma_enet_intr(void *arg)
546 {
547 
548 	/*
549 	 * @@@ This is bogus, we can't be certain of arg's type
550 	 * unless the interrupt is for us.  For now we successfully
551 	 * cheat because DMA interrupts are the only things invoked
552 	 * at this interrupt level.
553 	 */
554 	struct nextdma_softc *nsc = arg;
555 	unsigned int state;
556 	bus_addr_t onext;
557 	bus_addr_t olimit;
558 	bus_addr_t slimit;
559 	int result;
560 	struct nextdma_status *stat = &nsc->sc_stat;
561 
562 	if (!INTR_OCCURRED(nsc->sc_chan->nd_intr))
563 		return 0;
564 	/* Handle dma interrupts */
565 
566 	NDTRACEIF(ndtrace_addc('D'));
567 #ifdef ND_DEBUG
568 	if (NEXTDMA_DEBUG) {
569 		char sbuf[256];
570 
571 		snprintb(sbuf, sizeof(sbuf), NEXT_INTR_BITS,
572 		    NEXT_I_BIT(nsc->sc_chan->nd_intr));
573 		printf("DMA interrupt ipl (%ld) intr(%s)\n",
574 		    NEXT_I_IPL(nsc->sc_chan->nd_intr), sbuf);
575 	}
576 #endif
577 
578 #ifdef DIAGNOSTIC
579 	if (stat->nd_map == NULL) {
580 		nextdma_print(nsc);
581 		panic("DMA missing current map in interrupt!");
582 	}
583 #endif
584 
585 	state = nd_bsr4(DD_CSR);
586 
587 #if defined(ND_DEBUG)
588 	nextdma_debug_savestate(nsc, state);
589 #endif
590 
591 #ifdef DIAGNOSTIC
592 	if (/* (state & DMACSR_READ) || */ (state & DMACSR_COMPLETE) == 0) {
593 		char sbuf[256];
594 		nextdma_print(nsc);
595 		snprintb(sbuf, sizeof(sbuf), DMACSR_BITS, state);
596 		printf("DMA: state %s\n",sbuf);
597 		panic("DMA complete not set in interrupt");
598 	}
599 #endif
600 
601 	DPRINTF(("DMA: finishing xfer\n"));
602 
603 	onext = stat->nd_map->dm_segs[stat->nd_idx].ds_addr;
604 	olimit = onext + stat->nd_map->dm_segs[stat->nd_idx].ds_len;
605 
606 	result = 0;
607 	if ((state & DMACSR_ENABLE) != 0) {
608 		/* enable bit was set */
609 		result |= 0x01;
610 	}
611 	if ((state & DMACSR_SUPDATE) != 0) {
612 		/* supdate bit was set */
613 		result |= 0x02;
614 	}
615 	if (stat->nd_map_cont == NULL) {
616 		KASSERT(stat->nd_idx+1 == stat->nd_map->dm_nsegs);
617 		/* Expecting a shutdown, didn't SETSUPDATE last turn */
618 		result |= 0x04;
619 	}
620 	if ((state & DMACSR_BUSEXC) != 0) {
621 		/* bus exception bit was set */
622 		result |= 0x08;
623 	}
624 	switch (result) {
625 	case 0x00: /* !BUSEXC && !expecting && !SUPDATE && !ENABLE */
626 	case 0x08: /* BUSEXC && !expecting && !SUPDATE && !ENABLE */
627 		if (turbo) {
628 			volatile u_int *limit =
629 			    (volatile u_int *)IIOV(0x2000050 + 0x4000);
630 			slimit = *limit;
631 		} else {
632 			slimit = nd_bsr4(DD_SAVED_LIMIT);
633 		}
634 		break;
635 	case 0x01: /* !BUSEXC && !expecting && !SUPDATE && ENABLE */
636 	case 0x09: /* BUSEXC && !expecting && !SUPDATE && ENABLE */
637 		if (turbo) {
638 			volatile u_int *limit =
639 			    (volatile u_int *)IIOV(0x2000050 + 0x4000);
640 			slimit = *limit;
641 		} else {
642 			slimit = nd_bsr4(DD_SAVED_LIMIT);
643 		}
644 		break;
645 	case 0x02: /* !BUSEXC && !expecting && SUPDATE && !ENABLE */
646 	case 0x0a: /* BUSEXC && !expecting && SUPDATE && !ENABLE */
647 		slimit = nd_bsr4(DD_NEXT);
648 		break;
649 	case 0x04:  /* !BUSEXC && expecting && !SUPDATE && !ENABLE */
650 	case 0x0c: /* BUSEXC && expecting && !SUPDATE && !ENABLE */
651 		slimit = nd_bsr4(DD_LIMIT);
652 		break;
653 	default:
654 #ifdef DIAGNOSTIC
655 	{
656 		char sbuf[256];
657 		printf("DMA: please send this output to"
658 		    " port-next68k-maintainer@NetBSD.org:\n");
659 		snprintb(sbuf, sizeof(sbuf), DMACSR_BITS, state);
660 		printf("DMA: state %s\n",sbuf);
661 		nextdma_print(nsc);
662 		panic("DMA: condition 0x%02x not yet documented to occur",
663 		    result);
664 	}
665 #endif
666 	slimit = olimit;
667 	break;
668 	}
669 
670 	if (!turbo && nsc->sc_chan->nd_intr == NEXT_I_ENETX_DMA) {
671 		slimit &= ~0x80000000;
672 		slimit -= 15;
673 	}
674 
675 #ifdef DIAGNOSTIC
676 	if ((state & DMACSR_READ) != 0)
677 		DPRINTF(("limits: 0x%08lx <= 0x%08lx <= 0x%08lx %s\n",
678 		    onext, slimit, olimit,
679 		    (state & DMACSR_READ) ? "read" : "write"));
680 	if (slimit < onext || slimit > olimit) {
681 		char sbuf[256];
682 		snprintb(sbuf, sizeof(sbuf), DMACSR_BITS, state);
683 		printf("DMA: state %s\n",sbuf);
684 		nextdma_print(nsc);
685 		panic("DMA: Unexpected limit register (0x%08lx) in finish_xfer",
686 		    slimit);
687 	}
688 #endif
689 
690 #ifdef DIAGNOSTIC
691 	if ((state & DMACSR_ENABLE) != 0 &&
692 	    stat->nd_idx + 1 != stat->nd_map->dm_nsegs) {
693 		if (slimit != olimit) {
694 			char sbuf[256];
695 			snprintb(sbuf, sizeof(sbuf), DMACSR_BITS, state);
696 			printf("DMA: state %s\n",sbuf);
697 			nextdma_print(nsc);
698 			panic("DMA: short limit register (0x%08lx)"
699 			    " w/o finishing map.", slimit);
700 		}
701 	}
702 #endif
703 
704 #if (defined(ND_DEBUG))
705 	if (NEXTDMA_DEBUG > 2)
706 		nextdma_print(nsc);
707 #endif
708 
709 	stat->nd_map->dm_xfer_len += slimit-onext;
710 
711 	/* If we've reached the end of the current map, then inform
712 	 * that we've completed that map.
713 	 */
714 	if (stat->nd_idx + 1 == stat->nd_map->dm_nsegs) {
715 		if (nsc->sc_conf.nd_completed_cb)
716 			(*nsc->sc_conf.nd_completed_cb)(stat->nd_map,
717 			    nsc->sc_conf.nd_cb_arg);
718 	} else {
719 		KASSERT(stat->nd_map == stat->nd_map_cont);
720 		KASSERT(stat->nd_idx+1 == stat->nd_idx_cont);
721 	}
722 	stat->nd_map = 0;
723 	stat->nd_idx = 0;
724 
725 #if (defined(ND_DEBUG))
726 	if (NEXTDMA_DEBUG) {
727 		char sbuf[256];
728 		snprintb(sbuf, sizeof(sbuf), DMACSR_BITS, state);
729 		printf("CLNDMAP: dd->dd_csr          = %s\n", sbuf);
730 	}
731 #endif
732 	if ((state & DMACSR_ENABLE) != 0) {
733 		u_long dmadir;		/* DMACSR_SETREAD or DMACSR_SETWRITE */
734 
735 		nextdma_rotate(nsc);
736 		nextdma_setup_cont_regs(nsc);
737 
738 		if ((state & DMACSR_READ) != 0) {
739 			dmadir = DMACSR_SETREAD;
740 		} else {
741 			dmadir = DMACSR_SETWRITE;
742 		}
743 
744 		if (stat->nd_map_cont == NULL) {
745 			KASSERT(stat->nd_idx+1 == stat->nd_map->dm_nsegs);
746 			nd_bsw4(DD_CSR, DMACSR_CLRCOMPLETE | dmadir);
747 			NDTRACEIF(ndtrace_addc('g'));
748 		} else {
749 			nd_bsw4(DD_CSR,
750 			    DMACSR_CLRCOMPLETE | dmadir | DMACSR_SETSUPDATE);
751 			NDTRACEIF(ndtrace_addc('G'));
752 		}
753 	} else {
754 		DPRINTF(("DMA: a shutdown occurred\n"));
755 		nd_bsw4(DD_CSR, DMACSR_CLRCOMPLETE | DMACSR_RESET);
756 
757 		/* Cleanup more incomplete transfers */
758 		/* cleanup continue map */
759 		if (stat->nd_map_cont) {
760 			DPRINTF(("DMA: shutting down with"
761 			    " non null continue map\n"));
762 			if (nsc->sc_conf.nd_completed_cb != NULL)
763 				(*nsc->sc_conf.nd_completed_cb)(
764 				    stat->nd_map_cont, nsc->sc_conf.nd_cb_arg);
765 
766 			stat->nd_map_cont = 0;
767 			stat->nd_idx_cont = 0;
768 		}
769 		if (nsc->sc_conf.nd_shutdown_cb != NULL)
770 			(*nsc->sc_conf.nd_shutdown_cb)(nsc->sc_conf.nd_cb_arg);
771 	}
772 
773 #ifdef ND_DEBUG
774 	if (NEXTDMA_DEBUG) {
775 		char sbuf[256];
776 
777 		snprintb(sbuf, sizeof(sbuf),
778 		    NEXT_INTR_BITS, NEXT_I_BIT(nsc->sc_chan->nd_intr));
779 		printf("DMA exiting interrupt ipl (%ld) intr(%s)\n",
780 		    NEXT_I_IPL(nsc->sc_chan->nd_intr), sbuf);
781 	}
782 #endif
783 
784 	return 1;
785 }
786 #endif
787 
788 /*
789  * Check to see if dma has finished for a channel */
790 int
nextdma_finished(struct nextdma_softc * nsc)791 nextdma_finished(struct nextdma_softc *nsc)
792 {
793 	int r;
794 	int s;
795 	struct nextdma_status *stat = &nsc->sc_stat;
796 
797 	s = spldma();
798 	r = (stat->nd_map == NULL) && (stat->nd_map_cont == NULL);
799 	splx(s);
800 
801 	return r;
802 }
803 
804 void
nextdma_start(struct nextdma_softc * nsc,u_long dmadir)805 nextdma_start(struct nextdma_softc *nsc, u_long dmadir)
806 {
807 	struct nextdma_status *stat = &nsc->sc_stat;
808 
809 	NDTRACEIF(ndtrace_addc('n'));
810 #ifdef DIAGNOSTIC
811 	if (!nextdma_finished(nsc)) {
812 		char sbuf[256];
813 
814 		snprintb(sbuf, sizeof(sbuf),
815 		    NEXT_INTR_BITS, NEXT_I_BIT(nsc->sc_chan->nd_intr));
816 		panic("DMA trying to start before previous finished"
817 		    " on intr(%s)", sbuf);
818 	}
819 #endif
820 
821 #ifdef ND_DEBUG
822 	if (NEXTDMA_DEBUG) {
823 		char sbuf[256];
824 
825 		snprintb(sbuf, sizeof(sbuf),
826 		    NEXT_INTR_BITS, NEXT_I_BIT(nsc->sc_chan->nd_intr));
827 		printf("DMA start (%ld) intr(%s)\n",
828 		    NEXT_I_IPL(nsc->sc_chan->nd_intr), sbuf);
829 	}
830 #endif
831 
832 #ifdef DIAGNOSTIC
833 	if (stat->nd_map != NULL) {
834 		nextdma_print(nsc);
835 		panic("DMA: nextdma_start() with non null map");
836 	}
837 	if (stat->nd_map_cont != NULL) {
838 		nextdma_print(nsc);
839 		panic("DMA: nextdma_start() with non null continue map");
840 	}
841 #endif
842 
843 #ifdef DIAGNOSTIC
844 	if (dmadir != DMACSR_SETREAD && dmadir != DMACSR_SETWRITE) {
845 		panic("DMA: nextdma_start(), dmadir arg must be"
846 		    " DMACSR_SETREAD or DMACSR_SETWRITE");
847 	}
848 #endif
849 
850 #if defined(ND_DEBUG)
851 	nextdma_debug_initstate(nsc);
852 #endif
853 
854 	/* preload both the current and the continue maps */
855 	nextdma_rotate(nsc);
856 
857 #ifdef DIAGNOSTIC
858 	if (stat->nd_map_cont == NULL) {
859 		panic("No map available in nextdma_start()");
860 	}
861 #endif
862 
863 	nextdma_rotate(nsc);
864 
865 #ifdef ND_DEBUG
866 	if (NEXTDMA_DEBUG) {
867 		char sbuf[256];
868 
869 		snprintb(sbuf, sizeof(sbuf),
870 		    NEXT_INTR_BITS, NEXT_I_BIT(nsc->sc_chan->nd_intr));
871 		printf("DMA initiating DMA %s of %d segments on intr(%s)\n",
872 		    (dmadir == DMACSR_SETREAD ? "read" : "write"),
873 		    stat->nd_map->dm_nsegs, sbuf);
874 	}
875 #endif
876 
877 	nd_bsw4(DD_CSR, (turbo ?
878 	    DMACSR_INITBUFTURBO : DMACSR_INITBUF) | DMACSR_RESET | dmadir);
879 	nd_bsw4(DD_CSR, 0);
880 
881 	nextdma_setup_curr_regs(nsc);
882 	nextdma_setup_cont_regs(nsc);
883 
884 #if (defined(ND_DEBUG))
885 	if (NEXTDMA_DEBUG > 2)
886 		nextdma_print(nsc);
887 #endif
888 
889 	if (stat->nd_map_cont == NULL) {
890 		nd_bsw4(DD_CSR, DMACSR_SETENABLE | dmadir);
891 	} else {
892 		nd_bsw4(DD_CSR, DMACSR_SETSUPDATE | DMACSR_SETENABLE | dmadir);
893 	}
894 }
895 
896 /* This routine is used for debugging */
897 void
nextdma_print(struct nextdma_softc * nsc)898 nextdma_print(struct nextdma_softc *nsc)
899 {
900 	u_long dd_csr;
901 	u_long dd_next;
902 	u_long dd_next_initbuf;
903 	u_long dd_limit;
904 	u_long dd_start;
905 	u_long dd_stop;
906 	u_long dd_saved_next;
907 	u_long dd_saved_limit;
908 	u_long dd_saved_start;
909 	u_long dd_saved_stop;
910 	char sbuf[256];
911 	struct nextdma_status *stat = &nsc->sc_stat;
912 
913 	/*
914 	 * Read all of the registers before we print anything out,
915 	 * in case something changes
916 	 */
917 	dd_csr          = nd_bsr4(DD_CSR);
918 	dd_next         = nd_bsr4(DD_NEXT);
919 	dd_next_initbuf = nd_bsr4(DD_NEXT_INITBUF);
920 	dd_limit        = nd_bsr4(DD_LIMIT);
921 	dd_start        = nd_bsr4(DD_START);
922 	dd_stop         = nd_bsr4(DD_STOP);
923 	dd_saved_next   = nd_bsr4(DD_SAVED_NEXT);
924 	dd_saved_limit  = nd_bsr4(DD_SAVED_LIMIT);
925 	dd_saved_start  = nd_bsr4(DD_SAVED_START);
926 	dd_saved_stop   = nd_bsr4(DD_SAVED_STOP);
927 
928 	snprintb(sbuf, sizeof(sbuf), NEXT_INTR_BITS,
929 	    *(volatile u_long *)IIOV(NEXT_P_INTRSTAT));
930 	printf("NDMAP: *intrstat = %s\n", sbuf);
931 
932 	snprintb(sbuf, sizeof(sbuf), NEXT_INTR_BITS,
933 	    *(volatile u_long *)IIOV(NEXT_P_INTRMASK));
934 	printf("NDMAP: *intrmask = %s\n", sbuf);
935 
936 	/* NDMAP is Next DMA Print (really!) */
937 
938 	if (stat->nd_map != NULL) {
939 		int i;
940 
941 		printf("NDMAP: nd_map->dm_mapsize = %ld\n",
942 		    stat->nd_map->dm_mapsize);
943 		printf("NDMAP: nd_map->dm_nsegs = %d\n",
944 		    stat->nd_map->dm_nsegs);
945 		printf("NDMAP: nd_map->dm_xfer_len = %ld\n",
946 		    stat->nd_map->dm_xfer_len);
947 		printf("NDMAP: nd_map->dm_segs[%d].ds_addr = 0x%08lx\n",
948 		    stat->nd_idx, stat->nd_map->dm_segs[stat->nd_idx].ds_addr);
949 		printf("NDMAP: nd_map->dm_segs[%d].ds_len = %ld\n",
950 		    stat->nd_idx, stat->nd_map->dm_segs[stat->nd_idx].ds_len);
951 
952 		printf("NDMAP: Entire map;\n");
953 		for(i = 0; i < stat->nd_map->dm_nsegs; i++) {
954 			printf("NDMAP:   "
955 			    "nd_map->dm_segs[%d].ds_addr = 0x%08lx\n",
956 			    i, stat->nd_map->dm_segs[i].ds_addr);
957 			printf("NDMAP:   nd_map->dm_segs[%d].ds_len = %ld\n",
958 			    i, stat->nd_map->dm_segs[i].ds_len);
959 		}
960 	} else {
961 		printf("NDMAP: nd_map = NULL\n");
962 	}
963 	if (stat->nd_map_cont != NULL) {
964 		printf("NDMAP: nd_map_cont->dm_mapsize = %ld\n",
965 		    stat->nd_map_cont->dm_mapsize);
966 		printf("NDMAP: nd_map_cont->dm_nsegs = %d\n",
967 		    stat->nd_map_cont->dm_nsegs);
968 		printf("NDMAP: nd_map_cont->dm_xfer_len = %ld\n",
969 		    stat->nd_map_cont->dm_xfer_len);
970 		printf("NDMAP: nd_map_cont->dm_segs[%d].ds_addr = 0x%08lx\n",
971 		    stat->nd_idx_cont,
972 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_addr);
973 		printf("NDMAP: nd_map_cont->dm_segs[%d].ds_len = %ld\n",
974 		    stat->nd_idx_cont,
975 		    stat->nd_map_cont->dm_segs[stat->nd_idx_cont].ds_len);
976 		if (stat->nd_map_cont != stat->nd_map) {
977 			int i;
978 			printf("NDMAP: Entire map;\n");
979 			for(i=0;i<stat->nd_map_cont->dm_nsegs;i++) {
980 				printf("NDMAP:   "
981 				    "nd_map_cont->dm_segs[%d].ds_addr"
982 				    " = 0x%08lx\n",
983 				    i, stat->nd_map_cont->dm_segs[i].ds_addr);
984 				printf("NDMAP:   "
985 				    "nd_map_cont->dm_segs[%d].ds_len = %ld\n",
986 				    i, stat->nd_map_cont->dm_segs[i].ds_len);
987 			}
988 		}
989 	} else {
990 		printf("NDMAP: nd_map_cont = NULL\n");
991 	}
992 
993 	snprintb(sbuf, sizeof(sbuf), DMACSR_BITS, dd_csr);
994 	printf("NDMAP: dd->dd_csr          = %s\n",   sbuf);
995 
996 	printf("NDMAP: dd->dd_saved_next   = 0x%08lx\n", dd_saved_next);
997 	printf("NDMAP: dd->dd_saved_limit  = 0x%08lx\n", dd_saved_limit);
998 	printf("NDMAP: dd->dd_saved_start  = 0x%08lx\n", dd_saved_start);
999 	printf("NDMAP: dd->dd_saved_stop   = 0x%08lx\n", dd_saved_stop);
1000 	printf("NDMAP: dd->dd_next         = 0x%08lx\n", dd_next);
1001 	printf("NDMAP: dd->dd_next_initbuf = 0x%08lx\n", dd_next_initbuf);
1002 	printf("NDMAP: dd->dd_limit        = 0x%08lx\n", dd_limit);
1003 	printf("NDMAP: dd->dd_start        = 0x%08lx\n", dd_start);
1004 	printf("NDMAP: dd->dd_stop         = 0x%08lx\n", dd_stop);
1005 
1006 	snprintb(sbuf, sizeof(sbuf), NEXT_INTR_BITS,
1007 	    NEXT_I_BIT(nsc->sc_chan->nd_intr));
1008 	printf("NDMAP: interrupt ipl (%ld) intr(%s)\n",
1009 	    NEXT_I_IPL(nsc->sc_chan->nd_intr), sbuf);
1010 }
1011 
1012 #if defined(ND_DEBUG)
1013 void
nextdma_debug_initstate(struct nextdma_softc * nsc)1014 nextdma_debug_initstate(struct nextdma_softc *nsc)
1015 {
1016 	switch(nsc->sc_chan->nd_intr) {
1017 	case NEXT_I_ENETR_DMA:
1018 		memset(nextdma_debug_enetr_state, 0,
1019 		    sizeof(nextdma_debug_enetr_state));
1020 		break;
1021 	case NEXT_I_SCSI_DMA:
1022 		memset(nextdma_debug_scsi_state, 0,
1023 		    sizeof(nextdma_debug_scsi_state));
1024 		break;
1025 	}
1026 }
1027 
1028 void
nextdma_debug_savestate(struct nextdma_softc * nsc,unsigned int state)1029 nextdma_debug_savestate(struct nextdma_softc *nsc, unsigned int state)
1030 {
1031 
1032 	switch(nsc->sc_chan->nd_intr) {
1033 	case NEXT_I_ENETR_DMA:
1034 		nextdma_debug_enetr_state[nextdma_debug_enetr_idx++] = state;
1035 		nextdma_debug_enetr_idx %=
1036 		    (sizeof(nextdma_debug_enetr_state) / sizeof(unsigned int));
1037 		break;
1038 	case NEXT_I_SCSI_DMA:
1039 		nextdma_debug_scsi_state[nextdma_debug_scsi_idx++] = state;
1040 		nextdma_debug_scsi_idx %=
1041 		    (sizeof(nextdma_debug_scsi_state) / sizeof(unsigned int));
1042 		break;
1043 	}
1044 }
1045 
1046 void
nextdma_debug_enetr_dumpstate(void)1047 nextdma_debug_enetr_dumpstate(void)
1048 {
1049 	int i;
1050 	int s;
1051 	s = spldma();
1052 	i = nextdma_debug_enetr_idx;
1053 	do {
1054 		char sbuf[256];
1055 		if (nextdma_debug_enetr_state[i]) {
1056 			snprintb(sbuf, sizeof(sbuf), DMACSR_BITS,
1057 			    nextdma_debug_enetr_state[i]);
1058 			printf("DMA: 0x%02x state %s\n", i, sbuf);
1059 		}
1060 		i++;
1061 		i %= (sizeof(nextdma_debug_enetr_state) / sizeof(unsigned int));
1062 	} while (i != nextdma_debug_enetr_idx);
1063 	splx(s);
1064 }
1065 
1066 void
nextdma_debug_scsi_dumpstate(void)1067 nextdma_debug_scsi_dumpstate(void)
1068 {
1069 	int i;
1070 	int s;
1071 	s = spldma();
1072 	i = nextdma_debug_scsi_idx;
1073 	do {
1074 		char sbuf[256];
1075 		if (nextdma_debug_scsi_state[i]) {
1076 			snprintb(sbuf, sizeof(sbuf), DMACSR_BITS,
1077 			    nextdma_debug_scsi_state[i]);
1078 			printf("DMA: 0x%02x state %s\n", i, sbuf);
1079 		}
1080 		i++;
1081 		i %= (sizeof(nextdma_debug_scsi_state) / sizeof(unsigned int));
1082 	} while (i != nextdma_debug_scsi_idx);
1083 	splx(s);
1084 }
1085 #endif
1086