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