if_vr.c revision 121816
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 */ 3241502Swpaul 3341502Swpaul/* 3441502Swpaul * VIA Rhine fast ethernet PCI NIC driver 3541502Swpaul * 3641502Swpaul * Supports various network adapters based on the VIA Rhine 3741502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX. 3841502Swpaul * Datasheets are available at http://www.via.com.tw. 3941502Swpaul * 4041502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4141502Swpaul * Electrical Engineering Department 4241502Swpaul * Columbia University, New York City 4341502Swpaul */ 4441502Swpaul 4541502Swpaul/* 4641502Swpaul * The VIA Rhine controllers are similar in some respects to the 4741502Swpaul * the DEC tulip chips, except less complicated. The controller 4841502Swpaul * uses an MII bus and an external physical layer interface. The 4941502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table 5041502Swpaul * multicast filter. Transmit and receive descriptors are similar 5141502Swpaul * to the tulip. 5241502Swpaul * 5341502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism: 5441502Swpaul * transmit buffers must be longword aligned. Unfortunately, 5541502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting 5641502Swpaul * at longword boundaries, so we have to do a buffer copy before 5741502Swpaul * transmission. 5841502Swpaul */ 5941502Swpaul 60113038Sobrien#include <sys/cdefs.h> 61113038Sobrien__FBSDID("$FreeBSD: head/sys/dev/vr/if_vr.c 121816 2003-10-31 18:32:15Z brooks $"); 62113038Sobrien 6341502Swpaul#include <sys/param.h> 6441502Swpaul#include <sys/systm.h> 6541502Swpaul#include <sys/sockio.h> 6641502Swpaul#include <sys/mbuf.h> 6741502Swpaul#include <sys/malloc.h> 6841502Swpaul#include <sys/kernel.h> 6941502Swpaul#include <sys/socket.h> 7041502Swpaul 7141502Swpaul#include <net/if.h> 7241502Swpaul#include <net/if_arp.h> 7341502Swpaul#include <net/ethernet.h> 7441502Swpaul#include <net/if_dl.h> 7541502Swpaul#include <net/if_media.h> 7641502Swpaul 7741502Swpaul#include <net/bpf.h> 7841502Swpaul 7941502Swpaul#include <vm/vm.h> /* for vtophys */ 8041502Swpaul#include <vm/pmap.h> /* for vtophys */ 8141502Swpaul#include <machine/bus_pio.h> 8241502Swpaul#include <machine/bus_memio.h> 8341502Swpaul#include <machine/bus.h> 8449610Swpaul#include <machine/resource.h> 8549610Swpaul#include <sys/bus.h> 8649610Swpaul#include <sys/rman.h> 8741502Swpaul 8851432Swpaul#include <dev/mii/mii.h> 8951432Swpaul#include <dev/mii/miivar.h> 9051432Swpaul 91119288Simp#include <dev/pci/pcireg.h> 92119288Simp#include <dev/pci/pcivar.h> 9341502Swpaul 9441502Swpaul#define VR_USEIOSPACE 9541502Swpaul 9641502Swpaul#include <pci/if_vrreg.h> 9741502Swpaul 98113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1); 99113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1); 10059758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 10159758Speter 10251432Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 10351432Swpaul#include "miibus_if.h" 10451432Swpaul 105110168Ssilby#undef VR_USESWSHIFT 106110168Ssilby 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" }, 117110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III, 118110170Ssilby "VIA VT6105 Rhine III 10/100BaseTX" }, 119110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, 120110170Ssilby "VIA VT6105M Rhine III 10/100BaseTX" }, 12144238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 12244238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 12344238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 12444238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 12541502Swpaul { 0, 0, NULL } 12641502Swpaul}; 12741502Swpaul 12892739Salfredstatic int vr_probe (device_t); 12992739Salfredstatic int vr_attach (device_t); 13092739Salfredstatic int vr_detach (device_t); 13141502Swpaul 13292739Salfredstatic int vr_newbuf (struct vr_softc *, 13349610Swpaul struct vr_chain_onefrag *, 13492739Salfred struct mbuf *); 13592739Salfredstatic int vr_encap (struct vr_softc *, struct vr_chain *, 13692739Salfred struct mbuf * ); 13741502Swpaul 13892739Salfredstatic void vr_rxeof (struct vr_softc *); 13992739Salfredstatic void vr_rxeoc (struct vr_softc *); 14092739Salfredstatic void vr_txeof (struct vr_softc *); 14192739Salfredstatic void vr_txeoc (struct vr_softc *); 14292739Salfredstatic void vr_tick (void *); 14392739Salfredstatic void vr_intr (void *); 14492739Salfredstatic void vr_start (struct ifnet *); 14592739Salfredstatic int vr_ioctl (struct ifnet *, u_long, caddr_t); 14692739Salfredstatic void vr_init (void *); 14792739Salfredstatic void vr_stop (struct vr_softc *); 14892739Salfredstatic void vr_watchdog (struct ifnet *); 14992739Salfredstatic void vr_shutdown (device_t); 15092739Salfredstatic int vr_ifmedia_upd (struct ifnet *); 15192739Salfredstatic void vr_ifmedia_sts (struct ifnet *, struct ifmediareq *); 15241502Swpaul 153110168Ssilby#ifdef VR_USESWSHIFT 15492739Salfredstatic void vr_mii_sync (struct vr_softc *); 15592739Salfredstatic void vr_mii_send (struct vr_softc *, u_int32_t, int); 156110168Ssilby#endif 15792739Salfredstatic int vr_mii_readreg (struct vr_softc *, struct vr_mii_frame *); 15892739Salfredstatic int vr_mii_writereg (struct vr_softc *, struct vr_mii_frame *); 15992739Salfredstatic int vr_miibus_readreg (device_t, int, int); 16092739Salfredstatic int vr_miibus_writereg (device_t, int, int, int); 16192739Salfredstatic void vr_miibus_statchg (device_t); 16241502Swpaul 16392739Salfredstatic void vr_setcfg (struct vr_softc *, int); 16492739Salfredstatic u_int8_t vr_calchash (u_int8_t *); 16592739Salfredstatic void vr_setmulti (struct vr_softc *); 16692739Salfredstatic void vr_reset (struct vr_softc *); 16792739Salfredstatic int vr_list_rx_init (struct vr_softc *); 16892739Salfredstatic int vr_list_tx_init (struct vr_softc *); 16941502Swpaul 17049610Swpaul#ifdef VR_USEIOSPACE 17149610Swpaul#define VR_RES SYS_RES_IOPORT 17249610Swpaul#define VR_RID VR_PCI_LOIO 17349610Swpaul#else 17449610Swpaul#define VR_RES SYS_RES_MEMORY 17549610Swpaul#define VR_RID VR_PCI_LOMEM 17649610Swpaul#endif 17749610Swpaul 17849610Swpaulstatic device_method_t vr_methods[] = { 17949610Swpaul /* Device interface */ 18049610Swpaul DEVMETHOD(device_probe, vr_probe), 18149610Swpaul DEVMETHOD(device_attach, vr_attach), 18249610Swpaul DEVMETHOD(device_detach, vr_detach), 18349610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 18451432Swpaul 18551432Swpaul /* bus interface */ 18651432Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 18751432Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 18851432Swpaul 18951432Swpaul /* MII interface */ 19051432Swpaul DEVMETHOD(miibus_readreg, vr_miibus_readreg), 19151432Swpaul DEVMETHOD(miibus_writereg, vr_miibus_writereg), 19251432Swpaul DEVMETHOD(miibus_statchg, vr_miibus_statchg), 19351432Swpaul 19449610Swpaul { 0, 0 } 19549610Swpaul}; 19649610Swpaul 19749610Swpaulstatic driver_t vr_driver = { 19851455Swpaul "vr", 19949610Swpaul vr_methods, 20049610Swpaul sizeof(struct vr_softc) 20149610Swpaul}; 20249610Swpaul 20349610Swpaulstatic devclass_t vr_devclass; 20449610Swpaul 205113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0); 20651473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0); 20749610Swpaul 20841502Swpaul#define VR_SETBIT(sc, reg, x) \ 20941502Swpaul CSR_WRITE_1(sc, reg, \ 210105221Sphk CSR_READ_1(sc, reg) | (x)) 21141502Swpaul 21241502Swpaul#define VR_CLRBIT(sc, reg, x) \ 21341502Swpaul CSR_WRITE_1(sc, reg, \ 214105221Sphk CSR_READ_1(sc, reg) & ~(x)) 21541502Swpaul 21641502Swpaul#define VR_SETBIT16(sc, reg, x) \ 21741502Swpaul CSR_WRITE_2(sc, reg, \ 218105221Sphk CSR_READ_2(sc, reg) | (x)) 21941502Swpaul 22041502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 22141502Swpaul CSR_WRITE_2(sc, reg, \ 222105221Sphk CSR_READ_2(sc, reg) & ~(x)) 22341502Swpaul 22441502Swpaul#define VR_SETBIT32(sc, reg, x) \ 22541502Swpaul CSR_WRITE_4(sc, reg, \ 226105221Sphk CSR_READ_4(sc, reg) | (x)) 22741502Swpaul 22841502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 22941502Swpaul CSR_WRITE_4(sc, reg, \ 230105221Sphk CSR_READ_4(sc, reg) & ~(x)) 23141502Swpaul 23241502Swpaul#define SIO_SET(x) \ 23341502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 234105221Sphk CSR_READ_1(sc, VR_MIICMD) | (x)) 23541502Swpaul 23641502Swpaul#define SIO_CLR(x) \ 23741502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 238105221Sphk CSR_READ_1(sc, VR_MIICMD) & ~(x)) 23941502Swpaul 240110168Ssilby#ifdef VR_USESWSHIFT 24141502Swpaul/* 24241502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 24341502Swpaul */ 244102336Salfredstatic void 245102336Salfredvr_mii_sync(sc) 24641502Swpaul struct vr_softc *sc; 24741502Swpaul{ 24841502Swpaul register int i; 24941502Swpaul 25041502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 25141502Swpaul 25241502Swpaul for (i = 0; i < 32; i++) { 25341502Swpaul SIO_SET(VR_MIICMD_CLK); 25441502Swpaul DELAY(1); 25541502Swpaul SIO_CLR(VR_MIICMD_CLK); 25641502Swpaul DELAY(1); 25741502Swpaul } 25841502Swpaul 25941502Swpaul return; 26041502Swpaul} 26141502Swpaul 26241502Swpaul/* 26341502Swpaul * Clock a series of bits through the MII. 26441502Swpaul */ 265102336Salfredstatic void 266102336Salfredvr_mii_send(sc, bits, cnt) 26741502Swpaul struct vr_softc *sc; 26841502Swpaul u_int32_t bits; 26941502Swpaul int cnt; 27041502Swpaul{ 27141502Swpaul int i; 27241502Swpaul 27341502Swpaul SIO_CLR(VR_MIICMD_CLK); 27441502Swpaul 27541502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 27641502Swpaul if (bits & i) { 27741502Swpaul SIO_SET(VR_MIICMD_DATAIN); 27841502Swpaul } else { 27941502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 28041502Swpaul } 28141502Swpaul DELAY(1); 28241502Swpaul SIO_CLR(VR_MIICMD_CLK); 28341502Swpaul DELAY(1); 28441502Swpaul SIO_SET(VR_MIICMD_CLK); 28541502Swpaul } 28641502Swpaul} 287110168Ssilby#endif 28841502Swpaul 28941502Swpaul/* 29041502Swpaul * Read an PHY register through the MII. 29141502Swpaul */ 292102336Salfredstatic int 293102336Salfredvr_mii_readreg(sc, frame) 29441502Swpaul struct vr_softc *sc; 29541502Swpaul struct vr_mii_frame *frame; 29641502Swpaul 297110168Ssilby#ifdef VR_USESWSHIFT 29841502Swpaul{ 29967087Swpaul int i, ack; 30041502Swpaul 30167087Swpaul VR_LOCK(sc); 30241502Swpaul 30341502Swpaul /* 30441502Swpaul * Set up frame for RX. 30541502Swpaul */ 30641502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 30741502Swpaul frame->mii_opcode = VR_MII_READOP; 30841502Swpaul frame->mii_turnaround = 0; 30941502Swpaul frame->mii_data = 0; 31041502Swpaul 31141502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 31241502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 31341502Swpaul 31441502Swpaul /* 31541502Swpaul * Turn on data xmit. 31641502Swpaul */ 31741502Swpaul SIO_SET(VR_MIICMD_DIR); 31841502Swpaul 31941502Swpaul vr_mii_sync(sc); 32041502Swpaul 32141502Swpaul /* 32241502Swpaul * Send command/address info. 32341502Swpaul */ 32441502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 32541502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 32641502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 32741502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 32841502Swpaul 32941502Swpaul /* Idle bit */ 33041502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 33141502Swpaul DELAY(1); 33241502Swpaul SIO_SET(VR_MIICMD_CLK); 33341502Swpaul DELAY(1); 33441502Swpaul 33541502Swpaul /* Turn off xmit. */ 33641502Swpaul SIO_CLR(VR_MIICMD_DIR); 33741502Swpaul 33841502Swpaul /* Check for ack */ 33941502Swpaul SIO_CLR(VR_MIICMD_CLK); 34041502Swpaul DELAY(1); 341109058Smbr ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 34241502Swpaul SIO_SET(VR_MIICMD_CLK); 34341502Swpaul DELAY(1); 34441502Swpaul 34541502Swpaul /* 34641502Swpaul * Now try reading data bits. If the ack failed, we still 34741502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 34841502Swpaul */ 34941502Swpaul if (ack) { 35041502Swpaul for(i = 0; i < 16; i++) { 35141502Swpaul SIO_CLR(VR_MIICMD_CLK); 35241502Swpaul DELAY(1); 35341502Swpaul SIO_SET(VR_MIICMD_CLK); 35441502Swpaul DELAY(1); 35541502Swpaul } 35641502Swpaul goto fail; 35741502Swpaul } 35841502Swpaul 35941502Swpaul for (i = 0x8000; i; i >>= 1) { 36041502Swpaul SIO_CLR(VR_MIICMD_CLK); 36141502Swpaul DELAY(1); 36241502Swpaul if (!ack) { 36341502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 36441502Swpaul frame->mii_data |= i; 36541502Swpaul DELAY(1); 36641502Swpaul } 36741502Swpaul SIO_SET(VR_MIICMD_CLK); 36841502Swpaul DELAY(1); 36941502Swpaul } 37041502Swpaul 37141502Swpaulfail: 37241502Swpaul 37341502Swpaul SIO_CLR(VR_MIICMD_CLK); 37441502Swpaul DELAY(1); 37541502Swpaul SIO_SET(VR_MIICMD_CLK); 37641502Swpaul DELAY(1); 37741502Swpaul 37867087Swpaul VR_UNLOCK(sc); 37941502Swpaul 38041502Swpaul if (ack) 38141502Swpaul return(1); 38241502Swpaul return(0); 38341502Swpaul} 384110168Ssilby#else 385110168Ssilby{ 386110168Ssilby int s, i; 38741502Swpaul 388110168Ssilby s = splimp(); 389110168Ssilby 390110168Ssilby /* Set the PHY-adress */ 391110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 392110168Ssilby frame->mii_phyaddr); 393110168Ssilby 394110168Ssilby /* Set the register-adress */ 395110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 396110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB); 397110168Ssilby 398110168Ssilby for (i = 0; i < 10000; i++) { 399110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0) 400110168Ssilby break; 401110168Ssilby DELAY(1); 402110168Ssilby } 403110168Ssilby 404110168Ssilby frame->mii_data = CSR_READ_2(sc, VR_MIIDATA); 405110168Ssilby 406110168Ssilby (void)splx(s); 407110168Ssilby 408110168Ssilby return(0); 409110168Ssilby} 410110168Ssilby#endif 411110168Ssilby 412110168Ssilby 41341502Swpaul/* 41441502Swpaul * Write to a PHY register through the MII. 41541502Swpaul */ 416102336Salfredstatic int 417102336Salfredvr_mii_writereg(sc, frame) 41841502Swpaul struct vr_softc *sc; 41941502Swpaul struct vr_mii_frame *frame; 42041502Swpaul 421110168Ssilby#ifdef VR_USESWSHIFT 42241502Swpaul{ 42367087Swpaul VR_LOCK(sc); 42441502Swpaul 42541502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 42641502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 42741502Swpaul 42841502Swpaul /* 42941502Swpaul * Set up frame for TX. 43041502Swpaul */ 43141502Swpaul 43241502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 43341502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 43441502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 43541502Swpaul 43641502Swpaul /* 43741502Swpaul * Turn on data output. 43841502Swpaul */ 43941502Swpaul SIO_SET(VR_MIICMD_DIR); 44041502Swpaul 44141502Swpaul vr_mii_sync(sc); 44241502Swpaul 44341502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 44441502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 44541502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 44641502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 44741502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 44841502Swpaul vr_mii_send(sc, frame->mii_data, 16); 44941502Swpaul 45041502Swpaul /* Idle bit. */ 45141502Swpaul SIO_SET(VR_MIICMD_CLK); 45241502Swpaul DELAY(1); 45341502Swpaul SIO_CLR(VR_MIICMD_CLK); 45441502Swpaul DELAY(1); 45541502Swpaul 45641502Swpaul /* 45741502Swpaul * Turn off xmit. 45841502Swpaul */ 45941502Swpaul SIO_CLR(VR_MIICMD_DIR); 46041502Swpaul 46167087Swpaul VR_UNLOCK(sc); 46241502Swpaul 46341502Swpaul return(0); 46441502Swpaul} 465110168Ssilby#else 466110168Ssilby{ 467110168Ssilby int s, i; 46841502Swpaul 469110168Ssilby s = splimp(); 470110168Ssilby 471110168Ssilby /* Set the PHY-adress */ 472110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 473110168Ssilby frame->mii_phyaddr); 474110168Ssilby 475110168Ssilby /* Set the register-adress and data to write */ 476110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 477110168Ssilby CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data); 478110168Ssilby 479110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB); 480110168Ssilby 481110168Ssilby for (i = 0; i < 10000; i++) { 482110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0) 483110168Ssilby break; 484110168Ssilby DELAY(1); 485110168Ssilby } 486110168Ssilby 487110168Ssilby (void)splx(s); 488110168Ssilby 489110168Ssilby return(0); 490110168Ssilby} 491110168Ssilby#endif 492110168Ssilby 493102336Salfredstatic int 494102336Salfredvr_miibus_readreg(dev, phy, reg) 49551432Swpaul device_t dev; 49651432Swpaul int phy, reg; 49751432Swpaul{ 49841502Swpaul struct vr_softc *sc; 49941502Swpaul struct vr_mii_frame frame; 50041502Swpaul 50151432Swpaul sc = device_get_softc(dev); 502110168Ssilby 503110168Ssilby switch (sc->vr_revid) { 504110168Ssilby case REV_ID_VT6102_APOLLO: 505110168Ssilby if (phy != 1) 506110168Ssilby return 0; 507110168Ssilby default: 508110168Ssilby break; 509110168Ssilby } 510110168Ssilby 51141502Swpaul bzero((char *)&frame, sizeof(frame)); 51241502Swpaul 51351432Swpaul frame.mii_phyaddr = phy; 51441502Swpaul frame.mii_regaddr = reg; 51541502Swpaul vr_mii_readreg(sc, &frame); 51641502Swpaul 51741502Swpaul return(frame.mii_data); 51841502Swpaul} 51941502Swpaul 520102336Salfredstatic int 521102336Salfredvr_miibus_writereg(dev, phy, reg, data) 52251432Swpaul device_t dev; 52351432Swpaul u_int16_t phy, reg, data; 52451432Swpaul{ 52541502Swpaul struct vr_softc *sc; 52641502Swpaul struct vr_mii_frame frame; 52741502Swpaul 52851432Swpaul sc = device_get_softc(dev); 529110168Ssilby 530110168Ssilby switch (sc->vr_revid) { 531110168Ssilby case REV_ID_VT6102_APOLLO: 532110168Ssilby if (phy != 1) 533110168Ssilby return 0; 534110168Ssilby default: 535110168Ssilby break; 536110168Ssilby } 537110168Ssilby 53841502Swpaul bzero((char *)&frame, sizeof(frame)); 53941502Swpaul 54051432Swpaul frame.mii_phyaddr = phy; 54141502Swpaul frame.mii_regaddr = reg; 54241502Swpaul frame.mii_data = data; 54341502Swpaul 54441502Swpaul vr_mii_writereg(sc, &frame); 54541502Swpaul 54651432Swpaul return(0); 54751432Swpaul} 54851432Swpaul 549102336Salfredstatic void 550102336Salfredvr_miibus_statchg(dev) 55151432Swpaul device_t dev; 55251432Swpaul{ 55351432Swpaul struct vr_softc *sc; 55451432Swpaul struct mii_data *mii; 55551432Swpaul 55651432Swpaul sc = device_get_softc(dev); 55767087Swpaul VR_LOCK(sc); 55851432Swpaul mii = device_get_softc(sc->vr_miibus); 55951432Swpaul vr_setcfg(sc, mii->mii_media_active); 56067087Swpaul VR_UNLOCK(sc); 56151432Swpaul 56241502Swpaul return; 56341502Swpaul} 56441502Swpaul 56541502Swpaul/* 56641502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits. 56741502Swpaul */ 56841502Swpaulstatic u_int8_t vr_calchash(addr) 56941502Swpaul u_int8_t *addr; 57041502Swpaul{ 57141502Swpaul u_int32_t crc, carry; 57241502Swpaul int i, j; 57341502Swpaul u_int8_t c; 57441502Swpaul 57541502Swpaul /* Compute CRC for the address value. */ 57641502Swpaul crc = 0xFFFFFFFF; /* initial value */ 57741502Swpaul 57841502Swpaul for (i = 0; i < 6; i++) { 57941502Swpaul c = *(addr + i); 58041502Swpaul for (j = 0; j < 8; j++) { 58141502Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 58241502Swpaul crc <<= 1; 58341502Swpaul c >>= 1; 58441502Swpaul if (carry) 58541502Swpaul crc = (crc ^ 0x04c11db6) | carry; 58641502Swpaul } 58741502Swpaul } 58841502Swpaul 58941502Swpaul /* return the filter bit position */ 59041502Swpaul return((crc >> 26) & 0x0000003F); 59141502Swpaul} 59241502Swpaul 59341502Swpaul/* 59441502Swpaul * Program the 64-bit multicast hash filter. 59541502Swpaul */ 596102336Salfredstatic void 597102336Salfredvr_setmulti(sc) 59841502Swpaul struct vr_softc *sc; 59941502Swpaul{ 60041502Swpaul struct ifnet *ifp; 60141502Swpaul int h = 0; 60241502Swpaul u_int32_t hashes[2] = { 0, 0 }; 60341502Swpaul struct ifmultiaddr *ifma; 60441502Swpaul u_int8_t rxfilt; 60541502Swpaul int mcnt = 0; 60641502Swpaul 60741502Swpaul ifp = &sc->arpcom.ac_if; 60841502Swpaul 60941502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 61041502Swpaul 61141502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 61241502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 61341502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 61441502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 61541502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 61641502Swpaul return; 61741502Swpaul } 61841502Swpaul 61941502Swpaul /* first, zot all the existing hash bits */ 62041502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 62141502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 62241502Swpaul 62341502Swpaul /* now program new ones */ 62472084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 62541502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 62641502Swpaul continue; 62741502Swpaul h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 62841502Swpaul if (h < 32) 62941502Swpaul hashes[0] |= (1 << h); 63041502Swpaul else 63141502Swpaul hashes[1] |= (1 << (h - 32)); 63241502Swpaul mcnt++; 63341502Swpaul } 63441502Swpaul 63541502Swpaul if (mcnt) 63641502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 63741502Swpaul else 63841502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 63941502Swpaul 64041502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 64141502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 64241502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 64341502Swpaul 64441502Swpaul return; 64541502Swpaul} 64641502Swpaul 64741502Swpaul/* 64841502Swpaul * In order to fiddle with the 64941502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 65041502Swpaul * first have to put the transmit and/or receive logic in the idle state. 65141502Swpaul */ 652102336Salfredstatic void 653102336Salfredvr_setcfg(sc, media) 65441502Swpaul struct vr_softc *sc; 65551432Swpaul int media; 65641502Swpaul{ 65741502Swpaul int restart = 0; 65841502Swpaul 65941502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 66041502Swpaul restart = 1; 66141502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 66241502Swpaul } 66341502Swpaul 66451432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 66541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 66641502Swpaul else 66741502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 66841502Swpaul 66941502Swpaul if (restart) 67041502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 67141502Swpaul 67241502Swpaul return; 67341502Swpaul} 67441502Swpaul 675102336Salfredstatic void 676102336Salfredvr_reset(sc) 67741502Swpaul struct vr_softc *sc; 67841502Swpaul{ 67941502Swpaul register int i; 68041502Swpaul 68141502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 68241502Swpaul 68341502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 68441502Swpaul DELAY(10); 68541502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 68641502Swpaul break; 68741502Swpaul } 688107220Ssilby if (i == VR_TIMEOUT) { 689107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 690107220Ssilby printf("vr%d: reset never completed!\n", sc->vr_unit); 691107220Ssilby else { 692107220Ssilby /* Use newer force reset command */ 693107220Ssilby printf("vr%d: Using force reset command.\n", sc->vr_unit); 694107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 695107220Ssilby } 696107220Ssilby } 69741502Swpaul 69841502Swpaul /* Wait a little while for the chip to get its brains in order. */ 69941502Swpaul DELAY(1000); 70041502Swpaul 70141502Swpaul return; 70241502Swpaul} 70341502Swpaul 70441502Swpaul/* 70541502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 70641502Swpaul * IDs against our list and return a device name if we find a match. 70741502Swpaul */ 708102336Salfredstatic int 709102336Salfredvr_probe(dev) 71049610Swpaul device_t dev; 71141502Swpaul{ 71241502Swpaul struct vr_type *t; 71341502Swpaul 71441502Swpaul t = vr_devs; 71541502Swpaul 71641502Swpaul while(t->vr_name != NULL) { 71749610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 71849610Swpaul (pci_get_device(dev) == t->vr_did)) { 71949610Swpaul device_set_desc(dev, t->vr_name); 72049610Swpaul return(0); 72141502Swpaul } 72241502Swpaul t++; 72341502Swpaul } 72441502Swpaul 72549610Swpaul return(ENXIO); 72641502Swpaul} 72741502Swpaul 72841502Swpaul/* 72941502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 73041502Swpaul * setup and ethernet/BPF attach. 73141502Swpaul */ 732102336Salfredstatic int 733102336Salfredvr_attach(dev) 73449610Swpaul device_t dev; 73541502Swpaul{ 73667087Swpaul int i; 73741502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 73841502Swpaul struct vr_softc *sc; 73941502Swpaul struct ifnet *ifp; 74049610Swpaul int unit, error = 0, rid; 74141502Swpaul 74249610Swpaul sc = device_get_softc(dev); 74349610Swpaul unit = device_get_unit(dev); 74441502Swpaul 74593818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 74693818Sjhb MTX_DEF | MTX_RECURSE); 747117208Simp#ifndef BURN_BRIDGES 74841502Swpaul /* 74941502Swpaul * Handle power management nonsense. 75041502Swpaul */ 75172813Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 75272813Swpaul u_int32_t iobase, membase, irq; 75341502Swpaul 75472813Swpaul /* Save important PCI config data. */ 75572813Swpaul iobase = pci_read_config(dev, VR_PCI_LOIO, 4); 75672813Swpaul membase = pci_read_config(dev, VR_PCI_LOMEM, 4); 75772813Swpaul irq = pci_read_config(dev, VR_PCI_INTLINE, 4); 75841502Swpaul 75972813Swpaul /* Reset the power state. */ 76072813Swpaul printf("vr%d: chip is in D%d power mode " 76172813Swpaul "-- setting to D0\n", unit, 76272813Swpaul pci_get_powerstate(dev)); 76372813Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 76441502Swpaul 76541502Swpaul /* Restore PCI config data. */ 76672813Swpaul pci_write_config(dev, VR_PCI_LOIO, iobase, 4); 76772813Swpaul pci_write_config(dev, VR_PCI_LOMEM, membase, 4); 76872813Swpaul pci_write_config(dev, VR_PCI_INTLINE, irq, 4); 76941502Swpaul } 770117208Simp#endif 77141502Swpaul /* 77241502Swpaul * Map control/status registers. 77341502Swpaul */ 77472813Swpaul pci_enable_busmaster(dev); 775107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 77641502Swpaul 77749610Swpaul rid = VR_RID; 77849610Swpaul sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid, 77949610Swpaul 0, ~0, 1, RF_ACTIVE); 78049610Swpaul 78149610Swpaul if (sc->vr_res == NULL) { 78249610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 78349610Swpaul error = ENXIO; 78441502Swpaul goto fail; 78541502Swpaul } 78641502Swpaul 78749610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 78849610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 78941502Swpaul 79041502Swpaul /* Allocate interrupt */ 79149610Swpaul rid = 0; 79249610Swpaul sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 79349610Swpaul RF_SHAREABLE | RF_ACTIVE); 79449610Swpaul 79549610Swpaul if (sc->vr_irq == NULL) { 79641502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 79749610Swpaul error = ENXIO; 79841502Swpaul goto fail; 79941502Swpaul } 80041502Swpaul 80176586Swpaul /* 80276586Swpaul * Windows may put the chip in suspend mode when it 80376586Swpaul * shuts down. Be sure to kick it in the head to wake it 80476586Swpaul * up again. 80576586Swpaul */ 80676586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 80776586Swpaul 80841502Swpaul /* Reset the adapter. */ 80941502Swpaul vr_reset(sc); 81041502Swpaul 811110168Ssilby /* 812110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 813110168Ssilby * initialization and disable AUTOPOLL. 814110168Ssilby */ 815110168Ssilby pci_write_config(dev, VR_PCI_MODE, 816110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 817110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 818110168Ssilby 81941502Swpaul /* 82041502Swpaul * Get station address. The way the Rhine chips work, 82141502Swpaul * you're not allowed to directly access the EEPROM once 82241502Swpaul * they've been programmed a special way. Consequently, 82341502Swpaul * we need to read the node address from the PAR0 and PAR1 82441502Swpaul * registers. 82541502Swpaul */ 82641502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 82741502Swpaul DELAY(200); 82841502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 82941502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 83041502Swpaul 83141502Swpaul /* 83241502Swpaul * A Rhine chip was detected. Inform the world. 83341502Swpaul */ 83441502Swpaul printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); 83541502Swpaul 83641502Swpaul sc->vr_unit = unit; 83741502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 83841502Swpaul 83951432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 84051657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 84151432Swpaul 84251432Swpaul if (sc->vr_ldata == NULL) { 84341502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 84449610Swpaul error = ENXIO; 84549610Swpaul goto fail; 84641502Swpaul } 84741502Swpaul 84841502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 84941502Swpaul 85041502Swpaul ifp = &sc->arpcom.ac_if; 85141502Swpaul ifp->if_softc = sc; 852121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 85341502Swpaul ifp->if_mtu = ETHERMTU; 85441502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 85541502Swpaul ifp->if_ioctl = vr_ioctl; 85641502Swpaul ifp->if_output = ether_output; 85741502Swpaul ifp->if_start = vr_start; 85841502Swpaul ifp->if_watchdog = vr_watchdog; 85941502Swpaul ifp->if_init = vr_init; 86041502Swpaul ifp->if_baudrate = 10000000; 86143515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 86241502Swpaul 86351432Swpaul /* 86451432Swpaul * Do MII setup. 86551432Swpaul */ 86651432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 86751432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 86841502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 86949610Swpaul error = ENXIO; 87041502Swpaul goto fail; 87141502Swpaul } 87241502Swpaul 87351432Swpaul callout_handle_init(&sc->vr_stat_ch); 87441502Swpaul 87541502Swpaul /* 87663090Sarchie * Call MI attach routine. 87741502Swpaul */ 878106936Ssam ether_ifattach(ifp, eaddr); 87941502Swpaul 880113609Snjl /* Hook interrupt last to avoid having to lock softc */ 881112872Snjl error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET, 882112872Snjl vr_intr, sc, &sc->vr_intrhand); 883112872Snjl 884112872Snjl if (error) { 885112872Snjl printf("vr%d: couldn't set up irq\n", unit); 886113609Snjl ether_ifdetach(ifp); 887112872Snjl goto fail; 888112872Snjl } 889112872Snjl 89041502Swpaulfail: 891112872Snjl if (error) 892112872Snjl vr_detach(dev); 89367087Swpaul 89449610Swpaul return(error); 89541502Swpaul} 89641502Swpaul 897113609Snjl/* 898113609Snjl * Shutdown hardware and free up resources. This can be called any 899113609Snjl * time after the mutex has been initialized. It is called in both 900113609Snjl * the error case in attach and the normal detach case so it needs 901113609Snjl * to be careful about only freeing resources that have actually been 902113609Snjl * allocated. 903113609Snjl */ 904102336Salfredstatic int 905102336Salfredvr_detach(dev) 90649610Swpaul device_t dev; 90749610Swpaul{ 90849610Swpaul struct vr_softc *sc; 90949610Swpaul struct ifnet *ifp; 91049610Swpaul 91149610Swpaul sc = device_get_softc(dev); 912112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 91367087Swpaul VR_LOCK(sc); 91449610Swpaul ifp = &sc->arpcom.ac_if; 91549610Swpaul 916113609Snjl /* These should only be active if attach succeeded */ 917113812Simp if (device_is_attached(dev)) { 918113609Snjl vr_stop(sc); 919112872Snjl ether_ifdetach(ifp); 920113609Snjl } 921113609Snjl if (sc->vr_miibus) 922112872Snjl device_delete_child(dev, sc->vr_miibus); 923113609Snjl bus_generic_detach(dev); 92449610Swpaul 925112872Snjl if (sc->vr_intrhand) 926112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 927112872Snjl if (sc->vr_irq) 928112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 929112872Snjl if (sc->vr_res) 930112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 93151432Swpaul 932112872Snjl if (sc->vr_ldata) 933112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 93449610Swpaul 93567087Swpaul VR_UNLOCK(sc); 93667087Swpaul mtx_destroy(&sc->vr_mtx); 93749610Swpaul 93849610Swpaul return(0); 93949610Swpaul} 94049610Swpaul 94141502Swpaul/* 94241502Swpaul * Initialize the transmit descriptors. 94341502Swpaul */ 944102336Salfredstatic int 945102336Salfredvr_list_tx_init(sc) 94641502Swpaul struct vr_softc *sc; 94741502Swpaul{ 94841502Swpaul struct vr_chain_data *cd; 94941502Swpaul struct vr_list_data *ld; 95041502Swpaul int i; 95141502Swpaul 95241502Swpaul cd = &sc->vr_cdata; 95341502Swpaul ld = sc->vr_ldata; 95441502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 95541502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 95641502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 95741502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 95841502Swpaul &cd->vr_tx_chain[0]; 95941502Swpaul else 96041502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 96141502Swpaul &cd->vr_tx_chain[i + 1]; 96241502Swpaul } 96341502Swpaul 96441502Swpaul cd->vr_tx_free = &cd->vr_tx_chain[0]; 96541502Swpaul cd->vr_tx_tail = cd->vr_tx_head = NULL; 96641502Swpaul 96741502Swpaul return(0); 96841502Swpaul} 96941502Swpaul 97041502Swpaul 97141502Swpaul/* 97241502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 97341502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 97441502Swpaul * points back to the first. 97541502Swpaul */ 976102336Salfredstatic int 977102336Salfredvr_list_rx_init(sc) 97841502Swpaul struct vr_softc *sc; 97941502Swpaul{ 98041502Swpaul struct vr_chain_data *cd; 98141502Swpaul struct vr_list_data *ld; 98241502Swpaul int i; 98341502Swpaul 98441502Swpaul cd = &sc->vr_cdata; 98541502Swpaul ld = sc->vr_ldata; 98641502Swpaul 98741502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 98841502Swpaul cd->vr_rx_chain[i].vr_ptr = 98941502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 99049610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 99141502Swpaul return(ENOBUFS); 99241502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 99341502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 99441502Swpaul &cd->vr_rx_chain[0]; 99541502Swpaul ld->vr_rx_list[i].vr_next = 99641502Swpaul vtophys(&ld->vr_rx_list[0]); 99741502Swpaul } else { 99841502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 99941502Swpaul &cd->vr_rx_chain[i + 1]; 100041502Swpaul ld->vr_rx_list[i].vr_next = 100141502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 100241502Swpaul } 100341502Swpaul } 100441502Swpaul 100541502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 100641502Swpaul 100741502Swpaul return(0); 100841502Swpaul} 100941502Swpaul 101041502Swpaul/* 101141502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 101241502Swpaul * Note: the length fields are only 11 bits wide, which means the 101341502Swpaul * largest size we can specify is 2047. This is important because 101441502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 101541502Swpaul * overflow the field and make a mess. 101641502Swpaul */ 1017102336Salfredstatic int 1018102336Salfredvr_newbuf(sc, c, m) 101941502Swpaul struct vr_softc *sc; 102041502Swpaul struct vr_chain_onefrag *c; 102149610Swpaul struct mbuf *m; 102241502Swpaul{ 102341502Swpaul struct mbuf *m_new = NULL; 102441502Swpaul 102549610Swpaul if (m == NULL) { 1026111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 102787846Sluigi if (m_new == NULL) 102849610Swpaul return(ENOBUFS); 102941502Swpaul 1030111119Simp MCLGET(m_new, M_DONTWAIT); 103149610Swpaul if (!(m_new->m_flags & M_EXT)) { 103249610Swpaul m_freem(m_new); 103349610Swpaul return(ENOBUFS); 103449610Swpaul } 103549610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 103649610Swpaul } else { 103749610Swpaul m_new = m; 103849610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 103949610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 104041502Swpaul } 104141502Swpaul 104249610Swpaul m_adj(m_new, sizeof(u_int64_t)); 104349610Swpaul 104441502Swpaul c->vr_mbuf = m_new; 104541502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 104641502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 104742491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 104841502Swpaul 104941502Swpaul return(0); 105041502Swpaul} 105141502Swpaul 105241502Swpaul/* 105341502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 105441502Swpaul * the higher level protocols. 105541502Swpaul */ 1056102336Salfredstatic void 1057102336Salfredvr_rxeof(sc) 105841502Swpaul struct vr_softc *sc; 105941502Swpaul{ 106041502Swpaul struct mbuf *m; 106141502Swpaul struct ifnet *ifp; 106241502Swpaul struct vr_chain_onefrag *cur_rx; 106341502Swpaul int total_len = 0; 106441502Swpaul u_int32_t rxstat; 106541502Swpaul 106641502Swpaul ifp = &sc->arpcom.ac_if; 106741502Swpaul 106841502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 106941502Swpaul VR_RXSTAT_OWN)) { 107049610Swpaul struct mbuf *m0 = NULL; 107149610Swpaul 107241502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 107341502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 107449610Swpaul m = cur_rx->vr_mbuf; 107541502Swpaul 107641502Swpaul /* 107741502Swpaul * If an error occurs, update stats, clear the 107841502Swpaul * status word and leave the mbuf cluster in place: 107941502Swpaul * it should simply get re-used next time this descriptor 108041502Swpaul * comes up in the ring. 108141502Swpaul */ 108241502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 108341502Swpaul ifp->if_ierrors++; 1084110131Ssilby printf("vr%d: rx error (%02x):", 1085110131Ssilby sc->vr_unit, rxstat & 0x000000ff); 1086110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 1087110131Ssilby printf(" crc error"); 1088110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 1089110131Ssilby printf(" frame alignment error\n"); 1090110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 1091110131Ssilby printf(" FIFO overflow"); 1092110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 1093110131Ssilby printf(" received giant packet"); 1094110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 1095110131Ssilby printf(" received runt packet"); 1096110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 1097110131Ssilby printf(" system bus error"); 1098110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 1099110131Ssilby printf("rx buffer error"); 1100110131Ssilby printf("\n"); 110149610Swpaul vr_newbuf(sc, cur_rx, m); 110241502Swpaul continue; 110341502Swpaul } 110441502Swpaul 110541502Swpaul /* No errors; receive the packet. */ 110641502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 110741502Swpaul 110841502Swpaul /* 110942048Swpaul * XXX The VIA Rhine chip includes the CRC with every 111042048Swpaul * received frame, and there's no way to turn this 111142048Swpaul * behavior off (at least, I can't find anything in 111242048Swpaul * the manual that explains how to do it) so we have 111342048Swpaul * to trim off the CRC manually. 111442048Swpaul */ 111542048Swpaul total_len -= ETHER_CRC_LEN; 111642048Swpaul 111778508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 111878508Sbmilekic NULL); 111949610Swpaul vr_newbuf(sc, cur_rx, m); 112049610Swpaul if (m0 == NULL) { 112141502Swpaul ifp->if_ierrors++; 112241502Swpaul continue; 112341502Swpaul } 112449610Swpaul m = m0; 112541502Swpaul 112641502Swpaul ifp->if_ipackets++; 1127106936Ssam (*ifp->if_input)(ifp, m); 112841502Swpaul } 112941502Swpaul 113041502Swpaul return; 113141502Swpaul} 113241502Swpaul 1133105221Sphkstatic void 1134102336Salfredvr_rxeoc(sc) 113541502Swpaul struct vr_softc *sc; 113641502Swpaul{ 1137110131Ssilby struct ifnet *ifp; 1138110131Ssilby int i; 113941502Swpaul 1140110131Ssilby ifp = &sc->arpcom.ac_if; 1141110131Ssilby 1142110131Ssilby ifp->if_ierrors++; 1143110131Ssilby 1144110131Ssilby VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1145110131Ssilby DELAY(10000); 1146110131Ssilby 1147110131Ssilby for (i = 0x400; 1148110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1149110131Ssilby i--) 1150110131Ssilby ; /* Wait for receiver to stop */ 1151110131Ssilby 1152110131Ssilby if (!i) { 1153110131Ssilby printf("vr%d: rx shutdown error!\n", sc->vr_unit); 1154110131Ssilby sc->vr_flags |= VR_F_RESTART; 1155110131Ssilby return; 1156110131Ssilby } 1157110131Ssilby 115841502Swpaul vr_rxeof(sc); 1159110131Ssilby 116041502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 116141502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 116241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 116341502Swpaul 116441502Swpaul return; 116541502Swpaul} 116641502Swpaul 116741502Swpaul/* 116841502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 116941502Swpaul * the list buffers. 117041502Swpaul */ 117141502Swpaul 1172102336Salfredstatic void 1173102336Salfredvr_txeof(sc) 117441502Swpaul struct vr_softc *sc; 117541502Swpaul{ 117641502Swpaul struct vr_chain *cur_tx; 117741502Swpaul struct ifnet *ifp; 117841502Swpaul 117941502Swpaul ifp = &sc->arpcom.ac_if; 118041502Swpaul 118196677Ssilby /* Reset the timeout timer; if_txeoc will clear it. */ 118296677Ssilby ifp->if_timer = 5; 118341502Swpaul 118441502Swpaul /* Sanity check. */ 118541502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 118641502Swpaul return; 118741502Swpaul 118841502Swpaul /* 118941502Swpaul * Go through our tx list and free mbufs for those 119041502Swpaul * frames that have been transmitted. 119141502Swpaul */ 119241502Swpaul while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { 119341502Swpaul u_int32_t txstat; 1194110131Ssilby int i; 119541502Swpaul 119641502Swpaul cur_tx = sc->vr_cdata.vr_tx_head; 119741502Swpaul txstat = cur_tx->vr_ptr->vr_status; 119841502Swpaul 1199101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1200101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1201110131Ssilby for (i = 0x400; 1202110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1203110131Ssilby i--) 1204101896Ssilby ; /* Wait for chip to shutdown */ 1205110131Ssilby if (!i) { 1206110131Ssilby printf("vr%d: tx shutdown timeout\n", sc->vr_unit); 1207110131Ssilby sc->vr_flags |= VR_F_RESTART; 1208110131Ssilby break; 1209110131Ssilby } 1210101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1211101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1212101896Ssilby break; 1213101896Ssilby } 1214101896Ssilby 121542491Swpaul if (txstat & VR_TXSTAT_OWN) 121641502Swpaul break; 121741502Swpaul 121841502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 121941502Swpaul ifp->if_oerrors++; 122041502Swpaul if (txstat & VR_TXSTAT_DEFER) 122141502Swpaul ifp->if_collisions++; 122241502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 122341502Swpaul ifp->if_collisions++; 122441502Swpaul } 122541502Swpaul 122641502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 122741502Swpaul 122841502Swpaul ifp->if_opackets++; 122951432Swpaul if (cur_tx->vr_mbuf != NULL) { 123051432Swpaul m_freem(cur_tx->vr_mbuf); 123151432Swpaul cur_tx->vr_mbuf = NULL; 123251432Swpaul } 123341502Swpaul 123441502Swpaul if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { 123541502Swpaul sc->vr_cdata.vr_tx_head = NULL; 123641502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 123741502Swpaul break; 123841502Swpaul } 123941502Swpaul 124041502Swpaul sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; 124141502Swpaul } 124241502Swpaul 124341502Swpaul return; 124441502Swpaul} 124541502Swpaul 124641502Swpaul/* 124741502Swpaul * TX 'end of channel' interrupt handler. 124841502Swpaul */ 1249102336Salfredstatic void 1250102336Salfredvr_txeoc(sc) 125141502Swpaul struct vr_softc *sc; 125241502Swpaul{ 125341502Swpaul struct ifnet *ifp; 125441502Swpaul 125541502Swpaul ifp = &sc->arpcom.ac_if; 125641502Swpaul 125741502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) { 125841502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 125941502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 126096677Ssilby ifp->if_timer = 0; 126141502Swpaul } 126241502Swpaul 126341502Swpaul return; 126441502Swpaul} 126541502Swpaul 1266102336Salfredstatic void 1267102336Salfredvr_tick(xsc) 126851432Swpaul void *xsc; 126951432Swpaul{ 127051432Swpaul struct vr_softc *sc; 127151432Swpaul struct mii_data *mii; 127251432Swpaul 127351432Swpaul sc = xsc; 127467087Swpaul VR_LOCK(sc); 1275110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1276110131Ssilby printf("vr%d: restarting\n", sc->vr_unit); 1277110131Ssilby vr_stop(sc); 1278110131Ssilby vr_reset(sc); 1279110131Ssilby vr_init(sc); 1280110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1281110131Ssilby } 1282110131Ssilby 128351432Swpaul mii = device_get_softc(sc->vr_miibus); 128451432Swpaul mii_tick(mii); 128551432Swpaul 128651432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 128751432Swpaul 128867087Swpaul VR_UNLOCK(sc); 128951432Swpaul 129051432Swpaul return; 129151432Swpaul} 129251432Swpaul 1293102336Salfredstatic void 1294102336Salfredvr_intr(arg) 129541502Swpaul void *arg; 129641502Swpaul{ 129741502Swpaul struct vr_softc *sc; 129841502Swpaul struct ifnet *ifp; 129941502Swpaul u_int16_t status; 130041502Swpaul 130141502Swpaul sc = arg; 130267087Swpaul VR_LOCK(sc); 130341502Swpaul ifp = &sc->arpcom.ac_if; 130441502Swpaul 130541502Swpaul /* Supress unwanted interrupts. */ 130641502Swpaul if (!(ifp->if_flags & IFF_UP)) { 130741502Swpaul vr_stop(sc); 130867087Swpaul VR_UNLOCK(sc); 130941502Swpaul return; 131041502Swpaul } 131141502Swpaul 131241502Swpaul /* Disable interrupts. */ 131341502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 131441502Swpaul 131541502Swpaul for (;;) { 131641502Swpaul 131741502Swpaul status = CSR_READ_2(sc, VR_ISR); 131841502Swpaul if (status) 131941502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 132041502Swpaul 132141502Swpaul if ((status & VR_INTRS) == 0) 132241502Swpaul break; 132341502Swpaul 132441502Swpaul if (status & VR_ISR_RX_OK) 132541502Swpaul vr_rxeof(sc); 132641502Swpaul 1327110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1328110131Ssilby printf("vr%d: rx packet lost\n", sc->vr_unit); 1329110131Ssilby ifp->if_ierrors++; 1330110131Ssilby } 1331110131Ssilby 133241502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1333110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1334110131Ssilby printf("vr%d: receive error (%04x)", 1335110131Ssilby sc->vr_unit, status); 1336110131Ssilby if (status & VR_ISR_RX_NOBUF) 1337110131Ssilby printf(" no buffers"); 1338110131Ssilby if (status & VR_ISR_RX_OFLOW) 1339110131Ssilby printf(" overflow"); 1340110131Ssilby if (status & VR_ISR_RX_DROPPED) 1341110131Ssilby printf(" packet lost"); 1342110131Ssilby printf("\n"); 134341502Swpaul vr_rxeoc(sc); 134441502Swpaul } 134541502Swpaul 1346101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1347101896Ssilby vr_reset(sc); 1348101896Ssilby vr_init(sc); 1349101896Ssilby break; 135041502Swpaul } 135141502Swpaul 1352101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1353101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 135441502Swpaul vr_txeof(sc); 1355101896Ssilby if ((status & VR_ISR_UDFI) || 1356101896Ssilby (status & VR_ISR_TX_ABRT2) || 1357101896Ssilby (status & VR_ISR_TX_ABRT)) { 1358101896Ssilby ifp->if_oerrors++; 1359101896Ssilby if (sc->vr_cdata.vr_tx_head != NULL) { 1360101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1361101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1362101896Ssilby } 1363101896Ssilby } else 1364101896Ssilby vr_txeoc(sc); 136541502Swpaul } 136641502Swpaul 136741502Swpaul } 136841502Swpaul 136941502Swpaul /* Re-enable interrupts. */ 137041502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 137141502Swpaul 137241502Swpaul if (ifp->if_snd.ifq_head != NULL) { 137341502Swpaul vr_start(ifp); 137441502Swpaul } 137541502Swpaul 137667087Swpaul VR_UNLOCK(sc); 137767087Swpaul 137841502Swpaul return; 137941502Swpaul} 138041502Swpaul 138141502Swpaul/* 138241502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 138341502Swpaul * pointers to the fragment pointers. 138441502Swpaul */ 1385102336Salfredstatic int 1386102336Salfredvr_encap(sc, c, m_head) 138741502Swpaul struct vr_softc *sc; 138841502Swpaul struct vr_chain *c; 138941502Swpaul struct mbuf *m_head; 139041502Swpaul{ 139141502Swpaul int frag = 0; 139241502Swpaul struct vr_desc *f = NULL; 139341502Swpaul int total_len; 139441502Swpaul struct mbuf *m; 139541502Swpaul 139641502Swpaul m = m_head; 139741502Swpaul total_len = 0; 139841502Swpaul 139941502Swpaul /* 140041502Swpaul * The VIA Rhine wants packet buffers to be longword 140141502Swpaul * aligned, but very often our mbufs aren't. Rather than 140241502Swpaul * waste time trying to decide when to copy and when not 140341502Swpaul * to copy, just do it all the time. 140441502Swpaul */ 140541502Swpaul if (m != NULL) { 140641502Swpaul struct mbuf *m_new = NULL; 140741502Swpaul 1408112821Ssilby m_new = m_defrag(m_head, M_DONTWAIT); 140941502Swpaul if (m_new == NULL) { 141041502Swpaul return(1); 141141502Swpaul } 1412112821Ssilby 141341502Swpaul m_head = m_new; 141441502Swpaul /* 141541502Swpaul * The Rhine chip doesn't auto-pad, so we have to make 141641502Swpaul * sure to pad short frames out to the minimum frame length 141741502Swpaul * ourselves. 141841502Swpaul */ 141941502Swpaul if (m_head->m_len < VR_MIN_FRAMELEN) { 142041502Swpaul m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; 142141502Swpaul m_new->m_len = m_new->m_pkthdr.len; 142241502Swpaul } 142341502Swpaul f = c->vr_ptr; 142441502Swpaul f->vr_data = vtophys(mtod(m_new, caddr_t)); 142541502Swpaul f->vr_ctl = total_len = m_new->m_len; 142641502Swpaul f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 142741502Swpaul f->vr_status = 0; 142841502Swpaul frag = 1; 142941502Swpaul } 143041502Swpaul 143141502Swpaul c->vr_mbuf = m_head; 143242491Swpaul c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 143341502Swpaul c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 143441502Swpaul 143541502Swpaul return(0); 143641502Swpaul} 143741502Swpaul 143841502Swpaul/* 143941502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 144041502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 144141502Swpaul * copy of the pointers since the transmit list fragment pointers are 144241502Swpaul * physical addresses. 144341502Swpaul */ 144441502Swpaul 1445102336Salfredstatic void 1446102336Salfredvr_start(ifp) 144741502Swpaul struct ifnet *ifp; 144841502Swpaul{ 144941502Swpaul struct vr_softc *sc; 145041502Swpaul struct mbuf *m_head = NULL; 1451113274Ssilby struct vr_chain *cur_tx = NULL, *start_tx, *prev_tx; 145241502Swpaul 145341502Swpaul sc = ifp->if_softc; 145441502Swpaul 145567087Swpaul VR_LOCK(sc); 145641502Swpaul 145741502Swpaul /* 145841502Swpaul * Check for an available queue slot. If there are none, 145941502Swpaul * punt. 146041502Swpaul */ 146141502Swpaul if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { 1462113274Ssilby VR_UNLOCK(sc); 146341502Swpaul return; 146441502Swpaul } 146541502Swpaul 146641502Swpaul start_tx = sc->vr_cdata.vr_tx_free; 146741502Swpaul 146841502Swpaul while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { 146941502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 147041502Swpaul if (m_head == NULL) 147141502Swpaul break; 147241502Swpaul 147341502Swpaul /* Pick a descriptor off the free list. */ 1474113274Ssilby prev_tx = cur_tx; 147541502Swpaul cur_tx = sc->vr_cdata.vr_tx_free; 147641502Swpaul sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; 147741502Swpaul 147841502Swpaul /* Pack the data into the descriptor. */ 147971271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 1480113274Ssilby /* Rollback, send what we were able to encap. */ 148171271Swpaul IF_PREPEND(&ifp->if_snd, m_head); 1482113274Ssilby sc->vr_cdata.vr_tx_free = cur_tx; 1483113274Ssilby cur_tx = prev_tx; 148471271Swpaul break; 148571271Swpaul } 148641502Swpaul 148741502Swpaul if (cur_tx != start_tx) 148841502Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 148941502Swpaul 149041502Swpaul /* 149141502Swpaul * If there's a BPF listener, bounce a copy of this frame 149241502Swpaul * to him. 149341502Swpaul */ 1494106936Ssam BPF_MTAP(ifp, cur_tx->vr_mbuf); 149551583Swpaul 149642491Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 149741502Swpaul } 149841502Swpaul 149941502Swpaul /* 150041526Swpaul * If there are no frames queued, bail. 150141526Swpaul */ 150267087Swpaul if (cur_tx == NULL) { 150367087Swpaul VR_UNLOCK(sc); 150441526Swpaul return; 150567087Swpaul } 150641526Swpaul 150741502Swpaul sc->vr_cdata.vr_tx_tail = cur_tx; 150841502Swpaul 150942491Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 151041502Swpaul sc->vr_cdata.vr_tx_head = start_tx; 1511113274Ssilby 1512113274Ssilby /* Tell the chip to start transmitting. */ 1513113274Ssilby VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); 151441502Swpaul 151541502Swpaul /* 151641502Swpaul * Set a timeout in case the chip goes out to lunch. 151741502Swpaul */ 151841502Swpaul ifp->if_timer = 5; 151967087Swpaul VR_UNLOCK(sc); 152041502Swpaul 152141502Swpaul return; 152241502Swpaul} 152341502Swpaul 1524102336Salfredstatic void 1525102336Salfredvr_init(xsc) 152641502Swpaul void *xsc; 152741502Swpaul{ 152841502Swpaul struct vr_softc *sc = xsc; 152941502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 153051432Swpaul struct mii_data *mii; 153173963Swpaul int i; 153241502Swpaul 153367087Swpaul VR_LOCK(sc); 153441502Swpaul 153551432Swpaul mii = device_get_softc(sc->vr_miibus); 153641502Swpaul 153741502Swpaul /* 153841502Swpaul * Cancel pending I/O and free all RX/TX buffers. 153941502Swpaul */ 154041502Swpaul vr_stop(sc); 154141502Swpaul vr_reset(sc); 154241502Swpaul 154373963Swpaul /* 154473963Swpaul * Set our station address. 154573963Swpaul */ 154673963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 154773963Swpaul CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]); 1548101375Ssilby 1549101375Ssilby /* Set DMA size */ 1550101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1551101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 155273963Swpaul 1553101375Ssilby /* 1554101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1555101108Ssilby * so we must set both. 1556101108Ssilby */ 1557101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1558110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1559101108Ssilby 1560101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1561101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1562101108Ssilby 156341502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1564110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 156541502Swpaul 156641502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 156741502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 156841502Swpaul 156941502Swpaul /* Init circular RX list. */ 157041502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 157141502Swpaul printf("vr%d: initialization failed: no " 157241502Swpaul "memory for rx buffers\n", sc->vr_unit); 157341502Swpaul vr_stop(sc); 157467087Swpaul VR_UNLOCK(sc); 157541502Swpaul return; 157641502Swpaul } 157741502Swpaul 157841502Swpaul /* 157941502Swpaul * Init tx descriptors. 158041502Swpaul */ 158141502Swpaul vr_list_tx_init(sc); 158241502Swpaul 158341502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 158441502Swpaul if (ifp->if_flags & IFF_PROMISC) 158541502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 158641502Swpaul else 158741502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 158841502Swpaul 158941502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 159041502Swpaul if (ifp->if_flags & IFF_BROADCAST) 159141502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 159241502Swpaul else 159341502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 159441502Swpaul 159541502Swpaul /* 159641502Swpaul * Program the multicast filter, if necessary. 159741502Swpaul */ 159841502Swpaul vr_setmulti(sc); 159941502Swpaul 160041502Swpaul /* 160141502Swpaul * Load the address of the RX list. 160241502Swpaul */ 160341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 160441502Swpaul 160541502Swpaul /* Enable receiver and transmitter. */ 160641502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 160741502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 160841502Swpaul VR_CMD_RX_GO); 160941502Swpaul 161041502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 161141502Swpaul 161241502Swpaul /* 161341502Swpaul * Enable interrupts. 161441502Swpaul */ 161541502Swpaul CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 161641502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 161741502Swpaul 161851432Swpaul mii_mediachg(mii); 161941502Swpaul 162041502Swpaul ifp->if_flags |= IFF_RUNNING; 162141502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 162241502Swpaul 162351432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 162451432Swpaul 162567087Swpaul VR_UNLOCK(sc); 162667087Swpaul 162741502Swpaul return; 162841502Swpaul} 162941502Swpaul 163041502Swpaul/* 163141502Swpaul * Set media options. 163241502Swpaul */ 1633102336Salfredstatic int 1634102336Salfredvr_ifmedia_upd(ifp) 163541502Swpaul struct ifnet *ifp; 163641502Swpaul{ 163741502Swpaul struct vr_softc *sc; 163841502Swpaul 163941502Swpaul sc = ifp->if_softc; 164041502Swpaul 164151432Swpaul if (ifp->if_flags & IFF_UP) 164251432Swpaul vr_init(sc); 164341502Swpaul 164441502Swpaul return(0); 164541502Swpaul} 164641502Swpaul 164741502Swpaul/* 164841502Swpaul * Report current media status. 164941502Swpaul */ 1650102336Salfredstatic void 1651102336Salfredvr_ifmedia_sts(ifp, ifmr) 165241502Swpaul struct ifnet *ifp; 165341502Swpaul struct ifmediareq *ifmr; 165441502Swpaul{ 165541502Swpaul struct vr_softc *sc; 165651432Swpaul struct mii_data *mii; 165741502Swpaul 165841502Swpaul sc = ifp->if_softc; 165951432Swpaul mii = device_get_softc(sc->vr_miibus); 166051432Swpaul mii_pollstat(mii); 166151432Swpaul ifmr->ifm_active = mii->mii_media_active; 166251432Swpaul ifmr->ifm_status = mii->mii_media_status; 166341502Swpaul 166441502Swpaul return; 166541502Swpaul} 166641502Swpaul 1667102336Salfredstatic int 1668102336Salfredvr_ioctl(ifp, command, data) 166941502Swpaul struct ifnet *ifp; 167041502Swpaul u_long command; 167141502Swpaul caddr_t data; 167241502Swpaul{ 167341502Swpaul struct vr_softc *sc = ifp->if_softc; 167441502Swpaul struct ifreq *ifr = (struct ifreq *) data; 167551432Swpaul struct mii_data *mii; 167667087Swpaul int error = 0; 167741502Swpaul 167867087Swpaul VR_LOCK(sc); 167941502Swpaul 168041502Swpaul switch(command) { 168141502Swpaul case SIOCSIFFLAGS: 168241502Swpaul if (ifp->if_flags & IFF_UP) { 168341502Swpaul vr_init(sc); 168441502Swpaul } else { 168541502Swpaul if (ifp->if_flags & IFF_RUNNING) 168641502Swpaul vr_stop(sc); 168741502Swpaul } 168841502Swpaul error = 0; 168941502Swpaul break; 169041502Swpaul case SIOCADDMULTI: 169141502Swpaul case SIOCDELMULTI: 169241502Swpaul vr_setmulti(sc); 169341502Swpaul error = 0; 169441502Swpaul break; 169541502Swpaul case SIOCGIFMEDIA: 169641502Swpaul case SIOCSIFMEDIA: 169751432Swpaul mii = device_get_softc(sc->vr_miibus); 169851432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 169941502Swpaul break; 170041502Swpaul default: 1701106936Ssam error = ether_ioctl(ifp, command, data); 170241502Swpaul break; 170341502Swpaul } 170441502Swpaul 170567087Swpaul VR_UNLOCK(sc); 170641502Swpaul 170741502Swpaul return(error); 170841502Swpaul} 170941502Swpaul 1710102336Salfredstatic void 1711102336Salfredvr_watchdog(ifp) 171241502Swpaul struct ifnet *ifp; 171341502Swpaul{ 171441502Swpaul struct vr_softc *sc; 171541502Swpaul 171641502Swpaul sc = ifp->if_softc; 171741502Swpaul 171867087Swpaul VR_LOCK(sc); 171941502Swpaul ifp->if_oerrors++; 172041502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 172141502Swpaul 172241502Swpaul vr_stop(sc); 172341502Swpaul vr_reset(sc); 172441502Swpaul vr_init(sc); 172541502Swpaul 172641502Swpaul if (ifp->if_snd.ifq_head != NULL) 172741502Swpaul vr_start(ifp); 172841502Swpaul 172967087Swpaul VR_UNLOCK(sc); 173067087Swpaul 173141502Swpaul return; 173241502Swpaul} 173341502Swpaul 173441502Swpaul/* 173541502Swpaul * Stop the adapter and free any mbufs allocated to the 173641502Swpaul * RX and TX lists. 173741502Swpaul */ 1738102336Salfredstatic void 1739102336Salfredvr_stop(sc) 174041502Swpaul struct vr_softc *sc; 174141502Swpaul{ 174241502Swpaul register int i; 174341502Swpaul struct ifnet *ifp; 174441502Swpaul 174567087Swpaul VR_LOCK(sc); 174667087Swpaul 174741502Swpaul ifp = &sc->arpcom.ac_if; 174841502Swpaul ifp->if_timer = 0; 174941502Swpaul 175051432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 175151432Swpaul 175241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 175341502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 175441502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 175541502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 175641502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 175741502Swpaul 175841502Swpaul /* 175941502Swpaul * Free data in the RX lists. 176041502Swpaul */ 176141502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 176241502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 176341502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 176441502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 176541502Swpaul } 176641502Swpaul } 176741502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 176841502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 176941502Swpaul 177041502Swpaul /* 177141502Swpaul * Free the TX list buffers. 177241502Swpaul */ 177341502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 177441502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 177541502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 177641502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 177741502Swpaul } 177841502Swpaul } 177941502Swpaul 178041502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 178141502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 178241502Swpaul 178341502Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 178467087Swpaul VR_UNLOCK(sc); 178541502Swpaul 178641502Swpaul return; 178741502Swpaul} 178841502Swpaul 178941502Swpaul/* 179041502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 179141502Swpaul * get confused by errant DMAs when rebooting. 179241502Swpaul */ 1793102336Salfredstatic void 1794102336Salfredvr_shutdown(dev) 179549610Swpaul device_t dev; 179641502Swpaul{ 179749610Swpaul struct vr_softc *sc; 179841502Swpaul 179949610Swpaul sc = device_get_softc(dev); 180049610Swpaul 180141502Swpaul vr_stop(sc); 180241502Swpaul 180341502Swpaul return; 180441502Swpaul} 1805