if_vr.c revision 44238
141502Swpaul/* 241502Swpaul * Copyright (c) 1997, 1998 341502Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 441502Swpaul * 541502Swpaul * Redistribution and use in source and binary forms, with or without 641502Swpaul * modification, are permitted provided that the following conditions 741502Swpaul * are met: 841502Swpaul * 1. Redistributions of source code must retain the above copyright 941502Swpaul * notice, this list of conditions and the following disclaimer. 1041502Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1141502Swpaul * notice, this list of conditions and the following disclaimer in the 1241502Swpaul * documentation and/or other materials provided with the distribution. 1341502Swpaul * 3. All advertising materials mentioning features or use of this software 1441502Swpaul * must display the following acknowledgement: 1541502Swpaul * This product includes software developed by Bill Paul. 1641502Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1741502Swpaul * may be used to endorse or promote products derived from this software 1841502Swpaul * without specific prior written permission. 1941502Swpaul * 2041502Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2141502Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2241502Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2341502Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2441502Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2541502Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2641502Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2741502Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2841502Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2941502Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3041502Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3141502Swpaul * 3244238Swpaul * $Id: if_vr.c,v 1.18 1999/02/23 06:47:52 wpaul Exp $ 3341502Swpaul */ 3441502Swpaul 3541502Swpaul/* 3641502Swpaul * VIA Rhine fast ethernet PCI NIC driver 3741502Swpaul * 3841502Swpaul * Supports various network adapters based on the VIA Rhine 3941502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX. 4041502Swpaul * Datasheets are available at http://www.via.com.tw. 4141502Swpaul * 4241502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4341502Swpaul * Electrical Engineering Department 4441502Swpaul * Columbia University, New York City 4541502Swpaul */ 4641502Swpaul 4741502Swpaul/* 4841502Swpaul * The VIA Rhine controllers are similar in some respects to the 4941502Swpaul * the DEC tulip chips, except less complicated. The controller 5041502Swpaul * uses an MII bus and an external physical layer interface. The 5141502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table 5241502Swpaul * multicast filter. Transmit and receive descriptors are similar 5341502Swpaul * to the tulip. 5441502Swpaul * 5541502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism: 5641502Swpaul * transmit buffers must be longword aligned. Unfortunately, 5741502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting 5841502Swpaul * at longword boundaries, so we have to do a buffer copy before 5941502Swpaul * transmission. 6041502Swpaul */ 6141502Swpaul 6241502Swpaul#include "bpfilter.h" 6341502Swpaul 6441502Swpaul#include <sys/param.h> 6541502Swpaul#include <sys/systm.h> 6641502Swpaul#include <sys/sockio.h> 6741502Swpaul#include <sys/mbuf.h> 6841502Swpaul#include <sys/malloc.h> 6941502Swpaul#include <sys/kernel.h> 7041502Swpaul#include <sys/socket.h> 7141502Swpaul 7241502Swpaul#include <net/if.h> 7341502Swpaul#include <net/if_arp.h> 7441502Swpaul#include <net/ethernet.h> 7541502Swpaul#include <net/if_dl.h> 7641502Swpaul#include <net/if_media.h> 7741502Swpaul 7841502Swpaul#if NBPFILTER > 0 7941502Swpaul#include <net/bpf.h> 8041502Swpaul#endif 8141502Swpaul 8241502Swpaul#include <vm/vm.h> /* for vtophys */ 8341502Swpaul#include <vm/pmap.h> /* for vtophys */ 8441502Swpaul#include <machine/clock.h> /* for DELAY */ 8541502Swpaul#include <machine/bus_pio.h> 8641502Swpaul#include <machine/bus_memio.h> 8741502Swpaul#include <machine/bus.h> 8841502Swpaul 8941502Swpaul#include <pci/pcireg.h> 9041502Swpaul#include <pci/pcivar.h> 9141502Swpaul 9241502Swpaul#define VR_USEIOSPACE 9341502Swpaul 9441502Swpaul/* #define VR_BACKGROUND_AUTONEG */ 9541502Swpaul 9641502Swpaul#include <pci/if_vrreg.h> 9741502Swpaul 9841502Swpaul#ifndef lint 9941591Sarchiestatic const char rcsid[] = 10044238Swpaul "$Id: if_vr.c,v 1.18 1999/02/23 06:47:52 wpaul Exp $"; 10141502Swpaul#endif 10241502Swpaul 10341502Swpaul/* 10441502Swpaul * Various supported device vendors/types and their names. 10541502Swpaul */ 10641502Swpaulstatic struct vr_type vr_devs[] = { 10741502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 10841502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 10941502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11041502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11144238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 11244238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 11344238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 11444238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 11541502Swpaul { 0, 0, NULL } 11641502Swpaul}; 11741502Swpaul 11841502Swpaul/* 11941502Swpaul * Various supported PHY vendors/types and their names. Note that 12041502Swpaul * this driver will work with pretty much any MII-compliant PHY, 12141502Swpaul * so failure to positively identify the chip is not a fatal error. 12241502Swpaul */ 12341502Swpaul 12441502Swpaulstatic struct vr_type vr_phys[] = { 12541502Swpaul { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, 12641502Swpaul { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, 12741502Swpaul { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, 12841502Swpaul { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, 12941502Swpaul { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, 13041502Swpaul { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, 13141502Swpaul { 0, 0, "<MII-compliant physical interface>" } 13241502Swpaul}; 13341502Swpaul 13441502Swpaulstatic unsigned long vr_count = 0; 13541771Sdillonstatic const char *vr_probe __P((pcici_t, pcidi_t)); 13641502Swpaulstatic void vr_attach __P((pcici_t, int)); 13741502Swpaul 13841502Swpaulstatic int vr_newbuf __P((struct vr_softc *, 13941502Swpaul struct vr_chain_onefrag *)); 14041502Swpaulstatic int vr_encap __P((struct vr_softc *, struct vr_chain *, 14141502Swpaul struct mbuf * )); 14241502Swpaul 14341502Swpaulstatic void vr_rxeof __P((struct vr_softc *)); 14441502Swpaulstatic void vr_rxeoc __P((struct vr_softc *)); 14541502Swpaulstatic void vr_txeof __P((struct vr_softc *)); 14641502Swpaulstatic void vr_txeoc __P((struct vr_softc *)); 14741502Swpaulstatic void vr_intr __P((void *)); 14841502Swpaulstatic void vr_start __P((struct ifnet *)); 14941502Swpaulstatic int vr_ioctl __P((struct ifnet *, u_long, caddr_t)); 15041502Swpaulstatic void vr_init __P((void *)); 15141502Swpaulstatic void vr_stop __P((struct vr_softc *)); 15241502Swpaulstatic void vr_watchdog __P((struct ifnet *)); 15341502Swpaulstatic void vr_shutdown __P((int, void *)); 15441502Swpaulstatic int vr_ifmedia_upd __P((struct ifnet *)); 15541502Swpaulstatic void vr_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 15641502Swpaul 15741502Swpaulstatic void vr_mii_sync __P((struct vr_softc *)); 15841502Swpaulstatic void vr_mii_send __P((struct vr_softc *, u_int32_t, int)); 15941502Swpaulstatic int vr_mii_readreg __P((struct vr_softc *, struct vr_mii_frame *)); 16041502Swpaulstatic int vr_mii_writereg __P((struct vr_softc *, struct vr_mii_frame *)); 16141502Swpaulstatic u_int16_t vr_phy_readreg __P((struct vr_softc *, int)); 16241502Swpaulstatic void vr_phy_writereg __P((struct vr_softc *, u_int16_t, u_int16_t)); 16341502Swpaul 16441502Swpaulstatic void vr_autoneg_xmit __P((struct vr_softc *)); 16541502Swpaulstatic void vr_autoneg_mii __P((struct vr_softc *, int, int)); 16641502Swpaulstatic void vr_setmode_mii __P((struct vr_softc *, int)); 16741502Swpaulstatic void vr_getmode_mii __P((struct vr_softc *)); 16841502Swpaulstatic void vr_setcfg __P((struct vr_softc *, u_int16_t)); 16941502Swpaulstatic u_int8_t vr_calchash __P((u_int8_t *)); 17041502Swpaulstatic void vr_setmulti __P((struct vr_softc *)); 17141502Swpaulstatic void vr_reset __P((struct vr_softc *)); 17241502Swpaulstatic int vr_list_rx_init __P((struct vr_softc *)); 17341502Swpaulstatic int vr_list_tx_init __P((struct vr_softc *)); 17441502Swpaul 17541502Swpaul#define VR_SETBIT(sc, reg, x) \ 17641502Swpaul CSR_WRITE_1(sc, reg, \ 17741502Swpaul CSR_READ_1(sc, reg) | x) 17841502Swpaul 17941502Swpaul#define VR_CLRBIT(sc, reg, x) \ 18041502Swpaul CSR_WRITE_1(sc, reg, \ 18141502Swpaul CSR_READ_1(sc, reg) & ~x) 18241502Swpaul 18341502Swpaul#define VR_SETBIT16(sc, reg, x) \ 18441502Swpaul CSR_WRITE_2(sc, reg, \ 18541502Swpaul CSR_READ_2(sc, reg) | x) 18641502Swpaul 18741502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 18841502Swpaul CSR_WRITE_2(sc, reg, \ 18941502Swpaul CSR_READ_2(sc, reg) & ~x) 19041502Swpaul 19141502Swpaul#define VR_SETBIT32(sc, reg, x) \ 19241502Swpaul CSR_WRITE_4(sc, reg, \ 19341502Swpaul CSR_READ_4(sc, reg) | x) 19441502Swpaul 19541502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 19641502Swpaul CSR_WRITE_4(sc, reg, \ 19741502Swpaul CSR_READ_4(sc, reg) & ~x) 19841502Swpaul 19941502Swpaul#define SIO_SET(x) \ 20041502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 20141502Swpaul CSR_READ_1(sc, VR_MIICMD) | x) 20241502Swpaul 20341502Swpaul#define SIO_CLR(x) \ 20441502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 20541502Swpaul CSR_READ_1(sc, VR_MIICMD) & ~x) 20641502Swpaul 20741502Swpaul/* 20841502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 20941502Swpaul */ 21041502Swpaulstatic void vr_mii_sync(sc) 21141502Swpaul struct vr_softc *sc; 21241502Swpaul{ 21341502Swpaul register int i; 21441502Swpaul 21541502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 21641502Swpaul 21741502Swpaul for (i = 0; i < 32; i++) { 21841502Swpaul SIO_SET(VR_MIICMD_CLK); 21941502Swpaul DELAY(1); 22041502Swpaul SIO_CLR(VR_MIICMD_CLK); 22141502Swpaul DELAY(1); 22241502Swpaul } 22341502Swpaul 22441502Swpaul return; 22541502Swpaul} 22641502Swpaul 22741502Swpaul/* 22841502Swpaul * Clock a series of bits through the MII. 22941502Swpaul */ 23041502Swpaulstatic void vr_mii_send(sc, bits, cnt) 23141502Swpaul struct vr_softc *sc; 23241502Swpaul u_int32_t bits; 23341502Swpaul int cnt; 23441502Swpaul{ 23541502Swpaul int i; 23641502Swpaul 23741502Swpaul SIO_CLR(VR_MIICMD_CLK); 23841502Swpaul 23941502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 24041502Swpaul if (bits & i) { 24141502Swpaul SIO_SET(VR_MIICMD_DATAIN); 24241502Swpaul } else { 24341502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 24441502Swpaul } 24541502Swpaul DELAY(1); 24641502Swpaul SIO_CLR(VR_MIICMD_CLK); 24741502Swpaul DELAY(1); 24841502Swpaul SIO_SET(VR_MIICMD_CLK); 24941502Swpaul } 25041502Swpaul} 25141502Swpaul 25241502Swpaul/* 25341502Swpaul * Read an PHY register through the MII. 25441502Swpaul */ 25541502Swpaulstatic int vr_mii_readreg(sc, frame) 25641502Swpaul struct vr_softc *sc; 25741502Swpaul struct vr_mii_frame *frame; 25841502Swpaul 25941502Swpaul{ 26041502Swpaul int i, ack, s; 26141502Swpaul 26241502Swpaul s = splimp(); 26341502Swpaul 26441502Swpaul /* 26541502Swpaul * Set up frame for RX. 26641502Swpaul */ 26741502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 26841502Swpaul frame->mii_opcode = VR_MII_READOP; 26941502Swpaul frame->mii_turnaround = 0; 27041502Swpaul frame->mii_data = 0; 27141502Swpaul 27241502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 27341502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 27441502Swpaul 27541502Swpaul /* 27641502Swpaul * Turn on data xmit. 27741502Swpaul */ 27841502Swpaul SIO_SET(VR_MIICMD_DIR); 27941502Swpaul 28041502Swpaul vr_mii_sync(sc); 28141502Swpaul 28241502Swpaul /* 28341502Swpaul * Send command/address info. 28441502Swpaul */ 28541502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 28641502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 28741502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 28841502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 28941502Swpaul 29041502Swpaul /* Idle bit */ 29141502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 29241502Swpaul DELAY(1); 29341502Swpaul SIO_SET(VR_MIICMD_CLK); 29441502Swpaul DELAY(1); 29541502Swpaul 29641502Swpaul /* Turn off xmit. */ 29741502Swpaul SIO_CLR(VR_MIICMD_DIR); 29841502Swpaul 29941502Swpaul /* Check for ack */ 30041502Swpaul SIO_CLR(VR_MIICMD_CLK); 30141502Swpaul DELAY(1); 30241502Swpaul SIO_SET(VR_MIICMD_CLK); 30341502Swpaul DELAY(1); 30441502Swpaul ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 30541502Swpaul 30641502Swpaul /* 30741502Swpaul * Now try reading data bits. If the ack failed, we still 30841502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 30941502Swpaul */ 31041502Swpaul if (ack) { 31141502Swpaul for(i = 0; i < 16; i++) { 31241502Swpaul SIO_CLR(VR_MIICMD_CLK); 31341502Swpaul DELAY(1); 31441502Swpaul SIO_SET(VR_MIICMD_CLK); 31541502Swpaul DELAY(1); 31641502Swpaul } 31741502Swpaul goto fail; 31841502Swpaul } 31941502Swpaul 32041502Swpaul for (i = 0x8000; i; i >>= 1) { 32141502Swpaul SIO_CLR(VR_MIICMD_CLK); 32241502Swpaul DELAY(1); 32341502Swpaul if (!ack) { 32441502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 32541502Swpaul frame->mii_data |= i; 32641502Swpaul DELAY(1); 32741502Swpaul } 32841502Swpaul SIO_SET(VR_MIICMD_CLK); 32941502Swpaul DELAY(1); 33041502Swpaul } 33141502Swpaul 33241502Swpaulfail: 33341502Swpaul 33441502Swpaul SIO_CLR(VR_MIICMD_CLK); 33541502Swpaul DELAY(1); 33641502Swpaul SIO_SET(VR_MIICMD_CLK); 33741502Swpaul DELAY(1); 33841502Swpaul 33941502Swpaul splx(s); 34041502Swpaul 34141502Swpaul if (ack) 34241502Swpaul return(1); 34341502Swpaul return(0); 34441502Swpaul} 34541502Swpaul 34641502Swpaul/* 34741502Swpaul * Write to a PHY register through the MII. 34841502Swpaul */ 34941502Swpaulstatic int vr_mii_writereg(sc, frame) 35041502Swpaul struct vr_softc *sc; 35141502Swpaul struct vr_mii_frame *frame; 35241502Swpaul 35341502Swpaul{ 35441502Swpaul int s; 35541502Swpaul 35641502Swpaul s = splimp(); 35741502Swpaul 35841502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 35941502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 36041502Swpaul 36141502Swpaul /* 36241502Swpaul * Set up frame for TX. 36341502Swpaul */ 36441502Swpaul 36541502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 36641502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 36741502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 36841502Swpaul 36941502Swpaul /* 37041502Swpaul * Turn on data output. 37141502Swpaul */ 37241502Swpaul SIO_SET(VR_MIICMD_DIR); 37341502Swpaul 37441502Swpaul vr_mii_sync(sc); 37541502Swpaul 37641502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 37741502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 37841502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 37941502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 38041502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 38141502Swpaul vr_mii_send(sc, frame->mii_data, 16); 38241502Swpaul 38341502Swpaul /* Idle bit. */ 38441502Swpaul SIO_SET(VR_MIICMD_CLK); 38541502Swpaul DELAY(1); 38641502Swpaul SIO_CLR(VR_MIICMD_CLK); 38741502Swpaul DELAY(1); 38841502Swpaul 38941502Swpaul /* 39041502Swpaul * Turn off xmit. 39141502Swpaul */ 39241502Swpaul SIO_CLR(VR_MIICMD_DIR); 39341502Swpaul 39441502Swpaul splx(s); 39541502Swpaul 39641502Swpaul return(0); 39741502Swpaul} 39841502Swpaul 39941502Swpaulstatic u_int16_t vr_phy_readreg(sc, reg) 40041502Swpaul struct vr_softc *sc; 40141502Swpaul int reg; 40241502Swpaul{ 40341502Swpaul struct vr_mii_frame frame; 40441502Swpaul 40541502Swpaul bzero((char *)&frame, sizeof(frame)); 40641502Swpaul 40741502Swpaul frame.mii_phyaddr = sc->vr_phy_addr; 40841502Swpaul frame.mii_regaddr = reg; 40941502Swpaul vr_mii_readreg(sc, &frame); 41041502Swpaul 41141502Swpaul return(frame.mii_data); 41241502Swpaul} 41341502Swpaul 41441502Swpaulstatic void vr_phy_writereg(sc, reg, data) 41541502Swpaul struct vr_softc *sc; 41641502Swpaul u_int16_t reg; 41741502Swpaul u_int16_t data; 41841502Swpaul{ 41941502Swpaul struct vr_mii_frame frame; 42041502Swpaul 42141502Swpaul bzero((char *)&frame, sizeof(frame)); 42241502Swpaul 42341502Swpaul frame.mii_phyaddr = sc->vr_phy_addr; 42441502Swpaul frame.mii_regaddr = reg; 42541502Swpaul frame.mii_data = data; 42641502Swpaul 42741502Swpaul vr_mii_writereg(sc, &frame); 42841502Swpaul 42941502Swpaul return; 43041502Swpaul} 43141502Swpaul 43241502Swpaul/* 43341502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits. 43441502Swpaul */ 43541502Swpaulstatic u_int8_t vr_calchash(addr) 43641502Swpaul u_int8_t *addr; 43741502Swpaul{ 43841502Swpaul u_int32_t crc, carry; 43941502Swpaul int i, j; 44041502Swpaul u_int8_t c; 44141502Swpaul 44241502Swpaul /* Compute CRC for the address value. */ 44341502Swpaul crc = 0xFFFFFFFF; /* initial value */ 44441502Swpaul 44541502Swpaul for (i = 0; i < 6; i++) { 44641502Swpaul c = *(addr + i); 44741502Swpaul for (j = 0; j < 8; j++) { 44841502Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 44941502Swpaul crc <<= 1; 45041502Swpaul c >>= 1; 45141502Swpaul if (carry) 45241502Swpaul crc = (crc ^ 0x04c11db6) | carry; 45341502Swpaul } 45441502Swpaul } 45541502Swpaul 45641502Swpaul /* return the filter bit position */ 45741502Swpaul return((crc >> 26) & 0x0000003F); 45841502Swpaul} 45941502Swpaul 46041502Swpaul/* 46141502Swpaul * Program the 64-bit multicast hash filter. 46241502Swpaul */ 46341502Swpaulstatic void vr_setmulti(sc) 46441502Swpaul struct vr_softc *sc; 46541502Swpaul{ 46641502Swpaul struct ifnet *ifp; 46741502Swpaul int h = 0; 46841502Swpaul u_int32_t hashes[2] = { 0, 0 }; 46941502Swpaul struct ifmultiaddr *ifma; 47041502Swpaul u_int8_t rxfilt; 47141502Swpaul int mcnt = 0; 47241502Swpaul 47341502Swpaul ifp = &sc->arpcom.ac_if; 47441502Swpaul 47541502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 47641502Swpaul 47741502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 47841502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 47941502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 48041502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 48141502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 48241502Swpaul return; 48341502Swpaul } 48441502Swpaul 48541502Swpaul /* first, zot all the existing hash bits */ 48641502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 48741502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 48841502Swpaul 48941502Swpaul /* now program new ones */ 49041502Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 49141502Swpaul ifma = ifma->ifma_link.le_next) { 49241502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 49341502Swpaul continue; 49441502Swpaul h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 49541502Swpaul if (h < 32) 49641502Swpaul hashes[0] |= (1 << h); 49741502Swpaul else 49841502Swpaul hashes[1] |= (1 << (h - 32)); 49941502Swpaul mcnt++; 50041502Swpaul } 50141502Swpaul 50241502Swpaul if (mcnt) 50341502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 50441502Swpaul else 50541502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 50641502Swpaul 50741502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 50841502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 50941502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 51041502Swpaul 51141502Swpaul return; 51241502Swpaul} 51341502Swpaul 51441502Swpaul/* 51541502Swpaul * Initiate an autonegotiation session. 51641502Swpaul */ 51741502Swpaulstatic void vr_autoneg_xmit(sc) 51841502Swpaul struct vr_softc *sc; 51941502Swpaul{ 52041502Swpaul u_int16_t phy_sts; 52141502Swpaul 52241502Swpaul vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 52341502Swpaul DELAY(500); 52441502Swpaul while(vr_phy_readreg(sc, PHY_BMCR) 52541502Swpaul & PHY_BMCR_RESET); 52641502Swpaul 52741502Swpaul phy_sts = vr_phy_readreg(sc, PHY_BMCR); 52841502Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 52941502Swpaul vr_phy_writereg(sc, PHY_BMCR, phy_sts); 53041502Swpaul 53141502Swpaul return; 53241502Swpaul} 53341502Swpaul 53441502Swpaul/* 53541502Swpaul * Invoke autonegotiation on a PHY. 53641502Swpaul */ 53741502Swpaulstatic void vr_autoneg_mii(sc, flag, verbose) 53841502Swpaul struct vr_softc *sc; 53941502Swpaul int flag; 54041502Swpaul int verbose; 54141502Swpaul{ 54241502Swpaul u_int16_t phy_sts = 0, media, advert, ability; 54341502Swpaul struct ifnet *ifp; 54441502Swpaul struct ifmedia *ifm; 54541502Swpaul 54641502Swpaul ifm = &sc->ifmedia; 54741502Swpaul ifp = &sc->arpcom.ac_if; 54841502Swpaul 54941502Swpaul ifm->ifm_media = IFM_ETHER | IFM_AUTO; 55041502Swpaul 55141502Swpaul /* 55241502Swpaul * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' 55341502Swpaul * bit cleared in the status register, but has the 'autoneg enabled' 55441502Swpaul * bit set in the control register. This is a contradiction, and 55541502Swpaul * I'm not sure how to handle it. If you want to force an attempt 55641502Swpaul * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR 55741502Swpaul * and see what happens. 55841502Swpaul */ 55941502Swpaul#ifndef FORCE_AUTONEG_TFOUR 56041502Swpaul /* 56141502Swpaul * First, see if autoneg is supported. If not, there's 56241502Swpaul * no point in continuing. 56341502Swpaul */ 56441502Swpaul phy_sts = vr_phy_readreg(sc, PHY_BMSR); 56541502Swpaul if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { 56641502Swpaul if (verbose) 56741502Swpaul printf("vr%d: autonegotiation not supported\n", 56841502Swpaul sc->vr_unit); 56941502Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 57041502Swpaul return; 57141502Swpaul } 57241502Swpaul#endif 57341502Swpaul 57441502Swpaul switch (flag) { 57541502Swpaul case VR_FLAG_FORCEDELAY: 57641502Swpaul /* 57741502Swpaul * XXX Never use this option anywhere but in the probe 57841502Swpaul * routine: making the kernel stop dead in its tracks 57941502Swpaul * for three whole seconds after we've gone multi-user 58041502Swpaul * is really bad manners. 58141502Swpaul */ 58241502Swpaul vr_autoneg_xmit(sc); 58341502Swpaul DELAY(5000000); 58441502Swpaul break; 58541502Swpaul case VR_FLAG_SCHEDDELAY: 58641502Swpaul /* 58741502Swpaul * Wait for the transmitter to go idle before starting 58841502Swpaul * an autoneg session, otherwise vr_start() may clobber 58941502Swpaul * our timeout, and we don't want to allow transmission 59041502Swpaul * during an autoneg session since that can screw it up. 59141502Swpaul */ 59241502Swpaul if (sc->vr_cdata.vr_tx_head != NULL) { 59341502Swpaul sc->vr_want_auto = 1; 59441502Swpaul return; 59541502Swpaul } 59641502Swpaul vr_autoneg_xmit(sc); 59741502Swpaul ifp->if_timer = 5; 59841502Swpaul sc->vr_autoneg = 1; 59941502Swpaul sc->vr_want_auto = 0; 60041502Swpaul return; 60141502Swpaul break; 60241502Swpaul case VR_FLAG_DELAYTIMEO: 60341502Swpaul ifp->if_timer = 0; 60441502Swpaul sc->vr_autoneg = 0; 60541502Swpaul break; 60641502Swpaul default: 60741502Swpaul printf("vr%d: invalid autoneg flag: %d\n", sc->vr_unit, flag); 60841502Swpaul return; 60941502Swpaul } 61041502Swpaul 61141502Swpaul if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { 61241502Swpaul if (verbose) 61341502Swpaul printf("vr%d: autoneg complete, ", sc->vr_unit); 61441502Swpaul phy_sts = vr_phy_readreg(sc, PHY_BMSR); 61541502Swpaul } else { 61641502Swpaul if (verbose) 61741502Swpaul printf("vr%d: autoneg not complete, ", sc->vr_unit); 61841502Swpaul } 61941502Swpaul 62041502Swpaul media = vr_phy_readreg(sc, PHY_BMCR); 62141502Swpaul 62241502Swpaul /* Link is good. Report modes and set duplex mode. */ 62341502Swpaul if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { 62441502Swpaul if (verbose) 62541502Swpaul printf("link status good "); 62641502Swpaul advert = vr_phy_readreg(sc, PHY_ANAR); 62741502Swpaul ability = vr_phy_readreg(sc, PHY_LPAR); 62841502Swpaul 62941502Swpaul if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { 63041502Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_T4; 63141502Swpaul media |= PHY_BMCR_SPEEDSEL; 63241502Swpaul media &= ~PHY_BMCR_DUPLEX; 63341502Swpaul printf("(100baseT4)\n"); 63441502Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 63541502Swpaul ability & PHY_ANAR_100BTXFULL) { 63641502Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 63741502Swpaul media |= PHY_BMCR_SPEEDSEL; 63841502Swpaul media |= PHY_BMCR_DUPLEX; 63941502Swpaul printf("(full-duplex, 100Mbps)\n"); 64041502Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 64141502Swpaul ability & PHY_ANAR_100BTXHALF) { 64241502Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 64341502Swpaul media |= PHY_BMCR_SPEEDSEL; 64441502Swpaul media &= ~PHY_BMCR_DUPLEX; 64541502Swpaul printf("(half-duplex, 100Mbps)\n"); 64641502Swpaul } else if (advert & PHY_ANAR_10BTFULL && 64741502Swpaul ability & PHY_ANAR_10BTFULL) { 64841502Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 64941502Swpaul media &= ~PHY_BMCR_SPEEDSEL; 65041502Swpaul media |= PHY_BMCR_DUPLEX; 65141502Swpaul printf("(full-duplex, 10Mbps)\n"); 65241502Swpaul } else { 65341502Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 65441502Swpaul media &= ~PHY_BMCR_SPEEDSEL; 65541502Swpaul media &= ~PHY_BMCR_DUPLEX; 65641502Swpaul printf("(half-duplex, 10Mbps)\n"); 65741502Swpaul } 65841502Swpaul 65941502Swpaul media &= ~PHY_BMCR_AUTONEGENBL; 66041502Swpaul 66141502Swpaul /* Set ASIC's duplex mode to match the PHY. */ 66241502Swpaul vr_setcfg(sc, media); 66341502Swpaul vr_phy_writereg(sc, PHY_BMCR, media); 66441502Swpaul } else { 66541502Swpaul if (verbose) 66641502Swpaul printf("no carrier\n"); 66741502Swpaul } 66841502Swpaul 66941502Swpaul vr_init(sc); 67041502Swpaul 67141502Swpaul if (sc->vr_tx_pend) { 67241502Swpaul sc->vr_autoneg = 0; 67341502Swpaul sc->vr_tx_pend = 0; 67441502Swpaul vr_start(ifp); 67541502Swpaul } 67641502Swpaul 67741502Swpaul return; 67841502Swpaul} 67941502Swpaul 68041502Swpaulstatic void vr_getmode_mii(sc) 68141502Swpaul struct vr_softc *sc; 68241502Swpaul{ 68341502Swpaul u_int16_t bmsr; 68441502Swpaul struct ifnet *ifp; 68541502Swpaul 68641502Swpaul ifp = &sc->arpcom.ac_if; 68741502Swpaul 68841502Swpaul bmsr = vr_phy_readreg(sc, PHY_BMSR); 68941502Swpaul if (bootverbose) 69041502Swpaul printf("vr%d: PHY status word: %x\n", sc->vr_unit, bmsr); 69141502Swpaul 69241502Swpaul /* fallback */ 69341502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 69441502Swpaul 69541502Swpaul if (bmsr & PHY_BMSR_10BTHALF) { 69641502Swpaul if (bootverbose) 69741502Swpaul printf("vr%d: 10Mbps half-duplex mode supported\n", 69841502Swpaul sc->vr_unit); 69941502Swpaul ifmedia_add(&sc->ifmedia, 70041502Swpaul IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 70141502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 70241502Swpaul } 70341502Swpaul 70441502Swpaul if (bmsr & PHY_BMSR_10BTFULL) { 70541502Swpaul if (bootverbose) 70641502Swpaul printf("vr%d: 10Mbps full-duplex mode supported\n", 70741502Swpaul sc->vr_unit); 70841502Swpaul ifmedia_add(&sc->ifmedia, 70941502Swpaul IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 71041502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 71141502Swpaul } 71241502Swpaul 71341502Swpaul if (bmsr & PHY_BMSR_100BTXHALF) { 71441502Swpaul if (bootverbose) 71541502Swpaul printf("vr%d: 100Mbps half-duplex mode supported\n", 71641502Swpaul sc->vr_unit); 71741502Swpaul ifp->if_baudrate = 100000000; 71841502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 71941502Swpaul ifmedia_add(&sc->ifmedia, 72041502Swpaul IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); 72141502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 72241502Swpaul } 72341502Swpaul 72441502Swpaul if (bmsr & PHY_BMSR_100BTXFULL) { 72541502Swpaul if (bootverbose) 72641502Swpaul printf("vr%d: 100Mbps full-duplex mode supported\n", 72741502Swpaul sc->vr_unit); 72841502Swpaul ifp->if_baudrate = 100000000; 72941502Swpaul ifmedia_add(&sc->ifmedia, 73041502Swpaul IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 73141502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 73241502Swpaul } 73341502Swpaul 73441502Swpaul /* Some also support 100BaseT4. */ 73541502Swpaul if (bmsr & PHY_BMSR_100BT4) { 73641502Swpaul if (bootverbose) 73741502Swpaul printf("vr%d: 100baseT4 mode supported\n", sc->vr_unit); 73841502Swpaul ifp->if_baudrate = 100000000; 73941502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); 74041502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; 74141502Swpaul#ifdef FORCE_AUTONEG_TFOUR 74241502Swpaul if (bootverbose) 74341502Swpaul printf("vr%d: forcing on autoneg support for BT4\n", 74441502Swpaul sc->vr_unit); 74541502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): 74641502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 74741502Swpaul#endif 74841502Swpaul } 74941502Swpaul 75041502Swpaul if (bmsr & PHY_BMSR_CANAUTONEG) { 75141502Swpaul if (bootverbose) 75241502Swpaul printf("vr%d: autoneg supported\n", sc->vr_unit); 75341502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 75441502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 75541502Swpaul } 75641502Swpaul 75741502Swpaul return; 75841502Swpaul} 75941502Swpaul 76041502Swpaul/* 76141502Swpaul * Set speed and duplex mode. 76241502Swpaul */ 76341502Swpaulstatic void vr_setmode_mii(sc, media) 76441502Swpaul struct vr_softc *sc; 76541502Swpaul int media; 76641502Swpaul{ 76741502Swpaul u_int16_t bmcr; 76841502Swpaul struct ifnet *ifp; 76941502Swpaul 77041502Swpaul ifp = &sc->arpcom.ac_if; 77141502Swpaul 77241502Swpaul /* 77341502Swpaul * If an autoneg session is in progress, stop it. 77441502Swpaul */ 77541502Swpaul if (sc->vr_autoneg) { 77641502Swpaul printf("vr%d: canceling autoneg session\n", sc->vr_unit); 77741502Swpaul ifp->if_timer = sc->vr_autoneg = sc->vr_want_auto = 0; 77841502Swpaul bmcr = vr_phy_readreg(sc, PHY_BMCR); 77941502Swpaul bmcr &= ~PHY_BMCR_AUTONEGENBL; 78041502Swpaul vr_phy_writereg(sc, PHY_BMCR, bmcr); 78141502Swpaul } 78241502Swpaul 78341502Swpaul printf("vr%d: selecting MII, ", sc->vr_unit); 78441502Swpaul 78541502Swpaul bmcr = vr_phy_readreg(sc, PHY_BMCR); 78641502Swpaul 78741502Swpaul bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| 78841502Swpaul PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); 78941502Swpaul 79041502Swpaul if (IFM_SUBTYPE(media) == IFM_100_T4) { 79141502Swpaul printf("100Mbps/T4, half-duplex\n"); 79241502Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 79341502Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 79441502Swpaul } 79541502Swpaul 79641502Swpaul if (IFM_SUBTYPE(media) == IFM_100_TX) { 79741502Swpaul printf("100Mbps, "); 79841502Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 79941502Swpaul } 80041502Swpaul 80141502Swpaul if (IFM_SUBTYPE(media) == IFM_10_T) { 80241502Swpaul printf("10Mbps, "); 80341502Swpaul bmcr &= ~PHY_BMCR_SPEEDSEL; 80441502Swpaul } 80541502Swpaul 80641502Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 80741502Swpaul printf("full duplex\n"); 80841502Swpaul bmcr |= PHY_BMCR_DUPLEX; 80941502Swpaul } else { 81041502Swpaul printf("half duplex\n"); 81141502Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 81241502Swpaul } 81341502Swpaul 81441502Swpaul vr_setcfg(sc, bmcr); 81541502Swpaul vr_phy_writereg(sc, PHY_BMCR, bmcr); 81641502Swpaul 81741502Swpaul return; 81841502Swpaul} 81941502Swpaul 82041502Swpaul/* 82141502Swpaul * In order to fiddle with the 82241502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 82341502Swpaul * first have to put the transmit and/or receive logic in the idle state. 82441502Swpaul */ 82541502Swpaulstatic void vr_setcfg(sc, bmcr) 82641502Swpaul struct vr_softc *sc; 82741502Swpaul u_int16_t bmcr; 82841502Swpaul{ 82941502Swpaul int restart = 0; 83041502Swpaul 83141502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 83241502Swpaul restart = 1; 83341502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 83441502Swpaul } 83541502Swpaul 83641502Swpaul if (bmcr & PHY_BMCR_DUPLEX) 83741502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 83841502Swpaul else 83941502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 84041502Swpaul 84141502Swpaul if (restart) 84241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 84341502Swpaul 84441502Swpaul return; 84541502Swpaul} 84641502Swpaul 84741502Swpaulstatic void vr_reset(sc) 84841502Swpaul struct vr_softc *sc; 84941502Swpaul{ 85041502Swpaul register int i; 85141502Swpaul 85241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 85341502Swpaul 85441502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 85541502Swpaul DELAY(10); 85641502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 85741502Swpaul break; 85841502Swpaul } 85941502Swpaul if (i == VR_TIMEOUT) 86041502Swpaul printf("vr%d: reset never completed!\n", sc->vr_unit); 86141502Swpaul 86241502Swpaul /* Wait a little while for the chip to get its brains in order. */ 86341502Swpaul DELAY(1000); 86441502Swpaul 86541502Swpaul return; 86641502Swpaul} 86741502Swpaul 86841502Swpaul/* 86941502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 87041502Swpaul * IDs against our list and return a device name if we find a match. 87141502Swpaul */ 87241771Sdillonstatic const char * 87341502Swpaulvr_probe(config_id, device_id) 87441502Swpaul pcici_t config_id; 87541502Swpaul pcidi_t device_id; 87641502Swpaul{ 87741502Swpaul struct vr_type *t; 87841502Swpaul 87941502Swpaul t = vr_devs; 88041502Swpaul 88141502Swpaul while(t->vr_name != NULL) { 88241502Swpaul if ((device_id & 0xFFFF) == t->vr_vid && 88341502Swpaul ((device_id >> 16) & 0xFFFF) == t->vr_did) { 88441502Swpaul return(t->vr_name); 88541502Swpaul } 88641502Swpaul t++; 88741502Swpaul } 88841502Swpaul 88941502Swpaul return(NULL); 89041502Swpaul} 89141502Swpaul 89241502Swpaul/* 89341502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 89441502Swpaul * setup and ethernet/BPF attach. 89541502Swpaul */ 89641502Swpaulstatic void 89741502Swpaulvr_attach(config_id, unit) 89841502Swpaul pcici_t config_id; 89941502Swpaul int unit; 90041502Swpaul{ 90141502Swpaul int s, i; 90241502Swpaul#ifndef VR_USEIOSPACE 90341502Swpaul vm_offset_t pbase, vbase; 90441502Swpaul#endif 90541502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 90641502Swpaul u_int32_t command; 90741502Swpaul struct vr_softc *sc; 90841502Swpaul struct ifnet *ifp; 90941502Swpaul int media = IFM_ETHER|IFM_100_TX|IFM_FDX; 91041502Swpaul unsigned int round; 91141502Swpaul caddr_t roundptr; 91241502Swpaul struct vr_type *p; 91341502Swpaul u_int16_t phy_vid, phy_did, phy_sts; 91441502Swpaul 91541502Swpaul s = splimp(); 91641502Swpaul 91741502Swpaul sc = malloc(sizeof(struct vr_softc), M_DEVBUF, M_NOWAIT); 91841502Swpaul if (sc == NULL) { 91941502Swpaul printf("vr%d: no memory for softc struct!\n", unit); 92041502Swpaul return; 92141502Swpaul } 92241502Swpaul bzero(sc, sizeof(struct vr_softc)); 92341502Swpaul 92441502Swpaul /* 92541502Swpaul * Handle power management nonsense. 92641502Swpaul */ 92741502Swpaul 92841502Swpaul command = pci_conf_read(config_id, VR_PCI_CAPID) & 0x000000FF; 92941502Swpaul if (command == 0x01) { 93041502Swpaul 93141502Swpaul command = pci_conf_read(config_id, VR_PCI_PWRMGMTCTRL); 93241502Swpaul if (command & VR_PSTATE_MASK) { 93341502Swpaul u_int32_t iobase, membase, irq; 93441502Swpaul 93541502Swpaul /* Save important PCI config data. */ 93641502Swpaul iobase = pci_conf_read(config_id, VR_PCI_LOIO); 93741502Swpaul membase = pci_conf_read(config_id, VR_PCI_LOMEM); 93841502Swpaul irq = pci_conf_read(config_id, VR_PCI_INTLINE); 93941502Swpaul 94041502Swpaul /* Reset the power state. */ 94141502Swpaul printf("vr%d: chip is in D%d power mode " 94241502Swpaul "-- setting to D0\n", unit, command & VR_PSTATE_MASK); 94341502Swpaul command &= 0xFFFFFFFC; 94441502Swpaul pci_conf_write(config_id, VR_PCI_PWRMGMTCTRL, command); 94541502Swpaul 94641502Swpaul /* Restore PCI config data. */ 94741502Swpaul pci_conf_write(config_id, VR_PCI_LOIO, iobase); 94841502Swpaul pci_conf_write(config_id, VR_PCI_LOMEM, membase); 94941502Swpaul pci_conf_write(config_id, VR_PCI_INTLINE, irq); 95041502Swpaul } 95141502Swpaul } 95241502Swpaul 95341502Swpaul /* 95441502Swpaul * Map control/status registers. 95541502Swpaul */ 95641502Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 95741502Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 95841502Swpaul pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, command); 95941502Swpaul command = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG); 96041502Swpaul 96141502Swpaul#ifdef VR_USEIOSPACE 96241502Swpaul if (!(command & PCIM_CMD_PORTEN)) { 96341502Swpaul printf("vr%d: failed to enable I/O ports!\n", unit); 96441502Swpaul free(sc, M_DEVBUF); 96541502Swpaul goto fail; 96641502Swpaul } 96741502Swpaul 96841502Swpaul if (!pci_map_port(config_id, VR_PCI_LOIO, 96941502Swpaul (u_int16_t *)(&sc->vr_bhandle))) { 97041502Swpaul printf ("vr%d: couldn't map ports\n", unit); 97141502Swpaul goto fail; 97241502Swpaul } 97341502Swpaul sc->vr_btag = I386_BUS_SPACE_IO; 97441502Swpaul#else 97541502Swpaul if (!(command & PCIM_CMD_MEMEN)) { 97641502Swpaul printf("vr%d: failed to enable memory mapping!\n", unit); 97741502Swpaul goto fail; 97841502Swpaul } 97941502Swpaul 98041502Swpaul if (!pci_map_mem(config_id, VR_PCI_LOMEM, &vbase, &pbase)) { 98141502Swpaul printf ("vr%d: couldn't map memory\n", unit); 98241502Swpaul goto fail; 98341502Swpaul } 98441502Swpaul 98541502Swpaul sc->vr_bhandle = vbase; 98641502Swpaul sc->vr_btag = I386_BUS_SPACE_MEM; 98741502Swpaul#endif 98841502Swpaul 98941502Swpaul /* Allocate interrupt */ 99041502Swpaul if (!pci_map_int(config_id, vr_intr, sc, &net_imask)) { 99141502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 99241502Swpaul goto fail; 99341502Swpaul } 99441502Swpaul 99541502Swpaul /* Reset the adapter. */ 99641502Swpaul vr_reset(sc); 99741502Swpaul 99841502Swpaul /* 99941502Swpaul * Get station address. The way the Rhine chips work, 100041502Swpaul * you're not allowed to directly access the EEPROM once 100141502Swpaul * they've been programmed a special way. Consequently, 100241502Swpaul * we need to read the node address from the PAR0 and PAR1 100341502Swpaul * registers. 100441502Swpaul */ 100541502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 100641502Swpaul DELAY(200); 100741502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 100841502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 100941502Swpaul 101041502Swpaul /* 101141502Swpaul * A Rhine chip was detected. Inform the world. 101241502Swpaul */ 101341502Swpaul printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); 101441502Swpaul 101541502Swpaul sc->vr_unit = unit; 101641502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 101741502Swpaul 101841502Swpaul sc->vr_ldata_ptr = malloc(sizeof(struct vr_list_data) + 8, 101941502Swpaul M_DEVBUF, M_NOWAIT); 102041502Swpaul if (sc->vr_ldata_ptr == NULL) { 102141502Swpaul free(sc, M_DEVBUF); 102241502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 102341502Swpaul return; 102441502Swpaul } 102541502Swpaul 102641502Swpaul sc->vr_ldata = (struct vr_list_data *)sc->vr_ldata_ptr; 102741502Swpaul round = (unsigned int)sc->vr_ldata_ptr & 0xF; 102841502Swpaul roundptr = sc->vr_ldata_ptr; 102941502Swpaul for (i = 0; i < 8; i++) { 103041502Swpaul if (round % 8) { 103141502Swpaul round++; 103241502Swpaul roundptr++; 103341502Swpaul } else 103441502Swpaul break; 103541502Swpaul } 103641502Swpaul sc->vr_ldata = (struct vr_list_data *)roundptr; 103741502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 103841502Swpaul 103941502Swpaul ifp = &sc->arpcom.ac_if; 104041502Swpaul ifp->if_softc = sc; 104141502Swpaul ifp->if_unit = unit; 104241502Swpaul ifp->if_name = "vr"; 104341502Swpaul ifp->if_mtu = ETHERMTU; 104441502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 104541502Swpaul ifp->if_ioctl = vr_ioctl; 104641502Swpaul ifp->if_output = ether_output; 104741502Swpaul ifp->if_start = vr_start; 104841502Swpaul ifp->if_watchdog = vr_watchdog; 104941502Swpaul ifp->if_init = vr_init; 105041502Swpaul ifp->if_baudrate = 10000000; 105143515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 105241502Swpaul 105341502Swpaul if (bootverbose) 105441502Swpaul printf("vr%d: probing for a PHY\n", sc->vr_unit); 105541502Swpaul for (i = VR_PHYADDR_MIN; i < VR_PHYADDR_MAX + 1; i++) { 105641502Swpaul if (bootverbose) 105741502Swpaul printf("vr%d: checking address: %d\n", 105841502Swpaul sc->vr_unit, i); 105941502Swpaul sc->vr_phy_addr = i; 106041502Swpaul vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 106141502Swpaul DELAY(500); 106241502Swpaul while(vr_phy_readreg(sc, PHY_BMCR) 106341502Swpaul & PHY_BMCR_RESET); 106441502Swpaul if ((phy_sts = vr_phy_readreg(sc, PHY_BMSR))) 106541502Swpaul break; 106641502Swpaul } 106741502Swpaul if (phy_sts) { 106841502Swpaul phy_vid = vr_phy_readreg(sc, PHY_VENID); 106941502Swpaul phy_did = vr_phy_readreg(sc, PHY_DEVID); 107041502Swpaul if (bootverbose) 107141502Swpaul printf("vr%d: found PHY at address %d, ", 107241502Swpaul sc->vr_unit, sc->vr_phy_addr); 107341502Swpaul if (bootverbose) 107441502Swpaul printf("vendor id: %x device id: %x\n", 107541502Swpaul phy_vid, phy_did); 107641502Swpaul p = vr_phys; 107741502Swpaul while(p->vr_vid) { 107841502Swpaul if (phy_vid == p->vr_vid && 107941502Swpaul (phy_did | 0x000F) == p->vr_did) { 108041502Swpaul sc->vr_pinfo = p; 108141502Swpaul break; 108241502Swpaul } 108341502Swpaul p++; 108441502Swpaul } 108541502Swpaul if (sc->vr_pinfo == NULL) 108641502Swpaul sc->vr_pinfo = &vr_phys[PHY_UNKNOWN]; 108741502Swpaul if (bootverbose) 108841502Swpaul printf("vr%d: PHY type: %s\n", 108941502Swpaul sc->vr_unit, sc->vr_pinfo->vr_name); 109041502Swpaul } else { 109141502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 109241502Swpaul goto fail; 109341502Swpaul } 109441502Swpaul 109541502Swpaul /* 109641502Swpaul * Do ifmedia setup. 109741502Swpaul */ 109841502Swpaul ifmedia_init(&sc->ifmedia, 0, vr_ifmedia_upd, vr_ifmedia_sts); 109941502Swpaul 110041502Swpaul vr_getmode_mii(sc); 110141502Swpaul vr_autoneg_mii(sc, VR_FLAG_FORCEDELAY, 1); 110241502Swpaul media = sc->ifmedia.ifm_media; 110341502Swpaul vr_stop(sc); 110441502Swpaul 110541502Swpaul ifmedia_set(&sc->ifmedia, media); 110641502Swpaul 110741502Swpaul /* 110841502Swpaul * Call MI attach routines. 110941502Swpaul */ 111041502Swpaul if_attach(ifp); 111141502Swpaul ether_ifattach(ifp); 111241502Swpaul 111341502Swpaul#if NBPFILTER > 0 111441502Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 111541502Swpaul#endif 111641502Swpaul 111741502Swpaul at_shutdown(vr_shutdown, sc, SHUTDOWN_POST_SYNC); 111841502Swpaul 111941502Swpaulfail: 112041502Swpaul splx(s); 112141502Swpaul return; 112241502Swpaul} 112341502Swpaul 112441502Swpaul/* 112541502Swpaul * Initialize the transmit descriptors. 112641502Swpaul */ 112741502Swpaulstatic int vr_list_tx_init(sc) 112841502Swpaul struct vr_softc *sc; 112941502Swpaul{ 113041502Swpaul struct vr_chain_data *cd; 113141502Swpaul struct vr_list_data *ld; 113241502Swpaul int i; 113341502Swpaul 113441502Swpaul cd = &sc->vr_cdata; 113541502Swpaul ld = sc->vr_ldata; 113641502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 113741502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 113841502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 113941502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 114041502Swpaul &cd->vr_tx_chain[0]; 114141502Swpaul else 114241502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 114341502Swpaul &cd->vr_tx_chain[i + 1]; 114441502Swpaul } 114541502Swpaul 114641502Swpaul cd->vr_tx_free = &cd->vr_tx_chain[0]; 114741502Swpaul cd->vr_tx_tail = cd->vr_tx_head = NULL; 114841502Swpaul 114941502Swpaul return(0); 115041502Swpaul} 115141502Swpaul 115241502Swpaul 115341502Swpaul/* 115441502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 115541502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 115641502Swpaul * points back to the first. 115741502Swpaul */ 115841502Swpaulstatic int vr_list_rx_init(sc) 115941502Swpaul struct vr_softc *sc; 116041502Swpaul{ 116141502Swpaul struct vr_chain_data *cd; 116241502Swpaul struct vr_list_data *ld; 116341502Swpaul int i; 116441502Swpaul 116541502Swpaul cd = &sc->vr_cdata; 116641502Swpaul ld = sc->vr_ldata; 116741502Swpaul 116841502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 116941502Swpaul cd->vr_rx_chain[i].vr_ptr = 117041502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 117141502Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i]) == ENOBUFS) 117241502Swpaul return(ENOBUFS); 117341502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 117441502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 117541502Swpaul &cd->vr_rx_chain[0]; 117641502Swpaul ld->vr_rx_list[i].vr_next = 117741502Swpaul vtophys(&ld->vr_rx_list[0]); 117841502Swpaul } else { 117941502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 118041502Swpaul &cd->vr_rx_chain[i + 1]; 118141502Swpaul ld->vr_rx_list[i].vr_next = 118241502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 118341502Swpaul } 118441502Swpaul } 118541502Swpaul 118641502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 118741502Swpaul 118841502Swpaul return(0); 118941502Swpaul} 119041502Swpaul 119141502Swpaul/* 119241502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 119341502Swpaul * Note: the length fields are only 11 bits wide, which means the 119441502Swpaul * largest size we can specify is 2047. This is important because 119541502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 119641502Swpaul * overflow the field and make a mess. 119741502Swpaul */ 119841502Swpaulstatic int vr_newbuf(sc, c) 119941502Swpaul struct vr_softc *sc; 120041502Swpaul struct vr_chain_onefrag *c; 120141502Swpaul{ 120241502Swpaul struct mbuf *m_new = NULL; 120341502Swpaul 120441502Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 120541502Swpaul if (m_new == NULL) { 120641502Swpaul printf("vr%d: no memory for rx list -- packet dropped!\n", 120741502Swpaul sc->vr_unit); 120841502Swpaul return(ENOBUFS); 120941502Swpaul } 121041502Swpaul 121141502Swpaul MCLGET(m_new, M_DONTWAIT); 121241502Swpaul if (!(m_new->m_flags & M_EXT)) { 121341502Swpaul printf("vr%d: no memory for rx list -- packet dropped!\n", 121441502Swpaul sc->vr_unit); 121541502Swpaul m_freem(m_new); 121641502Swpaul return(ENOBUFS); 121741502Swpaul } 121841502Swpaul 121941502Swpaul c->vr_mbuf = m_new; 122041502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 122141502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 122242491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 122341502Swpaul 122441502Swpaul return(0); 122541502Swpaul} 122641502Swpaul 122741502Swpaul/* 122841502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 122941502Swpaul * the higher level protocols. 123041502Swpaul */ 123141502Swpaulstatic void vr_rxeof(sc) 123241502Swpaul struct vr_softc *sc; 123341502Swpaul{ 123441502Swpaul struct ether_header *eh; 123541502Swpaul struct mbuf *m; 123641502Swpaul struct ifnet *ifp; 123741502Swpaul struct vr_chain_onefrag *cur_rx; 123841502Swpaul int total_len = 0; 123941502Swpaul u_int32_t rxstat; 124041502Swpaul 124141502Swpaul ifp = &sc->arpcom.ac_if; 124241502Swpaul 124341502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 124441502Swpaul VR_RXSTAT_OWN)) { 124541502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 124641502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 124741502Swpaul 124841502Swpaul /* 124941502Swpaul * If an error occurs, update stats, clear the 125041502Swpaul * status word and leave the mbuf cluster in place: 125141502Swpaul * it should simply get re-used next time this descriptor 125241502Swpaul * comes up in the ring. 125341502Swpaul */ 125441502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 125541502Swpaul ifp->if_ierrors++; 125641502Swpaul printf("vr%d: rx error: ", sc->vr_unit); 125741502Swpaul switch(rxstat & 0x000000FF) { 125841502Swpaul case VR_RXSTAT_CRCERR: 125941502Swpaul printf("crc error\n"); 126041502Swpaul break; 126141502Swpaul case VR_RXSTAT_FRAMEALIGNERR: 126241502Swpaul printf("frame alignment error\n"); 126341502Swpaul break; 126441502Swpaul case VR_RXSTAT_FIFOOFLOW: 126541502Swpaul printf("FIFO overflow\n"); 126641502Swpaul break; 126741502Swpaul case VR_RXSTAT_GIANT: 126841502Swpaul printf("received giant packet\n"); 126941502Swpaul break; 127041502Swpaul case VR_RXSTAT_RUNT: 127141502Swpaul printf("received runt packet\n"); 127241502Swpaul break; 127341502Swpaul case VR_RXSTAT_BUSERR: 127441502Swpaul printf("system bus error\n"); 127541502Swpaul break; 127641502Swpaul case VR_RXSTAT_BUFFERR: 127741502Swpaul printf("rx buffer error\n"); 127841502Swpaul break; 127941502Swpaul default: 128041502Swpaul printf("unknown rx error\n"); 128141502Swpaul break; 128241502Swpaul } 128341502Swpaul cur_rx->vr_ptr->vr_status = VR_RXSTAT; 128442491Swpaul cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN; 128541502Swpaul continue; 128641502Swpaul } 128741502Swpaul 128841502Swpaul /* No errors; receive the packet. */ 128941502Swpaul m = cur_rx->vr_mbuf; 129041502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 129141502Swpaul 129241502Swpaul /* 129342048Swpaul * XXX The VIA Rhine chip includes the CRC with every 129442048Swpaul * received frame, and there's no way to turn this 129542048Swpaul * behavior off (at least, I can't find anything in 129642048Swpaul * the manual that explains how to do it) so we have 129742048Swpaul * to trim off the CRC manually. 129842048Swpaul */ 129942048Swpaul total_len -= ETHER_CRC_LEN; 130042048Swpaul 130142048Swpaul /* 130241502Swpaul * Try to conjure up a new mbuf cluster. If that 130341502Swpaul * fails, it means we have an out of memory condition and 130441502Swpaul * should leave the buffer in place and continue. This will 130541502Swpaul * result in a lost packet, but there's little else we 130641502Swpaul * can do in this situation. 130741502Swpaul */ 130841502Swpaul if (vr_newbuf(sc, cur_rx) == ENOBUFS) { 130941502Swpaul ifp->if_ierrors++; 131042260Swpaul cur_rx->vr_ptr->vr_status = VR_RXSTAT; 131142491Swpaul cur_rx->vr_ptr->vr_ctl = VR_RXCTL|VR_RXLEN; 131241502Swpaul continue; 131341502Swpaul } 131441502Swpaul 131541502Swpaul ifp->if_ipackets++; 131641502Swpaul eh = mtod(m, struct ether_header *); 131741502Swpaul m->m_pkthdr.rcvif = ifp; 131841502Swpaul m->m_pkthdr.len = m->m_len = total_len; 131941502Swpaul#if NBPFILTER > 0 132041502Swpaul /* 132141502Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 132241502Swpaul * don't pass it up to the ether_input() layer unless it's 132341502Swpaul * a broadcast packet, multicast packet, matches our ethernet 132441502Swpaul * address or the interface is in promiscuous mode. 132541502Swpaul */ 132641502Swpaul if (ifp->if_bpf) { 132741502Swpaul bpf_mtap(ifp, m); 132841502Swpaul if (ifp->if_flags & IFF_PROMISC && 132941502Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 133041502Swpaul ETHER_ADDR_LEN) && 133141502Swpaul (eh->ether_dhost[0] & 1) == 0)) { 133241502Swpaul m_freem(m); 133341502Swpaul continue; 133441502Swpaul } 133541502Swpaul } 133641502Swpaul#endif 133741502Swpaul /* Remove header from mbuf and pass it on. */ 133841502Swpaul m_adj(m, sizeof(struct ether_header)); 133941502Swpaul ether_input(ifp, eh, m); 134041502Swpaul } 134141502Swpaul 134241502Swpaul return; 134341502Swpaul} 134441502Swpaul 134541502Swpaulvoid vr_rxeoc(sc) 134641502Swpaul struct vr_softc *sc; 134741502Swpaul{ 134841502Swpaul 134941502Swpaul vr_rxeof(sc); 135041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 135141502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 135241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 135341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 135441502Swpaul 135541502Swpaul return; 135641502Swpaul} 135741502Swpaul 135841502Swpaul/* 135941502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 136041502Swpaul * the list buffers. 136141502Swpaul */ 136241502Swpaul 136341502Swpaulstatic void vr_txeof(sc) 136441502Swpaul struct vr_softc *sc; 136541502Swpaul{ 136641502Swpaul struct vr_chain *cur_tx; 136741502Swpaul struct ifnet *ifp; 136841502Swpaul register struct mbuf *n; 136941502Swpaul 137041502Swpaul ifp = &sc->arpcom.ac_if; 137141502Swpaul 137241502Swpaul /* Clear the timeout timer. */ 137341502Swpaul ifp->if_timer = 0; 137441502Swpaul 137541502Swpaul /* Sanity check. */ 137641502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 137741502Swpaul return; 137841502Swpaul 137941502Swpaul /* 138041502Swpaul * Go through our tx list and free mbufs for those 138141502Swpaul * frames that have been transmitted. 138241502Swpaul */ 138341502Swpaul while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { 138441502Swpaul u_int32_t txstat; 138541502Swpaul 138641502Swpaul cur_tx = sc->vr_cdata.vr_tx_head; 138741502Swpaul txstat = cur_tx->vr_ptr->vr_status; 138841502Swpaul 138942491Swpaul if (txstat & VR_TXSTAT_OWN) 139041502Swpaul break; 139141502Swpaul 139241502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 139341502Swpaul ifp->if_oerrors++; 139441502Swpaul if (txstat & VR_TXSTAT_DEFER) 139541502Swpaul ifp->if_collisions++; 139641502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 139741502Swpaul ifp->if_collisions++; 139841502Swpaul } 139941502Swpaul 140041502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 140141502Swpaul 140241502Swpaul ifp->if_opackets++; 140341502Swpaul MFREE(cur_tx->vr_mbuf, n); 140441502Swpaul cur_tx->vr_mbuf = NULL; 140541502Swpaul 140641502Swpaul if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { 140741502Swpaul sc->vr_cdata.vr_tx_head = NULL; 140841502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 140941502Swpaul break; 141041502Swpaul } 141141502Swpaul 141241502Swpaul sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; 141341502Swpaul } 141441502Swpaul 141541502Swpaul return; 141641502Swpaul} 141741502Swpaul 141841502Swpaul/* 141941502Swpaul * TX 'end of channel' interrupt handler. 142041502Swpaul */ 142141502Swpaulstatic void vr_txeoc(sc) 142241502Swpaul struct vr_softc *sc; 142341502Swpaul{ 142441502Swpaul struct ifnet *ifp; 142541502Swpaul 142641502Swpaul ifp = &sc->arpcom.ac_if; 142741502Swpaul 142841502Swpaul ifp->if_timer = 0; 142941502Swpaul 143041502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) { 143141502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 143241502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 143341502Swpaul if (sc->vr_want_auto) 143441502Swpaul vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); 143541502Swpaul } 143641502Swpaul 143741502Swpaul return; 143841502Swpaul} 143941502Swpaul 144041502Swpaulstatic void vr_intr(arg) 144141502Swpaul void *arg; 144241502Swpaul{ 144341502Swpaul struct vr_softc *sc; 144441502Swpaul struct ifnet *ifp; 144541502Swpaul u_int16_t status; 144641502Swpaul 144741502Swpaul sc = arg; 144841502Swpaul ifp = &sc->arpcom.ac_if; 144941502Swpaul 145041502Swpaul /* Supress unwanted interrupts. */ 145141502Swpaul if (!(ifp->if_flags & IFF_UP)) { 145241502Swpaul vr_stop(sc); 145341502Swpaul return; 145441502Swpaul } 145541502Swpaul 145641502Swpaul /* Disable interrupts. */ 145741502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 145841502Swpaul 145941502Swpaul for (;;) { 146041502Swpaul 146141502Swpaul status = CSR_READ_2(sc, VR_ISR); 146241502Swpaul if (status) 146341502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 146441502Swpaul 146541502Swpaul if ((status & VR_INTRS) == 0) 146641502Swpaul break; 146741502Swpaul 146841502Swpaul if (status & VR_ISR_RX_OK) 146941502Swpaul vr_rxeof(sc); 147041502Swpaul 147141502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 147241502Swpaul (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) || 147341502Swpaul (status & VR_ISR_RX_DROPPED)) { 147441502Swpaul vr_rxeof(sc); 147541502Swpaul vr_rxeoc(sc); 147641502Swpaul } 147741502Swpaul 147841502Swpaul if (status & VR_ISR_TX_OK) { 147941502Swpaul vr_txeof(sc); 148041502Swpaul vr_txeoc(sc); 148141502Swpaul } 148241502Swpaul 148341502Swpaul if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){ 148441502Swpaul ifp->if_oerrors++; 148541502Swpaul vr_txeof(sc); 148641502Swpaul if (sc->vr_cdata.vr_tx_head != NULL) { 148741502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 148841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 148941502Swpaul } 149041502Swpaul } 149141502Swpaul 149241502Swpaul if (status & VR_ISR_BUSERR) { 149341502Swpaul vr_reset(sc); 149441502Swpaul vr_init(sc); 149541502Swpaul } 149641502Swpaul } 149741502Swpaul 149841502Swpaul /* Re-enable interrupts. */ 149941502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 150041502Swpaul 150141502Swpaul if (ifp->if_snd.ifq_head != NULL) { 150241502Swpaul vr_start(ifp); 150341502Swpaul } 150441502Swpaul 150541502Swpaul return; 150641502Swpaul} 150741502Swpaul 150841502Swpaul/* 150941502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 151041502Swpaul * pointers to the fragment pointers. 151141502Swpaul */ 151241502Swpaulstatic int vr_encap(sc, c, m_head) 151341502Swpaul struct vr_softc *sc; 151441502Swpaul struct vr_chain *c; 151541502Swpaul struct mbuf *m_head; 151641502Swpaul{ 151741502Swpaul int frag = 0; 151841502Swpaul struct vr_desc *f = NULL; 151941502Swpaul int total_len; 152041502Swpaul struct mbuf *m; 152141502Swpaul 152241502Swpaul m = m_head; 152341502Swpaul total_len = 0; 152441502Swpaul 152541502Swpaul /* 152641502Swpaul * The VIA Rhine wants packet buffers to be longword 152741502Swpaul * aligned, but very often our mbufs aren't. Rather than 152841502Swpaul * waste time trying to decide when to copy and when not 152941502Swpaul * to copy, just do it all the time. 153041502Swpaul */ 153141502Swpaul if (m != NULL) { 153241502Swpaul struct mbuf *m_new = NULL; 153341502Swpaul 153441502Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 153541502Swpaul if (m_new == NULL) { 153641502Swpaul printf("vr%d: no memory for tx list", sc->vr_unit); 153741502Swpaul return(1); 153841502Swpaul } 153941502Swpaul if (m_head->m_pkthdr.len > MHLEN) { 154041502Swpaul MCLGET(m_new, M_DONTWAIT); 154141502Swpaul if (!(m_new->m_flags & M_EXT)) { 154241502Swpaul m_freem(m_new); 154341502Swpaul printf("vr%d: no memory for tx list", 154441502Swpaul sc->vr_unit); 154541502Swpaul return(1); 154641502Swpaul } 154741502Swpaul } 154841502Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 154941502Swpaul mtod(m_new, caddr_t)); 155041502Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 155141502Swpaul m_freem(m_head); 155241502Swpaul m_head = m_new; 155341502Swpaul /* 155441502Swpaul * The Rhine chip doesn't auto-pad, so we have to make 155541502Swpaul * sure to pad short frames out to the minimum frame length 155641502Swpaul * ourselves. 155741502Swpaul */ 155841502Swpaul if (m_head->m_len < VR_MIN_FRAMELEN) { 155941502Swpaul m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; 156041502Swpaul m_new->m_len = m_new->m_pkthdr.len; 156141502Swpaul } 156241502Swpaul f = c->vr_ptr; 156341502Swpaul f->vr_data = vtophys(mtod(m_new, caddr_t)); 156441502Swpaul f->vr_ctl = total_len = m_new->m_len; 156541502Swpaul f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 156641502Swpaul f->vr_status = 0; 156741502Swpaul frag = 1; 156841502Swpaul } 156941502Swpaul 157041502Swpaul c->vr_mbuf = m_head; 157142491Swpaul c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 157241502Swpaul c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 157341502Swpaul 157441502Swpaul return(0); 157541502Swpaul} 157641502Swpaul 157741502Swpaul/* 157841502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 157941502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 158041502Swpaul * copy of the pointers since the transmit list fragment pointers are 158141502Swpaul * physical addresses. 158241502Swpaul */ 158341502Swpaul 158441502Swpaulstatic void vr_start(ifp) 158541502Swpaul struct ifnet *ifp; 158641502Swpaul{ 158741502Swpaul struct vr_softc *sc; 158841502Swpaul struct mbuf *m_head = NULL; 158941502Swpaul struct vr_chain *cur_tx = NULL, *start_tx; 159041502Swpaul 159141502Swpaul sc = ifp->if_softc; 159241502Swpaul 159341502Swpaul if (sc->vr_autoneg) { 159441502Swpaul sc->vr_tx_pend = 1; 159541502Swpaul return; 159641502Swpaul } 159741502Swpaul 159841502Swpaul /* 159941502Swpaul * Check for an available queue slot. If there are none, 160041502Swpaul * punt. 160141502Swpaul */ 160241502Swpaul if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { 160341502Swpaul ifp->if_flags |= IFF_OACTIVE; 160441502Swpaul return; 160541502Swpaul } 160641502Swpaul 160741502Swpaul start_tx = sc->vr_cdata.vr_tx_free; 160841502Swpaul 160941502Swpaul while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { 161041502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 161141502Swpaul if (m_head == NULL) 161241502Swpaul break; 161341502Swpaul 161441502Swpaul /* Pick a descriptor off the free list. */ 161541502Swpaul cur_tx = sc->vr_cdata.vr_tx_free; 161641502Swpaul sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; 161741502Swpaul 161841502Swpaul /* Pack the data into the descriptor. */ 161941502Swpaul vr_encap(sc, cur_tx, m_head); 162041502Swpaul 162141502Swpaul if (cur_tx != start_tx) 162241502Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 162341502Swpaul 162441502Swpaul#if NBPFILTER > 0 162541502Swpaul /* 162641502Swpaul * If there's a BPF listener, bounce a copy of this frame 162741502Swpaul * to him. 162841502Swpaul */ 162941502Swpaul if (ifp->if_bpf) 163041502Swpaul bpf_mtap(ifp, cur_tx->vr_mbuf); 163141502Swpaul#endif 163242491Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 163342491Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_TX_GO); 163441502Swpaul } 163541502Swpaul 163641502Swpaul /* 163741526Swpaul * If there are no frames queued, bail. 163841526Swpaul */ 163941526Swpaul if (cur_tx == NULL) 164041526Swpaul return; 164141526Swpaul 164241502Swpaul sc->vr_cdata.vr_tx_tail = cur_tx; 164341502Swpaul 164442491Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 164541502Swpaul sc->vr_cdata.vr_tx_head = start_tx; 164641502Swpaul 164741502Swpaul /* 164841502Swpaul * Set a timeout in case the chip goes out to lunch. 164941502Swpaul */ 165041502Swpaul ifp->if_timer = 5; 165141502Swpaul 165241502Swpaul return; 165341502Swpaul} 165441502Swpaul 165541502Swpaulstatic void vr_init(xsc) 165641502Swpaul void *xsc; 165741502Swpaul{ 165841502Swpaul struct vr_softc *sc = xsc; 165941502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 166041502Swpaul u_int16_t phy_bmcr = 0; 166141502Swpaul int s; 166241502Swpaul 166341502Swpaul if (sc->vr_autoneg) 166441502Swpaul return; 166541502Swpaul 166641502Swpaul s = splimp(); 166741502Swpaul 166841502Swpaul if (sc->vr_pinfo != NULL) 166941502Swpaul phy_bmcr = vr_phy_readreg(sc, PHY_BMCR); 167041502Swpaul 167141502Swpaul /* 167241502Swpaul * Cancel pending I/O and free all RX/TX buffers. 167341502Swpaul */ 167441502Swpaul vr_stop(sc); 167541502Swpaul vr_reset(sc); 167641502Swpaul 167741502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 167841502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD); 167941502Swpaul 168041502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 168141502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 168241502Swpaul 168341502Swpaul /* Init circular RX list. */ 168441502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 168541502Swpaul printf("vr%d: initialization failed: no " 168641502Swpaul "memory for rx buffers\n", sc->vr_unit); 168741502Swpaul vr_stop(sc); 168841502Swpaul (void)splx(s); 168941502Swpaul return; 169041502Swpaul } 169141502Swpaul 169241502Swpaul /* 169341502Swpaul * Init tx descriptors. 169441502Swpaul */ 169541502Swpaul vr_list_tx_init(sc); 169641502Swpaul 169741502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 169841502Swpaul if (ifp->if_flags & IFF_PROMISC) 169941502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 170041502Swpaul else 170141502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 170241502Swpaul 170341502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 170441502Swpaul if (ifp->if_flags & IFF_BROADCAST) 170541502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 170641502Swpaul else 170741502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 170841502Swpaul 170941502Swpaul /* 171041502Swpaul * Program the multicast filter, if necessary. 171141502Swpaul */ 171241502Swpaul vr_setmulti(sc); 171341502Swpaul 171441502Swpaul /* 171541502Swpaul * Load the address of the RX list. 171641502Swpaul */ 171741502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 171841502Swpaul 171941502Swpaul /* Enable receiver and transmitter. */ 172041502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 172141502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 172241502Swpaul VR_CMD_RX_GO); 172341502Swpaul 172441502Swpaul vr_setcfg(sc, vr_phy_readreg(sc, PHY_BMCR)); 172541502Swpaul 172641502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 172741502Swpaul 172841502Swpaul /* 172941502Swpaul * Enable interrupts. 173041502Swpaul */ 173141502Swpaul CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 173241502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 173341502Swpaul 173441502Swpaul /* Restore state of BMCR */ 173541502Swpaul if (sc->vr_pinfo != NULL) 173641502Swpaul vr_phy_writereg(sc, PHY_BMCR, phy_bmcr); 173741502Swpaul 173841502Swpaul ifp->if_flags |= IFF_RUNNING; 173941502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 174041502Swpaul 174141502Swpaul (void)splx(s); 174241502Swpaul 174341502Swpaul return; 174441502Swpaul} 174541502Swpaul 174641502Swpaul/* 174741502Swpaul * Set media options. 174841502Swpaul */ 174941502Swpaulstatic int vr_ifmedia_upd(ifp) 175041502Swpaul struct ifnet *ifp; 175141502Swpaul{ 175241502Swpaul struct vr_softc *sc; 175341502Swpaul struct ifmedia *ifm; 175441502Swpaul 175541502Swpaul sc = ifp->if_softc; 175641502Swpaul ifm = &sc->ifmedia; 175741502Swpaul 175841502Swpaul if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 175941502Swpaul return(EINVAL); 176041502Swpaul 176141502Swpaul if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 176241502Swpaul vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); 176341502Swpaul else 176441502Swpaul vr_setmode_mii(sc, ifm->ifm_media); 176541502Swpaul 176641502Swpaul return(0); 176741502Swpaul} 176841502Swpaul 176941502Swpaul/* 177041502Swpaul * Report current media status. 177141502Swpaul */ 177241502Swpaulstatic void vr_ifmedia_sts(ifp, ifmr) 177341502Swpaul struct ifnet *ifp; 177441502Swpaul struct ifmediareq *ifmr; 177541502Swpaul{ 177641502Swpaul struct vr_softc *sc; 177741502Swpaul u_int16_t advert = 0, ability = 0; 177841502Swpaul 177941502Swpaul sc = ifp->if_softc; 178041502Swpaul 178141502Swpaul ifmr->ifm_active = IFM_ETHER; 178241502Swpaul 178341502Swpaul if (!(vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { 178441502Swpaul if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) 178541502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX; 178641502Swpaul else 178741502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T; 178841502Swpaul if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) 178941502Swpaul ifmr->ifm_active |= IFM_FDX; 179041502Swpaul else 179141502Swpaul ifmr->ifm_active |= IFM_HDX; 179241502Swpaul return; 179341502Swpaul } 179441502Swpaul 179541502Swpaul ability = vr_phy_readreg(sc, PHY_LPAR); 179641502Swpaul advert = vr_phy_readreg(sc, PHY_ANAR); 179741502Swpaul if (advert & PHY_ANAR_100BT4 && 179841502Swpaul ability & PHY_ANAR_100BT4) { 179941502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_T4; 180041502Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 180141502Swpaul ability & PHY_ANAR_100BTXFULL) { 180241502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; 180341502Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 180441502Swpaul ability & PHY_ANAR_100BTXHALF) { 180541502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; 180641502Swpaul } else if (advert & PHY_ANAR_10BTFULL && 180741502Swpaul ability & PHY_ANAR_10BTFULL) { 180841502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; 180941502Swpaul } else if (advert & PHY_ANAR_10BTHALF && 181041502Swpaul ability & PHY_ANAR_10BTHALF) { 181141502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; 181241502Swpaul } 181341502Swpaul 181441502Swpaul return; 181541502Swpaul} 181641502Swpaul 181741502Swpaulstatic int vr_ioctl(ifp, command, data) 181841502Swpaul struct ifnet *ifp; 181941502Swpaul u_long command; 182041502Swpaul caddr_t data; 182141502Swpaul{ 182241502Swpaul struct vr_softc *sc = ifp->if_softc; 182341502Swpaul struct ifreq *ifr = (struct ifreq *) data; 182441502Swpaul int s, error = 0; 182541502Swpaul 182641502Swpaul s = splimp(); 182741502Swpaul 182841502Swpaul switch(command) { 182941502Swpaul case SIOCSIFADDR: 183041502Swpaul case SIOCGIFADDR: 183141502Swpaul case SIOCSIFMTU: 183241502Swpaul error = ether_ioctl(ifp, command, data); 183341502Swpaul break; 183441502Swpaul case SIOCSIFFLAGS: 183541502Swpaul if (ifp->if_flags & IFF_UP) { 183641502Swpaul vr_init(sc); 183741502Swpaul } else { 183841502Swpaul if (ifp->if_flags & IFF_RUNNING) 183941502Swpaul vr_stop(sc); 184041502Swpaul } 184141502Swpaul error = 0; 184241502Swpaul break; 184341502Swpaul case SIOCADDMULTI: 184441502Swpaul case SIOCDELMULTI: 184541502Swpaul vr_setmulti(sc); 184641502Swpaul error = 0; 184741502Swpaul break; 184841502Swpaul case SIOCGIFMEDIA: 184941502Swpaul case SIOCSIFMEDIA: 185041502Swpaul error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 185141502Swpaul break; 185241502Swpaul default: 185341502Swpaul error = EINVAL; 185441502Swpaul break; 185541502Swpaul } 185641502Swpaul 185741502Swpaul (void)splx(s); 185841502Swpaul 185941502Swpaul return(error); 186041502Swpaul} 186141502Swpaul 186241502Swpaulstatic void vr_watchdog(ifp) 186341502Swpaul struct ifnet *ifp; 186441502Swpaul{ 186541502Swpaul struct vr_softc *sc; 186641502Swpaul 186741502Swpaul sc = ifp->if_softc; 186841502Swpaul 186941502Swpaul if (sc->vr_autoneg) { 187041502Swpaul vr_autoneg_mii(sc, VR_FLAG_DELAYTIMEO, 1); 187141502Swpaul return; 187241502Swpaul } 187341502Swpaul 187441502Swpaul ifp->if_oerrors++; 187541502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 187641502Swpaul 187741502Swpaul if (!(vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) 187841502Swpaul printf("vr%d: no carrier - transceiver cable problem?\n", 187941502Swpaul sc->vr_unit); 188041502Swpaul 188141502Swpaul vr_stop(sc); 188241502Swpaul vr_reset(sc); 188341502Swpaul vr_init(sc); 188441502Swpaul 188541502Swpaul if (ifp->if_snd.ifq_head != NULL) 188641502Swpaul vr_start(ifp); 188741502Swpaul 188841502Swpaul return; 188941502Swpaul} 189041502Swpaul 189141502Swpaul/* 189241502Swpaul * Stop the adapter and free any mbufs allocated to the 189341502Swpaul * RX and TX lists. 189441502Swpaul */ 189541502Swpaulstatic void vr_stop(sc) 189641502Swpaul struct vr_softc *sc; 189741502Swpaul{ 189841502Swpaul register int i; 189941502Swpaul struct ifnet *ifp; 190041502Swpaul 190141502Swpaul ifp = &sc->arpcom.ac_if; 190241502Swpaul ifp->if_timer = 0; 190341502Swpaul 190441502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 190541502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 190641502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 190741502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 190841502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 190941502Swpaul 191041502Swpaul /* 191141502Swpaul * Free data in the RX lists. 191241502Swpaul */ 191341502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 191441502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 191541502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 191641502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 191741502Swpaul } 191841502Swpaul } 191941502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 192041502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 192141502Swpaul 192241502Swpaul /* 192341502Swpaul * Free the TX list buffers. 192441502Swpaul */ 192541502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 192641502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 192741502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 192841502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 192941502Swpaul } 193041502Swpaul } 193141502Swpaul 193241502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 193341502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 193441502Swpaul 193541502Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 193641502Swpaul 193741502Swpaul return; 193841502Swpaul} 193941502Swpaul 194041502Swpaul/* 194141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 194241502Swpaul * get confused by errant DMAs when rebooting. 194341502Swpaul */ 194441502Swpaulstatic void vr_shutdown(howto, arg) 194541502Swpaul int howto; 194641502Swpaul void *arg; 194741502Swpaul{ 194841502Swpaul struct vr_softc *sc = (struct vr_softc *)arg; 194941502Swpaul 195041502Swpaul vr_stop(sc); 195141502Swpaul 195241502Swpaul return; 195341502Swpaul} 195441502Swpaul 195541502Swpaulstatic struct pci_device vr_device = { 195641502Swpaul "vr", 195741502Swpaul vr_probe, 195841502Swpaul vr_attach, 195941502Swpaul &vr_count, 196041502Swpaul NULL 196141502Swpaul}; 196241502SwpaulDATA_SET(pcidevice_set, vr_device); 1963