1155093Smarius/* $NetBSD: am79900.c,v 1.17 2005/12/24 20:27:29 perry Exp $ */ 2155093Smarius 3155093Smarius/*- 4155093Smarius * Copyright (c) 1997 The NetBSD Foundation, Inc. 5155093Smarius * All rights reserved. 6155093Smarius * 7155093Smarius * This code is derived from software contributed to The NetBSD Foundation 8155093Smarius * by Jason R. Thorpe. 9155093Smarius * 10155093Smarius * Redistribution and use in source and binary forms, with or without 11155093Smarius * modification, are permitted provided that the following conditions 12155093Smarius * are met: 13155093Smarius * 1. Redistributions of source code must retain the above copyright 14155093Smarius * notice, this list of conditions and the following disclaimer. 15155093Smarius * 2. Redistributions in binary form must reproduce the above copyright 16155093Smarius * notice, this list of conditions and the following disclaimer in the 17155093Smarius * documentation and/or other materials provided with the distribution. 18155093Smarius * 3. All advertising materials mentioning features or use of this software 19155093Smarius * must display the following acknowledgement: 20155093Smarius * This product includes software developed by the NetBSD 21155093Smarius * Foundation, Inc. and its contributors. 22155093Smarius * 4. Neither the name of The NetBSD Foundation nor the names of its 23155093Smarius * contributors may be used to endorse or promote products derived 24155093Smarius * from this software without specific prior written permission. 25155093Smarius * 26155093Smarius * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27155093Smarius * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28155093Smarius * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29155093Smarius * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30155093Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31155093Smarius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32155093Smarius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33155093Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34155093Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35155093Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36155093Smarius * POSSIBILITY OF SUCH DAMAGE. 37155093Smarius */ 38155093Smarius 39155093Smarius/*- 40155093Smarius * Copyright (c) 1992, 1993 41155093Smarius * The Regents of the University of California. All rights reserved. 42155093Smarius * 43155093Smarius * This code is derived from software contributed to Berkeley by 44155093Smarius * Ralph Campbell and Rick Macklem. 45155093Smarius * 46155093Smarius * Redistribution and use in source and binary forms, with or without 47155093Smarius * modification, are permitted provided that the following conditions 48155093Smarius * are met: 49155093Smarius * 1. Redistributions of source code must retain the above copyright 50155093Smarius * notice, this list of conditions and the following disclaimer. 51155093Smarius * 2. Redistributions in binary form must reproduce the above copyright 52155093Smarius * notice, this list of conditions and the following disclaimer in the 53155093Smarius * documentation and/or other materials provided with the distribution. 54155093Smarius * 3. Neither the name of the University nor the names of its contributors 55155093Smarius * may be used to endorse or promote products derived from this software 56155093Smarius * without specific prior written permission. 57155093Smarius * 58155093Smarius * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59155093Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60155093Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61155093Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62155093Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63155093Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64155093Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65155093Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66155093Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67155093Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68155093Smarius * SUCH DAMAGE. 69155093Smarius * 70155093Smarius * @(#)if_le.c 8.2 (Berkeley) 11/16/93 71155093Smarius */ 72155093Smarius 73155093Smarius/*- 74155093Smarius * Copyright (c) 1998 75155093Smarius * Matthias Drochner. All rights reserved. 76155093Smarius * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 77155093Smarius * 78155093Smarius * This code is derived from software contributed to Berkeley by 79155093Smarius * Ralph Campbell and Rick Macklem. 80155093Smarius * 81155093Smarius * Redistribution and use in source and binary forms, with or without 82155093Smarius * modification, are permitted provided that the following conditions 83155093Smarius * are met: 84155093Smarius * 1. Redistributions of source code must retain the above copyright 85155093Smarius * notice, this list of conditions and the following disclaimer. 86155093Smarius * 2. Redistributions in binary form must reproduce the above copyright 87155093Smarius * notice, this list of conditions and the following disclaimer in the 88155093Smarius * documentation and/or other materials provided with the distribution. 89155093Smarius * 3. All advertising materials mentioning features or use of this software 90155093Smarius * must display the following acknowledgement: 91155093Smarius * This product includes software developed by the University of 92155093Smarius * California, Berkeley and its contributors. 93155093Smarius * 4. Neither the name of the University nor the names of its contributors 94155093Smarius * may be used to endorse or promote products derived from this software 95155093Smarius * without specific prior written permission. 96155093Smarius * 97155093Smarius * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 98155093Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 99155093Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 100155093Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 101155093Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 102155093Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 103155093Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 104155093Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 105155093Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 106155093Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 107155093Smarius * SUCH DAMAGE. 108155093Smarius * 109155093Smarius * @(#)if_le.c 8.2 (Berkeley) 11/16/93 110155093Smarius */ 111155093Smarius 112155093Smarius#include <sys/cdefs.h> 113155093Smarius__FBSDID("$FreeBSD$"); 114155093Smarius 115155093Smarius#include <sys/param.h> 116155093Smarius#include <sys/bus.h> 117155093Smarius#include <sys/endian.h> 118155093Smarius#include <sys/lock.h> 119155093Smarius#include <sys/mbuf.h> 120155093Smarius#include <sys/mutex.h> 121155093Smarius#include <sys/socket.h> 122155093Smarius 123155093Smarius#include <net/bpf.h> 124155093Smarius#include <net/ethernet.h> 125155093Smarius#include <net/if.h> 126155093Smarius#include <net/if_arp.h> 127155093Smarius#include <net/if_dl.h> 128155093Smarius#include <net/if_media.h> 129155093Smarius#include <net/if_var.h> 130155093Smarius 131158663Smarius#include <machine/bus.h> 132158663Smarius 133155093Smarius#include <dev/le/lancereg.h> 134155093Smarius#include <dev/le/lancevar.h> 135155093Smarius#include <dev/le/am79900reg.h> 136155093Smarius#include <dev/le/am79900var.h> 137155093Smarius 138155093Smariusstatic void am79900_meminit(struct lance_softc *); 139155093Smariusstatic void am79900_rint(struct lance_softc *); 140155093Smariusstatic void am79900_tint(struct lance_softc *); 141155093Smariusstatic void am79900_start_locked(struct lance_softc *sc); 142155093Smarius 143155093Smarius#ifdef LEDEBUG 144155093Smariusstatic void am79900_recv_print(struct lance_softc *, int); 145155093Smariusstatic void am79900_xmit_print(struct lance_softc *, int); 146155093Smarius#endif 147155093Smarius 148155093Smariusint 149155093Smariusam79900_config(struct am79900_softc *sc, const char* name, int unit) 150155093Smarius{ 151155093Smarius int error, mem; 152155093Smarius 153155093Smarius sc->lsc.sc_meminit = am79900_meminit; 154155093Smarius sc->lsc.sc_start_locked = am79900_start_locked; 155155093Smarius 156155093Smarius error = lance_config(&sc->lsc, name, unit); 157155093Smarius if (error != 0) 158155093Smarius return (error); 159155093Smarius 160155093Smarius mem = 0; 161155093Smarius sc->lsc.sc_initaddr = mem; 162155093Smarius mem += sizeof(struct leinit); 163155093Smarius sc->lsc.sc_rmdaddr = mem; 164155093Smarius mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf; 165155093Smarius sc->lsc.sc_tmdaddr = mem; 166155093Smarius mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf; 167155093Smarius sc->lsc.sc_rbufaddr = mem; 168155093Smarius mem += LEBLEN * sc->lsc.sc_nrbuf; 169155093Smarius sc->lsc.sc_tbufaddr = mem; 170155093Smarius mem += LEBLEN * sc->lsc.sc_ntbuf; 171155093Smarius 172155093Smarius if (mem > sc->lsc.sc_memsize) 173155093Smarius panic("%s: memsize", __func__); 174155093Smarius 175155093Smarius lance_attach(&sc->lsc); 176155093Smarius 177155093Smarius return (0); 178155093Smarius} 179155093Smarius 180155093Smariusvoid 181155093Smariusam79900_detach(struct am79900_softc *sc) 182155093Smarius{ 183155093Smarius 184155093Smarius lance_detach(&sc->lsc); 185155093Smarius} 186155093Smarius 187155093Smarius/* 188155093Smarius * Set up the initialization block and the descriptor rings. 189155093Smarius */ 190155093Smariusstatic void 191155093Smariusam79900_meminit(struct lance_softc *sc) 192155093Smarius{ 193155093Smarius struct ifnet *ifp = sc->sc_ifp; 194155093Smarius struct leinit init; 195155093Smarius struct lermd rmd; 196155093Smarius struct letmd tmd; 197155093Smarius u_long a; 198155093Smarius int bix; 199155093Smarius 200155093Smarius LE_LOCK_ASSERT(sc, MA_OWNED); 201155093Smarius 202155093Smarius if (ifp->if_flags & IFF_PROMISC) 203155093Smarius init.init_mode = LE_HTOLE32(LE_MODE_NORMAL | LE_MODE_PROM); 204155093Smarius else 205155093Smarius init.init_mode = LE_HTOLE32(LE_MODE_NORMAL); 206155093Smarius 207155093Smarius init.init_mode |= LE_HTOLE32(((ffs(sc->sc_ntbuf) - 1) << 28) | 208155093Smarius ((ffs(sc->sc_nrbuf) - 1) << 20)); 209155093Smarius 210155093Smarius init.init_padr[0] = LE_HTOLE32(sc->sc_enaddr[0] | 211155093Smarius (sc->sc_enaddr[1] << 8) | (sc->sc_enaddr[2] << 16) | 212155093Smarius (sc->sc_enaddr[3] << 24)); 213155093Smarius init.init_padr[1] = LE_HTOLE32(sc->sc_enaddr[4] | 214155093Smarius (sc->sc_enaddr[5] << 8)); 215155093Smarius lance_setladrf(sc, init.init_ladrf); 216155093Smarius 217155093Smarius sc->sc_last_rd = 0; 218155093Smarius sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0; 219155093Smarius 220155093Smarius a = sc->sc_addr + LE_RMDADDR(sc, 0); 221155093Smarius init.init_rdra = LE_HTOLE32(a); 222155093Smarius 223155093Smarius a = sc->sc_addr + LE_TMDADDR(sc, 0); 224155093Smarius init.init_tdra = LE_HTOLE32(a); 225155093Smarius 226155093Smarius (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init)); 227155093Smarius 228155093Smarius /* 229155093Smarius * Set up receive ring descriptors. 230155093Smarius */ 231155093Smarius for (bix = 0; bix < sc->sc_nrbuf; bix++) { 232155093Smarius a = sc->sc_addr + LE_RBUFADDR(sc, bix); 233155093Smarius rmd.rmd0 = LE_HTOLE32(a); 234155093Smarius rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES | 235155093Smarius (-LEBLEN & 0xfff)); 236155093Smarius rmd.rmd2 = 0; 237155093Smarius rmd.rmd3 = 0; 238155093Smarius (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix), 239155093Smarius sizeof(rmd)); 240155093Smarius } 241155093Smarius 242155093Smarius /* 243155093Smarius * Set up transmit ring descriptors. 244155093Smarius */ 245155093Smarius for (bix = 0; bix < sc->sc_ntbuf; bix++) { 246155093Smarius a = sc->sc_addr + LE_TBUFADDR(sc, bix); 247155093Smarius tmd.tmd0 = LE_HTOLE32(a); 248155093Smarius tmd.tmd1 = LE_HTOLE32(LE_T1_ONES); 249155093Smarius tmd.tmd2 = 0; 250155093Smarius tmd.tmd3 = 0; 251155093Smarius (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix), 252155093Smarius sizeof(tmd)); 253155093Smarius } 254155093Smarius} 255155093Smarius 256155093Smariusstatic inline void 257155093Smariusam79900_rint(struct lance_softc *sc) 258155093Smarius{ 259155093Smarius struct ifnet *ifp = sc->sc_ifp; 260158663Smarius struct mbuf *m; 261155093Smarius struct lermd rmd; 262155093Smarius uint32_t rmd1; 263155093Smarius int bix, rp; 264158663Smarius#if defined(__i386__) && !defined(PC98) 265158663Smarius struct ether_header *eh; 266158663Smarius#endif 267155093Smarius 268155093Smarius bix = sc->sc_last_rd; 269155093Smarius 270155093Smarius /* Process all buffers with valid data. */ 271155093Smarius for (;;) { 272155093Smarius rp = LE_RMDADDR(sc, bix); 273155093Smarius (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd)); 274155093Smarius 275155093Smarius rmd1 = LE_LE32TOH(rmd.rmd1); 276155093Smarius if (rmd1 & LE_R1_OWN) 277155093Smarius break; 278155093Smarius 279158663Smarius m = NULL; 280158663Smarius if ((rmd1 & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) != 281158663Smarius (LE_R1_STP | LE_R1_ENP)){ 282158663Smarius if (rmd1 & LE_R1_ERR) { 283155093Smarius#ifdef LEDEBUG 284158663Smarius if (rmd1 & LE_R1_ENP) { 285158663Smarius if ((rmd1 & LE_R1_OFLO) == 0) { 286158663Smarius if (rmd1 & LE_R1_FRAM) 287158663Smarius if_printf(ifp, 288158663Smarius "framing error\n"); 289158663Smarius if (rmd1 & LE_R1_CRC) 290158663Smarius if_printf(ifp, 291158663Smarius "crc mismatch\n"); 292158663Smarius } 293158663Smarius } else 294158663Smarius if (rmd1 & LE_R1_OFLO) 295158663Smarius if_printf(ifp, "overflow\n"); 296155093Smarius#endif 297158663Smarius if (rmd1 & LE_R1_BUFF) 298158663Smarius if_printf(ifp, 299158663Smarius "receive buffer error\n"); 300158663Smarius } else if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) != 301158663Smarius (LE_R1_STP | LE_R1_ENP)) 302158663Smarius if_printf(ifp, "dropping chained buffer\n"); 303155093Smarius } else { 304155093Smarius#ifdef LEDEBUG 305155093Smarius if (sc->sc_flags & LE_DEBUG) 306158663Smarius am79900_recv_print(sc, bix); 307155093Smarius#endif 308158663Smarius /* Pull the packet off the interface. */ 309158663Smarius m = lance_get(sc, LE_RBUFADDR(sc, bix), 310155093Smarius (LE_LE32TOH(rmd.rmd2) & 0xfff) - ETHER_CRC_LEN); 311155093Smarius } 312155093Smarius 313155093Smarius rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES | 314155093Smarius (-LEBLEN & 0xfff)); 315155093Smarius rmd.rmd2 = 0; 316155093Smarius rmd.rmd3 = 0; 317155093Smarius (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd)); 318155093Smarius 319158663Smarius if (++bix == sc->sc_nrbuf) 320158663Smarius bix = 0; 321158663Smarius 322158663Smarius if (m != NULL) { 323158663Smarius ifp->if_ipackets++; 324158663Smarius 325158663Smarius#if defined(__i386__) && !defined(PC98) 326158663Smarius /* 327158663Smarius * The VMware LANCE does not present IFF_SIMPLEX 328158663Smarius * behavior on multicast packets. Thus drop the 329158663Smarius * packet if it is from ourselves. 330158663Smarius */ 331158663Smarius eh = mtod(m, struct ether_header *); 332158663Smarius if (!ether_cmp(eh->ether_shost, sc->sc_enaddr)) { 333158663Smarius m_freem(m); 334158663Smarius continue; 335158663Smarius } 336155093Smarius#endif 337155093Smarius 338158663Smarius /* Pass the packet up. */ 339158663Smarius LE_UNLOCK(sc); 340158663Smarius (*ifp->if_input)(ifp, m); 341158663Smarius LE_LOCK(sc); 342158663Smarius } else 343158663Smarius ifp->if_ierrors++; 344155093Smarius } 345155093Smarius 346155093Smarius sc->sc_last_rd = bix; 347155093Smarius} 348155093Smarius 349155093Smariusstatic inline void 350155093Smariusam79900_tint(struct lance_softc *sc) 351155093Smarius{ 352155093Smarius struct ifnet *ifp = sc->sc_ifp; 353155093Smarius struct letmd tmd; 354155093Smarius uint32_t tmd1, tmd2; 355155093Smarius int bix; 356155093Smarius 357155093Smarius bix = sc->sc_first_td; 358155093Smarius 359155093Smarius for (;;) { 360155093Smarius if (sc->sc_no_td <= 0) 361155093Smarius break; 362155093Smarius 363155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), 364155093Smarius sizeof(tmd)); 365155093Smarius 366158663Smarius tmd1 = LE_LE32TOH(tmd.tmd1); 367158663Smarius 368155093Smarius#ifdef LEDEBUG 369155093Smarius if (sc->sc_flags & LE_DEBUG) 370155093Smarius if_printf(ifp, "trans tmd: " 371155093Smarius "adr %08x, flags/blen %08x\n", 372158663Smarius LE_LE32TOH(tmd.tmd0), tmd1); 373155093Smarius#endif 374155093Smarius 375155093Smarius if (tmd1 & LE_T1_OWN) 376155093Smarius break; 377155093Smarius 378155093Smarius ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 379155093Smarius 380155093Smarius if (tmd1 & LE_T1_ERR) { 381158663Smarius tmd2 = LE_LE32TOH(tmd.tmd2); 382155093Smarius if (tmd2 & LE_T2_BUFF) 383155093Smarius if_printf(ifp, "transmit buffer error\n"); 384155093Smarius else if (tmd2 & LE_T2_UFLO) 385155093Smarius if_printf(ifp, "underflow\n"); 386155093Smarius if (tmd2 & (LE_T2_BUFF | LE_T2_UFLO)) { 387155093Smarius lance_init_locked(sc); 388155093Smarius return; 389155093Smarius } 390155093Smarius if (tmd2 & LE_T2_LCAR) { 391155093Smarius if (sc->sc_flags & LE_CARRIER) 392155093Smarius if_link_state_change(ifp, 393155093Smarius LINK_STATE_DOWN); 394155093Smarius sc->sc_flags &= ~LE_CARRIER; 395155093Smarius if (sc->sc_nocarrier) 396155093Smarius (*sc->sc_nocarrier)(sc); 397155093Smarius else 398155093Smarius if_printf(ifp, "lost carrier\n"); 399155093Smarius } 400155093Smarius if (tmd2 & LE_T2_LCOL) 401155093Smarius ifp->if_collisions++; 402155093Smarius if (tmd2 & LE_T2_RTRY) { 403155093Smarius#ifdef LEDEBUG 404155093Smarius if_printf(ifp, "excessive collisions\n"); 405155093Smarius#endif 406155093Smarius ifp->if_collisions += 16; 407155093Smarius } 408155093Smarius ifp->if_oerrors++; 409155093Smarius } else { 410155093Smarius if (tmd1 & LE_T1_ONE) 411155093Smarius ifp->if_collisions++; 412155093Smarius else if (tmd1 & LE_T1_MORE) 413155093Smarius /* Real number is unknown. */ 414155093Smarius ifp->if_collisions += 2; 415155093Smarius ifp->if_opackets++; 416155093Smarius } 417155093Smarius 418155093Smarius if (++bix == sc->sc_ntbuf) 419155093Smarius bix = 0; 420155093Smarius 421155093Smarius --sc->sc_no_td; 422155093Smarius } 423155093Smarius 424155093Smarius sc->sc_first_td = bix; 425155093Smarius 426164933Smarius sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0; 427155093Smarius} 428155093Smarius 429155093Smarius/* 430155093Smarius * Controller interrupt 431155093Smarius */ 432155093Smariusvoid 433155093Smariusam79900_intr(void *arg) 434155093Smarius{ 435155093Smarius struct lance_softc *sc = arg; 436155093Smarius struct ifnet *ifp = sc->sc_ifp; 437155093Smarius uint16_t isr; 438155093Smarius 439155093Smarius LE_LOCK(sc); 440155093Smarius 441155093Smarius if (sc->sc_hwintr && (*sc->sc_hwintr)(sc) == -1) { 442155093Smarius ifp->if_ierrors++; 443155093Smarius lance_init_locked(sc); 444155093Smarius LE_UNLOCK(sc); 445155093Smarius return; 446155093Smarius } 447155093Smarius 448155093Smarius isr = (*sc->sc_rdcsr)(sc, LE_CSR0); 449155093Smarius#if defined(LEDEBUG) && LEDEBUG > 1 450155093Smarius if (sc->sc_flags & LE_DEBUG) 451155093Smarius if_printf(ifp, "%s: entering with isr=%04x\n", __func__, isr); 452155093Smarius#endif 453155093Smarius if ((isr & LE_C0_INTR) == 0) { 454155093Smarius LE_UNLOCK(sc); 455155093Smarius return; 456155093Smarius } 457155093Smarius 458155881Smarius /* 459155881Smarius * Clear interrupt source flags and turn off interrupts. If we 460155881Smarius * don't clear these flags before processing their sources we 461158663Smarius * could completely miss some interrupt events as the NIC can 462174986Smarius * change these flags while we're in this handler. We toggle 463174986Smarius * the interrupt enable bit in order to keep receiving them 464174986Smarius * (some chips work without this, some don't). 465155881Smarius */ 466155881Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD | 467155881Smarius LE_C0_STOP | LE_C0_STRT | LE_C0_INIT)); 468155881Smarius 469155093Smarius if (isr & LE_C0_ERR) { 470155093Smarius if (isr & LE_C0_BABL) { 471155093Smarius#ifdef LEDEBUG 472155093Smarius if_printf(ifp, "babble\n"); 473155093Smarius#endif 474155093Smarius ifp->if_oerrors++; 475155093Smarius } 476155093Smarius#if 0 477155093Smarius if (isr & LE_C0_CERR) { 478155093Smarius if_printf(ifp, "collision error\n"); 479155093Smarius ifp->if_collisions++; 480155093Smarius } 481155093Smarius#endif 482155093Smarius if (isr & LE_C0_MISS) { 483155093Smarius#ifdef LEDEBUG 484155093Smarius if_printf(ifp, "missed packet\n"); 485155093Smarius#endif 486155093Smarius ifp->if_ierrors++; 487155093Smarius } 488155093Smarius if (isr & LE_C0_MERR) { 489155093Smarius if_printf(ifp, "memory error\n"); 490155093Smarius lance_init_locked(sc); 491155093Smarius LE_UNLOCK(sc); 492155093Smarius return; 493155093Smarius } 494155093Smarius } 495155093Smarius 496155093Smarius if ((isr & LE_C0_RXON) == 0) { 497155093Smarius if_printf(ifp, "receiver disabled\n"); 498155093Smarius ifp->if_ierrors++; 499155093Smarius lance_init_locked(sc); 500155093Smarius LE_UNLOCK(sc); 501155093Smarius return; 502155093Smarius } 503155093Smarius if ((isr & LE_C0_TXON) == 0) { 504155093Smarius if_printf(ifp, "transmitter disabled\n"); 505155093Smarius ifp->if_oerrors++; 506155093Smarius lance_init_locked(sc); 507155093Smarius LE_UNLOCK(sc); 508155093Smarius return; 509155093Smarius } 510155093Smarius 511155093Smarius /* 512155093Smarius * Pretend we have carrier; if we don't this will be cleared shortly. 513155093Smarius */ 514155093Smarius if (!(sc->sc_flags & LE_CARRIER)) 515155093Smarius if_link_state_change(ifp, LINK_STATE_UP); 516155093Smarius sc->sc_flags |= LE_CARRIER; 517155093Smarius 518155093Smarius if (isr & LE_C0_RINT) 519155093Smarius am79900_rint(sc); 520155093Smarius if (isr & LE_C0_TINT) 521155093Smarius am79900_tint(sc); 522155093Smarius 523155881Smarius /* Enable interrupts again. */ 524155881Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA); 525155093Smarius 526155881Smarius if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 527155881Smarius am79900_start_locked(sc); 528155881Smarius 529155093Smarius LE_UNLOCK(sc); 530155093Smarius} 531155093Smarius 532155093Smarius/* 533155093Smarius * Set up output on interface. 534155093Smarius * Get another datagram to send off of the interface queue, and map it to the 535155093Smarius * interface before starting the output. 536155093Smarius */ 537155093Smariusstatic void 538155093Smariusam79900_start_locked(struct lance_softc *sc) 539155093Smarius{ 540155093Smarius struct ifnet *ifp = sc->sc_ifp; 541155093Smarius struct letmd tmd; 542155093Smarius struct mbuf *m; 543155881Smarius int bix, enq, len, rp; 544155093Smarius 545155093Smarius LE_LOCK_ASSERT(sc, MA_OWNED); 546155093Smarius 547155093Smarius if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 548155093Smarius IFF_DRV_RUNNING) 549155093Smarius return; 550155093Smarius 551155093Smarius bix = sc->sc_last_td; 552155881Smarius enq = 0; 553155093Smarius 554155093Smarius for (; sc->sc_no_td < sc->sc_ntbuf && 555155093Smarius !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 556155093Smarius rp = LE_TMDADDR(sc, bix); 557155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd)); 558155093Smarius 559155093Smarius if (LE_LE32TOH(tmd.tmd1) & LE_T1_OWN) { 560155093Smarius ifp->if_drv_flags |= IFF_DRV_OACTIVE; 561155093Smarius if_printf(ifp, 562155093Smarius "missing buffer, no_td = %d, last_td = %d\n", 563155093Smarius sc->sc_no_td, sc->sc_last_td); 564155093Smarius } 565155093Smarius 566155093Smarius IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 567155093Smarius if (m == 0) 568155093Smarius break; 569155093Smarius 570155093Smarius /* 571155093Smarius * If BPF is listening on this interface, let it see the packet 572155093Smarius * before we commit it to the wire. 573155093Smarius */ 574155093Smarius BPF_MTAP(ifp, m); 575155093Smarius 576155093Smarius /* 577155093Smarius * Copy the mbuf chain into the transmit buffer. 578155093Smarius */ 579155093Smarius len = lance_put(sc, LE_TBUFADDR(sc, bix), m); 580155093Smarius 581155093Smarius#ifdef LEDEBUG 582155093Smarius if (len > ETHERMTU + ETHER_HDR_LEN) 583155093Smarius if_printf(ifp, "packet length %d\n", len); 584155093Smarius#endif 585155093Smarius 586155093Smarius /* 587155093Smarius * Init transmit registers, and set transmit start flag. 588155093Smarius */ 589155093Smarius tmd.tmd1 = LE_HTOLE32(LE_T1_OWN | LE_T1_STP | LE_T1_ENP | 590155093Smarius LE_T1_ONES | (-len & 0xfff)); 591155093Smarius tmd.tmd2 = 0; 592155093Smarius tmd.tmd3 = 0; 593155093Smarius 594155093Smarius (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd)); 595155093Smarius 596155093Smarius#ifdef LEDEBUG 597155093Smarius if (sc->sc_flags & LE_DEBUG) 598158663Smarius am79900_xmit_print(sc, bix); 599155093Smarius#endif 600155093Smarius 601155093Smarius (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); 602155881Smarius enq++; 603155093Smarius 604155093Smarius if (++bix == sc->sc_ntbuf) 605155093Smarius bix = 0; 606155093Smarius 607155093Smarius if (++sc->sc_no_td == sc->sc_ntbuf) { 608155093Smarius ifp->if_drv_flags |= IFF_DRV_OACTIVE; 609155093Smarius break; 610155093Smarius } 611155093Smarius } 612155093Smarius 613155093Smarius sc->sc_last_td = bix; 614155881Smarius 615155881Smarius if (enq > 0) 616164933Smarius sc->sc_wdog_timer = 5; 617155093Smarius} 618155093Smarius 619155093Smarius#ifdef LEDEBUG 620155093Smariusstatic void 621155093Smariusam79900_recv_print(struct lance_softc *sc, int no) 622155093Smarius{ 623155093Smarius struct ifnet *ifp = sc->sc_ifp; 624155093Smarius struct ether_header eh; 625155093Smarius struct lermd rmd; 626155093Smarius uint16_t len; 627155093Smarius 628155093Smarius (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd)); 629155093Smarius len = LE_LE32TOH(rmd.rmd2) & 0xfff; 630155093Smarius if_printf(ifp, "receive buffer %d, len = %d\n", no, len); 631155093Smarius if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0)); 632155093Smarius if_printf(ifp, "adr %08x, flags/blen %08x\n", LE_LE32TOH(rmd.rmd0), 633155093Smarius LE_LE32TOH(rmd.rmd1)); 634155093Smarius if (len - ETHER_CRC_LEN >= sizeof(eh)) { 635155093Smarius (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh)); 636155093Smarius if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost)); 637155093Smarius printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 638155093Smarius ntohs(eh.ether_type)); 639155093Smarius } 640155093Smarius} 641155093Smarius 642155093Smariusstatic void 643155093Smariusam79900_xmit_print(struct lance_softc *sc, int no) 644155093Smarius{ 645155093Smarius struct ifnet *ifp = sc->sc_ifp; 646155093Smarius struct ether_header eh; 647155093Smarius struct letmd tmd; 648155093Smarius uint16_t len; 649155093Smarius 650155093Smarius (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd)); 651155093Smarius len = -(LE_LE32TOH(tmd.tmd1) & 0xfff); 652155093Smarius if_printf(ifp, "transmit buffer %d, len = %d\n", no, len); 653155093Smarius if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0)); 654155093Smarius if_printf(ifp, "adr %08x, flags/blen %08x\n", LE_LE32TOH(tmd.tmd0), 655155093Smarius LE_LE32TOH(tmd.tmd1)); 656155093Smarius if (len >= sizeof(eh)) { 657155093Smarius (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh)); 658155093Smarius if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost)); 659155093Smarius printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 660155093Smarius ntohs(eh.ether_type)); 661155093Smarius } 662155093Smarius} 663155093Smarius#endif /* LEDEBUG */ 664