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