if_vr.c revision 109058
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 109058 2003-01-10 08:09:58Z mbr $ 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 <sys/param.h> 6341502Swpaul#include <sys/systm.h> 6441502Swpaul#include <sys/sockio.h> 6541502Swpaul#include <sys/mbuf.h> 6641502Swpaul#include <sys/malloc.h> 6741502Swpaul#include <sys/kernel.h> 6841502Swpaul#include <sys/socket.h> 6941502Swpaul 7041502Swpaul#include <net/if.h> 7141502Swpaul#include <net/if_arp.h> 7241502Swpaul#include <net/ethernet.h> 7341502Swpaul#include <net/if_dl.h> 7441502Swpaul#include <net/if_media.h> 7541502Swpaul 7641502Swpaul#include <net/bpf.h> 7741502Swpaul 7841502Swpaul#include <vm/vm.h> /* for vtophys */ 7941502Swpaul#include <vm/pmap.h> /* for vtophys */ 8041502Swpaul#include <machine/bus_pio.h> 8141502Swpaul#include <machine/bus_memio.h> 8241502Swpaul#include <machine/bus.h> 8349610Swpaul#include <machine/resource.h> 8449610Swpaul#include <sys/bus.h> 8549610Swpaul#include <sys/rman.h> 8641502Swpaul 8751432Swpaul#include <dev/mii/mii.h> 8851432Swpaul#include <dev/mii/miivar.h> 8951432Swpaul 9041502Swpaul#include <pci/pcireg.h> 9141502Swpaul#include <pci/pcivar.h> 9241502Swpaul 9341502Swpaul#define VR_USEIOSPACE 9441502Swpaul 9541502Swpaul#include <pci/if_vrreg.h> 9641502Swpaul 9759758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 9859758Speter 9951432Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 10051432Swpaul#include "miibus_if.h" 10151432Swpaul 10241502Swpaul#ifndef lint 10341591Sarchiestatic const char rcsid[] = 10450477Speter "$FreeBSD: head/sys/dev/vr/if_vr.c 109058 2003-01-10 08:09:58Z mbr $"; 10541502Swpaul#endif 10641502Swpaul 10741502Swpaul/* 10841502Swpaul * Various supported device vendors/types and their names. 10941502Swpaul */ 11041502Swpaulstatic struct vr_type vr_devs[] = { 11141502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 11241502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 11341502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11441502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11562653Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 11662653Swpaul "VIA VT6102 Rhine II 10/100BaseTX" }, 11744238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 11844238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 11944238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 12044238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 12141502Swpaul { 0, 0, NULL } 12241502Swpaul}; 12341502Swpaul 12492739Salfredstatic int vr_probe (device_t); 12592739Salfredstatic int vr_attach (device_t); 12692739Salfredstatic int vr_detach (device_t); 12741502Swpaul 12892739Salfredstatic int vr_newbuf (struct vr_softc *, 12949610Swpaul struct vr_chain_onefrag *, 13092739Salfred struct mbuf *); 13192739Salfredstatic int vr_encap (struct vr_softc *, struct vr_chain *, 13292739Salfred struct mbuf * ); 13341502Swpaul 13492739Salfredstatic void vr_rxeof (struct vr_softc *); 13592739Salfredstatic void vr_rxeoc (struct vr_softc *); 13692739Salfredstatic void vr_txeof (struct vr_softc *); 13792739Salfredstatic void vr_txeoc (struct vr_softc *); 13892739Salfredstatic void vr_tick (void *); 13992739Salfredstatic void vr_intr (void *); 14092739Salfredstatic void vr_start (struct ifnet *); 14192739Salfredstatic int vr_ioctl (struct ifnet *, u_long, caddr_t); 14292739Salfredstatic void vr_init (void *); 14392739Salfredstatic void vr_stop (struct vr_softc *); 14492739Salfredstatic void vr_watchdog (struct ifnet *); 14592739Salfredstatic void vr_shutdown (device_t); 14692739Salfredstatic int vr_ifmedia_upd (struct ifnet *); 14792739Salfredstatic void vr_ifmedia_sts (struct ifnet *, struct ifmediareq *); 14841502Swpaul 14992739Salfredstatic void vr_mii_sync (struct vr_softc *); 15092739Salfredstatic void vr_mii_send (struct vr_softc *, u_int32_t, int); 15192739Salfredstatic int vr_mii_readreg (struct vr_softc *, struct vr_mii_frame *); 15292739Salfredstatic int vr_mii_writereg (struct vr_softc *, struct vr_mii_frame *); 15392739Salfredstatic int vr_miibus_readreg (device_t, int, int); 15492739Salfredstatic int vr_miibus_writereg (device_t, int, int, int); 15592739Salfredstatic void vr_miibus_statchg (device_t); 15641502Swpaul 15792739Salfredstatic void vr_setcfg (struct vr_softc *, int); 15892739Salfredstatic u_int8_t vr_calchash (u_int8_t *); 15992739Salfredstatic void vr_setmulti (struct vr_softc *); 16092739Salfredstatic void vr_reset (struct vr_softc *); 16192739Salfredstatic int vr_list_rx_init (struct vr_softc *); 16292739Salfredstatic int vr_list_tx_init (struct vr_softc *); 16341502Swpaul 16449610Swpaul#ifdef VR_USEIOSPACE 16549610Swpaul#define VR_RES SYS_RES_IOPORT 16649610Swpaul#define VR_RID VR_PCI_LOIO 16749610Swpaul#else 16849610Swpaul#define VR_RES SYS_RES_MEMORY 16949610Swpaul#define VR_RID VR_PCI_LOMEM 17049610Swpaul#endif 17149610Swpaul 17249610Swpaulstatic device_method_t vr_methods[] = { 17349610Swpaul /* Device interface */ 17449610Swpaul DEVMETHOD(device_probe, vr_probe), 17549610Swpaul DEVMETHOD(device_attach, vr_attach), 17649610Swpaul DEVMETHOD(device_detach, vr_detach), 17749610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 17851432Swpaul 17951432Swpaul /* bus interface */ 18051432Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 18151432Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 18251432Swpaul 18351432Swpaul /* MII interface */ 18451432Swpaul DEVMETHOD(miibus_readreg, vr_miibus_readreg), 18551432Swpaul DEVMETHOD(miibus_writereg, vr_miibus_writereg), 18651432Swpaul DEVMETHOD(miibus_statchg, vr_miibus_statchg), 18751432Swpaul 18849610Swpaul { 0, 0 } 18949610Swpaul}; 19049610Swpaul 19149610Swpaulstatic driver_t vr_driver = { 19251455Swpaul "vr", 19349610Swpaul vr_methods, 19449610Swpaul sizeof(struct vr_softc) 19549610Swpaul}; 19649610Swpaul 19749610Swpaulstatic devclass_t vr_devclass; 19849610Swpaul 19951533SwpaulDRIVER_MODULE(if_vr, pci, vr_driver, vr_devclass, 0, 0); 20051473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0); 20149610Swpaul 20241502Swpaul#define VR_SETBIT(sc, reg, x) \ 20341502Swpaul CSR_WRITE_1(sc, reg, \ 204105221Sphk CSR_READ_1(sc, reg) | (x)) 20541502Swpaul 20641502Swpaul#define VR_CLRBIT(sc, reg, x) \ 20741502Swpaul CSR_WRITE_1(sc, reg, \ 208105221Sphk CSR_READ_1(sc, reg) & ~(x)) 20941502Swpaul 21041502Swpaul#define VR_SETBIT16(sc, reg, x) \ 21141502Swpaul CSR_WRITE_2(sc, reg, \ 212105221Sphk CSR_READ_2(sc, reg) | (x)) 21341502Swpaul 21441502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 21541502Swpaul CSR_WRITE_2(sc, reg, \ 216105221Sphk CSR_READ_2(sc, reg) & ~(x)) 21741502Swpaul 21841502Swpaul#define VR_SETBIT32(sc, reg, x) \ 21941502Swpaul CSR_WRITE_4(sc, reg, \ 220105221Sphk CSR_READ_4(sc, reg) | (x)) 22141502Swpaul 22241502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 22341502Swpaul CSR_WRITE_4(sc, reg, \ 224105221Sphk CSR_READ_4(sc, reg) & ~(x)) 22541502Swpaul 22641502Swpaul#define SIO_SET(x) \ 22741502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 228105221Sphk CSR_READ_1(sc, VR_MIICMD) | (x)) 22941502Swpaul 23041502Swpaul#define SIO_CLR(x) \ 23141502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 232105221Sphk CSR_READ_1(sc, VR_MIICMD) & ~(x)) 23341502Swpaul 23441502Swpaul/* 23541502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 23641502Swpaul */ 237102336Salfredstatic void 238102336Salfredvr_mii_sync(sc) 23941502Swpaul struct vr_softc *sc; 24041502Swpaul{ 24141502Swpaul register int i; 24241502Swpaul 24341502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 24441502Swpaul 24541502Swpaul for (i = 0; i < 32; i++) { 24641502Swpaul SIO_SET(VR_MIICMD_CLK); 24741502Swpaul DELAY(1); 24841502Swpaul SIO_CLR(VR_MIICMD_CLK); 24941502Swpaul DELAY(1); 25041502Swpaul } 25141502Swpaul 25241502Swpaul return; 25341502Swpaul} 25441502Swpaul 25541502Swpaul/* 25641502Swpaul * Clock a series of bits through the MII. 25741502Swpaul */ 258102336Salfredstatic void 259102336Salfredvr_mii_send(sc, bits, cnt) 26041502Swpaul struct vr_softc *sc; 26141502Swpaul u_int32_t bits; 26241502Swpaul int cnt; 26341502Swpaul{ 26441502Swpaul int i; 26541502Swpaul 26641502Swpaul SIO_CLR(VR_MIICMD_CLK); 26741502Swpaul 26841502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 26941502Swpaul if (bits & i) { 27041502Swpaul SIO_SET(VR_MIICMD_DATAIN); 27141502Swpaul } else { 27241502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 27341502Swpaul } 27441502Swpaul DELAY(1); 27541502Swpaul SIO_CLR(VR_MIICMD_CLK); 27641502Swpaul DELAY(1); 27741502Swpaul SIO_SET(VR_MIICMD_CLK); 27841502Swpaul } 27941502Swpaul} 28041502Swpaul 28141502Swpaul/* 28241502Swpaul * Read an PHY register through the MII. 28341502Swpaul */ 284102336Salfredstatic int 285102336Salfredvr_mii_readreg(sc, frame) 28641502Swpaul struct vr_softc *sc; 28741502Swpaul struct vr_mii_frame *frame; 28841502Swpaul 28941502Swpaul{ 29067087Swpaul int i, ack; 29141502Swpaul 29267087Swpaul VR_LOCK(sc); 29341502Swpaul 29441502Swpaul /* 29541502Swpaul * Set up frame for RX. 29641502Swpaul */ 29741502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 29841502Swpaul frame->mii_opcode = VR_MII_READOP; 29941502Swpaul frame->mii_turnaround = 0; 30041502Swpaul frame->mii_data = 0; 30141502Swpaul 30241502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 30341502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 30441502Swpaul 30541502Swpaul /* 30641502Swpaul * Turn on data xmit. 30741502Swpaul */ 30841502Swpaul SIO_SET(VR_MIICMD_DIR); 30941502Swpaul 31041502Swpaul vr_mii_sync(sc); 31141502Swpaul 31241502Swpaul /* 31341502Swpaul * Send command/address info. 31441502Swpaul */ 31541502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 31641502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 31741502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 31841502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 31941502Swpaul 32041502Swpaul /* Idle bit */ 32141502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 32241502Swpaul DELAY(1); 32341502Swpaul SIO_SET(VR_MIICMD_CLK); 32441502Swpaul DELAY(1); 32541502Swpaul 32641502Swpaul /* Turn off xmit. */ 32741502Swpaul SIO_CLR(VR_MIICMD_DIR); 32841502Swpaul 32941502Swpaul /* Check for ack */ 33041502Swpaul SIO_CLR(VR_MIICMD_CLK); 33141502Swpaul DELAY(1); 332109058Smbr ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 33341502Swpaul SIO_SET(VR_MIICMD_CLK); 33441502Swpaul DELAY(1); 33541502Swpaul 33641502Swpaul /* 33741502Swpaul * Now try reading data bits. If the ack failed, we still 33841502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 33941502Swpaul */ 34041502Swpaul if (ack) { 34141502Swpaul for(i = 0; i < 16; i++) { 34241502Swpaul SIO_CLR(VR_MIICMD_CLK); 34341502Swpaul DELAY(1); 34441502Swpaul SIO_SET(VR_MIICMD_CLK); 34541502Swpaul DELAY(1); 34641502Swpaul } 34741502Swpaul goto fail; 34841502Swpaul } 34941502Swpaul 35041502Swpaul for (i = 0x8000; i; i >>= 1) { 35141502Swpaul SIO_CLR(VR_MIICMD_CLK); 35241502Swpaul DELAY(1); 35341502Swpaul if (!ack) { 35441502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 35541502Swpaul frame->mii_data |= i; 35641502Swpaul DELAY(1); 35741502Swpaul } 35841502Swpaul SIO_SET(VR_MIICMD_CLK); 35941502Swpaul DELAY(1); 36041502Swpaul } 36141502Swpaul 36241502Swpaulfail: 36341502Swpaul 36441502Swpaul SIO_CLR(VR_MIICMD_CLK); 36541502Swpaul DELAY(1); 36641502Swpaul SIO_SET(VR_MIICMD_CLK); 36741502Swpaul DELAY(1); 36841502Swpaul 36967087Swpaul VR_UNLOCK(sc); 37041502Swpaul 37141502Swpaul if (ack) 37241502Swpaul return(1); 37341502Swpaul return(0); 37441502Swpaul} 37541502Swpaul 37641502Swpaul/* 37741502Swpaul * Write to a PHY register through the MII. 37841502Swpaul */ 379102336Salfredstatic int 380102336Salfredvr_mii_writereg(sc, frame) 38141502Swpaul struct vr_softc *sc; 38241502Swpaul struct vr_mii_frame *frame; 38341502Swpaul 38441502Swpaul{ 38567087Swpaul VR_LOCK(sc); 38641502Swpaul 38741502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 38841502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 38941502Swpaul 39041502Swpaul /* 39141502Swpaul * Set up frame for TX. 39241502Swpaul */ 39341502Swpaul 39441502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 39541502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 39641502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 39741502Swpaul 39841502Swpaul /* 39941502Swpaul * Turn on data output. 40041502Swpaul */ 40141502Swpaul SIO_SET(VR_MIICMD_DIR); 40241502Swpaul 40341502Swpaul vr_mii_sync(sc); 40441502Swpaul 40541502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 40641502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 40741502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 40841502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 40941502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 41041502Swpaul vr_mii_send(sc, frame->mii_data, 16); 41141502Swpaul 41241502Swpaul /* Idle bit. */ 41341502Swpaul SIO_SET(VR_MIICMD_CLK); 41441502Swpaul DELAY(1); 41541502Swpaul SIO_CLR(VR_MIICMD_CLK); 41641502Swpaul DELAY(1); 41741502Swpaul 41841502Swpaul /* 41941502Swpaul * Turn off xmit. 42041502Swpaul */ 42141502Swpaul SIO_CLR(VR_MIICMD_DIR); 42241502Swpaul 42367087Swpaul VR_UNLOCK(sc); 42441502Swpaul 42541502Swpaul return(0); 42641502Swpaul} 42741502Swpaul 428102336Salfredstatic int 429102336Salfredvr_miibus_readreg(dev, phy, reg) 43051432Swpaul device_t dev; 43151432Swpaul int phy, reg; 43251432Swpaul{ 43341502Swpaul struct vr_softc *sc; 43441502Swpaul struct vr_mii_frame frame; 43541502Swpaul 43651432Swpaul sc = device_get_softc(dev); 43741502Swpaul bzero((char *)&frame, sizeof(frame)); 43841502Swpaul 43951432Swpaul frame.mii_phyaddr = phy; 44041502Swpaul frame.mii_regaddr = reg; 44141502Swpaul vr_mii_readreg(sc, &frame); 44241502Swpaul 44341502Swpaul return(frame.mii_data); 44441502Swpaul} 44541502Swpaul 446102336Salfredstatic int 447102336Salfredvr_miibus_writereg(dev, phy, reg, data) 44851432Swpaul device_t dev; 44951432Swpaul u_int16_t phy, reg, data; 45051432Swpaul{ 45141502Swpaul struct vr_softc *sc; 45241502Swpaul struct vr_mii_frame frame; 45341502Swpaul 45451432Swpaul sc = device_get_softc(dev); 45541502Swpaul bzero((char *)&frame, sizeof(frame)); 45641502Swpaul 45751432Swpaul frame.mii_phyaddr = phy; 45841502Swpaul frame.mii_regaddr = reg; 45941502Swpaul frame.mii_data = data; 46041502Swpaul 46141502Swpaul vr_mii_writereg(sc, &frame); 46241502Swpaul 46351432Swpaul return(0); 46451432Swpaul} 46551432Swpaul 466102336Salfredstatic void 467102336Salfredvr_miibus_statchg(dev) 46851432Swpaul device_t dev; 46951432Swpaul{ 47051432Swpaul struct vr_softc *sc; 47151432Swpaul struct mii_data *mii; 47251432Swpaul 47351432Swpaul sc = device_get_softc(dev); 47467087Swpaul VR_LOCK(sc); 47551432Swpaul mii = device_get_softc(sc->vr_miibus); 47651432Swpaul vr_setcfg(sc, mii->mii_media_active); 47767087Swpaul VR_UNLOCK(sc); 47851432Swpaul 47941502Swpaul return; 48041502Swpaul} 48141502Swpaul 48241502Swpaul/* 48341502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits. 48441502Swpaul */ 48541502Swpaulstatic u_int8_t vr_calchash(addr) 48641502Swpaul u_int8_t *addr; 48741502Swpaul{ 48841502Swpaul u_int32_t crc, carry; 48941502Swpaul int i, j; 49041502Swpaul u_int8_t c; 49141502Swpaul 49241502Swpaul /* Compute CRC for the address value. */ 49341502Swpaul crc = 0xFFFFFFFF; /* initial value */ 49441502Swpaul 49541502Swpaul for (i = 0; i < 6; i++) { 49641502Swpaul c = *(addr + i); 49741502Swpaul for (j = 0; j < 8; j++) { 49841502Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 49941502Swpaul crc <<= 1; 50041502Swpaul c >>= 1; 50141502Swpaul if (carry) 50241502Swpaul crc = (crc ^ 0x04c11db6) | carry; 50341502Swpaul } 50441502Swpaul } 50541502Swpaul 50641502Swpaul /* return the filter bit position */ 50741502Swpaul return((crc >> 26) & 0x0000003F); 50841502Swpaul} 50941502Swpaul 51041502Swpaul/* 51141502Swpaul * Program the 64-bit multicast hash filter. 51241502Swpaul */ 513102336Salfredstatic void 514102336Salfredvr_setmulti(sc) 51541502Swpaul struct vr_softc *sc; 51641502Swpaul{ 51741502Swpaul struct ifnet *ifp; 51841502Swpaul int h = 0; 51941502Swpaul u_int32_t hashes[2] = { 0, 0 }; 52041502Swpaul struct ifmultiaddr *ifma; 52141502Swpaul u_int8_t rxfilt; 52241502Swpaul int mcnt = 0; 52341502Swpaul 52441502Swpaul ifp = &sc->arpcom.ac_if; 52541502Swpaul 52641502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 52741502Swpaul 52841502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 52941502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 53041502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 53141502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 53241502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 53341502Swpaul return; 53441502Swpaul } 53541502Swpaul 53641502Swpaul /* first, zot all the existing hash bits */ 53741502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 53841502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 53941502Swpaul 54041502Swpaul /* now program new ones */ 54172084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 54241502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 54341502Swpaul continue; 54441502Swpaul h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 54541502Swpaul if (h < 32) 54641502Swpaul hashes[0] |= (1 << h); 54741502Swpaul else 54841502Swpaul hashes[1] |= (1 << (h - 32)); 54941502Swpaul mcnt++; 55041502Swpaul } 55141502Swpaul 55241502Swpaul if (mcnt) 55341502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 55441502Swpaul else 55541502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 55641502Swpaul 55741502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 55841502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 55941502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 56041502Swpaul 56141502Swpaul return; 56241502Swpaul} 56341502Swpaul 56441502Swpaul/* 56541502Swpaul * In order to fiddle with the 56641502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 56741502Swpaul * first have to put the transmit and/or receive logic in the idle state. 56841502Swpaul */ 569102336Salfredstatic void 570102336Salfredvr_setcfg(sc, media) 57141502Swpaul struct vr_softc *sc; 57251432Swpaul int media; 57341502Swpaul{ 57441502Swpaul int restart = 0; 57541502Swpaul 57641502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 57741502Swpaul restart = 1; 57841502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 57941502Swpaul } 58041502Swpaul 58151432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 58241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 58341502Swpaul else 58441502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 58541502Swpaul 58641502Swpaul if (restart) 58741502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 58841502Swpaul 58941502Swpaul return; 59041502Swpaul} 59141502Swpaul 592102336Salfredstatic void 593102336Salfredvr_reset(sc) 59441502Swpaul struct vr_softc *sc; 59541502Swpaul{ 59641502Swpaul register int i; 59741502Swpaul 59841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 59941502Swpaul 60041502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 60141502Swpaul DELAY(10); 60241502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 60341502Swpaul break; 60441502Swpaul } 605107220Ssilby if (i == VR_TIMEOUT) { 606107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 607107220Ssilby printf("vr%d: reset never completed!\n", sc->vr_unit); 608107220Ssilby else { 609107220Ssilby /* Use newer force reset command */ 610107220Ssilby printf("vr%d: Using force reset command.\n", sc->vr_unit); 611107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 612107220Ssilby } 613107220Ssilby } 61441502Swpaul 61541502Swpaul /* Wait a little while for the chip to get its brains in order. */ 61641502Swpaul DELAY(1000); 61741502Swpaul 61841502Swpaul return; 61941502Swpaul} 62041502Swpaul 62141502Swpaul/* 62241502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 62341502Swpaul * IDs against our list and return a device name if we find a match. 62441502Swpaul */ 625102336Salfredstatic int 626102336Salfredvr_probe(dev) 62749610Swpaul device_t dev; 62841502Swpaul{ 62941502Swpaul struct vr_type *t; 63041502Swpaul 63141502Swpaul t = vr_devs; 63241502Swpaul 63341502Swpaul while(t->vr_name != NULL) { 63449610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 63549610Swpaul (pci_get_device(dev) == t->vr_did)) { 63649610Swpaul device_set_desc(dev, t->vr_name); 63749610Swpaul return(0); 63841502Swpaul } 63941502Swpaul t++; 64041502Swpaul } 64141502Swpaul 64249610Swpaul return(ENXIO); 64341502Swpaul} 64441502Swpaul 64541502Swpaul/* 64641502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 64741502Swpaul * setup and ethernet/BPF attach. 64841502Swpaul */ 649102336Salfredstatic int 650102336Salfredvr_attach(dev) 65149610Swpaul device_t dev; 65241502Swpaul{ 65367087Swpaul int i; 65441502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 65541502Swpaul u_int32_t command; 65641502Swpaul struct vr_softc *sc; 65741502Swpaul struct ifnet *ifp; 65849610Swpaul int unit, error = 0, rid; 65941502Swpaul 66049610Swpaul sc = device_get_softc(dev); 66149610Swpaul unit = device_get_unit(dev); 66249610Swpaul bzero(sc, sizeof(struct vr_softc *)); 66341502Swpaul 66493818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 66593818Sjhb MTX_DEF | MTX_RECURSE); 66669583Swpaul VR_LOCK(sc); 66769583Swpaul 66841502Swpaul /* 66941502Swpaul * Handle power management nonsense. 67041502Swpaul */ 67172813Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 67272813Swpaul u_int32_t iobase, membase, irq; 67341502Swpaul 67472813Swpaul /* Save important PCI config data. */ 67572813Swpaul iobase = pci_read_config(dev, VR_PCI_LOIO, 4); 67672813Swpaul membase = pci_read_config(dev, VR_PCI_LOMEM, 4); 67772813Swpaul irq = pci_read_config(dev, VR_PCI_INTLINE, 4); 67841502Swpaul 67972813Swpaul /* Reset the power state. */ 68072813Swpaul printf("vr%d: chip is in D%d power mode " 68172813Swpaul "-- setting to D0\n", unit, 68272813Swpaul pci_get_powerstate(dev)); 68372813Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 68441502Swpaul 68541502Swpaul /* Restore PCI config data. */ 68672813Swpaul pci_write_config(dev, VR_PCI_LOIO, iobase, 4); 68772813Swpaul pci_write_config(dev, VR_PCI_LOMEM, membase, 4); 68872813Swpaul pci_write_config(dev, VR_PCI_INTLINE, irq, 4); 68941502Swpaul } 69041502Swpaul 69141502Swpaul /* 69241502Swpaul * Map control/status registers. 69341502Swpaul */ 69472813Swpaul pci_enable_busmaster(dev); 69579472Swpaul pci_enable_io(dev, SYS_RES_IOPORT); 69679472Swpaul pci_enable_io(dev, SYS_RES_MEMORY); 69761041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 698107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 69941502Swpaul 70041502Swpaul#ifdef VR_USEIOSPACE 70141502Swpaul if (!(command & PCIM_CMD_PORTEN)) { 70241502Swpaul printf("vr%d: failed to enable I/O ports!\n", unit); 70341502Swpaul free(sc, M_DEVBUF); 70441502Swpaul goto fail; 70541502Swpaul } 70641502Swpaul#else 70741502Swpaul if (!(command & PCIM_CMD_MEMEN)) { 70841502Swpaul printf("vr%d: failed to enable memory mapping!\n", unit); 70941502Swpaul goto fail; 71041502Swpaul } 71149610Swpaul#endif 71241502Swpaul 71349610Swpaul rid = VR_RID; 71449610Swpaul sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid, 71549610Swpaul 0, ~0, 1, RF_ACTIVE); 71649610Swpaul 71749610Swpaul if (sc->vr_res == NULL) { 71849610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 71949610Swpaul error = ENXIO; 72041502Swpaul goto fail; 72141502Swpaul } 72241502Swpaul 72349610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 72449610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 72541502Swpaul 72641502Swpaul /* Allocate interrupt */ 72749610Swpaul rid = 0; 72849610Swpaul sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 72949610Swpaul RF_SHAREABLE | RF_ACTIVE); 73049610Swpaul 73149610Swpaul if (sc->vr_irq == NULL) { 73241502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 73349610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 73449610Swpaul error = ENXIO; 73541502Swpaul goto fail; 73641502Swpaul } 73741502Swpaul 73849610Swpaul error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET, 73949610Swpaul vr_intr, sc, &sc->vr_intrhand); 74049610Swpaul 74149610Swpaul if (error) { 74249610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 74349610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 74449610Swpaul printf("vr%d: couldn't set up irq\n", unit); 74549610Swpaul goto fail; 74649610Swpaul } 74749610Swpaul 74876586Swpaul /* 74976586Swpaul * Windows may put the chip in suspend mode when it 75076586Swpaul * shuts down. Be sure to kick it in the head to wake it 75176586Swpaul * up again. 75276586Swpaul */ 75376586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 75476586Swpaul 75541502Swpaul /* Reset the adapter. */ 75641502Swpaul vr_reset(sc); 75741502Swpaul 75841502Swpaul /* 75941502Swpaul * Get station address. The way the Rhine chips work, 76041502Swpaul * you're not allowed to directly access the EEPROM once 76141502Swpaul * they've been programmed a special way. Consequently, 76241502Swpaul * we need to read the node address from the PAR0 and PAR1 76341502Swpaul * registers. 76441502Swpaul */ 76541502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 76641502Swpaul DELAY(200); 76741502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 76841502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 76941502Swpaul 77041502Swpaul /* 77141502Swpaul * A Rhine chip was detected. Inform the world. 77241502Swpaul */ 77341502Swpaul printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); 77441502Swpaul 77541502Swpaul sc->vr_unit = unit; 77641502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 77741502Swpaul 77851432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 77951657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 78051432Swpaul 78151432Swpaul if (sc->vr_ldata == NULL) { 78241502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 78349610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 78449610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 78549610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 78649610Swpaul error = ENXIO; 78749610Swpaul goto fail; 78841502Swpaul } 78941502Swpaul 79041502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 79141502Swpaul 79241502Swpaul ifp = &sc->arpcom.ac_if; 79341502Swpaul ifp->if_softc = sc; 79441502Swpaul ifp->if_unit = unit; 79541502Swpaul ifp->if_name = "vr"; 79641502Swpaul ifp->if_mtu = ETHERMTU; 79741502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 79841502Swpaul ifp->if_ioctl = vr_ioctl; 79941502Swpaul ifp->if_output = ether_output; 80041502Swpaul ifp->if_start = vr_start; 80141502Swpaul ifp->if_watchdog = vr_watchdog; 80241502Swpaul ifp->if_init = vr_init; 80341502Swpaul ifp->if_baudrate = 10000000; 80443515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 80541502Swpaul 80651432Swpaul /* 80751432Swpaul * Do MII setup. 80851432Swpaul */ 80951432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 81051432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 81141502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 81249610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 81349610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 81449610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 81551432Swpaul contigfree(sc->vr_ldata, 81651432Swpaul sizeof(struct vr_list_data), M_DEVBUF); 81749610Swpaul error = ENXIO; 81841502Swpaul goto fail; 81941502Swpaul } 82041502Swpaul 82151432Swpaul callout_handle_init(&sc->vr_stat_ch); 82241502Swpaul 82341502Swpaul /* 82463090Sarchie * Call MI attach routine. 82541502Swpaul */ 826106936Ssam ether_ifattach(ifp, eaddr); 82767087Swpaul VR_UNLOCK(sc); 82867087Swpaul return(0); 82941502Swpaul 83041502Swpaulfail: 83167087Swpaul VR_UNLOCK(sc); 83267087Swpaul mtx_destroy(&sc->vr_mtx); 83367087Swpaul 83449610Swpaul return(error); 83541502Swpaul} 83641502Swpaul 837102336Salfredstatic int 838102336Salfredvr_detach(dev) 83949610Swpaul device_t dev; 84049610Swpaul{ 84149610Swpaul struct vr_softc *sc; 84249610Swpaul struct ifnet *ifp; 84349610Swpaul 84449610Swpaul sc = device_get_softc(dev); 84567087Swpaul VR_LOCK(sc); 84649610Swpaul ifp = &sc->arpcom.ac_if; 84749610Swpaul 84849610Swpaul vr_stop(sc); 849106936Ssam ether_ifdetach(ifp); 85049610Swpaul 85151432Swpaul bus_generic_detach(dev); 85251432Swpaul device_delete_child(dev, sc->vr_miibus); 85351432Swpaul 85449610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 85549610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 85649610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 85749610Swpaul 85851432Swpaul contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 85949610Swpaul 86067087Swpaul VR_UNLOCK(sc); 86167087Swpaul mtx_destroy(&sc->vr_mtx); 86249610Swpaul 86349610Swpaul return(0); 86449610Swpaul} 86549610Swpaul 86641502Swpaul/* 86741502Swpaul * Initialize the transmit descriptors. 86841502Swpaul */ 869102336Salfredstatic int 870102336Salfredvr_list_tx_init(sc) 87141502Swpaul struct vr_softc *sc; 87241502Swpaul{ 87341502Swpaul struct vr_chain_data *cd; 87441502Swpaul struct vr_list_data *ld; 87541502Swpaul int i; 87641502Swpaul 87741502Swpaul cd = &sc->vr_cdata; 87841502Swpaul ld = sc->vr_ldata; 87941502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 88041502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 88141502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 88241502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 88341502Swpaul &cd->vr_tx_chain[0]; 88441502Swpaul else 88541502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 88641502Swpaul &cd->vr_tx_chain[i + 1]; 88741502Swpaul } 88841502Swpaul 88941502Swpaul cd->vr_tx_free = &cd->vr_tx_chain[0]; 89041502Swpaul cd->vr_tx_tail = cd->vr_tx_head = NULL; 89141502Swpaul 89241502Swpaul return(0); 89341502Swpaul} 89441502Swpaul 89541502Swpaul 89641502Swpaul/* 89741502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 89841502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 89941502Swpaul * points back to the first. 90041502Swpaul */ 901102336Salfredstatic int 902102336Salfredvr_list_rx_init(sc) 90341502Swpaul struct vr_softc *sc; 90441502Swpaul{ 90541502Swpaul struct vr_chain_data *cd; 90641502Swpaul struct vr_list_data *ld; 90741502Swpaul int i; 90841502Swpaul 90941502Swpaul cd = &sc->vr_cdata; 91041502Swpaul ld = sc->vr_ldata; 91141502Swpaul 91241502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 91341502Swpaul cd->vr_rx_chain[i].vr_ptr = 91441502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 91549610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 91641502Swpaul return(ENOBUFS); 91741502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 91841502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 91941502Swpaul &cd->vr_rx_chain[0]; 92041502Swpaul ld->vr_rx_list[i].vr_next = 92141502Swpaul vtophys(&ld->vr_rx_list[0]); 92241502Swpaul } else { 92341502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 92441502Swpaul &cd->vr_rx_chain[i + 1]; 92541502Swpaul ld->vr_rx_list[i].vr_next = 92641502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 92741502Swpaul } 92841502Swpaul } 92941502Swpaul 93041502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 93141502Swpaul 93241502Swpaul return(0); 93341502Swpaul} 93441502Swpaul 93541502Swpaul/* 93641502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 93741502Swpaul * Note: the length fields are only 11 bits wide, which means the 93841502Swpaul * largest size we can specify is 2047. This is important because 93941502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 94041502Swpaul * overflow the field and make a mess. 94141502Swpaul */ 942102336Salfredstatic int 943102336Salfredvr_newbuf(sc, c, m) 94441502Swpaul struct vr_softc *sc; 94541502Swpaul struct vr_chain_onefrag *c; 94649610Swpaul struct mbuf *m; 94741502Swpaul{ 94841502Swpaul struct mbuf *m_new = NULL; 94941502Swpaul 95049610Swpaul if (m == NULL) { 95149610Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 95287846Sluigi if (m_new == NULL) 95349610Swpaul return(ENOBUFS); 95441502Swpaul 95549610Swpaul MCLGET(m_new, M_DONTWAIT); 95649610Swpaul if (!(m_new->m_flags & M_EXT)) { 95749610Swpaul m_freem(m_new); 95849610Swpaul return(ENOBUFS); 95949610Swpaul } 96049610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 96149610Swpaul } else { 96249610Swpaul m_new = m; 96349610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 96449610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 96541502Swpaul } 96641502Swpaul 96749610Swpaul m_adj(m_new, sizeof(u_int64_t)); 96849610Swpaul 96941502Swpaul c->vr_mbuf = m_new; 97041502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 97141502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 97242491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 97341502Swpaul 97441502Swpaul return(0); 97541502Swpaul} 97641502Swpaul 97741502Swpaul/* 97841502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 97941502Swpaul * the higher level protocols. 98041502Swpaul */ 981102336Salfredstatic void 982102336Salfredvr_rxeof(sc) 98341502Swpaul struct vr_softc *sc; 98441502Swpaul{ 98541502Swpaul struct mbuf *m; 98641502Swpaul struct ifnet *ifp; 98741502Swpaul struct vr_chain_onefrag *cur_rx; 98841502Swpaul int total_len = 0; 98941502Swpaul u_int32_t rxstat; 99041502Swpaul 99141502Swpaul ifp = &sc->arpcom.ac_if; 99241502Swpaul 99341502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 99441502Swpaul VR_RXSTAT_OWN)) { 99549610Swpaul struct mbuf *m0 = NULL; 99649610Swpaul 99741502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 99841502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 99949610Swpaul m = cur_rx->vr_mbuf; 100041502Swpaul 100141502Swpaul /* 100241502Swpaul * If an error occurs, update stats, clear the 100341502Swpaul * status word and leave the mbuf cluster in place: 100441502Swpaul * it should simply get re-used next time this descriptor 100541502Swpaul * comes up in the ring. 100641502Swpaul */ 100741502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 100841502Swpaul ifp->if_ierrors++; 100941502Swpaul printf("vr%d: rx error: ", sc->vr_unit); 101041502Swpaul switch(rxstat & 0x000000FF) { 101141502Swpaul case VR_RXSTAT_CRCERR: 101241502Swpaul printf("crc error\n"); 101341502Swpaul break; 101441502Swpaul case VR_RXSTAT_FRAMEALIGNERR: 101541502Swpaul printf("frame alignment error\n"); 101641502Swpaul break; 101741502Swpaul case VR_RXSTAT_FIFOOFLOW: 101841502Swpaul printf("FIFO overflow\n"); 101941502Swpaul break; 102041502Swpaul case VR_RXSTAT_GIANT: 102141502Swpaul printf("received giant packet\n"); 102241502Swpaul break; 102341502Swpaul case VR_RXSTAT_RUNT: 102441502Swpaul printf("received runt packet\n"); 102541502Swpaul break; 102641502Swpaul case VR_RXSTAT_BUSERR: 102741502Swpaul printf("system bus error\n"); 102841502Swpaul break; 102941502Swpaul case VR_RXSTAT_BUFFERR: 103041502Swpaul printf("rx buffer error\n"); 103141502Swpaul break; 103241502Swpaul default: 103341502Swpaul printf("unknown rx error\n"); 103441502Swpaul break; 103541502Swpaul } 103649610Swpaul vr_newbuf(sc, cur_rx, m); 103741502Swpaul continue; 103841502Swpaul } 103941502Swpaul 104041502Swpaul /* No errors; receive the packet. */ 104141502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 104241502Swpaul 104341502Swpaul /* 104442048Swpaul * XXX The VIA Rhine chip includes the CRC with every 104542048Swpaul * received frame, and there's no way to turn this 104642048Swpaul * behavior off (at least, I can't find anything in 104742048Swpaul * the manual that explains how to do it) so we have 104842048Swpaul * to trim off the CRC manually. 104942048Swpaul */ 105042048Swpaul total_len -= ETHER_CRC_LEN; 105142048Swpaul 105278508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 105378508Sbmilekic NULL); 105449610Swpaul vr_newbuf(sc, cur_rx, m); 105549610Swpaul if (m0 == NULL) { 105641502Swpaul ifp->if_ierrors++; 105741502Swpaul continue; 105841502Swpaul } 105949610Swpaul m = m0; 106041502Swpaul 106141502Swpaul ifp->if_ipackets++; 1062106936Ssam (*ifp->if_input)(ifp, m); 106341502Swpaul } 106441502Swpaul 106541502Swpaul return; 106641502Swpaul} 106741502Swpaul 1068105221Sphkstatic void 1069102336Salfredvr_rxeoc(sc) 107041502Swpaul struct vr_softc *sc; 107141502Swpaul{ 107241502Swpaul 107341502Swpaul vr_rxeof(sc); 107441502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 107541502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 107641502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 107741502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 107841502Swpaul 107941502Swpaul return; 108041502Swpaul} 108141502Swpaul 108241502Swpaul/* 108341502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 108441502Swpaul * the list buffers. 108541502Swpaul */ 108641502Swpaul 1087102336Salfredstatic void 1088102336Salfredvr_txeof(sc) 108941502Swpaul struct vr_softc *sc; 109041502Swpaul{ 109141502Swpaul struct vr_chain *cur_tx; 109241502Swpaul struct ifnet *ifp; 109341502Swpaul 109441502Swpaul ifp = &sc->arpcom.ac_if; 109541502Swpaul 109696677Ssilby /* Reset the timeout timer; if_txeoc will clear it. */ 109796677Ssilby ifp->if_timer = 5; 109841502Swpaul 109941502Swpaul /* Sanity check. */ 110041502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 110141502Swpaul return; 110241502Swpaul 110341502Swpaul /* 110441502Swpaul * Go through our tx list and free mbufs for those 110541502Swpaul * frames that have been transmitted. 110641502Swpaul */ 110741502Swpaul while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { 110841502Swpaul u_int32_t txstat; 110941502Swpaul 111041502Swpaul cur_tx = sc->vr_cdata.vr_tx_head; 111141502Swpaul txstat = cur_tx->vr_ptr->vr_status; 111241502Swpaul 1113101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1114101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1115101896Ssilby while (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON) 1116101896Ssilby ; /* Wait for chip to shutdown */ 1117101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1118101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1119101896Ssilby break; 1120101896Ssilby } 1121101896Ssilby 112242491Swpaul if (txstat & VR_TXSTAT_OWN) 112341502Swpaul break; 112441502Swpaul 112541502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 112641502Swpaul ifp->if_oerrors++; 112741502Swpaul if (txstat & VR_TXSTAT_DEFER) 112841502Swpaul ifp->if_collisions++; 112941502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 113041502Swpaul ifp->if_collisions++; 113141502Swpaul } 113241502Swpaul 113341502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 113441502Swpaul 113541502Swpaul ifp->if_opackets++; 113651432Swpaul if (cur_tx->vr_mbuf != NULL) { 113751432Swpaul m_freem(cur_tx->vr_mbuf); 113851432Swpaul cur_tx->vr_mbuf = NULL; 113951432Swpaul } 114041502Swpaul 114141502Swpaul if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { 114241502Swpaul sc->vr_cdata.vr_tx_head = NULL; 114341502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 114441502Swpaul break; 114541502Swpaul } 114641502Swpaul 114741502Swpaul sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; 114841502Swpaul } 114941502Swpaul 115041502Swpaul return; 115141502Swpaul} 115241502Swpaul 115341502Swpaul/* 115441502Swpaul * TX 'end of channel' interrupt handler. 115541502Swpaul */ 1156102336Salfredstatic void 1157102336Salfredvr_txeoc(sc) 115841502Swpaul struct vr_softc *sc; 115941502Swpaul{ 116041502Swpaul struct ifnet *ifp; 116141502Swpaul 116241502Swpaul ifp = &sc->arpcom.ac_if; 116341502Swpaul 116441502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) { 116541502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 116641502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 116796677Ssilby ifp->if_timer = 0; 116841502Swpaul } 116941502Swpaul 117041502Swpaul return; 117141502Swpaul} 117241502Swpaul 1173102336Salfredstatic void 1174102336Salfredvr_tick(xsc) 117551432Swpaul void *xsc; 117651432Swpaul{ 117751432Swpaul struct vr_softc *sc; 117851432Swpaul struct mii_data *mii; 117951432Swpaul 118051432Swpaul sc = xsc; 118167087Swpaul VR_LOCK(sc); 118251432Swpaul mii = device_get_softc(sc->vr_miibus); 118351432Swpaul mii_tick(mii); 118451432Swpaul 118551432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 118651432Swpaul 118767087Swpaul VR_UNLOCK(sc); 118851432Swpaul 118951432Swpaul return; 119051432Swpaul} 119151432Swpaul 1192102336Salfredstatic void 1193102336Salfredvr_intr(arg) 119441502Swpaul void *arg; 119541502Swpaul{ 119641502Swpaul struct vr_softc *sc; 119741502Swpaul struct ifnet *ifp; 119841502Swpaul u_int16_t status; 119941502Swpaul 120041502Swpaul sc = arg; 120167087Swpaul VR_LOCK(sc); 120241502Swpaul ifp = &sc->arpcom.ac_if; 120341502Swpaul 120441502Swpaul /* Supress unwanted interrupts. */ 120541502Swpaul if (!(ifp->if_flags & IFF_UP)) { 120641502Swpaul vr_stop(sc); 120767087Swpaul VR_UNLOCK(sc); 120841502Swpaul return; 120941502Swpaul } 121041502Swpaul 121141502Swpaul /* Disable interrupts. */ 121241502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 121341502Swpaul 121441502Swpaul for (;;) { 121541502Swpaul 121641502Swpaul status = CSR_READ_2(sc, VR_ISR); 121741502Swpaul if (status) 121841502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 121941502Swpaul 122041502Swpaul if ((status & VR_INTRS) == 0) 122141502Swpaul break; 122241502Swpaul 122341502Swpaul if (status & VR_ISR_RX_OK) 122441502Swpaul vr_rxeof(sc); 122541502Swpaul 122641502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 122741502Swpaul (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) || 122841502Swpaul (status & VR_ISR_RX_DROPPED)) { 122941502Swpaul vr_rxeof(sc); 123041502Swpaul vr_rxeoc(sc); 123141502Swpaul } 123241502Swpaul 1233101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1234101896Ssilby vr_reset(sc); 1235101896Ssilby vr_init(sc); 1236101896Ssilby break; 123741502Swpaul } 123841502Swpaul 1239101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1240101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 124141502Swpaul vr_txeof(sc); 1242101896Ssilby if ((status & VR_ISR_UDFI) || 1243101896Ssilby (status & VR_ISR_TX_ABRT2) || 1244101896Ssilby (status & VR_ISR_TX_ABRT)) { 1245101896Ssilby ifp->if_oerrors++; 1246101896Ssilby if (sc->vr_cdata.vr_tx_head != NULL) { 1247101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1248101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1249101896Ssilby } 1250101896Ssilby } else 1251101896Ssilby vr_txeoc(sc); 125241502Swpaul } 125341502Swpaul 125441502Swpaul } 125541502Swpaul 125641502Swpaul /* Re-enable interrupts. */ 125741502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 125841502Swpaul 125941502Swpaul if (ifp->if_snd.ifq_head != NULL) { 126041502Swpaul vr_start(ifp); 126141502Swpaul } 126241502Swpaul 126367087Swpaul VR_UNLOCK(sc); 126467087Swpaul 126541502Swpaul return; 126641502Swpaul} 126741502Swpaul 126841502Swpaul/* 126941502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 127041502Swpaul * pointers to the fragment pointers. 127141502Swpaul */ 1272102336Salfredstatic int 1273102336Salfredvr_encap(sc, c, m_head) 127441502Swpaul struct vr_softc *sc; 127541502Swpaul struct vr_chain *c; 127641502Swpaul struct mbuf *m_head; 127741502Swpaul{ 127841502Swpaul int frag = 0; 127941502Swpaul struct vr_desc *f = NULL; 128041502Swpaul int total_len; 128141502Swpaul struct mbuf *m; 128241502Swpaul 128341502Swpaul m = m_head; 128441502Swpaul total_len = 0; 128541502Swpaul 128641502Swpaul /* 128741502Swpaul * The VIA Rhine wants packet buffers to be longword 128841502Swpaul * aligned, but very often our mbufs aren't. Rather than 128941502Swpaul * waste time trying to decide when to copy and when not 129041502Swpaul * to copy, just do it all the time. 129141502Swpaul */ 129241502Swpaul if (m != NULL) { 129341502Swpaul struct mbuf *m_new = NULL; 129441502Swpaul 129541502Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 129641502Swpaul if (m_new == NULL) { 129771271Swpaul printf("vr%d: no memory for tx list\n", sc->vr_unit); 129841502Swpaul return(1); 129941502Swpaul } 130041502Swpaul if (m_head->m_pkthdr.len > MHLEN) { 130141502Swpaul MCLGET(m_new, M_DONTWAIT); 130241502Swpaul if (!(m_new->m_flags & M_EXT)) { 130341502Swpaul m_freem(m_new); 130471271Swpaul printf("vr%d: no memory for tx list\n", 130541502Swpaul sc->vr_unit); 130641502Swpaul return(1); 130741502Swpaul } 130841502Swpaul } 130941502Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 131041502Swpaul mtod(m_new, caddr_t)); 131141502Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 131241502Swpaul m_freem(m_head); 131341502Swpaul m_head = m_new; 131441502Swpaul /* 131541502Swpaul * The Rhine chip doesn't auto-pad, so we have to make 131641502Swpaul * sure to pad short frames out to the minimum frame length 131741502Swpaul * ourselves. 131841502Swpaul */ 131941502Swpaul if (m_head->m_len < VR_MIN_FRAMELEN) { 132041502Swpaul m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; 132141502Swpaul m_new->m_len = m_new->m_pkthdr.len; 132241502Swpaul } 132341502Swpaul f = c->vr_ptr; 132441502Swpaul f->vr_data = vtophys(mtod(m_new, caddr_t)); 132541502Swpaul f->vr_ctl = total_len = m_new->m_len; 132641502Swpaul f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 132741502Swpaul f->vr_status = 0; 132841502Swpaul frag = 1; 132941502Swpaul } 133041502Swpaul 133141502Swpaul c->vr_mbuf = m_head; 133242491Swpaul c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 133341502Swpaul c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 133441502Swpaul 133541502Swpaul return(0); 133641502Swpaul} 133741502Swpaul 133841502Swpaul/* 133941502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 134041502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 134141502Swpaul * copy of the pointers since the transmit list fragment pointers are 134241502Swpaul * physical addresses. 134341502Swpaul */ 134441502Swpaul 1345102336Salfredstatic void 1346102336Salfredvr_start(ifp) 134741502Swpaul struct ifnet *ifp; 134841502Swpaul{ 134941502Swpaul struct vr_softc *sc; 135041502Swpaul struct mbuf *m_head = NULL; 135141502Swpaul struct vr_chain *cur_tx = NULL, *start_tx; 135241502Swpaul 135341502Swpaul sc = ifp->if_softc; 135441502Swpaul 135567087Swpaul VR_LOCK(sc); 135667087Swpaul if (ifp->if_flags & IFF_OACTIVE) { 135767087Swpaul VR_UNLOCK(sc); 135841502Swpaul return; 135967087Swpaul } 136041502Swpaul 136141502Swpaul /* 136241502Swpaul * Check for an available queue slot. If there are none, 136341502Swpaul * punt. 136441502Swpaul */ 136541502Swpaul if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { 136641502Swpaul ifp->if_flags |= IFF_OACTIVE; 136741502Swpaul return; 136841502Swpaul } 136941502Swpaul 137041502Swpaul start_tx = sc->vr_cdata.vr_tx_free; 137141502Swpaul 137241502Swpaul while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { 137341502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 137441502Swpaul if (m_head == NULL) 137541502Swpaul break; 137641502Swpaul 137741502Swpaul /* Pick a descriptor off the free list. */ 137841502Swpaul cur_tx = sc->vr_cdata.vr_tx_free; 137941502Swpaul sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; 138041502Swpaul 138141502Swpaul /* Pack the data into the descriptor. */ 138271271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 138371271Swpaul IF_PREPEND(&ifp->if_snd, m_head); 138471275Swpaul ifp->if_flags |= IFF_OACTIVE; 138571271Swpaul cur_tx = NULL; 138671271Swpaul break; 138771271Swpaul } 138841502Swpaul 138941502Swpaul if (cur_tx != start_tx) 139041502Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 139141502Swpaul 139241502Swpaul /* 139341502Swpaul * If there's a BPF listener, bounce a copy of this frame 139441502Swpaul * to him. 139541502Swpaul */ 1396106936Ssam BPF_MTAP(ifp, cur_tx->vr_mbuf); 139751583Swpaul 139842491Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 139951432Swpaul VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); 140041502Swpaul } 140141502Swpaul 140241502Swpaul /* 140341526Swpaul * If there are no frames queued, bail. 140441526Swpaul */ 140567087Swpaul if (cur_tx == NULL) { 140667087Swpaul VR_UNLOCK(sc); 140741526Swpaul return; 140867087Swpaul } 140941526Swpaul 141041502Swpaul sc->vr_cdata.vr_tx_tail = cur_tx; 141141502Swpaul 141242491Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 141341502Swpaul sc->vr_cdata.vr_tx_head = start_tx; 141441502Swpaul 141541502Swpaul /* 141641502Swpaul * Set a timeout in case the chip goes out to lunch. 141741502Swpaul */ 141841502Swpaul ifp->if_timer = 5; 141967087Swpaul VR_UNLOCK(sc); 142041502Swpaul 142141502Swpaul return; 142241502Swpaul} 142341502Swpaul 1424102336Salfredstatic void 1425102336Salfredvr_init(xsc) 142641502Swpaul void *xsc; 142741502Swpaul{ 142841502Swpaul struct vr_softc *sc = xsc; 142941502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 143051432Swpaul struct mii_data *mii; 143173963Swpaul int i; 143241502Swpaul 143367087Swpaul VR_LOCK(sc); 143441502Swpaul 143551432Swpaul mii = device_get_softc(sc->vr_miibus); 143641502Swpaul 143741502Swpaul /* 143841502Swpaul * Cancel pending I/O and free all RX/TX buffers. 143941502Swpaul */ 144041502Swpaul vr_stop(sc); 144141502Swpaul vr_reset(sc); 144241502Swpaul 144373963Swpaul /* 144473963Swpaul * Set our station address. 144573963Swpaul */ 144673963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 144773963Swpaul CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]); 1448101375Ssilby 1449101375Ssilby /* Set DMA size */ 1450101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1451101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 145273963Swpaul 1453101375Ssilby /* 1454101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1455101108Ssilby * so we must set both. 1456101108Ssilby */ 1457101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1458101108Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESHSTORENFWD); 1459101108Ssilby 1460101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1461101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1462101108Ssilby 146341502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 146441502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD); 146541502Swpaul 146641502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 146741502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 146841502Swpaul 146941502Swpaul /* Init circular RX list. */ 147041502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 147141502Swpaul printf("vr%d: initialization failed: no " 147241502Swpaul "memory for rx buffers\n", sc->vr_unit); 147341502Swpaul vr_stop(sc); 147467087Swpaul VR_UNLOCK(sc); 147541502Swpaul return; 147641502Swpaul } 147741502Swpaul 147841502Swpaul /* 147941502Swpaul * Init tx descriptors. 148041502Swpaul */ 148141502Swpaul vr_list_tx_init(sc); 148241502Swpaul 148341502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 148441502Swpaul if (ifp->if_flags & IFF_PROMISC) 148541502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 148641502Swpaul else 148741502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 148841502Swpaul 148941502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 149041502Swpaul if (ifp->if_flags & IFF_BROADCAST) 149141502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 149241502Swpaul else 149341502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 149441502Swpaul 149541502Swpaul /* 149641502Swpaul * Program the multicast filter, if necessary. 149741502Swpaul */ 149841502Swpaul vr_setmulti(sc); 149941502Swpaul 150041502Swpaul /* 150141502Swpaul * Load the address of the RX list. 150241502Swpaul */ 150341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 150441502Swpaul 150541502Swpaul /* Enable receiver and transmitter. */ 150641502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 150741502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 150841502Swpaul VR_CMD_RX_GO); 150941502Swpaul 151041502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 151141502Swpaul 151241502Swpaul /* 151341502Swpaul * Enable interrupts. 151441502Swpaul */ 151541502Swpaul CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 151641502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 151741502Swpaul 151851432Swpaul mii_mediachg(mii); 151941502Swpaul 152041502Swpaul ifp->if_flags |= IFF_RUNNING; 152141502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 152241502Swpaul 152351432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 152451432Swpaul 152567087Swpaul VR_UNLOCK(sc); 152667087Swpaul 152741502Swpaul return; 152841502Swpaul} 152941502Swpaul 153041502Swpaul/* 153141502Swpaul * Set media options. 153241502Swpaul */ 1533102336Salfredstatic int 1534102336Salfredvr_ifmedia_upd(ifp) 153541502Swpaul struct ifnet *ifp; 153641502Swpaul{ 153741502Swpaul struct vr_softc *sc; 153841502Swpaul 153941502Swpaul sc = ifp->if_softc; 154041502Swpaul 154151432Swpaul if (ifp->if_flags & IFF_UP) 154251432Swpaul vr_init(sc); 154341502Swpaul 154441502Swpaul return(0); 154541502Swpaul} 154641502Swpaul 154741502Swpaul/* 154841502Swpaul * Report current media status. 154941502Swpaul */ 1550102336Salfredstatic void 1551102336Salfredvr_ifmedia_sts(ifp, ifmr) 155241502Swpaul struct ifnet *ifp; 155341502Swpaul struct ifmediareq *ifmr; 155441502Swpaul{ 155541502Swpaul struct vr_softc *sc; 155651432Swpaul struct mii_data *mii; 155741502Swpaul 155841502Swpaul sc = ifp->if_softc; 155951432Swpaul mii = device_get_softc(sc->vr_miibus); 156051432Swpaul mii_pollstat(mii); 156151432Swpaul ifmr->ifm_active = mii->mii_media_active; 156251432Swpaul ifmr->ifm_status = mii->mii_media_status; 156341502Swpaul 156441502Swpaul return; 156541502Swpaul} 156641502Swpaul 1567102336Salfredstatic int 1568102336Salfredvr_ioctl(ifp, command, data) 156941502Swpaul struct ifnet *ifp; 157041502Swpaul u_long command; 157141502Swpaul caddr_t data; 157241502Swpaul{ 157341502Swpaul struct vr_softc *sc = ifp->if_softc; 157441502Swpaul struct ifreq *ifr = (struct ifreq *) data; 157551432Swpaul struct mii_data *mii; 157667087Swpaul int error = 0; 157741502Swpaul 157867087Swpaul VR_LOCK(sc); 157941502Swpaul 158041502Swpaul switch(command) { 158141502Swpaul case SIOCSIFFLAGS: 158241502Swpaul if (ifp->if_flags & IFF_UP) { 158341502Swpaul vr_init(sc); 158441502Swpaul } else { 158541502Swpaul if (ifp->if_flags & IFF_RUNNING) 158641502Swpaul vr_stop(sc); 158741502Swpaul } 158841502Swpaul error = 0; 158941502Swpaul break; 159041502Swpaul case SIOCADDMULTI: 159141502Swpaul case SIOCDELMULTI: 159241502Swpaul vr_setmulti(sc); 159341502Swpaul error = 0; 159441502Swpaul break; 159541502Swpaul case SIOCGIFMEDIA: 159641502Swpaul case SIOCSIFMEDIA: 159751432Swpaul mii = device_get_softc(sc->vr_miibus); 159851432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 159941502Swpaul break; 160041502Swpaul default: 1601106936Ssam error = ether_ioctl(ifp, command, data); 160241502Swpaul break; 160341502Swpaul } 160441502Swpaul 160567087Swpaul VR_UNLOCK(sc); 160641502Swpaul 160741502Swpaul return(error); 160841502Swpaul} 160941502Swpaul 1610102336Salfredstatic void 1611102336Salfredvr_watchdog(ifp) 161241502Swpaul struct ifnet *ifp; 161341502Swpaul{ 161441502Swpaul struct vr_softc *sc; 161541502Swpaul 161641502Swpaul sc = ifp->if_softc; 161741502Swpaul 161867087Swpaul VR_LOCK(sc); 161941502Swpaul ifp->if_oerrors++; 162041502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 162141502Swpaul 162241502Swpaul vr_stop(sc); 162341502Swpaul vr_reset(sc); 162441502Swpaul vr_init(sc); 162541502Swpaul 162641502Swpaul if (ifp->if_snd.ifq_head != NULL) 162741502Swpaul vr_start(ifp); 162841502Swpaul 162967087Swpaul VR_UNLOCK(sc); 163067087Swpaul 163141502Swpaul return; 163241502Swpaul} 163341502Swpaul 163441502Swpaul/* 163541502Swpaul * Stop the adapter and free any mbufs allocated to the 163641502Swpaul * RX and TX lists. 163741502Swpaul */ 1638102336Salfredstatic void 1639102336Salfredvr_stop(sc) 164041502Swpaul struct vr_softc *sc; 164141502Swpaul{ 164241502Swpaul register int i; 164341502Swpaul struct ifnet *ifp; 164441502Swpaul 164567087Swpaul VR_LOCK(sc); 164667087Swpaul 164741502Swpaul ifp = &sc->arpcom.ac_if; 164841502Swpaul ifp->if_timer = 0; 164941502Swpaul 165051432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 165151432Swpaul 165241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 165341502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 165441502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 165541502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 165641502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 165741502Swpaul 165841502Swpaul /* 165941502Swpaul * Free data in the RX lists. 166041502Swpaul */ 166141502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 166241502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 166341502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 166441502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 166541502Swpaul } 166641502Swpaul } 166741502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 166841502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 166941502Swpaul 167041502Swpaul /* 167141502Swpaul * Free the TX list buffers. 167241502Swpaul */ 167341502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 167441502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 167541502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 167641502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 167741502Swpaul } 167841502Swpaul } 167941502Swpaul 168041502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 168141502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 168241502Swpaul 168341502Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 168467087Swpaul VR_UNLOCK(sc); 168541502Swpaul 168641502Swpaul return; 168741502Swpaul} 168841502Swpaul 168941502Swpaul/* 169041502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 169141502Swpaul * get confused by errant DMAs when rebooting. 169241502Swpaul */ 1693102336Salfredstatic void 1694102336Salfredvr_shutdown(dev) 169549610Swpaul device_t dev; 169641502Swpaul{ 169749610Swpaul struct vr_softc *sc; 169841502Swpaul 169949610Swpaul sc = device_get_softc(dev); 170049610Swpaul 170141502Swpaul vr_stop(sc); 170241502Swpaul 170341502Swpaul return; 170441502Swpaul} 1705