if_vr.c revision 130270
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 33122678Sobrien#include <sys/cdefs.h> 34122678Sobrien__FBSDID("$FreeBSD: head/sys/dev/vr/if_vr.c 130270 2004-06-09 14:34:04Z naddy $"); 35122678Sobrien 3641502Swpaul/* 3741502Swpaul * VIA Rhine fast ethernet PCI NIC driver 3841502Swpaul * 3941502Swpaul * Supports various network adapters based on the VIA Rhine 4041502Swpaul * and Rhine II PCI controllers, including the D-Link DFE530TX. 4141502Swpaul * Datasheets are available at http://www.via.com.tw. 4241502Swpaul * 4341502Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu> 4441502Swpaul * Electrical Engineering Department 4541502Swpaul * Columbia University, New York City 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> 68129878Sphk#include <sys/module.h> 6941502Swpaul#include <sys/socket.h> 7041502Swpaul 7141502Swpaul#include <net/if.h> 7241502Swpaul#include <net/if_arp.h> 7341502Swpaul#include <net/ethernet.h> 7441502Swpaul#include <net/if_dl.h> 7541502Swpaul#include <net/if_media.h> 7641502Swpaul 7741502Swpaul#include <net/bpf.h> 7841502Swpaul 7941502Swpaul#include <vm/vm.h> /* for vtophys */ 8041502Swpaul#include <vm/pmap.h> /* for vtophys */ 8141502Swpaul#include <machine/bus_pio.h> 8241502Swpaul#include <machine/bus_memio.h> 8341502Swpaul#include <machine/bus.h> 8449610Swpaul#include <machine/resource.h> 8549610Swpaul#include <sys/bus.h> 8649610Swpaul#include <sys/rman.h> 8741502Swpaul 8851432Swpaul#include <dev/mii/mii.h> 8951432Swpaul#include <dev/mii/miivar.h> 9051432Swpaul 91119288Simp#include <dev/pci/pcireg.h> 92119288Simp#include <dev/pci/pcivar.h> 9341502Swpaul 9441502Swpaul#define VR_USEIOSPACE 9541502Swpaul 9641502Swpaul#include <pci/if_vrreg.h> 9741502Swpaul 98113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1); 99113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1); 10059758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 10159758Speter 10251432Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 10351432Swpaul#include "miibus_if.h" 10451432Swpaul 105110168Ssilby#undef VR_USESWSHIFT 106110168Ssilby 10741502Swpaul/* 10841502Swpaul * Various supported device vendors/types and their names. 10941502Swpaul */ 11041502Swpaulstatic struct vr_type vr_devs[] = { 11141502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 11241502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 11341502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11441502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11562653Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 11662653Swpaul "VIA VT6102 Rhine II 10/100BaseTX" }, 117110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III, 118110170Ssilby "VIA VT6105 Rhine III 10/100BaseTX" }, 119110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, 120110170Ssilby "VIA VT6105M Rhine III 10/100BaseTX" }, 12144238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 12244238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 12344238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 12444238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 12541502Swpaul { 0, 0, NULL } 12641502Swpaul}; 12741502Swpaul 12892739Salfredstatic int vr_probe (device_t); 12992739Salfredstatic int vr_attach (device_t); 13092739Salfredstatic int vr_detach (device_t); 13141502Swpaul 13292739Salfredstatic int vr_newbuf (struct vr_softc *, 13349610Swpaul struct vr_chain_onefrag *, 13492739Salfred struct mbuf *); 13592739Salfredstatic int vr_encap (struct vr_softc *, struct vr_chain *, 13692739Salfred struct mbuf * ); 13741502Swpaul 13892739Salfredstatic void vr_rxeof (struct vr_softc *); 13992739Salfredstatic void vr_rxeoc (struct vr_softc *); 14092739Salfredstatic void vr_txeof (struct vr_softc *); 14192739Salfredstatic void vr_tick (void *); 14292739Salfredstatic void vr_intr (void *); 14392739Salfredstatic void vr_start (struct ifnet *); 14492739Salfredstatic int vr_ioctl (struct ifnet *, u_long, caddr_t); 14592739Salfredstatic void vr_init (void *); 14692739Salfredstatic void vr_stop (struct vr_softc *); 14792739Salfredstatic void vr_watchdog (struct ifnet *); 14892739Salfredstatic void vr_shutdown (device_t); 14992739Salfredstatic int vr_ifmedia_upd (struct ifnet *); 15092739Salfredstatic void vr_ifmedia_sts (struct ifnet *, struct ifmediareq *); 15141502Swpaul 152110168Ssilby#ifdef VR_USESWSHIFT 15392739Salfredstatic void vr_mii_sync (struct vr_softc *); 15492739Salfredstatic void vr_mii_send (struct vr_softc *, u_int32_t, int); 155110168Ssilby#endif 15692739Salfredstatic int vr_mii_readreg (struct vr_softc *, struct vr_mii_frame *); 15792739Salfredstatic int vr_mii_writereg (struct vr_softc *, struct vr_mii_frame *); 15892739Salfredstatic int vr_miibus_readreg (device_t, int, int); 15992739Salfredstatic int vr_miibus_writereg (device_t, int, int, int); 16092739Salfredstatic void vr_miibus_statchg (device_t); 16141502Swpaul 16292739Salfredstatic void vr_setcfg (struct vr_softc *, int); 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 203113506SmdoddDRIVER_MODULE(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 * Program the 64-bit multicast hash filter. 56541502Swpaul */ 566102336Salfredstatic void 567102336Salfredvr_setmulti(sc) 56841502Swpaul struct vr_softc *sc; 56941502Swpaul{ 57041502Swpaul struct ifnet *ifp; 57141502Swpaul int h = 0; 57241502Swpaul u_int32_t hashes[2] = { 0, 0 }; 57341502Swpaul struct ifmultiaddr *ifma; 57441502Swpaul u_int8_t rxfilt; 57541502Swpaul int mcnt = 0; 57641502Swpaul 57741502Swpaul ifp = &sc->arpcom.ac_if; 57841502Swpaul 57941502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 58041502Swpaul 58141502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 58241502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 58341502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 58441502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 58541502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 58641502Swpaul return; 58741502Swpaul } 58841502Swpaul 58941502Swpaul /* first, zot all the existing hash bits */ 59041502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 59141502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 59241502Swpaul 59341502Swpaul /* now program new ones */ 59472084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 59541502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 59641502Swpaul continue; 597130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 598130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 59941502Swpaul if (h < 32) 60041502Swpaul hashes[0] |= (1 << h); 60141502Swpaul else 60241502Swpaul hashes[1] |= (1 << (h - 32)); 60341502Swpaul mcnt++; 60441502Swpaul } 60541502Swpaul 60641502Swpaul if (mcnt) 60741502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 60841502Swpaul else 60941502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 61041502Swpaul 61141502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 61241502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 61341502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 61441502Swpaul 61541502Swpaul return; 61641502Swpaul} 61741502Swpaul 61841502Swpaul/* 61941502Swpaul * In order to fiddle with the 62041502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 62141502Swpaul * first have to put the transmit and/or receive logic in the idle state. 62241502Swpaul */ 623102336Salfredstatic void 624102336Salfredvr_setcfg(sc, media) 62541502Swpaul struct vr_softc *sc; 62651432Swpaul int media; 62741502Swpaul{ 62841502Swpaul int restart = 0; 62941502Swpaul 63041502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 63141502Swpaul restart = 1; 63241502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 63341502Swpaul } 63441502Swpaul 63551432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 63641502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 63741502Swpaul else 63841502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 63941502Swpaul 64041502Swpaul if (restart) 64141502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 64241502Swpaul 64341502Swpaul return; 64441502Swpaul} 64541502Swpaul 646102336Salfredstatic void 647102336Salfredvr_reset(sc) 64841502Swpaul struct vr_softc *sc; 64941502Swpaul{ 65041502Swpaul register int i; 65141502Swpaul 65241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 65341502Swpaul 65441502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 65541502Swpaul DELAY(10); 65641502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 65741502Swpaul break; 65841502Swpaul } 659107220Ssilby if (i == VR_TIMEOUT) { 660107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 661107220Ssilby printf("vr%d: reset never completed!\n", sc->vr_unit); 662107220Ssilby else { 663107220Ssilby /* Use newer force reset command */ 664107220Ssilby printf("vr%d: Using force reset command.\n", sc->vr_unit); 665107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 666107220Ssilby } 667107220Ssilby } 66841502Swpaul 66941502Swpaul /* Wait a little while for the chip to get its brains in order. */ 67041502Swpaul DELAY(1000); 67141502Swpaul 67241502Swpaul return; 67341502Swpaul} 67441502Swpaul 67541502Swpaul/* 67641502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 67741502Swpaul * IDs against our list and return a device name if we find a match. 67841502Swpaul */ 679102336Salfredstatic int 680102336Salfredvr_probe(dev) 68149610Swpaul device_t dev; 68241502Swpaul{ 68341502Swpaul struct vr_type *t; 68441502Swpaul 68541502Swpaul t = vr_devs; 68641502Swpaul 68741502Swpaul while(t->vr_name != NULL) { 68849610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 68949610Swpaul (pci_get_device(dev) == t->vr_did)) { 69049610Swpaul device_set_desc(dev, t->vr_name); 69149610Swpaul return(0); 69241502Swpaul } 69341502Swpaul t++; 69441502Swpaul } 69541502Swpaul 69649610Swpaul return(ENXIO); 69741502Swpaul} 69841502Swpaul 69941502Swpaul/* 70041502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 70141502Swpaul * setup and ethernet/BPF attach. 70241502Swpaul */ 703102336Salfredstatic int 704102336Salfredvr_attach(dev) 70549610Swpaul device_t dev; 70641502Swpaul{ 70767087Swpaul int i; 70841502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 70941502Swpaul struct vr_softc *sc; 71041502Swpaul struct ifnet *ifp; 71149610Swpaul int unit, error = 0, rid; 71241502Swpaul 71349610Swpaul sc = device_get_softc(dev); 71449610Swpaul unit = device_get_unit(dev); 71541502Swpaul 71693818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 71793818Sjhb MTX_DEF | MTX_RECURSE); 718117208Simp#ifndef BURN_BRIDGES 71941502Swpaul /* 72041502Swpaul * Handle power management nonsense. 72141502Swpaul */ 72272813Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 72372813Swpaul u_int32_t iobase, membase, irq; 72441502Swpaul 72572813Swpaul /* Save important PCI config data. */ 72672813Swpaul iobase = pci_read_config(dev, VR_PCI_LOIO, 4); 72772813Swpaul membase = pci_read_config(dev, VR_PCI_LOMEM, 4); 72872813Swpaul irq = pci_read_config(dev, VR_PCI_INTLINE, 4); 72941502Swpaul 73072813Swpaul /* Reset the power state. */ 73172813Swpaul printf("vr%d: chip is in D%d power mode " 73272813Swpaul "-- setting to D0\n", unit, 73372813Swpaul pci_get_powerstate(dev)); 73472813Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 73541502Swpaul 73641502Swpaul /* Restore PCI config data. */ 73772813Swpaul pci_write_config(dev, VR_PCI_LOIO, iobase, 4); 73872813Swpaul pci_write_config(dev, VR_PCI_LOMEM, membase, 4); 73972813Swpaul pci_write_config(dev, VR_PCI_INTLINE, irq, 4); 74041502Swpaul } 741117208Simp#endif 74241502Swpaul /* 74341502Swpaul * Map control/status registers. 74441502Swpaul */ 74572813Swpaul pci_enable_busmaster(dev); 746107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 74741502Swpaul 74849610Swpaul rid = VR_RID; 749127135Snjl sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE); 75049610Swpaul 75149610Swpaul if (sc->vr_res == NULL) { 75249610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 75349610Swpaul error = ENXIO; 75441502Swpaul goto fail; 75541502Swpaul } 75641502Swpaul 75749610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 75849610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 75941502Swpaul 76041502Swpaul /* Allocate interrupt */ 76149610Swpaul rid = 0; 762127135Snjl sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 76349610Swpaul RF_SHAREABLE | RF_ACTIVE); 76449610Swpaul 76549610Swpaul if (sc->vr_irq == NULL) { 76641502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 76749610Swpaul error = ENXIO; 76841502Swpaul goto fail; 76941502Swpaul } 77041502Swpaul 77176586Swpaul /* 77276586Swpaul * Windows may put the chip in suspend mode when it 77376586Swpaul * shuts down. Be sure to kick it in the head to wake it 77476586Swpaul * up again. 77576586Swpaul */ 77676586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 77776586Swpaul 77841502Swpaul /* Reset the adapter. */ 77941502Swpaul vr_reset(sc); 78041502Swpaul 781110168Ssilby /* 782110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 783110168Ssilby * initialization and disable AUTOPOLL. 784110168Ssilby */ 785110168Ssilby pci_write_config(dev, VR_PCI_MODE, 786110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 787110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 788110168Ssilby 78941502Swpaul /* 79041502Swpaul * Get station address. The way the Rhine chips work, 79141502Swpaul * you're not allowed to directly access the EEPROM once 79241502Swpaul * they've been programmed a special way. Consequently, 79341502Swpaul * we need to read the node address from the PAR0 and PAR1 79441502Swpaul * registers. 79541502Swpaul */ 79641502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 79741502Swpaul DELAY(200); 79841502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 79941502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 80041502Swpaul 80141502Swpaul sc->vr_unit = unit; 80241502Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 80341502Swpaul 80451432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 80551657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 80651432Swpaul 80751432Swpaul if (sc->vr_ldata == NULL) { 80841502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 80949610Swpaul error = ENXIO; 81049610Swpaul goto fail; 81141502Swpaul } 81241502Swpaul 81341502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 81441502Swpaul 81541502Swpaul ifp = &sc->arpcom.ac_if; 81641502Swpaul ifp->if_softc = sc; 817121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 81841502Swpaul ifp->if_mtu = ETHERMTU; 81941502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 82041502Swpaul ifp->if_ioctl = vr_ioctl; 82141502Swpaul ifp->if_start = vr_start; 82241502Swpaul ifp->if_watchdog = vr_watchdog; 82341502Swpaul ifp->if_init = vr_init; 82441502Swpaul ifp->if_baudrate = 10000000; 82543515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 826128118Sru#ifdef DEVICE_POLLING 827128118Sru ifp->if_capabilities |= IFCAP_POLLING; 828128118Sru#endif 829128118Sru ifp->if_capenable = ifp->if_capabilities; 83041502Swpaul 83151432Swpaul /* 83251432Swpaul * Do MII setup. 83351432Swpaul */ 83451432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 83551432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 83641502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 83749610Swpaul error = ENXIO; 83841502Swpaul goto fail; 83941502Swpaul } 84041502Swpaul 84151432Swpaul callout_handle_init(&sc->vr_stat_ch); 84241502Swpaul 84341502Swpaul /* 84463090Sarchie * Call MI attach routine. 84541502Swpaul */ 846106936Ssam ether_ifattach(ifp, eaddr); 84741502Swpaul 848113609Snjl /* Hook interrupt last to avoid having to lock softc */ 849112872Snjl error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET, 850112872Snjl vr_intr, sc, &sc->vr_intrhand); 851112872Snjl 852112872Snjl if (error) { 853112872Snjl printf("vr%d: couldn't set up irq\n", unit); 854113609Snjl ether_ifdetach(ifp); 855112872Snjl goto fail; 856112872Snjl } 857112872Snjl 85841502Swpaulfail: 859112872Snjl if (error) 860112872Snjl vr_detach(dev); 86167087Swpaul 86249610Swpaul return(error); 86341502Swpaul} 86441502Swpaul 865113609Snjl/* 866113609Snjl * Shutdown hardware and free up resources. This can be called any 867113609Snjl * time after the mutex has been initialized. It is called in both 868113609Snjl * the error case in attach and the normal detach case so it needs 869113609Snjl * to be careful about only freeing resources that have actually been 870113609Snjl * allocated. 871113609Snjl */ 872102336Salfredstatic int 873102336Salfredvr_detach(dev) 87449610Swpaul device_t dev; 87549610Swpaul{ 87649610Swpaul struct vr_softc *sc; 87749610Swpaul struct ifnet *ifp; 87849610Swpaul 87949610Swpaul sc = device_get_softc(dev); 880112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 88167087Swpaul VR_LOCK(sc); 88249610Swpaul ifp = &sc->arpcom.ac_if; 88349610Swpaul 884113609Snjl /* These should only be active if attach succeeded */ 885113812Simp if (device_is_attached(dev)) { 886113609Snjl vr_stop(sc); 887112872Snjl ether_ifdetach(ifp); 888113609Snjl } 889113609Snjl if (sc->vr_miibus) 890112872Snjl device_delete_child(dev, sc->vr_miibus); 891113609Snjl bus_generic_detach(dev); 89249610Swpaul 893112872Snjl if (sc->vr_intrhand) 894112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 895112872Snjl if (sc->vr_irq) 896112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 897112872Snjl if (sc->vr_res) 898112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 89951432Swpaul 900112872Snjl if (sc->vr_ldata) 901112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 90249610Swpaul 90367087Swpaul VR_UNLOCK(sc); 90467087Swpaul mtx_destroy(&sc->vr_mtx); 90549610Swpaul 90649610Swpaul return(0); 90749610Swpaul} 90849610Swpaul 90941502Swpaul/* 91041502Swpaul * Initialize the transmit descriptors. 91141502Swpaul */ 912102336Salfredstatic int 913102336Salfredvr_list_tx_init(sc) 91441502Swpaul struct vr_softc *sc; 91541502Swpaul{ 91641502Swpaul struct vr_chain_data *cd; 91741502Swpaul struct vr_list_data *ld; 91841502Swpaul int i; 91941502Swpaul 92041502Swpaul cd = &sc->vr_cdata; 92141502Swpaul ld = sc->vr_ldata; 92241502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 92341502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 92441502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 92541502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 92641502Swpaul &cd->vr_tx_chain[0]; 92741502Swpaul else 92841502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 92941502Swpaul &cd->vr_tx_chain[i + 1]; 93041502Swpaul } 93141502Swpaul 932127901Sru cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0]; 93341502Swpaul 93441502Swpaul return(0); 93541502Swpaul} 93641502Swpaul 93741502Swpaul 93841502Swpaul/* 93941502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 94041502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 94141502Swpaul * points back to the first. 94241502Swpaul */ 943102336Salfredstatic int 944102336Salfredvr_list_rx_init(sc) 94541502Swpaul struct vr_softc *sc; 94641502Swpaul{ 94741502Swpaul struct vr_chain_data *cd; 94841502Swpaul struct vr_list_data *ld; 94941502Swpaul int i; 95041502Swpaul 95141502Swpaul cd = &sc->vr_cdata; 95241502Swpaul ld = sc->vr_ldata; 95341502Swpaul 95441502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 95541502Swpaul cd->vr_rx_chain[i].vr_ptr = 95641502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 95749610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 95841502Swpaul return(ENOBUFS); 95941502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 96041502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 96141502Swpaul &cd->vr_rx_chain[0]; 96241502Swpaul ld->vr_rx_list[i].vr_next = 96341502Swpaul vtophys(&ld->vr_rx_list[0]); 96441502Swpaul } else { 96541502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 96641502Swpaul &cd->vr_rx_chain[i + 1]; 96741502Swpaul ld->vr_rx_list[i].vr_next = 96841502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 96941502Swpaul } 97041502Swpaul } 97141502Swpaul 97241502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 97341502Swpaul 97441502Swpaul return(0); 97541502Swpaul} 97641502Swpaul 97741502Swpaul/* 97841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 97941502Swpaul * Note: the length fields are only 11 bits wide, which means the 98041502Swpaul * largest size we can specify is 2047. This is important because 98141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 98241502Swpaul * overflow the field and make a mess. 98341502Swpaul */ 984102336Salfredstatic int 985102336Salfredvr_newbuf(sc, c, m) 98641502Swpaul struct vr_softc *sc; 98741502Swpaul struct vr_chain_onefrag *c; 98849610Swpaul struct mbuf *m; 98941502Swpaul{ 99041502Swpaul struct mbuf *m_new = NULL; 99141502Swpaul 99249610Swpaul if (m == NULL) { 993111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 99487846Sluigi if (m_new == NULL) 99549610Swpaul return(ENOBUFS); 99641502Swpaul 997111119Simp MCLGET(m_new, M_DONTWAIT); 99849610Swpaul if (!(m_new->m_flags & M_EXT)) { 99949610Swpaul m_freem(m_new); 100049610Swpaul return(ENOBUFS); 100149610Swpaul } 100249610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 100349610Swpaul } else { 100449610Swpaul m_new = m; 100549610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 100649610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 100741502Swpaul } 100841502Swpaul 100949610Swpaul m_adj(m_new, sizeof(u_int64_t)); 101049610Swpaul 101141502Swpaul c->vr_mbuf = m_new; 101241502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 101341502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 101442491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 101541502Swpaul 101641502Swpaul return(0); 101741502Swpaul} 101841502Swpaul 101941502Swpaul/* 102041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 102141502Swpaul * the higher level protocols. 102241502Swpaul */ 1023102336Salfredstatic void 1024102336Salfredvr_rxeof(sc) 102541502Swpaul struct vr_softc *sc; 102641502Swpaul{ 1027127901Sru struct mbuf *m, *m0; 102841502Swpaul struct ifnet *ifp; 102941502Swpaul struct vr_chain_onefrag *cur_rx; 103041502Swpaul int total_len = 0; 103141502Swpaul u_int32_t rxstat; 103241502Swpaul 1033122689Ssam VR_LOCK_ASSERT(sc); 1034122689Ssam 103541502Swpaul ifp = &sc->arpcom.ac_if; 103641502Swpaul 103741502Swpaul while(!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 103841502Swpaul VR_RXSTAT_OWN)) { 1039127901Sru#ifdef DEVICE_POLLING 1040127901Sru if (ifp->if_flags & IFF_POLLING) { 1041127901Sru if (sc->rxcycles <= 0) 1042127901Sru break; 1043127901Sru sc->rxcycles--; 1044127901Sru } 1045127901Sru#endif /* DEVICE_POLLING */ 1046127901Sru m0 = NULL; 104741502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 104841502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 104949610Swpaul m = cur_rx->vr_mbuf; 105041502Swpaul 105141502Swpaul /* 105241502Swpaul * If an error occurs, update stats, clear the 105341502Swpaul * status word and leave the mbuf cluster in place: 105441502Swpaul * it should simply get re-used next time this descriptor 105541502Swpaul * comes up in the ring. 105641502Swpaul */ 105741502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 105841502Swpaul ifp->if_ierrors++; 1059110131Ssilby printf("vr%d: rx error (%02x):", 1060110131Ssilby sc->vr_unit, rxstat & 0x000000ff); 1061110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 1062110131Ssilby printf(" crc error"); 1063110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 1064110131Ssilby printf(" frame alignment error\n"); 1065110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 1066110131Ssilby printf(" FIFO overflow"); 1067110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 1068110131Ssilby printf(" received giant packet"); 1069110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 1070110131Ssilby printf(" received runt packet"); 1071110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 1072110131Ssilby printf(" system bus error"); 1073110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 1074110131Ssilby printf("rx buffer error"); 1075110131Ssilby printf("\n"); 107649610Swpaul vr_newbuf(sc, cur_rx, m); 107741502Swpaul continue; 107841502Swpaul } 107941502Swpaul 108041502Swpaul /* No errors; receive the packet. */ 108141502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 108241502Swpaul 108341502Swpaul /* 108442048Swpaul * XXX The VIA Rhine chip includes the CRC with every 108542048Swpaul * received frame, and there's no way to turn this 108642048Swpaul * behavior off (at least, I can't find anything in 108742048Swpaul * the manual that explains how to do it) so we have 108842048Swpaul * to trim off the CRC manually. 108942048Swpaul */ 109042048Swpaul total_len -= ETHER_CRC_LEN; 109142048Swpaul 109278508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 109378508Sbmilekic NULL); 109449610Swpaul vr_newbuf(sc, cur_rx, m); 109549610Swpaul if (m0 == NULL) { 109641502Swpaul ifp->if_ierrors++; 109741502Swpaul continue; 109841502Swpaul } 109949610Swpaul m = m0; 110041502Swpaul 110141502Swpaul ifp->if_ipackets++; 1102122689Ssam VR_UNLOCK(sc); 1103106936Ssam (*ifp->if_input)(ifp, m); 1104122689Ssam VR_LOCK(sc); 110541502Swpaul } 110641502Swpaul 110741502Swpaul return; 110841502Swpaul} 110941502Swpaul 1110105221Sphkstatic void 1111102336Salfredvr_rxeoc(sc) 111241502Swpaul struct vr_softc *sc; 111341502Swpaul{ 1114110131Ssilby struct ifnet *ifp; 1115110131Ssilby int i; 111641502Swpaul 1117110131Ssilby ifp = &sc->arpcom.ac_if; 1118110131Ssilby 1119110131Ssilby ifp->if_ierrors++; 1120110131Ssilby 1121110131Ssilby VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1122110131Ssilby DELAY(10000); 1123110131Ssilby 1124110131Ssilby for (i = 0x400; 1125110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1126110131Ssilby i--) 1127110131Ssilby ; /* Wait for receiver to stop */ 1128110131Ssilby 1129110131Ssilby if (!i) { 1130110131Ssilby printf("vr%d: rx shutdown error!\n", sc->vr_unit); 1131110131Ssilby sc->vr_flags |= VR_F_RESTART; 1132110131Ssilby return; 1133110131Ssilby } 1134110131Ssilby 113541502Swpaul vr_rxeof(sc); 1136110131Ssilby 113741502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 113841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 113941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 114041502Swpaul 114141502Swpaul return; 114241502Swpaul} 114341502Swpaul 114441502Swpaul/* 114541502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 114641502Swpaul * the list buffers. 114741502Swpaul */ 114841502Swpaul 1149102336Salfredstatic void 1150102336Salfredvr_txeof(sc) 115141502Swpaul struct vr_softc *sc; 115241502Swpaul{ 115341502Swpaul struct vr_chain *cur_tx; 115441502Swpaul struct ifnet *ifp; 115541502Swpaul 115641502Swpaul ifp = &sc->arpcom.ac_if; 115741502Swpaul 115841502Swpaul /* 115941502Swpaul * Go through our tx list and free mbufs for those 116041502Swpaul * frames that have been transmitted. 116141502Swpaul */ 1162127901Sru cur_tx = sc->vr_cdata.vr_tx_cons; 1163127901Sru while (cur_tx->vr_mbuf != NULL) { 116441502Swpaul u_int32_t txstat; 1165110131Ssilby int i; 116641502Swpaul 116741502Swpaul txstat = cur_tx->vr_ptr->vr_status; 116841502Swpaul 1169101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1170101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1171110131Ssilby for (i = 0x400; 1172110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1173110131Ssilby i--) 1174101896Ssilby ; /* Wait for chip to shutdown */ 1175110131Ssilby if (!i) { 1176110131Ssilby printf("vr%d: tx shutdown timeout\n", sc->vr_unit); 1177110131Ssilby sc->vr_flags |= VR_F_RESTART; 1178110131Ssilby break; 1179110131Ssilby } 1180101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1181101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1182101896Ssilby break; 1183101896Ssilby } 1184101896Ssilby 118542491Swpaul if (txstat & VR_TXSTAT_OWN) 118641502Swpaul break; 118741502Swpaul 118841502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 118941502Swpaul ifp->if_oerrors++; 119041502Swpaul if (txstat & VR_TXSTAT_DEFER) 119141502Swpaul ifp->if_collisions++; 119241502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 119341502Swpaul ifp->if_collisions++; 119441502Swpaul } 119541502Swpaul 119641502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 119741502Swpaul 119841502Swpaul ifp->if_opackets++; 1199127901Sru m_freem(cur_tx->vr_mbuf); 1200127901Sru cur_tx->vr_mbuf = NULL; 1201127901Sru ifp->if_flags &= ~IFF_OACTIVE; 120241502Swpaul 1203127901Sru cur_tx = cur_tx->vr_nextdesc; 120441502Swpaul } 1205127901Sru sc->vr_cdata.vr_tx_cons = cur_tx; 1206127901Sru if (cur_tx->vr_mbuf == NULL) 120796677Ssilby ifp->if_timer = 0; 120841502Swpaul} 120941502Swpaul 1210102336Salfredstatic void 1211102336Salfredvr_tick(xsc) 121251432Swpaul void *xsc; 121351432Swpaul{ 121451432Swpaul struct vr_softc *sc; 121551432Swpaul struct mii_data *mii; 121651432Swpaul 121751432Swpaul sc = xsc; 121867087Swpaul VR_LOCK(sc); 1219110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1220110131Ssilby printf("vr%d: restarting\n", sc->vr_unit); 1221110131Ssilby vr_stop(sc); 1222110131Ssilby vr_reset(sc); 1223110131Ssilby vr_init(sc); 1224110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1225110131Ssilby } 1226110131Ssilby 122751432Swpaul mii = device_get_softc(sc->vr_miibus); 122851432Swpaul mii_tick(mii); 122951432Swpaul 123051432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 123151432Swpaul 123267087Swpaul VR_UNLOCK(sc); 123351432Swpaul 123451432Swpaul return; 123551432Swpaul} 123651432Swpaul 1237127901Sru#ifdef DEVICE_POLLING 1238127901Srustatic poll_handler_t vr_poll; 1239127901Sru 1240102336Salfredstatic void 1241127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1242127901Sru{ 1243127901Sru struct vr_softc *sc = ifp->if_softc; 1244127901Sru 1245127901Sru VR_LOCK(sc); 1246128118Sru if (!(ifp->if_capenable & IFCAP_POLLING)) { 1247128118Sru ether_poll_deregister(ifp); 1248128118Sru cmd = POLL_DEREGISTER; 1249128118Sru } 1250127901Sru if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ 1251127901Sru CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 1252127901Sru goto done; 1253127901Sru } 1254127901Sru 1255127901Sru sc->rxcycles = count; 1256127901Sru vr_rxeof(sc); 1257127901Sru vr_txeof(sc); 1258127901Sru if (ifp->if_snd.ifq_head != NULL) 1259127901Sru vr_start(ifp); 1260127901Sru 1261127901Sru if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ 1262127901Sru u_int16_t status; 1263127901Sru 1264127901Sru status = CSR_READ_2(sc, VR_ISR); 1265127901Sru if (status) 1266127901Sru CSR_WRITE_2(sc, VR_ISR, status); 1267127901Sru 1268127901Sru if ((status & VR_INTRS) == 0) 1269127901Sru goto done; 1270127901Sru 1271127901Sru if (status & VR_ISR_RX_DROPPED) { 1272127901Sru printf("vr%d: rx packet lost\n", sc->vr_unit); 1273127901Sru ifp->if_ierrors++; 1274127901Sru } 1275127901Sru 1276127901Sru if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1277127901Sru (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1278127901Sru printf("vr%d: receive error (%04x)", 1279127901Sru sc->vr_unit, status); 1280127901Sru if (status & VR_ISR_RX_NOBUF) 1281127901Sru printf(" no buffers"); 1282127901Sru if (status & VR_ISR_RX_OFLOW) 1283127901Sru printf(" overflow"); 1284127901Sru if (status & VR_ISR_RX_DROPPED) 1285127901Sru printf(" packet lost"); 1286127901Sru printf("\n"); 1287127901Sru vr_rxeoc(sc); 1288127901Sru } 1289127901Sru 1290127901Sru if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1291127901Sru vr_reset(sc); 1292127901Sru vr_init(sc); 1293127901Sru goto done; 1294127901Sru } 1295127901Sru 1296127901Sru if ((status & VR_ISR_UDFI) || 1297127901Sru (status & VR_ISR_TX_ABRT2) || 1298127901Sru (status & VR_ISR_TX_ABRT)) { 1299127901Sru ifp->if_oerrors++; 1300127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1301127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1302127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1303127901Sru } 1304127901Sru } 1305127901Sru } 1306127901Sru 1307127901Srudone: 1308127901Sru VR_UNLOCK(sc); 1309127901Sru 1310127901Sru} 1311127901Sru#endif /* DEVICE_POLLING */ 1312127901Sru 1313127901Srustatic void 1314102336Salfredvr_intr(arg) 131541502Swpaul void *arg; 131641502Swpaul{ 131741502Swpaul struct vr_softc *sc; 131841502Swpaul struct ifnet *ifp; 131941502Swpaul u_int16_t status; 132041502Swpaul 132141502Swpaul sc = arg; 132267087Swpaul VR_LOCK(sc); 132341502Swpaul ifp = &sc->arpcom.ac_if; 132441502Swpaul 1325127901Sru#ifdef DEVICE_POLLING 1326127901Sru if (ifp->if_flags & IFF_POLLING) 1327127901Sru goto done; 1328128118Sru if ((ifp->if_capenable & IFCAP_POLLING) && 1329128118Sru ether_poll_register(vr_poll, ifp)) { /* ok, disable interrupts */ 1330127901Sru CSR_WRITE_2(sc, VR_IMR, 0x0000); 1331127901Sru vr_poll(ifp, 0, 1); 1332127901Sru goto done; 1333127901Sru } 1334127901Sru#endif /* DEVICE_POLLING */ 1335127901Sru 133641502Swpaul /* Supress unwanted interrupts. */ 133741502Swpaul if (!(ifp->if_flags & IFF_UP)) { 133841502Swpaul vr_stop(sc); 133967087Swpaul VR_UNLOCK(sc); 134041502Swpaul return; 134141502Swpaul } 134241502Swpaul 134341502Swpaul /* Disable interrupts. */ 134441502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 134541502Swpaul 134641502Swpaul for (;;) { 134741502Swpaul 134841502Swpaul status = CSR_READ_2(sc, VR_ISR); 134941502Swpaul if (status) 135041502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 135141502Swpaul 135241502Swpaul if ((status & VR_INTRS) == 0) 135341502Swpaul break; 135441502Swpaul 135541502Swpaul if (status & VR_ISR_RX_OK) 135641502Swpaul vr_rxeof(sc); 135741502Swpaul 1358110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1359110131Ssilby printf("vr%d: rx packet lost\n", sc->vr_unit); 1360110131Ssilby ifp->if_ierrors++; 1361110131Ssilby } 1362110131Ssilby 136341502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1364110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1365110131Ssilby printf("vr%d: receive error (%04x)", 1366110131Ssilby sc->vr_unit, status); 1367110131Ssilby if (status & VR_ISR_RX_NOBUF) 1368110131Ssilby printf(" no buffers"); 1369110131Ssilby if (status & VR_ISR_RX_OFLOW) 1370110131Ssilby printf(" overflow"); 1371110131Ssilby if (status & VR_ISR_RX_DROPPED) 1372110131Ssilby printf(" packet lost"); 1373110131Ssilby printf("\n"); 137441502Swpaul vr_rxeoc(sc); 137541502Swpaul } 137641502Swpaul 1377101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1378101896Ssilby vr_reset(sc); 1379101896Ssilby vr_init(sc); 1380101896Ssilby break; 138141502Swpaul } 138241502Swpaul 1383101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1384101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 138541502Swpaul vr_txeof(sc); 1386101896Ssilby if ((status & VR_ISR_UDFI) || 1387101896Ssilby (status & VR_ISR_TX_ABRT2) || 1388101896Ssilby (status & VR_ISR_TX_ABRT)) { 1389101896Ssilby ifp->if_oerrors++; 1390127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1391101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1392101896Ssilby VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1393101896Ssilby } 1394127901Sru } 139541502Swpaul } 139641502Swpaul 139741502Swpaul } 139841502Swpaul 139941502Swpaul /* Re-enable interrupts. */ 140041502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 140141502Swpaul 140241502Swpaul if (ifp->if_snd.ifq_head != NULL) { 140341502Swpaul vr_start(ifp); 140441502Swpaul } 140541502Swpaul 1406127901Sru#ifdef DEVICE_POLLING 1407127901Srudone: 1408127901Sru#endif /* DEVICE_POLLING */ 140967087Swpaul VR_UNLOCK(sc); 141067087Swpaul 141141502Swpaul return; 141241502Swpaul} 141341502Swpaul 141441502Swpaul/* 141541502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 141641502Swpaul * pointers to the fragment pointers. 141741502Swpaul */ 1418102336Salfredstatic int 1419102336Salfredvr_encap(sc, c, m_head) 142041502Swpaul struct vr_softc *sc; 142141502Swpaul struct vr_chain *c; 142241502Swpaul struct mbuf *m_head; 142341502Swpaul{ 142441502Swpaul struct vr_desc *f = NULL; 142541502Swpaul struct mbuf *m; 142641502Swpaul 142741502Swpaul /* 142841502Swpaul * The VIA Rhine wants packet buffers to be longword 142941502Swpaul * aligned, but very often our mbufs aren't. Rather than 143041502Swpaul * waste time trying to decide when to copy and when not 143141502Swpaul * to copy, just do it all the time. 143241502Swpaul */ 1433127901Sru m = m_defrag(m_head, M_DONTWAIT); 1434127901Sru if (m == NULL) { 1435127901Sru return(1); 1436127901Sru } 143741502Swpaul 1438127901Sru /* 1439127901Sru * The Rhine chip doesn't auto-pad, so we have to make 1440127901Sru * sure to pad short frames out to the minimum frame length 1441127901Sru * ourselves. 1442127901Sru */ 1443127901Sru if (m->m_len < VR_MIN_FRAMELEN) { 1444127901Sru m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len; 1445127901Sru m->m_len = m->m_pkthdr.len; 144641502Swpaul } 144741502Swpaul 1448127901Sru c->vr_mbuf = m; 1449127901Sru f = c->vr_ptr; 1450127901Sru f->vr_data = vtophys(mtod(m, caddr_t)); 1451127901Sru f->vr_ctl = m->m_len; 1452127901Sru f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 1453127901Sru f->vr_status = 0; 1454127901Sru f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 1455127901Sru f->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 145641502Swpaul 145741502Swpaul return(0); 145841502Swpaul} 145941502Swpaul 146041502Swpaul/* 146141502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 146241502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 146341502Swpaul * copy of the pointers since the transmit list fragment pointers are 146441502Swpaul * physical addresses. 146541502Swpaul */ 146641502Swpaul 1467102336Salfredstatic void 1468102336Salfredvr_start(ifp) 146941502Swpaul struct ifnet *ifp; 147041502Swpaul{ 147141502Swpaul struct vr_softc *sc; 1472127901Sru struct mbuf *m_head; 1473127901Sru struct vr_chain *cur_tx; 147441502Swpaul 1475127901Sru if (ifp->if_flags & IFF_OACTIVE) 1476127901Sru return; 1477127901Sru 147841502Swpaul sc = ifp->if_softc; 147941502Swpaul 148067087Swpaul VR_LOCK(sc); 148141502Swpaul 1482127901Sru cur_tx = sc->vr_cdata.vr_tx_prod; 1483127901Sru while (cur_tx->vr_mbuf == NULL) { 148441502Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 148541502Swpaul if (m_head == NULL) 148641502Swpaul break; 148741502Swpaul 148841502Swpaul /* Pack the data into the descriptor. */ 148971271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 1490113274Ssilby /* Rollback, send what we were able to encap. */ 149171271Swpaul IF_PREPEND(&ifp->if_snd, m_head); 149271271Swpaul break; 149371271Swpaul } 149441502Swpaul 1495127901Sru 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 1503127901Sru cur_tx = cur_tx->vr_nextdesc; 150441502Swpaul } 1505127901Sru if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) { 1506127901Sru sc->vr_cdata.vr_tx_prod = cur_tx; 150741502Swpaul 1508127901Sru /* Tell the chip to start transmitting. */ 1509127901Sru VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/VR_CMD_TX_GO); 151041526Swpaul 1511127901Sru /* Set a timeout in case the chip goes out to lunch. */ 1512127901Sru ifp->if_timer = 5; 151341502Swpaul 1514127901Sru if (cur_tx->vr_mbuf != NULL) 1515127901Sru ifp->if_flags |= IFF_OACTIVE; 1516127901Sru } 151741502Swpaul 151867087Swpaul VR_UNLOCK(sc); 151941502Swpaul 152041502Swpaul return; 152141502Swpaul} 152241502Swpaul 1523102336Salfredstatic void 1524102336Salfredvr_init(xsc) 152541502Swpaul void *xsc; 152641502Swpaul{ 152741502Swpaul struct vr_softc *sc = xsc; 152841502Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 152951432Swpaul struct mii_data *mii; 153073963Swpaul int i; 153141502Swpaul 153267087Swpaul VR_LOCK(sc); 153341502Swpaul 153451432Swpaul mii = device_get_softc(sc->vr_miibus); 153541502Swpaul 153641502Swpaul /* 153741502Swpaul * Cancel pending I/O and free all RX/TX buffers. 153841502Swpaul */ 153941502Swpaul vr_stop(sc); 154041502Swpaul vr_reset(sc); 154141502Swpaul 154273963Swpaul /* 154373963Swpaul * Set our station address. 154473963Swpaul */ 154573963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 154673963Swpaul CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]); 1547101375Ssilby 1548101375Ssilby /* Set DMA size */ 1549101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1550101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 155173963Swpaul 1552101375Ssilby /* 1553101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1554101108Ssilby * so we must set both. 1555101108Ssilby */ 1556101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1557110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1558101108Ssilby 1559101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1560101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1561101108Ssilby 156241502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1563110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 156441502Swpaul 156541502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 156641502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 156741502Swpaul 156841502Swpaul /* Init circular RX list. */ 156941502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 157041502Swpaul printf("vr%d: initialization failed: no " 157141502Swpaul "memory for rx buffers\n", sc->vr_unit); 157241502Swpaul vr_stop(sc); 157367087Swpaul VR_UNLOCK(sc); 157441502Swpaul return; 157541502Swpaul } 157641502Swpaul 157741502Swpaul /* 157841502Swpaul * Init tx descriptors. 157941502Swpaul */ 158041502Swpaul vr_list_tx_init(sc); 158141502Swpaul 158241502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 158341502Swpaul if (ifp->if_flags & IFF_PROMISC) 158441502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 158541502Swpaul else 158641502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 158741502Swpaul 158841502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 158941502Swpaul if (ifp->if_flags & IFF_BROADCAST) 159041502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 159141502Swpaul else 159241502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 159341502Swpaul 159441502Swpaul /* 159541502Swpaul * Program the multicast filter, if necessary. 159641502Swpaul */ 159741502Swpaul vr_setmulti(sc); 159841502Swpaul 159941502Swpaul /* 160041502Swpaul * Load the address of the RX list. 160141502Swpaul */ 160241502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 160341502Swpaul 160441502Swpaul /* Enable receiver and transmitter. */ 160541502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 160641502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 160741502Swpaul VR_CMD_RX_GO); 160841502Swpaul 160941502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 161041502Swpaul 1611127901Sru CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 1612127901Sru#ifdef DEVICE_POLLING 161341502Swpaul /* 1614127901Sru * Disable interrupts if we are polling. 1615127901Sru */ 1616127901Sru if (ifp->if_flags & IFF_POLLING) 1617127901Sru CSR_WRITE_2(sc, VR_IMR, 0); 1618127901Sru else 1619127901Sru#endif /* DEVICE_POLLING */ 1620127901Sru /* 162141502Swpaul * Enable interrupts. 162241502Swpaul */ 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; 1707128118Sru case SIOCSIFCAP: 1708128118Sru ifp->if_capenable = ifr->ifr_reqcap; 1709128118Sru break; 171041502Swpaul default: 1711106936Ssam error = ether_ioctl(ifp, command, data); 171241502Swpaul break; 171341502Swpaul } 171441502Swpaul 171567087Swpaul VR_UNLOCK(sc); 171641502Swpaul 171741502Swpaul return(error); 171841502Swpaul} 171941502Swpaul 1720102336Salfredstatic void 1721102336Salfredvr_watchdog(ifp) 172241502Swpaul struct ifnet *ifp; 172341502Swpaul{ 172441502Swpaul struct vr_softc *sc; 172541502Swpaul 172641502Swpaul sc = ifp->if_softc; 172741502Swpaul 172867087Swpaul VR_LOCK(sc); 172941502Swpaul ifp->if_oerrors++; 173041502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 173141502Swpaul 173241502Swpaul vr_stop(sc); 173341502Swpaul vr_reset(sc); 173441502Swpaul vr_init(sc); 173541502Swpaul 173641502Swpaul if (ifp->if_snd.ifq_head != NULL) 173741502Swpaul vr_start(ifp); 173841502Swpaul 173967087Swpaul VR_UNLOCK(sc); 174067087Swpaul 174141502Swpaul return; 174241502Swpaul} 174341502Swpaul 174441502Swpaul/* 174541502Swpaul * Stop the adapter and free any mbufs allocated to the 174641502Swpaul * RX and TX lists. 174741502Swpaul */ 1748102336Salfredstatic void 1749102336Salfredvr_stop(sc) 175041502Swpaul struct vr_softc *sc; 175141502Swpaul{ 175241502Swpaul register int i; 175341502Swpaul struct ifnet *ifp; 175441502Swpaul 175567087Swpaul VR_LOCK(sc); 175667087Swpaul 175741502Swpaul ifp = &sc->arpcom.ac_if; 175841502Swpaul ifp->if_timer = 0; 175941502Swpaul 176051432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 1761127901Sru ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1762127901Sru#ifdef DEVICE_POLLING 1763127901Sru ether_poll_deregister(ifp); 1764127901Sru#endif /* DEVICE_POLLING */ 176551432Swpaul 176641502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 176741502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 176841502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 176941502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 177041502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 177141502Swpaul 177241502Swpaul /* 177341502Swpaul * Free data in the RX lists. 177441502Swpaul */ 177541502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 177641502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 177741502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 177841502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 177941502Swpaul } 178041502Swpaul } 178141502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 178241502Swpaul sizeof(sc->vr_ldata->vr_rx_list)); 178341502Swpaul 178441502Swpaul /* 178541502Swpaul * Free the TX list buffers. 178641502Swpaul */ 178741502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 178841502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 178941502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 179041502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 179141502Swpaul } 179241502Swpaul } 179341502Swpaul 179441502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 179541502Swpaul sizeof(sc->vr_ldata->vr_tx_list)); 179641502Swpaul 179767087Swpaul VR_UNLOCK(sc); 179841502Swpaul 179941502Swpaul return; 180041502Swpaul} 180141502Swpaul 180241502Swpaul/* 180341502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 180441502Swpaul * get confused by errant DMAs when rebooting. 180541502Swpaul */ 1806102336Salfredstatic void 1807102336Salfredvr_shutdown(dev) 180849610Swpaul device_t dev; 180941502Swpaul{ 181049610Swpaul struct vr_softc *sc; 181141502Swpaul 181249610Swpaul sc = device_get_softc(dev); 181349610Swpaul 181441502Swpaul vr_stop(sc); 181541502Swpaul 181641502Swpaul return; 181741502Swpaul} 1818