if_ex.c revision 139749
1139749Simp/*- 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 139749 2005-01-06 01:43:34Z 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; 226133684Srwatson ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST | 227133684Srwatson IFF_NEEDSGIANT; 22821769Sjkh ifp->if_start = ex_start; 22921769Sjkh ifp->if_ioctl = ex_ioctl; 23021769Sjkh ifp->if_watchdog = ex_watchdog; 23155883Smdodd ifp->if_init = ex_init; 23255883Smdodd ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 23321769Sjkh 23457987Smdodd ifmedia_init(&sc->ifmedia, 0, ex_ifmedia_upd, ex_ifmedia_sts); 23557987Smdodd 236131192Simp temp = ex_eeprom_read(sc, EE_W5); 23757987Smdodd if (temp & EE_W5_PORT_TPE) 23857987Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 23957987Smdodd if (temp & EE_W5_PORT_BNC) 24057987Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL); 24157987Smdodd if (temp & EE_W5_PORT_AUI) 24257987Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL); 24357987Smdodd 244112764Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 245112764Smdodd ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL); 246131192Simp ifmedia_set(&sc->ifmedia, ex_get_media(sc)); 24757987Smdodd 24857987Smdodd ifm = &sc->ifmedia; 24957987Smdodd ifm->ifm_media = ifm->ifm_cur->ifm_media; 25057987Smdodd ex_ifmedia_upd(ifp); 25157987Smdodd 25221769Sjkh /* 25321769Sjkh * Attach the interface. 25421769Sjkh */ 255106937Ssam ether_ifattach(ifp, sc->arpcom.ac_enaddr); 25621769Sjkh 25752286Smdodd return(0); 25821769Sjkh} 25921769Sjkh 260112800Smdoddint 261131192Simpex_detach(device_t dev) 262112800Smdodd{ 263112800Smdodd struct ex_softc *sc; 264112800Smdodd struct ifnet *ifp; 265112800Smdodd 266112800Smdodd sc = device_get_softc(dev); 267112800Smdodd ifp = &sc->arpcom.ac_if; 268112800Smdodd 269112800Smdodd ex_stop(sc); 270112800Smdodd 271112800Smdodd ifp->if_flags &= ~IFF_RUNNING; 272112800Smdodd ether_ifdetach(ifp); 273112800Smdodd 274112800Smdodd ex_release_resources(dev); 275112800Smdodd 276112800Smdodd return (0); 277112800Smdodd} 278112800Smdodd 27955883Smdoddstatic void 28055883Smdoddex_init(void *xsc) 28121769Sjkh{ 28252286Smdodd struct ex_softc * sc = (struct ex_softc *) xsc; 28352286Smdodd struct ifnet * ifp = &sc->arpcom.ac_if; 28452286Smdodd int s; 28552286Smdodd int i; 28652286Smdodd unsigned short temp_reg; 28721769Sjkh 288121816Sbrooks DODEBUG(Start_End, printf("%s: ex_init: start\n", ifp->if_xname);); 28921769Sjkh 29021769Sjkh s = splimp(); 29159816Smdodd ifp->if_timer = 0; 29221769Sjkh 29321769Sjkh /* 29421769Sjkh * Load the ethernet address into the card. 29521769Sjkh */ 296131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 297131192Simp temp_reg = CSR_READ_1(sc, EEPROM_REG); 29852286Smdodd if (temp_reg & Trnoff_Enable) { 299131192Simp CSR_WRITE_1(sc, EEPROM_REG, temp_reg & ~Trnoff_Enable); 30052286Smdodd } 30152286Smdodd for (i = 0; i < ETHER_ADDR_LEN; i++) { 302131192Simp CSR_WRITE_1(sc, I_ADDR_REG0 + i, sc->arpcom.ac_enaddr[i]); 30352286Smdodd } 30421769Sjkh /* 30521769Sjkh * - Setup transmit chaining and discard bad received frames. 30621769Sjkh * - Match broadcast. 30721769Sjkh * - Clear test mode. 30821769Sjkh * - Set receiving mode. 30921769Sjkh * - Set IRQ number. 31021769Sjkh */ 311131192Simp CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) | Tx_Chn_Int_Md | Tx_Chn_ErStp | Disc_Bad_Fr); 312131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | No_SA_Ins | RX_CRC_InMem); 313131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3) & 0x3f /* XXX constants. */ ); 314131192Simp CSR_WRITE_1(sc, CMD_REG, Bank1_Sel); 315131192Simp CSR_WRITE_1(sc, INT_NO_REG, (CSR_READ_1(sc, INT_NO_REG) & 0xf8) | sc->irq2ee[sc->irq_no]); 31621769Sjkh 31721769Sjkh /* 31821769Sjkh * Divide the available memory in the card into rcv and xmt buffers. 31921769Sjkh * By default, I use the first 3/4 of the memory for the rcv buffer, 32021769Sjkh * and the remaining 1/4 of the memory for the xmt buffer. 32121769Sjkh */ 32221769Sjkh sc->rx_mem_size = sc->mem_size * 3 / 4; 32321769Sjkh sc->tx_mem_size = sc->mem_size - sc->rx_mem_size; 32421769Sjkh sc->rx_lower_limit = 0x0000; 32521769Sjkh sc->rx_upper_limit = sc->rx_mem_size - 2; 32621769Sjkh sc->tx_lower_limit = sc->rx_mem_size; 32721769Sjkh sc->tx_upper_limit = sc->mem_size - 2; 328131192Simp CSR_WRITE_1(sc, RCV_LOWER_LIMIT_REG, sc->rx_lower_limit >> 8); 329131192Simp CSR_WRITE_1(sc, RCV_UPPER_LIMIT_REG, sc->rx_upper_limit >> 8); 330131192Simp CSR_WRITE_1(sc, XMT_LOWER_LIMIT_REG, sc->tx_lower_limit >> 8); 331131192Simp CSR_WRITE_1(sc, XMT_UPPER_LIMIT_REG, sc->tx_upper_limit >> 8); 33221769Sjkh 33321769Sjkh /* 33421769Sjkh * Enable receive and transmit interrupts, and clear any pending int. 33521769Sjkh */ 336131192Simp CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) | TriST_INT); 337131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 338131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 339131192Simp CSR_WRITE_1(sc, STATUS_REG, All_Int); 34021769Sjkh 34121769Sjkh /* 34221769Sjkh * Initialize receive and transmit ring buffers. 34321769Sjkh */ 344131192Simp CSR_WRITE_2(sc, RCV_BAR, sc->rx_lower_limit); 34521769Sjkh sc->rx_head = sc->rx_lower_limit; 346131192Simp CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_upper_limit | 0xfe); 347131192Simp CSR_WRITE_2(sc, XMT_BAR, sc->tx_lower_limit); 34821769Sjkh sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 34921769Sjkh 35021769Sjkh ifp->if_flags |= IFF_RUNNING; 35121769Sjkh ifp->if_flags &= ~IFF_OACTIVE; 35221769Sjkh DODEBUG(Status, printf("OIDLE init\n");); 35321769Sjkh 354112731Smdodd ex_setmulti(sc); 355112731Smdodd 35621769Sjkh /* 35721769Sjkh * Final reset of the board, and enable operation. 35821769Sjkh */ 359131192Simp CSR_WRITE_1(sc, CMD_REG, Sel_Reset_CMD); 36021769Sjkh DELAY(2); 361131192Simp CSR_WRITE_1(sc, CMD_REG, Rcv_Enable_CMD); 36221769Sjkh 36321769Sjkh ex_start(ifp); 36421769Sjkh splx(s); 36521769Sjkh 366121816Sbrooks DODEBUG(Start_End, printf("%s: ex_init: finish\n", ifp->if_xname);); 36721769Sjkh} 36821769Sjkh 36921769Sjkh 37055883Smdoddstatic void 37152286Smdoddex_start(struct ifnet *ifp) 37221769Sjkh{ 37352286Smdodd struct ex_softc * sc = ifp->if_softc; 37452286Smdodd int i, s, len, data_len, avail, dest, next; 37552286Smdodd unsigned char tmp16[2]; 37652286Smdodd struct mbuf * opkt; 37752286Smdodd struct mbuf * m; 37821769Sjkh 37952286Smdodd DODEBUG(Start_End, printf("ex_start%d: start\n", unit);); 38021769Sjkh 38152286Smdodd s = splimp(); 38221769Sjkh 38352286Smdodd /* 38452286Smdodd * Main loop: send outgoing packets to network card until there are no 38552286Smdodd * more packets left, or the card cannot accept any more yet. 38652286Smdodd */ 38752286Smdodd while (((opkt = ifp->if_snd.ifq_head) != NULL) && 38852286Smdodd !(ifp->if_flags & IFF_OACTIVE)) { 38921769Sjkh 39052286Smdodd /* 39152286Smdodd * Ensure there is enough free transmit buffer space for 39252286Smdodd * this packet, including its header. Note: the header 39352286Smdodd * cannot wrap around the end of the transmit buffer and 39452286Smdodd * must be kept together, so we allow space for twice the 39552286Smdodd * length of the header, just in case. 39652286Smdodd */ 39721769Sjkh 39852286Smdodd for (len = 0, m = opkt; m != NULL; m = m->m_next) { 39952286Smdodd len += m->m_len; 40052286Smdodd } 40152286Smdodd 40252286Smdodd data_len = len; 40352286Smdodd 40452286Smdodd DODEBUG(Sent_Pkts, printf("1. Sending packet with %d data bytes. ", data_len);); 40552286Smdodd 40652286Smdodd if (len & 1) { 40752286Smdodd len += XMT_HEADER_LEN + 1; 40852286Smdodd } else { 40952286Smdodd len += XMT_HEADER_LEN; 41052286Smdodd } 41152286Smdodd 41252286Smdodd if ((i = sc->tx_tail - sc->tx_head) >= 0) { 41352286Smdodd avail = sc->tx_mem_size - i; 41452286Smdodd } else { 41552286Smdodd avail = -i; 41652286Smdodd } 41752286Smdodd 41852286Smdodd DODEBUG(Sent_Pkts, printf("i=%d, avail=%d\n", i, avail);); 41952286Smdodd 42052286Smdodd if (avail >= len + XMT_HEADER_LEN) { 42152286Smdodd IF_DEQUEUE(&ifp->if_snd, opkt); 42252286Smdodd 42321769Sjkh#ifdef EX_PSA_INTR 42452286Smdodd /* 42552286Smdodd * Disable rx and tx interrupts, to avoid corruption 42652286Smdodd * of the host address register by interrupt service 42752286Smdodd * routines. 42852286Smdodd * XXX Is this necessary with splimp() enabled? 42952286Smdodd */ 430131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int); 43121769Sjkh#endif 43221769Sjkh 43352286Smdodd /* 43452286Smdodd * Compute the start and end addresses of this 43552286Smdodd * frame in the tx buffer. 43652286Smdodd */ 43752286Smdodd dest = sc->tx_tail; 43852286Smdodd next = dest + len; 43921769Sjkh 44052286Smdodd if (next > sc->tx_upper_limit) { 44152286Smdodd if ((sc->tx_upper_limit + 2 - sc->tx_tail) <= 44252286Smdodd XMT_HEADER_LEN) { 44352286Smdodd dest = sc->tx_lower_limit; 44452286Smdodd next = dest + len; 44555881Smdodd } else { 44655881Smdodd next = sc->tx_lower_limit + 44755881Smdodd next - sc->tx_upper_limit - 2; 44852286Smdodd } 44952286Smdodd } 45021769Sjkh 45152286Smdodd /* 45252286Smdodd * Build the packet frame in the card's ring buffer. 45352286Smdodd */ 45452286Smdodd DODEBUG(Sent_Pkts, printf("2. dest=%d, next=%d. ", dest, next);); 45521769Sjkh 456131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, dest); 457131192Simp CSR_WRITE_2(sc, IO_PORT_REG, Transmit_CMD); 458131192Simp CSR_WRITE_2(sc, IO_PORT_REG, 0); 459131192Simp CSR_WRITE_2(sc, IO_PORT_REG, next); 460131192Simp CSR_WRITE_2(sc, IO_PORT_REG, data_len); 46121769Sjkh 46252286Smdodd /* 46352286Smdodd * Output the packet data to the card. Ensure all 46452286Smdodd * transfers are 16-bit wide, even if individual 46552286Smdodd * mbufs have odd length. 46652286Smdodd */ 46752286Smdodd for (m = opkt, i = 0; m != NULL; m = m->m_next) { 46852286Smdodd DODEBUG(Sent_Pkts, printf("[%d]", m->m_len);); 46952286Smdodd if (i) { 47052286Smdodd tmp16[1] = *(mtod(m, caddr_t)); 471131192Simp CSR_WRITE_MULTI_2(sc, IO_PORT_REG, 472131192Simp (uint16_t *) tmp16, 1); 47352286Smdodd } 474131192Simp CSR_WRITE_MULTI_2(sc, IO_PORT_REG, 475131192Simp (uint16_t *) (mtod(m, caddr_t) + i), 476131192Simp (m->m_len - i) / 2); 47752286Smdodd if ((i = (m->m_len - i) & 1) != 0) { 47852286Smdodd tmp16[0] = *(mtod(m, caddr_t) + 47952286Smdodd m->m_len - 1); 48052286Smdodd } 48152286Smdodd } 482131192Simp if (i) 483131192Simp CSR_WRITE_MULTI_2(sc, IO_PORT_REG, 484131192Simp (uint16_t *) tmp16, 1); 48555881Smdodd /* 48655881Smdodd * If there were other frames chained, update the 48755881Smdodd * chain in the last one. 48855881Smdodd */ 48955881Smdodd if (sc->tx_head != sc->tx_tail) { 49055881Smdodd if (sc->tx_tail != dest) { 491131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, 49255881Smdodd sc->tx_last + XMT_Chain_Point); 493131192Simp CSR_WRITE_2(sc, IO_PORT_REG, dest); 49452286Smdodd } 495131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, 49655881Smdodd sc->tx_last + XMT_Byte_Count); 497131192Simp i = CSR_READ_2(sc, IO_PORT_REG); 498131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, 49955881Smdodd sc->tx_last + XMT_Byte_Count); 500131192Simp CSR_WRITE_2(sc, IO_PORT_REG, i | Ch_bit); 50155881Smdodd } 50255881Smdodd 50355881Smdodd /* 50455881Smdodd * Resume normal operation of the card: 50555881Smdodd * - Make a dummy read to flush the DRAM write 50655881Smdodd * pipeline. 50755881Smdodd * - Enable receive and transmit interrupts. 50855881Smdodd * - Send Transmit or Resume_XMT command, as 50955881Smdodd * appropriate. 51055881Smdodd */ 511131192Simp CSR_READ_2(sc, IO_PORT_REG); 51221769Sjkh#ifdef EX_PSA_INTR 513131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int & ~(Rx_Int | Tx_Int)); 51421769Sjkh#endif 51555881Smdodd if (sc->tx_head == sc->tx_tail) { 516131192Simp CSR_WRITE_2(sc, XMT_BAR, dest); 517131192Simp CSR_WRITE_1(sc, CMD_REG, Transmit_CMD); 51855881Smdodd sc->tx_head = dest; 51955881Smdodd DODEBUG(Sent_Pkts, printf("Transmit\n");); 52052286Smdodd } else { 521131192Simp CSR_WRITE_1(sc, CMD_REG, Resume_XMT_List_CMD); 52255881Smdodd DODEBUG(Sent_Pkts, printf("Resume\n");); 52352286Smdodd } 52455881Smdodd 52555881Smdodd sc->tx_last = dest; 52655881Smdodd sc->tx_tail = next; 52755881Smdodd 528106937Ssam BPF_MTAP(ifp, opkt); 52955881Smdodd 53055881Smdodd ifp->if_timer = 2; 53155881Smdodd ifp->if_opackets++; 53255881Smdodd m_freem(opkt); 53355881Smdodd } else { 53455881Smdodd ifp->if_flags |= IFF_OACTIVE; 53555881Smdodd DODEBUG(Status, printf("OACTIVE start\n");); 53652286Smdodd } 53721769Sjkh } 53821769Sjkh 53952286Smdodd splx(s); 54021769Sjkh 54152286Smdodd DODEBUG(Start_End, printf("ex_start%d: finish\n", unit);); 54221769Sjkh} 54321769Sjkh 54466440Simpvoid 54552286Smdoddex_stop(struct ex_softc *sc) 54621769Sjkh{ 547131192Simp 54852286Smdodd DODEBUG(Start_End, printf("ex_stop%d: start\n", unit);); 54921769Sjkh 55052286Smdodd /* 55152286Smdodd * Disable card operation: 55252286Smdodd * - Disable the interrupt line. 55352286Smdodd * - Flush transmission and disable reception. 55452286Smdodd * - Mask and clear all interrupts. 55552286Smdodd * - Reset the 82595. 55652286Smdodd */ 557131192Simp CSR_WRITE_1(sc, CMD_REG, Bank1_Sel); 558131192Simp CSR_WRITE_1(sc, REG1, CSR_READ_1(sc, REG1) & ~TriST_INT); 559131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 560131192Simp CSR_WRITE_1(sc, CMD_REG, Rcv_Stop); 56152286Smdodd sc->tx_head = sc->tx_tail = sc->tx_lower_limit; 56252286Smdodd 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. */ 563131192Simp CSR_WRITE_1(sc, MASK_REG, All_Int); 564131192Simp CSR_WRITE_1(sc, STATUS_REG, All_Int); 565131192Simp CSR_WRITE_1(sc, CMD_REG, Reset_CMD); 56652286Smdodd DELAY(200); 56721769Sjkh 56852286Smdodd DODEBUG(Start_End, printf("ex_stop%d: finish\n", unit);); 56952286Smdodd 57052286Smdodd return; 57121769Sjkh} 57221769Sjkh 57359816Smdoddvoid 57455883Smdoddex_intr(void *arg) 57521769Sjkh{ 576131192Simp struct ex_softc *sc = (struct ex_softc *)arg; 577131192Simp struct ifnet *ifp = &sc->arpcom.ac_if; 578131192Simp int int_status, send_pkts; 579131192Simp int loops = 100; 58021769Sjkh 58155883Smdodd DODEBUG(Start_End, printf("ex_intr%d: start\n", unit);); 58221769Sjkh 58352286Smdodd send_pkts = 0; 584131192Simp while (loops-- > 0 && 585131192Simp (int_status = CSR_READ_1(sc, STATUS_REG)) & (Tx_Int | Rx_Int)) { 586131192Simp /* don't loop forever */ 587131192Simp if (int_status == 0xff) 588131192Simp break; 58952286Smdodd if (int_status & Rx_Int) { 590131192Simp CSR_WRITE_1(sc, STATUS_REG, Rx_Int); 59152286Smdodd ex_rx_intr(sc); 59252286Smdodd } else if (int_status & Tx_Int) { 593131192Simp CSR_WRITE_1(sc, STATUS_REG, Tx_Int); 59452286Smdodd ex_tx_intr(sc); 59552286Smdodd send_pkts = 1; 59652286Smdodd } 59752286Smdodd } 598131192Simp if (loops == 0) 599131192Simp printf("100 loops are not enough\n"); 60021769Sjkh 60152286Smdodd /* 60252286Smdodd * If any packet has been transmitted, and there are queued packets to 60352286Smdodd * be sent, attempt to send more packets to the network card. 60452286Smdodd */ 605131192Simp if (send_pkts && (ifp->if_snd.ifq_head != NULL)) 60652286Smdodd ex_start(ifp); 60752286Smdodd 60855883Smdodd DODEBUG(Start_End, printf("ex_intr%d: finish\n", unit);); 60952286Smdodd 61052286Smdodd return; 61121769Sjkh} 61221769Sjkh 61352286Smdoddstatic void 61452286Smdoddex_tx_intr(struct ex_softc *sc) 61521769Sjkh{ 61652286Smdodd struct ifnet * ifp = &sc->arpcom.ac_if; 61752286Smdodd int tx_status; 61821769Sjkh 61952286Smdodd DODEBUG(Start_End, printf("ex_tx_intr%d: start\n", unit);); 62021769Sjkh 62152286Smdodd /* 62252286Smdodd * - Cancel the watchdog. 62352286Smdodd * For all packets transmitted since last transmit interrupt: 62452286Smdodd * - Advance chain pointer to next queued packet. 62552286Smdodd * - Update statistics. 62652286Smdodd */ 62721769Sjkh 62852286Smdodd ifp->if_timer = 0; 62921769Sjkh 63052286Smdodd while (sc->tx_head != sc->tx_tail) { 631131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->tx_head); 63221769Sjkh 633131192Simp if (! CSR_READ_2(sc, IO_PORT_REG) & Done_bit) 63452286Smdodd break; 63521769Sjkh 636131192Simp tx_status = CSR_READ_2(sc, IO_PORT_REG); 637131192Simp sc->tx_head = CSR_READ_2(sc, IO_PORT_REG); 63852286Smdodd 63952286Smdodd if (tx_status & TX_OK_bit) { 64052286Smdodd ifp->if_opackets++; 64152286Smdodd } else { 64252286Smdodd ifp->if_oerrors++; 64352286Smdodd } 64452286Smdodd 64552286Smdodd ifp->if_collisions += tx_status & No_Collisions_bits; 64652286Smdodd } 64752286Smdodd 64852286Smdodd /* 64952286Smdodd * The card should be ready to accept more packets now. 65052286Smdodd */ 65152286Smdodd 65252286Smdodd ifp->if_flags &= ~IFF_OACTIVE; 65352286Smdodd 65452286Smdodd DODEBUG(Status, printf("OIDLE tx_intr\n");); 65552286Smdodd DODEBUG(Start_End, printf("ex_tx_intr%d: finish\n", unit);); 65652286Smdodd 65752286Smdodd return; 65821769Sjkh} 65921769Sjkh 66052286Smdoddstatic void 66152286Smdoddex_rx_intr(struct ex_softc *sc) 66221769Sjkh{ 66352286Smdodd struct ifnet * ifp = &sc->arpcom.ac_if; 66452286Smdodd int rx_status; 66552286Smdodd int pkt_len; 66652286Smdodd int QQQ; 66752286Smdodd struct mbuf * m; 66852286Smdodd struct mbuf * ipkt; 66952286Smdodd struct ether_header * eh; 67021769Sjkh 67152286Smdodd DODEBUG(Start_End, printf("ex_rx_intr%d: start\n", unit);); 67221769Sjkh 67352286Smdodd /* 67452286Smdodd * For all packets received since last receive interrupt: 67552286Smdodd * - If packet ok, read it into a new mbuf and queue it to interface, 67652286Smdodd * updating statistics. 67752286Smdodd * - If packet bad, just discard it, and update statistics. 67852286Smdodd * Finally, advance receive stop limit in card's memory to new location. 67952286Smdodd */ 68021769Sjkh 681131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->rx_head); 68221769Sjkh 683131192Simp while (CSR_READ_2(sc, IO_PORT_REG) == RCV_Done) { 68452286Smdodd 685131192Simp rx_status = CSR_READ_2(sc, IO_PORT_REG); 686131192Simp sc->rx_head = CSR_READ_2(sc, IO_PORT_REG); 687131192Simp QQQ = pkt_len = CSR_READ_2(sc, IO_PORT_REG); 68852286Smdodd 68952286Smdodd if (rx_status & RCV_OK_bit) { 690111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 69152286Smdodd ipkt = m; 69252286Smdodd if (ipkt == NULL) { 69352286Smdodd ifp->if_iqdrops++; 69452286Smdodd } else { 69552286Smdodd ipkt->m_pkthdr.rcvif = ifp; 69652286Smdodd ipkt->m_pkthdr.len = pkt_len; 69752286Smdodd ipkt->m_len = MHLEN; 69852286Smdodd 69952286Smdodd while (pkt_len > 0) { 700136625Sglebius if (pkt_len >= MINCLSIZE) { 701111119Simp MCLGET(m, M_DONTWAIT); 70252286Smdodd if (m->m_flags & M_EXT) { 70352286Smdodd m->m_len = MCLBYTES; 70452286Smdodd } else { 70552286Smdodd m_freem(ipkt); 70652286Smdodd ifp->if_iqdrops++; 70752286Smdodd goto rx_another; 70852286Smdodd } 70952286Smdodd } 71052286Smdodd m->m_len = min(m->m_len, pkt_len); 71152286Smdodd 71221769Sjkh /* 71321769Sjkh * NOTE: I'm assuming that all mbufs allocated are of even length, 71421769Sjkh * except for the last one in an odd-length packet. 71521769Sjkh */ 71652286Smdodd 717131192Simp CSR_READ_MULTI_2(sc, IO_PORT_REG, 718131192Simp mtod(m, uint16_t *), m->m_len / 2); 71952286Smdodd 72052286Smdodd if (m->m_len & 1) { 721131192Simp *(mtod(m, caddr_t) + m->m_len - 1) = CSR_READ_1(sc, IO_PORT_REG); 72252286Smdodd } 72352286Smdodd pkt_len -= m->m_len; 72452286Smdodd 72552286Smdodd if (pkt_len > 0) { 726111119Simp MGET(m->m_next, M_DONTWAIT, MT_DATA); 72752286Smdodd if (m->m_next == NULL) { 72852286Smdodd m_freem(ipkt); 72952286Smdodd ifp->if_iqdrops++; 73052286Smdodd goto rx_another; 73152286Smdodd } 73252286Smdodd m = m->m_next; 73352286Smdodd m->m_len = MLEN; 73452286Smdodd } 73552286Smdodd } 73652286Smdodd eh = mtod(ipkt, struct ether_header *); 73752286Smdodd#ifdef EXDEBUG 73852286Smdodd if (debug_mask & Rcvd_Pkts) { 73952286Smdodd if ((eh->ether_dhost[5] != 0xff) || (eh->ether_dhost[0] != 0xff)) { 74052286Smdodd printf("Receive packet with %d data bytes: %6D -> ", QQQ, eh->ether_shost, ":"); 74152286Smdodd printf("%6D\n", eh->ether_dhost, ":"); 74252286Smdodd } /* QQQ */ 74321769Sjkh } 74421769Sjkh#endif 745106937Ssam (*ifp->if_input)(ifp, ipkt); 74652286Smdodd ifp->if_ipackets++; 74752286Smdodd } 74852286Smdodd } else { 74952286Smdodd ifp->if_ierrors++; 75021769Sjkh } 751131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->rx_head); 75252286Smdoddrx_another: ; 75321769Sjkh } 75421769Sjkh 75552286Smdodd if (sc->rx_head < sc->rx_lower_limit + 2) 756131192Simp CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_upper_limit); 75752286Smdodd else 758131192Simp CSR_WRITE_2(sc, RCV_STOP_REG, sc->rx_head - 2); 75952286Smdodd 76052286Smdodd DODEBUG(Start_End, printf("ex_rx_intr%d: finish\n", unit);); 76152286Smdodd 76252286Smdodd return; 76321769Sjkh} 76421769Sjkh 76521769Sjkh 76655883Smdoddstatic int 76755883Smdoddex_ioctl(register struct ifnet *ifp, u_long cmd, caddr_t data) 76821769Sjkh{ 76952286Smdodd struct ex_softc * sc = ifp->if_softc; 77057987Smdodd struct ifreq * ifr = (struct ifreq *)data; 77152286Smdodd int s; 77252286Smdodd int error = 0; 77321769Sjkh 774121816Sbrooks DODEBUG(Start_End, printf("%s: ex_ioctl: start ", ifp->if_xname);); 77521769Sjkh 77652286Smdodd s = splimp(); 77721769Sjkh 77852286Smdodd switch(cmd) { 77952286Smdodd case SIOCSIFADDR: 78052286Smdodd case SIOCGIFADDR: 78152286Smdodd case SIOCSIFMTU: 78252286Smdodd error = ether_ioctl(ifp, cmd, data); 78352286Smdodd break; 78421769Sjkh 78552286Smdodd case SIOCSIFFLAGS: 78652286Smdodd DODEBUG(Start_End, printf("SIOCSIFFLAGS");); 78752286Smdodd if ((ifp->if_flags & IFF_UP) == 0 && 78852286Smdodd (ifp->if_flags & IFF_RUNNING)) { 78952286Smdodd 79052286Smdodd ifp->if_flags &= ~IFF_RUNNING; 79152286Smdodd ex_stop(sc); 79252286Smdodd } else { 79352286Smdodd ex_init(sc); 79452286Smdodd } 79552286Smdodd break; 79621769Sjkh#ifdef NODEF 79752286Smdodd case SIOCGHWADDR: 79852286Smdodd DODEBUG(Start_End, printf("SIOCGHWADDR");); 79952286Smdodd bcopy((caddr_t)sc->sc_addr, (caddr_t)&ifr->ifr_data, 80052286Smdodd sizeof(sc->sc_addr)); 80152286Smdodd break; 80221769Sjkh#endif 80352286Smdodd case SIOCADDMULTI: 80452286Smdodd case SIOCDELMULTI: 805112731Smdodd ex_init(sc); 806112731Smdodd error = 0; 80752286Smdodd break; 80857987Smdodd case SIOCSIFMEDIA: 80957987Smdodd case SIOCGIFMEDIA: 81057987Smdodd error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd); 81157987Smdodd break; 81252286Smdodd default: 81352286Smdodd DODEBUG(Start_End, printf("unknown");); 81452286Smdodd error = EINVAL; 81552286Smdodd } 81621769Sjkh 81752286Smdodd splx(s); 81821769Sjkh 819121816Sbrooks DODEBUG(Start_End, printf("\n%s: ex_ioctl: finish\n", ifp->if_xname);); 82052286Smdodd 82152286Smdodd return(error); 82221769Sjkh} 82321769Sjkh 824112731Smdoddstatic void 825112731Smdoddex_setmulti(struct ex_softc *sc) 826112731Smdodd{ 827112731Smdodd struct ifnet *ifp; 828112731Smdodd struct ifmultiaddr *maddr; 829131192Simp uint16_t *addr; 830112731Smdodd int count; 831112731Smdodd int timeout, status; 832112731Smdodd 833112731Smdodd ifp = &sc->arpcom.ac_if; 83421769Sjkh 835112731Smdodd count = 0; 836112731Smdodd TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) { 837112731Smdodd if (maddr->ifma_addr->sa_family != AF_LINK) 838112731Smdodd continue; 839112731Smdodd count++; 840112731Smdodd } 841112731Smdodd 842112731Smdodd if ((ifp->if_flags & IFF_PROMISC) || (ifp->if_flags & IFF_ALLMULTI) 843112731Smdodd || count > 63) { 844112731Smdodd /* Interface is in promiscuous mode or there are too many 845112731Smdodd * multicast addresses for the card to handle */ 846131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 847131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | Promisc_Mode); 848131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3)); 849131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 850112731Smdodd } 851112731Smdodd else if ((ifp->if_flags & IFF_MULTICAST) && (count > 0)) { 852112731Smdodd /* Program multicast addresses plus our MAC address 853112731Smdodd * into the filter */ 854131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 855131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) | Multi_IA); 856131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3)); 857131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 858112731Smdodd 859112731Smdodd /* Borrow space from TX buffer; this should be safe 860112731Smdodd * as this is only called from ex_init */ 861112731Smdodd 862131192Simp CSR_WRITE_2(sc, HOST_ADDR_REG, sc->tx_lower_limit); 863131192Simp CSR_WRITE_2(sc, IO_PORT_REG, MC_Setup_CMD); 864131192Simp CSR_WRITE_2(sc, IO_PORT_REG, 0); 865131192Simp CSR_WRITE_2(sc, IO_PORT_REG, 0); 866131192Simp CSR_WRITE_2(sc, IO_PORT_REG, (count + 1) * 6); 867112731Smdodd 868112731Smdodd TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) { 869112731Smdodd if (maddr->ifma_addr->sa_family != AF_LINK) 870112731Smdodd continue; 871112731Smdodd 872131192Simp addr = (uint16_t*)LLADDR((struct sockaddr_dl *) 873112731Smdodd maddr->ifma_addr); 874131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 875131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 876131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 877112731Smdodd } 878112731Smdodd 879112731Smdodd /* Program our MAC address as well */ 880112731Smdodd /* XXX: Is this necessary? The Linux driver does this 881112731Smdodd * but the NetBSD driver does not */ 882131192Simp addr = (uint16_t*)(&sc->arpcom.ac_enaddr); 883131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 884131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 885131192Simp CSR_WRITE_2(sc, IO_PORT_REG, *addr++); 886112731Smdodd 887131192Simp CSR_READ_2(sc, IO_PORT_REG); 888131192Simp CSR_WRITE_2(sc, XMT_BAR, sc->tx_lower_limit); 889131192Simp CSR_WRITE_1(sc, CMD_REG, MC_Setup_CMD); 890112731Smdodd 891112731Smdodd sc->tx_head = sc->tx_lower_limit; 892112731Smdodd sc->tx_tail = sc->tx_head + XMT_HEADER_LEN + (count + 1) * 6; 893112731Smdodd 894112731Smdodd for (timeout=0; timeout<100; timeout++) { 895112731Smdodd DELAY(2); 896131192Simp if ((CSR_READ_1(sc, STATUS_REG) & Exec_Int) == 0) 897112731Smdodd continue; 898112731Smdodd 899131192Simp status = CSR_READ_1(sc, CMD_REG); 900131192Simp CSR_WRITE_1(sc, STATUS_REG, Exec_Int); 901112731Smdodd break; 902112731Smdodd } 903112731Smdodd 904112731Smdodd sc->tx_head = sc->tx_tail; 905112731Smdodd } 906112731Smdodd else 907112731Smdodd { 908112731Smdodd /* No multicast or promiscuous mode */ 909131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 910131192Simp CSR_WRITE_1(sc, REG2, CSR_READ_1(sc, REG2) & 0xDE); 911112731Smdodd /* ~(Multi_IA | Promisc_Mode) */ 912131192Simp CSR_WRITE_1(sc, REG3, CSR_READ_1(sc, REG3)); 913131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 914112731Smdodd } 915112731Smdodd} 916112731Smdodd 91752286Smdoddstatic void 91852286Smdoddex_reset(struct ex_softc *sc) 91921769Sjkh{ 92052286Smdodd int s; 92121769Sjkh 92252286Smdodd DODEBUG(Start_End, printf("ex_reset%d: start\n", unit);); 92321769Sjkh 92452286Smdodd s = splimp(); 92521769Sjkh 92652286Smdodd ex_stop(sc); 92752286Smdodd ex_init(sc); 92821769Sjkh 92952286Smdodd splx(s); 93021769Sjkh 93152286Smdodd DODEBUG(Start_End, printf("ex_reset%d: finish\n", unit);); 93252286Smdodd 93352286Smdodd return; 93421769Sjkh} 93521769Sjkh 93652286Smdoddstatic void 93752286Smdoddex_watchdog(struct ifnet *ifp) 93821769Sjkh{ 93952286Smdodd struct ex_softc * sc = ifp->if_softc; 94021769Sjkh 941121816Sbrooks DODEBUG(Start_End, printf("%s: ex_watchdog: start\n", ifp->if_xname);); 94221769Sjkh 94352286Smdodd ifp->if_flags &= ~IFF_OACTIVE; 94421769Sjkh 94552286Smdodd DODEBUG(Status, printf("OIDLE watchdog\n");); 94652286Smdodd 94752286Smdodd ifp->if_oerrors++; 94852286Smdodd ex_reset(sc); 94952286Smdodd ex_start(ifp); 95052286Smdodd 951121816Sbrooks DODEBUG(Start_End, printf("%s: ex_watchdog: finish\n", ifp->if_xname);); 95252286Smdodd 95352286Smdodd return; 95421769Sjkh} 95521769Sjkh 95657987Smdoddstatic int 957131192Simpex_get_media(struct ex_softc *sc) 95859816Smdodd{ 959112764Smdodd int current; 960112764Smdodd int media; 96159816Smdodd 962131192Simp media = ex_eeprom_read(sc, EE_W5); 963112764Smdodd 964131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 965131192Simp current = CSR_READ_1(sc, REG3); 966131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 96759816Smdodd 968112764Smdodd if ((current & TPE_bit) && (media & EE_W5_PORT_TPE)) 96959816Smdodd return(IFM_ETHER|IFM_10_T); 970112764Smdodd if ((current & BNC_bit) && (media & EE_W5_PORT_BNC)) 97159816Smdodd return(IFM_ETHER|IFM_10_2); 97259816Smdodd 973112764Smdodd if (media & EE_W5_PORT_AUI) 974112764Smdodd return (IFM_ETHER|IFM_10_5); 975112764Smdodd 976112764Smdodd return (IFM_ETHER|IFM_AUTO); 97759816Smdodd} 97859816Smdodd 97959816Smdoddstatic int 980131192Simpex_ifmedia_upd(ifp) 98157987Smdodd struct ifnet * ifp; 98257987Smdodd{ 983112764Smdodd struct ex_softc * sc = ifp->if_softc; 98421769Sjkh 985112764Smdodd if (IFM_TYPE(sc->ifmedia.ifm_media) != IFM_ETHER) 986112764Smdodd return EINVAL; 987112764Smdodd 98857987Smdodd return (0); 98957987Smdodd} 99057987Smdodd 99157987Smdoddstatic void 99257987Smdoddex_ifmedia_sts(ifp, ifmr) 99357987Smdodd struct ifnet * ifp; 99457987Smdodd struct ifmediareq * ifmr; 99557987Smdodd{ 99657987Smdodd struct ex_softc * sc = ifp->if_softc; 99757987Smdodd 998131192Simp ifmr->ifm_active = ex_get_media(sc); 999112764Smdodd ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 100057987Smdodd 100157987Smdodd return; 100257987Smdodd} 100357987Smdodd 100459816Smdoddu_short 1005131192Simpex_eeprom_read(struct ex_softc *sc, int location) 100621769Sjkh{ 100721769Sjkh int i; 100821769Sjkh u_short data = 0; 100921769Sjkh int read_cmd = location | EE_READ_CMD; 101021769Sjkh short ctrl_val = EECS; 101121769Sjkh 1012131192Simp CSR_WRITE_1(sc, CMD_REG, Bank2_Sel); 1013131192Simp CSR_WRITE_1(sc, EEPROM_REG, EECS); 101421769Sjkh for (i = 8; i >= 0; i--) { 101521769Sjkh short outval = (read_cmd & (1 << i)) ? ctrl_val | EEDI : ctrl_val; 1016131192Simp CSR_WRITE_1(sc, EEPROM_REG, outval); 1017131192Simp CSR_WRITE_1(sc, EEPROM_REG, outval | EESK); 101821769Sjkh DELAY(3); 1019131192Simp CSR_WRITE_1(sc, EEPROM_REG, outval); 102021769Sjkh DELAY(2); 102121769Sjkh } 1022131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val); 102321769Sjkh 102421769Sjkh for (i = 16; i > 0; i--) { 1025131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val | EESK); 102621769Sjkh DELAY(3); 1027131192Simp data = (data << 1) | 1028131192Simp ((CSR_READ_1(sc, EEPROM_REG) & EEDO) ? 1 : 0); 1029131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val); 103021769Sjkh DELAY(2); 103121769Sjkh } 103221769Sjkh 103321769Sjkh ctrl_val &= ~EECS; 1034131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val | EESK); 103521769Sjkh DELAY(3); 1036131192Simp CSR_WRITE_1(sc, EEPROM_REG, ctrl_val); 103721769Sjkh DELAY(2); 1038131192Simp CSR_WRITE_1(sc, CMD_REG, Bank0_Sel); 103921769Sjkh return(data); 104021769Sjkh} 1041