if_vr.c revision 110168
141502Swpaul/* 241502Swpaul * Copyright (c) 1997, 1998 341502Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 441502Swpaul * 541502Swpaul * Redistribution and use in source and binary forms, with or without 641502Swpaul * modification, are permitted provided that the following conditions 741502Swpaul * are met: 841502Swpaul * 1. Redistributions of source code must retain the above copyright 941502Swpaul * notice, this list of conditions and the following disclaimer. 1041502Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1141502Swpaul * notice, this list of conditions and the following disclaimer in the 1241502Swpaul * documentation and/or other materials provided with the distribution. 1341502Swpaul * 3. All advertising materials mentioning features or use of this software 1441502Swpaul * must display the following acknowledgement: 1541502Swpaul * This product includes software developed by Bill Paul. 1641502Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1741502Swpaul * may be used to endorse or promote products derived from this software 1841502Swpaul * without specific prior written permission. 1941502Swpaul * 2041502Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2141502Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2241502Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2341502Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2441502Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2541502Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2641502Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2741502Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2841502Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2941502Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3041502Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3141502Swpaul * 3250477Speter * $FreeBSD: head/sys/dev/vr/if_vr.c 110168 2003-02-01 01:18:26Z silby $ 3341502Swpaul */ 3441502Swpaul 3541502Swpaul/* 3641502Swpaul * VIA Rhine fast ethernet PCI NIC driver 3741502Swpaul * 3841502Swpaul * Supports various network adapters based on the VIA Rhine 3941502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX. 4041502Swpaul * Datasheets are available at http://www.via.com.tw. 4141502Swpaul * 4241502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4341502Swpaul * Electrical Engineering Department 4441502Swpaul * Columbia University, New York City 4541502Swpaul */ 4641502Swpaul 4741502Swpaul/* 4841502Swpaul * The VIA Rhine controllers are similar in some respects to the 4941502Swpaul * the DEC tulip chips, except less complicated. The controller 5041502Swpaul * uses an MII bus and an external physical layer interface. The 5141502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table 5241502Swpaul * multicast filter. Transmit and receive descriptors are similar 5341502Swpaul * to the tulip. 5441502Swpaul * 5541502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism: 5641502Swpaul * transmit buffers must be longword aligned. Unfortunately, 5741502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting 5841502Swpaul * at longword boundaries, so we have to do a buffer copy before 5941502Swpaul * transmission. 6041502Swpaul */ 6141502Swpaul 6241502Swpaul#include <sys/param.h> 6341502Swpaul#include <sys/systm.h> 6441502Swpaul#include <sys/sockio.h> 6541502Swpaul#include <sys/mbuf.h> 6641502Swpaul#include <sys/malloc.h> 6741502Swpaul#include <sys/kernel.h> 6841502Swpaul#include <sys/socket.h> 6941502Swpaul 7041502Swpaul#include <net/if.h> 7141502Swpaul#include <net/if_arp.h> 7241502Swpaul#include <net/ethernet.h> 7341502Swpaul#include <net/if_dl.h> 7441502Swpaul#include <net/if_media.h> 7541502Swpaul 7641502Swpaul#include <net/bpf.h> 7741502Swpaul 7841502Swpaul#include <vm/vm.h> /* for vtophys */ 7941502Swpaul#include <vm/pmap.h> /* for vtophys */ 8041502Swpaul#include <machine/bus_pio.h> 8141502Swpaul#include <machine/bus_memio.h> 8241502Swpaul#include <machine/bus.h> 8349610Swpaul#include <machine/resource.h> 8449610Swpaul#include <sys/bus.h> 8549610Swpaul#include <sys/rman.h> 8641502Swpaul 8751432Swpaul#include <dev/mii/mii.h> 8851432Swpaul#include <dev/mii/miivar.h> 8951432Swpaul 9041502Swpaul#include <pci/pcireg.h> 9141502Swpaul#include <pci/pcivar.h> 9241502Swpaul 9341502Swpaul#define VR_USEIOSPACE 9441502Swpaul 9541502Swpaul#include <pci/if_vrreg.h> 9641502Swpaul 9759758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 9859758Speter 9951432Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 10051432Swpaul#include "miibus_if.h" 10151432Swpaul 10241502Swpaul#ifndef lint 10341591Sarchiestatic const char rcsid[] = 10450477Speter "$FreeBSD: head/sys/dev/vr/if_vr.c 110168 2003-02-01 01:18:26Z silby $"; 10541502Swpaul#endif 10641502Swpaul 107110168Ssilby#undef VR_USESWSHIFT 108110168Ssilby 10941502Swpaul/* 11041502Swpaul * Various supported device vendors/types and their names. 11141502Swpaul */ 11241502Swpaulstatic struct vr_type vr_devs[] = { 11341502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 11441502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 11541502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11641502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11762653Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 11862653Swpaul "VIA VT6102 Rhine II 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); 74349610Swpaul bzero(sc, sizeof(struct vr_softc *)); 74441502Swpaul 74593818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 74693818Sjhb MTX_DEF | MTX_RECURSE); 74769583Swpaul VR_LOCK(sc); 74869583Swpaul 74941502Swpaul /* 75041502Swpaul * Handle power management nonsense. 75141502Swpaul */ 75272813Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 75372813Swpaul u_int32_t iobase, membase, irq; 75441502Swpaul 75572813Swpaul /* Save important PCI config data. */ 75672813Swpaul iobase = pci_read_config(dev, VR_PCI_LOIO, 4); 75772813Swpaul membase = pci_read_config(dev, VR_PCI_LOMEM, 4); 75872813Swpaul irq = pci_read_config(dev, VR_PCI_INTLINE, 4); 75941502Swpaul 76072813Swpaul /* Reset the power state. */ 76172813Swpaul printf("vr%d: chip is in D%d power mode " 76272813Swpaul "-- setting to D0\n", unit, 76372813Swpaul pci_get_powerstate(dev)); 76472813Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 76541502Swpaul 76641502Swpaul /* Restore PCI config data. */ 76772813Swpaul pci_write_config(dev, VR_PCI_LOIO, iobase, 4); 76872813Swpaul pci_write_config(dev, VR_PCI_LOMEM, membase, 4); 76972813Swpaul pci_write_config(dev, VR_PCI_INTLINE, irq, 4); 77041502Swpaul } 77141502Swpaul 77241502Swpaul /* 77341502Swpaul * Map control/status registers. 77441502Swpaul */ 77572813Swpaul pci_enable_busmaster(dev); 77679472Swpaul pci_enable_io(dev, SYS_RES_IOPORT); 77779472Swpaul pci_enable_io(dev, SYS_RES_MEMORY); 77861041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 779107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 78041502Swpaul 78141502Swpaul#ifdef VR_USEIOSPACE 78241502Swpaul if (!(command & PCIM_CMD_PORTEN)) { 78341502Swpaul printf("vr%d: failed to enable I/O ports!\n", unit); 78441502Swpaul free(sc, M_DEVBUF); 78541502Swpaul goto fail; 78641502Swpaul } 78741502Swpaul#else 78841502Swpaul if (!(command & PCIM_CMD_MEMEN)) { 78941502Swpaul printf("vr%d: failed to enable memory mapping!\n", unit); 79041502Swpaul goto fail; 79141502Swpaul } 79249610Swpaul#endif 79341502Swpaul 79449610Swpaul rid = VR_RID; 79549610Swpaul sc->vr_res = bus_alloc_resource(dev, VR_RES, &rid, 79649610Swpaul 0, ~0, 1, RF_ACTIVE); 79749610Swpaul 79849610Swpaul if (sc->vr_res == NULL) { 79949610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 80049610Swpaul error = ENXIO; 80141502Swpaul goto fail; 80241502Swpaul } 80341502Swpaul 80449610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 80549610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 80641502Swpaul 80741502Swpaul /* Allocate interrupt */ 80849610Swpaul rid = 0; 80949610Swpaul sc->vr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 81049610Swpaul RF_SHAREABLE | RF_ACTIVE); 81149610Swpaul 81249610Swpaul if (sc->vr_irq == NULL) { 81341502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 81449610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 81549610Swpaul error = ENXIO; 81641502Swpaul goto fail; 81741502Swpaul } 81841502Swpaul 81949610Swpaul error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET, 82049610Swpaul vr_intr, sc, &sc->vr_intrhand); 82149610Swpaul 82249610Swpaul if (error) { 82349610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 82449610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 82549610Swpaul printf("vr%d: couldn't set up irq\n", unit); 82649610Swpaul goto fail; 82749610Swpaul } 82849610Swpaul 82976586Swpaul /* 83076586Swpaul * Windows may put the chip in suspend mode when it 83176586Swpaul * shuts down. Be sure to kick it in the head to wake it 83276586Swpaul * up again. 83376586Swpaul */ 83476586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 83576586Swpaul 83641502Swpaul /* Reset the adapter. */ 83741502Swpaul vr_reset(sc); 83841502Swpaul 839110168Ssilby /* 840110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 841110168Ssilby * initialization and disable AUTOPOLL. 842110168Ssilby */ 843110168Ssilby pci_write_config(dev, VR_PCI_MODE, 844110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 845110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 846110168Ssilby 84741502Swpaul /* 84841502Swpaul * Get station address. The way the Rhine chips work, 84941502Swpaul * you're not allowed to directly access the EEPROM once 85041502Swpaul * they've been programmed a special way. Consequently, 85141502Swpaul * we need to read the node address from the PAR0 and PAR1 85241502Swpaul * registers. 85341502Swpaul */ 85441502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 85541502Swpaul DELAY(200); 85641502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 85741502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 85841502Swpaul 85941502Swpaul /* 86041502Swpaul * A Rhine chip was detected. Inform the world. 86141502Swpaul */ 86241502Swpaul printf("vr%d: Ethernet address: %6D\n", unit, eaddr, ":"); 86341502Swpaul 86441502Swpaul sc->vr_unit = unit; 86541502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 86641502Swpaul 86751432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 86851657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 86951432Swpaul 87051432Swpaul if (sc->vr_ldata == NULL) { 87141502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 87249610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 87349610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 87449610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 87549610Swpaul error = ENXIO; 87649610Swpaul goto fail; 87741502Swpaul } 87841502Swpaul 87941502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 88041502Swpaul 88141502Swpaul ifp = &sc->arpcom.ac_if; 88241502Swpaul ifp->if_softc = sc; 88341502Swpaul ifp->if_unit = unit; 88441502Swpaul ifp->if_name = "vr"; 88541502Swpaul ifp->if_mtu = ETHERMTU; 88641502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 88741502Swpaul ifp->if_ioctl = vr_ioctl; 88841502Swpaul ifp->if_output = ether_output; 88941502Swpaul ifp->if_start = vr_start; 89041502Swpaul ifp->if_watchdog = vr_watchdog; 89141502Swpaul ifp->if_init = vr_init; 89241502Swpaul ifp->if_baudrate = 10000000; 89343515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 89441502Swpaul 89551432Swpaul /* 89651432Swpaul * Do MII setup. 89751432Swpaul */ 89851432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 89951432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 90041502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 90149610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 90249610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 90349610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 90451432Swpaul contigfree(sc->vr_ldata, 90551432Swpaul sizeof(struct vr_list_data), M_DEVBUF); 90649610Swpaul error = ENXIO; 90741502Swpaul goto fail; 90841502Swpaul } 90941502Swpaul 91051432Swpaul callout_handle_init(&sc->vr_stat_ch); 91141502Swpaul 91241502Swpaul /* 91363090Sarchie * Call MI attach routine. 91441502Swpaul */ 915106936Ssam ether_ifattach(ifp, eaddr); 91667087Swpaul VR_UNLOCK(sc); 91767087Swpaul return(0); 91841502Swpaul 91941502Swpaulfail: 92067087Swpaul VR_UNLOCK(sc); 92167087Swpaul mtx_destroy(&sc->vr_mtx); 92267087Swpaul 92349610Swpaul return(error); 92441502Swpaul} 92541502Swpaul 926102336Salfredstatic int 927102336Salfredvr_detach(dev) 92849610Swpaul device_t dev; 92949610Swpaul{ 93049610Swpaul struct vr_softc *sc; 93149610Swpaul struct ifnet *ifp; 93249610Swpaul 93349610Swpaul sc = device_get_softc(dev); 93467087Swpaul VR_LOCK(sc); 93549610Swpaul ifp = &sc->arpcom.ac_if; 93649610Swpaul 93749610Swpaul vr_stop(sc); 938106936Ssam ether_ifdetach(ifp); 93949610Swpaul 94051432Swpaul bus_generic_detach(dev); 94151432Swpaul device_delete_child(dev, sc->vr_miibus); 94251432Swpaul 94349610Swpaul bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 94449610Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 94549610Swpaul bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 94649610Swpaul 94751432Swpaul contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 94849610Swpaul 94967087Swpaul VR_UNLOCK(sc); 95067087Swpaul mtx_destroy(&sc->vr_mtx); 95149610Swpaul 95249610Swpaul return(0); 95349610Swpaul} 95449610Swpaul 95541502Swpaul/* 95641502Swpaul * Initialize the transmit descriptors. 95741502Swpaul */ 958102336Salfredstatic int 959102336Salfredvr_list_tx_init(sc) 96041502Swpaul struct vr_softc *sc; 96141502Swpaul{ 96241502Swpaul struct vr_chain_data *cd; 96341502Swpaul struct vr_list_data *ld; 96441502Swpaul int i; 96541502Swpaul 96641502Swpaul cd = &sc->vr_cdata; 96741502Swpaul ld = sc->vr_ldata; 96841502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 96941502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 97041502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 97141502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 97241502Swpaul &cd->vr_tx_chain[0]; 97341502Swpaul else 97441502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 97541502Swpaul &cd->vr_tx_chain[i + 1]; 97641502Swpaul } 97741502Swpaul 97841502Swpaul cd->vr_tx_free = &cd->vr_tx_chain[0]; 97941502Swpaul cd->vr_tx_tail = cd->vr_tx_head = NULL; 98041502Swpaul 98141502Swpaul return(0); 98241502Swpaul} 98341502Swpaul 98441502Swpaul 98541502Swpaul/* 98641502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 98741502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 98841502Swpaul * points back to the first. 98941502Swpaul */ 990102336Salfredstatic int 991102336Salfredvr_list_rx_init(sc) 99241502Swpaul struct vr_softc *sc; 99341502Swpaul{ 99441502Swpaul struct vr_chain_data *cd; 99541502Swpaul struct vr_list_data *ld; 99641502Swpaul int i; 99741502Swpaul 99841502Swpaul cd = &sc->vr_cdata; 99941502Swpaul ld = sc->vr_ldata; 100041502Swpaul 100141502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 100241502Swpaul cd->vr_rx_chain[i].vr_ptr = 100341502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 100449610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 100541502Swpaul return(ENOBUFS); 100641502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 100741502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 100841502Swpaul &cd->vr_rx_chain[0]; 100941502Swpaul ld->vr_rx_list[i].vr_next = 101041502Swpaul vtophys(&ld->vr_rx_list[0]); 101141502Swpaul } else { 101241502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 101341502Swpaul &cd->vr_rx_chain[i + 1]; 101441502Swpaul ld->vr_rx_list[i].vr_next = 101541502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 101641502Swpaul } 101741502Swpaul } 101841502Swpaul 101941502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 102041502Swpaul 102141502Swpaul return(0); 102241502Swpaul} 102341502Swpaul 102441502Swpaul/* 102541502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 102641502Swpaul * Note: the length fields are only 11 bits wide, which means the 102741502Swpaul * largest size we can specify is 2047. This is important because 102841502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 102941502Swpaul * overflow the field and make a mess. 103041502Swpaul */ 1031102336Salfredstatic int 1032102336Salfredvr_newbuf(sc, c, m) 103341502Swpaul struct vr_softc *sc; 103441502Swpaul struct vr_chain_onefrag *c; 103549610Swpaul struct mbuf *m; 103641502Swpaul{ 103741502Swpaul struct mbuf *m_new = NULL; 103841502Swpaul 103949610Swpaul if (m == NULL) { 1040109623Salfred MGETHDR(m_new, M_NOWAIT, MT_DATA); 104187846Sluigi if (m_new == NULL) 104249610Swpaul return(ENOBUFS); 104341502Swpaul 1044109623Salfred MCLGET(m_new, M_NOWAIT); 104549610Swpaul if (!(m_new->m_flags & M_EXT)) { 104649610Swpaul m_freem(m_new); 104749610Swpaul return(ENOBUFS); 104849610Swpaul } 104949610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 105049610Swpaul } else { 105149610Swpaul m_new = m; 105249610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 105349610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 105441502Swpaul } 105541502Swpaul 105649610Swpaul m_adj(m_new, sizeof(u_int64_t)); 105749610Swpaul 105841502Swpaul c->vr_mbuf = m_new; 105941502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 106041502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 106142491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 106241502Swpaul 106341502Swpaul return(0); 106441502Swpaul} 106541502Swpaul 106641502Swpaul/* 106741502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 106841502Swpaul * the higher level protocols. 106941502Swpaul */ 1070102336Salfredstatic void 1071102336Salfredvr_rxeof(sc) 107241502Swpaul struct vr_softc *sc; 107341502Swpaul{ 107441502Swpaul struct mbuf *m; 107541502Swpaul struct ifnet *ifp; 107641502Swpaul struct vr_chain_onefrag *cur_rx; 107741502Swpaul int total_len = 0; 107841502Swpaul u_int32_t rxstat; 107941502Swpaul 108041502Swpaul ifp = &sc->arpcom.ac_if; 108141502Swpaul 108241502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 108341502Swpaul VR_RXSTAT_OWN)) { 108449610Swpaul struct mbuf *m0 = NULL; 108549610Swpaul 108641502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 108741502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 108849610Swpaul m = cur_rx->vr_mbuf; 108941502Swpaul 109041502Swpaul /* 109141502Swpaul * If an error occurs, update stats, clear the 109241502Swpaul * status word and leave the mbuf cluster in place: 109341502Swpaul * it should simply get re-used next time this descriptor 109441502Swpaul * comes up in the ring. 109541502Swpaul */ 109641502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 109741502Swpaul ifp->if_ierrors++; 1098110131Ssilby printf("vr%d: rx error (%02x):", 1099110131Ssilby sc->vr_unit, rxstat & 0x000000ff); 1100110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 1101110131Ssilby printf(" crc error"); 1102110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 1103110131Ssilby printf(" frame alignment error\n"); 1104110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 1105110131Ssilby printf(" FIFO overflow"); 1106110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 1107110131Ssilby printf(" received giant packet"); 1108110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 1109110131Ssilby printf(" received runt packet"); 1110110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 1111110131Ssilby printf(" system bus error"); 1112110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 1113110131Ssilby printf("rx buffer error"); 1114110131Ssilby printf("\n"); 111549610Swpaul vr_newbuf(sc, cur_rx, m); 111641502Swpaul continue; 111741502Swpaul } 111841502Swpaul 111941502Swpaul /* No errors; receive the packet. */ 112041502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 112141502Swpaul 112241502Swpaul /* 112342048Swpaul * XXX The VIA Rhine chip includes the CRC with every 112442048Swpaul * received frame, and there's no way to turn this 112542048Swpaul * behavior off (at least, I can't find anything in 112642048Swpaul * the manual that explains how to do it) so we have 112742048Swpaul * to trim off the CRC manually. 112842048Swpaul */ 112942048Swpaul total_len -= ETHER_CRC_LEN; 113042048Swpaul 113178508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 113278508Sbmilekic NULL); 113349610Swpaul vr_newbuf(sc, cur_rx, m); 113449610Swpaul if (m0 == NULL) { 113541502Swpaul ifp->if_ierrors++; 113641502Swpaul continue; 113741502Swpaul } 113849610Swpaul m = m0; 113941502Swpaul 114041502Swpaul ifp->if_ipackets++; 1141106936Ssam (*ifp->if_input)(ifp, m); 114241502Swpaul } 114341502Swpaul 114441502Swpaul return; 114541502Swpaul} 114641502Swpaul 1147105221Sphkstatic void 1148102336Salfredvr_rxeoc(sc) 114941502Swpaul struct vr_softc *sc; 115041502Swpaul{ 1151110131Ssilby struct ifnet *ifp; 1152110131Ssilby int i; 115341502Swpaul 1154110131Ssilby ifp = &sc->arpcom.ac_if; 1155110131Ssilby 1156110131Ssilby ifp->if_ierrors++; 1157110131Ssilby 1158110131Ssilby VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1159110131Ssilby DELAY(10000); 1160110131Ssilby 1161110131Ssilby for (i = 0x400; 1162110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1163110131Ssilby i--) 1164110131Ssilby ; /* Wait for receiver to stop */ 1165110131Ssilby 1166110131Ssilby if (!i) { 1167110131Ssilby printf("vr%d: rx shutdown error!\n", sc->vr_unit); 1168110131Ssilby sc->vr_flags |= VR_F_RESTART; 1169110131Ssilby return; 1170110131Ssilby } 1171110131Ssilby 117241502Swpaul vr_rxeof(sc); 1173110131Ssilby 117441502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 117541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 117641502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 117741502Swpaul 117841502Swpaul return; 117941502Swpaul} 118041502Swpaul 118141502Swpaul/* 118241502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 118341502Swpaul * the list buffers. 118441502Swpaul */ 118541502Swpaul 1186102336Salfredstatic void 1187102336Salfredvr_txeof(sc) 118841502Swpaul struct vr_softc *sc; 118941502Swpaul{ 119041502Swpaul struct vr_chain *cur_tx; 119141502Swpaul struct ifnet *ifp; 119241502Swpaul 119341502Swpaul ifp = &sc->arpcom.ac_if; 119441502Swpaul 119596677Ssilby /* Reset the timeout timer; if_txeoc will clear it. */ 119696677Ssilby ifp->if_timer = 5; 119741502Swpaul 119841502Swpaul /* Sanity check. */ 119941502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 120041502Swpaul return; 120141502Swpaul 120241502Swpaul /* 120341502Swpaul * Go through our tx list and free mbufs for those 120441502Swpaul * frames that have been transmitted. 120541502Swpaul */ 120641502Swpaul while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { 120741502Swpaul u_int32_t txstat; 1208110131Ssilby int i; 120941502Swpaul 121041502Swpaul cur_tx = sc->vr_cdata.vr_tx_head; 121141502Swpaul txstat = cur_tx->vr_ptr->vr_status; 121241502Swpaul 1213101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1214101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1215110131Ssilby for (i = 0x400; 1216110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1217110131Ssilby i--) 1218101896Ssilby ; /* Wait for chip to shutdown */ 1219110131Ssilby if (!i) { 1220110131Ssilby printf("vr%d: tx shutdown timeout\n", sc->vr_unit); 1221110131Ssilby sc->vr_flags |= VR_F_RESTART; 1222110131Ssilby break; 1223110131Ssilby } 1224101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1225101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1226101896Ssilby break; 1227101896Ssilby } 1228101896Ssilby 122942491Swpaul if (txstat & VR_TXSTAT_OWN) 123041502Swpaul break; 123141502Swpaul 123241502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 123341502Swpaul ifp->if_oerrors++; 123441502Swpaul if (txstat & VR_TXSTAT_DEFER) 123541502Swpaul ifp->if_collisions++; 123641502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 123741502Swpaul ifp->if_collisions++; 123841502Swpaul } 123941502Swpaul 124041502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 124141502Swpaul 124241502Swpaul ifp->if_opackets++; 124351432Swpaul if (cur_tx->vr_mbuf != NULL) { 124451432Swpaul m_freem(cur_tx->vr_mbuf); 124551432Swpaul cur_tx->vr_mbuf = NULL; 124651432Swpaul } 124741502Swpaul 124841502Swpaul if (sc->vr_cdata.vr_tx_head == sc->vr_cdata.vr_tx_tail) { 124941502Swpaul sc->vr_cdata.vr_tx_head = NULL; 125041502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 125141502Swpaul break; 125241502Swpaul } 125341502Swpaul 125441502Swpaul sc->vr_cdata.vr_tx_head = cur_tx->vr_nextdesc; 125541502Swpaul } 125641502Swpaul 125741502Swpaul return; 125841502Swpaul} 125941502Swpaul 126041502Swpaul/* 126141502Swpaul * TX 'end of channel' interrupt handler. 126241502Swpaul */ 1263102336Salfredstatic void 1264102336Salfredvr_txeoc(sc) 126541502Swpaul struct vr_softc *sc; 126641502Swpaul{ 126741502Swpaul struct ifnet *ifp; 126841502Swpaul 126941502Swpaul ifp = &sc->arpcom.ac_if; 127041502Swpaul 127141502Swpaul if (sc->vr_cdata.vr_tx_head == NULL) { 127241502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 127341502Swpaul sc->vr_cdata.vr_tx_tail = NULL; 127496677Ssilby ifp->if_timer = 0; 127541502Swpaul } 127641502Swpaul 127741502Swpaul return; 127841502Swpaul} 127941502Swpaul 1280102336Salfredstatic void 1281102336Salfredvr_tick(xsc) 128251432Swpaul void *xsc; 128351432Swpaul{ 128451432Swpaul struct vr_softc *sc; 128551432Swpaul struct mii_data *mii; 128651432Swpaul 128751432Swpaul sc = xsc; 128867087Swpaul VR_LOCK(sc); 1289110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1290110131Ssilby printf("vr%d: restarting\n", sc->vr_unit); 1291110131Ssilby vr_stop(sc); 1292110131Ssilby vr_reset(sc); 1293110131Ssilby vr_init(sc); 1294110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1295110131Ssilby } 1296110131Ssilby 129751432Swpaul mii = device_get_softc(sc->vr_miibus); 129851432Swpaul mii_tick(mii); 129951432Swpaul 130051432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 130151432Swpaul 130267087Swpaul VR_UNLOCK(sc); 130351432Swpaul 130451432Swpaul return; 130551432Swpaul} 130651432Swpaul 1307102336Salfredstatic void 1308102336Salfredvr_intr(arg) 130941502Swpaul void *arg; 131041502Swpaul{ 131141502Swpaul struct vr_softc *sc; 131241502Swpaul struct ifnet *ifp; 131341502Swpaul u_int16_t status; 131441502Swpaul 131541502Swpaul sc = arg; 131667087Swpaul VR_LOCK(sc); 131741502Swpaul ifp = &sc->arpcom.ac_if; 131841502Swpaul 131941502Swpaul /* Supress unwanted interrupts. */ 132041502Swpaul if (!(ifp->if_flags & IFF_UP)) { 132141502Swpaul vr_stop(sc); 132267087Swpaul VR_UNLOCK(sc); 132341502Swpaul return; 132441502Swpaul } 132541502Swpaul 132641502Swpaul /* Disable interrupts. */ 132741502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 132841502Swpaul 132941502Swpaul for (;;) { 133041502Swpaul 133141502Swpaul status = CSR_READ_2(sc, VR_ISR); 133241502Swpaul if (status) 133341502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 133441502Swpaul 133541502Swpaul if ((status & VR_INTRS) == 0) 133641502Swpaul break; 133741502Swpaul 133841502Swpaul if (status & VR_ISR_RX_OK) 133941502Swpaul vr_rxeof(sc); 134041502Swpaul 1341110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1342110131Ssilby printf("vr%d: rx packet lost\n", sc->vr_unit); 1343110131Ssilby ifp->if_ierrors++; 1344110131Ssilby } 1345110131Ssilby 134641502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1347110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1348110131Ssilby printf("vr%d: receive error (%04x)", 1349110131Ssilby sc->vr_unit, status); 1350110131Ssilby if (status & VR_ISR_RX_NOBUF) 1351110131Ssilby printf(" no buffers"); 1352110131Ssilby if (status & VR_ISR_RX_OFLOW) 1353110131Ssilby printf(" overflow"); 1354110131Ssilby if (status & VR_ISR_RX_DROPPED) 1355110131Ssilby printf(" packet lost"); 1356110131Ssilby printf("\n"); 135741502Swpaul vr_rxeoc(sc); 135841502Swpaul } 135941502Swpaul 1360101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1361101896Ssilby vr_reset(sc); 1362101896Ssilby vr_init(sc); 1363101896Ssilby break; 136441502Swpaul } 136541502Swpaul 1366101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1367101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 136841502Swpaul vr_txeof(sc); 1369101896Ssilby if ((status & VR_ISR_UDFI) || 1370101896Ssilby (status & VR_ISR_TX_ABRT2) || 1371101896Ssilby (status & VR_ISR_TX_ABRT)) { 1372101896Ssilby ifp->if_oerrors++; 1373101896Ssilby if (sc->vr_cdata.vr_tx_head != NULL) { 1374101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1375101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1376101896Ssilby } 1377101896Ssilby } else 1378101896Ssilby vr_txeoc(sc); 137941502Swpaul } 138041502Swpaul 138141502Swpaul } 138241502Swpaul 138341502Swpaul /* Re-enable interrupts. */ 138441502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 138541502Swpaul 138641502Swpaul if (ifp->if_snd.ifq_head != NULL) { 138741502Swpaul vr_start(ifp); 138841502Swpaul } 138941502Swpaul 139067087Swpaul VR_UNLOCK(sc); 139167087Swpaul 139241502Swpaul return; 139341502Swpaul} 139441502Swpaul 139541502Swpaul/* 139641502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 139741502Swpaul * pointers to the fragment pointers. 139841502Swpaul */ 1399102336Salfredstatic int 1400102336Salfredvr_encap(sc, c, m_head) 140141502Swpaul struct vr_softc *sc; 140241502Swpaul struct vr_chain *c; 140341502Swpaul struct mbuf *m_head; 140441502Swpaul{ 140541502Swpaul int frag = 0; 140641502Swpaul struct vr_desc *f = NULL; 140741502Swpaul int total_len; 140841502Swpaul struct mbuf *m; 140941502Swpaul 141041502Swpaul m = m_head; 141141502Swpaul total_len = 0; 141241502Swpaul 141341502Swpaul /* 141441502Swpaul * The VIA Rhine wants packet buffers to be longword 141541502Swpaul * aligned, but very often our mbufs aren't. Rather than 141641502Swpaul * waste time trying to decide when to copy and when not 141741502Swpaul * to copy, just do it all the time. 141841502Swpaul */ 141941502Swpaul if (m != NULL) { 142041502Swpaul struct mbuf *m_new = NULL; 142141502Swpaul 1422109623Salfred MGETHDR(m_new, M_NOWAIT, MT_DATA); 142341502Swpaul if (m_new == NULL) { 142471271Swpaul printf("vr%d: no memory for tx list\n", sc->vr_unit); 142541502Swpaul return(1); 142641502Swpaul } 142741502Swpaul if (m_head->m_pkthdr.len > MHLEN) { 1428109623Salfred MCLGET(m_new, M_NOWAIT); 142941502Swpaul if (!(m_new->m_flags & M_EXT)) { 143041502Swpaul m_freem(m_new); 143171271Swpaul printf("vr%d: no memory for tx list\n", 143241502Swpaul sc->vr_unit); 143341502Swpaul return(1); 143441502Swpaul } 143541502Swpaul } 143641502Swpaul m_copydata(m_head, 0, m_head->m_pkthdr.len, 143741502Swpaul mtod(m_new, caddr_t)); 143841502Swpaul m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; 143941502Swpaul m_freem(m_head); 144041502Swpaul m_head = m_new; 144141502Swpaul /* 144241502Swpaul * The Rhine chip doesn't auto-pad, so we have to make 144341502Swpaul * sure to pad short frames out to the minimum frame length 144441502Swpaul * ourselves. 144541502Swpaul */ 144641502Swpaul if (m_head->m_len < VR_MIN_FRAMELEN) { 144741502Swpaul m_new->m_pkthdr.len += VR_MIN_FRAMELEN - m_new->m_len; 144841502Swpaul m_new->m_len = m_new->m_pkthdr.len; 144941502Swpaul } 145041502Swpaul f = c->vr_ptr; 145141502Swpaul f->vr_data = vtophys(mtod(m_new, caddr_t)); 145241502Swpaul f->vr_ctl = total_len = m_new->m_len; 145341502Swpaul f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 145441502Swpaul f->vr_status = 0; 145541502Swpaul frag = 1; 145641502Swpaul } 145741502Swpaul 145841502Swpaul c->vr_mbuf = m_head; 145942491Swpaul c->vr_ptr->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 146041502Swpaul c->vr_ptr->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 146141502Swpaul 146241502Swpaul return(0); 146341502Swpaul} 146441502Swpaul 146541502Swpaul/* 146641502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 146741502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 146841502Swpaul * copy of the pointers since the transmit list fragment pointers are 146941502Swpaul * physical addresses. 147041502Swpaul */ 147141502Swpaul 1472102336Salfredstatic void 1473102336Salfredvr_start(ifp) 147441502Swpaul struct ifnet *ifp; 147541502Swpaul{ 147641502Swpaul struct vr_softc *sc; 147741502Swpaul struct mbuf *m_head = NULL; 147841502Swpaul struct vr_chain *cur_tx = NULL, *start_tx; 147941502Swpaul 148041502Swpaul sc = ifp->if_softc; 148141502Swpaul 148267087Swpaul VR_LOCK(sc); 148367087Swpaul if (ifp->if_flags & IFF_OACTIVE) { 148467087Swpaul VR_UNLOCK(sc); 148541502Swpaul return; 148667087Swpaul } 148741502Swpaul 148841502Swpaul /* 148941502Swpaul * Check for an available queue slot. If there are none, 149041502Swpaul * punt. 149141502Swpaul */ 149241502Swpaul if (sc->vr_cdata.vr_tx_free->vr_mbuf != NULL) { 149341502Swpaul ifp->if_flags |= IFF_OACTIVE; 149441502Swpaul return; 149541502Swpaul } 149641502Swpaul 149741502Swpaul start_tx = sc->vr_cdata.vr_tx_free; 149841502Swpaul 149941502Swpaul while(sc->vr_cdata.vr_tx_free->vr_mbuf == NULL) { 150041502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 150141502Swpaul if (m_head == NULL) 150241502Swpaul break; 150341502Swpaul 150441502Swpaul /* Pick a descriptor off the free list. */ 150541502Swpaul cur_tx = sc->vr_cdata.vr_tx_free; 150641502Swpaul sc->vr_cdata.vr_tx_free = cur_tx->vr_nextdesc; 150741502Swpaul 150841502Swpaul /* Pack the data into the descriptor. */ 150971271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 151071271Swpaul IF_PREPEND(&ifp->if_snd, m_head); 151171275Swpaul ifp->if_flags |= IFF_OACTIVE; 151271271Swpaul cur_tx = NULL; 151371271Swpaul break; 151471271Swpaul } 151541502Swpaul 151641502Swpaul if (cur_tx != start_tx) 151741502Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 151841502Swpaul 151941502Swpaul /* 152041502Swpaul * If there's a BPF listener, bounce a copy of this frame 152141502Swpaul * to him. 152241502Swpaul */ 1523106936Ssam BPF_MTAP(ifp, cur_tx->vr_mbuf); 152451583Swpaul 152542491Swpaul VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 152651432Swpaul VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); 152741502Swpaul } 152841502Swpaul 152941502Swpaul /* 153041526Swpaul * If there are no frames queued, bail. 153141526Swpaul */ 153267087Swpaul if (cur_tx == NULL) { 153367087Swpaul VR_UNLOCK(sc); 153441526Swpaul return; 153567087Swpaul } 153641526Swpaul 153741502Swpaul sc->vr_cdata.vr_tx_tail = cur_tx; 153841502Swpaul 153942491Swpaul if (sc->vr_cdata.vr_tx_head == NULL) 154041502Swpaul sc->vr_cdata.vr_tx_head = start_tx; 154141502Swpaul 154241502Swpaul /* 154341502Swpaul * Set a timeout in case the chip goes out to lunch. 154441502Swpaul */ 154541502Swpaul ifp->if_timer = 5; 154667087Swpaul VR_UNLOCK(sc); 154741502Swpaul 154841502Swpaul return; 154941502Swpaul} 155041502Swpaul 1551102336Salfredstatic void 1552102336Salfredvr_init(xsc) 155341502Swpaul void *xsc; 155441502Swpaul{ 155541502Swpaul struct vr_softc *sc = xsc; 155641502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 155751432Swpaul struct mii_data *mii; 155873963Swpaul int i; 155941502Swpaul 156067087Swpaul VR_LOCK(sc); 156141502Swpaul 156251432Swpaul mii = device_get_softc(sc->vr_miibus); 156341502Swpaul 156441502Swpaul /* 156541502Swpaul * Cancel pending I/O and free all RX/TX buffers. 156641502Swpaul */ 156741502Swpaul vr_stop(sc); 156841502Swpaul vr_reset(sc); 156941502Swpaul 157073963Swpaul /* 157173963Swpaul * Set our station address. 157273963Swpaul */ 157373963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 157473963Swpaul CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]); 1575101375Ssilby 1576101375Ssilby /* Set DMA size */ 1577101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1578101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 157973963Swpaul 1580101375Ssilby /* 1581101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1582101108Ssilby * so we must set both. 1583101108Ssilby */ 1584101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1585110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1586101108Ssilby 1587101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1588101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1589101108Ssilby 159041502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1591110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 159241502Swpaul 159341502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 159441502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 159541502Swpaul 159641502Swpaul /* Init circular RX list. */ 159741502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 159841502Swpaul printf("vr%d: initialization failed: no " 159941502Swpaul "memory for rx buffers\n", sc->vr_unit); 160041502Swpaul vr_stop(sc); 160167087Swpaul VR_UNLOCK(sc); 160241502Swpaul return; 160341502Swpaul } 160441502Swpaul 160541502Swpaul /* 160641502Swpaul * Init tx descriptors. 160741502Swpaul */ 160841502Swpaul vr_list_tx_init(sc); 160941502Swpaul 161041502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 161141502Swpaul if (ifp->if_flags & IFF_PROMISC) 161241502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 161341502Swpaul else 161441502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 161541502Swpaul 161641502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 161741502Swpaul if (ifp->if_flags & IFF_BROADCAST) 161841502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 161941502Swpaul else 162041502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 162141502Swpaul 162241502Swpaul /* 162341502Swpaul * Program the multicast filter, if necessary. 162441502Swpaul */ 162541502Swpaul vr_setmulti(sc); 162641502Swpaul 162741502Swpaul /* 162841502Swpaul * Load the address of the RX list. 162941502Swpaul */ 163041502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 163141502Swpaul 163241502Swpaul /* Enable receiver and transmitter. */ 163341502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 163441502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 163541502Swpaul VR_CMD_RX_GO); 163641502Swpaul 163741502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 163841502Swpaul 163941502Swpaul /* 164041502Swpaul * Enable interrupts. 164141502Swpaul */ 164241502Swpaul CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 164341502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 164441502Swpaul 164551432Swpaul mii_mediachg(mii); 164641502Swpaul 164741502Swpaul ifp->if_flags |= IFF_RUNNING; 164841502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 164941502Swpaul 165051432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 165151432Swpaul 165267087Swpaul VR_UNLOCK(sc); 165367087Swpaul 165441502Swpaul return; 165541502Swpaul} 165641502Swpaul 165741502Swpaul/* 165841502Swpaul * Set media options. 165941502Swpaul */ 1660102336Salfredstatic int 1661102336Salfredvr_ifmedia_upd(ifp) 166241502Swpaul struct ifnet *ifp; 166341502Swpaul{ 166441502Swpaul struct vr_softc *sc; 166541502Swpaul 166641502Swpaul sc = ifp->if_softc; 166741502Swpaul 166851432Swpaul if (ifp->if_flags & IFF_UP) 166951432Swpaul vr_init(sc); 167041502Swpaul 167141502Swpaul return(0); 167241502Swpaul} 167341502Swpaul 167441502Swpaul/* 167541502Swpaul * Report current media status. 167641502Swpaul */ 1677102336Salfredstatic void 1678102336Salfredvr_ifmedia_sts(ifp, ifmr) 167941502Swpaul struct ifnet *ifp; 168041502Swpaul struct ifmediareq *ifmr; 168141502Swpaul{ 168241502Swpaul struct vr_softc *sc; 168351432Swpaul struct mii_data *mii; 168441502Swpaul 168541502Swpaul sc = ifp->if_softc; 168651432Swpaul mii = device_get_softc(sc->vr_miibus); 168751432Swpaul mii_pollstat(mii); 168851432Swpaul ifmr->ifm_active = mii->mii_media_active; 168951432Swpaul ifmr->ifm_status = mii->mii_media_status; 169041502Swpaul 169141502Swpaul return; 169241502Swpaul} 169341502Swpaul 1694102336Salfredstatic int 1695102336Salfredvr_ioctl(ifp, command, data) 169641502Swpaul struct ifnet *ifp; 169741502Swpaul u_long command; 169841502Swpaul caddr_t data; 169941502Swpaul{ 170041502Swpaul struct vr_softc *sc = ifp->if_softc; 170141502Swpaul struct ifreq *ifr = (struct ifreq *) data; 170251432Swpaul struct mii_data *mii; 170367087Swpaul int error = 0; 170441502Swpaul 170567087Swpaul VR_LOCK(sc); 170641502Swpaul 170741502Swpaul switch(command) { 170841502Swpaul case SIOCSIFFLAGS: 170941502Swpaul if (ifp->if_flags & IFF_UP) { 171041502Swpaul vr_init(sc); 171141502Swpaul } else { 171241502Swpaul if (ifp->if_flags & IFF_RUNNING) 171341502Swpaul vr_stop(sc); 171441502Swpaul } 171541502Swpaul error = 0; 171641502Swpaul break; 171741502Swpaul case SIOCADDMULTI: 171841502Swpaul case SIOCDELMULTI: 171941502Swpaul vr_setmulti(sc); 172041502Swpaul error = 0; 172141502Swpaul break; 172241502Swpaul case SIOCGIFMEDIA: 172341502Swpaul case SIOCSIFMEDIA: 172451432Swpaul mii = device_get_softc(sc->vr_miibus); 172551432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 172641502Swpaul break; 172741502Swpaul default: 1728106936Ssam error = ether_ioctl(ifp, command, data); 172941502Swpaul break; 173041502Swpaul } 173141502Swpaul 173267087Swpaul VR_UNLOCK(sc); 173341502Swpaul 173441502Swpaul return(error); 173541502Swpaul} 173641502Swpaul 1737102336Salfredstatic void 1738102336Salfredvr_watchdog(ifp) 173941502Swpaul struct ifnet *ifp; 174041502Swpaul{ 174141502Swpaul struct vr_softc *sc; 174241502Swpaul 174341502Swpaul sc = ifp->if_softc; 174441502Swpaul 174567087Swpaul VR_LOCK(sc); 174641502Swpaul ifp->if_oerrors++; 174741502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 174841502Swpaul 174941502Swpaul vr_stop(sc); 175041502Swpaul vr_reset(sc); 175141502Swpaul vr_init(sc); 175241502Swpaul 175341502Swpaul if (ifp->if_snd.ifq_head != NULL) 175441502Swpaul vr_start(ifp); 175541502Swpaul 175667087Swpaul VR_UNLOCK(sc); 175767087Swpaul 175841502Swpaul return; 175941502Swpaul} 176041502Swpaul 176141502Swpaul/* 176241502Swpaul * Stop the adapter and free any mbufs allocated to the 176341502Swpaul * RX and TX lists. 176441502Swpaul */ 1765102336Salfredstatic void 1766102336Salfredvr_stop(sc) 176741502Swpaul struct vr_softc *sc; 176841502Swpaul{ 176941502Swpaul register int i; 177041502Swpaul struct ifnet *ifp; 177141502Swpaul 177267087Swpaul VR_LOCK(sc); 177367087Swpaul 177441502Swpaul ifp = &sc->arpcom.ac_if; 177541502Swpaul ifp->if_timer = 0; 177641502Swpaul 177751432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 177851432Swpaul 177941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 178041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 178141502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 178241502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 178341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 178441502Swpaul 178541502Swpaul /* 178641502Swpaul * Free data in the RX lists. 178741502Swpaul */ 178841502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 178941502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 179041502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 179141502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 179241502Swpaul } 179341502Swpaul } 179441502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 179541502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 179641502Swpaul 179741502Swpaul /* 179841502Swpaul * Free the TX list buffers. 179941502Swpaul */ 180041502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 180141502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 180241502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 180341502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 180441502Swpaul } 180541502Swpaul } 180641502Swpaul 180741502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 180841502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 180941502Swpaul 181041502Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 181167087Swpaul VR_UNLOCK(sc); 181241502Swpaul 181341502Swpaul return; 181441502Swpaul} 181541502Swpaul 181641502Swpaul/* 181741502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 181841502Swpaul * get confused by errant DMAs when rebooting. 181941502Swpaul */ 1820102336Salfredstatic void 1821102336Salfredvr_shutdown(dev) 182249610Swpaul device_t dev; 182341502Swpaul{ 182449610Swpaul struct vr_softc *sc; 182541502Swpaul 182649610Swpaul sc = device_get_softc(dev); 182749610Swpaul 182841502Swpaul vr_stop(sc); 182941502Swpaul 183041502Swpaul return; 183141502Swpaul} 1832