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