if_vr.c revision 101896
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 101896 2002-08-15 04:04:53Z silby $ 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 101896 2002-08-15 04:04:53Z silby $"; 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, \ 20441502Swpaul CSR_READ_1(sc, reg) | x) 20541502Swpaul 20641502Swpaul#define VR_CLRBIT(sc, reg, x) \ 20741502Swpaul CSR_WRITE_1(sc, reg, \ 20841502Swpaul CSR_READ_1(sc, reg) & ~x) 20941502Swpaul 21041502Swpaul#define VR_SETBIT16(sc, reg, x) \ 21141502Swpaul CSR_WRITE_2(sc, reg, \ 21241502Swpaul CSR_READ_2(sc, reg) | x) 21341502Swpaul 21441502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 21541502Swpaul CSR_WRITE_2(sc, reg, \ 21641502Swpaul CSR_READ_2(sc, reg) & ~x) 21741502Swpaul 21841502Swpaul#define VR_SETBIT32(sc, reg, x) \ 21941502Swpaul CSR_WRITE_4(sc, reg, \ 22041502Swpaul CSR_READ_4(sc, reg) | x) 22141502Swpaul 22241502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 22341502Swpaul CSR_WRITE_4(sc, reg, \ 22441502Swpaul CSR_READ_4(sc, reg) & ~x) 22541502Swpaul 22641502Swpaul#define SIO_SET(x) \ 22741502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 22841502Swpaul CSR_READ_1(sc, VR_MIICMD) | x) 22941502Swpaul 23041502Swpaul#define SIO_CLR(x) \ 23141502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 23241502Swpaul CSR_READ_1(sc, VR_MIICMD) & ~x) 23341502Swpaul 23441502Swpaul/* 23541502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 23641502Swpaul */ 23741502Swpaulstatic void vr_mii_sync(sc) 23841502Swpaul struct vr_softc *sc; 23941502Swpaul{ 24041502Swpaul register int i; 24141502Swpaul 24241502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 24341502Swpaul 24441502Swpaul for (i = 0; i < 32; i++) { 24541502Swpaul SIO_SET(VR_MIICMD_CLK); 24641502Swpaul DELAY(1); 24741502Swpaul SIO_CLR(VR_MIICMD_CLK); 24841502Swpaul DELAY(1); 24941502Swpaul } 25041502Swpaul 25141502Swpaul return; 25241502Swpaul} 25341502Swpaul 25441502Swpaul/* 25541502Swpaul * Clock a series of bits through the MII. 25641502Swpaul */ 25741502Swpaulstatic void vr_mii_send(sc, bits, cnt) 25841502Swpaul struct vr_softc *sc; 25941502Swpaul u_int32_t bits; 26041502Swpaul int cnt; 26141502Swpaul{ 26241502Swpaul int i; 26341502Swpaul 26441502Swpaul SIO_CLR(VR_MIICMD_CLK); 26541502Swpaul 26641502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 26741502Swpaul if (bits & i) { 26841502Swpaul SIO_SET(VR_MIICMD_DATAIN); 26941502Swpaul } else { 27041502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 27141502Swpaul } 27241502Swpaul DELAY(1); 27341502Swpaul SIO_CLR(VR_MIICMD_CLK); 27441502Swpaul DELAY(1); 27541502Swpaul SIO_SET(VR_MIICMD_CLK); 27641502Swpaul } 27741502Swpaul} 27841502Swpaul 27941502Swpaul/* 28041502Swpaul * Read an PHY register through the MII. 28141502Swpaul */ 28241502Swpaulstatic int vr_mii_readreg(sc, frame) 28341502Swpaul struct vr_softc *sc; 28441502Swpaul struct vr_mii_frame *frame; 28541502Swpaul 28641502Swpaul{ 28767087Swpaul int i, ack; 28841502Swpaul 28967087Swpaul VR_LOCK(sc); 29041502Swpaul 29141502Swpaul /* 29241502Swpaul * Set up frame for RX. 29341502Swpaul */ 29441502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 29541502Swpaul frame->mii_opcode = VR_MII_READOP; 29641502Swpaul frame->mii_turnaround = 0; 29741502Swpaul frame->mii_data = 0; 29841502Swpaul 29941502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 30041502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 30141502Swpaul 30241502Swpaul /* 30341502Swpaul * Turn on data xmit. 30441502Swpaul */ 30541502Swpaul SIO_SET(VR_MIICMD_DIR); 30641502Swpaul 30741502Swpaul vr_mii_sync(sc); 30841502Swpaul 30941502Swpaul /* 31041502Swpaul * Send command/address info. 31141502Swpaul */ 31241502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 31341502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 31441502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 31541502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 31641502Swpaul 31741502Swpaul /* Idle bit */ 31841502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 31941502Swpaul DELAY(1); 32041502Swpaul SIO_SET(VR_MIICMD_CLK); 32141502Swpaul DELAY(1); 32241502Swpaul 32341502Swpaul /* Turn off xmit. */ 32441502Swpaul SIO_CLR(VR_MIICMD_DIR); 32541502Swpaul 32641502Swpaul /* Check for ack */ 32741502Swpaul SIO_CLR(VR_MIICMD_CLK); 32841502Swpaul DELAY(1); 32941502Swpaul SIO_SET(VR_MIICMD_CLK); 33041502Swpaul DELAY(1); 33141502Swpaul ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 33241502Swpaul 33341502Swpaul /* 33441502Swpaul * Now try reading data bits. If the ack failed, we still 33541502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 33641502Swpaul */ 33741502Swpaul if (ack) { 33841502Swpaul for(i = 0; i < 16; i++) { 33941502Swpaul SIO_CLR(VR_MIICMD_CLK); 34041502Swpaul DELAY(1); 34141502Swpaul SIO_SET(VR_MIICMD_CLK); 34241502Swpaul DELAY(1); 34341502Swpaul } 34441502Swpaul goto fail; 34541502Swpaul } 34641502Swpaul 34741502Swpaul for (i = 0x8000; i; i >>= 1) { 34841502Swpaul SIO_CLR(VR_MIICMD_CLK); 34941502Swpaul DELAY(1); 35041502Swpaul if (!ack) { 35141502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 35241502Swpaul frame->mii_data |= i; 35341502Swpaul DELAY(1); 35441502Swpaul } 35541502Swpaul SIO_SET(VR_MIICMD_CLK); 35641502Swpaul DELAY(1); 35741502Swpaul } 35841502Swpaul 35941502Swpaulfail: 36041502Swpaul 36141502Swpaul SIO_CLR(VR_MIICMD_CLK); 36241502Swpaul DELAY(1); 36341502Swpaul SIO_SET(VR_MIICMD_CLK); 36441502Swpaul DELAY(1); 36541502Swpaul 36667087Swpaul VR_UNLOCK(sc); 36741502Swpaul 36841502Swpaul if (ack) 36941502Swpaul return(1); 37041502Swpaul return(0); 37141502Swpaul} 37241502Swpaul 37341502Swpaul/* 37441502Swpaul * Write to a PHY register through the MII. 37541502Swpaul */ 37641502Swpaulstatic int vr_mii_writereg(sc, frame) 37741502Swpaul struct vr_softc *sc; 37841502Swpaul struct vr_mii_frame *frame; 37941502Swpaul 38041502Swpaul{ 38167087Swpaul VR_LOCK(sc); 38241502Swpaul 38341502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 38441502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 38541502Swpaul 38641502Swpaul /* 38741502Swpaul * Set up frame for TX. 38841502Swpaul */ 38941502Swpaul 39041502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 39141502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 39241502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 39341502Swpaul 39441502Swpaul /* 39541502Swpaul * Turn on data output. 39641502Swpaul */ 39741502Swpaul SIO_SET(VR_MIICMD_DIR); 39841502Swpaul 39941502Swpaul vr_mii_sync(sc); 40041502Swpaul 40141502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 40241502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 40341502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 40441502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 40541502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 40641502Swpaul vr_mii_send(sc, frame->mii_data, 16); 40741502Swpaul 40841502Swpaul /* Idle bit. */ 40941502Swpaul SIO_SET(VR_MIICMD_CLK); 41041502Swpaul DELAY(1); 41141502Swpaul SIO_CLR(VR_MIICMD_CLK); 41241502Swpaul DELAY(1); 41341502Swpaul 41441502Swpaul /* 41541502Swpaul * Turn off xmit. 41641502Swpaul */ 41741502Swpaul SIO_CLR(VR_MIICMD_DIR); 41841502Swpaul 41967087Swpaul VR_UNLOCK(sc); 42041502Swpaul 42141502Swpaul return(0); 42241502Swpaul} 42341502Swpaul 42451432Swpaulstatic int vr_miibus_readreg(dev, phy, reg) 42551432Swpaul device_t dev; 42651432Swpaul int phy, reg; 42751432Swpaul{ 42841502Swpaul struct vr_softc *sc; 42941502Swpaul struct vr_mii_frame frame; 43041502Swpaul 43151432Swpaul sc = device_get_softc(dev); 43241502Swpaul bzero((char *)&frame, sizeof(frame)); 43341502Swpaul 43451432Swpaul frame.mii_phyaddr = phy; 43541502Swpaul frame.mii_regaddr = reg; 43641502Swpaul vr_mii_readreg(sc, &frame); 43741502Swpaul 43841502Swpaul return(frame.mii_data); 43941502Swpaul} 44041502Swpaul 44151432Swpaulstatic int vr_miibus_writereg(dev, phy, reg, data) 44251432Swpaul device_t dev; 44351432Swpaul u_int16_t phy, reg, data; 44451432Swpaul{ 44541502Swpaul struct vr_softc *sc; 44641502Swpaul struct vr_mii_frame frame; 44741502Swpaul 44851432Swpaul sc = device_get_softc(dev); 44941502Swpaul bzero((char *)&frame, sizeof(frame)); 45041502Swpaul 45151432Swpaul frame.mii_phyaddr = phy; 45241502Swpaul frame.mii_regaddr = reg; 45341502Swpaul frame.mii_data = data; 45441502Swpaul 45541502Swpaul vr_mii_writereg(sc, &frame); 45641502Swpaul 45751432Swpaul return(0); 45851432Swpaul} 45951432Swpaul 46051432Swpaulstatic void vr_miibus_statchg(dev) 46151432Swpaul device_t dev; 46251432Swpaul{ 46351432Swpaul struct vr_softc *sc; 46451432Swpaul struct mii_data *mii; 46551432Swpaul 46651432Swpaul sc = device_get_softc(dev); 46767087Swpaul VR_LOCK(sc); 46851432Swpaul mii = device_get_softc(sc->vr_miibus); 46951432Swpaul vr_setcfg(sc, mii->mii_media_active); 47067087Swpaul VR_UNLOCK(sc); 47151432Swpaul 47241502Swpaul return; 47341502Swpaul} 47441502Swpaul 47541502Swpaul/* 47641502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits. 47741502Swpaul */ 47841502Swpaulstatic u_int8_t vr_calchash(addr) 47941502Swpaul u_int8_t *addr; 48041502Swpaul{ 48141502Swpaul u_int32_t crc, carry; 48241502Swpaul int i, j; 48341502Swpaul u_int8_t c; 48441502Swpaul 48541502Swpaul /* Compute CRC for the address value. */ 48641502Swpaul crc = 0xFFFFFFFF; /* initial value */ 48741502Swpaul 48841502Swpaul for (i = 0; i < 6; i++) { 48941502Swpaul c = *(addr + i); 49041502Swpaul for (j = 0; j < 8; j++) { 49141502Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 49241502Swpaul crc <<= 1; 49341502Swpaul c >>= 1; 49441502Swpaul if (carry) 49541502Swpaul crc = (crc ^ 0x04c11db6) | carry; 49641502Swpaul } 49741502Swpaul } 49841502Swpaul 49941502Swpaul /* return the filter bit position */ 50041502Swpaul return((crc >> 26) & 0x0000003F); 50141502Swpaul} 50241502Swpaul 50341502Swpaul/* 50441502Swpaul * Program the 64-bit multicast hash filter. 50541502Swpaul */ 50641502Swpaulstatic void vr_setmulti(sc) 50741502Swpaul struct vr_softc *sc; 50841502Swpaul{ 50941502Swpaul struct ifnet *ifp; 51041502Swpaul int h = 0; 51141502Swpaul u_int32_t hashes[2] = { 0, 0 }; 51241502Swpaul struct ifmultiaddr *ifma; 51341502Swpaul u_int8_t rxfilt; 51441502Swpaul int mcnt = 0; 51541502Swpaul 51641502Swpaul ifp = &sc->arpcom.ac_if; 51741502Swpaul 51841502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 51941502Swpaul 52041502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 52141502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 52241502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 52341502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 52441502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 52541502Swpaul return; 52641502Swpaul } 52741502Swpaul 52841502Swpaul /* first, zot all the existing hash bits */ 52941502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 53041502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 53141502Swpaul 53241502Swpaul /* now program new ones */ 53372084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 53441502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 53541502Swpaul continue; 53641502Swpaul h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 53741502Swpaul if (h < 32) 53841502Swpaul hashes[0] |= (1 << h); 53941502Swpaul else 54041502Swpaul hashes[1] |= (1 << (h - 32)); 54141502Swpaul mcnt++; 54241502Swpaul } 54341502Swpaul 54441502Swpaul if (mcnt) 54541502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 54641502Swpaul else 54741502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 54841502Swpaul 54941502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 55041502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 55141502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 55241502Swpaul 55341502Swpaul return; 55441502Swpaul} 55541502Swpaul 55641502Swpaul/* 55741502Swpaul * In order to fiddle with the 55841502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 55941502Swpaul * first have to put the transmit and/or receive logic in the idle state. 56041502Swpaul */ 56151432Swpaulstatic void vr_setcfg(sc, media) 56241502Swpaul struct vr_softc *sc; 56351432Swpaul int media; 56441502Swpaul{ 56541502Swpaul int restart = 0; 56641502Swpaul 56741502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 56841502Swpaul restart = 1; 56941502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 57041502Swpaul } 57141502Swpaul 57251432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 57341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 57441502Swpaul else 57541502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 57641502Swpaul 57741502Swpaul if (restart) 57841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 57941502Swpaul 58041502Swpaul return; 58141502Swpaul} 58241502Swpaul 58341502Swpaulstatic void vr_reset(sc) 58441502Swpaul struct vr_softc *sc; 58541502Swpaul{ 58641502Swpaul register int i; 58741502Swpaul 58841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 58941502Swpaul 59041502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 59141502Swpaul DELAY(10); 59241502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 59341502Swpaul break; 59441502Swpaul } 59541502Swpaul if (i == VR_TIMEOUT) 59641502Swpaul printf("vr%d: reset never completed!\n", sc->vr_unit); 59741502Swpaul 59841502Swpaul /* Wait a little while for the chip to get its brains in order. */ 59941502Swpaul DELAY(1000); 60041502Swpaul 60141502Swpaul return; 60241502Swpaul} 60341502Swpaul 60441502Swpaul/* 60541502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 60641502Swpaul * IDs against our list and return a device name if we find a match. 60741502Swpaul */ 60849610Swpaulstatic int vr_probe(dev) 60949610Swpaul device_t dev; 61041502Swpaul{ 61141502Swpaul struct vr_type *t; 61241502Swpaul 61341502Swpaul t = vr_devs; 61441502Swpaul 61541502Swpaul while(t->vr_name != NULL) { 61649610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 61749610Swpaul (pci_get_device(dev) == t->vr_did)) { 61849610Swpaul device_set_desc(dev, t->vr_name); 61949610Swpaul return(0); 62041502Swpaul } 62141502Swpaul t++; 62241502Swpaul } 62341502Swpaul 62449610Swpaul return(ENXIO); 62541502Swpaul} 62641502Swpaul 62741502Swpaul/* 62841502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 62941502Swpaul * setup and ethernet/BPF attach. 63041502Swpaul */ 63149610Swpaulstatic int vr_attach(dev) 63249610Swpaul device_t dev; 63341502Swpaul{ 63467087Swpaul int i; 63541502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 63641502Swpaul u_int32_t command; 63741502Swpaul struct vr_softc *sc; 63841502Swpaul struct ifnet *ifp; 63949610Swpaul int unit, error = 0, rid; 64041502Swpaul 64149610Swpaul sc = device_get_softc(dev); 64249610Swpaul unit = device_get_unit(dev); 64349610Swpaul bzero(sc, sizeof(struct vr_softc *)); 64441502Swpaul 64593818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 64693818Sjhb MTX_DEF | MTX_RECURSE); 64769583Swpaul VR_LOCK(sc); 64869583Swpaul 64941502Swpaul /* 65041502Swpaul * Handle power management nonsense. 65141502Swpaul */ 65272813Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 65372813Swpaul u_int32_t iobase, membase, irq; 65441502Swpaul 65572813Swpaul /* Save important PCI config data. */ 65672813Swpaul iobase = pci_read_config(dev, VR_PCI_LOIO, 4); 65772813Swpaul membase = pci_read_config(dev, VR_PCI_LOMEM, 4); 65872813Swpaul irq = pci_read_config(dev, VR_PCI_INTLINE, 4); 65941502Swpaul 66072813Swpaul /* Reset the power state. */ 66172813Swpaul printf("vr%d: chip is in D%d power mode " 66272813Swpaul "-- setting to D0\n", unit, 66372813Swpaul pci_get_powerstate(dev)); 66472813Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 66541502Swpaul 66641502Swpaul /* Restore PCI config data. */ 66772813Swpaul pci_write_config(dev, VR_PCI_LOIO, iobase, 4); 66872813Swpaul pci_write_config(dev, VR_PCI_LOMEM, membase, 4); 66972813Swpaul pci_write_config(dev, VR_PCI_INTLINE, irq, 4); 67041502Swpaul } 67141502Swpaul 67241502Swpaul /* 67341502Swpaul * Map control/status registers. 67441502Swpaul */ 67572813Swpaul pci_enable_busmaster(dev); 67679472Swpaul pci_enable_io(dev, SYS_RES_IOPORT); 67779472Swpaul pci_enable_io(dev, SYS_RES_MEMORY); 67861041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 67941502Swpaul 68041502Swpaul#ifdef VR_USEIOSPACE 68141502Swpaul if (!(command & PCIM_CMD_PORTEN)) { 68241502Swpaul printf("vr%d: failed to enable I/O ports!\n", unit); 68341502Swpaul free(sc, M_DEVBUF); 68441502Swpaul goto fail; 68541502Swpaul } 68641502Swpaul#else 68741502Swpaul if (!(command & PCIM_CMD_MEMEN)) { 68841502Swpaul printf("vr%d: failed to enable memory mapping!\n", unit); 68941502Swpaul goto fail; 69041502Swpaul } 69149610Swpaul#endif 69241502Swpaul 69349610Swpaul rid = VR_RID; 69449610Swpaul sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid, 69549610Swpaul 0, ~0, 1, RF_ACTIVE); 69649610Swpaul 69749610Swpaul if (sc->vr_res == NULL) { 69849610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 69949610Swpaul error = ENXIO; 70041502Swpaul goto fail; 70141502Swpaul } 70241502Swpaul 70349610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 70449610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 70541502Swpaul 70641502Swpaul /* Allocate interrupt */ 70749610Swpaul rid = 0; 70849610Swpaul sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 70949610Swpaul RF_SHAREABLE | RF_ACTIVE); 71049610Swpaul 71149610Swpaul if (sc->vr_irq == NULL) { 71241502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 71349610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 71449610Swpaul error = ENXIO; 71541502Swpaul goto fail; 71641502Swpaul } 71741502Swpaul 71849610Swpaul error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET, 71949610Swpaul vr_intr, sc, &sc->vr_intrhand); 72049610Swpaul 72149610Swpaul if (error) { 72249610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 72349610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 72449610Swpaul printf("vr%d: couldn't set up irq\n", unit); 72549610Swpaul goto fail; 72649610Swpaul } 72749610Swpaul 72876586Swpaul /* 72976586Swpaul * Windows may put the chip in suspend mode when it 73076586Swpaul * shuts down. Be sure to kick it in the head to wake it 73176586Swpaul * up again. 73276586Swpaul */ 73376586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 73476586Swpaul 73541502Swpaul /* Reset the adapter. */ 73641502Swpaul vr_reset(sc); 73741502Swpaul 73841502Swpaul /* 73941502Swpaul * Get station address. The way the Rhine chips work, 74041502Swpaul * you're not allowed to directly access the EEPROM once 74141502Swpaul * they've been programmed a special way. Consequently, 74241502Swpaul * we need to read the node address from the PAR0 and PAR1 74341502Swpaul * registers. 74441502Swpaul */ 74541502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 74641502Swpaul DELAY(200); 74741502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 74841502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 74941502Swpaul 75041502Swpaul /* 75141502Swpaul * A Rhine chip was detected. Inform the world. 75241502Swpaul */ 75341502Swpaul printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); 75441502Swpaul 75541502Swpaul sc->vr_unit = unit; 75641502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 75741502Swpaul 75851432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 75951657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 76051432Swpaul 76151432Swpaul if (sc->vr_ldata == NULL) { 76241502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 76349610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 76449610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 76549610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 76649610Swpaul error = ENXIO; 76749610Swpaul goto fail; 76841502Swpaul } 76941502Swpaul 77041502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 77141502Swpaul 77241502Swpaul ifp = &sc->arpcom.ac_if; 77341502Swpaul ifp->if_softc = sc; 77441502Swpaul ifp->if_unit = unit; 77541502Swpaul ifp->if_name = "vr"; 77641502Swpaul ifp->if_mtu = ETHERMTU; 77741502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 77841502Swpaul ifp->if_ioctl = vr_ioctl; 77941502Swpaul ifp->if_output = ether_output; 78041502Swpaul ifp->if_start = vr_start; 78141502Swpaul ifp->if_watchdog = vr_watchdog; 78241502Swpaul ifp->if_init = vr_init; 78341502Swpaul ifp->if_baudrate = 10000000; 78443515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 78541502Swpaul 78651432Swpaul /* 78751432Swpaul * Do MII setup. 78851432Swpaul */ 78951432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 79051432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 79141502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 79249610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 79349610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 79449610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 79551432Swpaul contigfree(sc->vr_ldata, 79651432Swpaul sizeof(struct vr_list_data), M_DEVBUF); 79749610Swpaul error = ENXIO; 79841502Swpaul goto fail; 79941502Swpaul } 80041502Swpaul 80151432Swpaul callout_handle_init(&sc->vr_stat_ch); 80241502Swpaul 80341502Swpaul /* 80463090Sarchie * Call MI attach routine. 80541502Swpaul */ 80663090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 80767087Swpaul VR_UNLOCK(sc); 80867087Swpaul return(0); 80941502Swpaul 81041502Swpaulfail: 81167087Swpaul VR_UNLOCK(sc); 81267087Swpaul mtx_destroy(&sc->vr_mtx); 81367087Swpaul 81449610Swpaul return(error); 81541502Swpaul} 81641502Swpaul 81749610Swpaulstatic int vr_detach(dev) 81849610Swpaul device_t dev; 81949610Swpaul{ 82049610Swpaul struct vr_softc *sc; 82149610Swpaul struct ifnet *ifp; 82249610Swpaul 82349610Swpaul sc = device_get_softc(dev); 82467087Swpaul VR_LOCK(sc); 82549610Swpaul ifp = &sc->arpcom.ac_if; 82649610Swpaul 82749610Swpaul vr_stop(sc); 82863090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 82949610Swpaul 83051432Swpaul bus_generic_detach(dev); 83151432Swpaul device_delete_child(dev, sc->vr_miibus); 83251432Swpaul 83349610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 83449610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 83549610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 83649610Swpaul 83751432Swpaul contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 83849610Swpaul 83967087Swpaul VR_UNLOCK(sc); 84067087Swpaul mtx_destroy(&sc->vr_mtx); 84149610Swpaul 84249610Swpaul return(0); 84349610Swpaul} 84449610Swpaul 84541502Swpaul/* 84641502Swpaul * Initialize the transmit descriptors. 84741502Swpaul */ 84841502Swpaulstatic int vr_list_tx_init(sc) 84941502Swpaul struct vr_softc *sc; 85041502Swpaul{ 85141502Swpaul struct vr_chain_data *cd; 85241502Swpaul struct vr_list_data *ld; 85341502Swpaul int i; 85441502Swpaul 85541502Swpaul cd = &sc->vr_cdata; 85641502Swpaul ld = sc->vr_ldata; 85741502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 85841502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 85941502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 86041502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 86141502Swpaul &cd->vr_tx_chain[0]; 86241502Swpaul else 86341502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 86441502Swpaul &cd->vr_tx_chain[i + 1]; 86541502Swpaul } 86641502Swpaul 86741502Swpaul cd->vr_tx_free = &cd->vr_tx_chain[0]; 86841502Swpaul cd->vr_tx_tail = cd->vr_tx_head = NULL; 86941502Swpaul 87041502Swpaul return(0); 87141502Swpaul} 87241502Swpaul 87341502Swpaul 87441502Swpaul/* 87541502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 87641502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 87741502Swpaul * points back to the first. 87841502Swpaul */ 87941502Swpaulstatic int vr_list_rx_init(sc) 88041502Swpaul struct vr_softc *sc; 88141502Swpaul{ 88241502Swpaul struct vr_chain_data *cd; 88341502Swpaul struct vr_list_data *ld; 88441502Swpaul int i; 88541502Swpaul 88641502Swpaul cd = &sc->vr_cdata; 88741502Swpaul ld = sc->vr_ldata; 88841502Swpaul 88941502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 89041502Swpaul cd->vr_rx_chain[i].vr_ptr = 89141502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 89249610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 89341502Swpaul return(ENOBUFS); 89441502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 89541502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 89641502Swpaul &cd->vr_rx_chain[0]; 89741502Swpaul ld->vr_rx_list[i].vr_next = 89841502Swpaul vtophys(&ld->vr_rx_list[0]); 89941502Swpaul } else { 90041502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 90141502Swpaul &cd->vr_rx_chain[i + 1]; 90241502Swpaul ld->vr_rx_list[i].vr_next = 90341502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 90441502Swpaul } 90541502Swpaul } 90641502Swpaul 90741502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 90841502Swpaul 90941502Swpaul return(0); 91041502Swpaul} 91141502Swpaul 91241502Swpaul/* 91341502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 91441502Swpaul * Note: the length fields are only 11 bits wide, which means the 91541502Swpaul * largest size we can specify is 2047. This is important because 91641502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 91741502Swpaul * overflow the field and make a mess. 91841502Swpaul */ 91949610Swpaulstatic int vr_newbuf(sc, c, m) 92041502Swpaul struct vr_softc *sc; 92141502Swpaul struct vr_chain_onefrag *c; 92249610Swpaul struct mbuf *m; 92341502Swpaul{ 92441502Swpaul struct mbuf *m_new = NULL; 92541502Swpaul 92649610Swpaul if (m == NULL) { 92749610Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 92887846Sluigi if (m_new == NULL) 92949610Swpaul return(ENOBUFS); 93041502Swpaul 93149610Swpaul MCLGET(m_new, M_DONTWAIT); 93249610Swpaul if (!(m_new->m_flags & M_EXT)) { 93349610Swpaul m_freem(m_new); 93449610Swpaul return(ENOBUFS); 93549610Swpaul } 93649610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 93749610Swpaul } else { 93849610Swpaul m_new = m; 93949610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 94049610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 94141502Swpaul } 94241502Swpaul 94349610Swpaul m_adj(m_new, sizeof(u_int64_t)); 94449610Swpaul 94541502Swpaul c->vr_mbuf = m_new; 94641502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 94741502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 94842491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 94941502Swpaul 95041502Swpaul return(0); 95141502Swpaul} 95241502Swpaul 95341502Swpaul/* 95441502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 95541502Swpaul * the higher level protocols. 95641502Swpaul */ 95741502Swpaulstatic void vr_rxeof(sc) 95841502Swpaul struct vr_softc *sc; 95941502Swpaul{ 96041502Swpaul struct ether_header *eh; 96141502Swpaul struct mbuf *m; 96241502Swpaul struct ifnet *ifp; 96341502Swpaul struct vr_chain_onefrag *cur_rx; 96441502Swpaul int total_len = 0; 96541502Swpaul u_int32_t rxstat; 96641502Swpaul 96741502Swpaul ifp = &sc->arpcom.ac_if; 96841502Swpaul 96941502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 97041502Swpaul VR_RXSTAT_OWN)) { 97149610Swpaul struct mbuf *m0 = NULL; 97249610Swpaul 97341502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 97441502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 97549610Swpaul m = cur_rx->vr_mbuf; 97641502Swpaul 97741502Swpaul /* 97841502Swpaul * If an error occurs, update stats, clear the 97941502Swpaul * status word and leave the mbuf cluster in place: 98041502Swpaul * it should simply get re-used next time this descriptor 98141502Swpaul * comes up in the ring. 98241502Swpaul */ 98341502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 98441502Swpaul ifp->if_ierrors++; 98541502Swpaul printf("vr%d: rx error: ", sc->vr_unit); 98641502Swpaul switch(rxstat & 0x000000FF) { 98741502Swpaul case VR_RXSTAT_CRCERR: 98841502Swpaul printf("crc error\n"); 98941502Swpaul break; 99041502Swpaul case VR_RXSTAT_FRAMEALIGNERR: 99141502Swpaul printf("frame alignment error\n"); 99241502Swpaul break; 99341502Swpaul case VR_RXSTAT_FIFOOFLOW: 99441502Swpaul printf("FIFO overflow\n"); 99541502Swpaul break; 99641502Swpaul case VR_RXSTAT_GIANT: 99741502Swpaul printf("received giant packet\n"); 99841502Swpaul break; 99941502Swpaul case VR_RXSTAT_RUNT: 100041502Swpaul printf("received runt packet\n"); 100141502Swpaul break; 100241502Swpaul case VR_RXSTAT_BUSERR: 100341502Swpaul printf("system bus error\n"); 100441502Swpaul break; 100541502Swpaul case VR_RXSTAT_BUFFERR: 100641502Swpaul printf("rx buffer error\n"); 100741502Swpaul break; 100841502Swpaul default: 100941502Swpaul printf("unknown rx error\n"); 101041502Swpaul break; 101141502Swpaul } 101249610Swpaul vr_newbuf(sc, cur_rx, m); 101341502Swpaul continue; 101441502Swpaul } 101541502Swpaul 101641502Swpaul /* No errors; receive the packet. */ 101741502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 101841502Swpaul 101941502Swpaul /* 102042048Swpaul * XXX The VIA Rhine chip includes the CRC with every 102142048Swpaul * received frame, and there's no way to turn this 102242048Swpaul * behavior off (at least, I can't find anything in 102342048Swpaul * the manual that explains how to do it) so we have 102442048Swpaul * to trim off the CRC manually. 102542048Swpaul */ 102642048Swpaul total_len -= ETHER_CRC_LEN; 102742048Swpaul 102878508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 102978508Sbmilekic NULL); 103049610Swpaul vr_newbuf(sc, cur_rx, m); 103149610Swpaul if (m0 == NULL) { 103241502Swpaul ifp->if_ierrors++; 103341502Swpaul continue; 103441502Swpaul } 103549610Swpaul m = m0; 103641502Swpaul 103741502Swpaul ifp->if_ipackets++; 103841502Swpaul eh = mtod(m, struct ether_header *); 103949610Swpaul 104041502Swpaul /* Remove header from mbuf and pass it on. */ 104141502Swpaul m_adj(m, sizeof(struct ether_header)); 104241502Swpaul ether_input(ifp, eh, m); 104341502Swpaul } 104441502Swpaul 104541502Swpaul return; 104641502Swpaul} 104741502Swpaul 104841502Swpaulvoid vr_rxeoc(sc) 104941502Swpaul struct vr_softc *sc; 105041502Swpaul{ 105141502Swpaul 105241502Swpaul vr_rxeof(sc); 105341502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 105441502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 105541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 105641502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 105741502Swpaul 105841502Swpaul return; 105941502Swpaul} 106041502Swpaul 106141502Swpaul/* 106241502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 106341502Swpaul * the list buffers. 106441502Swpaul */ 106541502Swpaul 106641502Swpaulstatic void vr_txeof(sc) 106741502Swpaul struct vr_softc *sc; 106841502Swpaul{ 106941502Swpaul struct vr_chain *cur_tx; 107041502Swpaul struct ifnet *ifp; 107141502Swpaul 107241502Swpaul ifp = &sc->arpcom.ac_if; 107341502Swpaul 107496677Ssilby /* Reset the timeout timer; if_txeoc will clear it. */ 107596677Ssilby ifp->if_timer = 5; 107641502Swpaul 107741502Swpaul /* Sanity check. */ 107841502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 107941502Swpaul return; 108041502Swpaul 108141502Swpaul /* 108241502Swpaul * Go through our tx list and free mbufs for those 108341502Swpaul * frames that have been transmitted. 108441502Swpaul */ 108541502Swpaul while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { 108641502Swpaul u_int32_t txstat; 108741502Swpaul 108841502Swpaul cur_tx = sc->vr_cdata.vr_tx_head; 108941502Swpaul txstat = cur_tx->vr_ptr->vr_status; 109041502Swpaul 1091101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1092101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1093101896Ssilby while (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON) 1094101896Ssilby ; /* Wait for chip to shutdown */ 1095101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1096101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1097101896Ssilby break; 1098101896Ssilby } 1099101896Ssilby 110042491Swpaul if (txstat & VR_TXSTAT_OWN) 110141502Swpaul break; 110241502Swpaul 110341502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 110441502Swpaul ifp->if_oerrors++; 110541502Swpaul if (txstat & VR_TXSTAT_DEFER) 110641502Swpaul ifp->if_collisions++; 110741502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 110841502Swpaul ifp->if_collisions++; 110941502Swpaul } 111041502Swpaul 111141502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 111241502Swpaul 111341502Swpaul ifp->if_opackets++; 111451432Swpaul if (cur_tx->vr_mbuf != NULL) { 111551432Swpaul m_freem(cur_tx->vr_mbuf); 111651432Swpaul cur_tx->vr_mbuf = NULL; 111751432Swpaul } 111841502Swpaul 111941502Swpaul if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { 112041502Swpaul sc->vr_cdata.vr_tx_head = NULL; 112141502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 112241502Swpaul break; 112341502Swpaul } 112441502Swpaul 112541502Swpaul sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; 112641502Swpaul } 112741502Swpaul 112841502Swpaul return; 112941502Swpaul} 113041502Swpaul 113141502Swpaul/* 113241502Swpaul * TX 'end of channel' interrupt handler. 113341502Swpaul */ 113441502Swpaulstatic void vr_txeoc(sc) 113541502Swpaul struct vr_softc *sc; 113641502Swpaul{ 113741502Swpaul struct ifnet *ifp; 113841502Swpaul 113941502Swpaul ifp = &sc->arpcom.ac_if; 114041502Swpaul 114141502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) { 114241502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 114341502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 114496677Ssilby ifp->if_timer = 0; 114541502Swpaul } 114641502Swpaul 114741502Swpaul return; 114841502Swpaul} 114941502Swpaul 115051432Swpaulstatic void vr_tick(xsc) 115151432Swpaul void *xsc; 115251432Swpaul{ 115351432Swpaul struct vr_softc *sc; 115451432Swpaul struct mii_data *mii; 115551432Swpaul 115651432Swpaul sc = xsc; 115767087Swpaul VR_LOCK(sc); 115851432Swpaul mii = device_get_softc(sc->vr_miibus); 115951432Swpaul mii_tick(mii); 116051432Swpaul 116151432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 116251432Swpaul 116367087Swpaul VR_UNLOCK(sc); 116451432Swpaul 116551432Swpaul return; 116651432Swpaul} 116751432Swpaul 116841502Swpaulstatic void vr_intr(arg) 116941502Swpaul void *arg; 117041502Swpaul{ 117141502Swpaul struct vr_softc *sc; 117241502Swpaul struct ifnet *ifp; 117341502Swpaul u_int16_t status; 117441502Swpaul 117541502Swpaul sc = arg; 117667087Swpaul VR_LOCK(sc); 117741502Swpaul ifp = &sc->arpcom.ac_if; 117841502Swpaul 117941502Swpaul /* Supress unwanted interrupts. */ 118041502Swpaul if (!(ifp->if_flags & IFF_UP)) { 118141502Swpaul vr_stop(sc); 118267087Swpaul VR_UNLOCK(sc); 118341502Swpaul return; 118441502Swpaul } 118541502Swpaul 118641502Swpaul /* Disable interrupts. */ 118741502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 118841502Swpaul 118941502Swpaul for (;;) { 119041502Swpaul 119141502Swpaul status = CSR_READ_2(sc, VR_ISR); 119241502Swpaul if (status) 119341502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 119441502Swpaul 119541502Swpaul if ((status & VR_INTRS) == 0) 119641502Swpaul break; 119741502Swpaul 119841502Swpaul if (status & VR_ISR_RX_OK) 119941502Swpaul vr_rxeof(sc); 120041502Swpaul 120141502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 120241502Swpaul (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) || 120341502Swpaul (status & VR_ISR_RX_DROPPED)) { 120441502Swpaul vr_rxeof(sc); 120541502Swpaul vr_rxeoc(sc); 120641502Swpaul } 120741502Swpaul 1208101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1209101896Ssilby vr_reset(sc); 1210101896Ssilby vr_init(sc); 1211101896Ssilby break; 121241502Swpaul } 121341502Swpaul 1214101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1215101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 121641502Swpaul vr_txeof(sc); 1217101896Ssilby if ((status & VR_ISR_UDFI) || 1218101896Ssilby (status & VR_ISR_TX_ABRT2) || 1219101896Ssilby (status & VR_ISR_TX_ABRT)) { 1220101896Ssilby ifp->if_oerrors++; 1221101896Ssilby if (sc->vr_cdata.vr_tx_head != NULL) { 1222101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1223101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1224101896Ssilby } 1225101896Ssilby } else 1226101896Ssilby vr_txeoc(sc); 122741502Swpaul } 122841502Swpaul 122941502Swpaul } 123041502Swpaul 123141502Swpaul /* Re-enable interrupts. */ 123241502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 123341502Swpaul 123441502Swpaul if (ifp->if_snd.ifq_head != NULL) { 123541502Swpaul vr_start(ifp); 123641502Swpaul } 123741502Swpaul 123867087Swpaul VR_UNLOCK(sc); 123967087Swpaul 124041502Swpaul return; 124141502Swpaul} 124241502Swpaul 124341502Swpaul/* 124441502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 124541502Swpaul * pointers to the fragment pointers. 124641502Swpaul */ 124741502Swpaulstatic int vr_encap(sc, c, m_head) 124841502Swpaul struct vr_softc *sc; 124941502Swpaul struct vr_chain *c; 125041502Swpaul struct mbuf *m_head; 125141502Swpaul{ 125241502Swpaul int frag = 0; 125341502Swpaul struct vr_desc *f = NULL; 125441502Swpaul int total_len; 125541502Swpaul struct mbuf *m; 125641502Swpaul 125741502Swpaul m = m_head; 125841502Swpaul total_len = 0; 125941502Swpaul 126041502Swpaul /* 126141502Swpaul * The VIA Rhine wants packet buffers to be longword 126241502Swpaul * aligned, but very often our mbufs aren't. Rather than 126341502Swpaul * waste time trying to decide when to copy and when not 126441502Swpaul * to copy, just do it all the time. 126541502Swpaul */ 126641502Swpaul if (m != NULL) { 126741502Swpaul struct mbuf *m_new = NULL; 126841502Swpaul 126941502Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 127041502Swpaul if (m_new == NULL) { 127171271Swpaul printf("vr%d: no memory for tx list\n", sc->vr_unit); 127241502Swpaul return(1); 127341502Swpaul } 127441502Swpaul if (m_head->m_pkthdr.len > MHLEN) { 127541502Swpaul MCLGET(m_new, M_DONTWAIT); 127641502Swpaul if (!(m_new->m_flags & M_EXT)) { 127741502Swpaul m_freem(m_new); 127871271Swpaul printf("vr%d: no memory for tx list\n", 127941502Swpaul sc->vr_unit); 128041502Swpaul return(1); 128141502Swpaul } 128241502Swpaul } 128341502Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 128441502Swpaul mtod(m_new, caddr_t)); 128541502Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 128641502Swpaul m_freem(m_head); 128741502Swpaul m_head = m_new; 128841502Swpaul /* 128941502Swpaul * The Rhine chip doesn't auto-pad, so we have to make 129041502Swpaul * sure to pad short frames out to the minimum frame length 129141502Swpaul * ourselves. 129241502Swpaul */ 129341502Swpaul if (m_head->m_len < VR_MIN_FRAMELEN) { 129441502Swpaul m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; 129541502Swpaul m_new->m_len = m_new->m_pkthdr.len; 129641502Swpaul } 129741502Swpaul f = c->vr_ptr; 129841502Swpaul f->vr_data = vtophys(mtod(m_new, caddr_t)); 129941502Swpaul f->vr_ctl = total_len = m_new->m_len; 130041502Swpaul f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 130141502Swpaul f->vr_status = 0; 130241502Swpaul frag = 1; 130341502Swpaul } 130441502Swpaul 130541502Swpaul c->vr_mbuf = m_head; 130642491Swpaul c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 130741502Swpaul c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 130841502Swpaul 130941502Swpaul return(0); 131041502Swpaul} 131141502Swpaul 131241502Swpaul/* 131341502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 131441502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 131541502Swpaul * copy of the pointers since the transmit list fragment pointers are 131641502Swpaul * physical addresses. 131741502Swpaul */ 131841502Swpaul 131941502Swpaulstatic void vr_start(ifp) 132041502Swpaul struct ifnet *ifp; 132141502Swpaul{ 132241502Swpaul struct vr_softc *sc; 132341502Swpaul struct mbuf *m_head = NULL; 132441502Swpaul struct vr_chain *cur_tx = NULL, *start_tx; 132541502Swpaul 132641502Swpaul sc = ifp->if_softc; 132741502Swpaul 132867087Swpaul VR_LOCK(sc); 132967087Swpaul if (ifp->if_flags & IFF_OACTIVE) { 133067087Swpaul VR_UNLOCK(sc); 133141502Swpaul return; 133267087Swpaul } 133341502Swpaul 133441502Swpaul /* 133541502Swpaul * Check for an available queue slot. If there are none, 133641502Swpaul * punt. 133741502Swpaul */ 133841502Swpaul if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { 133941502Swpaul ifp->if_flags |= IFF_OACTIVE; 134041502Swpaul return; 134141502Swpaul } 134241502Swpaul 134341502Swpaul start_tx = sc->vr_cdata.vr_tx_free; 134441502Swpaul 134541502Swpaul while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { 134641502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 134741502Swpaul if (m_head == NULL) 134841502Swpaul break; 134941502Swpaul 135041502Swpaul /* Pick a descriptor off the free list. */ 135141502Swpaul cur_tx = sc->vr_cdata.vr_tx_free; 135241502Swpaul sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; 135341502Swpaul 135441502Swpaul /* Pack the data into the descriptor. */ 135571271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 135671271Swpaul IF_PREPEND(&ifp->if_snd, m_head); 135771275Swpaul ifp->if_flags |= IFF_OACTIVE; 135871271Swpaul cur_tx = NULL; 135971271Swpaul break; 136071271Swpaul } 136141502Swpaul 136241502Swpaul if (cur_tx != start_tx) 136341502Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 136441502Swpaul 136541502Swpaul /* 136641502Swpaul * If there's a BPF listener, bounce a copy of this frame 136741502Swpaul * to him. 136841502Swpaul */ 136941502Swpaul if (ifp->if_bpf) 137041502Swpaul bpf_mtap(ifp, cur_tx->vr_mbuf); 137151583Swpaul 137242491Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 137351432Swpaul VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); 137441502Swpaul } 137541502Swpaul 137641502Swpaul /* 137741526Swpaul * If there are no frames queued, bail. 137841526Swpaul */ 137967087Swpaul if (cur_tx == NULL) { 138067087Swpaul VR_UNLOCK(sc); 138141526Swpaul return; 138267087Swpaul } 138341526Swpaul 138441502Swpaul sc->vr_cdata.vr_tx_tail = cur_tx; 138541502Swpaul 138642491Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 138741502Swpaul sc->vr_cdata.vr_tx_head = start_tx; 138841502Swpaul 138941502Swpaul /* 139041502Swpaul * Set a timeout in case the chip goes out to lunch. 139141502Swpaul */ 139241502Swpaul ifp->if_timer = 5; 139367087Swpaul VR_UNLOCK(sc); 139441502Swpaul 139541502Swpaul return; 139641502Swpaul} 139741502Swpaul 139841502Swpaulstatic void vr_init(xsc) 139941502Swpaul void *xsc; 140041502Swpaul{ 140141502Swpaul struct vr_softc *sc = xsc; 140241502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 140351432Swpaul struct mii_data *mii; 140473963Swpaul int i; 140541502Swpaul 140667087Swpaul VR_LOCK(sc); 140741502Swpaul 140851432Swpaul mii = device_get_softc(sc->vr_miibus); 140941502Swpaul 141041502Swpaul /* 141141502Swpaul * Cancel pending I/O and free all RX/TX buffers. 141241502Swpaul */ 141341502Swpaul vr_stop(sc); 141441502Swpaul vr_reset(sc); 141541502Swpaul 141673963Swpaul /* 141773963Swpaul * Set our station address. 141873963Swpaul */ 141973963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 142073963Swpaul CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]); 1421101375Ssilby 1422101375Ssilby /* Set DMA size */ 1423101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1424101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 142573963Swpaul 1426101375Ssilby /* 1427101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1428101108Ssilby * so we must set both. 1429101108Ssilby */ 1430101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1431101108Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESHSTORENFWD); 1432101108Ssilby 1433101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1434101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1435101108Ssilby 143641502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 143741502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD); 143841502Swpaul 143941502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 144041502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 144141502Swpaul 144241502Swpaul /* Init circular RX list. */ 144341502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 144441502Swpaul printf("vr%d: initialization failed: no " 144541502Swpaul "memory for rx buffers\n", sc->vr_unit); 144641502Swpaul vr_stop(sc); 144767087Swpaul VR_UNLOCK(sc); 144841502Swpaul return; 144941502Swpaul } 145041502Swpaul 145141502Swpaul /* 145241502Swpaul * Init tx descriptors. 145341502Swpaul */ 145441502Swpaul vr_list_tx_init(sc); 145541502Swpaul 145641502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 145741502Swpaul if (ifp->if_flags & IFF_PROMISC) 145841502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 145941502Swpaul else 146041502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 146141502Swpaul 146241502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 146341502Swpaul if (ifp->if_flags & IFF_BROADCAST) 146441502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 146541502Swpaul else 146641502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 146741502Swpaul 146841502Swpaul /* 146941502Swpaul * Program the multicast filter, if necessary. 147041502Swpaul */ 147141502Swpaul vr_setmulti(sc); 147241502Swpaul 147341502Swpaul /* 147441502Swpaul * Load the address of the RX list. 147541502Swpaul */ 147641502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 147741502Swpaul 147841502Swpaul /* Enable receiver and transmitter. */ 147941502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 148041502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 148141502Swpaul VR_CMD_RX_GO); 148241502Swpaul 148341502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 148441502Swpaul 148541502Swpaul /* 148641502Swpaul * Enable interrupts. 148741502Swpaul */ 148841502Swpaul CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 148941502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 149041502Swpaul 149151432Swpaul mii_mediachg(mii); 149241502Swpaul 149341502Swpaul ifp->if_flags |= IFF_RUNNING; 149441502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 149541502Swpaul 149651432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 149751432Swpaul 149867087Swpaul VR_UNLOCK(sc); 149967087Swpaul 150041502Swpaul return; 150141502Swpaul} 150241502Swpaul 150341502Swpaul/* 150441502Swpaul * Set media options. 150541502Swpaul */ 150641502Swpaulstatic int vr_ifmedia_upd(ifp) 150741502Swpaul struct ifnet *ifp; 150841502Swpaul{ 150941502Swpaul struct vr_softc *sc; 151041502Swpaul 151141502Swpaul sc = ifp->if_softc; 151241502Swpaul 151351432Swpaul if (ifp->if_flags & IFF_UP) 151451432Swpaul vr_init(sc); 151541502Swpaul 151641502Swpaul return(0); 151741502Swpaul} 151841502Swpaul 151941502Swpaul/* 152041502Swpaul * Report current media status. 152141502Swpaul */ 152241502Swpaulstatic void vr_ifmedia_sts(ifp, ifmr) 152341502Swpaul struct ifnet *ifp; 152441502Swpaul struct ifmediareq *ifmr; 152541502Swpaul{ 152641502Swpaul struct vr_softc *sc; 152751432Swpaul struct mii_data *mii; 152841502Swpaul 152941502Swpaul sc = ifp->if_softc; 153051432Swpaul mii = device_get_softc(sc->vr_miibus); 153151432Swpaul mii_pollstat(mii); 153251432Swpaul ifmr->ifm_active = mii->mii_media_active; 153351432Swpaul ifmr->ifm_status = mii->mii_media_status; 153441502Swpaul 153541502Swpaul return; 153641502Swpaul} 153741502Swpaul 153841502Swpaulstatic int vr_ioctl(ifp, command, data) 153941502Swpaul struct ifnet *ifp; 154041502Swpaul u_long command; 154141502Swpaul caddr_t data; 154241502Swpaul{ 154341502Swpaul struct vr_softc *sc = ifp->if_softc; 154441502Swpaul struct ifreq *ifr = (struct ifreq *) data; 154551432Swpaul struct mii_data *mii; 154667087Swpaul int error = 0; 154741502Swpaul 154867087Swpaul VR_LOCK(sc); 154941502Swpaul 155041502Swpaul switch(command) { 155141502Swpaul case SIOCSIFADDR: 155241502Swpaul case SIOCGIFADDR: 155341502Swpaul case SIOCSIFMTU: 155441502Swpaul error = ether_ioctl(ifp, command, data); 155541502Swpaul break; 155641502Swpaul case SIOCSIFFLAGS: 155741502Swpaul if (ifp->if_flags & IFF_UP) { 155841502Swpaul vr_init(sc); 155941502Swpaul } else { 156041502Swpaul if (ifp->if_flags & IFF_RUNNING) 156141502Swpaul vr_stop(sc); 156241502Swpaul } 156341502Swpaul error = 0; 156441502Swpaul break; 156541502Swpaul case SIOCADDMULTI: 156641502Swpaul case SIOCDELMULTI: 156741502Swpaul vr_setmulti(sc); 156841502Swpaul error = 0; 156941502Swpaul break; 157041502Swpaul case SIOCGIFMEDIA: 157141502Swpaul case SIOCSIFMEDIA: 157251432Swpaul mii = device_get_softc(sc->vr_miibus); 157351432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 157441502Swpaul break; 157541502Swpaul default: 157641502Swpaul error = EINVAL; 157741502Swpaul break; 157841502Swpaul } 157941502Swpaul 158067087Swpaul VR_UNLOCK(sc); 158141502Swpaul 158241502Swpaul return(error); 158341502Swpaul} 158441502Swpaul 158541502Swpaulstatic void vr_watchdog(ifp) 158641502Swpaul struct ifnet *ifp; 158741502Swpaul{ 158841502Swpaul struct vr_softc *sc; 158941502Swpaul 159041502Swpaul sc = ifp->if_softc; 159141502Swpaul 159267087Swpaul VR_LOCK(sc); 159341502Swpaul ifp->if_oerrors++; 159441502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 159541502Swpaul 159641502Swpaul vr_stop(sc); 159741502Swpaul vr_reset(sc); 159841502Swpaul vr_init(sc); 159941502Swpaul 160041502Swpaul if (ifp->if_snd.ifq_head != NULL) 160141502Swpaul vr_start(ifp); 160241502Swpaul 160367087Swpaul VR_UNLOCK(sc); 160467087Swpaul 160541502Swpaul return; 160641502Swpaul} 160741502Swpaul 160841502Swpaul/* 160941502Swpaul * Stop the adapter and free any mbufs allocated to the 161041502Swpaul * RX and TX lists. 161141502Swpaul */ 161241502Swpaulstatic void vr_stop(sc) 161341502Swpaul struct vr_softc *sc; 161441502Swpaul{ 161541502Swpaul register int i; 161641502Swpaul struct ifnet *ifp; 161741502Swpaul 161867087Swpaul VR_LOCK(sc); 161967087Swpaul 162041502Swpaul ifp = &sc->arpcom.ac_if; 162141502Swpaul ifp->if_timer = 0; 162241502Swpaul 162351432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 162451432Swpaul 162541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 162641502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 162741502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 162841502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 162941502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 163041502Swpaul 163141502Swpaul /* 163241502Swpaul * Free data in the RX lists. 163341502Swpaul */ 163441502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 163541502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 163641502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 163741502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 163841502Swpaul } 163941502Swpaul } 164041502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 164141502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 164241502Swpaul 164341502Swpaul /* 164441502Swpaul * Free the TX list buffers. 164541502Swpaul */ 164641502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 164741502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 164841502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 164941502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 165041502Swpaul } 165141502Swpaul } 165241502Swpaul 165341502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 165441502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 165541502Swpaul 165641502Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 165767087Swpaul VR_UNLOCK(sc); 165841502Swpaul 165941502Swpaul return; 166041502Swpaul} 166141502Swpaul 166241502Swpaul/* 166341502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 166441502Swpaul * get confused by errant DMAs when rebooting. 166541502Swpaul */ 166649610Swpaulstatic void vr_shutdown(dev) 166749610Swpaul device_t dev; 166841502Swpaul{ 166949610Swpaul struct vr_softc *sc; 167041502Swpaul 167149610Swpaul sc = device_get_softc(dev); 167249610Swpaul 167341502Swpaul vr_stop(sc); 167441502Swpaul 167541502Swpaul return; 167641502Swpaul} 1677