if_vr.c revision 151911
1139825Simp/*- 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 151911 2005-10-31 21:37:27Z jhb $"); 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 */ 47131503Sbms 4841502Swpaul/* 4941502Swpaul * The VIA Rhine controllers are similar in some respects to the 5041502Swpaul * the DEC tulip chips, except less complicated. The controller 5141502Swpaul * uses an MII bus and an external physical layer interface. The 5241502Swpaul * receiver has a one entry perfect filter and a 64-bit hash table 5341502Swpaul * multicast filter. Transmit and receive descriptors are similar 5441502Swpaul * to the tulip. 5541502Swpaul * 5641502Swpaul * The Rhine has a serious flaw in its transmit DMA mechanism: 5741502Swpaul * transmit buffers must be longword aligned. Unfortunately, 5841502Swpaul * FreeBSD doesn't guarantee that mbufs will be filled in starting 5941502Swpaul * at longword boundaries, so we have to do a buffer copy before 6041502Swpaul * transmission. 6141502Swpaul */ 6241502Swpaul 63150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS 64150968Sglebius#include "opt_device_polling.h" 65150968Sglebius#endif 66150968Sglebius 6741502Swpaul#include <sys/param.h> 6841502Swpaul#include <sys/systm.h> 6941502Swpaul#include <sys/sockio.h> 7041502Swpaul#include <sys/mbuf.h> 7141502Swpaul#include <sys/malloc.h> 7241502Swpaul#include <sys/kernel.h> 73129878Sphk#include <sys/module.h> 7441502Swpaul#include <sys/socket.h> 7541502Swpaul 7641502Swpaul#include <net/if.h> 7741502Swpaul#include <net/if_arp.h> 7841502Swpaul#include <net/ethernet.h> 7941502Swpaul#include <net/if_dl.h> 8041502Swpaul#include <net/if_media.h> 81147256Sbrooks#include <net/if_types.h> 8241502Swpaul 8341502Swpaul#include <net/bpf.h> 8441502Swpaul 85131503Sbms#include <vm/vm.h> /* for vtophys */ 86131503Sbms#include <vm/pmap.h> /* for vtophys */ 8741502Swpaul#include <machine/bus.h> 8849610Swpaul#include <machine/resource.h> 8949610Swpaul#include <sys/bus.h> 9049610Swpaul#include <sys/rman.h> 9141502Swpaul 9251432Swpaul#include <dev/mii/mii.h> 9351432Swpaul#include <dev/mii/miivar.h> 9451432Swpaul 95119288Simp#include <dev/pci/pcireg.h> 96119288Simp#include <dev/pci/pcivar.h> 9741502Swpaul 9841502Swpaul#define VR_USEIOSPACE 9941502Swpaul 10041502Swpaul#include <pci/if_vrreg.h> 10141502Swpaul 102113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1); 103113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1); 10459758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 10559758Speter 106151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 10751432Swpaul#include "miibus_if.h" 10851432Swpaul 109110168Ssilby#undef VR_USESWSHIFT 110110168Ssilby 11141502Swpaul/* 11241502Swpaul * Various supported device vendors/types and their names. 11341502Swpaul */ 11441502Swpaulstatic struct vr_type vr_devs[] = { 11541502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 11641502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 11741502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11841502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11962653Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 12062653Swpaul "VIA VT6102 Rhine II 10/100BaseTX" }, 121110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III, 122110170Ssilby "VIA VT6105 Rhine III 10/100BaseTX" }, 123110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, 124110170Ssilby "VIA VT6105M Rhine III 10/100BaseTX" }, 12544238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 12644238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 12744238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 12844238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 12941502Swpaul { 0, 0, NULL } 13041502Swpaul}; 13141502Swpaul 132142407Simpstatic int vr_probe(device_t); 133142407Simpstatic int vr_attach(device_t); 134142407Simpstatic int vr_detach(device_t); 13541502Swpaul 136142407Simpstatic int vr_newbuf(struct vr_softc *, struct vr_chain_onefrag *, 137142407Simp struct mbuf *); 138142407Simpstatic int vr_encap(struct vr_softc *, struct vr_chain *, struct mbuf * ); 13941502Swpaul 140142407Simpstatic void vr_rxeof(struct vr_softc *); 141142407Simpstatic void vr_rxeoc(struct vr_softc *); 142142407Simpstatic void vr_txeof(struct vr_softc *); 143142407Simpstatic void vr_tick(void *); 144142407Simpstatic void vr_intr(void *); 145142407Simpstatic void vr_start(struct ifnet *); 146142407Simpstatic void vr_start_locked(struct ifnet *); 147142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t); 148142407Simpstatic void vr_init(void *); 149142407Simpstatic void vr_init_locked(struct vr_softc *); 150142407Simpstatic void vr_stop(struct vr_softc *); 151142407Simpstatic void vr_watchdog(struct ifnet *); 152142407Simpstatic void vr_shutdown(device_t); 153142407Simpstatic int vr_ifmedia_upd(struct ifnet *); 154142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *); 15541502Swpaul 156110168Ssilby#ifdef VR_USESWSHIFT 157142407Simpstatic void vr_mii_sync(struct vr_softc *); 158142407Simpstatic void vr_mii_send(struct vr_softc *, uint32_t, int); 159110168Ssilby#endif 160142407Simpstatic int vr_mii_readreg(struct vr_softc *, struct vr_mii_frame *); 161142407Simpstatic int vr_mii_writereg(struct vr_softc *, struct vr_mii_frame *); 162142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t); 163142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t); 164142407Simpstatic void vr_miibus_statchg(device_t); 16541502Swpaul 166142407Simpstatic void vr_setcfg(struct vr_softc *, int); 167142407Simpstatic void vr_setmulti(struct vr_softc *); 168142407Simpstatic void vr_reset(struct vr_softc *); 169142407Simpstatic int vr_list_rx_init(struct vr_softc *); 170142407Simpstatic int vr_list_tx_init(struct vr_softc *); 17141502Swpaul 17249610Swpaul#ifdef VR_USEIOSPACE 17349610Swpaul#define VR_RES SYS_RES_IOPORT 17449610Swpaul#define VR_RID VR_PCI_LOIO 17549610Swpaul#else 17649610Swpaul#define VR_RES SYS_RES_MEMORY 17749610Swpaul#define VR_RID VR_PCI_LOMEM 17849610Swpaul#endif 17949610Swpaul 18049610Swpaulstatic device_method_t vr_methods[] = { 18149610Swpaul /* Device interface */ 18249610Swpaul DEVMETHOD(device_probe, vr_probe), 18349610Swpaul DEVMETHOD(device_attach, vr_attach), 18449610Swpaul DEVMETHOD(device_detach, vr_detach), 18549610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 18651432Swpaul 18751432Swpaul /* bus interface */ 18851432Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 18951432Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 19051432Swpaul 19151432Swpaul /* MII interface */ 19251432Swpaul DEVMETHOD(miibus_readreg, vr_miibus_readreg), 19351432Swpaul DEVMETHOD(miibus_writereg, vr_miibus_writereg), 19451432Swpaul DEVMETHOD(miibus_statchg, vr_miibus_statchg), 19551432Swpaul 19649610Swpaul { 0, 0 } 19749610Swpaul}; 19849610Swpaul 19949610Swpaulstatic driver_t vr_driver = { 20051455Swpaul "vr", 20149610Swpaul vr_methods, 20249610Swpaul sizeof(struct vr_softc) 20349610Swpaul}; 20449610Swpaul 20549610Swpaulstatic devclass_t vr_devclass; 20649610Swpaul 207113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0); 20851473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0); 20949610Swpaul 21041502Swpaul#define VR_SETBIT(sc, reg, x) \ 21141502Swpaul CSR_WRITE_1(sc, reg, \ 212105221Sphk CSR_READ_1(sc, reg) | (x)) 21341502Swpaul 21441502Swpaul#define VR_CLRBIT(sc, reg, x) \ 21541502Swpaul CSR_WRITE_1(sc, reg, \ 216105221Sphk CSR_READ_1(sc, reg) & ~(x)) 21741502Swpaul 21841502Swpaul#define VR_SETBIT16(sc, reg, x) \ 21941502Swpaul CSR_WRITE_2(sc, reg, \ 220105221Sphk CSR_READ_2(sc, reg) | (x)) 22141502Swpaul 22241502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 22341502Swpaul CSR_WRITE_2(sc, reg, \ 224105221Sphk CSR_READ_2(sc, reg) & ~(x)) 22541502Swpaul 22641502Swpaul#define VR_SETBIT32(sc, reg, x) \ 22741502Swpaul CSR_WRITE_4(sc, reg, \ 228105221Sphk CSR_READ_4(sc, reg) | (x)) 22941502Swpaul 23041502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 23141502Swpaul CSR_WRITE_4(sc, reg, \ 232105221Sphk CSR_READ_4(sc, reg) & ~(x)) 23341502Swpaul 23441502Swpaul#define SIO_SET(x) \ 23541502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 236105221Sphk CSR_READ_1(sc, VR_MIICMD) | (x)) 23741502Swpaul 23841502Swpaul#define SIO_CLR(x) \ 23941502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 240105221Sphk CSR_READ_1(sc, VR_MIICMD) & ~(x)) 24141502Swpaul 242110168Ssilby#ifdef VR_USESWSHIFT 24341502Swpaul/* 24441502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 24541502Swpaul */ 246102336Salfredstatic void 247131503Sbmsvr_mii_sync(struct vr_softc *sc) 24841502Swpaul{ 249131503Sbms register int i; 25041502Swpaul 25141502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 25241502Swpaul 25341502Swpaul for (i = 0; i < 32; i++) { 25441502Swpaul SIO_SET(VR_MIICMD_CLK); 25541502Swpaul DELAY(1); 25641502Swpaul SIO_CLR(VR_MIICMD_CLK); 25741502Swpaul DELAY(1); 25841502Swpaul } 25941502Swpaul} 26041502Swpaul 26141502Swpaul/* 26241502Swpaul * Clock a series of bits through the MII. 26341502Swpaul */ 264102336Salfredstatic void 265131503Sbmsvr_mii_send(struct vr_softc *sc, uint32_t bits, int cnt) 26641502Swpaul{ 267131503Sbms int i; 26841502Swpaul 26941502Swpaul SIO_CLR(VR_MIICMD_CLK); 27041502Swpaul 27141502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 272131503Sbms if (bits & i) { 27341502Swpaul SIO_SET(VR_MIICMD_DATAIN); 274131503Sbms } else { 27541502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 276131503Sbms } 27741502Swpaul DELAY(1); 27841502Swpaul SIO_CLR(VR_MIICMD_CLK); 27941502Swpaul DELAY(1); 28041502Swpaul SIO_SET(VR_MIICMD_CLK); 28141502Swpaul } 28241502Swpaul} 283110168Ssilby#endif 28441502Swpaul 28541502Swpaul/* 28641502Swpaul * Read an PHY register through the MII. 28741502Swpaul */ 288102336Salfredstatic int 289131503Sbmsvr_mii_readreg(struct vr_softc *sc, struct vr_mii_frame *frame) 290131503Sbms#ifdef VR_USESWSHIFT 29141502Swpaul{ 292131503Sbms int i, ack; 29341502Swpaul 294131503Sbms /* Set up frame for RX. */ 29541502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 29641502Swpaul frame->mii_opcode = VR_MII_READOP; 29741502Swpaul frame->mii_turnaround = 0; 29841502Swpaul frame->mii_data = 0; 299131503Sbms 30041502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 30141502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 30241502Swpaul 303131503Sbms /* Turn on data xmit. */ 30441502Swpaul SIO_SET(VR_MIICMD_DIR); 30541502Swpaul 30641502Swpaul vr_mii_sync(sc); 30741502Swpaul 308131503Sbms /* Send command/address info. */ 30941502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 31041502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 31141502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 31241502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 31341502Swpaul 314131503Sbms /* Idle bit. */ 31541502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 31641502Swpaul DELAY(1); 31741502Swpaul SIO_SET(VR_MIICMD_CLK); 31841502Swpaul DELAY(1); 31941502Swpaul 32041502Swpaul /* Turn off xmit. */ 32141502Swpaul SIO_CLR(VR_MIICMD_DIR); 32241502Swpaul 32341502Swpaul /* Check for ack */ 32441502Swpaul SIO_CLR(VR_MIICMD_CLK); 32541502Swpaul DELAY(1); 326109058Smbr ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 32741502Swpaul SIO_SET(VR_MIICMD_CLK); 32841502Swpaul DELAY(1); 32941502Swpaul 33041502Swpaul /* 33141502Swpaul * Now try reading data bits. If the ack failed, we still 33241502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 33341502Swpaul */ 33441502Swpaul if (ack) { 33541502Swpaul for(i = 0; i < 16; i++) { 33641502Swpaul SIO_CLR(VR_MIICMD_CLK); 33741502Swpaul DELAY(1); 33841502Swpaul SIO_SET(VR_MIICMD_CLK); 33941502Swpaul DELAY(1); 34041502Swpaul } 34141502Swpaul goto fail; 34241502Swpaul } 34341502Swpaul 34441502Swpaul for (i = 0x8000; i; i >>= 1) { 34541502Swpaul SIO_CLR(VR_MIICMD_CLK); 34641502Swpaul DELAY(1); 34741502Swpaul if (!ack) { 34841502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 34941502Swpaul frame->mii_data |= i; 35041502Swpaul DELAY(1); 35141502Swpaul } 35241502Swpaul SIO_SET(VR_MIICMD_CLK); 35341502Swpaul DELAY(1); 35441502Swpaul } 35541502Swpaul 35641502Swpaulfail: 35741502Swpaul SIO_CLR(VR_MIICMD_CLK); 35841502Swpaul DELAY(1); 35941502Swpaul SIO_SET(VR_MIICMD_CLK); 36041502Swpaul DELAY(1); 36141502Swpaul 36241502Swpaul if (ack) 363131503Sbms return (1); 364131503Sbms return (0); 36541502Swpaul} 366110168Ssilby#else 367110168Ssilby{ 368131518Sbms int i; 36941502Swpaul 370131503Sbms /* Set the PHY address. */ 371110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 372110168Ssilby frame->mii_phyaddr); 373110168Ssilby 374131503Sbms /* Set the register address. */ 375110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 376110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB); 377131503Sbms 378110168Ssilby for (i = 0; i < 10000; i++) { 379110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0) 380110168Ssilby break; 381110168Ssilby DELAY(1); 382110168Ssilby } 383110168Ssilby frame->mii_data = CSR_READ_2(sc, VR_MIIDATA); 384110168Ssilby 385131503Sbms return (0); 386110168Ssilby} 387110168Ssilby#endif 388110168Ssilby 389110168Ssilby 39041502Swpaul/* 39141502Swpaul * Write to a PHY register through the MII. 39241502Swpaul */ 393102336Salfredstatic int 394131503Sbmsvr_mii_writereg(struct vr_softc *sc, struct vr_mii_frame *frame) 395131503Sbms#ifdef VR_USESWSHIFT 39641502Swpaul{ 39741502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 39841502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 39941502Swpaul 400131503Sbms /* Set up frame for TX. */ 40141502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 40241502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 40341502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 404131503Sbms 405131503Sbms /* Turn on data output. */ 40641502Swpaul SIO_SET(VR_MIICMD_DIR); 40741502Swpaul 40841502Swpaul vr_mii_sync(sc); 40941502Swpaul 41041502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 41141502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 41241502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 41341502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 41441502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 41541502Swpaul vr_mii_send(sc, frame->mii_data, 16); 41641502Swpaul 41741502Swpaul /* Idle bit. */ 41841502Swpaul SIO_SET(VR_MIICMD_CLK); 41941502Swpaul DELAY(1); 42041502Swpaul SIO_CLR(VR_MIICMD_CLK); 42141502Swpaul DELAY(1); 42241502Swpaul 423131503Sbms /* Turn off xmit. */ 42441502Swpaul SIO_CLR(VR_MIICMD_DIR); 42541502Swpaul 426131503Sbms return (0); 42741502Swpaul} 428110168Ssilby#else 429110168Ssilby{ 430131518Sbms int i; 43141502Swpaul 432131503Sbms /* Set the PHY address. */ 433110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 434131503Sbms frame->mii_phyaddr); 435110168Ssilby 436131503Sbms /* Set the register address and data to write. */ 437110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 438110168Ssilby CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data); 439110168Ssilby 440110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB); 441110168Ssilby 442110168Ssilby for (i = 0; i < 10000; i++) { 443110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0) 444110168Ssilby break; 445110168Ssilby DELAY(1); 446110168Ssilby } 447110168Ssilby 448131503Sbms return (0); 449110168Ssilby} 450110168Ssilby#endif 451110168Ssilby 452102336Salfredstatic int 453131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg) 45451432Swpaul{ 45541502Swpaul struct vr_mii_frame frame; 456131503Sbms struct vr_softc *sc = device_get_softc(dev); 45741502Swpaul 458110168Ssilby switch (sc->vr_revid) { 459131503Sbms case REV_ID_VT6102_APOLLO: 460131518Sbms if (phy != 1) { 461131518Sbms frame.mii_data = 0; 462131518Sbms goto out; 463131518Sbms } 464131503Sbms default: 465131503Sbms break; 466131503Sbms } 467110168Ssilby 46841502Swpaul bzero((char *)&frame, sizeof(frame)); 46951432Swpaul frame.mii_phyaddr = phy; 47041502Swpaul frame.mii_regaddr = reg; 47141502Swpaul vr_mii_readreg(sc, &frame); 47241502Swpaul 473131518Sbmsout: 474131503Sbms return (frame.mii_data); 47541502Swpaul} 47641502Swpaul 477102336Salfredstatic int 478131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data) 47951432Swpaul{ 48041502Swpaul struct vr_mii_frame frame; 481131503Sbms struct vr_softc *sc = device_get_softc(dev); 48241502Swpaul 483110168Ssilby switch (sc->vr_revid) { 484131503Sbms case REV_ID_VT6102_APOLLO: 485131503Sbms if (phy != 1) 486131503Sbms return (0); 487131503Sbms default: 488131503Sbms break; 489131503Sbms } 490110168Ssilby 49141502Swpaul bzero((char *)&frame, sizeof(frame)); 49251432Swpaul frame.mii_phyaddr = phy; 49341502Swpaul frame.mii_regaddr = reg; 49441502Swpaul frame.mii_data = data; 49541502Swpaul vr_mii_writereg(sc, &frame); 49641502Swpaul 497131503Sbms return (0); 49851432Swpaul} 49951432Swpaul 500102336Salfredstatic void 501131503Sbmsvr_miibus_statchg(device_t dev) 50251432Swpaul{ 50351432Swpaul struct mii_data *mii; 504131503Sbms struct vr_softc *sc = device_get_softc(dev); 50551432Swpaul 50651432Swpaul mii = device_get_softc(sc->vr_miibus); 50751432Swpaul vr_setcfg(sc, mii->mii_media_active); 50841502Swpaul} 50941502Swpaul 51041502Swpaul/* 51141502Swpaul * Program the 64-bit multicast hash filter. 51241502Swpaul */ 513102336Salfredstatic void 514131503Sbmsvr_setmulti(struct vr_softc *sc) 51541502Swpaul{ 516147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 51741502Swpaul int h = 0; 518131503Sbms uint32_t hashes[2] = { 0, 0 }; 51941502Swpaul struct ifmultiaddr *ifma; 520131503Sbms uint8_t rxfilt; 52141502Swpaul int mcnt = 0; 52241502Swpaul 523131518Sbms VR_LOCK_ASSERT(sc); 52441502Swpaul 52541502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 52641502Swpaul 52741502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 52841502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 52941502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 53041502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 53141502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 53241502Swpaul return; 53341502Swpaul } 53441502Swpaul 535131503Sbms /* First, zero out all the existing hash bits. */ 53641502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 53741502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 53841502Swpaul 539131503Sbms /* Now program new ones. */ 540148654Srwatson IF_ADDR_LOCK(ifp); 54172084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 54241502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 54341502Swpaul continue; 544130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 545130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 54641502Swpaul if (h < 32) 54741502Swpaul hashes[0] |= (1 << h); 54841502Swpaul else 54941502Swpaul hashes[1] |= (1 << (h - 32)); 55041502Swpaul mcnt++; 55141502Swpaul } 552148654Srwatson IF_ADDR_UNLOCK(ifp); 55341502Swpaul 55441502Swpaul if (mcnt) 55541502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 55641502Swpaul else 55741502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 55841502Swpaul 55941502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 56041502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 56141502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 56241502Swpaul} 56341502Swpaul 56441502Swpaul/* 56541502Swpaul * In order to fiddle with the 56641502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 56741502Swpaul * first have to put the transmit and/or receive logic in the idle state. 56841502Swpaul */ 569102336Salfredstatic void 570131503Sbmsvr_setcfg(struct vr_softc *sc, int media) 57141502Swpaul{ 572131517Sbms int restart = 0; 57341502Swpaul 574131518Sbms VR_LOCK_ASSERT(sc); 575131518Sbms 57641502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 57741502Swpaul restart = 1; 57841502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 57941502Swpaul } 58041502Swpaul 58151432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 58241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 58341502Swpaul else 58441502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 58541502Swpaul 58641502Swpaul if (restart) 58741502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 58841502Swpaul} 58941502Swpaul 590102336Salfredstatic void 591131503Sbmsvr_reset(struct vr_softc *sc) 59241502Swpaul{ 593131517Sbms register int i; 59441502Swpaul 595151773Sjhb /*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */ 596131518Sbms 59741502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 59841502Swpaul 59941502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 60041502Swpaul DELAY(10); 60141502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 60241502Swpaul break; 60341502Swpaul } 604107220Ssilby if (i == VR_TIMEOUT) { 605107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 606151773Sjhb if_printf(sc->vr_ifp, "reset never completed!\n"); 607107220Ssilby else { 608107220Ssilby /* Use newer force reset command */ 609151773Sjhb if_printf(sc->vr_ifp, "Using force reset command.\n"); 610107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 611107220Ssilby } 612107220Ssilby } 61341502Swpaul 61441502Swpaul /* Wait a little while for the chip to get its brains in order. */ 61541502Swpaul DELAY(1000); 61641502Swpaul} 61741502Swpaul 61841502Swpaul/* 61941502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 62041502Swpaul * IDs against our list and return a device name if we find a match. 62141502Swpaul */ 622102336Salfredstatic int 623131503Sbmsvr_probe(device_t dev) 62441502Swpaul{ 625131503Sbms struct vr_type *t = vr_devs; 62641502Swpaul 627131503Sbms while (t->vr_name != NULL) { 62849610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 62949610Swpaul (pci_get_device(dev) == t->vr_did)) { 63049610Swpaul device_set_desc(dev, t->vr_name); 631142398Simp return (BUS_PROBE_DEFAULT); 63241502Swpaul } 63341502Swpaul t++; 63441502Swpaul } 63541502Swpaul 636131503Sbms return (ENXIO); 63741502Swpaul} 63841502Swpaul 63941502Swpaul/* 64041502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 64141502Swpaul * setup and ethernet/BPF attach. 64241502Swpaul */ 643102336Salfredstatic int 644102336Salfredvr_attach(dev) 64549610Swpaul device_t dev; 64641502Swpaul{ 64767087Swpaul int i; 64841502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 64941502Swpaul struct vr_softc *sc; 65041502Swpaul struct ifnet *ifp; 65149610Swpaul int unit, error = 0, rid; 65241502Swpaul 65349610Swpaul sc = device_get_softc(dev); 65449610Swpaul unit = device_get_unit(dev); 65541502Swpaul 65693818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 657131518Sbms MTX_DEF); 658151911Sjhb callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0); 659151911Sjhb 66041502Swpaul /* 66141502Swpaul * Map control/status registers. 66241502Swpaul */ 66372813Swpaul pci_enable_busmaster(dev); 664107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 66541502Swpaul 66649610Swpaul rid = VR_RID; 667127135Snjl sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE); 66849610Swpaul 66949610Swpaul if (sc->vr_res == NULL) { 670151773Sjhb device_printf(dev, "couldn't map ports/memory\n"); 67149610Swpaul error = ENXIO; 67241502Swpaul goto fail; 67341502Swpaul } 67441502Swpaul 67549610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 67649610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 67741502Swpaul 67841502Swpaul /* Allocate interrupt */ 67949610Swpaul rid = 0; 680127135Snjl sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 68149610Swpaul RF_SHAREABLE | RF_ACTIVE); 68249610Swpaul 68349610Swpaul if (sc->vr_irq == NULL) { 684151773Sjhb device_printf(dev, "couldn't map interrupt\n"); 68549610Swpaul error = ENXIO; 68641502Swpaul goto fail; 68741502Swpaul } 68841502Swpaul 689151773Sjhb /* Allocate ifnet structure. */ 690151773Sjhb ifp = sc->vr_ifp = if_alloc(IFT_ETHER); 691151773Sjhb if (ifp == NULL) { 692151773Sjhb device_printf(dev, "can not if_alloc()\n"); 693151773Sjhb error = ENOSPC; 694151773Sjhb goto fail; 695151773Sjhb } 696151773Sjhb ifp->if_softc = sc; 697151773Sjhb if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 698151773Sjhb ifp->if_mtu = ETHERMTU; 699151773Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 700151773Sjhb ifp->if_ioctl = vr_ioctl; 701151773Sjhb ifp->if_start = vr_start; 702151773Sjhb ifp->if_watchdog = vr_watchdog; 703151773Sjhb ifp->if_init = vr_init; 704151773Sjhb ifp->if_baudrate = 10000000; 705151773Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1); 706151773Sjhb ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 707151773Sjhb IFQ_SET_READY(&ifp->if_snd); 708151773Sjhb ifp->if_capenable = ifp->if_capabilities; 709151773Sjhb#ifdef DEVICE_POLLING 710151773Sjhb ifp->if_capabilities |= IFCAP_POLLING; 711151773Sjhb#endif 712151773Sjhb 71376586Swpaul /* 71476586Swpaul * Windows may put the chip in suspend mode when it 71576586Swpaul * shuts down. Be sure to kick it in the head to wake it 71676586Swpaul * up again. 71776586Swpaul */ 71876586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 71976586Swpaul 72041502Swpaul /* Reset the adapter. */ 72141502Swpaul vr_reset(sc); 72241502Swpaul 723131503Sbms /* 724110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 725110168Ssilby * initialization and disable AUTOPOLL. 726110168Ssilby */ 727131503Sbms pci_write_config(dev, VR_PCI_MODE, 728110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 729110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 730110168Ssilby 73141502Swpaul /* 73241502Swpaul * Get station address. The way the Rhine chips work, 73341502Swpaul * you're not allowed to directly access the EEPROM once 73441502Swpaul * they've been programmed a special way. Consequently, 73541502Swpaul * we need to read the node address from the PAR0 and PAR1 73641502Swpaul * registers. 73741502Swpaul */ 73841502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 73941502Swpaul DELAY(200); 74041502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 74141502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 74241502Swpaul 74351432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 744151773Sjhb M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0); 74551432Swpaul 74651432Swpaul if (sc->vr_ldata == NULL) { 747151773Sjhb device_printf(dev, "no memory for list buffers!\n"); 74849610Swpaul error = ENXIO; 74949610Swpaul goto fail; 75041502Swpaul } 75141502Swpaul 752131503Sbms /* Do MII setup. */ 75351432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 75451432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 755151773Sjhb device_printf(dev, "MII without any phy!\n"); 75649610Swpaul error = ENXIO; 75741502Swpaul goto fail; 75841502Swpaul } 75941502Swpaul 760131503Sbms /* Call MI attach routine. */ 761106936Ssam ether_ifattach(ifp, eaddr); 76241502Swpaul 763131844Sbms sc->suspended = 0; 764131844Sbms 765113609Snjl /* Hook interrupt last to avoid having to lock softc */ 766131518Sbms error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, 767112872Snjl vr_intr, sc, &sc->vr_intrhand); 768112872Snjl 769112872Snjl if (error) { 770151773Sjhb device_printf(dev, "couldn't set up irq\n"); 771113609Snjl ether_ifdetach(ifp); 772112872Snjl goto fail; 773112872Snjl } 774112872Snjl 77541502Swpaulfail: 776112872Snjl if (error) 777112872Snjl vr_detach(dev); 77867087Swpaul 779131503Sbms return (error); 78041502Swpaul} 78141502Swpaul 782113609Snjl/* 783113609Snjl * Shutdown hardware and free up resources. This can be called any 784113609Snjl * time after the mutex has been initialized. It is called in both 785113609Snjl * the error case in attach and the normal detach case so it needs 786113609Snjl * to be careful about only freeing resources that have actually been 787113609Snjl * allocated. 788113609Snjl */ 789102336Salfredstatic int 790131503Sbmsvr_detach(device_t dev) 79149610Swpaul{ 792131503Sbms struct vr_softc *sc = device_get_softc(dev); 793147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 79449610Swpaul 795112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 796131518Sbms 797150789Sglebius#ifdef DEVICE_POLLING 798150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 799150789Sglebius ether_poll_deregister(ifp); 800150789Sglebius#endif 801150789Sglebius 802113609Snjl /* These should only be active if attach succeeded */ 803113812Simp if (device_is_attached(dev)) { 804151911Sjhb VR_LOCK(sc); 805151911Sjhb sc->suspended = 1; 806113609Snjl vr_stop(sc); 807151911Sjhb VR_UNLOCK(sc); 808151911Sjhb callout_drain(&sc->vr_stat_callout); 809112872Snjl ether_ifdetach(ifp); 810113609Snjl } 811113609Snjl if (sc->vr_miibus) 812112872Snjl device_delete_child(dev, sc->vr_miibus); 813113609Snjl bus_generic_detach(dev); 81449610Swpaul 815112872Snjl if (sc->vr_intrhand) 816112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 817112872Snjl if (sc->vr_irq) 818112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 819112872Snjl if (sc->vr_res) 820112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 82151432Swpaul 822151297Sru if (ifp) 823151297Sru if_free(ifp); 824151297Sru 825112872Snjl if (sc->vr_ldata) 826112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 82749610Swpaul 82867087Swpaul mtx_destroy(&sc->vr_mtx); 82949610Swpaul 830131503Sbms return (0); 83149610Swpaul} 83249610Swpaul 83341502Swpaul/* 83441502Swpaul * Initialize the transmit descriptors. 83541502Swpaul */ 836102336Salfredstatic int 837131503Sbmsvr_list_tx_init(struct vr_softc *sc) 83841502Swpaul{ 83941502Swpaul struct vr_chain_data *cd; 84041502Swpaul struct vr_list_data *ld; 84141502Swpaul int i; 84241502Swpaul 84341502Swpaul cd = &sc->vr_cdata; 84441502Swpaul ld = sc->vr_ldata; 84541502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 84641502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 84741502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 848131503Sbms cd->vr_tx_chain[i].vr_nextdesc = 84941502Swpaul &cd->vr_tx_chain[0]; 85041502Swpaul else 85141502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 85241502Swpaul &cd->vr_tx_chain[i + 1]; 85341502Swpaul } 854127901Sru cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0]; 85541502Swpaul 856131503Sbms return (0); 85741502Swpaul} 85841502Swpaul 85941502Swpaul 86041502Swpaul/* 86141502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 86241502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 86341502Swpaul * points back to the first. 86441502Swpaul */ 865102336Salfredstatic int 866131503Sbmsvr_list_rx_init(struct vr_softc *sc) 86741502Swpaul{ 86841502Swpaul struct vr_chain_data *cd; 86941502Swpaul struct vr_list_data *ld; 87041502Swpaul int i; 87141502Swpaul 872131518Sbms VR_LOCK_ASSERT(sc); 873131518Sbms 87441502Swpaul cd = &sc->vr_cdata; 87541502Swpaul ld = sc->vr_ldata; 87641502Swpaul 87741502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 87841502Swpaul cd->vr_rx_chain[i].vr_ptr = 87941502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 88049610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 881131503Sbms return (ENOBUFS); 88241502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 88341502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 88441502Swpaul &cd->vr_rx_chain[0]; 88541502Swpaul ld->vr_rx_list[i].vr_next = 88641502Swpaul vtophys(&ld->vr_rx_list[0]); 88741502Swpaul } else { 88841502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 88941502Swpaul &cd->vr_rx_chain[i + 1]; 89041502Swpaul ld->vr_rx_list[i].vr_next = 89141502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 89241502Swpaul } 89341502Swpaul } 89441502Swpaul 89541502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 89641502Swpaul 897131503Sbms return (0); 89841502Swpaul} 89941502Swpaul 90041502Swpaul/* 90141502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 90241502Swpaul * Note: the length fields are only 11 bits wide, which means the 90341502Swpaul * largest size we can specify is 2047. This is important because 90441502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 90541502Swpaul * overflow the field and make a mess. 90641502Swpaul */ 907102336Salfredstatic int 908131503Sbmsvr_newbuf(struct vr_softc *sc, struct vr_chain_onefrag *c, struct mbuf *m) 90941502Swpaul{ 91041502Swpaul struct mbuf *m_new = NULL; 91141502Swpaul 91249610Swpaul if (m == NULL) { 913111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 91487846Sluigi if (m_new == NULL) 915131503Sbms return (ENOBUFS); 91641502Swpaul 917111119Simp MCLGET(m_new, M_DONTWAIT); 91849610Swpaul if (!(m_new->m_flags & M_EXT)) { 91949610Swpaul m_freem(m_new); 920131503Sbms return (ENOBUFS); 92149610Swpaul } 92249610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 92349610Swpaul } else { 92449610Swpaul m_new = m; 92549610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 92649610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 92741502Swpaul } 92841502Swpaul 929131503Sbms m_adj(m_new, sizeof(uint64_t)); 93049610Swpaul 93141502Swpaul c->vr_mbuf = m_new; 93241502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 93341502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 93442491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 93541502Swpaul 936131503Sbms return (0); 93741502Swpaul} 93841502Swpaul 93941502Swpaul/* 94041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 94141502Swpaul * the higher level protocols. 94241502Swpaul */ 943102336Salfredstatic void 944131503Sbmsvr_rxeof(struct vr_softc *sc) 94541502Swpaul{ 946131503Sbms struct mbuf *m, *m0; 947131503Sbms struct ifnet *ifp; 94841502Swpaul struct vr_chain_onefrag *cur_rx; 94941502Swpaul int total_len = 0; 950131503Sbms uint32_t rxstat; 95141502Swpaul 952122689Ssam VR_LOCK_ASSERT(sc); 953147256Sbrooks ifp = sc->vr_ifp; 95441502Swpaul 955131503Sbms while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 956131503Sbms VR_RXSTAT_OWN)) { 957127901Sru#ifdef DEVICE_POLLING 958150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 959127901Sru if (sc->rxcycles <= 0) 960127901Sru break; 961127901Sru sc->rxcycles--; 962127901Sru } 963150789Sglebius#endif 964127901Sru m0 = NULL; 96541502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 96641502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 96749610Swpaul m = cur_rx->vr_mbuf; 96841502Swpaul 96941502Swpaul /* 97041502Swpaul * If an error occurs, update stats, clear the 97141502Swpaul * status word and leave the mbuf cluster in place: 97241502Swpaul * it should simply get re-used next time this descriptor 973131503Sbms * comes up in the ring. 97441502Swpaul */ 97541502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 97641502Swpaul ifp->if_ierrors++; 977151773Sjhb if_printf(ifp, "rx error (%02x):", rxstat & 0x000000ff); 978110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 979110131Ssilby printf(" crc error"); 980110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 981110131Ssilby printf(" frame alignment error\n"); 982110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 983110131Ssilby printf(" FIFO overflow"); 984110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 985110131Ssilby printf(" received giant packet"); 986110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 987110131Ssilby printf(" received runt packet"); 988110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 989110131Ssilby printf(" system bus error"); 990110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 991110131Ssilby printf("rx buffer error"); 992110131Ssilby printf("\n"); 99349610Swpaul vr_newbuf(sc, cur_rx, m); 99441502Swpaul continue; 99541502Swpaul } 99641502Swpaul 997131503Sbms /* No errors; receive the packet. */ 99841502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 99941502Swpaul 100041502Swpaul /* 100142048Swpaul * XXX The VIA Rhine chip includes the CRC with every 100242048Swpaul * received frame, and there's no way to turn this 100342048Swpaul * behavior off (at least, I can't find anything in 1004131503Sbms * the manual that explains how to do it) so we have 100542048Swpaul * to trim off the CRC manually. 100642048Swpaul */ 100742048Swpaul total_len -= ETHER_CRC_LEN; 100842048Swpaul 100978508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 101078508Sbmilekic NULL); 101149610Swpaul vr_newbuf(sc, cur_rx, m); 101249610Swpaul if (m0 == NULL) { 101341502Swpaul ifp->if_ierrors++; 101441502Swpaul continue; 101541502Swpaul } 101649610Swpaul m = m0; 101741502Swpaul 101841502Swpaul ifp->if_ipackets++; 1019122689Ssam VR_UNLOCK(sc); 1020106936Ssam (*ifp->if_input)(ifp, m); 1021122689Ssam VR_LOCK(sc); 102241502Swpaul } 102341502Swpaul} 102441502Swpaul 1025105221Sphkstatic void 1026131503Sbmsvr_rxeoc(struct vr_softc *sc) 102741502Swpaul{ 1028147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1029110131Ssilby int i; 103041502Swpaul 1031131518Sbms VR_LOCK_ASSERT(sc); 1032131518Sbms 1033110131Ssilby ifp->if_ierrors++; 1034110131Ssilby 1035131503Sbms VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1036131503Sbms DELAY(10000); 1037110131Ssilby 1038131503Sbms /* Wait for receiver to stop */ 1039110131Ssilby for (i = 0x400; 1040110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1041131503Sbms i--) { 1042131503Sbms ; 1043131503Sbms } 1044110131Ssilby 1045110131Ssilby if (!i) { 1046151773Sjhb if_printf(ifp, "rx shutdown error!\n"); 1047110131Ssilby sc->vr_flags |= VR_F_RESTART; 1048110131Ssilby return; 1049131503Sbms } 1050110131Ssilby 105141502Swpaul vr_rxeof(sc); 1052110131Ssilby 105341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 105441502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 105541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 105641502Swpaul} 105741502Swpaul 105841502Swpaul/* 105941502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 106041502Swpaul * the list buffers. 106141502Swpaul */ 1062102336Salfredstatic void 1063131503Sbmsvr_txeof(struct vr_softc *sc) 106441502Swpaul{ 106541502Swpaul struct vr_chain *cur_tx; 1066147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 106741502Swpaul 1068131518Sbms VR_LOCK_ASSERT(sc); 106941502Swpaul 107041502Swpaul /* 107141502Swpaul * Go through our tx list and free mbufs for those 107241502Swpaul * frames that have been transmitted. 107341502Swpaul */ 1074127901Sru cur_tx = sc->vr_cdata.vr_tx_cons; 1075127901Sru while (cur_tx->vr_mbuf != NULL) { 1076131503Sbms uint32_t txstat; 1077110131Ssilby int i; 107841502Swpaul 107941502Swpaul txstat = cur_tx->vr_ptr->vr_status; 108041502Swpaul 1081101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1082101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1083110131Ssilby for (i = 0x400; 1084110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1085110131Ssilby i--) 1086101896Ssilby ; /* Wait for chip to shutdown */ 1087110131Ssilby if (!i) { 1088151773Sjhb if_printf(ifp, "tx shutdown timeout\n"); 1089110131Ssilby sc->vr_flags |= VR_F_RESTART; 1090110131Ssilby break; 1091110131Ssilby } 1092101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1093101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1094101896Ssilby break; 1095101896Ssilby } 1096101896Ssilby 109742491Swpaul if (txstat & VR_TXSTAT_OWN) 109841502Swpaul break; 109941502Swpaul 110041502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 110141502Swpaul ifp->if_oerrors++; 110241502Swpaul if (txstat & VR_TXSTAT_DEFER) 110341502Swpaul ifp->if_collisions++; 110441502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 110541502Swpaul ifp->if_collisions++; 110641502Swpaul } 110741502Swpaul 110841502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 110941502Swpaul 111041502Swpaul ifp->if_opackets++; 1111127901Sru m_freem(cur_tx->vr_mbuf); 1112127901Sru cur_tx->vr_mbuf = NULL; 1113148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 111441502Swpaul 1115127901Sru cur_tx = cur_tx->vr_nextdesc; 111641502Swpaul } 1117127901Sru sc->vr_cdata.vr_tx_cons = cur_tx; 1118127901Sru if (cur_tx->vr_mbuf == NULL) 111996677Ssilby ifp->if_timer = 0; 112041502Swpaul} 112141502Swpaul 1122102336Salfredstatic void 1123131503Sbmsvr_tick(void *xsc) 112451432Swpaul{ 1125131503Sbms struct vr_softc *sc = xsc; 112651432Swpaul struct mii_data *mii; 112751432Swpaul 1128151911Sjhb VR_LOCK_ASSERT(sc); 1129131517Sbms 1130110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1131151773Sjhb if_printf(sc->vr_ifp, "restarting\n"); 1132110131Ssilby vr_stop(sc); 1133110131Ssilby vr_reset(sc); 1134131844Sbms vr_init_locked(sc); 1135110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1136110131Ssilby } 1137110131Ssilby 113851432Swpaul mii = device_get_softc(sc->vr_miibus); 113951432Swpaul mii_tick(mii); 1140151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 114151432Swpaul} 114251432Swpaul 1143127901Sru#ifdef DEVICE_POLLING 1144127901Srustatic poll_handler_t vr_poll; 1145131844Sbmsstatic poll_handler_t vr_poll_locked; 1146127901Sru 1147102336Salfredstatic void 1148127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1149127901Sru{ 1150127901Sru struct vr_softc *sc = ifp->if_softc; 1151127901Sru 1152127901Sru VR_LOCK(sc); 1153150789Sglebius if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1154150789Sglebius vr_poll_locked(ifp, cmd, count); 1155131844Sbms VR_UNLOCK(sc); 1156131844Sbms} 1157131517Sbms 1158131844Sbmsstatic void 1159131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1160131844Sbms{ 1161131844Sbms struct vr_softc *sc = ifp->if_softc; 1162131844Sbms 1163131844Sbms VR_LOCK_ASSERT(sc); 1164131844Sbms 1165127901Sru sc->rxcycles = count; 1166127901Sru vr_rxeof(sc); 1167127901Sru vr_txeof(sc); 1168133006Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1169131844Sbms vr_start_locked(ifp); 1170127901Sru 1171131503Sbms if (cmd == POLL_AND_CHECK_STATUS) { 1172131503Sbms uint16_t status; 1173127901Sru 1174131503Sbms /* Also check status register. */ 1175127901Sru status = CSR_READ_2(sc, VR_ISR); 1176127901Sru if (status) 1177127901Sru CSR_WRITE_2(sc, VR_ISR, status); 1178127901Sru 1179127901Sru if ((status & VR_INTRS) == 0) 1180131844Sbms return; 1181127901Sru 1182127901Sru if (status & VR_ISR_RX_DROPPED) { 1183151773Sjhb if_printf(ifp, "rx packet lost\n"); 1184127901Sru ifp->if_ierrors++; 1185127901Sru } 1186127901Sru 1187127901Sru if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1188127901Sru (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1189151773Sjhb if_printf(ifp, "receive error (%04x)", status); 1190127901Sru if (status & VR_ISR_RX_NOBUF) 1191127901Sru printf(" no buffers"); 1192127901Sru if (status & VR_ISR_RX_OFLOW) 1193127901Sru printf(" overflow"); 1194127901Sru if (status & VR_ISR_RX_DROPPED) 1195127901Sru printf(" packet lost"); 1196127901Sru printf("\n"); 1197127901Sru vr_rxeoc(sc); 1198127901Sru } 1199127901Sru 1200131503Sbms if ((status & VR_ISR_BUSERR) || 1201131503Sbms (status & VR_ISR_TX_UNDERRUN)) { 1202127901Sru vr_reset(sc); 1203131844Sbms vr_init_locked(sc); 1204131518Sbms return; 1205127901Sru } 1206127901Sru 1207127901Sru if ((status & VR_ISR_UDFI) || 1208127901Sru (status & VR_ISR_TX_ABRT2) || 1209127901Sru (status & VR_ISR_TX_ABRT)) { 1210127901Sru ifp->if_oerrors++; 1211127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1212127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1213127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1214127901Sru } 1215127901Sru } 1216127901Sru } 1217127901Sru} 1218127901Sru#endif /* DEVICE_POLLING */ 1219127901Sru 1220127901Srustatic void 1221131503Sbmsvr_intr(void *arg) 122241502Swpaul{ 1223131503Sbms struct vr_softc *sc = arg; 1224147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1225131503Sbms uint16_t status; 122641502Swpaul 122767087Swpaul VR_LOCK(sc); 1228131844Sbms 1229136997Sbms if (sc->suspended) { 1230136997Sbms /* 1231136997Sbms * Forcibly disable interrupts. 1232136997Sbms * XXX: Mobile VIA based platforms may need 1233136997Sbms * interrupt re-enable on resume. 1234136997Sbms */ 1235136997Sbms CSR_WRITE_2(sc, VR_IMR, 0x0000); 1236131844Sbms goto done_locked; 1237136997Sbms } 1238131844Sbms 1239127901Sru#ifdef DEVICE_POLLING 1240150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1241131844Sbms goto done_locked; 1242150789Sglebius#endif 1243131844Sbms 1244131844Sbms /* Suppress unwanted interrupts. */ 124541502Swpaul if (!(ifp->if_flags & IFF_UP)) { 124641502Swpaul vr_stop(sc); 1247131844Sbms goto done_locked; 124841502Swpaul } 124941502Swpaul 125041502Swpaul /* Disable interrupts. */ 125141502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 125241502Swpaul 125341502Swpaul for (;;) { 125441502Swpaul status = CSR_READ_2(sc, VR_ISR); 125541502Swpaul if (status) 125641502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 125741502Swpaul 125841502Swpaul if ((status & VR_INTRS) == 0) 125941502Swpaul break; 126041502Swpaul 126141502Swpaul if (status & VR_ISR_RX_OK) 126241502Swpaul vr_rxeof(sc); 126341502Swpaul 1264110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1265151773Sjhb if_printf(ifp, "rx packet lost\n"); 1266110131Ssilby ifp->if_ierrors++; 1267131503Sbms } 1268110131Ssilby 126941502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1270110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1271151773Sjhb if_printf(ifp, "receive error (%04x)", status); 1272110131Ssilby if (status & VR_ISR_RX_NOBUF) 1273110131Ssilby printf(" no buffers"); 1274110131Ssilby if (status & VR_ISR_RX_OFLOW) 1275110131Ssilby printf(" overflow"); 1276110131Ssilby if (status & VR_ISR_RX_DROPPED) 1277110131Ssilby printf(" packet lost"); 1278110131Ssilby printf("\n"); 127941502Swpaul vr_rxeoc(sc); 128041502Swpaul } 128141502Swpaul 1282101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1283101896Ssilby vr_reset(sc); 1284131844Sbms vr_init_locked(sc); 1285101896Ssilby break; 128641502Swpaul } 128741502Swpaul 1288101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1289101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 129041502Swpaul vr_txeof(sc); 1291101896Ssilby if ((status & VR_ISR_UDFI) || 1292101896Ssilby (status & VR_ISR_TX_ABRT2) || 1293101896Ssilby (status & VR_ISR_TX_ABRT)) { 1294101896Ssilby ifp->if_oerrors++; 1295127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1296131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1297131503Sbms VR_CMD_TX_ON); 1298131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1299131503Sbms VR_CMD_TX_GO); 1300101896Ssilby } 1301127901Sru } 130241502Swpaul } 130341502Swpaul } 130441502Swpaul 130541502Swpaul /* Re-enable interrupts. */ 130641502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 130741502Swpaul 1308132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1309131844Sbms vr_start_locked(ifp); 1310131844Sbms 1311131844Sbmsdone_locked: 1312131844Sbms VR_UNLOCK(sc); 131341502Swpaul} 131441502Swpaul 131541502Swpaul/* 131641502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 131741502Swpaul * pointers to the fragment pointers. 131841502Swpaul */ 1319102336Salfredstatic int 1320131503Sbmsvr_encap(struct vr_softc *sc, struct vr_chain *c, struct mbuf *m_head) 132141502Swpaul{ 132241502Swpaul struct vr_desc *f = NULL; 132341502Swpaul struct mbuf *m; 132441502Swpaul 1325131518Sbms VR_LOCK_ASSERT(sc); 132641502Swpaul /* 132741502Swpaul * The VIA Rhine wants packet buffers to be longword 132841502Swpaul * aligned, but very often our mbufs aren't. Rather than 132941502Swpaul * waste time trying to decide when to copy and when not 133041502Swpaul * to copy, just do it all the time. 133141502Swpaul */ 1332127901Sru m = m_defrag(m_head, M_DONTWAIT); 1333131503Sbms if (m == NULL) 1334131503Sbms return (1); 133541502Swpaul 1336127901Sru /* 1337127901Sru * The Rhine chip doesn't auto-pad, so we have to make 1338127901Sru * sure to pad short frames out to the minimum frame length 1339127901Sru * ourselves. 1340127901Sru */ 1341127901Sru if (m->m_len < VR_MIN_FRAMELEN) { 1342127901Sru m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len; 1343127901Sru m->m_len = m->m_pkthdr.len; 134441502Swpaul } 134541502Swpaul 1346127901Sru c->vr_mbuf = m; 1347127901Sru f = c->vr_ptr; 1348127901Sru f->vr_data = vtophys(mtod(m, caddr_t)); 1349127901Sru f->vr_ctl = m->m_len; 1350127901Sru f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 1351127901Sru f->vr_status = 0; 1352127901Sru f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 1353127901Sru f->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 135441502Swpaul 1355131503Sbms return (0); 135641502Swpaul} 135741502Swpaul 135841502Swpaul/* 135941502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 136041502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 136141502Swpaul * copy of the pointers since the transmit list fragment pointers are 136241502Swpaul * physical addresses. 136341502Swpaul */ 136441502Swpaul 1365102336Salfredstatic void 1366131503Sbmsvr_start(struct ifnet *ifp) 136741502Swpaul{ 1368131518Sbms struct vr_softc *sc = ifp->if_softc; 1369131844Sbms 1370131844Sbms VR_LOCK(sc); 1371131844Sbms vr_start_locked(ifp); 1372131844Sbms VR_UNLOCK(sc); 1373131844Sbms} 1374131844Sbms 1375131844Sbmsstatic void 1376131844Sbmsvr_start_locked(struct ifnet *ifp) 1377131844Sbms{ 1378131844Sbms struct vr_softc *sc = ifp->if_softc; 1379127901Sru struct mbuf *m_head; 1380127901Sru struct vr_chain *cur_tx; 138141502Swpaul 1382148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 1383127901Sru return; 1384127901Sru 1385127901Sru cur_tx = sc->vr_cdata.vr_tx_prod; 1386127901Sru while (cur_tx->vr_mbuf == NULL) { 1387132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 138841502Swpaul if (m_head == NULL) 138941502Swpaul break; 139041502Swpaul 139141502Swpaul /* Pack the data into the descriptor. */ 139271271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 1393113274Ssilby /* Rollback, send what we were able to encap. */ 1394132986Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 139571271Swpaul break; 139671271Swpaul } 139741502Swpaul 1398127901Sru VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 139941502Swpaul 140041502Swpaul /* 140141502Swpaul * If there's a BPF listener, bounce a copy of this frame 140241502Swpaul * to him. 140341502Swpaul */ 1404106936Ssam BPF_MTAP(ifp, cur_tx->vr_mbuf); 140551583Swpaul 1406127901Sru cur_tx = cur_tx->vr_nextdesc; 140741502Swpaul } 1408127901Sru if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) { 1409127901Sru sc->vr_cdata.vr_tx_prod = cur_tx; 141041502Swpaul 1411127901Sru /* Tell the chip to start transmitting. */ 1412131517Sbms VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO); 141341526Swpaul 1414127901Sru /* Set a timeout in case the chip goes out to lunch. */ 1415127901Sru ifp->if_timer = 5; 141641502Swpaul 1417127901Sru if (cur_tx->vr_mbuf != NULL) 1418148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1419127901Sru } 1420131844Sbms} 142141502Swpaul 1422131844Sbmsstatic void 1423131844Sbmsvr_init(void *xsc) 1424131844Sbms{ 1425131844Sbms struct vr_softc *sc = xsc; 1426131844Sbms 1427131844Sbms VR_LOCK(sc); 1428131844Sbms vr_init_locked(sc); 142967087Swpaul VR_UNLOCK(sc); 143041502Swpaul} 143141502Swpaul 1432102336Salfredstatic void 1433131844Sbmsvr_init_locked(struct vr_softc *sc) 143441502Swpaul{ 1435147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 143651432Swpaul struct mii_data *mii; 143773963Swpaul int i; 143841502Swpaul 1439131844Sbms VR_LOCK_ASSERT(sc); 144041502Swpaul 144151432Swpaul mii = device_get_softc(sc->vr_miibus); 144241502Swpaul 1443131503Sbms /* Cancel pending I/O and free all RX/TX buffers. */ 144441502Swpaul vr_stop(sc); 144541502Swpaul vr_reset(sc); 144641502Swpaul 1447131503Sbms /* Set our station address. */ 144873963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 1449147256Sbrooks CSR_WRITE_1(sc, VR_PAR0 + i, IFP2ENADDR(sc->vr_ifp)[i]); 1450131503Sbms 1451131503Sbms /* Set DMA size. */ 1452101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1453101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 145473963Swpaul 1455131503Sbms /* 1456101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1457101108Ssilby * so we must set both. 1458101108Ssilby */ 1459101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1460110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1461101108Ssilby 1462101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1463101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1464101108Ssilby 146541502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1466110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 146741502Swpaul 146841502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 146941502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 147041502Swpaul 147141502Swpaul /* Init circular RX list. */ 147241502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 1473151773Sjhb if_printf(ifp, 1474151773Sjhb "initialization failed: no memory for rx buffers\n"); 147541502Swpaul vr_stop(sc); 147641502Swpaul return; 147741502Swpaul } 147841502Swpaul 1479131503Sbms /* Init tx descriptors. */ 148041502Swpaul vr_list_tx_init(sc); 148141502Swpaul 148241502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 148341502Swpaul if (ifp->if_flags & IFF_PROMISC) 148441502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 148541502Swpaul else 148641502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 148741502Swpaul 148841502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 148941502Swpaul if (ifp->if_flags & IFF_BROADCAST) 149041502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 149141502Swpaul else 149241502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 149341502Swpaul 149441502Swpaul /* 149541502Swpaul * Program the multicast filter, if necessary. 149641502Swpaul */ 149741502Swpaul vr_setmulti(sc); 149841502Swpaul 149941502Swpaul /* 150041502Swpaul * Load the address of the RX list. 150141502Swpaul */ 150241502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 150341502Swpaul 150441502Swpaul /* Enable receiver and transmitter. */ 150541502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 150641502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 150741502Swpaul VR_CMD_RX_GO); 150841502Swpaul 150941502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 151041502Swpaul 1511127901Sru CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 1512127901Sru#ifdef DEVICE_POLLING 151341502Swpaul /* 1514127901Sru * Disable interrupts if we are polling. 1515127901Sru */ 1516150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1517127901Sru CSR_WRITE_2(sc, VR_IMR, 0); 1518131503Sbms else 1519150789Sglebius#endif 1520127901Sru /* 152141502Swpaul * Enable interrupts. 152241502Swpaul */ 152341502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 152441502Swpaul 152551432Swpaul mii_mediachg(mii); 152641502Swpaul 1527148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1528148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 152941502Swpaul 1530151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 153141502Swpaul} 153241502Swpaul 153341502Swpaul/* 153441502Swpaul * Set media options. 153541502Swpaul */ 1536102336Salfredstatic int 1537131503Sbmsvr_ifmedia_upd(struct ifnet *ifp) 153841502Swpaul{ 1539131503Sbms struct vr_softc *sc = ifp->if_softc; 154041502Swpaul 154151432Swpaul if (ifp->if_flags & IFF_UP) 154251432Swpaul vr_init(sc); 154341502Swpaul 1544131503Sbms return (0); 154541502Swpaul} 154641502Swpaul 154741502Swpaul/* 154841502Swpaul * Report current media status. 154941502Swpaul */ 1550102336Salfredstatic void 1551131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 155241502Swpaul{ 1553131518Sbms struct vr_softc *sc = ifp->if_softc; 155451432Swpaul struct mii_data *mii; 155541502Swpaul 155651432Swpaul mii = device_get_softc(sc->vr_miibus); 1557133468Sscottl VR_LOCK(sc); 155851432Swpaul mii_pollstat(mii); 1559133468Sscottl VR_UNLOCK(sc); 156051432Swpaul ifmr->ifm_active = mii->mii_media_active; 156151432Swpaul ifmr->ifm_status = mii->mii_media_status; 156241502Swpaul} 156341502Swpaul 1564102336Salfredstatic int 1565131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 156641502Swpaul{ 156741502Swpaul struct vr_softc *sc = ifp->if_softc; 156841502Swpaul struct ifreq *ifr = (struct ifreq *) data; 156951432Swpaul struct mii_data *mii; 157067087Swpaul int error = 0; 157141502Swpaul 1572131503Sbms switch (command) { 157341502Swpaul case SIOCSIFFLAGS: 1574131844Sbms VR_LOCK(sc); 157541502Swpaul if (ifp->if_flags & IFF_UP) { 1576131844Sbms vr_init_locked(sc); 157741502Swpaul } else { 1578148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 157941502Swpaul vr_stop(sc); 158041502Swpaul } 1581131844Sbms VR_UNLOCK(sc); 158241502Swpaul error = 0; 158341502Swpaul break; 158441502Swpaul case SIOCADDMULTI: 158541502Swpaul case SIOCDELMULTI: 1586131518Sbms VR_LOCK(sc); 158741502Swpaul vr_setmulti(sc); 1588131518Sbms VR_UNLOCK(sc); 158941502Swpaul error = 0; 159041502Swpaul break; 159141502Swpaul case SIOCGIFMEDIA: 159241502Swpaul case SIOCSIFMEDIA: 159351432Swpaul mii = device_get_softc(sc->vr_miibus); 159451432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 159541502Swpaul break; 1596128118Sru case SIOCSIFCAP: 1597150789Sglebius#ifdef DEVICE_POLLING 1598150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 1599150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 1600150789Sglebius error = ether_poll_register(vr_poll, ifp); 1601150789Sglebius if (error) 1602150789Sglebius return(error); 1603150789Sglebius VR_LOCK(sc); 1604150789Sglebius /* Disable interrupts */ 1605150789Sglebius CSR_WRITE_2(sc, VR_IMR, 0x0000); 1606150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 1607150789Sglebius VR_UNLOCK(sc); 1608150789Sglebius return (error); 1609150789Sglebius 1610150789Sglebius } 1611150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 1612150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 1613150789Sglebius error = ether_poll_deregister(ifp); 1614150789Sglebius /* Enable interrupts. */ 1615150789Sglebius VR_LOCK(sc); 1616150789Sglebius CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 1617150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 1618150789Sglebius VR_UNLOCK(sc); 1619150789Sglebius return (error); 1620150789Sglebius } 1621150789Sglebius#endif /* DEVICE_POLLING */ 1622128118Sru break; 162341502Swpaul default: 1624106936Ssam error = ether_ioctl(ifp, command, data); 162541502Swpaul break; 162641502Swpaul } 162741502Swpaul 1628131503Sbms return (error); 162941502Swpaul} 163041502Swpaul 1631102336Salfredstatic void 1632131503Sbmsvr_watchdog(struct ifnet *ifp) 163341502Swpaul{ 1634131518Sbms struct vr_softc *sc = ifp->if_softc; 163541502Swpaul 163667087Swpaul VR_LOCK(sc); 1637131844Sbms 163841502Swpaul ifp->if_oerrors++; 1639151773Sjhb if_printf(ifp, "watchdog timeout\n"); 164041502Swpaul 164141502Swpaul vr_stop(sc); 164241502Swpaul vr_reset(sc); 1643131844Sbms vr_init_locked(sc); 1644131518Sbms 1645132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1646131844Sbms vr_start_locked(ifp); 1647131844Sbms 1648131844Sbms VR_UNLOCK(sc); 164941502Swpaul} 165041502Swpaul 165141502Swpaul/* 165241502Swpaul * Stop the adapter and free any mbufs allocated to the 165341502Swpaul * RX and TX lists. 165441502Swpaul */ 1655102336Salfredstatic void 1656131503Sbmsvr_stop(struct vr_softc *sc) 165741502Swpaul{ 1658131503Sbms register int i; 1659131503Sbms struct ifnet *ifp; 166041502Swpaul 1661131518Sbms VR_LOCK_ASSERT(sc); 166267087Swpaul 1663147256Sbrooks ifp = sc->vr_ifp; 166441502Swpaul ifp->if_timer = 0; 166541502Swpaul 1666151911Sjhb callout_stop(&sc->vr_stat_callout); 1667148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 166851432Swpaul 166941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 167041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 167141502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 167241502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 167341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 167441502Swpaul 167541502Swpaul /* 167641502Swpaul * Free data in the RX lists. 167741502Swpaul */ 167841502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 167941502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 168041502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 168141502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 168241502Swpaul } 168341502Swpaul } 168441502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 1685131517Sbms sizeof(sc->vr_ldata->vr_rx_list)); 168641502Swpaul 168741502Swpaul /* 168841502Swpaul * Free the TX list buffers. 168941502Swpaul */ 169041502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 169141502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 169241502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 169341502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 169441502Swpaul } 169541502Swpaul } 169641502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 1697131517Sbms sizeof(sc->vr_ldata->vr_tx_list)); 169841502Swpaul} 169941502Swpaul 170041502Swpaul/* 170141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 170241502Swpaul * get confused by errant DMAs when rebooting. 170341502Swpaul */ 1704102336Salfredstatic void 1705131503Sbmsvr_shutdown(device_t dev) 170641502Swpaul{ 170741502Swpaul 1708136696Sbms vr_detach(dev); 170941502Swpaul} 1710