1155093Smarius/* $NetBSD: am7990.c,v 1.68 2005/12/11 12:21:25 christos Exp $ */ 2155093Smarius 3155093Smarius/*- 4155093Smarius * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 5155093Smarius * All rights reserved. 6155093Smarius * 7155093Smarius * This code is derived from software contributed to The NetBSD Foundation 8155093Smarius * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 9155093Smarius * Simulation Facility, NASA Ames Research Center. 10155093Smarius * 11155093Smarius * Redistribution and use in source and binary forms, with or without 12155093Smarius * modification, are permitted provided that the following conditions 13155093Smarius * are met: 14155093Smarius * 1. Redistributions of source code must retain the above copyright 15155093Smarius * notice, this list of conditions and the following disclaimer. 16155093Smarius * 2. Redistributions in binary form must reproduce the above copyright 17155093Smarius * notice, this list of conditions and the following disclaimer in the 18155093Smarius * documentation and/or other materials provided with the distribution. 19155093Smarius * 20155093Smarius * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21155093Smarius * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22155093Smarius * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23155093Smarius * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24155093Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25155093Smarius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26155093Smarius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27155093Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28155093Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29155093Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30155093Smarius * POSSIBILITY OF SUCH DAMAGE. 31155093Smarius */ 32155093Smarius 33155093Smarius/*- 34155093Smarius * Copyright (c) 1992, 1993 35155093Smarius * The Regents of the University of California. All rights reserved. 36155093Smarius * 37155093Smarius * This code is derived from software contributed to Berkeley by 38155093Smarius * Ralph Campbell and Rick Macklem. 39155093Smarius * 40155093Smarius * Redistribution and use in source and binary forms, with or without 41155093Smarius * modification, are permitted provided that the following conditions 42155093Smarius * are met: 43155093Smarius * 1. Redistributions of source code must retain the above copyright 44155093Smarius * notice, this list of conditions and the following disclaimer. 45155093Smarius * 2. Redistributions in binary form must reproduce the above copyright 46155093Smarius * notice, this list of conditions and the following disclaimer in the 47155093Smarius * documentation and/or other materials provided with the distribution. 48155093Smarius * 3. Neither the name of the University nor the names of its contributors 49155093Smarius * may be used to endorse or promote products derived from this software 50155093Smarius * without specific prior written permission. 51155093Smarius * 52155093Smarius * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53155093Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54155093Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55155093Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56155093Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57155093Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58155093Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59155093Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60155093Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61155093Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62155093Smarius * SUCH DAMAGE. 63155093Smarius * 64155093Smarius * @(#)if_le.c 8.2 (Berkeley) 11/16/93 65155093Smarius */ 66155093Smarius 67155093Smarius#include <sys/cdefs.h> 68155093Smarius__FBSDID("$FreeBSD$"); 69155093Smarius 70155093Smarius#include <sys/param.h> 71155093Smarius#include <sys/bus.h> 72155093Smarius#include <sys/endian.h> 73155093Smarius#include <sys/lock.h> 74155093Smarius#include <sys/mbuf.h> 75155093Smarius#include <sys/mutex.h> 76155093Smarius#include <sys/socket.h> 77155093Smarius 78155093Smarius#include <net/bpf.h> 79155093Smarius#include <net/ethernet.h> 80155093Smarius#include <net/if.h> 81155093Smarius#include <net/if_arp.h> 82155093Smarius#include <net/if_dl.h> 83155093Smarius#include <net/if_media.h> 84155093Smarius#include <net/if_var.h> 85155093Smarius 86158663Smarius#include <machine/bus.h> 87158663Smarius 88155093Smarius#include <dev/le/lancereg.h> 89155093Smarius#include <dev/le/lancevar.h> 90155093Smarius#include <dev/le/am7990reg.h> 91155093Smarius#include <dev/le/am7990var.h> 92155093Smarius 93155093Smariusstatic void am7990_meminit(struct lance_softc *); 94155093Smariusstatic void am7990_rint(struct lance_softc *); 95155093Smariusstatic void am7990_tint(struct lance_softc *); 96155093Smariusstatic void am7990_start_locked(struct lance_softc *sc); 97155093Smarius 98155093Smarius#ifdef LEDEBUG 99155093Smariusstatic void am7990_recv_print(struct lance_softc *, int); 100155093Smariusstatic void am7990_xmit_print(struct lance_softc *, int); 101155093Smarius#endif 102155093Smarius 103155093Smariusint 104155093Smariusam7990_config(struct am7990_softc *sc, const char* name, int unit) 105155093Smarius{ 106155093Smarius int error, mem; 107155093Smarius 108155093Smarius sc->lsc.sc_meminit = am7990_meminit; 109155093Smarius sc->lsc.sc_start_locked = am7990_start_locked; 110155093Smarius 111155093Smarius error = lance_config(&sc->lsc, name, unit); 112155093Smarius if (error != 0) 113155093Smarius return (error); 114155093Smarius 115155093Smarius mem = 0; 116155093Smarius sc->lsc.sc_initaddr = mem; 117155093Smarius mem += sizeof(struct leinit); 118155093Smarius sc->lsc.sc_rmdaddr = mem; 119155093Smarius mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf; 120155093Smarius sc->lsc.sc_tmdaddr = mem; 121155093Smarius mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf; 122155093Smarius sc->lsc.sc_rbufaddr = mem; 123155093Smarius mem += LEBLEN * sc->lsc.sc_nrbuf; 124155093Smarius sc->lsc.sc_tbufaddr = mem; 125155093Smarius mem += LEBLEN * sc->lsc.sc_ntbuf; 126155093Smarius 127155093Smarius if (mem > sc->lsc.sc_memsize) 128155093Smarius panic("%s: memsize", __func__); 129155093Smarius 130155093Smarius lance_attach(&sc->lsc); 131155093Smarius 132155093Smarius return (0); 133155093Smarius} 134155093Smarius 135155093Smariusvoid 136155093Smariusam7990_detach(struct am7990_softc *sc) 137155093Smarius{ 138155093Smarius 139155093Smarius lance_detach(&sc->lsc); 140155093Smarius} 141155093Smarius 142155093Smarius/* 143155093Smarius * Set up the initialization block and the descriptor rings. 144155093Smarius */ 145155093Smariusstatic void 146155093Smariusam7990_meminit(struct lance_softc *sc) 147155093Smarius{ 148155093Smarius struct ifnet *ifp = sc->sc_ifp; 149155093Smarius struct leinit init; 150155093Smarius struct lermd rmd; 151155093Smarius struct letmd tmd; 152155093Smarius u_long a; 153155093Smarius int bix; 154155093Smarius 155155093Smarius LE_LOCK_ASSERT(sc, MA_OWNED); 156155093Smarius 157155093Smarius if (ifp->if_flags & IFF_PROMISC) 158155093Smarius init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM; 159155093Smarius else 160155093Smarius init.init_mode = LE_MODE_NORMAL; 161155093Smarius 162155093Smarius init.init_padr[0] = (sc->sc_enaddr[1] << 8) | sc->sc_enaddr[0]; 163155093Smarius init.init_padr[1] = (sc->sc_enaddr[3] << 8) | sc->sc_enaddr[2]; 164155093Smarius init.init_padr[2] = (sc->sc_enaddr[5] << 8) | sc->sc_enaddr[4]; 165155093Smarius lance_setladrf(sc, init.init_ladrf); 166155093Smarius 167155093Smarius sc->sc_last_rd = 0; 168155093Smarius sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0; 169155093Smarius 170155093Smarius a = sc->sc_addr + LE_RMDADDR(sc, 0); 171155093Smarius init.init_rdra = a; 172155093Smarius init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13); 173155093Smarius 174155093Smarius a = sc->sc_addr + LE_TMDADDR(sc, 0); 175155093Smarius init.init_tdra = a; 176155093Smarius init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13); 177155093Smarius 178155093Smarius (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init)); 179155093Smarius 180155093Smarius /* 181155093Smarius * Set up receive ring descriptors. 182155093Smarius */ 183155093Smarius for (bix = 0; bix < sc->sc_nrbuf; bix++) { 184155093Smarius a = sc->sc_addr + LE_RBUFADDR(sc, bix); 185155093Smarius rmd.rmd0 = a; 186155093Smarius rmd.rmd1_hadr = a >> 16; 187155093Smarius rmd.rmd1_bits = LE_R1_OWN; 188155093Smarius rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; 189155093Smarius rmd.rmd3 = 0; 190155093Smarius (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix), 191155093Smarius sizeof(rmd)); 192155093Smarius } 193155093Smarius 194155093Smarius /* 195155093Smarius * Set up transmit ring descriptors. 196155093Smarius */ 197155093Smarius for (bix = 0; bix < sc->sc_ntbuf; bix++) { 198155093Smarius a = sc->sc_addr + LE_TBUFADDR(sc, bix); 199155093Smarius tmd.tmd0 = a; 200155093Smarius tmd.tmd1_hadr = a >> 16; 201155093Smarius tmd.tmd1_bits = 0; 202155093Smarius tmd.tmd2 = LE_XMD2_ONES; 203155093Smarius tmd.tmd3 = 0; 204155093Smarius (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix), 205155093Smarius sizeof(tmd)); 206155093Smarius } 207155093Smarius} 208155093Smarius 209155093Smariusstatic void 210155093Smariusam7990_rint(struct lance_softc *sc) 211155093Smarius{ 212155093Smarius struct ifnet *ifp = sc->sc_ifp; 213158663Smarius struct mbuf *m; 214155093Smarius struct lermd rmd; 215155093Smarius int bix, rp; 216158663Smarius#if defined(LANCE_REVC_BUG) 217158663Smarius struct ether_header *eh; 218158663Smarius /* Make sure this is short-aligned, for ether_cmp(). */ 219158663Smarius static uint16_t bcast_enaddr[3] = { ~0, ~0, ~0 }; 220158663Smarius#endif 221155093Smarius 222155093Smarius bix = sc->sc_last_rd; 223155093Smarius 224155093Smarius /* Process all buffers with valid data. */ 225155093Smarius for (;;) { 226155093Smarius rp = LE_RMDADDR(sc, bix); 227155093Smarius (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd)); 228155093Smarius 229155093Smarius if (rmd.rmd1_bits & LE_R1_OWN) 230155093Smarius break; 231155093Smarius 232158663Smarius m = NULL; 233158663Smarius if ((rmd.rmd1_bits & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) != 234158663Smarius (LE_R1_STP | LE_R1_ENP)) { 235158663Smarius if (rmd.rmd1_bits & LE_R1_ERR) { 236155093Smarius#ifdef LEDEBUG 237158663Smarius if (rmd.rmd1_bits & LE_R1_ENP) { 238158663Smarius if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) { 239158663Smarius if (rmd.rmd1_bits & LE_R1_FRAM) 240158663Smarius if_printf(ifp, 241158663Smarius "framing error\n"); 242158663Smarius if (rmd.rmd1_bits & LE_R1_CRC) 243158663Smarius if_printf(ifp, 244158663Smarius "crc mismatch\n"); 245158663Smarius } 246158663Smarius } else 247158663Smarius if (rmd.rmd1_bits & LE_R1_OFLO) 248158663Smarius if_printf(ifp, "overflow\n"); 249155093Smarius#endif 250158663Smarius if (rmd.rmd1_bits & LE_R1_BUFF) 251158663Smarius if_printf(ifp, 252158663Smarius "receive buffer error\n"); 253158663Smarius } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != 254158663Smarius (LE_R1_STP | LE_R1_ENP)) 255158663Smarius if_printf(ifp, "dropping chained buffer\n"); 256155093Smarius } else { 257155093Smarius#ifdef LEDEBUG 258155093Smarius if (sc->sc_flags & LE_DEBUG) 259158663Smarius am7990_recv_print(sc, bix); 260155093Smarius#endif 261158663Smarius /* Pull the packet off the interface. */ 262158663Smarius m = lance_get(sc, LE_RBUFADDR(sc, bix), 263155093Smarius (int)rmd.rmd3 - ETHER_CRC_LEN); 264155093Smarius } 265155093Smarius 266155093Smarius rmd.rmd1_bits = LE_R1_OWN; 267155093Smarius rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; 268155093Smarius rmd.rmd3 = 0; 269155093Smarius (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd)); 270155093Smarius 271158663Smarius if (++bix == sc->sc_nrbuf) 272158663Smarius bix = 0; 273158663Smarius 274158663Smarius if (m != NULL) { 275158663Smarius ifp->if_ipackets++; 276158663Smarius 277158663Smarius#ifdef LANCE_REVC_BUG 278158663Smarius /* 279158663Smarius * The old LANCE (Rev. C) chips have a bug which 280158663Smarius * causes garbage to be inserted in front of the 281158663Smarius * received packet. The workaround is to ignore 282158663Smarius * packets with an invalid destination address 283158663Smarius * (garbage will usually not match). 284158663Smarius * Of course, this precludes multicast support... 285158663Smarius */ 286158663Smarius eh = mtod(m, struct ether_header *); 287158663Smarius if (ether_cmp(eh->ether_dhost, sc->sc_enaddr) && 288158663Smarius ether_cmp(eh->ether_dhost, bcast_enaddr)) { 289158663Smarius m_freem(m); 290158663Smarius continue; 291158663Smarius } 292155093Smarius#endif 293155093Smarius 294158663Smarius /* Pass the packet up. */ 295158663Smarius LE_UNLOCK(sc); 296158663Smarius (*ifp->if_input)(ifp, m); 297158663Smarius LE_LOCK(sc); 298158663Smarius } else 299158663Smarius ifp->if_ierrors++; 300155093Smarius } 301155093Smarius 302155093Smarius sc->sc_last_rd = bix; 303155093Smarius} 304155093Smarius 305155093Smariusstatic void 306155093Smariusam7990_tint(struct lance_softc *sc) 307155093Smarius{ 308155093Smarius struct ifnet *ifp = sc->sc_ifp; 309155093Smarius struct letmd tmd; 310155093Smarius int bix; 311155093Smarius 312155093Smarius bix = sc->sc_first_td; 313155093Smarius 314155093Smarius for (;;) { 315155093Smarius if (sc->sc_no_td <= 0) 316155093Smarius break; 317155093Smarius 318155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), 319155093Smarius sizeof(tmd)); 320155093Smarius 321155093Smarius#ifdef LEDEBUG 322155093Smarius if (sc->sc_flags & LE_DEBUG) 323155093Smarius if_printf(ifp, "trans tmd: " 324155093Smarius "ladr %04x, hadr %02x, flags %02x, " 325155093Smarius "bcnt %04x, mcnt %04x\n", 326155093Smarius tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, 327155093Smarius tmd.tmd2, tmd.tmd3); 328155093Smarius#endif 329155093Smarius 330155093Smarius if (tmd.tmd1_bits & LE_T1_OWN) 331155093Smarius break; 332155093Smarius 333155093Smarius ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 334155093Smarius 335155093Smarius if (tmd.tmd1_bits & LE_T1_ERR) { 336155093Smarius if (tmd.tmd3 & LE_T3_BUFF) 337155093Smarius if_printf(ifp, "transmit buffer error\n"); 338155093Smarius else if (tmd.tmd3 & LE_T3_UFLO) 339155093Smarius if_printf(ifp, "underflow\n"); 340155093Smarius if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) { 341155093Smarius lance_init_locked(sc); 342155093Smarius return; 343155093Smarius } 344155093Smarius if (tmd.tmd3 & LE_T3_LCAR) { 345155093Smarius if (sc->sc_flags & LE_CARRIER) 346155093Smarius if_link_state_change(ifp, 347155093Smarius LINK_STATE_DOWN); 348155093Smarius sc->sc_flags &= ~LE_CARRIER; 349155093Smarius if (sc->sc_nocarrier) 350155093Smarius (*sc->sc_nocarrier)(sc); 351155093Smarius else 352155093Smarius if_printf(ifp, "lost carrier\n"); 353155093Smarius } 354155093Smarius if (tmd.tmd3 & LE_T3_LCOL) 355155093Smarius ifp->if_collisions++; 356155093Smarius if (tmd.tmd3 & LE_T3_RTRY) { 357155093Smarius#ifdef LEDEBUG 358155093Smarius if_printf(ifp, "excessive collisions, tdr %d\n", 359155093Smarius tmd.tmd3 & LE_T3_TDR_MASK); 360155093Smarius#endif 361155093Smarius ifp->if_collisions += 16; 362155093Smarius } 363155093Smarius ifp->if_oerrors++; 364155093Smarius } else { 365155093Smarius if (tmd.tmd1_bits & LE_T1_ONE) 366155093Smarius ifp->if_collisions++; 367155093Smarius else if (tmd.tmd1_bits & LE_T1_MORE) 368155093Smarius /* Real number is unknown. */ 369155093Smarius ifp->if_collisions += 2; 370155093Smarius ifp->if_opackets++; 371155093Smarius } 372155093Smarius 373155093Smarius if (++bix == sc->sc_ntbuf) 374155093Smarius bix = 0; 375155093Smarius 376155093Smarius --sc->sc_no_td; 377155093Smarius } 378155093Smarius 379155093Smarius sc->sc_first_td = bix; 380155093Smarius 381164933Smarius sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0; 382155093Smarius} 383155093Smarius 384155093Smarius/* 385155093Smarius * Controller interrupt 386155093Smarius */ 387155093Smariusvoid 388155093Smariusam7990_intr(void *arg) 389155093Smarius{ 390155093Smarius struct lance_softc *sc = arg; 391155093Smarius struct ifnet *ifp = sc->sc_ifp; 392155093Smarius uint16_t isr; 393155093Smarius 394155093Smarius LE_LOCK(sc); 395155093Smarius 396155093Smarius if (sc->sc_hwintr && (*sc->sc_hwintr)(sc) == -1) { 397155093Smarius ifp->if_ierrors++; 398155093Smarius lance_init_locked(sc); 399155093Smarius LE_UNLOCK(sc); 400155093Smarius return; 401155093Smarius } 402155093Smarius 403155093Smarius isr = (*sc->sc_rdcsr)(sc, LE_CSR0); 404155093Smarius#if defined(LEDEBUG) && LEDEBUG > 1 405155093Smarius if (sc->sc_flags & LE_DEBUG) 406155093Smarius if_printf(ifp, "%s: entering with isr=%04x\n", __func__, isr); 407155093Smarius#endif 408155093Smarius if ((isr & LE_C0_INTR) == 0) { 409155093Smarius LE_UNLOCK(sc); 410155093Smarius return; 411155093Smarius } 412155093Smarius 413155881Smarius /* 414155881Smarius * Clear interrupt source flags and turn off interrupts. If we 415155881Smarius * don't clear these flags before processing their sources we 416158663Smarius * could completely miss some interrupt events as the NIC can 417174986Smarius * change these flags while we're in this handler. We toggle 418174986Smarius * the interrupt enable bit in order to keep receiving them 419174986Smarius * (some chips work without this, some don't). 420155881Smarius */ 421155881Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD | 422155881Smarius LE_C0_STOP | LE_C0_STRT | LE_C0_INIT)); 423155881Smarius 424155093Smarius if (isr & LE_C0_ERR) { 425155093Smarius if (isr & LE_C0_BABL) { 426155093Smarius#ifdef LEDEBUG 427155093Smarius if_printf(ifp, "babble\n"); 428155093Smarius#endif 429155093Smarius ifp->if_oerrors++; 430155093Smarius } 431155093Smarius#if 0 432155093Smarius if (isr & LE_C0_CERR) { 433155093Smarius if_printf(ifp, "collision error\n"); 434155093Smarius ifp->if_collisions++; 435155093Smarius } 436155093Smarius#endif 437155093Smarius if (isr & LE_C0_MISS) { 438155093Smarius#ifdef LEDEBUG 439155093Smarius if_printf(ifp, "missed packet\n"); 440155093Smarius#endif 441155093Smarius ifp->if_ierrors++; 442155093Smarius } 443155093Smarius if (isr & LE_C0_MERR) { 444155093Smarius if_printf(ifp, "memory error\n"); 445155093Smarius lance_init_locked(sc); 446155093Smarius LE_UNLOCK(sc); 447155093Smarius return; 448155093Smarius } 449155093Smarius } 450155093Smarius 451155093Smarius if ((isr & LE_C0_RXON) == 0) { 452155093Smarius if_printf(ifp, "receiver disabled\n"); 453155093Smarius ifp->if_ierrors++; 454155093Smarius lance_init_locked(sc); 455155093Smarius LE_UNLOCK(sc); 456155093Smarius return; 457155093Smarius } 458155093Smarius if ((isr & LE_C0_TXON) == 0) { 459155093Smarius if_printf(ifp, "transmitter disabled\n"); 460155093Smarius ifp->if_oerrors++; 461155093Smarius lance_init_locked(sc); 462155093Smarius LE_UNLOCK(sc); 463155093Smarius return; 464155093Smarius } 465155093Smarius 466155093Smarius /* 467155093Smarius * Pretend we have carrier; if we don't this will be cleared shortly. 468155093Smarius */ 469155093Smarius if (!(sc->sc_flags & LE_CARRIER)) 470155093Smarius if_link_state_change(ifp, LINK_STATE_UP); 471155093Smarius sc->sc_flags |= LE_CARRIER; 472155093Smarius 473155093Smarius if (isr & LE_C0_RINT) 474155093Smarius am7990_rint(sc); 475155093Smarius if (isr & LE_C0_TINT) 476155093Smarius am7990_tint(sc); 477155093Smarius 478155881Smarius /* Enable interrupts again. */ 479155881Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA); 480155093Smarius 481155881Smarius if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 482155881Smarius am7990_start_locked(sc); 483155881Smarius 484155093Smarius LE_UNLOCK(sc); 485155093Smarius} 486155093Smarius 487155093Smarius/* 488155093Smarius * Set up output on interface. 489155093Smarius * Get another datagram to send off of the interface queue, and map it to the 490155093Smarius * interface before starting the output. 491155093Smarius */ 492155093Smariusstatic void 493155093Smariusam7990_start_locked(struct lance_softc *sc) 494155093Smarius{ 495155093Smarius struct ifnet *ifp = sc->sc_ifp; 496155093Smarius struct letmd tmd; 497155093Smarius struct mbuf *m; 498155881Smarius int bix, enq, len, rp; 499155093Smarius 500155093Smarius LE_LOCK_ASSERT(sc, MA_OWNED); 501155093Smarius 502155093Smarius if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 503155093Smarius IFF_DRV_RUNNING) 504155093Smarius return; 505155093Smarius 506155093Smarius bix = sc->sc_last_td; 507155881Smarius enq = 0; 508155093Smarius 509155093Smarius for (; sc->sc_no_td < sc->sc_ntbuf && 510155093Smarius !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 511155093Smarius rp = LE_TMDADDR(sc, bix); 512155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd)); 513155093Smarius 514155093Smarius if (tmd.tmd1_bits & LE_T1_OWN) { 515155093Smarius ifp->if_drv_flags |= IFF_DRV_OACTIVE; 516155093Smarius if_printf(ifp, 517155093Smarius "missing buffer, no_td = %d, last_td = %d\n", 518155093Smarius sc->sc_no_td, sc->sc_last_td); 519155093Smarius } 520155093Smarius 521155093Smarius IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 522155093Smarius if (m == 0) 523155093Smarius break; 524155093Smarius 525155093Smarius /* 526155093Smarius * If BPF is listening on this interface, let it see the packet 527155093Smarius * before we commit it to the wire. 528155093Smarius */ 529155093Smarius BPF_MTAP(ifp, m); 530155093Smarius 531155093Smarius /* 532155093Smarius * Copy the mbuf chain into the transmit buffer. 533155093Smarius */ 534155093Smarius len = lance_put(sc, LE_TBUFADDR(sc, bix), m); 535155093Smarius 536155093Smarius#ifdef LEDEBUG 537155093Smarius if (len > ETHERMTU + ETHER_HDR_LEN) 538155093Smarius if_printf(ifp, "packet length %d\n", len); 539155093Smarius#endif 540155093Smarius 541155093Smarius /* 542155093Smarius * Init transmit registers, and set transmit start flag. 543155093Smarius */ 544155093Smarius tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP; 545155093Smarius tmd.tmd2 = -len | LE_XMD2_ONES; 546155093Smarius tmd.tmd3 = 0; 547155093Smarius 548155093Smarius (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd)); 549155093Smarius 550155093Smarius#ifdef LEDEBUG 551155093Smarius if (sc->sc_flags & LE_DEBUG) 552158663Smarius am7990_xmit_print(sc, bix); 553155093Smarius#endif 554155093Smarius 555155093Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); 556155881Smarius enq++; 557155093Smarius 558155093Smarius if (++bix == sc->sc_ntbuf) 559155093Smarius bix = 0; 560155093Smarius 561155093Smarius if (++sc->sc_no_td == sc->sc_ntbuf) { 562155093Smarius ifp->if_drv_flags |= IFF_DRV_OACTIVE; 563155093Smarius break; 564155093Smarius } 565155093Smarius } 566155093Smarius 567155093Smarius sc->sc_last_td = bix; 568155881Smarius 569155881Smarius if (enq > 0) 570164933Smarius sc->sc_wdog_timer = 5; 571155093Smarius} 572155093Smarius 573155093Smarius#ifdef LEDEBUG 574155093Smariusstatic void 575155093Smariusam7990_recv_print(struct lance_softc *sc, int no) 576155093Smarius{ 577155093Smarius struct ifnet *ifp = sc->sc_ifp; 578155093Smarius struct ether_header eh; 579155093Smarius struct lermd rmd; 580155093Smarius uint16_t len; 581155093Smarius 582155093Smarius (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd)); 583155093Smarius len = rmd.rmd3; 584155093Smarius if_printf(ifp, "receive buffer %d, len = %d\n", no, len); 585155093Smarius if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0)); 586155093Smarius if_printf(ifp, 587155093Smarius "ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", 588155093Smarius rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3); 589155093Smarius if (len - ETHER_CRC_LEN >= sizeof(eh)) { 590155093Smarius (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh)); 591155093Smarius if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost)); 592155093Smarius printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 593155093Smarius ntohs(eh.ether_type)); 594155093Smarius } 595155093Smarius} 596155093Smarius 597155093Smariusstatic void 598155093Smariusam7990_xmit_print(struct lance_softc *sc, int no) 599155093Smarius{ 600155093Smarius struct ifnet *ifp = sc->sc_ifp; 601155093Smarius struct ether_header eh; 602155093Smarius struct letmd tmd; 603155093Smarius uint16_t len; 604155093Smarius 605155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd)); 606155093Smarius len = -tmd.tmd2; 607155093Smarius if_printf(ifp, "transmit buffer %d, len = %d\n", no, len); 608155093Smarius if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0)); 609155093Smarius if_printf(ifp, 610155093Smarius "ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", 611155093Smarius tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3); 612155093Smarius if (len >= sizeof(eh)) { 613155093Smarius (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh)); 614155093Smarius if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost)); 615155093Smarius printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 616155093Smarius ntohs(eh.ether_type)); 617155093Smarius } 618155093Smarius} 619155093Smarius#endif /* LEDEBUG */ 620