11590Srgrimes/* $NetBSD: lance.c,v 1.34 2005/12/24 20:27:30 perry Exp $ */ 21590Srgrimes 31590Srgrimes/*- 41590Srgrimes * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * This code is derived from software contributed to The NetBSD Foundation 81590Srgrimes * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 91590Srgrimes * Simulation Facility, NASA Ames Research Center. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 191590Srgrimes * 3. All advertising materials mentioning features or use of this software 201590Srgrimes * must display the following acknowledgement: 211590Srgrimes * This product includes software developed by the NetBSD 221590Srgrimes * Foundation, Inc. and its contributors. 231590Srgrimes * 4. Neither the name of The NetBSD Foundation nor the names of its 241590Srgrimes * contributors may be used to endorse or promote products derived 251590Srgrimes * from this software without specific prior written permission. 261590Srgrimes * 271590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 281590Srgrimes * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 291590Srgrimes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 3087715Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 3187715Smarkm * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 3287715Smarkm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3387715Smarkm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3487715Smarkm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3587715Smarkm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3628149Scharnier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 371590Srgrimes * POSSIBILITY OF SUCH DAMAGE. 381590Srgrimes */ 391590Srgrimes 401590Srgrimes/*- 411590Srgrimes * Copyright (c) 1992, 1993 421590Srgrimes * The Regents of the University of California. All rights reserved. 431590Srgrimes * 441590Srgrimes * This code is derived from software contributed to Berkeley by 451590Srgrimes * Ralph Campbell and Rick Macklem. 4612811Sbde * 471590Srgrimes * Redistribution and use in source and binary forms, with or without 48111007Sphk * modification, are permitted provided that the following conditions 491590Srgrimes * are met: 5012805Speter * 1. Redistributions of source code must retain the above copyright 511590Srgrimes * notice, this list of conditions and the following disclaimer. 5212811Sbde * 2. Redistributions in binary form must reproduce the above copyright 5312811Sbde * notice, this list of conditions and the following disclaimer in the 5428149Scharnier * documentation and/or other materials provided with the distribution. 5528149Scharnier * 3. Neither the name of the University nor the names of its contributors 5659217Simp * may be used to endorse or promote products derived from this software 5774595Sache * without specific prior written permission. 581590Srgrimes * 59200462Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 6028149Scharnier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 6128149Scharnier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 621590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 6314953Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 641590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65202200Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6639230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 671590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 681590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6940060Sobrien * SUCH DAMAGE. 701590Srgrimes * 711590Srgrimes * @(#)if_le.c 8.2 (Berkeley) 11/16/93 721590Srgrimes */ 7374671Stmm 7474671Stmm#include <sys/cdefs.h> 7574671Stmm__FBSDID("$FreeBSD$"); 7674671Stmm 7774671Stmm#include <sys/param.h> 7874671Stmm#include <sys/bus.h> 7974671Stmm#include <sys/endian.h> 8074671Stmm#include <sys/lock.h> 8174671Stmm#include <sys/kernel.h> 82246033Szont#include <sys/mbuf.h> 8374671Stmm#include <sys/mutex.h> 8474671Stmm#include <sys/socket.h> 8574671Stmm#include <sys/sockio.h> 8674671Stmm 8774671Stmm#include <net/ethernet.h> 8874671Stmm#include <net/if.h> 8974671Stmm#include <net/if_arp.h> 9074671Stmm#include <net/if_dl.h> 9174671Stmm#include <net/if_media.h> 9274671Stmm#include <net/if_types.h> 9374671Stmm#include <net/if_vlan_var.h> 9474671Stmm 9574671Stmm#include <machine/bus.h> 9674671Stmm 9774671Stmm#include <dev/le/lancereg.h> 9874671Stmm#include <dev/le/lancevar.h> 9974671Stmm 10074671Stmmdevclass_t le_devclass; 10174671Stmm 10274671Stmmstatic void lance_start(struct ifnet *); 10374671Stmmstatic void lance_stop(struct lance_softc *); 10474671Stmmstatic void lance_init(void *); 10574671Stmmstatic void lance_watchdog(void *s); 10674671Stmmstatic int lance_mediachange(struct ifnet *); 10774671Stmmstatic void lance_mediastatus(struct ifnet *, struct ifmediareq *); 10874671Stmmstatic int lance_ioctl(struct ifnet *, u_long, caddr_t); 10974671Stmm 11074671Stmmint 111292817Saraujolance_config(struct lance_softc *sc, const char* name, int unit) 1121590Srgrimes{ 1131590Srgrimes struct ifnet *ifp; 1141590Srgrimes int i, nbuf; 1151590Srgrimes 116189626Sjhb if (LE_LOCK_INITIALIZED(sc) == 0) 11729842Speter return (ENXIO); 11869529Sgallatin 11969529Sgallatin ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 12074978Sgallatin if (ifp == NULL) 1211590Srgrimes return (ENOSPC); 122292817Saraujo 123292817Saraujo callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0); 1241590Srgrimes 12539230Sgibbs /* Initialize ifnet structure. */ 12639230Sgibbs ifp->if_softc = sc; 1271590Srgrimes if_initname(ifp, name, unit); 1281590Srgrimes ifp->if_start = lance_start; 1291590Srgrimes ifp->if_ioctl = lance_ioctl; 1301590Srgrimes ifp->if_init = lance_init; 1311590Srgrimes ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1321590Srgrimes#ifdef LANCE_REVC_BUG 13392922Simp ifp->if_flags &= ~IFF_MULTICAST; 13492922Simp#endif 13592922Simp ifp->if_baudrate = IF_Mbps(10); 13692922Simp IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 13792922Simp ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 13892922Simp IFQ_SET_READY(&ifp->if_snd); 13992922Simp 14092922Simp /* Initialize ifmedia structures. */ 14192922Simp ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus); 1421590Srgrimes if (sc->sc_supmedia != NULL) { 14336430Sjhay for (i = 0; i < sc->sc_nsupmedia; i++) 1441590Srgrimes ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL); 1451590Srgrimes ifmedia_set(&sc->sc_media, sc->sc_defaultmedia); 1461590Srgrimes } else { 1471590Srgrimes ifmedia_add(&sc->sc_media, 1481590Srgrimes IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL); 1491590Srgrimes ifmedia_set(&sc->sc_media, 1501590Srgrimes IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0)); 1511590Srgrimes } 1521590Srgrimes 153175387Sdelphij switch (sc->sc_memsize) { 1541590Srgrimes case 8192: 1551590Srgrimes sc->sc_nrbuf = 4; 1561590Srgrimes sc->sc_ntbuf = 1; 1571590Srgrimes break; 1581590Srgrimes case 16384: 1591590Srgrimes sc->sc_nrbuf = 8; 160175387Sdelphij sc->sc_ntbuf = 2; 1611590Srgrimes break; 1621590Srgrimes case 32768: 1631590Srgrimes sc->sc_nrbuf = 16; 1641590Srgrimes sc->sc_ntbuf = 4; 1651590Srgrimes break; 1661590Srgrimes case 65536: 1671590Srgrimes sc->sc_nrbuf = 32; 1681590Srgrimes sc->sc_ntbuf = 8; 1691590Srgrimes break; 1701590Srgrimes case 131072: 1711590Srgrimes sc->sc_nrbuf = 64; 172155663Sbde sc->sc_ntbuf = 16; 173155677Sbde break; 174155663Sbde case 262144: 1751590Srgrimes sc->sc_nrbuf = 128; 176158198Sbde sc->sc_ntbuf = 32; 177155677Sbde break; 178155666Sbde default: 179155666Sbde /* weird memory size; cope with it */ 180155677Sbde nbuf = sc->sc_memsize / LEBLEN; 1811590Srgrimes sc->sc_ntbuf = nbuf / 5; 182155666Sbde sc->sc_nrbuf = nbuf - sc->sc_ntbuf; 183155666Sbde } 184158198Sbde 185158198Sbde if_printf(ifp, "%d receive buffers, %d transmit buffers\n", 186158198Sbde sc->sc_nrbuf, sc->sc_ntbuf); 1871590Srgrimes 188158187Sbde /* Make sure the chip is stopped. */ 189158187Sbde LE_LOCK(sc); 190158187Sbde lance_stop(sc); 1911590Srgrimes LE_UNLOCK(sc); 192155663Sbde 1931590Srgrimes return (0); 1941590Srgrimes} 19539230Sgibbs 1961590Srgrimesvoid 1971590Srgrimeslance_attach(struct lance_softc *sc) 1981590Srgrimes{ 1991590Srgrimes struct ifnet *ifp = sc->sc_ifp; 200175387Sdelphij 2011590Srgrimes /* Attach the interface. */ 202158154Sbde ether_ifattach(ifp, sc->sc_enaddr); 2031590Srgrimes 20477583Stmm /* Claim 802.1q capability. */ 2051590Srgrimes ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 20683131Sken ifp->if_capabilities |= IFCAP_VLAN_MTU; 20739230Sgibbs ifp->if_capenable |= IFCAP_VLAN_MTU; 2081590Srgrimes} 2091590Srgrimes 21039230Sgibbsvoid 211287633Sdelphijlance_detach(struct lance_softc *sc) 212287633Sdelphij{ 213287633Sdelphij struct ifnet *ifp = sc->sc_ifp; 21439230Sgibbs 21539230Sgibbs LE_LOCK(sc); 21639230Sgibbs lance_stop(sc); 21739230Sgibbs LE_UNLOCK(sc); 2181590Srgrimes callout_drain(&sc->sc_wdog_ch); 21977583Stmm ether_ifdetach(ifp); 22077583Stmm if_free(ifp); 22177583Stmm} 22277583Stmm 22377583Stmmvoid 22477583Stmmlance_suspend(struct lance_softc *sc) 2251590Srgrimes{ 22677583Stmm 22774671Stmm LE_LOCK(sc); 228226396Sed lance_stop(sc); 22974671Stmm LE_UNLOCK(sc); 23074671Stmm} 2311590Srgrimes 2321590Srgrimesvoid 2331590Srgrimeslance_resume(struct lance_softc *sc) 2341590Srgrimes{ 2351590Srgrimes 2361590Srgrimes LE_LOCK(sc); 2371590Srgrimes if (sc->sc_ifp->if_flags & IFF_UP) 2381590Srgrimes lance_init_locked(sc); 2391590Srgrimes LE_UNLOCK(sc); 2401590Srgrimes} 241158154Sbde 242158154Sbdestatic void 243158154Sbdelance_start(struct ifnet *ifp) 244158154Sbde{ 245158154Sbde struct lance_softc *sc = ifp->if_softc; 246158154Sbde 247158154Sbde LE_LOCK(sc); 248158154Sbde (*sc->sc_start_locked)(sc); 249158154Sbde LE_UNLOCK(sc); 250158154Sbde} 251158154Sbde 252158154Sbdestatic void 253158154Sbdelance_stop(struct lance_softc *sc) 254209312Smav{ 255158154Sbde struct ifnet *ifp = sc->sc_ifp; 256158154Sbde 257158154Sbde LE_LOCK_ASSERT(sc, MA_OWNED); 258209312Smav 259210228Smav /* 260209312Smav * Mark the interface down and cancel the watchdog timer. 261209312Smav */ 262209312Smav ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 263158154Sbde callout_stop(&sc->sc_wdog_ch); 264158154Sbde sc->sc_wdog_timer = 0; 265158154Sbde 266210228Smav (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP); 267210228Smav} 268210228Smav 269210228Smavstatic void 270210228Smavlance_init(void *xsc) 271210228Smav{ 272210228Smav struct lance_softc *sc = (struct lance_softc *)xsc; 273210228Smav 274210228Smav LE_LOCK(sc); 2751590Srgrimes lance_init_locked(sc); 276158154Sbde LE_UNLOCK(sc); 2771590Srgrimes} 2781590Srgrimes 2791590Srgrimes/* 2801590Srgrimes * Initialization of interface; set up initialization block 2811590Srgrimes * and transmit/receive descriptor rings. 2821590Srgrimes */ 2831590Srgrimesvoid 284292817Saraujolance_init_locked(struct lance_softc *sc) 285292817Saraujo{ 28687715Smarkm struct ifnet *ifp = sc->sc_ifp; 2871590Srgrimes u_long a; 2881590Srgrimes int timo; 2891590Srgrimes 2901590Srgrimes LE_LOCK_ASSERT(sc, MA_OWNED); 2911590Srgrimes 292175387Sdelphij (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP); 2931590Srgrimes DELAY(100); 2941590Srgrimes 29514953Sache /* Newer LANCE chips have a reset register. */ 29674595Sache if (sc->sc_hwreset) 2971590Srgrimes (*sc->sc_hwreset)(sc); 29874595Sache 29974595Sache /* Set the correct byte swapping mode, etc. */ 30074595Sache (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3); 3011590Srgrimes 30214953Sache /* Set the current media. This may require the chip to be stopped. */ 30374595Sache if (sc->sc_mediachange) 30474595Sache (void)(*sc->sc_mediachange)(sc); 30587715Smarkm 3061590Srgrimes /* 3071590Srgrimes * Update our private copy of the Ethernet address. 3081590Srgrimes * We NEED the copy so we can ensure its alignment! 309175387Sdelphij */ 3101590Srgrimes memcpy(sc->sc_enaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN); 31187715Smarkm 3121590Srgrimes /* Set up LANCE init block. */ 3131590Srgrimes (*sc->sc_meminit)(sc); 314155677Sbde 315292817Saraujo /* Give LANCE the physical address of its init block. */ 316292817Saraujo a = sc->sc_addr + LE_INITADDR(sc); 31719687Sjkh (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff); 3181590Srgrimes (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16); 3191590Srgrimes 3201590Srgrimes /* Try to initialize the LANCE. */ 32119687Sjkh DELAY(100); 3221590Srgrimes (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT); 323155677Sbde 324155677Sbde /* Wait for initialization to finish. */ 3251590Srgrimes for (timo = 100000; timo; timo--) 3261590Srgrimes if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) 3271590Srgrimes break; 328155666Sbde 329155666Sbde if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) { 3301590Srgrimes /* Start the LANCE. */ 331246033Szont (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT); 332246033Szont ifp->if_drv_flags |= IFF_DRV_RUNNING; 333246033Szont ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 334246033Szont sc->sc_wdog_timer = 0; 335246033Szont callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc); 336246033Szont (*sc->sc_start_locked)(sc); 337246033Szont } else 338246033Szont if_printf(ifp, "controller failed to initialize\n"); 339246033Szont 340246033Szont if (sc->sc_hwinit) 341246033Szont (*sc->sc_hwinit)(sc); 342246033Szont} 343246033Szont 344246033Szont/* 345246033Szont * Routine to copy from mbuf chain to transmit buffer in 346246033Szont * network buffer memory. 347246033Szont */ 348246033Szontint 349246033Szontlance_put(struct lance_softc *sc, int boff, struct mbuf *m) 3501590Srgrimes{ 351155666Sbde struct mbuf *n; 3521590Srgrimes int len, tlen = 0; 3531590Srgrimes 3544930Sbde LE_LOCK_ASSERT(sc, MA_OWNED); 355155677Sbde 356155677Sbde for (; m; m = n) { 3571590Srgrimes len = m->m_len; 3581590Srgrimes if (len == 0) { 3591590Srgrimes n = m_free(m); 360158187Sbde m = NULL; 361158187Sbde continue; 362158187Sbde } 363158187Sbde (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len); 364158187Sbde boff += len; 365158187Sbde tlen += len; 3661590Srgrimes n = m_free(m); 367158187Sbde m = NULL; 36851421Sgreen } 36939230Sgibbs if (tlen < LEMINSIZE) { 37039230Sgibbs (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen); 37139230Sgibbs tlen = LEMINSIZE; 372155666Sbde } 37339230Sgibbs return (tlen); 37439230Sgibbs} 37539230Sgibbs 37639230Sgibbs/* 37739230Sgibbs * Pull data off an interface. 37839230Sgibbs * Len is length of data, with local net header stripped. 3791590Srgrimes * We copy the data into mbufs. When full cluster sized units are present 38039230Sgibbs * we copy into clusters. 38139230Sgibbs */ 38239230Sgibbsstruct mbuf * 38339230Sgibbslance_get(struct lance_softc *sc, int boff, int totlen) 38439230Sgibbs{ 38539230Sgibbs struct ifnet *ifp = sc->sc_ifp; 38639230Sgibbs struct mbuf *m, *m0, *newm; 3871590Srgrimes caddr_t newdata; 3881590Srgrimes int len; 38943756Sdillon 3901590Srgrimes if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) { 3911590Srgrimes#ifdef LEDEBUG 3921590Srgrimes if_printf(ifp, "invalid packet size %d; dropping\n", totlen); 393155666Sbde#endif 3941590Srgrimes return (NULL); 3951590Srgrimes } 3961590Srgrimes 3971590Srgrimes MGETHDR(m0, M_DONTWAIT, MT_DATA); 39839230Sgibbs if (m0 == NULL) 3991590Srgrimes return (NULL); 4001590Srgrimes m0->m_pkthdr.rcvif = ifp; 4011590Srgrimes m0->m_pkthdr.len = totlen; 4021590Srgrimes len = MHLEN; 403155665Sbde m = m0; 4041590Srgrimes 405155665Sbde while (totlen > 0) { 406155665Sbde if (totlen >= MINCLSIZE) { 4071590Srgrimes MCLGET(m, M_DONTWAIT); 4081590Srgrimes if ((m->m_flags & M_EXT) == 0) 4094930Sbde goto bad; 4104930Sbde len = MCLBYTES; 4114930Sbde } 4121590Srgrimes 4131590Srgrimes if (m == m0) { 414175387Sdelphij newdata = (caddr_t) 4151590Srgrimes ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN; 4161590Srgrimes len -= newdata - m->m_data; 4171590Srgrimes m->m_data = newdata; 418158152Sbde } 4191590Srgrimes 4201590Srgrimes m->m_len = len = min(totlen, len); 4211590Srgrimes (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len); 4221590Srgrimes boff += len; 4231590Srgrimes 42439230Sgibbs totlen -= len; 4251590Srgrimes if (totlen > 0) { 4261590Srgrimes MGET(newm, M_DONTWAIT, MT_DATA); 4271590Srgrimes if (newm == 0) 4281590Srgrimes goto bad; 4291590Srgrimes len = MLEN; 4301590Srgrimes m = m->m_next = newm; 4311590Srgrimes } 4321590Srgrimes } 4331590Srgrimes 4341590Srgrimes return (m0); 4351590Srgrimes 4361590Srgrimes bad: 4371590Srgrimes m_freem(m0); 4381590Srgrimes return (NULL); 4391590Srgrimes} 4401590Srgrimes 4411590Srgrimesstatic void 44236430Sjhaylance_watchdog(void *xsc) 4431590Srgrimes{ 4441590Srgrimes struct lance_softc *sc = (struct lance_softc *)xsc; 4451590Srgrimes struct ifnet *ifp = sc->sc_ifp; 4461590Srgrimes 447212313Smav LE_LOCK_ASSERT(sc, MA_OWNED); 448212313Smav 449212313Smav if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) { 4501590Srgrimes callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc); 4511590Srgrimes return; 4521590Srgrimes } 4531590Srgrimes 454155666Sbde if_printf(ifp, "device timeout\n"); 455158152Sbde ++ifp->if_oerrors; 4561590Srgrimes lance_init_locked(sc); 457155666Sbde} 4581590Srgrimes 459155666Sbdestatic int 4601590Srgrimeslance_mediachange(struct ifnet *ifp) 4617138Sphk{ 4621590Srgrimes struct lance_softc *sc = ifp->if_softc; 4637012Sphk 4641590Srgrimes if (sc->sc_mediachange) { 4651590Srgrimes /* 4661590Srgrimes * For setting the port in LE_CSR15 the PCnet chips must 4671590Srgrimes * be powered down or stopped and unlike documented may 4681590Srgrimes * not take effect without an initialization. So don't 46987715Smarkm * invoke (*sc_mediachange) directly here but go through 47087715Smarkm * lance_init_locked(). 4711590Srgrimes */ 4721590Srgrimes LE_LOCK(sc); 4731590Srgrimes lance_stop(sc); 47487715Smarkm lance_init_locked(sc); 4751590Srgrimes if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 4761590Srgrimes (*sc->sc_start_locked)(sc); 4771590Srgrimes LE_UNLOCK(sc); 47887715Smarkm } 4791590Srgrimes return (0); 4801590Srgrimes} 481155677Sbde 482155677Sbdestatic void 483155677Sbdelance_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 484155677Sbde{ 485155677Sbde struct lance_softc *sc = ifp->if_softc; 486142175Sps 487292817Saraujo LE_LOCK(sc); 488292817Saraujo if (!(ifp->if_flags & IFF_UP)) { 489292817Saraujo LE_UNLOCK(sc); 490292817Saraujo return; 491292817Saraujo } 492164718Sru 493164718Sru ifmr->ifm_status = IFM_AVALID; 494164718Sru if (sc->sc_flags & LE_CARRIER) 495164718Sru ifmr->ifm_status |= IFM_ACTIVE; 496164718Sru 497164718Sru if (sc->sc_mediastatus) 498164718Sru (*sc->sc_mediastatus)(sc, ifmr); 499164718Sru LE_UNLOCK(sc); 500164718Sru} 501164718Sru 502164718Sru/* 503164718Sru * Process an ioctl request. 504164718Sru */ 505164718Srustatic int 506246033Szontlance_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 507246033Szont{ 508246033Szont struct lance_softc *sc = ifp->if_softc; 509246033Szont struct ifreq *ifr = (struct ifreq *)data; 510158196Sbde int error = 0; 511246033Szont 512246033Szont switch (cmd) { 513246033Szont case SIOCSIFFLAGS: 514246033Szont LE_LOCK(sc); 515246033Szont if (ifp->if_flags & IFF_PROMISC) { 516246033Szont if (!(sc->sc_flags & LE_PROMISC)) { 517246033Szont sc->sc_flags |= LE_PROMISC; 518246033Szont lance_init_locked(sc); 519246033Szont } 520246033Szont } else if (sc->sc_flags & LE_PROMISC) { 521246033Szont sc->sc_flags &= ~LE_PROMISC; 522246033Szont lance_init_locked(sc); 523246033Szont } 524246033Szont 525246033Szont if ((ifp->if_flags & IFF_ALLMULTI) && 526155677Sbde !(sc->sc_flags & LE_ALLMULTI)) { 527155677Sbde sc->sc_flags |= LE_ALLMULTI; 528155677Sbde lance_init_locked(sc); 529155677Sbde } else if (!(ifp->if_flags & IFF_ALLMULTI) && 530155677Sbde (sc->sc_flags & LE_ALLMULTI)) { 531155677Sbde sc->sc_flags &= ~LE_ALLMULTI; 532155677Sbde lance_init_locked(sc); 533155677Sbde } 534155666Sbde 535155666Sbde if (!(ifp->if_flags & IFF_UP) && 536155666Sbde ifp->if_drv_flags & IFF_DRV_RUNNING) { 537155666Sbde /* 538155666Sbde * If interface is marked down and it is running, then 539155666Sbde * stop it. 54087715Smarkm */ 54139230Sgibbs lance_stop(sc); 54239230Sgibbs } else if (ifp->if_flags & IFF_UP && 54339230Sgibbs !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 54487715Smarkm /* 54539230Sgibbs * If interface is marked up and it is stopped, then 54639230Sgibbs * start it. 54787715Smarkm */ 54839230Sgibbs lance_init_locked(sc); 54939230Sgibbs } 55087715Smarkm#ifdef LEDEBUG 55139230Sgibbs if (ifp->if_flags & IFF_DEBUG) 55239230Sgibbs sc->sc_flags |= LE_DEBUG; 5531590Srgrimes else 554158187Sbde sc->sc_flags &= ~LE_DEBUG; 555158187Sbde#endif 556158187Sbde LE_UNLOCK(sc); 557158187Sbde break; 558158187Sbde 5597012Sphk case SIOCADDMULTI: 560158187Sbde case SIOCDELMULTI: 5611590Srgrimes /* 5628874Srgrimes * Multicast list has changed; set the hardware filter 5637012Sphk * accordingly. 564158187Sbde */ 565158187Sbde LE_LOCK(sc); 5661590Srgrimes if (ifp->if_drv_flags & IFF_DRV_RUNNING) 567158187Sbde lance_init_locked(sc); 5681590Srgrimes LE_UNLOCK(sc); 5691590Srgrimes break; 5701590Srgrimes 5711590Srgrimes case SIOCGIFMEDIA: 572175387Sdelphij case SIOCSIFMEDIA: 5731590Srgrimes error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 57439230Sgibbs break; 5751590Srgrimes 5761590Srgrimes default: 57739230Sgibbs error = ether_ioctl(ifp, cmd, data); 5781590Srgrimes break; 57983131Sken } 58039230Sgibbs 58139230Sgibbs return (error); 58239230Sgibbs} 58339230Sgibbs 58439230Sgibbs/* 58539230Sgibbs * Set up the logical address filter. 58639230Sgibbs */ 58739230Sgibbsvoid 58839230Sgibbslance_setladrf(struct lance_softc *sc, uint16_t *af) 58939230Sgibbs{ 59039230Sgibbs struct ifnet *ifp = sc->sc_ifp; 59139230Sgibbs struct ifmultiaddr *ifma; 59239230Sgibbs uint32_t crc; 5931590Srgrimes 59439230Sgibbs /* 5951590Srgrimes * Set up multicast address filter by passing all multicast addresses 5961590Srgrimes * through a crc generator, and then using the high order 6 bits as an 5971590Srgrimes * index into the 64 bit logical address filter. The high order bit 5981590Srgrimes * selects the word, while the rest of the bits select the bit within 5991590Srgrimes * the word. 6001590Srgrimes */ 6011590Srgrimes 6021590Srgrimes if (ifp->if_flags & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) { 6031590Srgrimes af[0] = af[1] = af[2] = af[3] = 0xffff; 6041590Srgrimes return; 6051590Srgrimes } 60639230Sgibbs 60739230Sgibbs af[0] = af[1] = af[2] = af[3] = 0x0000; 60887715Smarkm if_maddr_rlock(ifp); 60983131Sken TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 61039230Sgibbs if (ifma->ifma_addr->sa_family != AF_LINK) 61139230Sgibbs continue; 61239230Sgibbs 61339230Sgibbs crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) 61439230Sgibbs ifma->ifma_addr), ETHER_ADDR_LEN); 61539230Sgibbs 61639230Sgibbs /* Just want the 6 most significant bits. */ 61739230Sgibbs crc >>= 26; 61839230Sgibbs 61939230Sgibbs /* Set the corresponding bit in the filter. */ 62039230Sgibbs af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf)); 62139230Sgibbs } 62239230Sgibbs if_maddr_runlock(ifp); 62339230Sgibbs} 62439230Sgibbs 6251590Srgrimes/* 62639230Sgibbs * Routines for accessing the transmit and receive buffers. 62739230Sgibbs * The various CPU and adapter configurations supported by this 62839230Sgibbs * driver require three different access methods for buffers 62939230Sgibbs * and descriptors: 63039230Sgibbs * (1) contig (contiguous data; no padding), 63139230Sgibbs * (2) gap2 (two bytes of data followed by two bytes of padding), 6321590Srgrimes * (3) gap16 (16 bytes of data followed by 16 bytes of padding). 6331590Srgrimes */ 6341590Srgrimes 6351590Srgrimes/* 636175387Sdelphij * contig: contiguous data with no padding. 6371590Srgrimes * 63887715Smarkm * Buffers may have any alignment. 639200167Sed */ 6401590Srgrimes 641200167Sedvoid 642200167Sedlance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len) 643200167Sed{ 6441590Srgrimes volatile caddr_t buf = sc->sc_mem; 645200167Sed 6461590Srgrimes /* 6471590Srgrimes * Just call memcpy() to do the work. 6481590Srgrimes */ 6491590Srgrimes memcpy(buf + boff, from, len); 6501590Srgrimes} 651175387Sdelphij 6521590Srgrimesvoid 65387715Smarkmlance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len) 65487715Smarkm{ 6551590Srgrimes volatile caddr_t buf = sc->sc_mem; 65687715Smarkm 6571590Srgrimes /* 65887715Smarkm * Just call memcpy() to do the work. 65987715Smarkm */ 66087715Smarkm memcpy(to, buf + boff, len); 66187715Smarkm} 6621590Srgrimes 6631590Srgrimesvoid 6641590Srgrimeslance_zerobuf_contig(struct lance_softc *sc, int boff, int len) 665175387Sdelphij{ 6661590Srgrimes volatile caddr_t buf = sc->sc_mem; 667155668Sbde 6681590Srgrimes /* 6691590Srgrimes * Just let memset() do the work 67087715Smarkm */ 671158168Sbde memset(buf + boff, 0, len); 672158168Sbde} 673158168Sbde 674158168Sbde#if 0 675158168Sbde/* 6761590Srgrimes * Examples only; duplicate these and tweak (if necessary) in 6771590Srgrimes * machine-specific front-ends. 6781590Srgrimes */ 6791590Srgrimes 6801590Srgrimes/* 681155668Sbde * gap2: two bytes of data followed by two bytes of pad. 682155668Sbde * 683155668Sbde * Buffers must be 4-byte aligned. The code doesn't worry about 684155668Sbde * doing an extra byte. 685155668Sbde */ 686155668Sbde 687155668Sbdestatic void 688155668Sbdelance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len) 689155668Sbde{ 690155668Sbde volatile caddr_t buf = sc->sc_mem; 6911590Srgrimes caddr_t from = fromv; 6921590Srgrimes volatile uint16_t *bptr; 6931590Srgrimes 6941590Srgrimes if (boff & 0x1) { 695175387Sdelphij /* Handle unaligned first byte. */ 6961590Srgrimes bptr = ((volatile uint16_t *)buf) + (boff - 1); 697155668Sbde *bptr = (*from++ << 8) | (*bptr & 0xff); 6981590Srgrimes bptr += 2; 6991590Srgrimes len--; 70087715Smarkm } else 701158168Sbde bptr = ((volatile uint16_t *)buf) + boff; 702158168Sbde while (len > 1) { 703158168Sbde *bptr = (from[1] << 8) | (from[0] & 0xff); 704158168Sbde bptr += 2; 705158168Sbde from += 2; 7061590Srgrimes len -= 2; 7071590Srgrimes } 7081590Srgrimes if (len == 1) 7091590Srgrimes *bptr = (uint16_t)*from; 7101590Srgrimes} 711155668Sbde 712155668Sbdestatic void 713155668Sbdelance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len) 714248647Smav{ 715248647Smav volatile caddr_t buf = sc->sc_mem; 716248647Smav caddr_t to = tov; 717248647Smav volatile uint16_t *bptr; 718155668Sbde uint16_t tmp; 7191590Srgrimes 7201590Srgrimes if (boff & 0x1) { 7211590Srgrimes /* Handle unaligned first byte. */ 7221590Srgrimes bptr = ((volatile uint16_t *)buf) + (boff - 1); 7231590Srgrimes *to++ = (*bptr >> 8) & 0xff; 7241590Srgrimes bptr += 2; 7251590Srgrimes len--; 7261590Srgrimes } else 727175387Sdelphij bptr = ((volatile uint16_t *)buf) + boff; 72839230Sgibbs while (len > 1) { 729155668Sbde tmp = *bptr; 73039230Sgibbs *to++ = tmp & 0xff; 73139230Sgibbs *to++ = (tmp >> 8) & 0xff; 73287715Smarkm bptr += 2; 733158168Sbde len -= 2; 734158168Sbde } 735158168Sbde if (len == 1) 736158168Sbde *to = *bptr & 0xff; 737158168Sbde} 73839230Sgibbs 73939230Sgibbsstatic void 74039230Sgibbslance_zerobuf_gap2(struct lance_softc *sc, int boff, int len) 74139230Sgibbs{ 74239230Sgibbs volatile caddr_t buf = sc->sc_mem; 743155668Sbde volatile uint16_t *bptr; 744155668Sbde 745155668Sbde if ((unsigned)boff & 0x1) { 746248647Smav bptr = ((volatile uint16_t *)buf) + (boff - 1); 747248647Smav *bptr &= 0xff; 748248647Smav bptr += 2; 749248647Smav len--; 750155668Sbde } else 75139230Sgibbs bptr = ((volatile uint16_t *)buf) + boff; 75239230Sgibbs while (len > 0) { 75339230Sgibbs *bptr = 0; 75439230Sgibbs bptr += 2; 75539230Sgibbs len -= 2; 75639230Sgibbs } 75739230Sgibbs} 75839230Sgibbs 759175387Sdelphij/* 7601590Srgrimes * gap16: 16 bytes of data followed by 16 bytes of pad. 76139230Sgibbs * 76274671Stmm * Buffers must be 32-byte aligned. 76374671Stmm */ 7641590Srgrimes 76587715Smarkmstatic void 76674671Stmmlance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len) 76787715Smarkm{ 76887715Smarkm volatile caddr_t buf = sc->sc_mem; 76987715Smarkm caddr_t bptr, from = fromv; 77087715Smarkm int xfer; 77187715Smarkm 77287715Smarkm bptr = buf + ((boff << 1) & ~0x1f); 773246033Szont boff &= 0xf; 77487715Smarkm xfer = min(len, 16 - boff); 77587715Smarkm while (len > 0) { 77687715Smarkm memcpy(bptr + boff, from, xfer); 77787715Smarkm from += xfer; 77887715Smarkm bptr += 32; 77987715Smarkm boff = 0; 78087715Smarkm len -= xfer; 78187715Smarkm xfer = min(len, 16); 78287715Smarkm } 78387715Smarkm} 78487715Smarkm 78587715Smarkmstatic void 78687715Smarkmlance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len) 78787715Smarkm{ 78887715Smarkm volatile caddr_t buf = sc->sc_mem; 78987715Smarkm caddr_t bptr, to = tov; 79087715Smarkm int xfer; 79187715Smarkm 79287715Smarkm bptr = buf + ((boff << 1) & ~0x1f); 79387715Smarkm boff &= 0xf; 79487715Smarkm xfer = min(len, 16 - boff); 79587715Smarkm while (len > 0) { 79687715Smarkm memcpy(to, bptr + boff, xfer); 79787715Smarkm to += xfer; 79887715Smarkm bptr += 32; 79987715Smarkm boff = 0; 80097970Sdes len -= xfer; 80197970Sdes xfer = min(len, 16); 80287715Smarkm } 80387715Smarkm} 804292817Saraujo 80587715Smarkmstatic void 80669143Srwatsonlance_zerobuf_gap16(struct lance_softc *sc, int boff, int len) 80787715Smarkm{ 8081590Srgrimes volatile caddr_t buf = sc->sc_mem; 809109097Sdillon caddr_t bptr; 81087715Smarkm int xfer; 8111590Srgrimes 81287715Smarkm bptr = buf + ((boff << 1) & ~0x1f); 8131590Srgrimes boff &= 0xf; 81436430Sjhay xfer = min(len, 16 - boff); 81569143Srwatson while (len > 0) { 81669143Srwatson memset(bptr + boff, 0, xfer); 81736430Sjhay bptr += 32; 81839230Sgibbs boff = 0; 81939230Sgibbs len -= xfer; 82039230Sgibbs xfer = min(len, 16); 82139230Sgibbs } 82239230Sgibbs} 823112288Sphk#endif /* Example only */ 82483131Sken