if_ex.c revision 131192
121769Sjkh/* 221769Sjkh * Copyright (c) 1996, Javier Mart�n Rueda (jmrueda@diatel.upm.es) 321769Sjkh * All rights reserved. 421769Sjkh * 521769Sjkh * Redistribution and use in source and binary forms, with or without 621769Sjkh * modification, are permitted provided that the following conditions 721769Sjkh * are met: 821769Sjkh * 1. Redistributions of source code must retain the above copyright 921769Sjkh * notice unmodified, this list of conditions, and the following 1021769Sjkh * disclaimer. 1121769Sjkh * 2. Redistributions in binary form must reproduce the above copyright 1221769Sjkh * notice, this list of conditions and the following disclaimer in the 1321769Sjkh * documentation and/or other materials provided with the distribution. 1421769Sjkh * 1521769Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1621769Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1721769Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1821769Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1921769Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2021769Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2121769Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2221769Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2321769Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2421769Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2521769Sjkh * SUCH DAMAGE. 2629877Smsmith * 2752286Smdodd * 2852286Smdodd * MAINTAINER: Matthew N. Dodd <winter@jurai.net> 2952286Smdodd * <mdodd@FreeBSD.org> 3021769Sjkh */ 3121769Sjkh 32119418Sobrien#include <sys/cdefs.h> 33119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/ex/if_ex.c 131192 2004-06-27 13:10:20Z imp $"); 34119418Sobrien 3521769Sjkh/* 3629877Smsmith * Intel EtherExpress Pro/10, Pro/10+ Ethernet driver 3721769Sjkh * 3821769Sjkh * Revision history: 3921769Sjkh * 40112731Smdodd * dd-mmm-yyyy: Multicast support ported from NetBSD's if_iy driver. 4121769Sjkh * 30-Oct-1996: first beta version. Inet and BPF supported, but no multicast. 4221769Sjkh */ 4321769Sjkh 4421769Sjkh#include <sys/param.h> 4521769Sjkh#include <sys/systm.h> 4652286Smdodd#include <sys/kernel.h> 4724204Sbde#include <sys/sockio.h> 4821769Sjkh#include <sys/mbuf.h> 4921769Sjkh#include <sys/socket.h> 5021769Sjkh 5152286Smdodd#include <sys/module.h> 5252286Smdodd#include <sys/bus.h> 5352286Smdodd 5452286Smdodd#include <machine/bus.h> 5552286Smdodd#include <machine/resource.h> 5652286Smdodd#include <sys/rman.h> 5752286Smdodd 5857987Smdodd#include <net/if.h> 5957987Smdodd#include <net/if_arp.h> 60112731Smdodd#include <net/if_dl.h> 6157987Smdodd#include <net/if_media.h> 6250026Smdodd#include <net/ethernet.h> 6357987Smdodd#include <net/bpf.h> 6421769Sjkh 6550026Smdodd#include <netinet/in.h> 6650026Smdodd#include <netinet/if_ether.h> 6750026Smdodd 6821769Sjkh 6952286Smdodd#include <isa/isavar.h> 7052286Smdodd#include <isa/pnpvar.h> 7152286Smdodd 7255953Speter#include <dev/ex/if_exreg.h> 7359816Smdodd#include <dev/ex/if_exvar.h> 7421769Sjkh 7521769Sjkh#ifdef EXDEBUG 7652286Smdodd# define Start_End 1 7752286Smdodd# define Rcvd_Pkts 2 7852286Smdodd# define Sent_Pkts 4 7952286Smdodd# define Status 8 8021769Sjkhstatic int debug_mask = 0; 8152286Smdodd# define DODEBUG(level, action) if (level & debug_mask) action 8221769Sjkh#else 8352286Smdodd# define DODEBUG(level, action) 8421769Sjkh#endif 8521769Sjkh 86112801Smdodddevclass_t ex_devclass; 87112801Smdodd 8859816Smdoddchar irq2eemap[] = 8952286Smdodd { -1, -1, 0, 1, -1, 2, -1, -1, -1, 0, 3, 4, -1, -1, -1, -1 }; 9059816Smdoddu_char ee2irqmap[] = 9152286Smdodd { 9, 3, 5, 10, 11, 0, 0, 0 }; 9259816Smdodd 9359816Smdoddchar plus_irq2eemap[] = 9452286Smdodd { -1, -1, -1, 0, 1, 2, -1, 3, -1, 4, 5, 6, 7, -1, -1, -1 }; 9559816Smdoddu_char plus_ee2irqmap[] = 9652286Smdodd { 3, 4, 5, 7, 9, 10, 11, 12 }; 9721769Sjkh 9852286Smdodd/* Network Interface Functions */ 99131192Simpstatic void ex_init(void *); 100131192Simpstatic void ex_start(struct ifnet *); 101131192Simpstatic int ex_ioctl(struct ifnet *, u_long, caddr_t); 102131192Simpstatic void ex_watchdog(struct ifnet *); 10321769Sjkh 10457987Smdodd/* ifmedia Functions */ 105131192Simpstatic int ex_ifmedia_upd(struct ifnet *); 106131192Simpstatic void ex_ifmedia_sts(struct ifnet *, struct ifmediareq *); 10757987Smdodd 108131192Simpstatic int ex_get_media(struct ex_softc *); 10959816Smdodd 110131192Simpstatic void ex_reset(struct ex_softc *); 111131192Simpstatic void ex_setmulti(struct ex_softc *); 11252286Smdodd 113131192Simpstatic void ex_tx_intr(struct ex_softc *); 114131192Simpstatic void ex_rx_intr(struct ex_softc *); 11552286Smdodd 11659816Smdoddvoid 117131192Simpex_get_address(struct ex_softc *sc, u_char *enaddr) 11821769Sjkh{ 119131192Simp uint16_t eaddr_tmp; 12021769Sjkh 121131192Simp eaddr_tmp = ex_eeprom_read(sc, EE_Eth_Addr_Lo); 12252286Smdodd enaddr[5] = eaddr_tmp & 0xff; 12352286Smdodd enaddr[4] = eaddr_tmp >> 8; 124131192Simp eaddr_tmp = ex_eeprom_read(sc, EE_Eth_Addr_Mid); 12552286Smdodd enaddr[3] = eaddr_tmp & 0xff; 12652286Smdodd enaddr[2] = eaddr_tmp >> 8; 127131192Simp eaddr_tmp = ex_eeprom_read(sc, EE_Eth_Addr_Hi); 12852286Smdodd enaddr[1] = eaddr_tmp & 0xff; 12952286Smdodd enaddr[0] = eaddr_tmp >> 8; 13052286Smdodd 13152286Smdodd return; 13252286Smdodd} 13321769Sjkh 13459816Smdoddint 135131192Simpex_card_type(u_char *enaddr) 13652286Smdodd{ 13752286Smdodd if ((enaddr[0] == 0x00) && (enaddr[1] == 0xA0) && (enaddr[2] == 0xC9)) 13852286Smdodd return (CARD_TYPE_EX_10_PLUS); 13952286Smdodd 14052286Smdodd return (CARD_TYPE_EX_10); 14152286Smdodd} 14252286Smdodd 14355882Smdodd/* 14459816Smdodd * Caller is responsible for eventually calling 14559816Smdodd * ex_release_resources() on failure. 14655882Smdodd */ 14759816Smdoddint 148131192Simpex_alloc_resources(device_t dev) 14955882Smdodd{ 15059816Smdodd struct ex_softc * sc = device_get_softc(dev); 15159816Smdodd int error = 0; 15255882Smdodd 153127135Snjl sc->ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 154127135Snjl &sc->ioport_rid, RF_ACTIVE); 15559816Smdodd if (!sc->ioport) { 15659816Smdodd device_printf(dev, "No I/O space?!\n"); 15759816Smdodd error = ENOMEM; 15859816Smdodd goto bad; 15959816Smdodd } 160131192Simp sc->bst = rman_get_bustag(sc->ioport); 161131192Simp sc->bsh = rman_get_bushandle(sc->ioport); 16257989Smdodd 163127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 164127135Snjl RF_ACTIVE); 16555882Smdodd 16659816Smdodd if (!sc->irq) { 16759816Smdodd device_printf(dev, "No IRQ?!\n"); 16859816Smdodd error = ENOMEM; 16959816Smdodd goto bad; 17055882Smdodd } 17155882Smdodd 17259816Smdoddbad: 17359816Smdodd return (error); 17455882Smdodd} 17555882Smdodd 17659816Smdoddvoid 177131192Simpex_release_resources(device_t dev) 17852286Smdodd{ 17959816Smdodd struct ex_softc * sc = device_get_softc(dev); 18052286Smdodd 18159816Smdodd if (sc->ih) { 18259816Smdodd bus_teardown_intr(dev, sc->irq, sc->ih); 18359816Smdodd sc->ih = NULL; 18452286Smdodd } 18552286Smdodd 18659816Smdodd if (sc->ioport) { 18759816Smdodd bus_release_resource(dev, SYS_RES_IOPORT, 18859816Smdodd sc->ioport_rid, sc->ioport); 18959816Smdodd sc->ioport = NULL; 19052286Smdodd } 19152286Smdodd 19259816Smdodd if (sc->irq) { 19359816Smdodd bus_release_resource(dev, SYS_RES_IRQ, 19459816Smdodd sc->irq_rid, sc->irq); 19559816Smdodd sc->irq = NULL; 19657989Smdodd } 19757989Smdodd 19859816Smdodd return; 19952286Smdodd} 20052286Smdodd 20159816Smdoddint 20259816Smdoddex_attach(device_t dev) 20352286Smdodd{ 20452286Smdodd struct ex_softc * sc = device_get_softc(dev); 20552286Smdodd struct ifnet * ifp = &sc->arpcom.ac_if; 20657987Smdodd struct ifmedia * ifm; 207131192Simp uint16_t temp; 20852286Smdodd 20929877Smsmith /* work out which set of irq <-> internal tables to use */ 21052286Smdodd if (ex_card_type(sc->arpcom.ac_enaddr) == CARD_TYPE_EX_10_PLUS) { 21129877Smsmith sc->irq2ee = plus_irq2eemap; 21229877Smsmith sc->ee2irq = plus_ee2irqmap; 21352286Smdodd } else { 21429877Smsmith sc->irq2ee = irq2eemap; 21529877Smsmith sc->ee2irq = ee2irqmap; 21629877Smsmith } 21729877Smsmith 21821769Sjkh sc->mem_size = CARD_RAM_SIZE; /* XXX This should be read from the card itself. */ 21921769Sjkh 22021769Sjkh /* 22121769Sjkh * Initialize the ifnet structure. 22221769Sjkh */ 22321769Sjkh ifp->if_softc = sc; 224121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 22555883Smdodd ifp->if_mtu = ETHERMTU; 226112731Smdodd ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; 22721769Sjkh ifp->if_start = ex_start; 22821769Sjkh ifp->if_ioctl = ex_ioctl; 22921769Sjkh ifp->if_watchdog = ex_watchdog; 23055883Smdodd ifp->if_init = ex_init; 23155883Smdodd ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 23221769Sjkh 23357987Smdodd ifmedia_init(&sc->ifmedia, 0, ex_ifmedia_upd, ex_ifmedia_sts); 23457987Smdodd 235131192Simp temp = ex_eeprom_read(sc, EE_W5); 23657987Smdodd if (temp & EE_W5_PORT_TPE) 23757987Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 23857987Smdodd if (temp & EE_W5_PORT_BNC) 23957987Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL); 24057987Smdodd if (temp & EE_W5_PORT_AUI) 24157987Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); 24257987Smdodd 243112764Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 244112764Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL); 245131192Simp ifmedia_set(&sc->ifmedia, ex_get_media(sc)); 24657987Smdodd 24757987Smdodd ifm = &sc->ifmedia; 24857987Smdodd ifm->ifm_media = ifm->ifm_cur->ifm_media; 24957987Smdodd ex_ifmedia_upd(ifp); 25057987Smdodd 25121769Sjkh /* 25221769Sjkh * Attach the interface. 25321769Sjkh */ 254106937Ssam ether_ifattach(ifp, sc->arpcom.ac_enaddr); 25521769Sjkh 25652286Smdodd return(0); 25721769Sjkh} 25821769Sjkh 259112800Smdoddint 260131192Simpex_detach(device_t dev) 261112800Smdodd{ 262112800Smdodd struct ex_softc *sc; 263112800Smdodd struct ifnet *ifp; 264112800Smdodd 265112800Smdodd sc = device_get_softc(dev); 266112800Smdodd ifp = &sc->arpcom.ac_if; 267112800Smdodd 268112800Smdodd ex_stop(sc); 269112800Smdodd 270112800Smdodd ifp->if_flags &= ~IFF_RUNNING; 271112800Smdodd ether_ifdetach(ifp); 272112800Smdodd 273112800Smdodd ex_release_resources(dev); 274112800Smdodd 275112800Smdodd return (0); 276112800Smdodd} 277112800Smdodd 27855883Smdoddstatic void 27955883Smdoddex_init(void *xsc) 28021769Sjkh{ 28152286Smdodd struct ex_softc * sc = (struct ex_softc *) xsc; 28252286Smdodd struct ifnet * ifp = &sc->arpcom.ac_if; 28352286Smdodd int s; 28452286Smdodd int i; 28552286Smdodd unsigned short temp_reg; 28621769Sjkh 287121816Sbrooks DODEBUG(Start_End, printf("%s: ex_init: start\n", ifp->if_xname);); 28821769Sjkh 28921769Sjkh s = splimp(); 29059816Smdodd ifp->if_timer = 0; 29121769Sjkh 29221769Sjkh /* 29321769Sjkh * Load the ethernet address into the card. 29421769Sjkh */ 295131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 296131192Simp temp_reg = CSR_READ_1(sc, EEPROM_REG); 29752286Smdodd if (temp_reg & Trnoff_Enable) { 298131192Simp CSR_WRITE_1(sc, EEPROM_REG, temp_reg & ~Trnoff_Enable); 29952286Smdodd } 30052286Smdodd for (i = 0; i < ETHER_ADDR_LEN; i++) { 301131192Simp CSR_WRITE_1(sc, I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]); 30252286Smdodd } 30321769Sjkh /* 30421769Sjkh * - Setup transmit chaining and discard bad received frames. 30521769Sjkh * - Match broadcast. 30621769Sjkh * - Clear test mode. 30721769Sjkh * - Set receiving mode. 30821769Sjkh * - Set IRQ number. 30921769Sjkh */ 310131192Simp CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr); 311131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | No_SA_Ins | RX_CRC_InMem); 312131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3) & 0x3f /* XXX constants. */ ); 313131192Simp CSR_WRITE_1(sc, CMD_REG, Bank1_Sel); 314131192Simp CSR_WRITE_1(sc, INT_NO_REG, (CSR_READ_1(sc, INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]); 31521769Sjkh 31621769Sjkh /* 31721769Sjkh * Divide the available memory in the card into rcv and xmt buffers. 31821769Sjkh * By default, I use the first 3/4 of the memory for the rcv buffer, 31921769Sjkh * and the remaining 1/4 of the memory for the xmt buffer. 32021769Sjkh */ 32121769Sjkh sc->rx_mem_size = sc->mem_size * 3 / 4; 32221769Sjkh sc->tx_mem_size = sc->mem_size - sc->rx_mem_size; 32321769Sjkh sc->rx_lower_limit = 0x0000; 32421769Sjkh sc->rx_upper_limit = sc->rx_mem_size - 2; 32521769Sjkh sc->tx_lower_limit = sc->rx_mem_size; 32621769Sjkh sc->tx_upper_limit = sc->mem_size - 2; 327131192Simp CSR_WRITE_1(sc, RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8); 328131192Simp CSR_WRITE_1(sc, RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8); 329131192Simp CSR_WRITE_1(sc, XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8); 330131192Simp CSR_WRITE_1(sc, XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8); 33121769Sjkh 33221769Sjkh /* 33321769Sjkh * Enable receive and transmit interrupts, and clear any pending int. 33421769Sjkh */ 335131192Simp CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) | TriST_INT); 336131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 337131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 338131192Simp CSR_WRITE_1(sc, STATUS_REG, All_Int); 33921769Sjkh 34021769Sjkh /* 34121769Sjkh * Initialize receive and transmit ring buffers. 34221769Sjkh */ 343131192Simp CSR_WRITE_2(sc, RCV_BAR, sc->rx_lower_limit); 34421769Sjkh sc->rx_head = sc->rx_lower_limit; 345131192Simp CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_upper_limit | 0xfe); 346131192Simp CSR_WRITE_2(sc, XMT_BAR, sc->tx_lower_limit); 34721769Sjkh sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 34821769Sjkh 34921769Sjkh ifp->if_flags |= IFF_RUNNING; 35021769Sjkh ifp->if_flags &= ~IFF_OACTIVE; 35121769Sjkh DODEBUG(Status, printf("OIDLE init\n");); 35221769Sjkh 353112731Smdodd ex_setmulti(sc); 354112731Smdodd 35521769Sjkh /* 35621769Sjkh * Final reset of the board, and enable operation. 35721769Sjkh */ 358131192Simp CSR_WRITE_1(sc, CMD_REG, Sel_Reset_CMD); 35921769Sjkh DELAY(2); 360131192Simp CSR_WRITE_1(sc, CMD_REG, Rcv_Enable_CMD); 36121769Sjkh 36221769Sjkh ex_start(ifp); 36321769Sjkh splx(s); 36421769Sjkh 365121816Sbrooks DODEBUG(Start_End, printf("%s: ex_init: finish\n", ifp->if_xname);); 36621769Sjkh} 36721769Sjkh 36821769Sjkh 36955883Smdoddstatic void 37052286Smdoddex_start(struct ifnet *ifp) 37121769Sjkh{ 37252286Smdodd struct ex_softc * sc = ifp->if_softc; 37352286Smdodd int i, s, len, data_len, avail, dest, next; 37452286Smdodd unsigned char tmp16[2]; 37552286Smdodd struct mbuf * opkt; 37652286Smdodd struct mbuf * m; 37721769Sjkh 37852286Smdodd DODEBUG(Start_End, printf("ex_start%d: start\n", unit);); 37921769Sjkh 38052286Smdodd s = splimp(); 38121769Sjkh 38252286Smdodd /* 38352286Smdodd * Main loop: send outgoing packets to network card until there are no 38452286Smdodd * more packets left, or the card cannot accept any more yet. 38552286Smdodd */ 38652286Smdodd while (((opkt = ifp->if_snd.ifq_head) != NULL) && 38752286Smdodd !(ifp->if_flags & IFF_OACTIVE)) { 38821769Sjkh 38952286Smdodd /* 39052286Smdodd * Ensure there is enough free transmit buffer space for 39152286Smdodd * this packet, including its header. Note: the header 39252286Smdodd * cannot wrap around the end of the transmit buffer and 39352286Smdodd * must be kept together, so we allow space for twice the 39452286Smdodd * length of the header, just in case. 39552286Smdodd */ 39621769Sjkh 39752286Smdodd for (len = 0, m = opkt; m != NULL; m = m->m_next) { 39852286Smdodd len += m->m_len; 39952286Smdodd } 40052286Smdodd 40152286Smdodd data_len = len; 40252286Smdodd 40352286Smdodd DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len);); 40452286Smdodd 40552286Smdodd if (len & 1) { 40652286Smdodd len += XMT_HEADER_LEN + 1; 40752286Smdodd } else { 40852286Smdodd len += XMT_HEADER_LEN; 40952286Smdodd } 41052286Smdodd 41152286Smdodd if ((i = sc->tx_tail - sc->tx_head) >= 0) { 41252286Smdodd avail = sc->tx_mem_size - i; 41352286Smdodd } else { 41452286Smdodd avail = -i; 41552286Smdodd } 41652286Smdodd 41752286Smdodd DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail);); 41852286Smdodd 41952286Smdodd if (avail >= len + XMT_HEADER_LEN) { 42052286Smdodd IF_DEQUEUE(&ifp->if_snd, opkt); 42152286Smdodd 42221769Sjkh#ifdef EX_PSA_INTR 42352286Smdodd /* 42452286Smdodd * Disable rx and tx interrupts, to avoid corruption 42552286Smdodd * of the host address register by interrupt service 42652286Smdodd * routines. 42752286Smdodd * XXX Is this necessary with splimp() enabled? 42852286Smdodd */ 429131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int); 43021769Sjkh#endif 43121769Sjkh 43252286Smdodd /* 43352286Smdodd * Compute the start and end addresses of this 43452286Smdodd * frame in the tx buffer. 43552286Smdodd */ 43652286Smdodd dest = sc->tx_tail; 43752286Smdodd next = dest + len; 43821769Sjkh 43952286Smdodd if (next > sc->tx_upper_limit) { 44052286Smdodd if ((sc->tx_upper_limit + 2 - sc->tx_tail) <= 44152286Smdodd XMT_HEADER_LEN) { 44252286Smdodd dest = sc->tx_lower_limit; 44352286Smdodd next = dest + len; 44455881Smdodd } else { 44555881Smdodd next = sc->tx_lower_limit + 44655881Smdodd next - sc->tx_upper_limit - 2; 44752286Smdodd } 44852286Smdodd } 44921769Sjkh 45052286Smdodd /* 45152286Smdodd * Build the packet frame in the card's ring buffer. 45252286Smdodd */ 45352286Smdodd DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next);); 45421769Sjkh 455131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, dest); 456131192Simp CSR_WRITE_2(sc, IO_PORT_REG, Transmit_CMD); 457131192Simp CSR_WRITE_2(sc, IO_PORT_REG, 0); 458131192Simp CSR_WRITE_2(sc, IO_PORT_REG, next); 459131192Simp CSR_WRITE_2(sc, IO_PORT_REG, data_len); 46021769Sjkh 46152286Smdodd /* 46252286Smdodd * Output the packet data to the card. Ensure all 46352286Smdodd * transfers are 16-bit wide, even if individual 46452286Smdodd * mbufs have odd length. 46552286Smdodd */ 46652286Smdodd for (m = opkt, i = 0; m != NULL; m = m->m_next) { 46752286Smdodd DODEBUG(Sent_Pkts, printf("[%d]", m->m_len);); 46852286Smdodd if (i) { 46952286Smdodd tmp16[1] = *(mtod(m, caddr_t)); 470131192Simp CSR_WRITE_MULTI_2(sc, IO_PORT_REG, 471131192Simp (uint16_t *) tmp16, 1); 47252286Smdodd } 473131192Simp CSR_WRITE_MULTI_2(sc, IO_PORT_REG, 474131192Simp (uint16_t *) (mtod(m, caddr_t) + i), 475131192Simp (m->m_len - i) / 2); 47652286Smdodd if ((i = (m->m_len - i) & 1) != 0) { 47752286Smdodd tmp16[0] = *(mtod(m, caddr_t) + 47852286Smdodd m->m_len - 1); 47952286Smdodd } 48052286Smdodd } 481131192Simp if (i) 482131192Simp CSR_WRITE_MULTI_2(sc, IO_PORT_REG, 483131192Simp (uint16_t *) tmp16, 1); 48455881Smdodd /* 48555881Smdodd * If there were other frames chained, update the 48655881Smdodd * chain in the last one. 48755881Smdodd */ 48855881Smdodd if (sc->tx_head != sc->tx_tail) { 48955881Smdodd if (sc->tx_tail != dest) { 490131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, 49155881Smdodd sc->tx_last + XMT_Chain_Point); 492131192Simp CSR_WRITE_2(sc, IO_PORT_REG, dest); 49352286Smdodd } 494131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, 49555881Smdodd sc->tx_last + XMT_Byte_Count); 496131192Simp i = CSR_READ_2(sc, IO_PORT_REG); 497131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, 49855881Smdodd sc->tx_last + XMT_Byte_Count); 499131192Simp CSR_WRITE_2(sc, IO_PORT_REG, i | Ch_bit); 50055881Smdodd } 50155881Smdodd 50255881Smdodd /* 50355881Smdodd * Resume normal operation of the card: 50455881Smdodd * - Make a dummy read to flush the DRAM write 50555881Smdodd * pipeline. 50655881Smdodd * - Enable receive and transmit interrupts. 50755881Smdodd * - Send Transmit or Resume_XMT command, as 50855881Smdodd * appropriate. 50955881Smdodd */ 510131192Simp CSR_READ_2(sc, IO_PORT_REG); 51121769Sjkh#ifdef EX_PSA_INTR 512131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 51321769Sjkh#endif 51455881Smdodd if (sc->tx_head == sc->tx_tail) { 515131192Simp CSR_WRITE_2(sc, XMT_BAR, dest); 516131192Simp CSR_WRITE_1(sc, CMD_REG, Transmit_CMD); 51755881Smdodd sc->tx_head = dest; 51855881Smdodd DODEBUG(Sent_Pkts, printf("Transmit\n");); 51952286Smdodd } else { 520131192Simp CSR_WRITE_1(sc, CMD_REG, Resume_XMT_List_CMD); 52155881Smdodd DODEBUG(Sent_Pkts, printf("Resume\n");); 52252286Smdodd } 52355881Smdodd 52455881Smdodd sc->tx_last = dest; 52555881Smdodd sc->tx_tail = next; 52655881Smdodd 527106937Ssam BPF_MTAP(ifp, opkt); 52855881Smdodd 52955881Smdodd ifp->if_timer = 2; 53055881Smdodd ifp->if_opackets++; 53155881Smdodd m_freem(opkt); 53255881Smdodd } else { 53355881Smdodd ifp->if_flags |= IFF_OACTIVE; 53455881Smdodd DODEBUG(Status, printf("OACTIVE start\n");); 53552286Smdodd } 53621769Sjkh } 53721769Sjkh 53852286Smdodd splx(s); 53921769Sjkh 54052286Smdodd DODEBUG(Start_End, printf("ex_start%d: finish\n", unit);); 54121769Sjkh} 54221769Sjkh 54366440Simpvoid 54452286Smdoddex_stop(struct ex_softc *sc) 54521769Sjkh{ 546131192Simp 54752286Smdodd DODEBUG(Start_End, printf("ex_stop%d: start\n", unit);); 54821769Sjkh 54952286Smdodd /* 55052286Smdodd * Disable card operation: 55152286Smdodd * - Disable the interrupt line. 55252286Smdodd * - Flush transmission and disable reception. 55352286Smdodd * - Mask and clear all interrupts. 55452286Smdodd * - Reset the 82595. 55552286Smdodd */ 556131192Simp CSR_WRITE_1(sc, CMD_REG, Bank1_Sel); 557131192Simp CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) & ~TriST_INT); 558131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 559131192Simp CSR_WRITE_1(sc, CMD_REG, Rcv_Stop); 56052286Smdodd sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 56152286Smdodd sc->tx_last = 0; /* XXX I think these two lines are not necessary, because ex_init will always be called again to reinit the interface. */ 562131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int); 563131192Simp CSR_WRITE_1(sc, STATUS_REG, All_Int); 564131192Simp CSR_WRITE_1(sc, CMD_REG, Reset_CMD); 56552286Smdodd DELAY(200); 56621769Sjkh 56752286Smdodd DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit);); 56852286Smdodd 56952286Smdodd return; 57021769Sjkh} 57121769Sjkh 57259816Smdoddvoid 57355883Smdoddex_intr(void *arg) 57421769Sjkh{ 575131192Simp struct ex_softc *sc = (struct ex_softc *)arg; 576131192Simp struct ifnet *ifp = &sc->arpcom.ac_if; 577131192Simp int int_status, send_pkts; 578131192Simp int loops = 100; 57921769Sjkh 58055883Smdodd DODEBUG(Start_End, printf("ex_intr%d: start\n", unit);); 58121769Sjkh 58252286Smdodd send_pkts = 0; 583131192Simp while (loops-- > 0 && 584131192Simp (int_status = CSR_READ_1(sc, STATUS_REG)) & (Tx_Int | Rx_Int)) { 585131192Simp /* don't loop forever */ 586131192Simp if (int_status == 0xff) 587131192Simp break; 58852286Smdodd if (int_status & Rx_Int) { 589131192Simp CSR_WRITE_1(sc, STATUS_REG, Rx_Int); 59052286Smdodd ex_rx_intr(sc); 59152286Smdodd } else if (int_status & Tx_Int) { 592131192Simp CSR_WRITE_1(sc, STATUS_REG, Tx_Int); 59352286Smdodd ex_tx_intr(sc); 59452286Smdodd send_pkts = 1; 59552286Smdodd } 59652286Smdodd } 597131192Simp if (loops == 0) 598131192Simp printf("100 loops are not enough\n"); 59921769Sjkh 60052286Smdodd /* 60152286Smdodd * If any packet has been transmitted, and there are queued packets to 60252286Smdodd * be sent, attempt to send more packets to the network card. 60352286Smdodd */ 604131192Simp if (send_pkts && (ifp->if_snd.ifq_head != NULL)) 60552286Smdodd ex_start(ifp); 60652286Smdodd 60755883Smdodd DODEBUG(Start_End, printf("ex_intr%d: finish\n", unit);); 60852286Smdodd 60952286Smdodd return; 61021769Sjkh} 61121769Sjkh 61252286Smdoddstatic void 61352286Smdoddex_tx_intr(struct ex_softc *sc) 61421769Sjkh{ 61552286Smdodd struct ifnet * ifp = &sc->arpcom.ac_if; 61652286Smdodd int tx_status; 61721769Sjkh 61852286Smdodd DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit);); 61921769Sjkh 62052286Smdodd /* 62152286Smdodd * - Cancel the watchdog. 62252286Smdodd * For all packets transmitted since last transmit interrupt: 62352286Smdodd * - Advance chain pointer to next queued packet. 62452286Smdodd * - Update statistics. 62552286Smdodd */ 62621769Sjkh 62752286Smdodd ifp->if_timer = 0; 62821769Sjkh 62952286Smdodd while (sc->tx_head != sc->tx_tail) { 630131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->tx_head); 63121769Sjkh 632131192Simp if (! CSR_READ_2(sc, IO_PORT_REG) & Done_bit) 63352286Smdodd break; 63421769Sjkh 635131192Simp tx_status = CSR_READ_2(sc, IO_PORT_REG); 636131192Simp sc->tx_head = CSR_READ_2(sc, IO_PORT_REG); 63752286Smdodd 63852286Smdodd if (tx_status & TX_OK_bit) { 63952286Smdodd ifp->if_opackets++; 64052286Smdodd } else { 64152286Smdodd ifp->if_oerrors++; 64252286Smdodd } 64352286Smdodd 64452286Smdodd ifp->if_collisions += tx_status & No_Collisions_bits; 64552286Smdodd } 64652286Smdodd 64752286Smdodd /* 64852286Smdodd * The card should be ready to accept more packets now. 64952286Smdodd */ 65052286Smdodd 65152286Smdodd ifp->if_flags &= ~IFF_OACTIVE; 65252286Smdodd 65352286Smdodd DODEBUG(Status, printf("OIDLE tx_intr\n");); 65452286Smdodd DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit);); 65552286Smdodd 65652286Smdodd return; 65721769Sjkh} 65821769Sjkh 65952286Smdoddstatic void 66052286Smdoddex_rx_intr(struct ex_softc *sc) 66121769Sjkh{ 66252286Smdodd struct ifnet * ifp = &sc->arpcom.ac_if; 66352286Smdodd int rx_status; 66452286Smdodd int pkt_len; 66552286Smdodd int QQQ; 66652286Smdodd struct mbuf * m; 66752286Smdodd struct mbuf * ipkt; 66852286Smdodd struct ether_header * eh; 66921769Sjkh 67052286Smdodd DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit);); 67121769Sjkh 67252286Smdodd /* 67352286Smdodd * For all packets received since last receive interrupt: 67452286Smdodd * - If packet ok, read it into a new mbuf and queue it to interface, 67552286Smdodd * updating statistics. 67652286Smdodd * - If packet bad, just discard it, and update statistics. 67752286Smdodd * Finally, advance receive stop limit in card's memory to new location. 67852286Smdodd */ 67921769Sjkh 680131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->rx_head); 68121769Sjkh 682131192Simp while (CSR_READ_2(sc, IO_PORT_REG) == RCV_Done) { 68352286Smdodd 684131192Simp rx_status = CSR_READ_2(sc, IO_PORT_REG); 685131192Simp sc->rx_head = CSR_READ_2(sc, IO_PORT_REG); 686131192Simp QQQ = pkt_len = CSR_READ_2(sc, IO_PORT_REG); 68752286Smdodd 68852286Smdodd if (rx_status & RCV_OK_bit) { 689111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 69052286Smdodd ipkt = m; 69152286Smdodd if (ipkt == NULL) { 69252286Smdodd ifp->if_iqdrops++; 69352286Smdodd } else { 69452286Smdodd ipkt->m_pkthdr.rcvif = ifp; 69552286Smdodd ipkt->m_pkthdr.len = pkt_len; 69652286Smdodd ipkt->m_len = MHLEN; 69752286Smdodd 69852286Smdodd while (pkt_len > 0) { 69952286Smdodd if (pkt_len > MINCLSIZE) { 700111119Simp MCLGET(m, M_DONTWAIT); 70152286Smdodd if (m->m_flags & M_EXT) { 70252286Smdodd m->m_len = MCLBYTES; 70352286Smdodd } else { 70452286Smdodd m_freem(ipkt); 70552286Smdodd ifp->if_iqdrops++; 70652286Smdodd goto rx_another; 70752286Smdodd } 70852286Smdodd } 70952286Smdodd m->m_len = min(m->m_len, pkt_len); 71052286Smdodd 71121769Sjkh /* 71221769Sjkh * NOTE: I'm assuming that all mbufs allocated are of even length, 71321769Sjkh * except for the last one in an odd-length packet. 71421769Sjkh */ 71552286Smdodd 716131192Simp CSR_READ_MULTI_2(sc, IO_PORT_REG, 717131192Simp mtod(m, uint16_t *), m->m_len / 2); 71852286Smdodd 71952286Smdodd if (m->m_len & 1) { 720131192Simp *(mtod(m, caddr_t) + m->m_len - 1) = CSR_READ_1(sc, IO_PORT_REG); 72152286Smdodd } 72252286Smdodd pkt_len -= m->m_len; 72352286Smdodd 72452286Smdodd if (pkt_len > 0) { 725111119Simp MGET(m->m_next, M_DONTWAIT, MT_DATA); 72652286Smdodd if (m->m_next == NULL) { 72752286Smdodd m_freem(ipkt); 72852286Smdodd ifp->if_iqdrops++; 72952286Smdodd goto rx_another; 73052286Smdodd } 73152286Smdodd m = m->m_next; 73252286Smdodd m->m_len = MLEN; 73352286Smdodd } 73452286Smdodd } 73552286Smdodd eh = mtod(ipkt, struct ether_header *); 73652286Smdodd#ifdef EXDEBUG 73752286Smdodd if (debug_mask & Rcvd_Pkts) { 73852286Smdodd if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) { 73952286Smdodd printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":"); 74052286Smdodd printf("%6D\n", eh->ether_dhost, ":"); 74152286Smdodd } /* QQQ */ 74221769Sjkh } 74321769Sjkh#endif 744106937Ssam (*ifp->if_input)(ifp, ipkt); 74552286Smdodd ifp->if_ipackets++; 74652286Smdodd } 74752286Smdodd } else { 74852286Smdodd ifp->if_ierrors++; 74921769Sjkh } 750131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->rx_head); 75152286Smdoddrx_another: ; 75221769Sjkh } 75321769Sjkh 75452286Smdodd if (sc->rx_head < sc->rx_lower_limit + 2) 755131192Simp CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_upper_limit); 75652286Smdodd else 757131192Simp CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_head - 2); 75852286Smdodd 75952286Smdodd DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit);); 76052286Smdodd 76152286Smdodd return; 76221769Sjkh} 76321769Sjkh 76421769Sjkh 76555883Smdoddstatic int 76655883Smdoddex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) 76721769Sjkh{ 76852286Smdodd struct ex_softc * sc = ifp->if_softc; 76957987Smdodd struct ifreq * ifr = (struct ifreq *)data; 77052286Smdodd int s; 77152286Smdodd int error = 0; 77221769Sjkh 773121816Sbrooks DODEBUG(Start_End, printf("%s: ex_ioctl: start ", ifp->if_xname);); 77421769Sjkh 77552286Smdodd s = splimp(); 77621769Sjkh 77752286Smdodd switch(cmd) { 77852286Smdodd case SIOCSIFADDR: 77952286Smdodd case SIOCGIFADDR: 78052286Smdodd case SIOCSIFMTU: 78152286Smdodd error = ether_ioctl(ifp, cmd, data); 78252286Smdodd break; 78321769Sjkh 78452286Smdodd case SIOCSIFFLAGS: 78552286Smdodd DODEBUG(Start_End, printf("SIOCSIFFLAGS");); 78652286Smdodd if ((ifp->if_flags & IFF_UP) == 0 && 78752286Smdodd (ifp->if_flags & IFF_RUNNING)) { 78852286Smdodd 78952286Smdodd ifp->if_flags &= ~IFF_RUNNING; 79052286Smdodd ex_stop(sc); 79152286Smdodd } else { 79252286Smdodd ex_init(sc); 79352286Smdodd } 79452286Smdodd break; 79521769Sjkh#ifdef NODEF 79652286Smdodd case SIOCGHWADDR: 79752286Smdodd DODEBUG(Start_End, printf("SIOCGHWADDR");); 79852286Smdodd bcopy((caddr_t)sc->sc_addr, (caddr_t)&ifr->ifr_data, 79952286Smdodd sizeof(sc->sc_addr)); 80052286Smdodd break; 80121769Sjkh#endif 80252286Smdodd case SIOCADDMULTI: 80352286Smdodd case SIOCDELMULTI: 804112731Smdodd ex_init(sc); 805112731Smdodd error = 0; 80652286Smdodd break; 80757987Smdodd case SIOCSIFMEDIA: 80857987Smdodd case SIOCGIFMEDIA: 80957987Smdodd error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd); 81057987Smdodd break; 81152286Smdodd default: 81252286Smdodd DODEBUG(Start_End, printf("unknown");); 81352286Smdodd error = EINVAL; 81452286Smdodd } 81521769Sjkh 81652286Smdodd splx(s); 81721769Sjkh 818121816Sbrooks DODEBUG(Start_End, printf("\n%s: ex_ioctl: finish\n", ifp->if_xname);); 81952286Smdodd 82052286Smdodd return(error); 82121769Sjkh} 82221769Sjkh 823112731Smdoddstatic void 824112731Smdoddex_setmulti(struct ex_softc *sc) 825112731Smdodd{ 826112731Smdodd struct ifnet *ifp; 827112731Smdodd struct ifmultiaddr *maddr; 828131192Simp uint16_t *addr; 829112731Smdodd int count; 830112731Smdodd int timeout, status; 831112731Smdodd 832112731Smdodd ifp = &sc->arpcom.ac_if; 83321769Sjkh 834112731Smdodd count = 0; 835112731Smdodd TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) { 836112731Smdodd if (maddr->ifma_addr->sa_family != AF_LINK) 837112731Smdodd continue; 838112731Smdodd count++; 839112731Smdodd } 840112731Smdodd 841112731Smdodd if ((ifp->if_flags & IFF_PROMISC) || (ifp->if_flags & IFF_ALLMULTI) 842112731Smdodd || count > 63) { 843112731Smdodd /* Interface is in promiscuous mode or there are too many 844112731Smdodd * multicast addresses for the card to handle */ 845131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 846131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | Promisc_Mode); 847131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3)); 848131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 849112731Smdodd } 850112731Smdodd else if ((ifp->if_flags & IFF_MULTICAST) && (count > 0)) { 851112731Smdodd /* Program multicast addresses plus our MAC address 852112731Smdodd * into the filter */ 853131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 854131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | Multi_IA); 855131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3)); 856131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 857112731Smdodd 858112731Smdodd /* Borrow space from TX buffer; this should be safe 859112731Smdodd * as this is only called from ex_init */ 860112731Smdodd 861131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->tx_lower_limit); 862131192Simp CSR_WRITE_2(sc, IO_PORT_REG, MC_Setup_CMD); 863131192Simp CSR_WRITE_2(sc, IO_PORT_REG, 0); 864131192Simp CSR_WRITE_2(sc, IO_PORT_REG, 0); 865131192Simp CSR_WRITE_2(sc, IO_PORT_REG, (count + 1) * 6); 866112731Smdodd 867112731Smdodd TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) { 868112731Smdodd if (maddr->ifma_addr->sa_family != AF_LINK) 869112731Smdodd continue; 870112731Smdodd 871131192Simp addr = (uint16_t*)LLADDR((struct sockaddr_dl *) 872112731Smdodd maddr->ifma_addr); 873131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 874131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 875131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 876112731Smdodd } 877112731Smdodd 878112731Smdodd /* Program our MAC address as well */ 879112731Smdodd /* XXX: Is this necessary? The Linux driver does this 880112731Smdodd * but the NetBSD driver does not */ 881131192Simp addr = (uint16_t*)(&sc->arpcom.ac_enaddr); 882131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 883131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 884131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 885112731Smdodd 886131192Simp CSR_READ_2(sc, IO_PORT_REG); 887131192Simp CSR_WRITE_2(sc, XMT_BAR, sc->tx_lower_limit); 888131192Simp CSR_WRITE_1(sc, CMD_REG, MC_Setup_CMD); 889112731Smdodd 890112731Smdodd sc->tx_head = sc->tx_lower_limit; 891112731Smdodd sc->tx_tail = sc->tx_head + XMT_HEADER_LEN + (count + 1) * 6; 892112731Smdodd 893112731Smdodd for (timeout=0; timeout<100; timeout++) { 894112731Smdodd DELAY(2); 895131192Simp if ((CSR_READ_1(sc, STATUS_REG) & Exec_Int) == 0) 896112731Smdodd continue; 897112731Smdodd 898131192Simp status = CSR_READ_1(sc, CMD_REG); 899131192Simp CSR_WRITE_1(sc, STATUS_REG, Exec_Int); 900112731Smdodd break; 901112731Smdodd } 902112731Smdodd 903112731Smdodd sc->tx_head = sc->tx_tail; 904112731Smdodd } 905112731Smdodd else 906112731Smdodd { 907112731Smdodd /* No multicast or promiscuous mode */ 908131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 909131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) & 0xDE); 910112731Smdodd /* ~(Multi_IA | Promisc_Mode) */ 911131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3)); 912131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 913112731Smdodd } 914112731Smdodd} 915112731Smdodd 91652286Smdoddstatic void 91752286Smdoddex_reset(struct ex_softc *sc) 91821769Sjkh{ 91952286Smdodd int s; 92021769Sjkh 92152286Smdodd DODEBUG(Start_End, printf("ex_reset%d: start\n", unit);); 92221769Sjkh 92352286Smdodd s = splimp(); 92421769Sjkh 92552286Smdodd ex_stop(sc); 92652286Smdodd ex_init(sc); 92721769Sjkh 92852286Smdodd splx(s); 92921769Sjkh 93052286Smdodd DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit);); 93152286Smdodd 93252286Smdodd return; 93321769Sjkh} 93421769Sjkh 93552286Smdoddstatic void 93652286Smdoddex_watchdog(struct ifnet *ifp) 93721769Sjkh{ 93852286Smdodd struct ex_softc * sc = ifp->if_softc; 93921769Sjkh 940121816Sbrooks DODEBUG(Start_End, printf("%s: ex_watchdog: start\n", ifp->if_xname);); 94121769Sjkh 94252286Smdodd ifp->if_flags &= ~IFF_OACTIVE; 94321769Sjkh 94452286Smdodd DODEBUG(Status, printf("OIDLE watchdog\n");); 94552286Smdodd 94652286Smdodd ifp->if_oerrors++; 94752286Smdodd ex_reset(sc); 94852286Smdodd ex_start(ifp); 94952286Smdodd 950121816Sbrooks DODEBUG(Start_End, printf("%s: ex_watchdog: finish\n", ifp->if_xname);); 95152286Smdodd 95252286Smdodd return; 95321769Sjkh} 95421769Sjkh 95557987Smdoddstatic int 956131192Simpex_get_media(struct ex_softc *sc) 95759816Smdodd{ 958112764Smdodd int current; 959112764Smdodd int media; 96059816Smdodd 961131192Simp media = ex_eeprom_read(sc, EE_W5); 962112764Smdodd 963131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 964131192Simp current = CSR_READ_1(sc, REG3); 965131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 96659816Smdodd 967112764Smdodd if ((current & TPE_bit) && (media & EE_W5_PORT_TPE)) 96859816Smdodd return(IFM_ETHER|IFM_10_T); 969112764Smdodd if ((current & BNC_bit) && (media & EE_W5_PORT_BNC)) 97059816Smdodd return(IFM_ETHER|IFM_10_2); 97159816Smdodd 972112764Smdodd if (media & EE_W5_PORT_AUI) 973112764Smdodd return (IFM_ETHER|IFM_10_5); 974112764Smdodd 975112764Smdodd return (IFM_ETHER|IFM_AUTO); 97659816Smdodd} 97759816Smdodd 97859816Smdoddstatic int 979131192Simpex_ifmedia_upd(ifp) 98057987Smdodd struct ifnet * ifp; 98157987Smdodd{ 982112764Smdodd struct ex_softc * sc = ifp->if_softc; 98321769Sjkh 984112764Smdodd if (IFM_TYPE(sc->ifmedia.ifm_media) != IFM_ETHER) 985112764Smdodd return EINVAL; 986112764Smdodd 98757987Smdodd return (0); 98857987Smdodd} 98957987Smdodd 99057987Smdoddstatic void 99157987Smdoddex_ifmedia_sts(ifp, ifmr) 99257987Smdodd struct ifnet * ifp; 99357987Smdodd struct ifmediareq * ifmr; 99457987Smdodd{ 99557987Smdodd struct ex_softc * sc = ifp->if_softc; 99657987Smdodd 997131192Simp ifmr->ifm_active = ex_get_media(sc); 998112764Smdodd ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 99957987Smdodd 100057987Smdodd return; 100157987Smdodd} 100257987Smdodd 100359816Smdoddu_short 1004131192Simpex_eeprom_read(struct ex_softc *sc, int location) 100521769Sjkh{ 100621769Sjkh int i; 100721769Sjkh u_short data = 0; 100821769Sjkh int read_cmd = location | EE_READ_CMD; 100921769Sjkh short ctrl_val = EECS; 101021769Sjkh 1011131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 1012131192Simp CSR_WRITE_1(sc, EEPROM_REG, EECS); 101321769Sjkh for (i = 8; i >= 0; i--) { 101421769Sjkh short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val; 1015131192Simp CSR_WRITE_1(sc, EEPROM_REG, outval); 1016131192Simp CSR_WRITE_1(sc, EEPROM_REG, outval | EESK); 101721769Sjkh DELAY(3); 1018131192Simp CSR_WRITE_1(sc, EEPROM_REG, outval); 101921769Sjkh DELAY(2); 102021769Sjkh } 1021131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val); 102221769Sjkh 102321769Sjkh for (i = 16; i > 0; i--) { 1024131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val | EESK); 102521769Sjkh DELAY(3); 1026131192Simp data = (data << 1) | 1027131192Simp ((CSR_READ_1(sc, EEPROM_REG) & EEDO) ? 1 : 0); 1028131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val); 102921769Sjkh DELAY(2); 103021769Sjkh } 103121769Sjkh 103221769Sjkh ctrl_val &= ~EECS; 1033131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val | EESK); 103421769Sjkh DELAY(3); 1035131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val); 103621769Sjkh DELAY(2); 1037131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 103821769Sjkh return(data); 103921769Sjkh} 1040