xref: /netbsd-src/sys/dev/ic/am79900.c (revision a30f264f2a5f410ffefcc55600a9238b3a0c935c)
1 /*	$NetBSD: am79900.c,v 1.17 2005/12/24 20:27:29 perry Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 1992, 1993
41  *	The Regents of the University of California.  All rights reserved.
42  *
43  * This code is derived from software contributed to Berkeley by
44  * Ralph Campbell and Rick Macklem.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. Neither the name of the University nor the names of its contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  *
70  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
71  */
72 
73 /*-
74  * Copyright (c) 1998
75  *	Matthias Drochner.  All rights reserved.
76  * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
77  *
78  * This code is derived from software contributed to Berkeley by
79  * Ralph Campbell and Rick Macklem.
80  *
81  * Redistribution and use in source and binary forms, with or without
82  * modification, are permitted provided that the following conditions
83  * are met:
84  * 1. Redistributions of source code must retain the above copyright
85  *    notice, this list of conditions and the following disclaimer.
86  * 2. Redistributions in binary form must reproduce the above copyright
87  *    notice, this list of conditions and the following disclaimer in the
88  *    documentation and/or other materials provided with the distribution.
89  * 3. All advertising materials mentioning features or use of this software
90  *    must display the following acknowledgement:
91  *	This product includes software developed by the University of
92  *	California, Berkeley and its contributors.
93  * 4. Neither the name of the University nor the names of its contributors
94  *    may be used to endorse or promote products derived from this software
95  *    without specific prior written permission.
96  *
97  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
98  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
99  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
100  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
101  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
102  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
103  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
104  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
105  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
106  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
107  * SUCH DAMAGE.
108  *
109  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
110  */
111 
112 #include <sys/cdefs.h>
113 __KERNEL_RCSID(0, "$NetBSD: am79900.c,v 1.17 2005/12/24 20:27:29 perry Exp $");
114 
115 #include "bpfilter.h"
116 #include "rnd.h"
117 
118 #include <sys/param.h>
119 #include <sys/systm.h>
120 #include <sys/mbuf.h>
121 #include <sys/syslog.h>
122 #include <sys/socket.h>
123 #include <sys/device.h>
124 #include <sys/malloc.h>
125 #include <sys/ioctl.h>
126 #include <sys/errno.h>
127 #if NRND > 0
128 #include <sys/rnd.h>
129 #endif
130 
131 #include <net/if.h>
132 #include <net/if_dl.h>
133 #include <net/if_ether.h>
134 #include <net/if_media.h>
135 
136 #if NBPFILTER > 0
137 #include <net/bpf.h>
138 #include <net/bpfdesc.h>
139 #endif
140 
141 #include <dev/ic/lancereg.h>
142 #include <dev/ic/lancevar.h>
143 #include <dev/ic/am79900reg.h>
144 #include <dev/ic/am79900var.h>
145 
146 static void	am79900_meminit(struct lance_softc *);
147 static void	am79900_start(struct ifnet *);
148 
149 #if defined(_KERNEL_OPT)
150 #include "opt_ddb.h"
151 #endif
152 
153 #ifdef LEDEBUG
154 static void	am79900_recv_print(struct lance_softc *, int);
155 static void	am79900_xmit_print(struct lance_softc *, int);
156 #endif
157 
158 #define	ifp	(&sc->sc_ethercom.ec_if)
159 
160 void
161 am79900_config(struct am79900_softc *sc)
162 {
163 	int mem, i;
164 
165 	sc->lsc.sc_meminit = am79900_meminit;
166 	sc->lsc.sc_start = am79900_start;
167 
168 	lance_config(&sc->lsc);
169 
170 	mem = 0;
171 	sc->lsc.sc_initaddr = mem;
172 	mem += sizeof(struct leinit);
173 	sc->lsc.sc_rmdaddr = mem;
174 	mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
175 	sc->lsc.sc_tmdaddr = mem;
176 	mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
177 	for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN)
178 		sc->lsc.sc_rbufaddr[i] = mem;
179 	for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN)
180 		sc->lsc.sc_tbufaddr[i] = mem;
181 
182 	if (mem > sc->lsc.sc_memsize)
183 		panic("%s: memsize", sc->lsc.sc_dev.dv_xname);
184 }
185 
186 /*
187  * Set up the initialization block and the descriptor rings.
188  */
189 static void
190 am79900_meminit(struct lance_softc *sc)
191 {
192 	u_long a;
193 	int bix;
194 	struct leinit init;
195 	struct lermd rmd;
196 	struct letmd tmd;
197 	u_int8_t *myaddr;
198 
199 #if NBPFILTER > 0
200 	if (ifp->if_flags & IFF_PROMISC)
201 		init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
202 	else
203 #endif
204 		init.init_mode = LE_MODE_NORMAL;
205 	if (sc->sc_initmodemedia == 1)
206 		init.init_mode |= LE_MODE_PSEL0;
207 
208 	init.init_mode |= ((ffs(sc->sc_ntbuf) - 1) << 28)
209 	  | ((ffs(sc->sc_nrbuf) - 1) << 20);
210 
211 	/*
212 	 * Update our private copy of the Ethernet address.
213 	 * We NEED the copy so we can ensure its alignment!
214 	 */
215 	memcpy(sc->sc_enaddr, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
216 	myaddr = sc->sc_enaddr;
217 
218 	init.init_padr[0] = myaddr[0] | (myaddr[1] << 8)
219 	  | (myaddr[2] << 16) | (myaddr[3] << 24);
220 	init.init_padr[1] = myaddr[4] | (myaddr[5] << 8);
221 	lance_setladrf(&sc->sc_ethercom, init.init_ladrf);
222 
223 	sc->sc_last_rd = 0;
224 	sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
225 
226 	a = sc->sc_addr + LE_RMDADDR(sc, 0);
227 	init.init_rdra = a;
228 
229 	a = sc->sc_addr + LE_TMDADDR(sc, 0);
230 	init.init_tdra = a;
231 
232 	(*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
233 
234 	/*
235 	 * Set up receive ring descriptors.
236 	 */
237 	for (bix = 0; bix < sc->sc_nrbuf; bix++) {
238 		a = sc->sc_addr + LE_RBUFADDR(sc, bix);
239 		rmd.rmd0 = a;
240 		rmd.rmd1 = LE_R1_OWN | LE_R1_ONES | (-LEBLEN & 0xfff);
241 		rmd.rmd2 = 0;
242 		rmd.rmd3 = 0;
243 		(*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
244 		    sizeof(rmd));
245 	}
246 
247 	/*
248 	 * Set up transmit ring descriptors.
249 	 */
250 	for (bix = 0; bix < sc->sc_ntbuf; bix++) {
251 		a = sc->sc_addr + LE_TBUFADDR(sc, bix);
252 		tmd.tmd0 = a;
253 		tmd.tmd1 = LE_T1_ONES;
254 		tmd.tmd2 = 0;
255 		tmd.tmd3 = 0;
256 		(*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
257 		    sizeof(tmd));
258 	}
259 }
260 
261 static inline void
262 am79900_rint(struct lance_softc *sc)
263 {
264 	int bix;
265 	int rp;
266 	struct lermd rmd;
267 
268 	bix = sc->sc_last_rd;
269 
270 	/* Process all buffers with valid data. */
271 	for (;;) {
272 		rp = LE_RMDADDR(sc, bix);
273 		(*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
274 
275 		if (rmd.rmd1 & LE_R1_OWN)
276 			break;
277 
278 		if (rmd.rmd1 & LE_R1_ERR) {
279 			if (rmd.rmd1 & LE_R1_ENP) {
280 #ifdef LEDEBUG
281 				if ((rmd.rmd1 & LE_R1_OFLO) == 0) {
282 					if (rmd.rmd1 & LE_R1_FRAM)
283 						printf("%s: framing error\n",
284 						    sc->sc_dev.dv_xname);
285 					if (rmd.rmd1 & LE_R1_CRC)
286 						printf("%s: crc mismatch\n",
287 						    sc->sc_dev.dv_xname);
288 				}
289 #endif
290 			} else {
291 				if (rmd.rmd1 & LE_R1_OFLO)
292 					printf("%s: overflow\n",
293 					    sc->sc_dev.dv_xname);
294 			}
295 			if (rmd.rmd1 & LE_R1_BUFF)
296 				printf("%s: receive buffer error\n",
297 				    sc->sc_dev.dv_xname);
298 			ifp->if_ierrors++;
299 		} else if ((rmd.rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
300 		    (LE_R1_STP | LE_R1_ENP)) {
301 			printf("%s: dropping chained buffer\n",
302 			    sc->sc_dev.dv_xname);
303 			ifp->if_ierrors++;
304 		} else {
305 #ifdef LEDEBUG
306 			if (sc->sc_debug)
307 				am79900_recv_print(sc, sc->sc_last_rd);
308 #endif
309 			lance_read(sc, LE_RBUFADDR(sc, bix),
310 				   (rmd.rmd2  & 0xfff) - 4);
311 		}
312 
313 		rmd.rmd1 = LE_R1_OWN | LE_R1_ONES | (-LEBLEN & 0xfff);
314 		rmd.rmd2 = 0;
315 		rmd.rmd3 = 0;
316 		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
317 
318 #ifdef LEDEBUG
319 		if (sc->sc_debug)
320 			printf("sc->sc_last_rd = %x, rmd: "
321 			       "adr %08x, flags/blen %08x\n",
322 				sc->sc_last_rd,
323 				rmd.rmd0, rmd.rmd1);
324 #endif
325 
326 		if (++bix == sc->sc_nrbuf)
327 			bix = 0;
328 	}
329 
330 	sc->sc_last_rd = bix;
331 }
332 
333 static inline void
334 am79900_tint(struct lance_softc *sc)
335 {
336 	int bix;
337 	struct letmd tmd;
338 
339 	bix = sc->sc_first_td;
340 
341 	for (;;) {
342 		if (sc->sc_no_td <= 0)
343 			break;
344 
345 		(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
346 		    sizeof(tmd));
347 
348 #ifdef LEDEBUG
349 		if (sc->sc_debug)
350 			printf("trans tmd: "
351 			    "adr %08x, flags/blen %08x\n",
352 			    tmd.tmd0, tmd.tmd1);
353 #endif
354 
355 		if (tmd.tmd1 & LE_T1_OWN)
356 			break;
357 
358 		ifp->if_flags &= ~IFF_OACTIVE;
359 
360 		if (tmd.tmd1 & LE_T1_ERR) {
361 			if (tmd.tmd2 & LE_T2_BUFF)
362 				printf("%s: transmit buffer error\n",
363 				    sc->sc_dev.dv_xname);
364 			else if (tmd.tmd2 & LE_T2_UFLO)
365 				printf("%s: underflow\n", sc->sc_dev.dv_xname);
366 			if (tmd.tmd2 & (LE_T2_BUFF | LE_T2_UFLO)) {
367 				lance_reset(sc);
368 				return;
369 			}
370 			if (tmd.tmd2 & LE_T2_LCAR) {
371 				sc->sc_havecarrier = 0;
372 				if (sc->sc_nocarrier)
373 					(*sc->sc_nocarrier)(sc);
374 				else
375 					printf("%s: lost carrier\n",
376 					    sc->sc_dev.dv_xname);
377 			}
378 			if (tmd.tmd2 & LE_T2_LCOL)
379 				ifp->if_collisions++;
380 			if (tmd.tmd2 & LE_T2_RTRY) {
381 #ifdef LEDEBUG
382 				printf("%s: excessive collisions\n",
383 				    sc->sc_dev.dv_xname);
384 #endif
385 				ifp->if_collisions += 16;
386 			}
387 			ifp->if_oerrors++;
388 		} else {
389 			if (tmd.tmd1 & LE_T1_ONE)
390 				ifp->if_collisions++;
391 			else if (tmd.tmd1 & LE_T1_MORE)
392 				/* Real number is unknown. */
393 				ifp->if_collisions += 2;
394 			ifp->if_opackets++;
395 		}
396 
397 		if (++bix == sc->sc_ntbuf)
398 			bix = 0;
399 
400 		--sc->sc_no_td;
401 	}
402 
403 	sc->sc_first_td = bix;
404 
405 	am79900_start(ifp);
406 
407 	if (sc->sc_no_td == 0)
408 		ifp->if_timer = 0;
409 }
410 
411 /*
412  * Controller interrupt.
413  */
414 int
415 am79900_intr(void *arg)
416 {
417 	struct lance_softc *sc = arg;
418 	u_int16_t isr;
419 
420 	isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
421 	sc->sc_saved_csr0 = 0;
422 #if defined(LEDEBUG) && LEDEBUG > 1
423 	if (sc->sc_debug)
424 		printf("%s: am79900_intr entering with isr=%04x\n",
425 		    sc->sc_dev.dv_xname, isr);
426 #endif
427 	if ((isr & LE_C0_INTR) == 0)
428 		return (0);
429 
430 	(*sc->sc_wrcsr)(sc, LE_CSR0,
431 	    isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
432 		   LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
433 	if (isr & LE_C0_ERR) {
434 		if (isr & LE_C0_BABL) {
435 #ifdef LEDEBUG
436 			printf("%s: babble\n", sc->sc_dev.dv_xname);
437 #endif
438 			ifp->if_oerrors++;
439 		}
440 #if 0
441 		if (isr & LE_C0_CERR) {
442 			printf("%s: collision error\n", sc->sc_dev.dv_xname);
443 			ifp->if_collisions++;
444 		}
445 #endif
446 		if (isr & LE_C0_MISS) {
447 #ifdef LEDEBUG
448 			printf("%s: missed packet\n", sc->sc_dev.dv_xname);
449 #endif
450 			ifp->if_ierrors++;
451 		}
452 		if (isr & LE_C0_MERR) {
453 			printf("%s: memory error\n", sc->sc_dev.dv_xname);
454 			lance_reset(sc);
455 			return (1);
456 		}
457 	}
458 
459 	if ((isr & LE_C0_RXON) == 0) {
460 		printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
461 		ifp->if_ierrors++;
462 		lance_reset(sc);
463 		return (1);
464 	}
465 	if ((isr & LE_C0_TXON) == 0) {
466 		printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
467 		ifp->if_oerrors++;
468 		lance_reset(sc);
469 		return (1);
470 	}
471 
472 	/*
473 	 * Pretend we have carrier; if we don't this will be cleared
474 	 * shortly.
475 	 */
476 	sc->sc_havecarrier = 1;
477 
478 	if (isr & LE_C0_RINT)
479 		am79900_rint(sc);
480 	if (isr & LE_C0_TINT)
481 		am79900_tint(sc);
482 
483 #if NRND > 0
484 	rnd_add_uint32(&sc->rnd_source, isr);
485 #endif
486 
487 	return (1);
488 }
489 
490 #undef	ifp
491 
492 /*
493  * Setup output on interface.
494  * Get another datagram to send off of the interface queue, and map it to the
495  * interface before starting the output.
496  * Called only at splnet or interrupt level.
497  */
498 static void
499 am79900_start(struct ifnet *ifp)
500 {
501 	struct lance_softc *sc = ifp->if_softc;
502 	int bix;
503 	struct mbuf *m;
504 	struct letmd tmd;
505 	int rp;
506 	int len;
507 
508 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
509 		return;
510 
511 	bix = sc->sc_last_td;
512 
513 	for (;;) {
514 		rp = LE_TMDADDR(sc, bix);
515 		(*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
516 
517 		if (tmd.tmd1 & LE_T1_OWN) {
518 			ifp->if_flags |= IFF_OACTIVE;
519 			printf("missing buffer, no_td = %d, last_td = %d\n",
520 			    sc->sc_no_td, sc->sc_last_td);
521 		}
522 
523 		IFQ_DEQUEUE(&ifp->if_snd, m);
524 		if (m == 0)
525 			break;
526 
527 #if NBPFILTER > 0
528 		/*
529 		 * If BPF is listening on this interface, let it see the packet
530 		 * before we commit it to the wire.
531 		 */
532 		if (ifp->if_bpf)
533 			bpf_mtap(ifp->if_bpf, m);
534 #endif
535 
536 		/*
537 		 * Copy the mbuf chain into the transmit buffer.
538 		 */
539 		len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
540 
541 #ifdef LEDEBUG
542 		if (len > ETHERMTU + sizeof(struct ether_header))
543 			printf("packet length %d\n", len);
544 #endif
545 
546 		ifp->if_timer = 5;
547 
548 		/*
549 		 * Init transmit registers, and set transmit start flag.
550 		 */
551 		tmd.tmd1 = LE_T1_OWN | LE_T1_STP | LE_T1_ENP | LE_T1_ONES | (-len & 0xfff);
552 		tmd.tmd2 = 0;
553 		tmd.tmd3 = 0;
554 
555 		(*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
556 
557 #ifdef LEDEBUG
558 		if (sc->sc_debug)
559 			am79900_xmit_print(sc, sc->sc_last_td);
560 #endif
561 
562 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
563 
564 		if (++bix == sc->sc_ntbuf)
565 			bix = 0;
566 
567 		if (++sc->sc_no_td == sc->sc_ntbuf) {
568 			ifp->if_flags |= IFF_OACTIVE;
569 			break;
570 		}
571 
572 	}
573 
574 	sc->sc_last_td = bix;
575 }
576 
577 #ifdef LEDEBUG
578 static void
579 am79900_recv_print(struct lance_softc *sc, int no)
580 {
581 	struct lermd rmd;
582 	u_int16_t len;
583 	struct ether_header eh;
584 
585 	(*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
586 	len = (rmd.rmd2  & 0xfff) - 4;
587 	printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
588 	    len);
589 	printf("%s: status %04x\n", sc->sc_dev.dv_xname,
590 	    (*sc->sc_rdcsr)(sc, LE_CSR0));
591 	printf("%s: adr %08x, flags/blen %08x\n",
592 	    sc->sc_dev.dv_xname, rmd.rmd0, rmd.rmd1);
593 	if (len >= sizeof(eh)) {
594 		(*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
595 		printf("%s: dst %s", sc->sc_dev.dv_xname,
596 			ether_sprintf(eh.ether_dhost));
597 		printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
598 			ntohs(eh.ether_type));
599 	}
600 }
601 
602 static void
603 am79900_xmit_print(struct lance_softc *sc, int no)
604 {
605 	struct letmd tmd;
606 	u_int16_t len;
607 	struct ether_header eh;
608 
609 	(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
610 	len = -(tmd.tmd1 & 0xfff);
611 	printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
612 	    len);
613 	printf("%s: status %04x\n", sc->sc_dev.dv_xname,
614 	    (*sc->sc_rdcsr)(sc, LE_CSR0));
615 	printf("%s: adr %08x, flags/blen %08x\n",
616 	    sc->sc_dev.dv_xname, tmd.tmd0, tmd.tmd1);
617 	if (len >= sizeof(eh)) {
618 		(*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
619 		printf("%s: dst %s", sc->sc_dev.dv_xname,
620 			ether_sprintf(eh.ether_dhost));
621 		printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
622 		    ntohs(eh.ether_type));
623 	}
624 }
625 #endif /* LEDEBUG */
626