1 /* $OpenBSD: am79900.c,v 1.8 2020/07/10 13:22:19 patrick 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 #include <netinet/in.h>
122 #include <netinet/if_ether.h>
123
124 #if NBPFILTER > 0
125 #include <net/bpf.h>
126 #endif
127
128 #include <dev/ic/lancereg.h>
129 #include <dev/ic/lancevar.h>
130 #include <dev/ic/am79900reg.h>
131 #include <dev/ic/am79900var.h>
132
133 void am79900_meminit(struct lance_softc *);
134 void am79900_start(struct ifnet *);
135
136 void am79900_rint(struct lance_softc *);
137 void am79900_tint(struct lance_softc *);
138
139 #ifdef LEDEBUG
140 void am79900_recv_print(struct lance_softc *, int);
141 void am79900_xmit_print(struct lance_softc *, int);
142 #endif
143
144 void
am79900_config(struct am79900_softc * sc)145 am79900_config(struct am79900_softc *sc)
146 {
147 int mem, i;
148
149 sc->lsc.sc_meminit = am79900_meminit;
150 sc->lsc.sc_start = am79900_start;
151
152 lance_config(&sc->lsc);
153
154 mem = 0;
155 sc->lsc.sc_initaddr = mem;
156 mem += sizeof(struct leinit);
157 sc->lsc.sc_rmdaddr = mem;
158 mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
159 sc->lsc.sc_tmdaddr = mem;
160 mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
161 for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN)
162 sc->lsc.sc_rbufaddr[i] = mem;
163 for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN)
164 sc->lsc.sc_tbufaddr[i] = mem;
165
166 if (mem > sc->lsc.sc_memsize)
167 panic("%s: memsize", sc->lsc.sc_dev.dv_xname);
168 }
169
170 /*
171 * Set up the initialization block and the descriptor rings.
172 */
173 void
am79900_meminit(struct lance_softc * sc)174 am79900_meminit(struct lance_softc *sc)
175 {
176 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
177 u_long a;
178 int bix;
179 struct leinit init;
180 struct lermd rmd;
181 struct letmd tmd;
182 uint8_t *myaddr;
183
184 if (ifp->if_flags & IFF_PROMISC)
185 init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
186 else
187 init.init_mode = LE_MODE_NORMAL;
188 if (sc->sc_initmodemedia == 1)
189 init.init_mode |= LE_MODE_PSEL0;
190
191 init.init_mode |= ((ffs(sc->sc_ntbuf) - 1) << 28) |
192 ((ffs(sc->sc_nrbuf) - 1) << 20);
193
194 /*
195 * Update our private copy of the Ethernet address.
196 * We NEED the copy so we can ensure its alignment!
197 */
198 memcpy(sc->sc_enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
199 myaddr = sc->sc_enaddr;
200
201 init.init_padr[0] = myaddr[0] | (myaddr[1] << 8) |
202 (myaddr[2] << 16) | (myaddr[3] << 24);
203 init.init_padr[1] = myaddr[4] | (myaddr[5] << 8);
204 lance_setladrf(&sc->sc_arpcom, init.init_ladrf);
205
206 sc->sc_last_rd = 0;
207 sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
208
209 a = sc->sc_addr + LE_RMDADDR(sc, 0);
210 init.init_rdra = a;
211
212 a = sc->sc_addr + LE_TMDADDR(sc, 0);
213 init.init_tdra = a;
214
215 (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
216
217 /*
218 * Set up receive ring descriptors.
219 */
220 for (bix = 0; bix < sc->sc_nrbuf; bix++) {
221 a = sc->sc_addr + LE_RBUFADDR(sc, bix);
222 rmd.rmd0 = a;
223 rmd.rmd1 = LE_R1_OWN | LE_R1_ONES | (-LEBLEN & 0xfff);
224 rmd.rmd2 = 0;
225 rmd.rmd3 = 0;
226 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
227 sizeof(rmd));
228 }
229
230 /*
231 * Set up transmit ring descriptors.
232 */
233 for (bix = 0; bix < sc->sc_ntbuf; bix++) {
234 a = sc->sc_addr + LE_TBUFADDR(sc, bix);
235 tmd.tmd0 = a;
236 tmd.tmd1 = LE_T1_ONES;
237 tmd.tmd2 = 0;
238 tmd.tmd3 = 0;
239 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
240 sizeof(tmd));
241 }
242 }
243
244 void
am79900_rint(struct lance_softc * sc)245 am79900_rint(struct lance_softc *sc)
246 {
247 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
248 struct mbuf *m;
249 struct mbuf_list ml = MBUF_LIST_INITIALIZER();
250 int bix;
251 int rp;
252 struct lermd rmd;
253
254 bix = sc->sc_last_rd;
255
256 /* Process all buffers with valid data. */
257 for (;;) {
258 rp = LE_RMDADDR(sc, bix);
259 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
260
261 if (rmd.rmd1 & LE_R1_OWN)
262 break;
263
264 if (rmd.rmd1 & LE_R1_ERR) {
265 if (rmd.rmd1 & LE_R1_ENP) {
266 #ifdef LEDEBUG
267 if ((rmd.rmd1 & LE_R1_OFLO) == 0) {
268 if (rmd.rmd1 & LE_R1_FRAM)
269 printf("%s: framing error\n",
270 sc->sc_dev.dv_xname);
271 if (rmd.rmd1 & LE_R1_CRC)
272 printf("%s: crc mismatch\n",
273 sc->sc_dev.dv_xname);
274 }
275 #endif
276 } else {
277 if (rmd.rmd1 & LE_R1_OFLO)
278 printf("%s: overflow\n",
279 sc->sc_dev.dv_xname);
280 }
281 if (rmd.rmd1 & LE_R1_BUFF)
282 printf("%s: receive buffer error\n",
283 sc->sc_dev.dv_xname);
284 ifp->if_ierrors++;
285 } else if ((rmd.rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
286 (LE_R1_STP | LE_R1_ENP)) {
287 printf("%s: dropping chained buffer\n",
288 sc->sc_dev.dv_xname);
289 ifp->if_ierrors++;
290 } else {
291 #ifdef LEDEBUG
292 if (sc->sc_debug > 1)
293 am79900_recv_print(sc, sc->sc_last_rd);
294 #endif
295 m = lance_read(sc, LE_RBUFADDR(sc, bix),
296 (rmd.rmd2 & 0xfff) - 4);
297 if (m != NULL)
298 ml_enqueue(&ml, m);
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 if_input(ifp, &ml);
321 }
322
323 void
am79900_tint(struct lance_softc * sc)324 am79900_tint(struct lance_softc *sc)
325 {
326 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
327 int bix;
328 struct letmd tmd;
329
330 bix = sc->sc_first_td;
331
332 for (;;) {
333 if (sc->sc_no_td <= 0)
334 break;
335
336 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
337 sizeof(tmd));
338
339 #ifdef LEDEBUG
340 if (sc->sc_debug)
341 printf("trans tmd: "
342 "adr %08x, flags/blen %08x\n",
343 tmd.tmd0, tmd.tmd1);
344 #endif
345
346 if (tmd.tmd1 & LE_T1_OWN)
347 break;
348
349 ifq_clr_oactive(&ifp->if_snd);
350
351 if (tmd.tmd1 & LE_T1_ERR) {
352 if (tmd.tmd2 & LE_T2_BUFF)
353 printf("%s: transmit buffer error\n",
354 sc->sc_dev.dv_xname);
355 else if (tmd.tmd2 & LE_T2_UFLO)
356 printf("%s: underflow\n", sc->sc_dev.dv_xname);
357 if (tmd.tmd2 & (LE_T2_BUFF | LE_T2_UFLO)) {
358 lance_reset(sc);
359 return;
360 }
361 if (tmd.tmd2 & LE_T2_LCAR) {
362 sc->sc_havecarrier = 0;
363 if (sc->sc_nocarrier)
364 (*sc->sc_nocarrier)(sc);
365 else
366 printf("%s: lost carrier\n",
367 sc->sc_dev.dv_xname);
368 }
369 if (tmd.tmd2 & LE_T2_LCOL)
370 ifp->if_collisions++;
371 if (tmd.tmd2 & LE_T2_RTRY) {
372 #ifdef LEDEBUG
373 printf("%s: excessive collisions\n",
374 sc->sc_dev.dv_xname);
375 #endif
376 ifp->if_collisions += 16;
377 }
378 ifp->if_oerrors++;
379 } else {
380 if (tmd.tmd1 & LE_T1_ONE)
381 ifp->if_collisions++;
382 else if (tmd.tmd1 & LE_T1_MORE)
383 /* Real number is unknown. */
384 ifp->if_collisions += 2;
385 }
386
387 if (++bix == sc->sc_ntbuf)
388 bix = 0;
389
390 --sc->sc_no_td;
391 }
392
393 sc->sc_first_td = bix;
394
395 am79900_start(ifp);
396
397 if (sc->sc_no_td == 0)
398 ifp->if_timer = 0;
399 }
400
401 /*
402 * Controller interrupt.
403 */
404 int
am79900_intr(void * arg)405 am79900_intr(void *arg)
406 {
407 struct lance_softc *sc = arg;
408 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
409 uint16_t isr;
410
411 isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
412 sc->sc_saved_csr0 = 0;
413 #if defined(LEDEBUG) && LEDEBUG > 1
414 if (sc->sc_debug)
415 printf("%s: am79900_intr entering with isr=%04x\n",
416 sc->sc_dev.dv_xname, isr);
417 #endif
418 if ((isr & LE_C0_INTR) == 0)
419 return (0);
420
421 (*sc->sc_wrcsr)(sc, LE_CSR0,
422 isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
423 LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
424 if (isr & LE_C0_ERR) {
425 if (isr & LE_C0_BABL) {
426 #ifdef LEDEBUG
427 printf("%s: babble\n", sc->sc_dev.dv_xname);
428 #endif
429 ifp->if_oerrors++;
430 }
431 #if 0
432 if (isr & LE_C0_CERR) {
433 printf("%s: collision error\n",
434 sc->sc_dev.dv_xname);
435 ifp->if_collisions++;
436 }
437 #endif
438 if (isr & LE_C0_MISS) {
439 #ifdef LEDEBUG
440 printf("%s: missed packet\n", sc->sc_dev.dv_xname);
441 #endif
442 ifp->if_ierrors++;
443 }
444 if (isr & LE_C0_MERR) {
445 printf("%s: memory error\n", sc->sc_dev.dv_xname);
446 lance_reset(sc);
447 return (1);
448 }
449 }
450
451 if ((isr & LE_C0_RXON) == 0) {
452 printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
453 ifp->if_ierrors++;
454 lance_reset(sc);
455 return (1);
456 }
457 if ((isr & LE_C0_TXON) == 0) {
458 printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
459 ifp->if_oerrors++;
460 lance_reset(sc);
461 return (1);
462 }
463
464 /*
465 * Pretend we have carrier; if we don't this will be cleared
466 * shortly.
467 */
468 sc->sc_havecarrier = 1;
469
470 if (isr & LE_C0_RINT)
471 am79900_rint(sc);
472 if (isr & LE_C0_TINT)
473 am79900_tint(sc);
474
475 return (1);
476 }
477
478 /*
479 * Setup output on interface.
480 * Get another datagram to send off of the interface queue, and map it to the
481 * interface before starting the output.
482 * Called only at splnet or interrupt level.
483 */
484 void
am79900_start(struct ifnet * ifp)485 am79900_start(struct ifnet *ifp)
486 {
487 struct lance_softc *sc = ifp->if_softc;
488 int bix;
489 struct mbuf *m;
490 struct letmd tmd;
491 int rp;
492 int len;
493
494 if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
495 return;
496
497 bix = sc->sc_last_td;
498
499 for (;;) {
500 rp = LE_TMDADDR(sc, bix);
501 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
502
503 if (tmd.tmd1 & LE_T1_OWN) {
504 ifq_set_oactive(&ifp->if_snd);
505 printf("missing buffer, no_td = %d, last_td = %d\n",
506 sc->sc_no_td, sc->sc_last_td);
507 }
508
509 m = ifq_dequeue(&ifp->if_snd);
510 if (m == NULL)
511 break;
512
513 #if NBPFILTER > 0
514 /*
515 * If BPF is listening on this interface, let it see the packet
516 * before we commit it to the wire.
517 */
518 if (ifp->if_bpf)
519 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
520 #endif
521
522 /*
523 * Copy the mbuf chain into the transmit buffer.
524 */
525 len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
526
527 #ifdef LEDEBUG
528 if (len > ETHERMTU + sizeof(struct ether_header))
529 printf("packet length %d\n", len);
530 #endif
531
532 ifp->if_timer = 5;
533
534 /*
535 * Init transmit registers, and set transmit start flag.
536 */
537 tmd.tmd1 = LE_T1_OWN | LE_T1_STP | LE_T1_ENP | LE_T1_ONES |
538 (-len & 0xfff);
539 tmd.tmd2 = 0;
540 tmd.tmd3 = 0;
541
542 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
543
544 #ifdef LEDEBUG
545 if (sc->sc_debug > 1)
546 am79900_xmit_print(sc, sc->sc_last_td);
547 #endif
548
549 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
550
551 if (++bix == sc->sc_ntbuf)
552 bix = 0;
553
554 if (++sc->sc_no_td == sc->sc_ntbuf) {
555 ifq_set_oactive(&ifp->if_snd);
556 break;
557 }
558
559 }
560
561 sc->sc_last_td = bix;
562 }
563
564 #ifdef LEDEBUG
565 void
am79900_recv_print(struct lance_softc * sc,int no)566 am79900_recv_print(struct lance_softc *sc, int no)
567 {
568 struct lermd rmd;
569 uint16_t len;
570 struct ether_header eh;
571
572 (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
573 len = (rmd.rmd2 & 0xfff) - 4;
574 printf("%s: receive buffer %d, len = %d\n",
575 sc->sc_dev.dv_xname, no, len);
576 printf("%s: status %04x\n", sc->sc_dev.dv_xname,
577 (*sc->sc_rdcsr)(sc, LE_CSR0));
578 printf("%s: adr %08x, flags/blen %08x\n",
579 sc->sc_dev.dv_xname, rmd.rmd0, rmd.rmd1);
580 if (len >= sizeof(eh)) {
581 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
582 printf("%s: dst %s", sc->sc_dev.dv_xname,
583 ether_sprintf(eh.ether_dhost));
584 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
585 ntohs(eh.ether_type));
586 }
587 }
588
589 void
am79900_xmit_print(struct lance_softc * sc,int no)590 am79900_xmit_print(struct lance_softc *sc, int no)
591 {
592 struct letmd tmd;
593 uint16_t len;
594 struct ether_header eh;
595
596 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
597 len = -(tmd.tmd1 & 0xfff);
598 printf("%s: transmit buffer %d, len = %d\n",
599 sc->sc_dev.dv_xname, no, len);
600 printf("%s: status %04x\n", sc->sc_dev.dv_xname,
601 (*sc->sc_rdcsr)(sc, LE_CSR0));
602 printf("%s: adr %08x, flags/blen %08x\n",
603 sc->sc_dev.dv_xname, tmd.tmd0, tmd.tmd1);
604 if (len >= sizeof(eh)) {
605 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
606 printf("%s: dst %s", sc->sc_dev.dv_xname,
607 ether_sprintf(eh.ether_dhost));
608 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
609 ntohs(eh.ether_type));
610 }
611 }
612 #endif /* LEDEBUG */
613