am7990.c revision 155881
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 * 3. All advertising materials mentioning features or use of this software 20155093Smarius * must display the following acknowledgement: 21155093Smarius * This product includes software developed by the NetBSD 22155093Smarius * Foundation, Inc. and its contributors. 23155093Smarius * 4. Neither the name of The NetBSD Foundation nor the names of its 24155093Smarius * contributors may be used to endorse or promote products derived 25155093Smarius * from this software without specific prior written permission. 26155093Smarius * 27155093Smarius * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28155093Smarius * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29155093Smarius * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30155093Smarius * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31155093Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32155093Smarius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33155093Smarius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34155093Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35155093Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36155093Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37155093Smarius * POSSIBILITY OF SUCH DAMAGE. 38155093Smarius */ 39155093Smarius 40155093Smarius/*- 41155093Smarius * Copyright (c) 1992, 1993 42155093Smarius * The Regents of the University of California. All rights reserved. 43155093Smarius * 44155093Smarius * This code is derived from software contributed to Berkeley by 45155093Smarius * Ralph Campbell and Rick Macklem. 46155093Smarius * 47155093Smarius * Redistribution and use in source and binary forms, with or without 48155093Smarius * modification, are permitted provided that the following conditions 49155093Smarius * are met: 50155093Smarius * 1. Redistributions of source code must retain the above copyright 51155093Smarius * notice, this list of conditions and the following disclaimer. 52155093Smarius * 2. Redistributions in binary form must reproduce the above copyright 53155093Smarius * notice, this list of conditions and the following disclaimer in the 54155093Smarius * documentation and/or other materials provided with the distribution. 55155093Smarius * 3. Neither the name of the University nor the names of its contributors 56155093Smarius * may be used to endorse or promote products derived from this software 57155093Smarius * without specific prior written permission. 58155093Smarius * 59155093Smarius * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60155093Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61155093Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62155093Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63155093Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64155093Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65155093Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66155093Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67155093Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68155093Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69155093Smarius * SUCH DAMAGE. 70155093Smarius * 71155093Smarius * @(#)if_le.c 8.2 (Berkeley) 11/16/93 72155093Smarius */ 73155093Smarius 74155093Smarius#include <sys/cdefs.h> 75155093Smarius__FBSDID("$FreeBSD: head/sys/dev/le/am7990.c 155881 2006-02-21 20:20:43Z marius $"); 76155093Smarius 77155093Smarius#include <sys/param.h> 78155093Smarius#include <sys/bus.h> 79155093Smarius#include <sys/endian.h> 80155093Smarius#include <sys/lock.h> 81155093Smarius#include <sys/mbuf.h> 82155093Smarius#include <sys/mutex.h> 83155093Smarius#include <sys/socket.h> 84155093Smarius 85155093Smarius#include <net/bpf.h> 86155093Smarius#include <net/ethernet.h> 87155093Smarius#include <net/if.h> 88155093Smarius#include <net/if_arp.h> 89155093Smarius#include <net/if_dl.h> 90155093Smarius#include <net/if_media.h> 91155093Smarius#include <net/if_var.h> 92155093Smarius 93155093Smarius#include <dev/le/lancereg.h> 94155093Smarius#include <dev/le/lancevar.h> 95155093Smarius#include <dev/le/am7990reg.h> 96155093Smarius#include <dev/le/am7990var.h> 97155093Smarius 98155093Smariusstatic void am7990_meminit(struct lance_softc *); 99155093Smariusstatic void am7990_rint(struct lance_softc *); 100155093Smariusstatic void am7990_tint(struct lance_softc *); 101155093Smariusstatic void am7990_start_locked(struct lance_softc *sc); 102155093Smarius 103155093Smarius#ifdef LEDEBUG 104155093Smariusstatic void am7990_recv_print(struct lance_softc *, int); 105155093Smariusstatic void am7990_xmit_print(struct lance_softc *, int); 106155093Smarius#endif 107155093Smarius 108155093Smariusint 109155093Smariusam7990_config(struct am7990_softc *sc, const char* name, int unit) 110155093Smarius{ 111155093Smarius int error, mem; 112155093Smarius 113155093Smarius sc->lsc.sc_meminit = am7990_meminit; 114155093Smarius sc->lsc.sc_start_locked = am7990_start_locked; 115155093Smarius 116155093Smarius error = lance_config(&sc->lsc, name, unit); 117155093Smarius if (error != 0) 118155093Smarius return (error); 119155093Smarius 120155093Smarius mem = 0; 121155093Smarius sc->lsc.sc_initaddr = mem; 122155093Smarius mem += sizeof(struct leinit); 123155093Smarius sc->lsc.sc_rmdaddr = mem; 124155093Smarius mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf; 125155093Smarius sc->lsc.sc_tmdaddr = mem; 126155093Smarius mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf; 127155093Smarius sc->lsc.sc_rbufaddr = mem; 128155093Smarius mem += LEBLEN * sc->lsc.sc_nrbuf; 129155093Smarius sc->lsc.sc_tbufaddr = mem; 130155093Smarius mem += LEBLEN * sc->lsc.sc_ntbuf; 131155093Smarius 132155093Smarius if (mem > sc->lsc.sc_memsize) 133155093Smarius panic("%s: memsize", __func__); 134155093Smarius 135155093Smarius lance_attach(&sc->lsc); 136155093Smarius 137155093Smarius return (0); 138155093Smarius} 139155093Smarius 140155093Smariusvoid 141155093Smariusam7990_detach(struct am7990_softc *sc) 142155093Smarius{ 143155093Smarius 144155093Smarius lance_detach(&sc->lsc); 145155093Smarius} 146155093Smarius 147155093Smarius/* 148155093Smarius * Set up the initialization block and the descriptor rings. 149155093Smarius */ 150155093Smariusstatic void 151155093Smariusam7990_meminit(struct lance_softc *sc) 152155093Smarius{ 153155093Smarius struct ifnet *ifp = sc->sc_ifp; 154155093Smarius struct leinit init; 155155093Smarius struct lermd rmd; 156155093Smarius struct letmd tmd; 157155093Smarius u_long a; 158155093Smarius int bix; 159155093Smarius 160155093Smarius LE_LOCK_ASSERT(sc, MA_OWNED); 161155093Smarius 162155093Smarius if (ifp->if_flags & IFF_PROMISC) 163155093Smarius init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM; 164155093Smarius else 165155093Smarius init.init_mode = LE_MODE_NORMAL; 166155093Smarius 167155093Smarius init.init_padr[0] = (sc->sc_enaddr[1] << 8) | sc->sc_enaddr[0]; 168155093Smarius init.init_padr[1] = (sc->sc_enaddr[3] << 8) | sc->sc_enaddr[2]; 169155093Smarius init.init_padr[2] = (sc->sc_enaddr[5] << 8) | sc->sc_enaddr[4]; 170155093Smarius lance_setladrf(sc, init.init_ladrf); 171155093Smarius 172155093Smarius sc->sc_last_rd = 0; 173155093Smarius sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0; 174155093Smarius 175155093Smarius a = sc->sc_addr + LE_RMDADDR(sc, 0); 176155093Smarius init.init_rdra = a; 177155093Smarius init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13); 178155093Smarius 179155093Smarius a = sc->sc_addr + LE_TMDADDR(sc, 0); 180155093Smarius init.init_tdra = a; 181155093Smarius init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13); 182155093Smarius 183155093Smarius (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init)); 184155093Smarius 185155093Smarius /* 186155093Smarius * Set up receive ring descriptors. 187155093Smarius */ 188155093Smarius for (bix = 0; bix < sc->sc_nrbuf; bix++) { 189155093Smarius a = sc->sc_addr + LE_RBUFADDR(sc, bix); 190155093Smarius rmd.rmd0 = a; 191155093Smarius rmd.rmd1_hadr = a >> 16; 192155093Smarius rmd.rmd1_bits = LE_R1_OWN; 193155093Smarius rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; 194155093Smarius rmd.rmd3 = 0; 195155093Smarius (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix), 196155093Smarius sizeof(rmd)); 197155093Smarius } 198155093Smarius 199155093Smarius /* 200155093Smarius * Set up transmit ring descriptors. 201155093Smarius */ 202155093Smarius for (bix = 0; bix < sc->sc_ntbuf; bix++) { 203155093Smarius a = sc->sc_addr + LE_TBUFADDR(sc, bix); 204155093Smarius tmd.tmd0 = a; 205155093Smarius tmd.tmd1_hadr = a >> 16; 206155093Smarius tmd.tmd1_bits = 0; 207155093Smarius tmd.tmd2 = LE_XMD2_ONES; 208155093Smarius tmd.tmd3 = 0; 209155093Smarius (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix), 210155093Smarius sizeof(tmd)); 211155093Smarius } 212155093Smarius} 213155093Smarius 214155093Smariusstatic void 215155093Smariusam7990_rint(struct lance_softc *sc) 216155093Smarius{ 217155093Smarius struct ifnet *ifp = sc->sc_ifp; 218155093Smarius struct lermd rmd; 219155093Smarius int bix, rp; 220155093Smarius 221155093Smarius bix = sc->sc_last_rd; 222155093Smarius 223155093Smarius /* Process all buffers with valid data. */ 224155093Smarius for (;;) { 225155093Smarius rp = LE_RMDADDR(sc, bix); 226155093Smarius (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd)); 227155093Smarius 228155093Smarius if (rmd.rmd1_bits & LE_R1_OWN) 229155093Smarius break; 230155093Smarius 231155093Smarius if (rmd.rmd1_bits & LE_R1_ERR) { 232155093Smarius if (rmd.rmd1_bits & LE_R1_ENP) { 233155093Smarius#ifdef LEDEBUG 234155093Smarius if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) { 235155093Smarius if (rmd.rmd1_bits & LE_R1_FRAM) 236155093Smarius if_printf(ifp, 237155093Smarius "framing error\n"); 238155093Smarius if (rmd.rmd1_bits & LE_R1_CRC) 239155093Smarius if_printf(ifp, 240155093Smarius "crc mismatch\n"); 241155093Smarius } 242155093Smarius#endif 243155093Smarius } else { 244155093Smarius if (rmd.rmd1_bits & LE_R1_OFLO) 245155093Smarius if_printf(ifp, "overflow\n"); 246155093Smarius } 247155093Smarius if (rmd.rmd1_bits & LE_R1_BUFF) 248155093Smarius if_printf(ifp, "receive buffer error\n"); 249155093Smarius ifp->if_ierrors++; 250155093Smarius } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != 251155093Smarius (LE_R1_STP | LE_R1_ENP)) { 252155093Smarius if_printf(ifp, "dropping chained buffer\n"); 253155093Smarius ifp->if_ierrors++; 254155093Smarius } else { 255155093Smarius#ifdef LEDEBUG 256155093Smarius if (sc->sc_flags & LE_DEBUG) 257155093Smarius am7990_recv_print(sc, sc->sc_last_rd); 258155093Smarius#endif 259155093Smarius lance_read(sc, LE_RBUFADDR(sc, bix), 260155093Smarius (int)rmd.rmd3 - ETHER_CRC_LEN); 261155093Smarius } 262155093Smarius 263155093Smarius rmd.rmd1_bits = LE_R1_OWN; 264155093Smarius rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; 265155093Smarius rmd.rmd3 = 0; 266155093Smarius (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd)); 267155093Smarius 268155093Smarius#ifdef LEDEBUG 269155093Smarius if (sc->sc_flags & LE_DEBUG) 270155093Smarius if_printf(ifp, "sc->sc_last_rd = %x, rmd: " 271155093Smarius "ladr %04x, hadr %02x, flags %02x, " 272155093Smarius "bcnt %04x, mcnt %04x\n", 273155093Smarius sc->sc_last_rd, rmd.rmd0, rmd.rmd1_hadr, 274155093Smarius rmd.rmd1_bits, rmd.rmd2, rmd.rmd3); 275155093Smarius#endif 276155093Smarius 277155093Smarius if (++bix == sc->sc_nrbuf) 278155093Smarius bix = 0; 279155093Smarius } 280155093Smarius 281155093Smarius sc->sc_last_rd = bix; 282155093Smarius} 283155093Smarius 284155093Smariusstatic void 285155093Smariusam7990_tint(struct lance_softc *sc) 286155093Smarius{ 287155093Smarius struct ifnet *ifp = sc->sc_ifp; 288155093Smarius struct letmd tmd; 289155093Smarius int bix; 290155093Smarius 291155093Smarius bix = sc->sc_first_td; 292155093Smarius 293155093Smarius for (;;) { 294155093Smarius if (sc->sc_no_td <= 0) 295155093Smarius break; 296155093Smarius 297155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), 298155093Smarius sizeof(tmd)); 299155093Smarius 300155093Smarius#ifdef LEDEBUG 301155093Smarius if (sc->sc_flags & LE_DEBUG) 302155093Smarius if_printf(ifp, "trans tmd: " 303155093Smarius "ladr %04x, hadr %02x, flags %02x, " 304155093Smarius "bcnt %04x, mcnt %04x\n", 305155093Smarius tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, 306155093Smarius tmd.tmd2, tmd.tmd3); 307155093Smarius#endif 308155093Smarius 309155093Smarius if (tmd.tmd1_bits & LE_T1_OWN) 310155093Smarius break; 311155093Smarius 312155093Smarius ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 313155093Smarius 314155093Smarius if (tmd.tmd1_bits & LE_T1_ERR) { 315155093Smarius if (tmd.tmd3 & LE_T3_BUFF) 316155093Smarius if_printf(ifp, "transmit buffer error\n"); 317155093Smarius else if (tmd.tmd3 & LE_T3_UFLO) 318155093Smarius if_printf(ifp, "underflow\n"); 319155093Smarius if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) { 320155093Smarius lance_init_locked(sc); 321155093Smarius return; 322155093Smarius } 323155093Smarius if (tmd.tmd3 & LE_T3_LCAR) { 324155093Smarius if (sc->sc_flags & LE_CARRIER) 325155093Smarius if_link_state_change(ifp, 326155093Smarius LINK_STATE_DOWN); 327155093Smarius sc->sc_flags &= ~LE_CARRIER; 328155093Smarius if (sc->sc_nocarrier) 329155093Smarius (*sc->sc_nocarrier)(sc); 330155093Smarius else 331155093Smarius if_printf(ifp, "lost carrier\n"); 332155093Smarius } 333155093Smarius if (tmd.tmd3 & LE_T3_LCOL) 334155093Smarius ifp->if_collisions++; 335155093Smarius if (tmd.tmd3 & LE_T3_RTRY) { 336155093Smarius#ifdef LEDEBUG 337155093Smarius if_printf(ifp, "excessive collisions, tdr %d\n", 338155093Smarius tmd.tmd3 & LE_T3_TDR_MASK); 339155093Smarius#endif 340155093Smarius ifp->if_collisions += 16; 341155093Smarius } 342155093Smarius ifp->if_oerrors++; 343155093Smarius } else { 344155093Smarius if (tmd.tmd1_bits & LE_T1_ONE) 345155093Smarius ifp->if_collisions++; 346155093Smarius else if (tmd.tmd1_bits & LE_T1_MORE) 347155093Smarius /* Real number is unknown. */ 348155093Smarius ifp->if_collisions += 2; 349155093Smarius ifp->if_opackets++; 350155093Smarius } 351155093Smarius 352155093Smarius if (++bix == sc->sc_ntbuf) 353155093Smarius bix = 0; 354155093Smarius 355155093Smarius --sc->sc_no_td; 356155093Smarius } 357155093Smarius 358155093Smarius sc->sc_first_td = bix; 359155093Smarius 360155881Smarius ifp->if_timer = sc->sc_no_td > 0 ? 5 : 0; 361155093Smarius} 362155093Smarius 363155093Smarius/* 364155093Smarius * Controller interrupt 365155093Smarius */ 366155093Smariusvoid 367155093Smariusam7990_intr(void *arg) 368155093Smarius{ 369155093Smarius struct lance_softc *sc = arg; 370155093Smarius struct ifnet *ifp = sc->sc_ifp; 371155093Smarius uint16_t isr; 372155093Smarius 373155093Smarius LE_LOCK(sc); 374155093Smarius 375155093Smarius if (sc->sc_hwintr && (*sc->sc_hwintr)(sc) == -1) { 376155093Smarius ifp->if_ierrors++; 377155093Smarius lance_init_locked(sc); 378155093Smarius LE_UNLOCK(sc); 379155093Smarius return; 380155093Smarius } 381155093Smarius 382155093Smarius isr = (*sc->sc_rdcsr)(sc, LE_CSR0); 383155093Smarius#if defined(LEDEBUG) && LEDEBUG > 1 384155093Smarius if (sc->sc_flags & LE_DEBUG) 385155093Smarius if_printf(ifp, "%s: entering with isr=%04x\n", __func__, isr); 386155093Smarius#endif 387155093Smarius if ((isr & LE_C0_INTR) == 0) { 388155093Smarius LE_UNLOCK(sc); 389155093Smarius return; 390155093Smarius } 391155093Smarius 392155881Smarius /* 393155881Smarius * Clear interrupt source flags and turn off interrupts. If we 394155881Smarius * don't clear these flags before processing their sources we 395155881Smarius * could completely miss some interrupt events as the the NIC 396155881Smarius * can change these flags while we're in this handler. We turn 397155881Smarius * of interrupts while processing them so we don't get another 398155881Smarius * one while we still process the previous one in ifp->if_input() 399155881Smarius * with the driver lock dropped. 400155881Smarius */ 401155881Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD | 402155881Smarius LE_C0_STOP | LE_C0_STRT | LE_C0_INIT)); 403155881Smarius 404155093Smarius if (isr & LE_C0_ERR) { 405155093Smarius if (isr & LE_C0_BABL) { 406155093Smarius#ifdef LEDEBUG 407155093Smarius if_printf(ifp, "babble\n"); 408155093Smarius#endif 409155093Smarius ifp->if_oerrors++; 410155093Smarius } 411155093Smarius#if 0 412155093Smarius if (isr & LE_C0_CERR) { 413155093Smarius if_printf(ifp, "collision error\n"); 414155093Smarius ifp->if_collisions++; 415155093Smarius } 416155093Smarius#endif 417155093Smarius if (isr & LE_C0_MISS) { 418155093Smarius#ifdef LEDEBUG 419155093Smarius if_printf(ifp, "missed packet\n"); 420155093Smarius#endif 421155093Smarius ifp->if_ierrors++; 422155093Smarius } 423155093Smarius if (isr & LE_C0_MERR) { 424155093Smarius if_printf(ifp, "memory error\n"); 425155093Smarius lance_init_locked(sc); 426155093Smarius LE_UNLOCK(sc); 427155093Smarius return; 428155093Smarius } 429155093Smarius } 430155093Smarius 431155093Smarius if ((isr & LE_C0_RXON) == 0) { 432155093Smarius if_printf(ifp, "receiver disabled\n"); 433155093Smarius ifp->if_ierrors++; 434155093Smarius lance_init_locked(sc); 435155093Smarius LE_UNLOCK(sc); 436155093Smarius return; 437155093Smarius } 438155093Smarius if ((isr & LE_C0_TXON) == 0) { 439155093Smarius if_printf(ifp, "transmitter disabled\n"); 440155093Smarius ifp->if_oerrors++; 441155093Smarius lance_init_locked(sc); 442155093Smarius LE_UNLOCK(sc); 443155093Smarius return; 444155093Smarius } 445155093Smarius 446155093Smarius /* 447155093Smarius * Pretend we have carrier; if we don't this will be cleared shortly. 448155093Smarius */ 449155093Smarius if (!(sc->sc_flags & LE_CARRIER)) 450155093Smarius if_link_state_change(ifp, LINK_STATE_UP); 451155093Smarius sc->sc_flags |= LE_CARRIER; 452155093Smarius 453155093Smarius if (isr & LE_C0_RINT) 454155093Smarius am7990_rint(sc); 455155093Smarius if (isr & LE_C0_TINT) 456155093Smarius am7990_tint(sc); 457155093Smarius 458155881Smarius /* Enable interrupts again. */ 459155881Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA); 460155093Smarius 461155881Smarius if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 462155881Smarius am7990_start_locked(sc); 463155881Smarius 464155093Smarius LE_UNLOCK(sc); 465155093Smarius} 466155093Smarius 467155093Smarius/* 468155093Smarius * Set up output on interface. 469155093Smarius * Get another datagram to send off of the interface queue, and map it to the 470155093Smarius * interface before starting the output. 471155093Smarius */ 472155093Smariusstatic void 473155093Smariusam7990_start_locked(struct lance_softc *sc) 474155093Smarius{ 475155093Smarius struct ifnet *ifp = sc->sc_ifp; 476155093Smarius struct letmd tmd; 477155093Smarius struct mbuf *m; 478155881Smarius int bix, enq, len, rp; 479155093Smarius 480155093Smarius LE_LOCK_ASSERT(sc, MA_OWNED); 481155093Smarius 482155093Smarius if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 483155093Smarius IFF_DRV_RUNNING) 484155093Smarius return; 485155093Smarius 486155093Smarius bix = sc->sc_last_td; 487155881Smarius enq = 0; 488155093Smarius 489155093Smarius for (; sc->sc_no_td < sc->sc_ntbuf && 490155093Smarius !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 491155093Smarius rp = LE_TMDADDR(sc, bix); 492155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd)); 493155093Smarius 494155093Smarius if (tmd.tmd1_bits & LE_T1_OWN) { 495155093Smarius ifp->if_drv_flags |= IFF_DRV_OACTIVE; 496155093Smarius if_printf(ifp, 497155093Smarius "missing buffer, no_td = %d, last_td = %d\n", 498155093Smarius sc->sc_no_td, sc->sc_last_td); 499155093Smarius } 500155093Smarius 501155093Smarius IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 502155093Smarius if (m == 0) 503155093Smarius break; 504155093Smarius 505155093Smarius /* 506155093Smarius * If BPF is listening on this interface, let it see the packet 507155093Smarius * before we commit it to the wire. 508155093Smarius */ 509155093Smarius BPF_MTAP(ifp, m); 510155093Smarius 511155093Smarius /* 512155093Smarius * Copy the mbuf chain into the transmit buffer. 513155093Smarius */ 514155093Smarius len = lance_put(sc, LE_TBUFADDR(sc, bix), m); 515155093Smarius 516155093Smarius#ifdef LEDEBUG 517155093Smarius if (len > ETHERMTU + ETHER_HDR_LEN) 518155093Smarius if_printf(ifp, "packet length %d\n", len); 519155093Smarius#endif 520155093Smarius 521155093Smarius /* 522155093Smarius * Init transmit registers, and set transmit start flag. 523155093Smarius */ 524155093Smarius tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP; 525155093Smarius tmd.tmd2 = -len | LE_XMD2_ONES; 526155093Smarius tmd.tmd3 = 0; 527155093Smarius 528155093Smarius (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd)); 529155093Smarius 530155093Smarius#ifdef LEDEBUG 531155093Smarius if (sc->sc_flags & LE_DEBUG) 532155093Smarius am7990_xmit_print(sc, sc->sc_last_td); 533155093Smarius#endif 534155093Smarius 535155093Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); 536155881Smarius enq++; 537155093Smarius 538155093Smarius if (++bix == sc->sc_ntbuf) 539155093Smarius bix = 0; 540155093Smarius 541155093Smarius if (++sc->sc_no_td == sc->sc_ntbuf) { 542155093Smarius ifp->if_drv_flags |= IFF_DRV_OACTIVE; 543155093Smarius break; 544155093Smarius } 545155093Smarius } 546155093Smarius 547155093Smarius sc->sc_last_td = bix; 548155881Smarius 549155881Smarius if (enq > 0) 550155881Smarius ifp->if_timer = 5; 551155093Smarius} 552155093Smarius 553155093Smarius#ifdef LEDEBUG 554155093Smariusstatic void 555155093Smariusam7990_recv_print(struct lance_softc *sc, int no) 556155093Smarius{ 557155093Smarius struct ifnet *ifp = sc->sc_ifp; 558155093Smarius struct ether_header eh; 559155093Smarius struct lermd rmd; 560155093Smarius uint16_t len; 561155093Smarius 562155093Smarius (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd)); 563155093Smarius len = rmd.rmd3; 564155093Smarius if_printf(ifp, "receive buffer %d, len = %d\n", no, len); 565155093Smarius if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0)); 566155093Smarius if_printf(ifp, 567155093Smarius "ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", 568155093Smarius rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3); 569155093Smarius if (len - ETHER_CRC_LEN >= sizeof(eh)) { 570155093Smarius (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh)); 571155093Smarius if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost)); 572155093Smarius printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 573155093Smarius ntohs(eh.ether_type)); 574155093Smarius } 575155093Smarius} 576155093Smarius 577155093Smariusstatic void 578155093Smariusam7990_xmit_print(struct lance_softc *sc, int no) 579155093Smarius{ 580155093Smarius struct ifnet *ifp = sc->sc_ifp; 581155093Smarius struct ether_header eh; 582155093Smarius struct letmd tmd; 583155093Smarius uint16_t len; 584155093Smarius 585155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd)); 586155093Smarius len = -tmd.tmd2; 587155093Smarius if_printf(ifp, "transmit buffer %d, len = %d\n", no, len); 588155093Smarius if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0)); 589155093Smarius if_printf(ifp, 590155093Smarius "ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", 591155093Smarius tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3); 592155093Smarius if (len >= sizeof(eh)) { 593155093Smarius (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh)); 594155093Smarius if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost)); 595155093Smarius printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 596155093Smarius ntohs(eh.ether_type)); 597155093Smarius } 598155093Smarius} 599155093Smarius#endif /* LEDEBUG */ 600