if_vr.c revision 113274
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 113274 2003-04-09 02:21:54Z silby $"); 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 9141502Swpaul#include <pci/pcireg.h> 9241502Swpaul#include <pci/pcivar.h> 9341502Swpaul 9441502Swpaul#define VR_USEIOSPACE 9541502Swpaul 9641502Swpaul#include <pci/if_vrreg.h> 9741502Swpaul 9859758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 9959758Speter 10051432Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 10151432Swpaul#include "miibus_if.h" 10251432Swpaul 103110168Ssilby#undef VR_USESWSHIFT 104110168Ssilby 10541502Swpaul/* 10641502Swpaul * Various supported device vendors/types and their names. 10741502Swpaul */ 10841502Swpaulstatic struct vr_type vr_devs[] = { 10941502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 11041502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 11141502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11241502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11362653Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 11462653Swpaul "VIA VT6102 Rhine II 10/100BaseTX" }, 115110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III, 116110170Ssilby "VIA VT6105 Rhine III 10/100BaseTX" }, 117110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, 118110170Ssilby "VIA VT6105M Rhine III 10/100BaseTX" }, 11944238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 12044238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 12144238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 12244238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 12341502Swpaul { 0, 0, NULL } 12441502Swpaul}; 12541502Swpaul 12692739Salfredstatic int vr_probe (device_t); 12792739Salfredstatic int vr_attach (device_t); 12892739Salfredstatic int vr_detach (device_t); 12941502Swpaul 13092739Salfredstatic int vr_newbuf (struct vr_softc *, 13149610Swpaul struct vr_chain_onefrag *, 13292739Salfred struct mbuf *); 13392739Salfredstatic int vr_encap (struct vr_softc *, struct vr_chain *, 13492739Salfred struct mbuf * ); 13541502Swpaul 13692739Salfredstatic void vr_rxeof (struct vr_softc *); 13792739Salfredstatic void vr_rxeoc (struct vr_softc *); 13892739Salfredstatic void vr_txeof (struct vr_softc *); 13992739Salfredstatic void vr_txeoc (struct vr_softc *); 14092739Salfredstatic void vr_tick (void *); 14192739Salfredstatic void vr_intr (void *); 14292739Salfredstatic void vr_start (struct ifnet *); 14392739Salfredstatic int vr_ioctl (struct ifnet *, u_long, caddr_t); 14492739Salfredstatic void vr_init (void *); 14592739Salfredstatic void vr_stop (struct vr_softc *); 14692739Salfredstatic void vr_watchdog (struct ifnet *); 14792739Salfredstatic void vr_shutdown (device_t); 14892739Salfredstatic int vr_ifmedia_upd (struct ifnet *); 14992739Salfredstatic void vr_ifmedia_sts (struct ifnet *, struct ifmediareq *); 15041502Swpaul 151110168Ssilby#ifdef VR_USESWSHIFT 15292739Salfredstatic void vr_mii_sync (struct vr_softc *); 15392739Salfredstatic void vr_mii_send (struct vr_softc *, u_int32_t, int); 154110168Ssilby#endif 15592739Salfredstatic int vr_mii_readreg (struct vr_softc *, struct vr_mii_frame *); 15692739Salfredstatic int vr_mii_writereg (struct vr_softc *, struct vr_mii_frame *); 15792739Salfredstatic int vr_miibus_readreg (device_t, int, int); 15892739Salfredstatic int vr_miibus_writereg (device_t, int, int, int); 15992739Salfredstatic void vr_miibus_statchg (device_t); 16041502Swpaul 16192739Salfredstatic void vr_setcfg (struct vr_softc *, int); 16292739Salfredstatic u_int8_t vr_calchash (u_int8_t *); 16392739Salfredstatic void vr_setmulti (struct vr_softc *); 16492739Salfredstatic void vr_reset (struct vr_softc *); 16592739Salfredstatic int vr_list_rx_init (struct vr_softc *); 16692739Salfredstatic int vr_list_tx_init (struct vr_softc *); 16741502Swpaul 16849610Swpaul#ifdef VR_USEIOSPACE 16949610Swpaul#define VR_RES SYS_RES_IOPORT 17049610Swpaul#define VR_RID VR_PCI_LOIO 17149610Swpaul#else 17249610Swpaul#define VR_RES SYS_RES_MEMORY 17349610Swpaul#define VR_RID VR_PCI_LOMEM 17449610Swpaul#endif 17549610Swpaul 17649610Swpaulstatic device_method_t vr_methods[] = { 17749610Swpaul /* Device interface */ 17849610Swpaul DEVMETHOD(device_probe, vr_probe), 17949610Swpaul DEVMETHOD(device_attach, vr_attach), 18049610Swpaul DEVMETHOD(device_detach, vr_detach), 18149610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 18251432Swpaul 18351432Swpaul /* bus interface */ 18451432Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 18551432Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 18651432Swpaul 18751432Swpaul /* MII interface */ 18851432Swpaul DEVMETHOD(miibus_readreg, vr_miibus_readreg), 18951432Swpaul DEVMETHOD(miibus_writereg, vr_miibus_writereg), 19051432Swpaul DEVMETHOD(miibus_statchg, vr_miibus_statchg), 19151432Swpaul 19249610Swpaul { 0, 0 } 19349610Swpaul}; 19449610Swpaul 19549610Swpaulstatic driver_t vr_driver = { 19651455Swpaul "vr", 19749610Swpaul vr_methods, 19849610Swpaul sizeof(struct vr_softc) 19949610Swpaul}; 20049610Swpaul 20149610Swpaulstatic devclass_t vr_devclass; 20249610Swpaul 20351533SwpaulDRIVER_MODULE(if_vr, pci, vr_driver, vr_devclass, 0, 0); 20451473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0); 20549610Swpaul 20641502Swpaul#define VR_SETBIT(sc, reg, x) \ 20741502Swpaul CSR_WRITE_1(sc, reg, \ 208105221Sphk CSR_READ_1(sc, reg) | (x)) 20941502Swpaul 21041502Swpaul#define VR_CLRBIT(sc, reg, x) \ 21141502Swpaul CSR_WRITE_1(sc, reg, \ 212105221Sphk CSR_READ_1(sc, reg) & ~(x)) 21341502Swpaul 21441502Swpaul#define VR_SETBIT16(sc, reg, x) \ 21541502Swpaul CSR_WRITE_2(sc, reg, \ 216105221Sphk CSR_READ_2(sc, reg) | (x)) 21741502Swpaul 21841502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 21941502Swpaul CSR_WRITE_2(sc, reg, \ 220105221Sphk CSR_READ_2(sc, reg) & ~(x)) 22141502Swpaul 22241502Swpaul#define VR_SETBIT32(sc, reg, x) \ 22341502Swpaul CSR_WRITE_4(sc, reg, \ 224105221Sphk CSR_READ_4(sc, reg) | (x)) 22541502Swpaul 22641502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 22741502Swpaul CSR_WRITE_4(sc, reg, \ 228105221Sphk CSR_READ_4(sc, reg) & ~(x)) 22941502Swpaul 23041502Swpaul#define SIO_SET(x) \ 23141502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 232105221Sphk CSR_READ_1(sc, VR_MIICMD) | (x)) 23341502Swpaul 23441502Swpaul#define SIO_CLR(x) \ 23541502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 236105221Sphk CSR_READ_1(sc, VR_MIICMD) & ~(x)) 23741502Swpaul 238110168Ssilby#ifdef VR_USESWSHIFT 23941502Swpaul/* 24041502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 24141502Swpaul */ 242102336Salfredstatic void 243102336Salfredvr_mii_sync(sc) 24441502Swpaul struct vr_softc *sc; 24541502Swpaul{ 24641502Swpaul register int i; 24741502Swpaul 24841502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 24941502Swpaul 25041502Swpaul for (i = 0; i < 32; i++) { 25141502Swpaul SIO_SET(VR_MIICMD_CLK); 25241502Swpaul DELAY(1); 25341502Swpaul SIO_CLR(VR_MIICMD_CLK); 25441502Swpaul DELAY(1); 25541502Swpaul } 25641502Swpaul 25741502Swpaul return; 25841502Swpaul} 25941502Swpaul 26041502Swpaul/* 26141502Swpaul * Clock a series of bits through the MII. 26241502Swpaul */ 263102336Salfredstatic void 264102336Salfredvr_mii_send(sc, bits, cnt) 26541502Swpaul struct vr_softc *sc; 26641502Swpaul u_int32_t bits; 26741502Swpaul int cnt; 26841502Swpaul{ 26941502Swpaul int i; 27041502Swpaul 27141502Swpaul SIO_CLR(VR_MIICMD_CLK); 27241502Swpaul 27341502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 27441502Swpaul if (bits & i) { 27541502Swpaul SIO_SET(VR_MIICMD_DATAIN); 27641502Swpaul } else { 27741502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 27841502Swpaul } 27941502Swpaul DELAY(1); 28041502Swpaul SIO_CLR(VR_MIICMD_CLK); 28141502Swpaul DELAY(1); 28241502Swpaul SIO_SET(VR_MIICMD_CLK); 28341502Swpaul } 28441502Swpaul} 285110168Ssilby#endif 28641502Swpaul 28741502Swpaul/* 28841502Swpaul * Read an PHY register through the MII. 28941502Swpaul */ 290102336Salfredstatic int 291102336Salfredvr_mii_readreg(sc, frame) 29241502Swpaul struct vr_softc *sc; 29341502Swpaul struct vr_mii_frame *frame; 29441502Swpaul 295110168Ssilby#ifdef VR_USESWSHIFT 29641502Swpaul{ 29767087Swpaul int i, ack; 29841502Swpaul 29967087Swpaul VR_LOCK(sc); 30041502Swpaul 30141502Swpaul /* 30241502Swpaul * Set up frame for RX. 30341502Swpaul */ 30441502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 30541502Swpaul frame->mii_opcode = VR_MII_READOP; 30641502Swpaul frame->mii_turnaround = 0; 30741502Swpaul frame->mii_data = 0; 30841502Swpaul 30941502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 31041502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 31141502Swpaul 31241502Swpaul /* 31341502Swpaul * Turn on data xmit. 31441502Swpaul */ 31541502Swpaul SIO_SET(VR_MIICMD_DIR); 31641502Swpaul 31741502Swpaul vr_mii_sync(sc); 31841502Swpaul 31941502Swpaul /* 32041502Swpaul * Send command/address info. 32141502Swpaul */ 32241502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 32341502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 32441502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 32541502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 32641502Swpaul 32741502Swpaul /* Idle bit */ 32841502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 32941502Swpaul DELAY(1); 33041502Swpaul SIO_SET(VR_MIICMD_CLK); 33141502Swpaul DELAY(1); 33241502Swpaul 33341502Swpaul /* Turn off xmit. */ 33441502Swpaul SIO_CLR(VR_MIICMD_DIR); 33541502Swpaul 33641502Swpaul /* Check for ack */ 33741502Swpaul SIO_CLR(VR_MIICMD_CLK); 33841502Swpaul DELAY(1); 339109058Smbr ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 34041502Swpaul SIO_SET(VR_MIICMD_CLK); 34141502Swpaul DELAY(1); 34241502Swpaul 34341502Swpaul /* 34441502Swpaul * Now try reading data bits. If the ack failed, we still 34541502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 34641502Swpaul */ 34741502Swpaul if (ack) { 34841502Swpaul for(i = 0; i < 16; i++) { 34941502Swpaul SIO_CLR(VR_MIICMD_CLK); 35041502Swpaul DELAY(1); 35141502Swpaul SIO_SET(VR_MIICMD_CLK); 35241502Swpaul DELAY(1); 35341502Swpaul } 35441502Swpaul goto fail; 35541502Swpaul } 35641502Swpaul 35741502Swpaul for (i = 0x8000; i; i >>= 1) { 35841502Swpaul SIO_CLR(VR_MIICMD_CLK); 35941502Swpaul DELAY(1); 36041502Swpaul if (!ack) { 36141502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 36241502Swpaul frame->mii_data |= i; 36341502Swpaul DELAY(1); 36441502Swpaul } 36541502Swpaul SIO_SET(VR_MIICMD_CLK); 36641502Swpaul DELAY(1); 36741502Swpaul } 36841502Swpaul 36941502Swpaulfail: 37041502Swpaul 37141502Swpaul SIO_CLR(VR_MIICMD_CLK); 37241502Swpaul DELAY(1); 37341502Swpaul SIO_SET(VR_MIICMD_CLK); 37441502Swpaul DELAY(1); 37541502Swpaul 37667087Swpaul VR_UNLOCK(sc); 37741502Swpaul 37841502Swpaul if (ack) 37941502Swpaul return(1); 38041502Swpaul return(0); 38141502Swpaul} 382110168Ssilby#else 383110168Ssilby{ 384110168Ssilby int s, i; 38541502Swpaul 386110168Ssilby s = splimp(); 387110168Ssilby 388110168Ssilby /* Set the PHY-adress */ 389110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 390110168Ssilby frame->mii_phyaddr); 391110168Ssilby 392110168Ssilby /* Set the register-adress */ 393110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 394110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB); 395110168Ssilby 396110168Ssilby for (i = 0; i < 10000; i++) { 397110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0) 398110168Ssilby break; 399110168Ssilby DELAY(1); 400110168Ssilby } 401110168Ssilby 402110168Ssilby frame->mii_data = CSR_READ_2(sc, VR_MIIDATA); 403110168Ssilby 404110168Ssilby (void)splx(s); 405110168Ssilby 406110168Ssilby return(0); 407110168Ssilby} 408110168Ssilby#endif 409110168Ssilby 410110168Ssilby 41141502Swpaul/* 41241502Swpaul * Write to a PHY register through the MII. 41341502Swpaul */ 414102336Salfredstatic int 415102336Salfredvr_mii_writereg(sc, frame) 41641502Swpaul struct vr_softc *sc; 41741502Swpaul struct vr_mii_frame *frame; 41841502Swpaul 419110168Ssilby#ifdef VR_USESWSHIFT 42041502Swpaul{ 42167087Swpaul VR_LOCK(sc); 42241502Swpaul 42341502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 42441502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 42541502Swpaul 42641502Swpaul /* 42741502Swpaul * Set up frame for TX. 42841502Swpaul */ 42941502Swpaul 43041502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 43141502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 43241502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 43341502Swpaul 43441502Swpaul /* 43541502Swpaul * Turn on data output. 43641502Swpaul */ 43741502Swpaul SIO_SET(VR_MIICMD_DIR); 43841502Swpaul 43941502Swpaul vr_mii_sync(sc); 44041502Swpaul 44141502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 44241502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 44341502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 44441502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 44541502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 44641502Swpaul vr_mii_send(sc, frame->mii_data, 16); 44741502Swpaul 44841502Swpaul /* Idle bit. */ 44941502Swpaul SIO_SET(VR_MIICMD_CLK); 45041502Swpaul DELAY(1); 45141502Swpaul SIO_CLR(VR_MIICMD_CLK); 45241502Swpaul DELAY(1); 45341502Swpaul 45441502Swpaul /* 45541502Swpaul * Turn off xmit. 45641502Swpaul */ 45741502Swpaul SIO_CLR(VR_MIICMD_DIR); 45841502Swpaul 45967087Swpaul VR_UNLOCK(sc); 46041502Swpaul 46141502Swpaul return(0); 46241502Swpaul} 463110168Ssilby#else 464110168Ssilby{ 465110168Ssilby int s, i; 46641502Swpaul 467110168Ssilby s = splimp(); 468110168Ssilby 469110168Ssilby /* Set the PHY-adress */ 470110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 471110168Ssilby frame->mii_phyaddr); 472110168Ssilby 473110168Ssilby /* Set the register-adress and data to write */ 474110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 475110168Ssilby CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data); 476110168Ssilby 477110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB); 478110168Ssilby 479110168Ssilby for (i = 0; i < 10000; i++) { 480110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0) 481110168Ssilby break; 482110168Ssilby DELAY(1); 483110168Ssilby } 484110168Ssilby 485110168Ssilby (void)splx(s); 486110168Ssilby 487110168Ssilby return(0); 488110168Ssilby} 489110168Ssilby#endif 490110168Ssilby 491102336Salfredstatic int 492102336Salfredvr_miibus_readreg(dev, phy, reg) 49351432Swpaul device_t dev; 49451432Swpaul int phy, reg; 49551432Swpaul{ 49641502Swpaul struct vr_softc *sc; 49741502Swpaul struct vr_mii_frame frame; 49841502Swpaul 49951432Swpaul sc = device_get_softc(dev); 500110168Ssilby 501110168Ssilby switch (sc->vr_revid) { 502110168Ssilby case REV_ID_VT6102_APOLLO: 503110168Ssilby if (phy != 1) 504110168Ssilby return 0; 505110168Ssilby default: 506110168Ssilby break; 507110168Ssilby } 508110168Ssilby 50941502Swpaul bzero((char *)&frame, sizeof(frame)); 51041502Swpaul 51151432Swpaul frame.mii_phyaddr = phy; 51241502Swpaul frame.mii_regaddr = reg; 51341502Swpaul vr_mii_readreg(sc, &frame); 51441502Swpaul 51541502Swpaul return(frame.mii_data); 51641502Swpaul} 51741502Swpaul 518102336Salfredstatic int 519102336Salfredvr_miibus_writereg(dev, phy, reg, data) 52051432Swpaul device_t dev; 52151432Swpaul u_int16_t phy, reg, data; 52251432Swpaul{ 52341502Swpaul struct vr_softc *sc; 52441502Swpaul struct vr_mii_frame frame; 52541502Swpaul 52651432Swpaul sc = device_get_softc(dev); 527110168Ssilby 528110168Ssilby switch (sc->vr_revid) { 529110168Ssilby case REV_ID_VT6102_APOLLO: 530110168Ssilby if (phy != 1) 531110168Ssilby return 0; 532110168Ssilby default: 533110168Ssilby break; 534110168Ssilby } 535110168Ssilby 53641502Swpaul bzero((char *)&frame, sizeof(frame)); 53741502Swpaul 53851432Swpaul frame.mii_phyaddr = phy; 53941502Swpaul frame.mii_regaddr = reg; 54041502Swpaul frame.mii_data = data; 54141502Swpaul 54241502Swpaul vr_mii_writereg(sc, &frame); 54341502Swpaul 54451432Swpaul return(0); 54551432Swpaul} 54651432Swpaul 547102336Salfredstatic void 548102336Salfredvr_miibus_statchg(dev) 54951432Swpaul device_t dev; 55051432Swpaul{ 55151432Swpaul struct vr_softc *sc; 55251432Swpaul struct mii_data *mii; 55351432Swpaul 55451432Swpaul sc = device_get_softc(dev); 55567087Swpaul VR_LOCK(sc); 55651432Swpaul mii = device_get_softc(sc->vr_miibus); 55751432Swpaul vr_setcfg(sc, mii->mii_media_active); 55867087Swpaul VR_UNLOCK(sc); 55951432Swpaul 56041502Swpaul return; 56141502Swpaul} 56241502Swpaul 56341502Swpaul/* 56441502Swpaul * Calculate CRC of a multicast group address, return the lower 6 bits. 56541502Swpaul */ 56641502Swpaulstatic u_int8_t vr_calchash(addr) 56741502Swpaul u_int8_t *addr; 56841502Swpaul{ 56941502Swpaul u_int32_t crc, carry; 57041502Swpaul int i, j; 57141502Swpaul u_int8_t c; 57241502Swpaul 57341502Swpaul /* Compute CRC for the address value. */ 57441502Swpaul crc = 0xFFFFFFFF; /* initial value */ 57541502Swpaul 57641502Swpaul for (i = 0; i < 6; i++) { 57741502Swpaul c = *(addr + i); 57841502Swpaul for (j = 0; j < 8; j++) { 57941502Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 58041502Swpaul crc <<= 1; 58141502Swpaul c >>= 1; 58241502Swpaul if (carry) 58341502Swpaul crc = (crc ^ 0x04c11db6) | carry; 58441502Swpaul } 58541502Swpaul } 58641502Swpaul 58741502Swpaul /* return the filter bit position */ 58841502Swpaul return((crc >> 26) & 0x0000003F); 58941502Swpaul} 59041502Swpaul 59141502Swpaul/* 59241502Swpaul * Program the 64-bit multicast hash filter. 59341502Swpaul */ 594102336Salfredstatic void 595102336Salfredvr_setmulti(sc) 59641502Swpaul struct vr_softc *sc; 59741502Swpaul{ 59841502Swpaul struct ifnet *ifp; 59941502Swpaul int h = 0; 60041502Swpaul u_int32_t hashes[2] = { 0, 0 }; 60141502Swpaul struct ifmultiaddr *ifma; 60241502Swpaul u_int8_t rxfilt; 60341502Swpaul int mcnt = 0; 60441502Swpaul 60541502Swpaul ifp = &sc->arpcom.ac_if; 60641502Swpaul 60741502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 60841502Swpaul 60941502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 61041502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 61141502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 61241502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 61341502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 61441502Swpaul return; 61541502Swpaul } 61641502Swpaul 61741502Swpaul /* first, zot all the existing hash bits */ 61841502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 61941502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 62041502Swpaul 62141502Swpaul /* now program new ones */ 62272084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 62341502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 62441502Swpaul continue; 62541502Swpaul h = vr_calchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 62641502Swpaul if (h < 32) 62741502Swpaul hashes[0] |= (1 << h); 62841502Swpaul else 62941502Swpaul hashes[1] |= (1 << (h - 32)); 63041502Swpaul mcnt++; 63141502Swpaul } 63241502Swpaul 63341502Swpaul if (mcnt) 63441502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 63541502Swpaul else 63641502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 63741502Swpaul 63841502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 63941502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 64041502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 64141502Swpaul 64241502Swpaul return; 64341502Swpaul} 64441502Swpaul 64541502Swpaul/* 64641502Swpaul * In order to fiddle with the 64741502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 64841502Swpaul * first have to put the transmit and/or receive logic in the idle state. 64941502Swpaul */ 650102336Salfredstatic void 651102336Salfredvr_setcfg(sc, media) 65241502Swpaul struct vr_softc *sc; 65351432Swpaul int media; 65441502Swpaul{ 65541502Swpaul int restart = 0; 65641502Swpaul 65741502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 65841502Swpaul restart = 1; 65941502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 66041502Swpaul } 66141502Swpaul 66251432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 66341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 66441502Swpaul else 66541502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 66641502Swpaul 66741502Swpaul if (restart) 66841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 66941502Swpaul 67041502Swpaul return; 67141502Swpaul} 67241502Swpaul 673102336Salfredstatic void 674102336Salfredvr_reset(sc) 67541502Swpaul struct vr_softc *sc; 67641502Swpaul{ 67741502Swpaul register int i; 67841502Swpaul 67941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 68041502Swpaul 68141502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 68241502Swpaul DELAY(10); 68341502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 68441502Swpaul break; 68541502Swpaul } 686107220Ssilby if (i == VR_TIMEOUT) { 687107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 688107220Ssilby printf("vr%d: reset never completed!\n", sc->vr_unit); 689107220Ssilby else { 690107220Ssilby /* Use newer force reset command */ 691107220Ssilby printf("vr%d: Using force reset command.\n", sc->vr_unit); 692107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 693107220Ssilby } 694107220Ssilby } 69541502Swpaul 69641502Swpaul /* Wait a little while for the chip to get its brains in order. */ 69741502Swpaul DELAY(1000); 69841502Swpaul 69941502Swpaul return; 70041502Swpaul} 70141502Swpaul 70241502Swpaul/* 70341502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 70441502Swpaul * IDs against our list and return a device name if we find a match. 70541502Swpaul */ 706102336Salfredstatic int 707102336Salfredvr_probe(dev) 70849610Swpaul device_t dev; 70941502Swpaul{ 71041502Swpaul struct vr_type *t; 71141502Swpaul 71241502Swpaul t = vr_devs; 71341502Swpaul 71441502Swpaul while(t->vr_name != NULL) { 71549610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 71649610Swpaul (pci_get_device(dev) == t->vr_did)) { 71749610Swpaul device_set_desc(dev, t->vr_name); 71849610Swpaul return(0); 71941502Swpaul } 72041502Swpaul t++; 72141502Swpaul } 72241502Swpaul 72349610Swpaul return(ENXIO); 72441502Swpaul} 72541502Swpaul 72641502Swpaul/* 72741502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 72841502Swpaul * setup and ethernet/BPF attach. 72941502Swpaul */ 730102336Salfredstatic int 731102336Salfredvr_attach(dev) 73249610Swpaul device_t dev; 73341502Swpaul{ 73467087Swpaul int i; 73541502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 73641502Swpaul u_int32_t command; 73741502Swpaul struct vr_softc *sc; 73841502Swpaul struct ifnet *ifp; 73949610Swpaul int unit, error = 0, rid; 74041502Swpaul 74149610Swpaul sc = device_get_softc(dev); 74249610Swpaul unit = device_get_unit(dev); 74341502Swpaul 74493818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 74593818Sjhb MTX_DEF | MTX_RECURSE); 74669583Swpaul 74741502Swpaul /* 74841502Swpaul * Handle power management nonsense. 74941502Swpaul */ 75072813Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 75172813Swpaul u_int32_t iobase, membase, irq; 75241502Swpaul 75372813Swpaul /* Save important PCI config data. */ 75472813Swpaul iobase = pci_read_config(dev, VR_PCI_LOIO, 4); 75572813Swpaul membase = pci_read_config(dev, VR_PCI_LOMEM, 4); 75672813Swpaul irq = pci_read_config(dev, VR_PCI_INTLINE, 4); 75741502Swpaul 75872813Swpaul /* Reset the power state. */ 75972813Swpaul printf("vr%d: chip is in D%d power mode " 76072813Swpaul "-- setting to D0\n", unit, 76172813Swpaul pci_get_powerstate(dev)); 76272813Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 76341502Swpaul 76441502Swpaul /* Restore PCI config data. */ 76572813Swpaul pci_write_config(dev, VR_PCI_LOIO, iobase, 4); 76672813Swpaul pci_write_config(dev, VR_PCI_LOMEM, membase, 4); 76772813Swpaul pci_write_config(dev, VR_PCI_INTLINE, irq, 4); 76841502Swpaul } 76941502Swpaul 77041502Swpaul /* 77141502Swpaul * Map control/status registers. 77241502Swpaul */ 77372813Swpaul pci_enable_busmaster(dev); 77479472Swpaul pci_enable_io(dev, SYS_RES_IOPORT); 77579472Swpaul pci_enable_io(dev, SYS_RES_MEMORY); 77661041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 777107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 77841502Swpaul 77941502Swpaul#ifdef VR_USEIOSPACE 78041502Swpaul if (!(command & PCIM_CMD_PORTEN)) { 78141502Swpaul printf("vr%d: failed to enable I/O ports!\n", unit); 782112872Snjl error = ENXIO; 78341502Swpaul goto fail; 78441502Swpaul } 78541502Swpaul#else 78641502Swpaul if (!(command & PCIM_CMD_MEMEN)) { 78741502Swpaul printf("vr%d: failed to enable memory mapping!\n", unit); 788112872Snjl error = ENXIO; 78941502Swpaul goto fail; 79041502Swpaul } 79149610Swpaul#endif 79241502Swpaul 79349610Swpaul rid = VR_RID; 79449610Swpaul sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid, 79549610Swpaul 0, ~0, 1, RF_ACTIVE); 79649610Swpaul 79749610Swpaul if (sc->vr_res == NULL) { 79849610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 79949610Swpaul error = ENXIO; 80041502Swpaul goto fail; 80141502Swpaul } 80241502Swpaul 80349610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 80449610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 80541502Swpaul 80641502Swpaul /* Allocate interrupt */ 80749610Swpaul rid = 0; 80849610Swpaul sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 80949610Swpaul RF_SHAREABLE | RF_ACTIVE); 81049610Swpaul 81149610Swpaul if (sc->vr_irq == NULL) { 81241502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 81349610Swpaul error = ENXIO; 81441502Swpaul goto fail; 81541502Swpaul } 81641502Swpaul 81776586Swpaul /* 81876586Swpaul * Windows may put the chip in suspend mode when it 81976586Swpaul * shuts down. Be sure to kick it in the head to wake it 82076586Swpaul * up again. 82176586Swpaul */ 82276586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 82376586Swpaul 82441502Swpaul /* Reset the adapter. */ 82541502Swpaul vr_reset(sc); 82641502Swpaul 827110168Ssilby /* 828110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 829110168Ssilby * initialization and disable AUTOPOLL. 830110168Ssilby */ 831110168Ssilby pci_write_config(dev, VR_PCI_MODE, 832110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 833110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 834110168Ssilby 83541502Swpaul /* 83641502Swpaul * Get station address. The way the Rhine chips work, 83741502Swpaul * you're not allowed to directly access the EEPROM once 83841502Swpaul * they've been programmed a special way. Consequently, 83941502Swpaul * we need to read the node address from the PAR0 and PAR1 84041502Swpaul * registers. 84141502Swpaul */ 84241502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 84341502Swpaul DELAY(200); 84441502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 84541502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 84641502Swpaul 84741502Swpaul /* 84841502Swpaul * A Rhine chip was detected. Inform the world. 84941502Swpaul */ 85041502Swpaul printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); 85141502Swpaul 85241502Swpaul sc->vr_unit = unit; 85341502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 85441502Swpaul 85551432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 85651657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 85751432Swpaul 85851432Swpaul if (sc->vr_ldata == NULL) { 85941502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 86049610Swpaul error = ENXIO; 86149610Swpaul goto fail; 86241502Swpaul } 86341502Swpaul 86441502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 86541502Swpaul 86641502Swpaul ifp = &sc->arpcom.ac_if; 86741502Swpaul ifp->if_softc = sc; 86841502Swpaul ifp->if_unit = unit; 86941502Swpaul ifp->if_name = "vr"; 87041502Swpaul ifp->if_mtu = ETHERMTU; 87141502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 87241502Swpaul ifp->if_ioctl = vr_ioctl; 87341502Swpaul ifp->if_output = ether_output; 87441502Swpaul ifp->if_start = vr_start; 87541502Swpaul ifp->if_watchdog = vr_watchdog; 87641502Swpaul ifp->if_init = vr_init; 87741502Swpaul ifp->if_baudrate = 10000000; 87843515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 87941502Swpaul 88051432Swpaul /* 88151432Swpaul * Do MII setup. 88251432Swpaul */ 88351432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 88451432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 88541502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 88649610Swpaul error = ENXIO; 88741502Swpaul goto fail; 88841502Swpaul } 88941502Swpaul 89051432Swpaul callout_handle_init(&sc->vr_stat_ch); 89141502Swpaul 89241502Swpaul /* 89363090Sarchie * Call MI attach routine. 89441502Swpaul */ 895106936Ssam ether_ifattach(ifp, eaddr); 89641502Swpaul 897112872Snjl error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET, 898112872Snjl vr_intr, sc, &sc->vr_intrhand); 899112872Snjl 900112872Snjl if (error) { 901112872Snjl printf("vr%d: couldn't set up irq\n", unit); 902112872Snjl goto fail; 903112872Snjl } 904112872Snjl 90541502Swpaulfail: 906112872Snjl if (error) 907112872Snjl vr_detach(dev); 90867087Swpaul 90949610Swpaul return(error); 91041502Swpaul} 91141502Swpaul 912102336Salfredstatic int 913102336Salfredvr_detach(dev) 91449610Swpaul device_t dev; 91549610Swpaul{ 91649610Swpaul struct vr_softc *sc; 91749610Swpaul struct ifnet *ifp; 91849610Swpaul 91949610Swpaul sc = device_get_softc(dev); 920112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 92167087Swpaul VR_LOCK(sc); 92249610Swpaul ifp = &sc->arpcom.ac_if; 92349610Swpaul 924112872Snjl if (device_is_alive(dev)) { 925112872Snjl if (bus_child_present(dev)) 926112872Snjl vr_stop(sc); 927112872Snjl ether_ifdetach(ifp); 928112872Snjl device_delete_child(dev, sc->vr_miibus); 929112872Snjl bus_generic_detach(dev); 930112872Snjl } 93149610Swpaul 932112872Snjl if (sc->vr_intrhand) 933112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 934112872Snjl if (sc->vr_irq) 935112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 936112872Snjl if (sc->vr_res) 937112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 93851432Swpaul 939112872Snjl if (sc->vr_ldata) 940112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 94149610Swpaul 94267087Swpaul VR_UNLOCK(sc); 94367087Swpaul mtx_destroy(&sc->vr_mtx); 94449610Swpaul 94549610Swpaul return(0); 94649610Swpaul} 94749610Swpaul 94841502Swpaul/* 94941502Swpaul * Initialize the transmit descriptors. 95041502Swpaul */ 951102336Salfredstatic int 952102336Salfredvr_list_tx_init(sc) 95341502Swpaul struct vr_softc *sc; 95441502Swpaul{ 95541502Swpaul struct vr_chain_data *cd; 95641502Swpaul struct vr_list_data *ld; 95741502Swpaul int i; 95841502Swpaul 95941502Swpaul cd = &sc->vr_cdata; 96041502Swpaul ld = sc->vr_ldata; 96141502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 96241502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 96341502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 96441502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 96541502Swpaul &cd->vr_tx_chain[0]; 96641502Swpaul else 96741502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 96841502Swpaul &cd->vr_tx_chain[i + 1]; 96941502Swpaul } 97041502Swpaul 97141502Swpaul cd->vr_tx_free = &cd->vr_tx_chain[0]; 97241502Swpaul cd->vr_tx_tail = cd->vr_tx_head = NULL; 97341502Swpaul 97441502Swpaul return(0); 97541502Swpaul} 97641502Swpaul 97741502Swpaul 97841502Swpaul/* 97941502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 98041502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 98141502Swpaul * points back to the first. 98241502Swpaul */ 983102336Salfredstatic int 984102336Salfredvr_list_rx_init(sc) 98541502Swpaul struct vr_softc *sc; 98641502Swpaul{ 98741502Swpaul struct vr_chain_data *cd; 98841502Swpaul struct vr_list_data *ld; 98941502Swpaul int i; 99041502Swpaul 99141502Swpaul cd = &sc->vr_cdata; 99241502Swpaul ld = sc->vr_ldata; 99341502Swpaul 99441502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 99541502Swpaul cd->vr_rx_chain[i].vr_ptr = 99641502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 99749610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 99841502Swpaul return(ENOBUFS); 99941502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 100041502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 100141502Swpaul &cd->vr_rx_chain[0]; 100241502Swpaul ld->vr_rx_list[i].vr_next = 100341502Swpaul vtophys(&ld->vr_rx_list[0]); 100441502Swpaul } else { 100541502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 100641502Swpaul &cd->vr_rx_chain[i + 1]; 100741502Swpaul ld->vr_rx_list[i].vr_next = 100841502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 100941502Swpaul } 101041502Swpaul } 101141502Swpaul 101241502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 101341502Swpaul 101441502Swpaul return(0); 101541502Swpaul} 101641502Swpaul 101741502Swpaul/* 101841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 101941502Swpaul * Note: the length fields are only 11 bits wide, which means the 102041502Swpaul * largest size we can specify is 2047. This is important because 102141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 102241502Swpaul * overflow the field and make a mess. 102341502Swpaul */ 1024102336Salfredstatic int 1025102336Salfredvr_newbuf(sc, c, m) 102641502Swpaul struct vr_softc *sc; 102741502Swpaul struct vr_chain_onefrag *c; 102849610Swpaul struct mbuf *m; 102941502Swpaul{ 103041502Swpaul struct mbuf *m_new = NULL; 103141502Swpaul 103249610Swpaul if (m == NULL) { 1033111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 103487846Sluigi if (m_new == NULL) 103549610Swpaul return(ENOBUFS); 103641502Swpaul 1037111119Simp MCLGET(m_new, M_DONTWAIT); 103849610Swpaul if (!(m_new->m_flags & M_EXT)) { 103949610Swpaul m_freem(m_new); 104049610Swpaul return(ENOBUFS); 104149610Swpaul } 104249610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 104349610Swpaul } else { 104449610Swpaul m_new = m; 104549610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 104649610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 104741502Swpaul } 104841502Swpaul 104949610Swpaul m_adj(m_new, sizeof(u_int64_t)); 105049610Swpaul 105141502Swpaul c->vr_mbuf = m_new; 105241502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 105341502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 105442491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 105541502Swpaul 105641502Swpaul return(0); 105741502Swpaul} 105841502Swpaul 105941502Swpaul/* 106041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 106141502Swpaul * the higher level protocols. 106241502Swpaul */ 1063102336Salfredstatic void 1064102336Salfredvr_rxeof(sc) 106541502Swpaul struct vr_softc *sc; 106641502Swpaul{ 106741502Swpaul struct mbuf *m; 106841502Swpaul struct ifnet *ifp; 106941502Swpaul struct vr_chain_onefrag *cur_rx; 107041502Swpaul int total_len = 0; 107141502Swpaul u_int32_t rxstat; 107241502Swpaul 107341502Swpaul ifp = &sc->arpcom.ac_if; 107441502Swpaul 107541502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 107641502Swpaul VR_RXSTAT_OWN)) { 107749610Swpaul struct mbuf *m0 = NULL; 107849610Swpaul 107941502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 108041502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 108149610Swpaul m = cur_rx->vr_mbuf; 108241502Swpaul 108341502Swpaul /* 108441502Swpaul * If an error occurs, update stats, clear the 108541502Swpaul * status word and leave the mbuf cluster in place: 108641502Swpaul * it should simply get re-used next time this descriptor 108741502Swpaul * comes up in the ring. 108841502Swpaul */ 108941502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 109041502Swpaul ifp->if_ierrors++; 1091110131Ssilby printf("vr%d: rx error (%02x):", 1092110131Ssilby sc->vr_unit, rxstat & 0x000000ff); 1093110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 1094110131Ssilby printf(" crc error"); 1095110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 1096110131Ssilby printf(" frame alignment error\n"); 1097110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 1098110131Ssilby printf(" FIFO overflow"); 1099110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 1100110131Ssilby printf(" received giant packet"); 1101110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 1102110131Ssilby printf(" received runt packet"); 1103110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 1104110131Ssilby printf(" system bus error"); 1105110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 1106110131Ssilby printf("rx buffer error"); 1107110131Ssilby printf("\n"); 110849610Swpaul vr_newbuf(sc, cur_rx, m); 110941502Swpaul continue; 111041502Swpaul } 111141502Swpaul 111241502Swpaul /* No errors; receive the packet. */ 111341502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 111441502Swpaul 111541502Swpaul /* 111642048Swpaul * XXX The VIA Rhine chip includes the CRC with every 111742048Swpaul * received frame, and there's no way to turn this 111842048Swpaul * behavior off (at least, I can't find anything in 111942048Swpaul * the manual that explains how to do it) so we have 112042048Swpaul * to trim off the CRC manually. 112142048Swpaul */ 112242048Swpaul total_len -= ETHER_CRC_LEN; 112342048Swpaul 112478508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 112578508Sbmilekic NULL); 112649610Swpaul vr_newbuf(sc, cur_rx, m); 112749610Swpaul if (m0 == NULL) { 112841502Swpaul ifp->if_ierrors++; 112941502Swpaul continue; 113041502Swpaul } 113149610Swpaul m = m0; 113241502Swpaul 113341502Swpaul ifp->if_ipackets++; 1134106936Ssam (*ifp->if_input)(ifp, m); 113541502Swpaul } 113641502Swpaul 113741502Swpaul return; 113841502Swpaul} 113941502Swpaul 1140105221Sphkstatic void 1141102336Salfredvr_rxeoc(sc) 114241502Swpaul struct vr_softc *sc; 114341502Swpaul{ 1144110131Ssilby struct ifnet *ifp; 1145110131Ssilby int i; 114641502Swpaul 1147110131Ssilby ifp = &sc->arpcom.ac_if; 1148110131Ssilby 1149110131Ssilby ifp->if_ierrors++; 1150110131Ssilby 1151110131Ssilby VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1152110131Ssilby DELAY(10000); 1153110131Ssilby 1154110131Ssilby for (i = 0x400; 1155110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1156110131Ssilby i--) 1157110131Ssilby ; /* Wait for receiver to stop */ 1158110131Ssilby 1159110131Ssilby if (!i) { 1160110131Ssilby printf("vr%d: rx shutdown error!\n", sc->vr_unit); 1161110131Ssilby sc->vr_flags |= VR_F_RESTART; 1162110131Ssilby return; 1163110131Ssilby } 1164110131Ssilby 116541502Swpaul vr_rxeof(sc); 1166110131Ssilby 116741502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 116841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 116941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 117041502Swpaul 117141502Swpaul return; 117241502Swpaul} 117341502Swpaul 117441502Swpaul/* 117541502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 117641502Swpaul * the list buffers. 117741502Swpaul */ 117841502Swpaul 1179102336Salfredstatic void 1180102336Salfredvr_txeof(sc) 118141502Swpaul struct vr_softc *sc; 118241502Swpaul{ 118341502Swpaul struct vr_chain *cur_tx; 118441502Swpaul struct ifnet *ifp; 118541502Swpaul 118641502Swpaul ifp = &sc->arpcom.ac_if; 118741502Swpaul 118896677Ssilby /* Reset the timeout timer; if_txeoc will clear it. */ 118996677Ssilby ifp->if_timer = 5; 119041502Swpaul 119141502Swpaul /* Sanity check. */ 119241502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 119341502Swpaul return; 119441502Swpaul 119541502Swpaul /* 119641502Swpaul * Go through our tx list and free mbufs for those 119741502Swpaul * frames that have been transmitted. 119841502Swpaul */ 119941502Swpaul while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { 120041502Swpaul u_int32_t txstat; 1201110131Ssilby int i; 120241502Swpaul 120341502Swpaul cur_tx = sc->vr_cdata.vr_tx_head; 120441502Swpaul txstat = cur_tx->vr_ptr->vr_status; 120541502Swpaul 1206101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1207101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1208110131Ssilby for (i = 0x400; 1209110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1210110131Ssilby i--) 1211101896Ssilby ; /* Wait for chip to shutdown */ 1212110131Ssilby if (!i) { 1213110131Ssilby printf("vr%d: tx shutdown timeout\n", sc->vr_unit); 1214110131Ssilby sc->vr_flags |= VR_F_RESTART; 1215110131Ssilby break; 1216110131Ssilby } 1217101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1218101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1219101896Ssilby break; 1220101896Ssilby } 1221101896Ssilby 122242491Swpaul if (txstat & VR_TXSTAT_OWN) 122341502Swpaul break; 122441502Swpaul 122541502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 122641502Swpaul ifp->if_oerrors++; 122741502Swpaul if (txstat & VR_TXSTAT_DEFER) 122841502Swpaul ifp->if_collisions++; 122941502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 123041502Swpaul ifp->if_collisions++; 123141502Swpaul } 123241502Swpaul 123341502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 123441502Swpaul 123541502Swpaul ifp->if_opackets++; 123651432Swpaul if (cur_tx->vr_mbuf != NULL) { 123751432Swpaul m_freem(cur_tx->vr_mbuf); 123851432Swpaul cur_tx->vr_mbuf = NULL; 123951432Swpaul } 124041502Swpaul 124141502Swpaul if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { 124241502Swpaul sc->vr_cdata.vr_tx_head = NULL; 124341502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 124441502Swpaul break; 124541502Swpaul } 124641502Swpaul 124741502Swpaul sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; 124841502Swpaul } 124941502Swpaul 125041502Swpaul return; 125141502Swpaul} 125241502Swpaul 125341502Swpaul/* 125441502Swpaul * TX 'end of channel' interrupt handler. 125541502Swpaul */ 1256102336Salfredstatic void 1257102336Salfredvr_txeoc(sc) 125841502Swpaul struct vr_softc *sc; 125941502Swpaul{ 126041502Swpaul struct ifnet *ifp; 126141502Swpaul 126241502Swpaul ifp = &sc->arpcom.ac_if; 126341502Swpaul 126441502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) { 126541502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 126641502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 126796677Ssilby ifp->if_timer = 0; 126841502Swpaul } 126941502Swpaul 127041502Swpaul return; 127141502Swpaul} 127241502Swpaul 1273102336Salfredstatic void 1274102336Salfredvr_tick(xsc) 127551432Swpaul void *xsc; 127651432Swpaul{ 127751432Swpaul struct vr_softc *sc; 127851432Swpaul struct mii_data *mii; 127951432Swpaul 128051432Swpaul sc = xsc; 128167087Swpaul VR_LOCK(sc); 1282110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1283110131Ssilby printf("vr%d: restarting\n", sc->vr_unit); 1284110131Ssilby vr_stop(sc); 1285110131Ssilby vr_reset(sc); 1286110131Ssilby vr_init(sc); 1287110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1288110131Ssilby } 1289110131Ssilby 129051432Swpaul mii = device_get_softc(sc->vr_miibus); 129151432Swpaul mii_tick(mii); 129251432Swpaul 129351432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 129451432Swpaul 129567087Swpaul VR_UNLOCK(sc); 129651432Swpaul 129751432Swpaul return; 129851432Swpaul} 129951432Swpaul 1300102336Salfredstatic void 1301102336Salfredvr_intr(arg) 130241502Swpaul void *arg; 130341502Swpaul{ 130441502Swpaul struct vr_softc *sc; 130541502Swpaul struct ifnet *ifp; 130641502Swpaul u_int16_t status; 130741502Swpaul 130841502Swpaul sc = arg; 130967087Swpaul VR_LOCK(sc); 131041502Swpaul ifp = &sc->arpcom.ac_if; 131141502Swpaul 131241502Swpaul /* Supress unwanted interrupts. */ 131341502Swpaul if (!(ifp->if_flags & IFF_UP)) { 131441502Swpaul vr_stop(sc); 131567087Swpaul VR_UNLOCK(sc); 131641502Swpaul return; 131741502Swpaul } 131841502Swpaul 131941502Swpaul /* Disable interrupts. */ 132041502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 132141502Swpaul 132241502Swpaul for (;;) { 132341502Swpaul 132441502Swpaul status = CSR_READ_2(sc, VR_ISR); 132541502Swpaul if (status) 132641502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 132741502Swpaul 132841502Swpaul if ((status & VR_INTRS) == 0) 132941502Swpaul break; 133041502Swpaul 133141502Swpaul if (status & VR_ISR_RX_OK) 133241502Swpaul vr_rxeof(sc); 133341502Swpaul 1334110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1335110131Ssilby printf("vr%d: rx packet lost\n", sc->vr_unit); 1336110131Ssilby ifp->if_ierrors++; 1337110131Ssilby } 1338110131Ssilby 133941502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1340110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1341110131Ssilby printf("vr%d: receive error (%04x)", 1342110131Ssilby sc->vr_unit, status); 1343110131Ssilby if (status & VR_ISR_RX_NOBUF) 1344110131Ssilby printf(" no buffers"); 1345110131Ssilby if (status & VR_ISR_RX_OFLOW) 1346110131Ssilby printf(" overflow"); 1347110131Ssilby if (status & VR_ISR_RX_DROPPED) 1348110131Ssilby printf(" packet lost"); 1349110131Ssilby printf("\n"); 135041502Swpaul vr_rxeoc(sc); 135141502Swpaul } 135241502Swpaul 1353101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1354101896Ssilby vr_reset(sc); 1355101896Ssilby vr_init(sc); 1356101896Ssilby break; 135741502Swpaul } 135841502Swpaul 1359101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1360101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 136141502Swpaul vr_txeof(sc); 1362101896Ssilby if ((status & VR_ISR_UDFI) || 1363101896Ssilby (status & VR_ISR_TX_ABRT2) || 1364101896Ssilby (status & VR_ISR_TX_ABRT)) { 1365101896Ssilby ifp->if_oerrors++; 1366101896Ssilby if (sc->vr_cdata.vr_tx_head != NULL) { 1367101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1368101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1369101896Ssilby } 1370101896Ssilby } else 1371101896Ssilby vr_txeoc(sc); 137241502Swpaul } 137341502Swpaul 137441502Swpaul } 137541502Swpaul 137641502Swpaul /* Re-enable interrupts. */ 137741502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 137841502Swpaul 137941502Swpaul if (ifp->if_snd.ifq_head != NULL) { 138041502Swpaul vr_start(ifp); 138141502Swpaul } 138241502Swpaul 138367087Swpaul VR_UNLOCK(sc); 138467087Swpaul 138541502Swpaul return; 138641502Swpaul} 138741502Swpaul 138841502Swpaul/* 138941502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 139041502Swpaul * pointers to the fragment pointers. 139141502Swpaul */ 1392102336Salfredstatic int 1393102336Salfredvr_encap(sc, c, m_head) 139441502Swpaul struct vr_softc *sc; 139541502Swpaul struct vr_chain *c; 139641502Swpaul struct mbuf *m_head; 139741502Swpaul{ 139841502Swpaul int frag = 0; 139941502Swpaul struct vr_desc *f = NULL; 140041502Swpaul int total_len; 140141502Swpaul struct mbuf *m; 140241502Swpaul 140341502Swpaul m = m_head; 140441502Swpaul total_len = 0; 140541502Swpaul 140641502Swpaul /* 140741502Swpaul * The VIA Rhine wants packet buffers to be longword 140841502Swpaul * aligned, but very often our mbufs aren't. Rather than 140941502Swpaul * waste time trying to decide when to copy and when not 141041502Swpaul * to copy, just do it all the time. 141141502Swpaul */ 141241502Swpaul if (m != NULL) { 141341502Swpaul struct mbuf *m_new = NULL; 141441502Swpaul 1415112821Ssilby m_new = m_defrag(m_head, M_DONTWAIT); 141641502Swpaul if (m_new == NULL) { 141741502Swpaul return(1); 141841502Swpaul } 1419112821Ssilby 142041502Swpaul m_head = m_new; 142141502Swpaul /* 142241502Swpaul * The Rhine chip doesn't auto-pad, so we have to make 142341502Swpaul * sure to pad short frames out to the minimum frame length 142441502Swpaul * ourselves. 142541502Swpaul */ 142641502Swpaul if (m_head->m_len < VR_MIN_FRAMELEN) { 142741502Swpaul m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; 142841502Swpaul m_new->m_len = m_new->m_pkthdr.len; 142941502Swpaul } 143041502Swpaul f = c->vr_ptr; 143141502Swpaul f->vr_data = vtophys(mtod(m_new, caddr_t)); 143241502Swpaul f->vr_ctl = total_len = m_new->m_len; 143341502Swpaul f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 143441502Swpaul f->vr_status = 0; 143541502Swpaul frag = 1; 143641502Swpaul } 143741502Swpaul 143841502Swpaul c->vr_mbuf = m_head; 143942491Swpaul c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 144041502Swpaul c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 144141502Swpaul 144241502Swpaul return(0); 144341502Swpaul} 144441502Swpaul 144541502Swpaul/* 144641502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 144741502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 144841502Swpaul * copy of the pointers since the transmit list fragment pointers are 144941502Swpaul * physical addresses. 145041502Swpaul */ 145141502Swpaul 1452102336Salfredstatic void 1453102336Salfredvr_start(ifp) 145441502Swpaul struct ifnet *ifp; 145541502Swpaul{ 145641502Swpaul struct vr_softc *sc; 145741502Swpaul struct mbuf *m_head = NULL; 1458113274Ssilby struct vr_chain *cur_tx = NULL, *start_tx, *prev_tx; 145941502Swpaul 146041502Swpaul sc = ifp->if_softc; 146141502Swpaul 146267087Swpaul VR_LOCK(sc); 146341502Swpaul 146441502Swpaul /* 146541502Swpaul * Check for an available queue slot. If there are none, 146641502Swpaul * punt. 146741502Swpaul */ 146841502Swpaul if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { 1469113274Ssilby VR_UNLOCK(sc); 147041502Swpaul return; 147141502Swpaul } 147241502Swpaul 147341502Swpaul start_tx = sc->vr_cdata.vr_tx_free; 147441502Swpaul 147541502Swpaul while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { 147641502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 147741502Swpaul if (m_head == NULL) 147841502Swpaul break; 147941502Swpaul 148041502Swpaul /* Pick a descriptor off the free list. */ 1481113274Ssilby prev_tx = cur_tx; 148241502Swpaul cur_tx = sc->vr_cdata.vr_tx_free; 148341502Swpaul sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; 148441502Swpaul 148541502Swpaul /* Pack the data into the descriptor. */ 148671271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 1487113274Ssilby /* Rollback, send what we were able to encap. */ 148871271Swpaul IF_PREPEND(&ifp->if_snd, m_head); 1489113274Ssilby sc->vr_cdata.vr_tx_free = cur_tx; 1490113274Ssilby cur_tx = prev_tx; 149171271Swpaul break; 149271271Swpaul } 149341502Swpaul 149441502Swpaul if (cur_tx != start_tx) 149541502Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 149641502Swpaul 149741502Swpaul /* 149841502Swpaul * If there's a BPF listener, bounce a copy of this frame 149941502Swpaul * to him. 150041502Swpaul */ 1501106936Ssam BPF_MTAP(ifp, cur_tx->vr_mbuf); 150251583Swpaul 150342491Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 150441502Swpaul } 150541502Swpaul 150641502Swpaul /* 150741526Swpaul * If there are no frames queued, bail. 150841526Swpaul */ 150967087Swpaul if (cur_tx == NULL) { 151067087Swpaul VR_UNLOCK(sc); 151141526Swpaul return; 151267087Swpaul } 151341526Swpaul 151441502Swpaul sc->vr_cdata.vr_tx_tail = cur_tx; 151541502Swpaul 151642491Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 151741502Swpaul sc->vr_cdata.vr_tx_head = start_tx; 1518113274Ssilby 1519113274Ssilby /* Tell the chip to start transmitting. */ 1520113274Ssilby VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); 152141502Swpaul 152241502Swpaul /* 152341502Swpaul * Set a timeout in case the chip goes out to lunch. 152441502Swpaul */ 152541502Swpaul ifp->if_timer = 5; 152667087Swpaul VR_UNLOCK(sc); 152741502Swpaul 152841502Swpaul return; 152941502Swpaul} 153041502Swpaul 1531102336Salfredstatic void 1532102336Salfredvr_init(xsc) 153341502Swpaul void *xsc; 153441502Swpaul{ 153541502Swpaul struct vr_softc *sc = xsc; 153641502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 153751432Swpaul struct mii_data *mii; 153873963Swpaul int i; 153941502Swpaul 154067087Swpaul VR_LOCK(sc); 154141502Swpaul 154251432Swpaul mii = device_get_softc(sc->vr_miibus); 154341502Swpaul 154441502Swpaul /* 154541502Swpaul * Cancel pending I/O and free all RX/TX buffers. 154641502Swpaul */ 154741502Swpaul vr_stop(sc); 154841502Swpaul vr_reset(sc); 154941502Swpaul 155073963Swpaul /* 155173963Swpaul * Set our station address. 155273963Swpaul */ 155373963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 155473963Swpaul CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]); 1555101375Ssilby 1556101375Ssilby /* Set DMA size */ 1557101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1558101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 155973963Swpaul 1560101375Ssilby /* 1561101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1562101108Ssilby * so we must set both. 1563101108Ssilby */ 1564101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1565110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1566101108Ssilby 1567101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1568101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1569101108Ssilby 157041502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1571110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 157241502Swpaul 157341502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 157441502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 157541502Swpaul 157641502Swpaul /* Init circular RX list. */ 157741502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 157841502Swpaul printf("vr%d: initialization failed: no " 157941502Swpaul "memory for rx buffers\n", sc->vr_unit); 158041502Swpaul vr_stop(sc); 158167087Swpaul VR_UNLOCK(sc); 158241502Swpaul return; 158341502Swpaul } 158441502Swpaul 158541502Swpaul /* 158641502Swpaul * Init tx descriptors. 158741502Swpaul */ 158841502Swpaul vr_list_tx_init(sc); 158941502Swpaul 159041502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 159141502Swpaul if (ifp->if_flags & IFF_PROMISC) 159241502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 159341502Swpaul else 159441502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 159541502Swpaul 159641502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 159741502Swpaul if (ifp->if_flags & IFF_BROADCAST) 159841502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 159941502Swpaul else 160041502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 160141502Swpaul 160241502Swpaul /* 160341502Swpaul * Program the multicast filter, if necessary. 160441502Swpaul */ 160541502Swpaul vr_setmulti(sc); 160641502Swpaul 160741502Swpaul /* 160841502Swpaul * Load the address of the RX list. 160941502Swpaul */ 161041502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 161141502Swpaul 161241502Swpaul /* Enable receiver and transmitter. */ 161341502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 161441502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 161541502Swpaul VR_CMD_RX_GO); 161641502Swpaul 161741502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 161841502Swpaul 161941502Swpaul /* 162041502Swpaul * Enable interrupts. 162141502Swpaul */ 162241502Swpaul CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 162341502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 162441502Swpaul 162551432Swpaul mii_mediachg(mii); 162641502Swpaul 162741502Swpaul ifp->if_flags |= IFF_RUNNING; 162841502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 162941502Swpaul 163051432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 163151432Swpaul 163267087Swpaul VR_UNLOCK(sc); 163367087Swpaul 163441502Swpaul return; 163541502Swpaul} 163641502Swpaul 163741502Swpaul/* 163841502Swpaul * Set media options. 163941502Swpaul */ 1640102336Salfredstatic int 1641102336Salfredvr_ifmedia_upd(ifp) 164241502Swpaul struct ifnet *ifp; 164341502Swpaul{ 164441502Swpaul struct vr_softc *sc; 164541502Swpaul 164641502Swpaul sc = ifp->if_softc; 164741502Swpaul 164851432Swpaul if (ifp->if_flags & IFF_UP) 164951432Swpaul vr_init(sc); 165041502Swpaul 165141502Swpaul return(0); 165241502Swpaul} 165341502Swpaul 165441502Swpaul/* 165541502Swpaul * Report current media status. 165641502Swpaul */ 1657102336Salfredstatic void 1658102336Salfredvr_ifmedia_sts(ifp, ifmr) 165941502Swpaul struct ifnet *ifp; 166041502Swpaul struct ifmediareq *ifmr; 166141502Swpaul{ 166241502Swpaul struct vr_softc *sc; 166351432Swpaul struct mii_data *mii; 166441502Swpaul 166541502Swpaul sc = ifp->if_softc; 166651432Swpaul mii = device_get_softc(sc->vr_miibus); 166751432Swpaul mii_pollstat(mii); 166851432Swpaul ifmr->ifm_active = mii->mii_media_active; 166951432Swpaul ifmr->ifm_status = mii->mii_media_status; 167041502Swpaul 167141502Swpaul return; 167241502Swpaul} 167341502Swpaul 1674102336Salfredstatic int 1675102336Salfredvr_ioctl(ifp, command, data) 167641502Swpaul struct ifnet *ifp; 167741502Swpaul u_long command; 167841502Swpaul caddr_t data; 167941502Swpaul{ 168041502Swpaul struct vr_softc *sc = ifp->if_softc; 168141502Swpaul struct ifreq *ifr = (struct ifreq *) data; 168251432Swpaul struct mii_data *mii; 168367087Swpaul int error = 0; 168441502Swpaul 168567087Swpaul VR_LOCK(sc); 168641502Swpaul 168741502Swpaul switch(command) { 168841502Swpaul case SIOCSIFFLAGS: 168941502Swpaul if (ifp->if_flags & IFF_UP) { 169041502Swpaul vr_init(sc); 169141502Swpaul } else { 169241502Swpaul if (ifp->if_flags & IFF_RUNNING) 169341502Swpaul vr_stop(sc); 169441502Swpaul } 169541502Swpaul error = 0; 169641502Swpaul break; 169741502Swpaul case SIOCADDMULTI: 169841502Swpaul case SIOCDELMULTI: 169941502Swpaul vr_setmulti(sc); 170041502Swpaul error = 0; 170141502Swpaul break; 170241502Swpaul case SIOCGIFMEDIA: 170341502Swpaul case SIOCSIFMEDIA: 170451432Swpaul mii = device_get_softc(sc->vr_miibus); 170551432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 170641502Swpaul break; 170741502Swpaul default: 1708106936Ssam error = ether_ioctl(ifp, command, data); 170941502Swpaul break; 171041502Swpaul } 171141502Swpaul 171267087Swpaul VR_UNLOCK(sc); 171341502Swpaul 171441502Swpaul return(error); 171541502Swpaul} 171641502Swpaul 1717102336Salfredstatic void 1718102336Salfredvr_watchdog(ifp) 171941502Swpaul struct ifnet *ifp; 172041502Swpaul{ 172141502Swpaul struct vr_softc *sc; 172241502Swpaul 172341502Swpaul sc = ifp->if_softc; 172441502Swpaul 172567087Swpaul VR_LOCK(sc); 172641502Swpaul ifp->if_oerrors++; 172741502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 172841502Swpaul 172941502Swpaul vr_stop(sc); 173041502Swpaul vr_reset(sc); 173141502Swpaul vr_init(sc); 173241502Swpaul 173341502Swpaul if (ifp->if_snd.ifq_head != NULL) 173441502Swpaul vr_start(ifp); 173541502Swpaul 173667087Swpaul VR_UNLOCK(sc); 173767087Swpaul 173841502Swpaul return; 173941502Swpaul} 174041502Swpaul 174141502Swpaul/* 174241502Swpaul * Stop the adapter and free any mbufs allocated to the 174341502Swpaul * RX and TX lists. 174441502Swpaul */ 1745102336Salfredstatic void 1746102336Salfredvr_stop(sc) 174741502Swpaul struct vr_softc *sc; 174841502Swpaul{ 174941502Swpaul register int i; 175041502Swpaul struct ifnet *ifp; 175141502Swpaul 175267087Swpaul VR_LOCK(sc); 175367087Swpaul 175441502Swpaul ifp = &sc->arpcom.ac_if; 175541502Swpaul ifp->if_timer = 0; 175641502Swpaul 175751432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 175851432Swpaul 175941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 176041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 176141502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 176241502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 176341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 176441502Swpaul 176541502Swpaul /* 176641502Swpaul * Free data in the RX lists. 176741502Swpaul */ 176841502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 176941502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 177041502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 177141502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 177241502Swpaul } 177341502Swpaul } 177441502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 177541502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 177641502Swpaul 177741502Swpaul /* 177841502Swpaul * Free the TX list buffers. 177941502Swpaul */ 178041502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 178141502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 178241502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 178341502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 178441502Swpaul } 178541502Swpaul } 178641502Swpaul 178741502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 178841502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 178941502Swpaul 179041502Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 179167087Swpaul VR_UNLOCK(sc); 179241502Swpaul 179341502Swpaul return; 179441502Swpaul} 179541502Swpaul 179641502Swpaul/* 179741502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 179841502Swpaul * get confused by errant DMAs when rebooting. 179941502Swpaul */ 1800102336Salfredstatic void 1801102336Salfredvr_shutdown(dev) 180249610Swpaul device_t dev; 180341502Swpaul{ 180449610Swpaul struct vr_softc *sc; 180541502Swpaul 180649610Swpaul sc = device_get_softc(dev); 180749610Swpaul 180841502Swpaul vr_stop(sc); 180941502Swpaul 181041502Swpaul return; 181141502Swpaul} 1812