1139749Simp/*- 25436Sdg * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca> 35436Sdg * All rights reserved. 45436Sdg * 5963Sats * Redistribution and use in source and binary forms, with or without 65436Sdg * modification, are permitted provided that the following conditions 75436Sdg * are met: 85436Sdg * 1. Redistributions of source code must retain the above copyright 95436Sdg * notice, this list of conditions and the following disclaimer. 105436Sdg * 2. Redistributions in binary form must reproduce the above copyright 115436Sdg * notice, this list of conditions and the following disclaimer in the 125436Sdg * documentation and/or other materials provided with the distribution. 135436Sdg * 3. All advertising materials mentioning features or use of this software 145436Sdg * must display the following acknowledgement: 155436Sdg * This product includes software developed by Herb Peyerl. 165436Sdg * 4. The name of Herb Peyerl may not be used to endorse or promote products 175436Sdg * derived from this software without specific prior written permission. 185436Sdg * 195436Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 205436Sdg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 215436Sdg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 225436Sdg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 235436Sdg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 245436Sdg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255436Sdg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265436Sdg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275436Sdg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 285436Sdg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29963Sats */ 301444Sats 31119418Sobrien#include <sys/cdefs.h> 32119418Sobrien__FBSDID("$FreeBSD$"); 33119418Sobrien 345863Sdg/* 355863Sdg * Modified from the FreeBSD 1.1.5.1 version by: 368876Srgrimes * Andres Vega Garcia 375863Sdg * INRIA - Sophia Antipolis, France 385863Sdg * avega@sophia.inria.fr 395863Sdg */ 405863Sdg 417510Sjkh/* 427510Sjkh * Promiscuous mode added and interrupt logic slightly changed 437510Sjkh * to reduce the number of adapter failures. Transceiver select 447510Sjkh * logic changed to use value from EEPROM. Autoconfiguration 457510Sjkh * features added. 467510Sjkh * Done by: 477510Sjkh * Serge Babkin 487510Sjkh * Chelindbank (Chelyabinsk, Russia) 497510Sjkh * babkin@hq.icb.chel.su 507510Sjkh */ 517510Sjkh 5216374Snate/* 5316374Snate * Pccard support for 3C589 by: 5416374Snate * HAMADA Naoki 5516374Snate * nao@tom-yam.or.jp 5616374Snate */ 5716374Snate 5852549Smdodd/* 5952549Smdodd * MAINTAINER: Matthew N. Dodd <winter@jurai.net> 6052549Smdodd * <mdodd@FreeBSD.org> 6152549Smdodd */ 621017Snate 631444Sats#include <sys/param.h> 641444Sats#include <sys/systm.h> 65199559Sjhb#include <sys/kernel.h> 661444Sats#include <sys/mbuf.h> 671444Sats#include <sys/socket.h> 6824204Sbde#include <sys/sockio.h> 6952472Simp#include <sys/bus.h> 70963Sats 7152549Smdodd#include <machine/bus.h> 7252549Smdodd#include <machine/resource.h> 73117700Smarkm#include <sys/rman.h> 7452549Smdodd 7552549Smdodd#include <net/if.h> 76152315Sru#include <net/if_dl.h> 77117700Smarkm#include <net/if_media.h> 78147256Sbrooks#include <net/if_types.h> 7950026Smdodd#include <net/ethernet.h> 8052549Smdodd#include <net/bpf.h> 8152549Smdodd 8251673Smdodd#include <dev/ep/if_epreg.h> 8351673Smdodd#include <dev/ep/if_epvar.h> 84963Sats 8514259Sgibbs/* Exported variables */ 8652472Simpdevclass_t ep_devclass; 8712854Sbde 88117700Smarkmstatic int ep_media2if_media[] = 89117700Smarkm{IFM_10_T, IFM_10_5, IFM_NONE, IFM_10_2, IFM_NONE}; 90963Sats 9152549Smdodd/* if functions */ 92121492Simpstatic void epinit(void *); 93121492Simpstatic int epioctl(struct ifnet *, u_long, caddr_t); 94121492Simpstatic void epstart(struct ifnet *); 954435Sgibbs 96199559Sjhbstatic void ep_intr_locked(struct ep_softc *); 97121515Simpstatic void epstart_locked(struct ifnet *); 98121515Simpstatic void epinit_locked(struct ep_softc *); 99199559Sjhbstatic void eptick(void *); 100199559Sjhbstatic void epwatchdog(struct ep_softc *); 101121492Simp 10252549Smdodd/* if_media functions */ 103117700Smarkmstatic int ep_ifmedia_upd(struct ifnet *); 104117700Smarkmstatic void ep_ifmedia_sts(struct ifnet *, struct ifmediareq *); 10552549Smdodd 106117700Smarkmstatic void epstop(struct ep_softc *); 107117700Smarkmstatic void epread(struct ep_softc *); 108117700Smarkmstatic int eeprom_rdy(struct ep_softc *); 10952549Smdodd 11052549Smdodd#define EP_FTST(sc, f) (sc->stat & (f)) 11152549Smdodd#define EP_FSET(sc, f) (sc->stat |= (f)) 11252549Smdodd#define EP_FRST(sc, f) (sc->stat &= ~(f)) 11352549Smdodd 11416374Snatestatic int 115117700Smarkmeeprom_rdy(struct ep_softc *sc) 1164435Sgibbs{ 117117700Smarkm int i; 1182478Sats 119121206Simp for (i = 0; is_eeprom_busy(sc) && i < MAX_EEPROMBUSY; i++) 120117700Smarkm DELAY(100); 121117700Smarkm 122117700Smarkm if (i >= MAX_EEPROMBUSY) { 123147715Simp device_printf(sc->dev, "eeprom failed to come ready.\n"); 124121903Simp return (ENXIO); 125117700Smarkm } 126117700Smarkm 127117700Smarkm return (0); 1284435Sgibbs} 1292478Sats 1304435Sgibbs/* 1314435Sgibbs * get_e: gets a 16 bits word from the EEPROM. we must have set the window 1324435Sgibbs * before 1334435Sgibbs */ 134112822Smdoddint 135147607Simpep_get_e(struct ep_softc *sc, uint16_t offset, uint16_t *result) 1364435Sgibbs{ 137112822Smdodd 138112822Smdodd if (eeprom_rdy(sc)) 139112822Smdodd return (ENXIO); 140117700Smarkm 141121492Simp CSR_WRITE_2(sc, EP_W0_EEPROM_COMMAND, 142117700Smarkm (EEPROM_CMD_RD << sc->epb.cmd_off) | offset); 143117700Smarkm 144112822Smdodd if (eeprom_rdy(sc)) 145112822Smdodd return (ENXIO); 146117700Smarkm 147121492Simp (*result) = CSR_READ_2(sc, EP_W0_EEPROM_DATA); 148112822Smdodd 14956017Smdodd return (0); 1504435Sgibbs} 1512478Sats 152147715Simpstatic int 153117700Smarkmep_get_macaddr(struct ep_softc *sc, u_char *addr) 15414259Sgibbs{ 155117700Smarkm int i; 156140523Simp uint16_t result; 157117700Smarkm int error; 158140523Simp uint16_t *macaddr; 15914259Sgibbs 160140523Simp macaddr = (uint16_t *) addr; 161112822Smdodd 162121588Simp GO_WINDOW(sc, 0); 163117700Smarkm for (i = EEPROM_NODE_ADDR_0; i <= EEPROM_NODE_ADDR_2; i++) { 164147607Simp error = ep_get_e(sc, i, &result); 165112822Smdodd if (error) 166112822Smdodd return (error); 167112822Smdodd macaddr[i] = htons(result); 168117700Smarkm } 169112822Smdodd return (0); 17052549Smdodd} 17114259Sgibbs 17252549Smdoddint 17352549Smdoddep_alloc(device_t dev) 17452549Smdodd{ 175117700Smarkm struct ep_softc *sc = device_get_softc(dev); 176117700Smarkm int rid; 177117700Smarkm int error = 0; 178140523Simp uint16_t result; 17952549Smdodd 180117700Smarkm rid = 0; 181127135Snjl sc->iobase = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, 182127135Snjl RF_ACTIVE); 183117700Smarkm if (!sc->iobase) { 184117700Smarkm device_printf(dev, "No I/O space?!\n"); 18552549Smdodd error = ENXIO; 186117700Smarkm goto bad; 187117700Smarkm } 188117700Smarkm rid = 0; 189127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 190117700Smarkm if (!sc->irq) { 191117700Smarkm device_printf(dev, "No irq?!\n"); 19252549Smdodd error = ENXIO; 193117700Smarkm goto bad; 194117700Smarkm } 195117700Smarkm sc->dev = dev; 196117700Smarkm sc->stat = 0; /* 16 bit access */ 19752549Smdodd 198121206Simp sc->bst = rman_get_bustag(sc->iobase); 199121206Simp sc->bsh = rman_get_bushandle(sc->iobase); 20052549Smdodd 20152549Smdodd sc->ep_connectors = 0; 20252549Smdodd sc->ep_connector = 0; 20352549Smdodd 204121588Simp GO_WINDOW(sc, 0); 20552549Smdodd 206147607Simp error = ep_get_e(sc, EEPROM_PROD_ID, &result); 207112822Smdodd if (error) 208112822Smdodd goto bad; 209112822Smdodd sc->epb.prod_id = result; 210112822Smdodd 211147607Simp error = ep_get_e(sc, EEPROM_RESOURCE_CFG, &result); 212112822Smdodd if (error) 213112822Smdodd goto bad; 214112822Smdodd sc->epb.res_cfg = result; 215112822Smdodd 21652549Smdoddbad: 217121903Simp if (error != 0) 218121903Simp ep_free(dev); 21952549Smdodd return (error); 22014259Sgibbs} 22114259Sgibbs 22214259Sgibbsvoid 223117700Smarkmep_get_media(struct ep_softc *sc) 22414259Sgibbs{ 225140523Simp uint16_t config; 22652549Smdodd 227121588Simp GO_WINDOW(sc, 0); 228121492Simp config = CSR_READ_2(sc, EP_W0_CONFIG_CTRL); 229117700Smarkm if (config & IS_AUI) 230117700Smarkm sc->ep_connectors |= AUI; 231117700Smarkm if (config & IS_BNC) 232117700Smarkm sc->ep_connectors |= BNC; 233117700Smarkm if (config & IS_UTP) 234117700Smarkm sc->ep_connectors |= UTP; 235117700Smarkm 236117700Smarkm if (!(sc->ep_connectors & 7)) 23752549Smdodd if (bootverbose) 238117700Smarkm device_printf(sc->dev, "no connectors!\n"); 23952549Smdodd 24052549Smdodd /* 24152549Smdodd * This works for most of the cards so we'll do it here. 24252549Smdodd * The cards that require something different can override 24352549Smdodd * this later on. 24452549Smdodd */ 245121492Simp sc->ep_connector = CSR_READ_2(sc, EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS; 24614259Sgibbs} 24714259Sgibbs 24852549Smdoddvoid 24952549Smdoddep_free(device_t dev) 25052549Smdodd{ 251117700Smarkm struct ep_softc *sc = device_get_softc(dev); 25252549Smdodd 253112829Smdodd if (sc->ep_intrhand) 254112829Smdodd bus_teardown_intr(dev, sc->irq, sc->ep_intrhand); 25552549Smdodd if (sc->iobase) 25652549Smdodd bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase); 25752549Smdodd if (sc->irq) 25852549Smdodd bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 259148581Simp sc->ep_intrhand = 0; 260148581Simp sc->iobase = 0; 261148581Simp sc->irq = 0; 262117700Smarkm} 26352549Smdodd 264147715Simpstatic void 265147715Simpep_setup_station(struct ep_softc *sc, u_char *enaddr) 266147715Simp{ 267147715Simp int i; 268147715Simp 269147715Simp /* 270147715Simp * Setup the station address 271147715Simp */ 272147715Simp GO_WINDOW(sc, 2); 273147715Simp for (i = 0; i < ETHER_ADDR_LEN; i++) 274147715Simp CSR_WRITE_1(sc, EP_W2_ADDR_0 + i, enaddr[i]); 275147715Simp} 276147715Simp 2774435Sgibbsint 278117700Smarkmep_attach(struct ep_softc *sc) 27914259Sgibbs{ 280117700Smarkm struct ifnet *ifp = NULL; 281117700Smarkm struct ifmedia *ifm = NULL; 282117700Smarkm int error; 28314259Sgibbs 28452549Smdodd sc->gone = 0; 285121515Simp EP_LOCK_INIT(sc); 286147715Simp if (! (sc->stat & F_ENADDR_SKIP)) { 287147715Simp error = ep_get_macaddr(sc, sc->eaddr); 288147715Simp if (error) { 289147715Simp device_printf(sc->dev, "Unable to get MAC address!\n"); 290148164Simp EP_LOCK_DESTROY(sc); 291147715Simp return (ENXIO); 292147715Simp } 293112822Smdodd } 294147715Simp ep_setup_station(sc, sc->eaddr); 295147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ETHER); 296147256Sbrooks if (ifp == NULL) { 297147717Simp device_printf(sc->dev, "if_alloc() failed\n"); 298148164Simp EP_LOCK_DESTROY(sc); 299147256Sbrooks return (ENOSPC); 300147256Sbrooks } 30114259Sgibbs 30252549Smdodd ifp->if_softc = sc; 303121816Sbrooks if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); 30452549Smdodd ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 305121492Simp ifp->if_start = epstart; 306121492Simp ifp->if_ioctl = epioctl; 307121492Simp ifp->if_init = epinit; 308207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 309207554Ssobomax ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; 310164810Smlaier IFQ_SET_READY(&ifp->if_snd); 3111017Snate 312199559Sjhb callout_init_mtx(&sc->watchdog_timer, &sc->sc_mtx, 0); 31352549Smdodd if (!sc->epb.mii_trans) { 31452549Smdodd ifmedia_init(&sc->ifmedia, 0, ep_ifmedia_upd, ep_ifmedia_sts); 3151017Snate 31652549Smdodd if (sc->ep_connectors & AUI) 317119572Smarkm ifmedia_add(&sc->ifmedia, 318119572Smarkm IFM_ETHER | IFM_10_5, 0, NULL); 31952549Smdodd if (sc->ep_connectors & UTP) 320119572Smarkm ifmedia_add(&sc->ifmedia, 321119572Smarkm IFM_ETHER | IFM_10_T, 0, NULL); 32252549Smdodd if (sc->ep_connectors & BNC) 323119572Smarkm ifmedia_add(&sc->ifmedia, 324119572Smarkm IFM_ETHER | IFM_10_2, 0, NULL); 32552549Smdodd if (!sc->ep_connectors) 326119572Smarkm ifmedia_add(&sc->ifmedia, 327119572Smarkm IFM_ETHER | IFM_NONE, 0, NULL); 328117700Smarkm 329119572Smarkm ifmedia_set(&sc->ifmedia, 330119572Smarkm IFM_ETHER | ep_media2if_media[sc->ep_connector]); 331117700Smarkm 33252549Smdodd ifm = &sc->ifmedia; 33352549Smdodd ifm->ifm_media = ifm->ifm_cur->ifm_media; 33452549Smdodd ep_ifmedia_upd(ifp); 33552549Smdodd } 336147715Simp ether_ifattach(ifp, sc->eaddr); 33752549Smdodd 3384435Sgibbs#ifdef EP_LOCAL_STATS 33952549Smdodd sc->rx_no_first = sc->rx_no_mbuf = sc->rx_bpf_disc = 340117700Smarkm sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0; 3414435Sgibbs#endif 34252549Smdodd EP_FSET(sc, F_RX_FIRST); 34352549Smdodd sc->top = sc->mcur = 0; 3444435Sgibbs 34557981Smdodd epstop(sc); 34657981Smdodd 347117700Smarkm return (0); 348963Sats} 349963Sats 350112829Smdoddint 351112829Smdoddep_detach(device_t dev) 352112829Smdodd{ 353112829Smdodd struct ep_softc *sc; 354112829Smdodd struct ifnet *ifp; 355112829Smdodd 356112829Smdodd sc = device_get_softc(dev); 357150395Simp ifp = sc->ifp; 358121515Simp EP_ASSERT_UNLOCKED(sc); 359150395Simp EP_LOCK(sc); 360119125Scognet if (bus_child_present(dev)) 361119125Scognet epstop(sc); 362150395Simp sc->gone = 1; 363148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 364150395Simp EP_UNLOCK(sc); 365112829Smdodd ether_ifdetach(ifp); 366199559Sjhb callout_drain(&sc->watchdog_timer); 367150395Simp ep_free(dev); 368112829Smdodd 369150306Simp if_free(ifp); 370148164Simp EP_LOCK_DESTROY(sc); 371112829Smdodd 372112829Smdodd return (0); 373112829Smdodd} 374112829Smdodd 375121492Simpstatic void 376121492Simpepinit(void *xsc) 377121492Simp{ 378121492Simp struct ep_softc *sc = xsc; 379121492Simp EP_LOCK(sc); 380121515Simp epinit_locked(sc); 381121492Simp EP_UNLOCK(sc); 382121492Simp} 383121492Simp 3841017Snate/* 3851017Snate * The order in here seems important. Otherwise we may not receive 3861017Snate * interrupts. ?! 3871017Snate */ 38812724Sphkstatic void 389121515Simpepinit_locked(struct ep_softc *sc) 390963Sats{ 391147256Sbrooks struct ifnet *ifp = sc->ifp; 392121492Simp int i; 393963Sats 394117700Smarkm if (sc->gone) 395117700Smarkm return; 39616374Snate 397121515Simp EP_ASSERT_LOCKED(sc); 398121515Simp EP_BUSY_WAIT(sc); 399963Sats 400121588Simp GO_WINDOW(sc, 0); 401121492Simp CSR_WRITE_2(sc, EP_COMMAND, STOP_TRANSCEIVER); 402121588Simp GO_WINDOW(sc, 4); 403121492Simp CSR_WRITE_2(sc, EP_W4_MEDIA_TYPE, DISABLE_UTP); 404121588Simp GO_WINDOW(sc, 0); 405963Sats 406117700Smarkm /* Disable the card */ 407121492Simp CSR_WRITE_2(sc, EP_W0_CONFIG_CTRL, 0); 408963Sats 409117700Smarkm /* Enable the card */ 410121492Simp CSR_WRITE_2(sc, EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); 411963Sats 412121588Simp GO_WINDOW(sc, 2); 413117700Smarkm /* Reload the ether_addr. */ 414152315Sru ep_setup_station(sc, IF_LLADDR(sc->ifp)); 415963Sats 416121492Simp CSR_WRITE_2(sc, EP_COMMAND, RX_RESET); 417121492Simp CSR_WRITE_2(sc, EP_COMMAND, TX_RESET); 418121515Simp EP_BUSY_WAIT(sc); 4191018Snate 420117700Smarkm /* Window 1 is operating window */ 421121588Simp GO_WINDOW(sc, 1); 422117700Smarkm for (i = 0; i < 31; i++) 423121492Simp CSR_READ_1(sc, EP_W1_TX_STATUS); 424963Sats 425117700Smarkm /* get rid of stray intr's */ 426121492Simp CSR_WRITE_2(sc, EP_COMMAND, ACK_INTR | 0xff); 427963Sats 428121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RD_0_MASK | S_5_INTS); 429121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK | S_5_INTS); 430963Sats 431117700Smarkm if (ifp->if_flags & IFF_PROMISC) 432121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 433121492Simp FIL_MULTICAST | FIL_BRDCST | FIL_PROMISC); 434117700Smarkm else 435121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | 436121492Simp FIL_MULTICAST | FIL_BRDCST); 437963Sats 438117700Smarkm if (!sc->epb.mii_trans) 439117700Smarkm ep_ifmedia_upd(ifp); 4404435Sgibbs 441190908Simp if (sc->stat & F_HAS_TX_PLL) 442190908Simp CSR_WRITE_2(sc, EP_COMMAND, TX_PLL_ENABLE); 443121492Simp CSR_WRITE_2(sc, EP_COMMAND, RX_ENABLE); 444121492Simp CSR_WRITE_2(sc, EP_COMMAND, TX_ENABLE); 4457510Sjkh 446148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 447148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; /* just in case */ 448963Sats 4494435Sgibbs#ifdef EP_LOCAL_STATS 450117700Smarkm sc->rx_no_first = sc->rx_no_mbuf = 451117700Smarkm sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0; 4524435Sgibbs#endif 453117700Smarkm EP_FSET(sc, F_RX_FIRST); 454117700Smarkm if (sc->top) { 455117700Smarkm m_freem(sc->top); 456117700Smarkm sc->top = sc->mcur = 0; 457117700Smarkm } 458121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); 459121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_TX_START_THRESH | 16); 4607749Sjkh 461121588Simp GO_WINDOW(sc, 1); 462121515Simp epstart_locked(ifp); 463199559Sjhb callout_reset(&sc->watchdog_timer, hz, eptick, sc); 464963Sats} 465963Sats 46612724Sphkstatic void 467121492Simpepstart(struct ifnet *ifp) 468963Sats{ 469117700Smarkm struct ep_softc *sc; 470121492Simp sc = ifp->if_softc; 471121492Simp EP_LOCK(sc); 472121515Simp epstart_locked(ifp); 473121492Simp EP_UNLOCK(sc); 474121492Simp} 475121492Simp 476121492Simpstatic void 477121515Simpepstart_locked(struct ifnet *ifp) 478121492Simp{ 479121492Simp struct ep_softc *sc; 480117700Smarkm u_int len; 481117700Smarkm struct mbuf *m, *m0; 482190908Simp int pad, started; 483963Sats 484117700Smarkm sc = ifp->if_softc; 485117700Smarkm if (sc->gone) 486117700Smarkm return; 487121515Simp EP_ASSERT_LOCKED(sc); 488121515Simp EP_BUSY_WAIT(sc); 489148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 490117700Smarkm return; 491190908Simp started = 0; 492963Satsstartagain: 493117700Smarkm /* Sneak a peek at the next packet */ 494164810Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 495117700Smarkm if (m0 == NULL) 496117700Smarkm return; 497190908Simp if (!started && (sc->stat & F_HAS_TX_PLL)) 498190908Simp CSR_WRITE_2(sc, EP_COMMAND, TX_PLL_ENABLE); 499190908Simp started++; 500117700Smarkm for (len = 0, m = m0; m != NULL; m = m->m_next) 501117700Smarkm len += m->m_len; 502963Sats 503117700Smarkm pad = (4 - len) & 3; 5041017Snate 505117700Smarkm /* 506119572Smarkm * The 3c509 automatically pads short packets to minimum 507119572Smarkm * ethernet length, but we drop packets that are too large. 508119572Smarkm * Perhaps we should truncate them instead? 509119572Smarkm */ 510117700Smarkm if (len + pad > ETHER_MAX_LEN) { 511117700Smarkm /* packet is obviously too large: toss it */ 512117700Smarkm ifp->if_oerrors++; 513117700Smarkm m_freem(m0); 514117700Smarkm goto readcheck; 515117700Smarkm } 516121492Simp if (CSR_READ_2(sc, EP_W1_FREE_TX) < len + pad + 4) { 517117700Smarkm /* no room in FIFO */ 518121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); 519117700Smarkm /* make sure */ 520121492Simp if (CSR_READ_2(sc, EP_W1_FREE_TX) < len + pad + 4) { 521148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 522164810Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m0); 523121492Simp goto done; 524117700Smarkm } 525117700Smarkm } else 526121492Simp CSR_WRITE_2(sc, EP_COMMAND, 527119572Smarkm SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE); 52855834Smdodd 529121492Simp /* XXX 4.x and earlier would splhigh here */ 53055834Smdodd 531121492Simp CSR_WRITE_2(sc, EP_W1_TX_PIO_WR_1, len); 532119572Smarkm /* Second dword meaningless */ 533121492Simp CSR_WRITE_2(sc, EP_W1_TX_PIO_WR_1, 0x0); 534963Sats 535117700Smarkm if (EP_FTST(sc, F_ACCESS_32_BITS)) { 536117700Smarkm for (m = m0; m != NULL; m = m->m_next) { 537117700Smarkm if (m->m_len > 3) 538121492Simp CSR_WRITE_MULTI_4(sc, EP_W1_TX_PIO_WR_1, 539121206Simp mtod(m, uint32_t *), m->m_len / 4); 540117700Smarkm if (m->m_len & 3) 541121492Simp CSR_WRITE_MULTI_1(sc, EP_W1_TX_PIO_WR_1, 542121206Simp mtod(m, uint8_t *)+(m->m_len & (~3)), 543119572Smarkm m->m_len & 3); 544117700Smarkm } 545117700Smarkm } else { 546117700Smarkm for (m = m0; m != NULL; m = m->m_next) { 547117700Smarkm if (m->m_len > 1) 548121492Simp CSR_WRITE_MULTI_2(sc, EP_W1_TX_PIO_WR_1, 549121206Simp mtod(m, uint16_t *), m->m_len / 2); 550117700Smarkm if (m->m_len & 1) 551121492Simp CSR_WRITE_1(sc, EP_W1_TX_PIO_WR_1, 552121206Simp *(mtod(m, uint8_t *)+m->m_len - 1)); 553117700Smarkm } 55455834Smdodd } 555963Sats 556117700Smarkm while (pad--) 557121492Simp CSR_WRITE_1(sc, EP_W1_TX_PIO_WR_1, 0); /* Padding */ 5584435Sgibbs 559121492Simp /* XXX and drop splhigh here */ 56055834Smdodd 561117700Smarkm BPF_MTAP(ifp, m0); 562963Sats 563199559Sjhb sc->tx_timer = 2; 564117700Smarkm ifp->if_opackets++; 565117700Smarkm m_freem(m0); 5661017Snate 567117700Smarkm /* 568119572Smarkm * Is another packet coming in? We don't want to overflow 569119572Smarkm * the tiny RX fifo. 570119572Smarkm */ 5714435Sgibbsreadcheck: 572121492Simp if (CSR_READ_2(sc, EP_W1_RX_STATUS) & RX_BYTES_MASK) { 573117700Smarkm /* 574119572Smarkm * we check if we have packets left, in that case 575119572Smarkm * we prepare to come back later 576117700Smarkm */ 577164810Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 578121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_TX_AVAIL_THRESH | 8); 579121492Simp goto done; 580117700Smarkm } 581117700Smarkm goto startagain; 582121492Simpdone:; 583121492Simp return; 584963Sats} 585963Sats 58614259Sgibbsvoid 587117700Smarkmep_intr(void *arg) 58814259Sgibbs{ 589117700Smarkm struct ep_softc *sc; 590199559Sjhb 591199559Sjhb sc = (struct ep_softc *) arg; 592199559Sjhb EP_LOCK(sc); 593199559Sjhb ep_intr_locked(sc); 594199559Sjhb EP_UNLOCK(sc); 595199559Sjhb} 596199559Sjhb 597199559Sjhbstatic void 598199559Sjhbep_intr_locked(struct ep_softc *sc) 599199559Sjhb{ 600117700Smarkm int status; 601117700Smarkm struct ifnet *ifp; 602963Sats 603121492Simp /* XXX 4.x splbio'd here to reduce interruptability */ 60414259Sgibbs 605117700Smarkm /* 606119572Smarkm * quick fix: Try to detect an interrupt when the card goes away. 607119572Smarkm */ 608199559Sjhb if (sc->gone || CSR_READ_2(sc, EP_STATUS) == 0xffff) 609117700Smarkm return; 610147256Sbrooks ifp = sc->ifp; 61152472Simp 612121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK); /* disable all Ints */ 61314091Sgibbs 6147267Sdgrescan: 6154435Sgibbs 616121492Simp while ((status = CSR_READ_2(sc, EP_STATUS)) & S_5_INTS) { 6177510Sjkh 618117700Smarkm /* first acknowledge all interrupt sources */ 619121492Simp CSR_WRITE_2(sc, EP_COMMAND, ACK_INTR | (status & S_MASK)); 6207510Sjkh 621117700Smarkm if (status & (S_RX_COMPLETE | S_RX_EARLY)) 622117700Smarkm epread(sc); 623117700Smarkm if (status & S_TX_AVAIL) { 624117700Smarkm /* we need ACK */ 625199559Sjhb sc->tx_timer = 0; 626148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 627121588Simp GO_WINDOW(sc, 1); 628121492Simp CSR_READ_2(sc, EP_W1_FREE_TX); 629121515Simp epstart_locked(ifp); 630117700Smarkm } 631117700Smarkm if (status & S_CARD_FAILURE) { 632199559Sjhb sc->tx_timer = 0; 6334435Sgibbs#ifdef EP_LOCAL_STATS 634147715Simp device_printf(sc->dev, "\n\tStatus: %x\n", status); 635121588Simp GO_WINDOW(sc, 4); 636119572Smarkm printf("\tFIFO Diagnostic: %x\n", 637121492Simp CSR_READ_2(sc, EP_W4_FIFO_DIAG)); 638117700Smarkm printf("\tStat: %x\n", sc->stat); 639117700Smarkm printf("\tIpackets=%d, Opackets=%d\n", 640117700Smarkm ifp->if_ipackets, ifp->if_opackets); 641117700Smarkm printf("\tNOF=%d, NOMB=%d, RXOF=%d, RXOL=%d, TXU=%d\n", 642117700Smarkm sc->rx_no_first, sc->rx_no_mbuf, sc->rx_overrunf, 643117700Smarkm sc->rx_overrunl, sc->tx_underrun); 6444435Sgibbs#else 64513692Sgibbs 64613692Sgibbs#ifdef DIAGNOSTIC 647147715Simp device_printf(sc->dev, 648147715Simp "Status: %x (input buffer overflow)\n", status); 64913692Sgibbs#else 650117700Smarkm ++ifp->if_ierrors; 6514435Sgibbs#endif 65213692Sgibbs 65313692Sgibbs#endif 654121515Simp epinit_locked(sc); 655117700Smarkm return; 656117700Smarkm } 657117700Smarkm if (status & S_TX_COMPLETE) { 658199559Sjhb sc->tx_timer = 0; 659117700Smarkm /* 660119572Smarkm * We need ACK. We do it at the end. 661119572Smarkm * 662119572Smarkm * We need to read TX_STATUS until we get a 663119572Smarkm * 0 status in order to turn off the interrupt flag. 664117700Smarkm */ 665121492Simp while ((status = CSR_READ_1(sc, EP_W1_TX_STATUS)) & 666119572Smarkm TXS_COMPLETE) { 667144996Smdodd if (status & TXS_SUCCES_INTR_REQ) 668144996Smdodd ; /* nothing */ 669119572Smarkm else if (status & 670119572Smarkm (TXS_UNDERRUN | TXS_JABBER | 671119572Smarkm TXS_MAX_COLLISION)) { 672121492Simp CSR_WRITE_2(sc, EP_COMMAND, TX_RESET); 673117700Smarkm if (status & TXS_UNDERRUN) { 6744435Sgibbs#ifdef EP_LOCAL_STATS 675117700Smarkm sc->tx_underrun++; 6764435Sgibbs#endif 677117700Smarkm } 678196984Simp if (status & TXS_MAX_COLLISION) { 679196984Simp /* 680196984Simp * TXS_MAX_COLLISION we 681196984Simp * shouldn't get here 682196984Simp */ 683196984Simp ++ifp->if_collisions; 684196984Simp } 685117700Smarkm ++ifp->if_oerrors; 686121492Simp CSR_WRITE_2(sc, EP_COMMAND, TX_ENABLE); 687117700Smarkm /* 688119572Smarkm * To have a tx_avail_int but giving 689119572Smarkm * the chance to the Reception 690117700Smarkm */ 691164810Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 692121492Simp CSR_WRITE_2(sc, EP_COMMAND, 693119572Smarkm SET_TX_AVAIL_THRESH | 8); 694117700Smarkm } 695119572Smarkm /* pops up the next status */ 696121492Simp CSR_WRITE_1(sc, EP_W1_TX_STATUS, 0x0); 697117700Smarkm } /* while */ 698148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 699121588Simp GO_WINDOW(sc, 1); 700121492Simp CSR_READ_2(sc, EP_W1_FREE_TX); 701121515Simp epstart_locked(ifp); 702119572Smarkm } /* end TX_COMPLETE */ 703117700Smarkm } 7047267Sdg 705121492Simp CSR_WRITE_2(sc, EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */ 7067267Sdg 707121492Simp if ((status = CSR_READ_2(sc, EP_STATUS)) & S_5_INTS) 708117700Smarkm goto rescan; 7097635Sjkh 710117700Smarkm /* re-enable Ints */ 711121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK | S_5_INTS); 712963Sats} 713963Sats 71412724Sphkstatic void 715117700Smarkmepread(struct ep_softc *sc) 716963Sats{ 717117700Smarkm struct mbuf *top, *mcur, *m; 718117700Smarkm struct ifnet *ifp; 719117700Smarkm int lenthisone; 720117700Smarkm short rx_fifo2, status; 721117700Smarkm short rx_fifo; 722963Sats 723121492Simp/* XXX Must be called with sc locked */ 724121492Simp 725147256Sbrooks ifp = sc->ifp; 726121492Simp status = CSR_READ_2(sc, EP_W1_RX_STATUS); 7274435Sgibbs 7284435Sgibbsread_again: 7294435Sgibbs 730117700Smarkm if (status & ERR_RX) { 731117700Smarkm ++ifp->if_ierrors; 732117700Smarkm if (status & ERR_RX_OVERRUN) { 733117700Smarkm /* 734119572Smarkm * We can think the rx latency is actually 735119572Smarkm * greather than we expect 736117700Smarkm */ 7374435Sgibbs#ifdef EP_LOCAL_STATS 738117700Smarkm if (EP_FTST(sc, F_RX_FIRST)) 739117700Smarkm sc->rx_overrunf++; 740117700Smarkm else 741117700Smarkm sc->rx_overrunl++; 7424435Sgibbs#endif 743117700Smarkm } 744117700Smarkm goto out; 7451017Snate } 746117700Smarkm rx_fifo = rx_fifo2 = status & RX_BYTES_MASK; 747963Sats 748117700Smarkm if (EP_FTST(sc, F_RX_FIRST)) { 749243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 750117700Smarkm if (!m) 751117700Smarkm goto out; 752117700Smarkm if (rx_fifo >= MINCLSIZE) 753243857Sglebius MCLGET(m, M_NOWAIT); 754117700Smarkm sc->top = sc->mcur = top = m; 7551017Snate#define EROUND ((sizeof(struct ether_header) + 3) & ~3) 7561017Snate#define EOFF (EROUND - sizeof(struct ether_header)) 757117700Smarkm top->m_data += EOFF; 7584435Sgibbs 759117700Smarkm /* Read what should be the header. */ 760121492Simp CSR_READ_MULTI_2(sc, EP_W1_RX_PIO_RD_1, 761121206Simp mtod(top, uint16_t *), sizeof(struct ether_header) / 2); 762117700Smarkm top->m_len = sizeof(struct ether_header); 763117700Smarkm rx_fifo -= sizeof(struct ether_header); 764117700Smarkm sc->cur_len = rx_fifo2; 765963Sats } else { 766117700Smarkm /* come here if we didn't have a complete packet last time */ 767117700Smarkm top = sc->top; 768117700Smarkm m = sc->mcur; 769117700Smarkm sc->cur_len += rx_fifo2; 770963Sats } 7711017Snate 772117700Smarkm /* Reads what is left in the RX FIFO */ 773117700Smarkm while (rx_fifo > 0) { 774117700Smarkm lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); 775117700Smarkm if (lenthisone == 0) { /* no room in this one */ 776117700Smarkm mcur = m; 777243857Sglebius MGET(m, M_NOWAIT, MT_DATA); 778117700Smarkm if (!m) 779117700Smarkm goto out; 780117700Smarkm if (rx_fifo >= MINCLSIZE) 781243857Sglebius MCLGET(m, M_NOWAIT); 782117700Smarkm m->m_len = 0; 783117700Smarkm mcur->m_next = m; 784117700Smarkm lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); 785117700Smarkm } 786119572Smarkm if (EP_FTST(sc, F_ACCESS_32_BITS)) { 787119572Smarkm /* default for EISA configured cards */ 788121492Simp CSR_READ_MULTI_4(sc, EP_W1_RX_PIO_RD_1, 789121388Simp (uint32_t *)(mtod(m, caddr_t)+m->m_len), 790117700Smarkm lenthisone / 4); 791117700Smarkm m->m_len += (lenthisone & ~3); 792117700Smarkm if (lenthisone & 3) 793121492Simp CSR_READ_MULTI_1(sc, EP_W1_RX_PIO_RD_1, 794119572Smarkm mtod(m, caddr_t)+m->m_len, lenthisone & 3); 795117700Smarkm m->m_len += (lenthisone & 3); 796117700Smarkm } else { 797121492Simp CSR_READ_MULTI_2(sc, EP_W1_RX_PIO_RD_1, 798121399Simp (uint16_t *)(mtod(m, caddr_t)+m->m_len), 799121388Simp lenthisone / 2); 800117700Smarkm m->m_len += lenthisone; 801117700Smarkm if (lenthisone & 1) 802119572Smarkm *(mtod(m, caddr_t)+m->m_len - 1) = 803121492Simp CSR_READ_1(sc, EP_W1_RX_PIO_RD_1); 804117700Smarkm } 805117700Smarkm rx_fifo -= lenthisone; 806117700Smarkm } 807117700Smarkm 808119572Smarkm if (status & ERR_RX_INCOMPLETE) { 809119572Smarkm /* we haven't received the complete packet */ 810117700Smarkm sc->mcur = m; 8114435Sgibbs#ifdef EP_LOCAL_STATS 812119572Smarkm /* to know how often we come here */ 813119572Smarkm sc->rx_no_first++; 8144435Sgibbs#endif 815117700Smarkm EP_FRST(sc, F_RX_FIRST); 816121492Simp status = CSR_READ_2(sc, EP_W1_RX_STATUS); 817201794Strasz if (!(status & ERR_RX_INCOMPLETE)) { 818117700Smarkm /* 819119572Smarkm * We see if by now, the packet has completly 820117700Smarkm * arrived 821117700Smarkm */ 822117700Smarkm goto read_again; 823117700Smarkm } 824121492Simp CSR_WRITE_2(sc, EP_COMMAND, 825119572Smarkm SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH); 826117700Smarkm return; 8274435Sgibbs } 828121492Simp CSR_WRITE_2(sc, EP_COMMAND, RX_DISCARD_TOP_PACK); 829117700Smarkm ++ifp->if_ipackets; 830117700Smarkm EP_FSET(sc, F_RX_FIRST); 831147256Sbrooks top->m_pkthdr.rcvif = sc->ifp; 832117700Smarkm top->m_pkthdr.len = sc->cur_len; 833117700Smarkm 834121492Simp /* 835121492Simp * Drop locks before calling if_input() since it may re-enter 836121492Simp * ep_start() in the netisr case. This would result in a 837121492Simp * lock reversal. Better performance might be obtained by 838121492Simp * chaining all packets received, dropping the lock, and then 839121492Simp * calling if_input() on each one. 840121492Simp */ 841121492Simp EP_UNLOCK(sc); 842117700Smarkm (*ifp->if_input) (ifp, top); 843121492Simp EP_LOCK(sc); 844117700Smarkm sc->top = 0; 845121515Simp EP_BUSY_WAIT(sc); 846121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); 8474435Sgibbs return; 8484435Sgibbs 8494435Sgibbsout: 850121492Simp CSR_WRITE_2(sc, EP_COMMAND, RX_DISCARD_TOP_PACK); 851117700Smarkm if (sc->top) { 852117700Smarkm m_freem(sc->top); 853117700Smarkm sc->top = 0; 8544435Sgibbs#ifdef EP_LOCAL_STATS 855117700Smarkm sc->rx_no_mbuf++; 8564435Sgibbs#endif 857117700Smarkm } 858117700Smarkm EP_FSET(sc, F_RX_FIRST); 859121515Simp EP_BUSY_WAIT(sc); 860121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH); 861963Sats} 862963Sats 863117700Smarkmstatic int 864117700Smarkmep_ifmedia_upd(struct ifnet *ifp) 865963Sats{ 866117700Smarkm struct ep_softc *sc = ifp->if_softc; 867117700Smarkm int i = 0, j; 8681017Snate 869121588Simp GO_WINDOW(sc, 0); 870121492Simp CSR_WRITE_2(sc, EP_COMMAND, STOP_TRANSCEIVER); 871121588Simp GO_WINDOW(sc, 4); 872121492Simp CSR_WRITE_2(sc, EP_W4_MEDIA_TYPE, DISABLE_UTP); 873121588Simp GO_WINDOW(sc, 0); 8749404Sdg 87552549Smdodd switch (IFM_SUBTYPE(sc->ifmedia.ifm_media)) { 876117700Smarkm case IFM_10_T: 877117700Smarkm if (sc->ep_connectors & UTP) { 878117700Smarkm i = ACF_CONNECTOR_UTP; 879121588Simp GO_WINDOW(sc, 4); 880121492Simp CSR_WRITE_2(sc, EP_W4_MEDIA_TYPE, ENABLE_UTP); 881117700Smarkm } 882117700Smarkm break; 883117700Smarkm case IFM_10_2: 884117700Smarkm if (sc->ep_connectors & BNC) { 885117700Smarkm i = ACF_CONNECTOR_BNC; 886121492Simp CSR_WRITE_2(sc, EP_COMMAND, START_TRANSCEIVER); 887117700Smarkm DELAY(DELAY_MULTIPLE * 1000); 888117700Smarkm } 889117700Smarkm break; 890117700Smarkm case IFM_10_5: 891117700Smarkm if (sc->ep_connectors & AUI) 892117700Smarkm i = ACF_CONNECTOR_AUI; 893117700Smarkm break; 894117700Smarkm default: 895117700Smarkm i = sc->ep_connector; 896117700Smarkm device_printf(sc->dev, 897117700Smarkm "strange connector type in EEPROM: assuming AUI\n"); 89852549Smdodd } 89913692Sgibbs 900121588Simp GO_WINDOW(sc, 0); 901121492Simp j = CSR_READ_2(sc, EP_W0_ADDRESS_CFG) & 0x3fff; 902121492Simp CSR_WRITE_2(sc, EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS)); 90313692Sgibbs 90452549Smdodd return (0); 90552549Smdodd} 9067510Sjkh 90752549Smdoddstatic void 908117700Smarkmep_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 90952549Smdodd{ 910117700Smarkm struct ep_softc *sc = ifp->if_softc; 911190907Simp uint16_t ms; 91252549Smdodd 913190907Simp switch (IFM_SUBTYPE(sc->ifmedia.ifm_media)) { 914190907Simp case IFM_10_T: 915190907Simp GO_WINDOW(sc, 4); 916190907Simp ms = CSR_READ_2(sc, EP_W4_MEDIA_TYPE); 917190907Simp GO_WINDOW(sc, 0); 918190907Simp ifmr->ifm_status = IFM_AVALID; 919190907Simp if (ms & MT_LB) { 920190907Simp ifmr->ifm_status |= IFM_ACTIVE; 921190907Simp ifmr->ifm_active = IFM_ETHER | IFM_10_T; 922190907Simp } else { 923190907Simp ifmr->ifm_active = IFM_ETHER | IFM_NONE; 924190907Simp } 925192158Sbrueffer break; 926190907Simp default: 927190907Simp ifmr->ifm_active = sc->ifmedia.ifm_media; 928190907Simp break; 929190907Simp } 93052549Smdodd} 93152549Smdodd 93252549Smdoddstatic int 933121492Simpepioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 93452549Smdodd{ 935117700Smarkm struct ep_softc *sc = ifp->if_softc; 936117700Smarkm struct ifreq *ifr = (struct ifreq *) data; 937121492Simp int error = 0; 93852549Smdodd 93952549Smdodd switch (cmd) { 94052549Smdodd case SIOCSIFFLAGS: 941121492Simp EP_LOCK(sc); 94252549Smdodd if (((ifp->if_flags & IFF_UP) == 0) && 943148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING)) { 94452549Smdodd epstop(sc); 945117700Smarkm } else 94652549Smdodd /* reinitialize card on any parameter change */ 947121515Simp epinit_locked(sc); 948121492Simp EP_UNLOCK(sc); 94952549Smdodd break; 95013692Sgibbs case SIOCADDMULTI: 95113692Sgibbs case SIOCDELMULTI: 95252549Smdodd /* 95352549Smdodd * The Etherlink III has no programmable multicast 95452549Smdodd * filter. We always initialize the card to be 95552549Smdodd * promiscuous to multicast, since we're always a 95652549Smdodd * member of the ALL-SYSTEMS group, so there's no 95752549Smdodd * need to process SIOC*MULTI requests. 95852549Smdodd */ 95952549Smdodd error = 0; 96052549Smdodd break; 96152549Smdodd case SIOCSIFMEDIA: 96252549Smdodd case SIOCGIFMEDIA: 963117700Smarkm if (!sc->epb.mii_trans) 96456017Smdodd error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd); 965117700Smarkm else 96656017Smdodd error = EINVAL; 96752549Smdodd break; 96852549Smdodd default: 969106937Ssam error = ether_ioctl(ifp, cmd, data); 97052549Smdodd break; 97152549Smdodd } 97252549Smdodd return (error); 973963Sats} 974963Sats 97512724Sphkstatic void 976199559Sjhbeptick(void *arg) 977963Sats{ 978199559Sjhb struct ep_softc *sc; 97916374Snate 980199559Sjhb sc = arg; 981199559Sjhb if (sc->tx_timer != 0 && --sc->tx_timer == 0) 982199559Sjhb epwatchdog(sc); 983199559Sjhb callout_reset(&sc->watchdog_timer, hz, eptick, sc); 984199559Sjhb} 985199559Sjhb 986199559Sjhbstatic void 987199559Sjhbepwatchdog(struct ep_softc *sc) 988199559Sjhb{ 989199559Sjhb struct ifnet *ifp; 990199559Sjhb 991199559Sjhb ifp = sc->ifp; 992117700Smarkm if (sc->gone) 993117700Smarkm return; 994148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 995199559Sjhb epstart_locked(ifp); 996199559Sjhb ep_intr_locked(sc); 997963Sats} 998963Sats 99912724Sphkstatic void 1000117700Smarkmepstop(struct ep_softc *sc) 1001963Sats{ 1002121492Simp CSR_WRITE_2(sc, EP_COMMAND, RX_DISABLE); 1003121492Simp CSR_WRITE_2(sc, EP_COMMAND, RX_DISCARD_TOP_PACK); 1004121515Simp EP_BUSY_WAIT(sc); 100516374Snate 1006121492Simp CSR_WRITE_2(sc, EP_COMMAND, TX_DISABLE); 1007121492Simp CSR_WRITE_2(sc, EP_COMMAND, STOP_TRANSCEIVER); 1008117700Smarkm DELAY(800); 100957983Smdodd 1010121492Simp CSR_WRITE_2(sc, EP_COMMAND, RX_RESET); 1011121515Simp EP_BUSY_WAIT(sc); 1012121492Simp CSR_WRITE_2(sc, EP_COMMAND, TX_RESET); 1013121515Simp EP_BUSY_WAIT(sc); 101457983Smdodd 1015121492Simp CSR_WRITE_2(sc, EP_COMMAND, C_INTR_LATCH); 1016121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RD_0_MASK); 1017121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK); 1018121492Simp CSR_WRITE_2(sc, EP_COMMAND, SET_RX_FILTER); 1019199559Sjhb 1020199559Sjhb sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1021199559Sjhb callout_stop(&sc->watchdog_timer); 1022963Sats} 1023