if_vr.c revision 50477
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 * 3250477Speter * $FreeBSD: head/sys/dev/vr/if_vr.c 50477 1999-08-28 01:08:13Z peter $ 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 6248645Sdes#include "bpf.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 7848645Sdes#if NBPF > 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> 8849610Swpaul#include <machine/resource.h> 8949610Swpaul#include <sys/bus.h> 9049610Swpaul#include <sys/rman.h> 9141502Swpaul 9241502Swpaul#include <pci/pcireg.h> 9341502Swpaul#include <pci/pcivar.h> 9441502Swpaul 9541502Swpaul#define VR_USEIOSPACE 9641502Swpaul 9741502Swpaul/* #define VR_BACKGROUND_AUTONEG */ 9841502Swpaul 9941502Swpaul#include <pci/if_vrreg.h> 10041502Swpaul 10141502Swpaul#ifndef lint 10241591Sarchiestatic const char rcsid[] = 10350477Speter "$FreeBSD: head/sys/dev/vr/if_vr.c 50477 1999-08-28 01:08:13Z peter $"; 10441502Swpaul#endif 10541502Swpaul 10641502Swpaul/* 10741502Swpaul * Various supported device vendors/types and their names. 10841502Swpaul */ 10941502Swpaulstatic struct vr_type vr_devs[] = { 11041502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 11141502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 11241502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11341502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11444238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 11544238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 11644238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 11744238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 11841502Swpaul { 0, 0, NULL } 11941502Swpaul}; 12041502Swpaul 12141502Swpaul/* 12241502Swpaul * Various supported PHY vendors/types and their names. Note that 12341502Swpaul * this driver will work with pretty much any MII-compliant PHY, 12441502Swpaul * so failure to positively identify the chip is not a fatal error. 12541502Swpaul */ 12641502Swpaul 12741502Swpaulstatic struct vr_type vr_phys[] = { 12841502Swpaul { TI_PHY_VENDORID, TI_PHY_10BT, "<TI ThunderLAN 10BT (internal)>" }, 12941502Swpaul { TI_PHY_VENDORID, TI_PHY_100VGPMI, "<TI TNETE211 100VG Any-LAN>" }, 13041502Swpaul { NS_PHY_VENDORID, NS_PHY_83840A, "<National Semiconductor DP83840A>"}, 13141502Swpaul { LEVEL1_PHY_VENDORID, LEVEL1_PHY_LXT970, "<Level 1 LXT970>" }, 13241502Swpaul { INTEL_PHY_VENDORID, INTEL_PHY_82555, "<Intel 82555>" }, 13341502Swpaul { SEEQ_PHY_VENDORID, SEEQ_PHY_80220, "<SEEQ 80220>" }, 13441502Swpaul { 0, 0, "<MII-compliant physical interface>" } 13541502Swpaul}; 13641502Swpaul 13749610Swpaulstatic int vr_probe __P((device_t)); 13849610Swpaulstatic int vr_attach __P((device_t)); 13949610Swpaulstatic int vr_detach __P((device_t)); 14041502Swpaul 14141502Swpaulstatic int vr_newbuf __P((struct vr_softc *, 14249610Swpaul struct vr_chain_onefrag *, 14349610Swpaul struct mbuf *)); 14441502Swpaulstatic int vr_encap __P((struct vr_softc *, struct vr_chain *, 14541502Swpaul struct mbuf * )); 14641502Swpaul 14741502Swpaulstatic void vr_rxeof __P((struct vr_softc *)); 14841502Swpaulstatic void vr_rxeoc __P((struct vr_softc *)); 14941502Swpaulstatic void vr_txeof __P((struct vr_softc *)); 15041502Swpaulstatic void vr_txeoc __P((struct vr_softc *)); 15141502Swpaulstatic void vr_intr __P((void *)); 15241502Swpaulstatic void vr_start __P((struct ifnet *)); 15341502Swpaulstatic int vr_ioctl __P((struct ifnet *, u_long, caddr_t)); 15441502Swpaulstatic void vr_init __P((void *)); 15541502Swpaulstatic void vr_stop __P((struct vr_softc *)); 15641502Swpaulstatic void vr_watchdog __P((struct ifnet *)); 15749610Swpaulstatic void vr_shutdown __P((device_t)); 15841502Swpaulstatic int vr_ifmedia_upd __P((struct ifnet *)); 15941502Swpaulstatic void vr_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 16041502Swpaul 16141502Swpaulstatic void vr_mii_sync __P((struct vr_softc *)); 16241502Swpaulstatic void vr_mii_send __P((struct vr_softc *, u_int32_t, int)); 16341502Swpaulstatic int vr_mii_readreg __P((struct vr_softc *, struct vr_mii_frame *)); 16441502Swpaulstatic int vr_mii_writereg __P((struct vr_softc *, struct vr_mii_frame *)); 16541502Swpaulstatic u_int16_t vr_phy_readreg __P((struct vr_softc *, int)); 16641502Swpaulstatic void vr_phy_writereg __P((struct vr_softc *, u_int16_t, u_int16_t)); 16741502Swpaul 16841502Swpaulstatic void vr_autoneg_xmit __P((struct vr_softc *)); 16941502Swpaulstatic void vr_autoneg_mii __P((struct vr_softc *, int, int)); 17041502Swpaulstatic void vr_setmode_mii __P((struct vr_softc *, int)); 17141502Swpaulstatic void vr_getmode_mii __P((struct vr_softc *)); 17241502Swpaulstatic void vr_setcfg __P((struct vr_softc *, u_int16_t)); 17341502Swpaulstatic u_int8_t vr_calchash __P((u_int8_t *)); 17441502Swpaulstatic void vr_setmulti __P((struct vr_softc *)); 17541502Swpaulstatic void vr_reset __P((struct vr_softc *)); 17641502Swpaulstatic int vr_list_rx_init __P((struct vr_softc *)); 17741502Swpaulstatic int vr_list_tx_init __P((struct vr_softc *)); 17841502Swpaul 17949610Swpaul#ifdef VR_USEIOSPACE 18049610Swpaul#define VR_RES SYS_RES_IOPORT 18149610Swpaul#define VR_RID VR_PCI_LOIO 18249610Swpaul#else 18349610Swpaul#define VR_RES SYS_RES_MEMORY 18449610Swpaul#define VR_RID VR_PCI_LOMEM 18549610Swpaul#endif 18649610Swpaul 18749610Swpaulstatic device_method_t vr_methods[] = { 18849610Swpaul /* Device interface */ 18949610Swpaul DEVMETHOD(device_probe, vr_probe), 19049610Swpaul DEVMETHOD(device_attach, vr_attach), 19149610Swpaul DEVMETHOD(device_detach, vr_detach), 19249610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 19349610Swpaul { 0, 0 } 19449610Swpaul}; 19549610Swpaul 19649610Swpaulstatic driver_t vr_driver = { 19749610Swpaul "vr", 19849610Swpaul vr_methods, 19949610Swpaul sizeof(struct vr_softc) 20049610Swpaul}; 20149610Swpaul 20249610Swpaulstatic devclass_t vr_devclass; 20349610Swpaul 20449610SwpaulDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0); 20549610Swpaul 20641502Swpaul#define VR_SETBIT(sc, reg, x) \ 20741502Swpaul CSR_WRITE_1(sc, reg, \ 20841502Swpaul CSR_READ_1(sc, reg) | x) 20941502Swpaul 21041502Swpaul#define VR_CLRBIT(sc, reg, x) \ 21141502Swpaul CSR_WRITE_1(sc, reg, \ 21241502Swpaul CSR_READ_1(sc, reg) & ~x) 21341502Swpaul 21441502Swpaul#define VR_SETBIT16(sc, reg, x) \ 21541502Swpaul CSR_WRITE_2(sc, reg, \ 21641502Swpaul CSR_READ_2(sc, reg) | x) 21741502Swpaul 21841502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 21941502Swpaul CSR_WRITE_2(sc, reg, \ 22041502Swpaul CSR_READ_2(sc, reg) & ~x) 22141502Swpaul 22241502Swpaul#define VR_SETBIT32(sc, reg, x) \ 22341502Swpaul CSR_WRITE_4(sc, reg, \ 22441502Swpaul CSR_READ_4(sc, reg) | x) 22541502Swpaul 22641502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 22741502Swpaul CSR_WRITE_4(sc, reg, \ 22841502Swpaul CSR_READ_4(sc, reg) & ~x) 22941502Swpaul 23041502Swpaul#define SIO_SET(x) \ 23141502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 23241502Swpaul CSR_READ_1(sc, VR_MIICMD) | x) 23341502Swpaul 23441502Swpaul#define SIO_CLR(x) \ 23541502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 23641502Swpaul CSR_READ_1(sc, VR_MIICMD) & ~x) 23741502Swpaul 23841502Swpaul/* 23941502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 24041502Swpaul */ 24141502Swpaulstatic void vr_mii_sync(sc) 24241502Swpaul struct vr_softc *sc; 24341502Swpaul{ 24441502Swpaul register int i; 24541502Swpaul 24641502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 24741502Swpaul 24841502Swpaul for (i = 0; i < 32; i++) { 24941502Swpaul SIO_SET(VR_MIICMD_CLK); 25041502Swpaul DELAY(1); 25141502Swpaul SIO_CLR(VR_MIICMD_CLK); 25241502Swpaul DELAY(1); 25341502Swpaul } 25441502Swpaul 25541502Swpaul return; 25641502Swpaul} 25741502Swpaul 25841502Swpaul/* 25941502Swpaul * Clock a series of bits through the MII. 26041502Swpaul */ 26141502Swpaulstatic void vr_mii_send(sc, bits, cnt) 26241502Swpaul struct vr_softc *sc; 26341502Swpaul u_int32_t bits; 26441502Swpaul int cnt; 26541502Swpaul{ 26641502Swpaul int i; 26741502Swpaul 26841502Swpaul SIO_CLR(VR_MIICMD_CLK); 26941502Swpaul 27041502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 27141502Swpaul if (bits & i) { 27241502Swpaul SIO_SET(VR_MIICMD_DATAIN); 27341502Swpaul } else { 27441502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 27541502Swpaul } 27641502Swpaul DELAY(1); 27741502Swpaul SIO_CLR(VR_MIICMD_CLK); 27841502Swpaul DELAY(1); 27941502Swpaul SIO_SET(VR_MIICMD_CLK); 28041502Swpaul } 28141502Swpaul} 28241502Swpaul 28341502Swpaul/* 28441502Swpaul * Read an PHY register through the MII. 28541502Swpaul */ 28641502Swpaulstatic int vr_mii_readreg(sc, frame) 28741502Swpaul struct vr_softc *sc; 28841502Swpaul struct vr_mii_frame *frame; 28941502Swpaul 29041502Swpaul{ 29141502Swpaul int i, ack, s; 29241502Swpaul 29341502Swpaul s = splimp(); 29441502Swpaul 29541502Swpaul /* 29641502Swpaul * Set up frame for RX. 29741502Swpaul */ 29841502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 29941502Swpaul frame->mii_opcode = VR_MII_READOP; 30041502Swpaul frame->mii_turnaround = 0; 30141502Swpaul frame->mii_data = 0; 30241502Swpaul 30341502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 30441502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 30541502Swpaul 30641502Swpaul /* 30741502Swpaul * Turn on data xmit. 30841502Swpaul */ 30941502Swpaul SIO_SET(VR_MIICMD_DIR); 31041502Swpaul 31141502Swpaul vr_mii_sync(sc); 31241502Swpaul 31341502Swpaul /* 31441502Swpaul * Send command/address info. 31541502Swpaul */ 31641502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 31741502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 31841502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 31941502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 32041502Swpaul 32141502Swpaul /* Idle bit */ 32241502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 32341502Swpaul DELAY(1); 32441502Swpaul SIO_SET(VR_MIICMD_CLK); 32541502Swpaul DELAY(1); 32641502Swpaul 32741502Swpaul /* Turn off xmit. */ 32841502Swpaul SIO_CLR(VR_MIICMD_DIR); 32941502Swpaul 33041502Swpaul /* Check for ack */ 33141502Swpaul SIO_CLR(VR_MIICMD_CLK); 33241502Swpaul DELAY(1); 33341502Swpaul SIO_SET(VR_MIICMD_CLK); 33441502Swpaul DELAY(1); 33541502Swpaul ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 33641502Swpaul 33741502Swpaul /* 33841502Swpaul * Now try reading data bits. If the ack failed, we still 33941502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 34041502Swpaul */ 34141502Swpaul if (ack) { 34241502Swpaul for(i = 0; i < 16; i++) { 34341502Swpaul SIO_CLR(VR_MIICMD_CLK); 34441502Swpaul DELAY(1); 34541502Swpaul SIO_SET(VR_MIICMD_CLK); 34641502Swpaul DELAY(1); 34741502Swpaul } 34841502Swpaul goto fail; 34941502Swpaul } 35041502Swpaul 35141502Swpaul for (i = 0x8000; i; i >>= 1) { 35241502Swpaul SIO_CLR(VR_MIICMD_CLK); 35341502Swpaul DELAY(1); 35441502Swpaul if (!ack) { 35541502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 35641502Swpaul frame->mii_data |= i; 35741502Swpaul DELAY(1); 35841502Swpaul } 35941502Swpaul SIO_SET(VR_MIICMD_CLK); 36041502Swpaul DELAY(1); 36141502Swpaul } 36241502Swpaul 36341502Swpaulfail: 36441502Swpaul 36541502Swpaul SIO_CLR(VR_MIICMD_CLK); 36641502Swpaul DELAY(1); 36741502Swpaul SIO_SET(VR_MIICMD_CLK); 36841502Swpaul DELAY(1); 36941502Swpaul 37041502Swpaul splx(s); 37141502Swpaul 37241502Swpaul if (ack) 37341502Swpaul return(1); 37441502Swpaul return(0); 37541502Swpaul} 37641502Swpaul 37741502Swpaul/* 37841502Swpaul * Write to a PHY register through the MII. 37941502Swpaul */ 38041502Swpaulstatic int vr_mii_writereg(sc, frame) 38141502Swpaul struct vr_softc *sc; 38241502Swpaul struct vr_mii_frame *frame; 38341502Swpaul 38441502Swpaul{ 38541502Swpaul int s; 38641502Swpaul 38741502Swpaul s = splimp(); 38841502Swpaul 38941502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 39041502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 39141502Swpaul 39241502Swpaul /* 39341502Swpaul * Set up frame for TX. 39441502Swpaul */ 39541502Swpaul 39641502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 39741502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 39841502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 39941502Swpaul 40041502Swpaul /* 40141502Swpaul * Turn on data output. 40241502Swpaul */ 40341502Swpaul SIO_SET(VR_MIICMD_DIR); 40441502Swpaul 40541502Swpaul vr_mii_sync(sc); 40641502Swpaul 40741502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 40841502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 40941502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 41041502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 41141502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 41241502Swpaul vr_mii_send(sc, frame->mii_data, 16); 41341502Swpaul 41441502Swpaul /* Idle bit. */ 41541502Swpaul SIO_SET(VR_MIICMD_CLK); 41641502Swpaul DELAY(1); 41741502Swpaul SIO_CLR(VR_MIICMD_CLK); 41841502Swpaul DELAY(1); 41941502Swpaul 42041502Swpaul /* 42141502Swpaul * Turn off xmit. 42241502Swpaul */ 42341502Swpaul SIO_CLR(VR_MIICMD_DIR); 42441502Swpaul 42541502Swpaul splx(s); 42641502Swpaul 42741502Swpaul return(0); 42841502Swpaul} 42941502Swpaul 43041502Swpaulstatic u_int16_t vr_phy_readreg(sc, reg) 43141502Swpaul struct vr_softc *sc; 43241502Swpaul int reg; 43341502Swpaul{ 43441502Swpaul struct vr_mii_frame frame; 43541502Swpaul 43641502Swpaul bzero((char *)&frame, sizeof(frame)); 43741502Swpaul 43841502Swpaul frame.mii_phyaddr = sc->vr_phy_addr; 43941502Swpaul frame.mii_regaddr = reg; 44041502Swpaul vr_mii_readreg(sc, &frame); 44141502Swpaul 44241502Swpaul return(frame.mii_data); 44341502Swpaul} 44441502Swpaul 44541502Swpaulstatic void vr_phy_writereg(sc, reg, data) 44641502Swpaul struct vr_softc *sc; 44741502Swpaul u_int16_t reg; 44841502Swpaul u_int16_t data; 44941502Swpaul{ 45041502Swpaul struct vr_mii_frame frame; 45141502Swpaul 45241502Swpaul bzero((char *)&frame, sizeof(frame)); 45341502Swpaul 45441502Swpaul frame.mii_phyaddr = sc->vr_phy_addr; 45541502Swpaul frame.mii_regaddr = reg; 45641502Swpaul frame.mii_data = data; 45741502Swpaul 45841502Swpaul vr_mii_writereg(sc, &frame); 45941502Swpaul 46041502Swpaul return; 46141502Swpaul} 46241502Swpaul 46341502Swpaul/* 46441502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits. 46541502Swpaul */ 46641502Swpaulstatic u_int8_t vr_calchash(addr) 46741502Swpaul u_int8_t *addr; 46841502Swpaul{ 46941502Swpaul u_int32_t crc, carry; 47041502Swpaul int i, j; 47141502Swpaul u_int8_t c; 47241502Swpaul 47341502Swpaul /* Compute CRC for the address value. */ 47441502Swpaul crc = 0xFFFFFFFF; /* initial value */ 47541502Swpaul 47641502Swpaul for (i = 0; i < 6; i++) { 47741502Swpaul c = *(addr + i); 47841502Swpaul for (j = 0; j < 8; j++) { 47941502Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 48041502Swpaul crc <<= 1; 48141502Swpaul c >>= 1; 48241502Swpaul if (carry) 48341502Swpaul crc = (crc ^ 0x04c11db6) | carry; 48441502Swpaul } 48541502Swpaul } 48641502Swpaul 48741502Swpaul /* return the filter bit position */ 48841502Swpaul return((crc >> 26) & 0x0000003F); 48941502Swpaul} 49041502Swpaul 49141502Swpaul/* 49241502Swpaul * Program the 64-bit multicast hash filter. 49341502Swpaul */ 49441502Swpaulstatic void vr_setmulti(sc) 49541502Swpaul struct vr_softc *sc; 49641502Swpaul{ 49741502Swpaul struct ifnet *ifp; 49841502Swpaul int h = 0; 49941502Swpaul u_int32_t hashes[2] = { 0, 0 }; 50041502Swpaul struct ifmultiaddr *ifma; 50141502Swpaul u_int8_t rxfilt; 50241502Swpaul int mcnt = 0; 50341502Swpaul 50441502Swpaul ifp = &sc->arpcom.ac_if; 50541502Swpaul 50641502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 50741502Swpaul 50841502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 50941502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 51041502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 51141502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 51241502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 51341502Swpaul return; 51441502Swpaul } 51541502Swpaul 51641502Swpaul /* first, zot all the existing hash bits */ 51741502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 51841502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 51941502Swpaul 52041502Swpaul /* now program new ones */ 52141502Swpaul for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; 52241502Swpaul ifma = ifma->ifma_link.le_next) { 52341502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 52441502Swpaul continue; 52541502Swpaul h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 52641502Swpaul if (h < 32) 52741502Swpaul hashes[0] |= (1 << h); 52841502Swpaul else 52941502Swpaul hashes[1] |= (1 << (h - 32)); 53041502Swpaul mcnt++; 53141502Swpaul } 53241502Swpaul 53341502Swpaul if (mcnt) 53441502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 53541502Swpaul else 53641502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 53741502Swpaul 53841502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 53941502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 54041502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 54141502Swpaul 54241502Swpaul return; 54341502Swpaul} 54441502Swpaul 54541502Swpaul/* 54641502Swpaul * Initiate an autonegotiation session. 54741502Swpaul */ 54841502Swpaulstatic void vr_autoneg_xmit(sc) 54941502Swpaul struct vr_softc *sc; 55041502Swpaul{ 55141502Swpaul u_int16_t phy_sts; 55241502Swpaul 55341502Swpaul vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 55441502Swpaul DELAY(500); 55541502Swpaul while(vr_phy_readreg(sc, PHY_BMCR) 55641502Swpaul & PHY_BMCR_RESET); 55741502Swpaul 55841502Swpaul phy_sts = vr_phy_readreg(sc, PHY_BMCR); 55941502Swpaul phy_sts |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; 56041502Swpaul vr_phy_writereg(sc, PHY_BMCR, phy_sts); 56141502Swpaul 56241502Swpaul return; 56341502Swpaul} 56441502Swpaul 56541502Swpaul/* 56641502Swpaul * Invoke autonegotiation on a PHY. 56741502Swpaul */ 56841502Swpaulstatic void vr_autoneg_mii(sc, flag, verbose) 56941502Swpaul struct vr_softc *sc; 57041502Swpaul int flag; 57141502Swpaul int verbose; 57241502Swpaul{ 57341502Swpaul u_int16_t phy_sts = 0, media, advert, ability; 57441502Swpaul struct ifnet *ifp; 57541502Swpaul struct ifmedia *ifm; 57641502Swpaul 57741502Swpaul ifm = &sc->ifmedia; 57841502Swpaul ifp = &sc->arpcom.ac_if; 57941502Swpaul 58041502Swpaul ifm->ifm_media = IFM_ETHER | IFM_AUTO; 58141502Swpaul 58241502Swpaul /* 58341502Swpaul * The 100baseT4 PHY on the 3c905-T4 has the 'autoneg supported' 58441502Swpaul * bit cleared in the status register, but has the 'autoneg enabled' 58541502Swpaul * bit set in the control register. This is a contradiction, and 58641502Swpaul * I'm not sure how to handle it. If you want to force an attempt 58741502Swpaul * to autoneg for 100baseT4 PHYs, #define FORCE_AUTONEG_TFOUR 58841502Swpaul * and see what happens. 58941502Swpaul */ 59041502Swpaul#ifndef FORCE_AUTONEG_TFOUR 59141502Swpaul /* 59241502Swpaul * First, see if autoneg is supported. If not, there's 59341502Swpaul * no point in continuing. 59441502Swpaul */ 59541502Swpaul phy_sts = vr_phy_readreg(sc, PHY_BMSR); 59641502Swpaul if (!(phy_sts & PHY_BMSR_CANAUTONEG)) { 59741502Swpaul if (verbose) 59841502Swpaul printf("vr%d: autonegotiation not supported\n", 59941502Swpaul sc->vr_unit); 60041502Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 60141502Swpaul return; 60241502Swpaul } 60341502Swpaul#endif 60441502Swpaul 60541502Swpaul switch (flag) { 60641502Swpaul case VR_FLAG_FORCEDELAY: 60741502Swpaul /* 60841502Swpaul * XXX Never use this option anywhere but in the probe 60941502Swpaul * routine: making the kernel stop dead in its tracks 61041502Swpaul * for three whole seconds after we've gone multi-user 61141502Swpaul * is really bad manners. 61241502Swpaul */ 61341502Swpaul vr_autoneg_xmit(sc); 61441502Swpaul DELAY(5000000); 61541502Swpaul break; 61641502Swpaul case VR_FLAG_SCHEDDELAY: 61741502Swpaul /* 61841502Swpaul * Wait for the transmitter to go idle before starting 61941502Swpaul * an autoneg session, otherwise vr_start() may clobber 62041502Swpaul * our timeout, and we don't want to allow transmission 62141502Swpaul * during an autoneg session since that can screw it up. 62241502Swpaul */ 62341502Swpaul if (sc->vr_cdata.vr_tx_head != NULL) { 62441502Swpaul sc->vr_want_auto = 1; 62541502Swpaul return; 62641502Swpaul } 62741502Swpaul vr_autoneg_xmit(sc); 62841502Swpaul ifp->if_timer = 5; 62941502Swpaul sc->vr_autoneg = 1; 63041502Swpaul sc->vr_want_auto = 0; 63141502Swpaul return; 63241502Swpaul break; 63341502Swpaul case VR_FLAG_DELAYTIMEO: 63441502Swpaul ifp->if_timer = 0; 63541502Swpaul sc->vr_autoneg = 0; 63641502Swpaul break; 63741502Swpaul default: 63841502Swpaul printf("vr%d: invalid autoneg flag: %d\n", sc->vr_unit, flag); 63941502Swpaul return; 64041502Swpaul } 64141502Swpaul 64241502Swpaul if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) { 64341502Swpaul if (verbose) 64441502Swpaul printf("vr%d: autoneg complete, ", sc->vr_unit); 64541502Swpaul phy_sts = vr_phy_readreg(sc, PHY_BMSR); 64641502Swpaul } else { 64741502Swpaul if (verbose) 64841502Swpaul printf("vr%d: autoneg not complete, ", sc->vr_unit); 64941502Swpaul } 65041502Swpaul 65141502Swpaul media = vr_phy_readreg(sc, PHY_BMCR); 65241502Swpaul 65341502Swpaul /* Link is good. Report modes and set duplex mode. */ 65441502Swpaul if (vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) { 65541502Swpaul if (verbose) 65641502Swpaul printf("link status good "); 65741502Swpaul advert = vr_phy_readreg(sc, PHY_ANAR); 65841502Swpaul ability = vr_phy_readreg(sc, PHY_LPAR); 65941502Swpaul 66041502Swpaul if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) { 66141502Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_T4; 66241502Swpaul media |= PHY_BMCR_SPEEDSEL; 66341502Swpaul media &= ~PHY_BMCR_DUPLEX; 66441502Swpaul printf("(100baseT4)\n"); 66541502Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 66641502Swpaul ability & PHY_ANAR_100BTXFULL) { 66741502Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 66841502Swpaul media |= PHY_BMCR_SPEEDSEL; 66941502Swpaul media |= PHY_BMCR_DUPLEX; 67041502Swpaul printf("(full-duplex, 100Mbps)\n"); 67141502Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 67241502Swpaul ability & PHY_ANAR_100BTXHALF) { 67341502Swpaul ifm->ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 67441502Swpaul media |= PHY_BMCR_SPEEDSEL; 67541502Swpaul media &= ~PHY_BMCR_DUPLEX; 67641502Swpaul printf("(half-duplex, 100Mbps)\n"); 67741502Swpaul } else if (advert & PHY_ANAR_10BTFULL && 67841502Swpaul ability & PHY_ANAR_10BTFULL) { 67941502Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 68041502Swpaul media &= ~PHY_BMCR_SPEEDSEL; 68141502Swpaul media |= PHY_BMCR_DUPLEX; 68241502Swpaul printf("(full-duplex, 10Mbps)\n"); 68341502Swpaul } else { 68441502Swpaul ifm->ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 68541502Swpaul media &= ~PHY_BMCR_SPEEDSEL; 68641502Swpaul media &= ~PHY_BMCR_DUPLEX; 68741502Swpaul printf("(half-duplex, 10Mbps)\n"); 68841502Swpaul } 68941502Swpaul 69041502Swpaul media &= ~PHY_BMCR_AUTONEGENBL; 69141502Swpaul 69241502Swpaul /* Set ASIC's duplex mode to match the PHY. */ 69341502Swpaul vr_setcfg(sc, media); 69441502Swpaul vr_phy_writereg(sc, PHY_BMCR, media); 69541502Swpaul } else { 69641502Swpaul if (verbose) 69741502Swpaul printf("no carrier\n"); 69841502Swpaul } 69941502Swpaul 70041502Swpaul vr_init(sc); 70141502Swpaul 70241502Swpaul if (sc->vr_tx_pend) { 70341502Swpaul sc->vr_autoneg = 0; 70441502Swpaul sc->vr_tx_pend = 0; 70541502Swpaul vr_start(ifp); 70641502Swpaul } 70741502Swpaul 70841502Swpaul return; 70941502Swpaul} 71041502Swpaul 71141502Swpaulstatic void vr_getmode_mii(sc) 71241502Swpaul struct vr_softc *sc; 71341502Swpaul{ 71441502Swpaul u_int16_t bmsr; 71541502Swpaul struct ifnet *ifp; 71641502Swpaul 71741502Swpaul ifp = &sc->arpcom.ac_if; 71841502Swpaul 71941502Swpaul bmsr = vr_phy_readreg(sc, PHY_BMSR); 72041502Swpaul if (bootverbose) 72141502Swpaul printf("vr%d: PHY status word: %x\n", sc->vr_unit, bmsr); 72241502Swpaul 72341502Swpaul /* fallback */ 72441502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_HDX; 72541502Swpaul 72641502Swpaul if (bmsr & PHY_BMSR_10BTHALF) { 72741502Swpaul if (bootverbose) 72841502Swpaul printf("vr%d: 10Mbps half-duplex mode supported\n", 72941502Swpaul sc->vr_unit); 73041502Swpaul ifmedia_add(&sc->ifmedia, 73141502Swpaul IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 73241502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 73341502Swpaul } 73441502Swpaul 73541502Swpaul if (bmsr & PHY_BMSR_10BTFULL) { 73641502Swpaul if (bootverbose) 73741502Swpaul printf("vr%d: 10Mbps full-duplex mode supported\n", 73841502Swpaul sc->vr_unit); 73941502Swpaul ifmedia_add(&sc->ifmedia, 74041502Swpaul IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 74141502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_10_T|IFM_FDX; 74241502Swpaul } 74341502Swpaul 74441502Swpaul if (bmsr & PHY_BMSR_100BTXHALF) { 74541502Swpaul if (bootverbose) 74641502Swpaul printf("vr%d: 100Mbps half-duplex mode supported\n", 74741502Swpaul sc->vr_unit); 74841502Swpaul ifp->if_baudrate = 100000000; 74941502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 75041502Swpaul ifmedia_add(&sc->ifmedia, 75141502Swpaul IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); 75241502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_HDX; 75341502Swpaul } 75441502Swpaul 75541502Swpaul if (bmsr & PHY_BMSR_100BTXFULL) { 75641502Swpaul if (bootverbose) 75741502Swpaul printf("vr%d: 100Mbps full-duplex mode supported\n", 75841502Swpaul sc->vr_unit); 75941502Swpaul ifp->if_baudrate = 100000000; 76041502Swpaul ifmedia_add(&sc->ifmedia, 76141502Swpaul IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 76241502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_TX|IFM_FDX; 76341502Swpaul } 76441502Swpaul 76541502Swpaul /* Some also support 100BaseT4. */ 76641502Swpaul if (bmsr & PHY_BMSR_100BT4) { 76741502Swpaul if (bootverbose) 76841502Swpaul printf("vr%d: 100baseT4 mode supported\n", sc->vr_unit); 76941502Swpaul ifp->if_baudrate = 100000000; 77041502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_100_T4, 0, NULL); 77141502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_100_T4; 77241502Swpaul#ifdef FORCE_AUTONEG_TFOUR 77341502Swpaul if (bootverbose) 77441502Swpaul printf("vr%d: forcing on autoneg support for BT4\n", 77541502Swpaul sc->vr_unit); 77641502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0 NULL): 77741502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 77841502Swpaul#endif 77941502Swpaul } 78041502Swpaul 78141502Swpaul if (bmsr & PHY_BMSR_CANAUTONEG) { 78241502Swpaul if (bootverbose) 78341502Swpaul printf("vr%d: autoneg supported\n", sc->vr_unit); 78441502Swpaul ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 78541502Swpaul sc->ifmedia.ifm_media = IFM_ETHER|IFM_AUTO; 78641502Swpaul } 78741502Swpaul 78841502Swpaul return; 78941502Swpaul} 79041502Swpaul 79141502Swpaul/* 79241502Swpaul * Set speed and duplex mode. 79341502Swpaul */ 79441502Swpaulstatic void vr_setmode_mii(sc, media) 79541502Swpaul struct vr_softc *sc; 79641502Swpaul int media; 79741502Swpaul{ 79841502Swpaul u_int16_t bmcr; 79941502Swpaul struct ifnet *ifp; 80041502Swpaul 80141502Swpaul ifp = &sc->arpcom.ac_if; 80241502Swpaul 80341502Swpaul /* 80441502Swpaul * If an autoneg session is in progress, stop it. 80541502Swpaul */ 80641502Swpaul if (sc->vr_autoneg) { 80741502Swpaul printf("vr%d: canceling autoneg session\n", sc->vr_unit); 80841502Swpaul ifp->if_timer = sc->vr_autoneg = sc->vr_want_auto = 0; 80941502Swpaul bmcr = vr_phy_readreg(sc, PHY_BMCR); 81041502Swpaul bmcr &= ~PHY_BMCR_AUTONEGENBL; 81141502Swpaul vr_phy_writereg(sc, PHY_BMCR, bmcr); 81241502Swpaul } 81341502Swpaul 81441502Swpaul printf("vr%d: selecting MII, ", sc->vr_unit); 81541502Swpaul 81641502Swpaul bmcr = vr_phy_readreg(sc, PHY_BMCR); 81741502Swpaul 81841502Swpaul bmcr &= ~(PHY_BMCR_AUTONEGENBL|PHY_BMCR_SPEEDSEL| 81941502Swpaul PHY_BMCR_DUPLEX|PHY_BMCR_LOOPBK); 82041502Swpaul 82141502Swpaul if (IFM_SUBTYPE(media) == IFM_100_T4) { 82241502Swpaul printf("100Mbps/T4, half-duplex\n"); 82341502Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 82441502Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 82541502Swpaul } 82641502Swpaul 82741502Swpaul if (IFM_SUBTYPE(media) == IFM_100_TX) { 82841502Swpaul printf("100Mbps, "); 82941502Swpaul bmcr |= PHY_BMCR_SPEEDSEL; 83041502Swpaul } 83141502Swpaul 83241502Swpaul if (IFM_SUBTYPE(media) == IFM_10_T) { 83341502Swpaul printf("10Mbps, "); 83441502Swpaul bmcr &= ~PHY_BMCR_SPEEDSEL; 83541502Swpaul } 83641502Swpaul 83741502Swpaul if ((media & IFM_GMASK) == IFM_FDX) { 83841502Swpaul printf("full duplex\n"); 83941502Swpaul bmcr |= PHY_BMCR_DUPLEX; 84041502Swpaul } else { 84141502Swpaul printf("half duplex\n"); 84241502Swpaul bmcr &= ~PHY_BMCR_DUPLEX; 84341502Swpaul } 84441502Swpaul 84541502Swpaul vr_setcfg(sc, bmcr); 84641502Swpaul vr_phy_writereg(sc, PHY_BMCR, bmcr); 84741502Swpaul 84841502Swpaul return; 84941502Swpaul} 85041502Swpaul 85141502Swpaul/* 85241502Swpaul * In order to fiddle with the 85341502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 85441502Swpaul * first have to put the transmit and/or receive logic in the idle state. 85541502Swpaul */ 85641502Swpaulstatic void vr_setcfg(sc, bmcr) 85741502Swpaul struct vr_softc *sc; 85841502Swpaul u_int16_t bmcr; 85941502Swpaul{ 86041502Swpaul int restart = 0; 86141502Swpaul 86241502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 86341502Swpaul restart = 1; 86441502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 86541502Swpaul } 86641502Swpaul 86741502Swpaul if (bmcr & PHY_BMCR_DUPLEX) 86841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 86941502Swpaul else 87041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 87141502Swpaul 87241502Swpaul if (restart) 87341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 87441502Swpaul 87541502Swpaul return; 87641502Swpaul} 87741502Swpaul 87841502Swpaulstatic void vr_reset(sc) 87941502Swpaul struct vr_softc *sc; 88041502Swpaul{ 88141502Swpaul register int i; 88241502Swpaul 88341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 88441502Swpaul 88541502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 88641502Swpaul DELAY(10); 88741502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 88841502Swpaul break; 88941502Swpaul } 89041502Swpaul if (i == VR_TIMEOUT) 89141502Swpaul printf("vr%d: reset never completed!\n", sc->vr_unit); 89241502Swpaul 89341502Swpaul /* Wait a little while for the chip to get its brains in order. */ 89441502Swpaul DELAY(1000); 89541502Swpaul 89641502Swpaul return; 89741502Swpaul} 89841502Swpaul 89941502Swpaul/* 90041502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 90141502Swpaul * IDs against our list and return a device name if we find a match. 90241502Swpaul */ 90349610Swpaulstatic int vr_probe(dev) 90449610Swpaul device_t dev; 90541502Swpaul{ 90641502Swpaul struct vr_type *t; 90741502Swpaul 90841502Swpaul t = vr_devs; 90941502Swpaul 91041502Swpaul while(t->vr_name != NULL) { 91149610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 91249610Swpaul (pci_get_device(dev) == t->vr_did)) { 91349610Swpaul device_set_desc(dev, t->vr_name); 91449610Swpaul return(0); 91541502Swpaul } 91641502Swpaul t++; 91741502Swpaul } 91841502Swpaul 91949610Swpaul return(ENXIO); 92041502Swpaul} 92141502Swpaul 92241502Swpaul/* 92341502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 92441502Swpaul * setup and ethernet/BPF attach. 92541502Swpaul */ 92649610Swpaulstatic int vr_attach(dev) 92749610Swpaul device_t dev; 92841502Swpaul{ 92941502Swpaul int s, i; 93041502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 93141502Swpaul u_int32_t command; 93241502Swpaul struct vr_softc *sc; 93341502Swpaul struct ifnet *ifp; 93441502Swpaul int media = IFM_ETHER|IFM_100_TX|IFM_FDX; 93541502Swpaul unsigned int round; 93641502Swpaul caddr_t roundptr; 93741502Swpaul struct vr_type *p; 93841502Swpaul u_int16_t phy_vid, phy_did, phy_sts; 93949610Swpaul int unit, error = 0, rid; 94041502Swpaul 94141502Swpaul s = splimp(); 94241502Swpaul 94349610Swpaul sc = device_get_softc(dev); 94449610Swpaul unit = device_get_unit(dev); 94549610Swpaul bzero(sc, sizeof(struct vr_softc *)); 94641502Swpaul 94741502Swpaul /* 94841502Swpaul * Handle power management nonsense. 94941502Swpaul */ 95041502Swpaul 95149610Swpaul command = pci_read_config(dev, VR_PCI_CAPID, 4) & 0x000000FF; 95241502Swpaul if (command == 0x01) { 95341502Swpaul 95449610Swpaul command = pci_read_config(dev, VR_PCI_PWRMGMTCTRL, 4); 95541502Swpaul if (command & VR_PSTATE_MASK) { 95641502Swpaul u_int32_t iobase, membase, irq; 95741502Swpaul 95841502Swpaul /* Save important PCI config data. */ 95949610Swpaul iobase = pci_read_config(dev, VR_PCI_LOIO, 4); 96049610Swpaul membase = pci_read_config(dev, VR_PCI_LOMEM, 4); 96149610Swpaul irq = pci_read_config(dev, VR_PCI_INTLINE, 4); 96241502Swpaul 96341502Swpaul /* Reset the power state. */ 96441502Swpaul printf("vr%d: chip is in D%d power mode " 96541502Swpaul "-- setting to D0\n", unit, command & VR_PSTATE_MASK); 96641502Swpaul command &= 0xFFFFFFFC; 96749610Swpaul pci_write_config(dev, VR_PCI_PWRMGMTCTRL, command, 4); 96841502Swpaul 96941502Swpaul /* Restore PCI config data. */ 97049610Swpaul pci_write_config(dev, VR_PCI_LOIO, iobase, 4); 97149610Swpaul pci_write_config(dev, VR_PCI_LOMEM, membase, 4); 97249610Swpaul pci_write_config(dev, VR_PCI_INTLINE, irq, 4); 97341502Swpaul } 97441502Swpaul } 97541502Swpaul 97641502Swpaul /* 97741502Swpaul * Map control/status registers. 97841502Swpaul */ 97949610Swpaul command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); 98041502Swpaul command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 98149610Swpaul pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4); 98249610Swpaul command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4); 98341502Swpaul 98441502Swpaul#ifdef VR_USEIOSPACE 98541502Swpaul if (!(command & PCIM_CMD_PORTEN)) { 98641502Swpaul printf("vr%d: failed to enable I/O ports!\n", unit); 98741502Swpaul free(sc, M_DEVBUF); 98841502Swpaul goto fail; 98941502Swpaul } 99041502Swpaul#else 99141502Swpaul if (!(command & PCIM_CMD_MEMEN)) { 99241502Swpaul printf("vr%d: failed to enable memory mapping!\n", unit); 99341502Swpaul goto fail; 99441502Swpaul } 99549610Swpaul#endif 99641502Swpaul 99749610Swpaul rid = VR_RID; 99849610Swpaul sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid, 99949610Swpaul 0, ~0, 1, RF_ACTIVE); 100049610Swpaul 100149610Swpaul if (sc->vr_res == NULL) { 100249610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 100349610Swpaul error = ENXIO; 100441502Swpaul goto fail; 100541502Swpaul } 100641502Swpaul 100749610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 100849610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 100941502Swpaul 101041502Swpaul /* Allocate interrupt */ 101149610Swpaul rid = 0; 101249610Swpaul sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 101349610Swpaul RF_SHAREABLE | RF_ACTIVE); 101449610Swpaul 101549610Swpaul if (sc->vr_irq == NULL) { 101641502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 101749610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 101849610Swpaul error = ENXIO; 101941502Swpaul goto fail; 102041502Swpaul } 102141502Swpaul 102249610Swpaul error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET, 102349610Swpaul vr_intr, sc, &sc->vr_intrhand); 102449610Swpaul 102549610Swpaul if (error) { 102649610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 102749610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 102849610Swpaul printf("vr%d: couldn't set up irq\n", unit); 102949610Swpaul goto fail; 103049610Swpaul } 103149610Swpaul 103241502Swpaul /* Reset the adapter. */ 103341502Swpaul vr_reset(sc); 103441502Swpaul 103541502Swpaul /* 103641502Swpaul * Get station address. The way the Rhine chips work, 103741502Swpaul * you're not allowed to directly access the EEPROM once 103841502Swpaul * they've been programmed a special way. Consequently, 103941502Swpaul * we need to read the node address from the PAR0 and PAR1 104041502Swpaul * registers. 104141502Swpaul */ 104241502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 104341502Swpaul DELAY(200); 104441502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 104541502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 104641502Swpaul 104741502Swpaul /* 104841502Swpaul * A Rhine chip was detected. Inform the world. 104941502Swpaul */ 105041502Swpaul printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); 105141502Swpaul 105241502Swpaul sc->vr_unit = unit; 105341502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 105441502Swpaul 105541502Swpaul sc->vr_ldata_ptr = malloc(sizeof(struct vr_list_data) + 8, 105641502Swpaul M_DEVBUF, M_NOWAIT); 105741502Swpaul if (sc->vr_ldata_ptr == NULL) { 105841502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 105949610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 106049610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 106149610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 106249610Swpaul error = ENXIO; 106349610Swpaul goto fail; 106441502Swpaul } 106541502Swpaul 106641502Swpaul sc->vr_ldata = (struct vr_list_data *)sc->vr_ldata_ptr; 106741502Swpaul round = (unsigned int)sc->vr_ldata_ptr & 0xF; 106841502Swpaul roundptr = sc->vr_ldata_ptr; 106941502Swpaul for (i = 0; i < 8; i++) { 107041502Swpaul if (round % 8) { 107141502Swpaul round++; 107241502Swpaul roundptr++; 107341502Swpaul } else 107441502Swpaul break; 107541502Swpaul } 107641502Swpaul sc->vr_ldata = (struct vr_list_data *)roundptr; 107741502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 107841502Swpaul 107941502Swpaul ifp = &sc->arpcom.ac_if; 108041502Swpaul ifp->if_softc = sc; 108141502Swpaul ifp->if_unit = unit; 108241502Swpaul ifp->if_name = "vr"; 108341502Swpaul ifp->if_mtu = ETHERMTU; 108441502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 108541502Swpaul ifp->if_ioctl = vr_ioctl; 108641502Swpaul ifp->if_output = ether_output; 108741502Swpaul ifp->if_start = vr_start; 108841502Swpaul ifp->if_watchdog = vr_watchdog; 108941502Swpaul ifp->if_init = vr_init; 109041502Swpaul ifp->if_baudrate = 10000000; 109143515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 109241502Swpaul 109341502Swpaul if (bootverbose) 109441502Swpaul printf("vr%d: probing for a PHY\n", sc->vr_unit); 109541502Swpaul for (i = VR_PHYADDR_MIN; i < VR_PHYADDR_MAX + 1; i++) { 109641502Swpaul if (bootverbose) 109741502Swpaul printf("vr%d: checking address: %d\n", 109841502Swpaul sc->vr_unit, i); 109941502Swpaul sc->vr_phy_addr = i; 110041502Swpaul vr_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET); 110141502Swpaul DELAY(500); 110241502Swpaul while(vr_phy_readreg(sc, PHY_BMCR) 110341502Swpaul & PHY_BMCR_RESET); 110441502Swpaul if ((phy_sts = vr_phy_readreg(sc, PHY_BMSR))) 110541502Swpaul break; 110641502Swpaul } 110741502Swpaul if (phy_sts) { 110841502Swpaul phy_vid = vr_phy_readreg(sc, PHY_VENID); 110941502Swpaul phy_did = vr_phy_readreg(sc, PHY_DEVID); 111041502Swpaul if (bootverbose) 111141502Swpaul printf("vr%d: found PHY at address %d, ", 111241502Swpaul sc->vr_unit, sc->vr_phy_addr); 111341502Swpaul if (bootverbose) 111441502Swpaul printf("vendor id: %x device id: %x\n", 111541502Swpaul phy_vid, phy_did); 111641502Swpaul p = vr_phys; 111741502Swpaul while(p->vr_vid) { 111841502Swpaul if (phy_vid == p->vr_vid && 111941502Swpaul (phy_did | 0x000F) == p->vr_did) { 112041502Swpaul sc->vr_pinfo = p; 112141502Swpaul break; 112241502Swpaul } 112341502Swpaul p++; 112441502Swpaul } 112541502Swpaul if (sc->vr_pinfo == NULL) 112641502Swpaul sc->vr_pinfo = &vr_phys[PHY_UNKNOWN]; 112741502Swpaul if (bootverbose) 112841502Swpaul printf("vr%d: PHY type: %s\n", 112941502Swpaul sc->vr_unit, sc->vr_pinfo->vr_name); 113041502Swpaul } else { 113141502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 113249610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 113349610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 113449610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 113549612Swpaul free(sc->vr_ldata_ptr, M_DEVBUF); 113649610Swpaul error = ENXIO; 113741502Swpaul goto fail; 113841502Swpaul } 113941502Swpaul 114041502Swpaul /* 114141502Swpaul * Do ifmedia setup. 114241502Swpaul */ 114341502Swpaul ifmedia_init(&sc->ifmedia, 0, vr_ifmedia_upd, vr_ifmedia_sts); 114441502Swpaul 114541502Swpaul vr_getmode_mii(sc); 114649610Swpaul if (cold) { 114749610Swpaul vr_autoneg_mii(sc, VR_FLAG_FORCEDELAY, 1); 114849610Swpaul vr_stop(sc); 114949610Swpaul } else { 115049610Swpaul vr_init(sc); 115149610Swpaul vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); 115249610Swpaul } 115349610Swpaul 115441502Swpaul media = sc->ifmedia.ifm_media; 115541502Swpaul 115641502Swpaul ifmedia_set(&sc->ifmedia, media); 115741502Swpaul 115841502Swpaul /* 115941502Swpaul * Call MI attach routines. 116041502Swpaul */ 116141502Swpaul if_attach(ifp); 116241502Swpaul ether_ifattach(ifp); 116341502Swpaul 116448645Sdes#if NBPF > 0 116541502Swpaul bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 116641502Swpaul#endif 116741502Swpaul 116841502Swpaulfail: 116941502Swpaul splx(s); 117049610Swpaul return(error); 117141502Swpaul} 117241502Swpaul 117349610Swpaulstatic int vr_detach(dev) 117449610Swpaul device_t dev; 117549610Swpaul{ 117649610Swpaul struct vr_softc *sc; 117749610Swpaul struct ifnet *ifp; 117849610Swpaul int s; 117949610Swpaul 118049610Swpaul s = splimp(); 118149610Swpaul 118249610Swpaul sc = device_get_softc(dev); 118349610Swpaul ifp = &sc->arpcom.ac_if; 118449610Swpaul 118549610Swpaul vr_stop(sc); 118649610Swpaul if_detach(ifp); 118749610Swpaul 118849610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 118949610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 119049610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 119149610Swpaul 119249610Swpaul free(sc->vr_ldata_ptr, M_DEVBUF); 119349610Swpaul ifmedia_removeall(&sc->ifmedia); 119449610Swpaul 119549610Swpaul splx(s); 119649610Swpaul 119749610Swpaul return(0); 119849610Swpaul} 119949610Swpaul 120041502Swpaul/* 120141502Swpaul * Initialize the transmit descriptors. 120241502Swpaul */ 120341502Swpaulstatic int vr_list_tx_init(sc) 120441502Swpaul struct vr_softc *sc; 120541502Swpaul{ 120641502Swpaul struct vr_chain_data *cd; 120741502Swpaul struct vr_list_data *ld; 120841502Swpaul int i; 120941502Swpaul 121041502Swpaul cd = &sc->vr_cdata; 121141502Swpaul ld = sc->vr_ldata; 121241502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 121341502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 121441502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 121541502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 121641502Swpaul &cd->vr_tx_chain[0]; 121741502Swpaul else 121841502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 121941502Swpaul &cd->vr_tx_chain[i + 1]; 122041502Swpaul } 122141502Swpaul 122241502Swpaul cd->vr_tx_free = &cd->vr_tx_chain[0]; 122341502Swpaul cd->vr_tx_tail = cd->vr_tx_head = NULL; 122441502Swpaul 122541502Swpaul return(0); 122641502Swpaul} 122741502Swpaul 122841502Swpaul 122941502Swpaul/* 123041502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 123141502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 123241502Swpaul * points back to the first. 123341502Swpaul */ 123441502Swpaulstatic int vr_list_rx_init(sc) 123541502Swpaul struct vr_softc *sc; 123641502Swpaul{ 123741502Swpaul struct vr_chain_data *cd; 123841502Swpaul struct vr_list_data *ld; 123941502Swpaul int i; 124041502Swpaul 124141502Swpaul cd = &sc->vr_cdata; 124241502Swpaul ld = sc->vr_ldata; 124341502Swpaul 124441502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 124541502Swpaul cd->vr_rx_chain[i].vr_ptr = 124641502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 124749610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 124841502Swpaul return(ENOBUFS); 124941502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 125041502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 125141502Swpaul &cd->vr_rx_chain[0]; 125241502Swpaul ld->vr_rx_list[i].vr_next = 125341502Swpaul vtophys(&ld->vr_rx_list[0]); 125441502Swpaul } else { 125541502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 125641502Swpaul &cd->vr_rx_chain[i + 1]; 125741502Swpaul ld->vr_rx_list[i].vr_next = 125841502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 125941502Swpaul } 126041502Swpaul } 126141502Swpaul 126241502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 126341502Swpaul 126441502Swpaul return(0); 126541502Swpaul} 126641502Swpaul 126741502Swpaul/* 126841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 126941502Swpaul * Note: the length fields are only 11 bits wide, which means the 127041502Swpaul * largest size we can specify is 2047. This is important because 127141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 127241502Swpaul * overflow the field and make a mess. 127341502Swpaul */ 127449610Swpaulstatic int vr_newbuf(sc, c, m) 127541502Swpaul struct vr_softc *sc; 127641502Swpaul struct vr_chain_onefrag *c; 127749610Swpaul struct mbuf *m; 127841502Swpaul{ 127941502Swpaul struct mbuf *m_new = NULL; 128041502Swpaul 128149610Swpaul if (m == NULL) { 128249610Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 128349610Swpaul if (m_new == NULL) { 128449610Swpaul printf("vr%d: no memory for rx list " 128549610Swpaul "-- packet dropped!\n", sc->vr_unit); 128649610Swpaul return(ENOBUFS); 128749610Swpaul } 128841502Swpaul 128949610Swpaul MCLGET(m_new, M_DONTWAIT); 129049610Swpaul if (!(m_new->m_flags & M_EXT)) { 129149610Swpaul printf("vr%d: no memory for rx list " 129249610Swpaul "-- packet dropped!\n", sc->vr_unit); 129349610Swpaul m_freem(m_new); 129449610Swpaul return(ENOBUFS); 129549610Swpaul } 129649610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 129749610Swpaul } else { 129849610Swpaul m_new = m; 129949610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 130049610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 130141502Swpaul } 130241502Swpaul 130349610Swpaul m_adj(m_new, sizeof(u_int64_t)); 130449610Swpaul 130541502Swpaul c->vr_mbuf = m_new; 130641502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 130741502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 130842491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 130941502Swpaul 131041502Swpaul return(0); 131141502Swpaul} 131241502Swpaul 131341502Swpaul/* 131441502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 131541502Swpaul * the higher level protocols. 131641502Swpaul */ 131741502Swpaulstatic void vr_rxeof(sc) 131841502Swpaul struct vr_softc *sc; 131941502Swpaul{ 132041502Swpaul struct ether_header *eh; 132141502Swpaul struct mbuf *m; 132241502Swpaul struct ifnet *ifp; 132341502Swpaul struct vr_chain_onefrag *cur_rx; 132441502Swpaul int total_len = 0; 132541502Swpaul u_int32_t rxstat; 132641502Swpaul 132741502Swpaul ifp = &sc->arpcom.ac_if; 132841502Swpaul 132941502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 133041502Swpaul VR_RXSTAT_OWN)) { 133149610Swpaul struct mbuf *m0 = NULL; 133249610Swpaul 133341502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 133441502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 133549610Swpaul m = cur_rx->vr_mbuf; 133641502Swpaul 133741502Swpaul /* 133841502Swpaul * If an error occurs, update stats, clear the 133941502Swpaul * status word and leave the mbuf cluster in place: 134041502Swpaul * it should simply get re-used next time this descriptor 134141502Swpaul * comes up in the ring. 134241502Swpaul */ 134341502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 134441502Swpaul ifp->if_ierrors++; 134541502Swpaul printf("vr%d: rx error: ", sc->vr_unit); 134641502Swpaul switch(rxstat & 0x000000FF) { 134741502Swpaul case VR_RXSTAT_CRCERR: 134841502Swpaul printf("crc error\n"); 134941502Swpaul break; 135041502Swpaul case VR_RXSTAT_FRAMEALIGNERR: 135141502Swpaul printf("frame alignment error\n"); 135241502Swpaul break; 135341502Swpaul case VR_RXSTAT_FIFOOFLOW: 135441502Swpaul printf("FIFO overflow\n"); 135541502Swpaul break; 135641502Swpaul case VR_RXSTAT_GIANT: 135741502Swpaul printf("received giant packet\n"); 135841502Swpaul break; 135941502Swpaul case VR_RXSTAT_RUNT: 136041502Swpaul printf("received runt packet\n"); 136141502Swpaul break; 136241502Swpaul case VR_RXSTAT_BUSERR: 136341502Swpaul printf("system bus error\n"); 136441502Swpaul break; 136541502Swpaul case VR_RXSTAT_BUFFERR: 136641502Swpaul printf("rx buffer error\n"); 136741502Swpaul break; 136841502Swpaul default: 136941502Swpaul printf("unknown rx error\n"); 137041502Swpaul break; 137141502Swpaul } 137249610Swpaul vr_newbuf(sc, cur_rx, m); 137341502Swpaul continue; 137441502Swpaul } 137541502Swpaul 137641502Swpaul /* No errors; receive the packet. */ 137741502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 137841502Swpaul 137941502Swpaul /* 138042048Swpaul * XXX The VIA Rhine chip includes the CRC with every 138142048Swpaul * received frame, and there's no way to turn this 138242048Swpaul * behavior off (at least, I can't find anything in 138342048Swpaul * the manual that explains how to do it) so we have 138442048Swpaul * to trim off the CRC manually. 138542048Swpaul */ 138642048Swpaul total_len -= ETHER_CRC_LEN; 138742048Swpaul 138849610Swpaul m0 = m_devget(mtod(m, char *) - ETHER_ALIGN, 138949610Swpaul total_len + ETHER_ALIGN, 0, ifp, NULL); 139049610Swpaul vr_newbuf(sc, cur_rx, m); 139149610Swpaul if (m0 == NULL) { 139241502Swpaul ifp->if_ierrors++; 139341502Swpaul continue; 139441502Swpaul } 139549610Swpaul m_adj(m0, ETHER_ALIGN); 139649610Swpaul m = m0; 139741502Swpaul 139841502Swpaul ifp->if_ipackets++; 139941502Swpaul eh = mtod(m, struct ether_header *); 140049610Swpaul 140148645Sdes#if NBPF > 0 140241502Swpaul /* 140341502Swpaul * Handle BPF listeners. Let the BPF user see the packet, but 140441502Swpaul * don't pass it up to the ether_input() layer unless it's 140541502Swpaul * a broadcast packet, multicast packet, matches our ethernet 140641502Swpaul * address or the interface is in promiscuous mode. 140741502Swpaul */ 140841502Swpaul if (ifp->if_bpf) { 140941502Swpaul bpf_mtap(ifp, m); 141041502Swpaul if (ifp->if_flags & IFF_PROMISC && 141141502Swpaul (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, 141241502Swpaul ETHER_ADDR_LEN) && 141341502Swpaul (eh->ether_dhost[0] & 1) == 0)) { 141441502Swpaul m_freem(m); 141541502Swpaul continue; 141641502Swpaul } 141741502Swpaul } 141841502Swpaul#endif 141941502Swpaul /* Remove header from mbuf and pass it on. */ 142041502Swpaul m_adj(m, sizeof(struct ether_header)); 142141502Swpaul ether_input(ifp, eh, m); 142241502Swpaul } 142341502Swpaul 142441502Swpaul return; 142541502Swpaul} 142641502Swpaul 142741502Swpaulvoid vr_rxeoc(sc) 142841502Swpaul struct vr_softc *sc; 142941502Swpaul{ 143041502Swpaul 143141502Swpaul vr_rxeof(sc); 143241502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 143341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 143441502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 143541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 143641502Swpaul 143741502Swpaul return; 143841502Swpaul} 143941502Swpaul 144041502Swpaul/* 144141502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 144241502Swpaul * the list buffers. 144341502Swpaul */ 144441502Swpaul 144541502Swpaulstatic void vr_txeof(sc) 144641502Swpaul struct vr_softc *sc; 144741502Swpaul{ 144841502Swpaul struct vr_chain *cur_tx; 144941502Swpaul struct ifnet *ifp; 145041502Swpaul register struct mbuf *n; 145141502Swpaul 145241502Swpaul ifp = &sc->arpcom.ac_if; 145341502Swpaul 145441502Swpaul /* Clear the timeout timer. */ 145541502Swpaul ifp->if_timer = 0; 145641502Swpaul 145741502Swpaul /* Sanity check. */ 145841502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 145941502Swpaul return; 146041502Swpaul 146141502Swpaul /* 146241502Swpaul * Go through our tx list and free mbufs for those 146341502Swpaul * frames that have been transmitted. 146441502Swpaul */ 146541502Swpaul while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { 146641502Swpaul u_int32_t txstat; 146741502Swpaul 146841502Swpaul cur_tx = sc->vr_cdata.vr_tx_head; 146941502Swpaul txstat = cur_tx->vr_ptr->vr_status; 147041502Swpaul 147142491Swpaul if (txstat & VR_TXSTAT_OWN) 147241502Swpaul break; 147341502Swpaul 147441502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 147541502Swpaul ifp->if_oerrors++; 147641502Swpaul if (txstat & VR_TXSTAT_DEFER) 147741502Swpaul ifp->if_collisions++; 147841502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 147941502Swpaul ifp->if_collisions++; 148041502Swpaul } 148141502Swpaul 148241502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 148341502Swpaul 148441502Swpaul ifp->if_opackets++; 148541502Swpaul MFREE(cur_tx->vr_mbuf, n); 148641502Swpaul cur_tx->vr_mbuf = NULL; 148741502Swpaul 148841502Swpaul if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { 148941502Swpaul sc->vr_cdata.vr_tx_head = NULL; 149041502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 149141502Swpaul break; 149241502Swpaul } 149341502Swpaul 149441502Swpaul sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; 149541502Swpaul } 149641502Swpaul 149741502Swpaul return; 149841502Swpaul} 149941502Swpaul 150041502Swpaul/* 150141502Swpaul * TX 'end of channel' interrupt handler. 150241502Swpaul */ 150341502Swpaulstatic void vr_txeoc(sc) 150441502Swpaul struct vr_softc *sc; 150541502Swpaul{ 150641502Swpaul struct ifnet *ifp; 150741502Swpaul 150841502Swpaul ifp = &sc->arpcom.ac_if; 150941502Swpaul 151041502Swpaul ifp->if_timer = 0; 151141502Swpaul 151241502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) { 151341502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 151441502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 151541502Swpaul if (sc->vr_want_auto) 151641502Swpaul vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); 151741502Swpaul } 151841502Swpaul 151941502Swpaul return; 152041502Swpaul} 152141502Swpaul 152241502Swpaulstatic void vr_intr(arg) 152341502Swpaul void *arg; 152441502Swpaul{ 152541502Swpaul struct vr_softc *sc; 152641502Swpaul struct ifnet *ifp; 152741502Swpaul u_int16_t status; 152841502Swpaul 152941502Swpaul sc = arg; 153041502Swpaul ifp = &sc->arpcom.ac_if; 153141502Swpaul 153241502Swpaul /* Supress unwanted interrupts. */ 153341502Swpaul if (!(ifp->if_flags & IFF_UP)) { 153441502Swpaul vr_stop(sc); 153541502Swpaul return; 153641502Swpaul } 153741502Swpaul 153841502Swpaul /* Disable interrupts. */ 153941502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 154041502Swpaul 154141502Swpaul for (;;) { 154241502Swpaul 154341502Swpaul status = CSR_READ_2(sc, VR_ISR); 154441502Swpaul if (status) 154541502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 154641502Swpaul 154741502Swpaul if ((status & VR_INTRS) == 0) 154841502Swpaul break; 154941502Swpaul 155041502Swpaul if (status & VR_ISR_RX_OK) 155141502Swpaul vr_rxeof(sc); 155241502Swpaul 155341502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 155441502Swpaul (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) || 155541502Swpaul (status & VR_ISR_RX_DROPPED)) { 155641502Swpaul vr_rxeof(sc); 155741502Swpaul vr_rxeoc(sc); 155841502Swpaul } 155941502Swpaul 156041502Swpaul if (status & VR_ISR_TX_OK) { 156141502Swpaul vr_txeof(sc); 156241502Swpaul vr_txeoc(sc); 156341502Swpaul } 156441502Swpaul 156541502Swpaul if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){ 156641502Swpaul ifp->if_oerrors++; 156741502Swpaul vr_txeof(sc); 156841502Swpaul if (sc->vr_cdata.vr_tx_head != NULL) { 156941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 157041502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 157141502Swpaul } 157241502Swpaul } 157341502Swpaul 157441502Swpaul if (status & VR_ISR_BUSERR) { 157541502Swpaul vr_reset(sc); 157641502Swpaul vr_init(sc); 157741502Swpaul } 157841502Swpaul } 157941502Swpaul 158041502Swpaul /* Re-enable interrupts. */ 158141502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 158241502Swpaul 158341502Swpaul if (ifp->if_snd.ifq_head != NULL) { 158441502Swpaul vr_start(ifp); 158541502Swpaul } 158641502Swpaul 158741502Swpaul return; 158841502Swpaul} 158941502Swpaul 159041502Swpaul/* 159141502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 159241502Swpaul * pointers to the fragment pointers. 159341502Swpaul */ 159441502Swpaulstatic int vr_encap(sc, c, m_head) 159541502Swpaul struct vr_softc *sc; 159641502Swpaul struct vr_chain *c; 159741502Swpaul struct mbuf *m_head; 159841502Swpaul{ 159941502Swpaul int frag = 0; 160041502Swpaul struct vr_desc *f = NULL; 160141502Swpaul int total_len; 160241502Swpaul struct mbuf *m; 160341502Swpaul 160441502Swpaul m = m_head; 160541502Swpaul total_len = 0; 160641502Swpaul 160741502Swpaul /* 160841502Swpaul * The VIA Rhine wants packet buffers to be longword 160941502Swpaul * aligned, but very often our mbufs aren't. Rather than 161041502Swpaul * waste time trying to decide when to copy and when not 161141502Swpaul * to copy, just do it all the time. 161241502Swpaul */ 161341502Swpaul if (m != NULL) { 161441502Swpaul struct mbuf *m_new = NULL; 161541502Swpaul 161641502Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 161741502Swpaul if (m_new == NULL) { 161841502Swpaul printf("vr%d: no memory for tx list", sc->vr_unit); 161941502Swpaul return(1); 162041502Swpaul } 162141502Swpaul if (m_head->m_pkthdr.len > MHLEN) { 162241502Swpaul MCLGET(m_new, M_DONTWAIT); 162341502Swpaul if (!(m_new->m_flags & M_EXT)) { 162441502Swpaul m_freem(m_new); 162541502Swpaul printf("vr%d: no memory for tx list", 162641502Swpaul sc->vr_unit); 162741502Swpaul return(1); 162841502Swpaul } 162941502Swpaul } 163041502Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 163141502Swpaul mtod(m_new, caddr_t)); 163241502Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 163341502Swpaul m_freem(m_head); 163441502Swpaul m_head = m_new; 163541502Swpaul /* 163641502Swpaul * The Rhine chip doesn't auto-pad, so we have to make 163741502Swpaul * sure to pad short frames out to the minimum frame length 163841502Swpaul * ourselves. 163941502Swpaul */ 164041502Swpaul if (m_head->m_len < VR_MIN_FRAMELEN) { 164141502Swpaul m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; 164241502Swpaul m_new->m_len = m_new->m_pkthdr.len; 164341502Swpaul } 164441502Swpaul f = c->vr_ptr; 164541502Swpaul f->vr_data = vtophys(mtod(m_new, caddr_t)); 164641502Swpaul f->vr_ctl = total_len = m_new->m_len; 164741502Swpaul f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 164841502Swpaul f->vr_status = 0; 164941502Swpaul frag = 1; 165041502Swpaul } 165141502Swpaul 165241502Swpaul c->vr_mbuf = m_head; 165342491Swpaul c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 165441502Swpaul c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 165541502Swpaul 165641502Swpaul return(0); 165741502Swpaul} 165841502Swpaul 165941502Swpaul/* 166041502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 166141502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 166241502Swpaul * copy of the pointers since the transmit list fragment pointers are 166341502Swpaul * physical addresses. 166441502Swpaul */ 166541502Swpaul 166641502Swpaulstatic void vr_start(ifp) 166741502Swpaul struct ifnet *ifp; 166841502Swpaul{ 166941502Swpaul struct vr_softc *sc; 167041502Swpaul struct mbuf *m_head = NULL; 167141502Swpaul struct vr_chain *cur_tx = NULL, *start_tx; 167241502Swpaul 167341502Swpaul sc = ifp->if_softc; 167441502Swpaul 167541502Swpaul if (sc->vr_autoneg) { 167641502Swpaul sc->vr_tx_pend = 1; 167741502Swpaul return; 167841502Swpaul } 167941502Swpaul 168041502Swpaul /* 168141502Swpaul * Check for an available queue slot. If there are none, 168241502Swpaul * punt. 168341502Swpaul */ 168441502Swpaul if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { 168541502Swpaul ifp->if_flags |= IFF_OACTIVE; 168641502Swpaul return; 168741502Swpaul } 168841502Swpaul 168941502Swpaul start_tx = sc->vr_cdata.vr_tx_free; 169041502Swpaul 169141502Swpaul while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { 169241502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 169341502Swpaul if (m_head == NULL) 169441502Swpaul break; 169541502Swpaul 169641502Swpaul /* Pick a descriptor off the free list. */ 169741502Swpaul cur_tx = sc->vr_cdata.vr_tx_free; 169841502Swpaul sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; 169941502Swpaul 170041502Swpaul /* Pack the data into the descriptor. */ 170141502Swpaul vr_encap(sc, cur_tx, m_head); 170241502Swpaul 170341502Swpaul if (cur_tx != start_tx) 170441502Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 170541502Swpaul 170648645Sdes#if NBPF > 0 170741502Swpaul /* 170841502Swpaul * If there's a BPF listener, bounce a copy of this frame 170941502Swpaul * to him. 171041502Swpaul */ 171141502Swpaul if (ifp->if_bpf) 171241502Swpaul bpf_mtap(ifp, cur_tx->vr_mbuf); 171341502Swpaul#endif 171442491Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 171542491Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_TX_GO); 171641502Swpaul } 171741502Swpaul 171841502Swpaul /* 171941526Swpaul * If there are no frames queued, bail. 172041526Swpaul */ 172141526Swpaul if (cur_tx == NULL) 172241526Swpaul return; 172341526Swpaul 172441502Swpaul sc->vr_cdata.vr_tx_tail = cur_tx; 172541502Swpaul 172642491Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 172741502Swpaul sc->vr_cdata.vr_tx_head = start_tx; 172841502Swpaul 172941502Swpaul /* 173041502Swpaul * Set a timeout in case the chip goes out to lunch. 173141502Swpaul */ 173241502Swpaul ifp->if_timer = 5; 173341502Swpaul 173441502Swpaul return; 173541502Swpaul} 173641502Swpaul 173741502Swpaulstatic void vr_init(xsc) 173841502Swpaul void *xsc; 173941502Swpaul{ 174041502Swpaul struct vr_softc *sc = xsc; 174141502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 174241502Swpaul u_int16_t phy_bmcr = 0; 174341502Swpaul int s; 174441502Swpaul 174541502Swpaul if (sc->vr_autoneg) 174641502Swpaul return; 174741502Swpaul 174841502Swpaul s = splimp(); 174941502Swpaul 175041502Swpaul if (sc->vr_pinfo != NULL) 175141502Swpaul phy_bmcr = vr_phy_readreg(sc, PHY_BMCR); 175241502Swpaul 175341502Swpaul /* 175441502Swpaul * Cancel pending I/O and free all RX/TX buffers. 175541502Swpaul */ 175641502Swpaul vr_stop(sc); 175741502Swpaul vr_reset(sc); 175841502Swpaul 175941502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 176041502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD); 176141502Swpaul 176241502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 176341502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 176441502Swpaul 176541502Swpaul /* Init circular RX list. */ 176641502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 176741502Swpaul printf("vr%d: initialization failed: no " 176841502Swpaul "memory for rx buffers\n", sc->vr_unit); 176941502Swpaul vr_stop(sc); 177041502Swpaul (void)splx(s); 177141502Swpaul return; 177241502Swpaul } 177341502Swpaul 177441502Swpaul /* 177541502Swpaul * Init tx descriptors. 177641502Swpaul */ 177741502Swpaul vr_list_tx_init(sc); 177841502Swpaul 177941502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 178041502Swpaul if (ifp->if_flags & IFF_PROMISC) 178141502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 178241502Swpaul else 178341502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 178441502Swpaul 178541502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 178641502Swpaul if (ifp->if_flags & IFF_BROADCAST) 178741502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 178841502Swpaul else 178941502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 179041502Swpaul 179141502Swpaul /* 179241502Swpaul * Program the multicast filter, if necessary. 179341502Swpaul */ 179441502Swpaul vr_setmulti(sc); 179541502Swpaul 179641502Swpaul /* 179741502Swpaul * Load the address of the RX list. 179841502Swpaul */ 179941502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 180041502Swpaul 180141502Swpaul /* Enable receiver and transmitter. */ 180241502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 180341502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 180441502Swpaul VR_CMD_RX_GO); 180541502Swpaul 180641502Swpaul vr_setcfg(sc, vr_phy_readreg(sc, PHY_BMCR)); 180741502Swpaul 180841502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 180941502Swpaul 181041502Swpaul /* 181141502Swpaul * Enable interrupts. 181241502Swpaul */ 181341502Swpaul CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 181441502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 181541502Swpaul 181641502Swpaul /* Restore state of BMCR */ 181741502Swpaul if (sc->vr_pinfo != NULL) 181841502Swpaul vr_phy_writereg(sc, PHY_BMCR, phy_bmcr); 181941502Swpaul 182041502Swpaul ifp->if_flags |= IFF_RUNNING; 182141502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 182241502Swpaul 182341502Swpaul (void)splx(s); 182441502Swpaul 182541502Swpaul return; 182641502Swpaul} 182741502Swpaul 182841502Swpaul/* 182941502Swpaul * Set media options. 183041502Swpaul */ 183141502Swpaulstatic int vr_ifmedia_upd(ifp) 183241502Swpaul struct ifnet *ifp; 183341502Swpaul{ 183441502Swpaul struct vr_softc *sc; 183541502Swpaul struct ifmedia *ifm; 183641502Swpaul 183741502Swpaul sc = ifp->if_softc; 183841502Swpaul ifm = &sc->ifmedia; 183941502Swpaul 184041502Swpaul if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 184141502Swpaul return(EINVAL); 184241502Swpaul 184341502Swpaul if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) 184441502Swpaul vr_autoneg_mii(sc, VR_FLAG_SCHEDDELAY, 1); 184541502Swpaul else 184641502Swpaul vr_setmode_mii(sc, ifm->ifm_media); 184741502Swpaul 184841502Swpaul return(0); 184941502Swpaul} 185041502Swpaul 185141502Swpaul/* 185241502Swpaul * Report current media status. 185341502Swpaul */ 185441502Swpaulstatic void vr_ifmedia_sts(ifp, ifmr) 185541502Swpaul struct ifnet *ifp; 185641502Swpaul struct ifmediareq *ifmr; 185741502Swpaul{ 185841502Swpaul struct vr_softc *sc; 185941502Swpaul u_int16_t advert = 0, ability = 0; 186041502Swpaul 186141502Swpaul sc = ifp->if_softc; 186241502Swpaul 186341502Swpaul ifmr->ifm_active = IFM_ETHER; 186441502Swpaul 186541502Swpaul if (!(vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) { 186641502Swpaul if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL) 186741502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX; 186841502Swpaul else 186941502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T; 187041502Swpaul if (vr_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX) 187141502Swpaul ifmr->ifm_active |= IFM_FDX; 187241502Swpaul else 187341502Swpaul ifmr->ifm_active |= IFM_HDX; 187441502Swpaul return; 187541502Swpaul } 187641502Swpaul 187741502Swpaul ability = vr_phy_readreg(sc, PHY_LPAR); 187841502Swpaul advert = vr_phy_readreg(sc, PHY_ANAR); 187941502Swpaul if (advert & PHY_ANAR_100BT4 && 188041502Swpaul ability & PHY_ANAR_100BT4) { 188141502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_T4; 188241502Swpaul } else if (advert & PHY_ANAR_100BTXFULL && 188341502Swpaul ability & PHY_ANAR_100BTXFULL) { 188441502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_FDX; 188541502Swpaul } else if (advert & PHY_ANAR_100BTXHALF && 188641502Swpaul ability & PHY_ANAR_100BTXHALF) { 188741502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_100_TX|IFM_HDX; 188841502Swpaul } else if (advert & PHY_ANAR_10BTFULL && 188941502Swpaul ability & PHY_ANAR_10BTFULL) { 189041502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_FDX; 189141502Swpaul } else if (advert & PHY_ANAR_10BTHALF && 189241502Swpaul ability & PHY_ANAR_10BTHALF) { 189341502Swpaul ifmr->ifm_active = IFM_ETHER|IFM_10_T|IFM_HDX; 189441502Swpaul } 189541502Swpaul 189641502Swpaul return; 189741502Swpaul} 189841502Swpaul 189941502Swpaulstatic int vr_ioctl(ifp, command, data) 190041502Swpaul struct ifnet *ifp; 190141502Swpaul u_long command; 190241502Swpaul caddr_t data; 190341502Swpaul{ 190441502Swpaul struct vr_softc *sc = ifp->if_softc; 190541502Swpaul struct ifreq *ifr = (struct ifreq *) data; 190641502Swpaul int s, error = 0; 190741502Swpaul 190841502Swpaul s = splimp(); 190941502Swpaul 191041502Swpaul switch(command) { 191141502Swpaul case SIOCSIFADDR: 191241502Swpaul case SIOCGIFADDR: 191341502Swpaul case SIOCSIFMTU: 191441502Swpaul error = ether_ioctl(ifp, command, data); 191541502Swpaul break; 191641502Swpaul case SIOCSIFFLAGS: 191741502Swpaul if (ifp->if_flags & IFF_UP) { 191841502Swpaul vr_init(sc); 191941502Swpaul } else { 192041502Swpaul if (ifp->if_flags & IFF_RUNNING) 192141502Swpaul vr_stop(sc); 192241502Swpaul } 192341502Swpaul error = 0; 192441502Swpaul break; 192541502Swpaul case SIOCADDMULTI: 192641502Swpaul case SIOCDELMULTI: 192741502Swpaul vr_setmulti(sc); 192841502Swpaul error = 0; 192941502Swpaul break; 193041502Swpaul case SIOCGIFMEDIA: 193141502Swpaul case SIOCSIFMEDIA: 193241502Swpaul error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command); 193341502Swpaul break; 193441502Swpaul default: 193541502Swpaul error = EINVAL; 193641502Swpaul break; 193741502Swpaul } 193841502Swpaul 193941502Swpaul (void)splx(s); 194041502Swpaul 194141502Swpaul return(error); 194241502Swpaul} 194341502Swpaul 194441502Swpaulstatic void vr_watchdog(ifp) 194541502Swpaul struct ifnet *ifp; 194641502Swpaul{ 194741502Swpaul struct vr_softc *sc; 194841502Swpaul 194941502Swpaul sc = ifp->if_softc; 195041502Swpaul 195141502Swpaul if (sc->vr_autoneg) { 195241502Swpaul vr_autoneg_mii(sc, VR_FLAG_DELAYTIMEO, 1); 195349610Swpaul if (!(ifp->if_flags & IFF_UP)) 195449610Swpaul vr_stop(sc); 195541502Swpaul return; 195641502Swpaul } 195741502Swpaul 195841502Swpaul ifp->if_oerrors++; 195941502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 196041502Swpaul 196141502Swpaul if (!(vr_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT)) 196241502Swpaul printf("vr%d: no carrier - transceiver cable problem?\n", 196341502Swpaul sc->vr_unit); 196441502Swpaul 196541502Swpaul vr_stop(sc); 196641502Swpaul vr_reset(sc); 196741502Swpaul vr_init(sc); 196841502Swpaul 196941502Swpaul if (ifp->if_snd.ifq_head != NULL) 197041502Swpaul vr_start(ifp); 197141502Swpaul 197241502Swpaul return; 197341502Swpaul} 197441502Swpaul 197541502Swpaul/* 197641502Swpaul * Stop the adapter and free any mbufs allocated to the 197741502Swpaul * RX and TX lists. 197841502Swpaul */ 197941502Swpaulstatic void vr_stop(sc) 198041502Swpaul struct vr_softc *sc; 198141502Swpaul{ 198241502Swpaul register int i; 198341502Swpaul struct ifnet *ifp; 198441502Swpaul 198541502Swpaul ifp = &sc->arpcom.ac_if; 198641502Swpaul ifp->if_timer = 0; 198741502Swpaul 198841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 198941502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 199041502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 199141502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 199241502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 199341502Swpaul 199441502Swpaul /* 199541502Swpaul * Free data in the RX lists. 199641502Swpaul */ 199741502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 199841502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 199941502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 200041502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 200141502Swpaul } 200241502Swpaul } 200341502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 200441502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 200541502Swpaul 200641502Swpaul /* 200741502Swpaul * Free the TX list buffers. 200841502Swpaul */ 200941502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 201041502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 201141502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 201241502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 201341502Swpaul } 201441502Swpaul } 201541502Swpaul 201641502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 201741502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 201841502Swpaul 201941502Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 202041502Swpaul 202141502Swpaul return; 202241502Swpaul} 202341502Swpaul 202441502Swpaul/* 202541502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 202641502Swpaul * get confused by errant DMAs when rebooting. 202741502Swpaul */ 202849610Swpaulstatic void vr_shutdown(dev) 202949610Swpaul device_t dev; 203041502Swpaul{ 203149610Swpaul struct vr_softc *sc; 203241502Swpaul 203349610Swpaul sc = device_get_softc(dev); 203449610Swpaul 203541502Swpaul vr_stop(sc); 203641502Swpaul 203741502Swpaul return; 203841502Swpaul} 2039