if_vr.c revision 151545
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 151545 2005-10-22 05:06:55Z imp $"); 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 595131844Sbms /*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during detach 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) 606107220Ssilby printf("vr%d: reset never completed!\n", sc->vr_unit); 607107220Ssilby else { 608107220Ssilby /* Use newer force reset command */ 609131503Sbms printf("vr%d: Using force reset command.\n", 610131503Sbms sc->vr_unit); 611107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 612107220Ssilby } 613107220Ssilby } 61441502Swpaul 61541502Swpaul /* Wait a little while for the chip to get its brains in order. */ 61641502Swpaul DELAY(1000); 61741502Swpaul} 61841502Swpaul 61941502Swpaul/* 62041502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 62141502Swpaul * IDs against our list and return a device name if we find a match. 62241502Swpaul */ 623102336Salfredstatic int 624131503Sbmsvr_probe(device_t dev) 62541502Swpaul{ 626131503Sbms struct vr_type *t = vr_devs; 62741502Swpaul 628131503Sbms while (t->vr_name != NULL) { 62949610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 63049610Swpaul (pci_get_device(dev) == t->vr_did)) { 63149610Swpaul device_set_desc(dev, t->vr_name); 632142398Simp return (BUS_PROBE_DEFAULT); 63341502Swpaul } 63441502Swpaul t++; 63541502Swpaul } 63641502Swpaul 637131503Sbms return (ENXIO); 63841502Swpaul} 63941502Swpaul 64041502Swpaul/* 64141502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 64241502Swpaul * setup and ethernet/BPF attach. 64341502Swpaul */ 644102336Salfredstatic int 645102336Salfredvr_attach(dev) 64649610Swpaul device_t dev; 64741502Swpaul{ 64867087Swpaul int i; 64941502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 65041502Swpaul struct vr_softc *sc; 65141502Swpaul struct ifnet *ifp; 65249610Swpaul int unit, error = 0, rid; 65341502Swpaul 65449610Swpaul sc = device_get_softc(dev); 65549610Swpaul unit = device_get_unit(dev); 65641502Swpaul 65793818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 658131518Sbms MTX_DEF); 65941502Swpaul /* 66041502Swpaul * Map control/status registers. 66141502Swpaul */ 66272813Swpaul pci_enable_busmaster(dev); 663107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 66441502Swpaul 66549610Swpaul rid = VR_RID; 666127135Snjl sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE); 66749610Swpaul 66849610Swpaul if (sc->vr_res == NULL) { 66949610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 67049610Swpaul error = ENXIO; 67141502Swpaul goto fail; 67241502Swpaul } 67341502Swpaul 67449610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 67549610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 67641502Swpaul 67741502Swpaul /* Allocate interrupt */ 67849610Swpaul rid = 0; 679127135Snjl sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 68049610Swpaul RF_SHAREABLE | RF_ACTIVE); 68149610Swpaul 68249610Swpaul if (sc->vr_irq == NULL) { 68341502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 68449610Swpaul error = ENXIO; 68541502Swpaul goto fail; 68641502Swpaul } 68741502Swpaul 68876586Swpaul /* 68976586Swpaul * Windows may put the chip in suspend mode when it 69076586Swpaul * shuts down. Be sure to kick it in the head to wake it 69176586Swpaul * up again. 69276586Swpaul */ 69376586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 69476586Swpaul 69541502Swpaul /* Reset the adapter. */ 69641502Swpaul vr_reset(sc); 69741502Swpaul 698131503Sbms /* 699110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 700110168Ssilby * initialization and disable AUTOPOLL. 701110168Ssilby */ 702131503Sbms pci_write_config(dev, VR_PCI_MODE, 703110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 704110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 705110168Ssilby 70641502Swpaul /* 70741502Swpaul * Get station address. The way the Rhine chips work, 70841502Swpaul * you're not allowed to directly access the EEPROM once 70941502Swpaul * they've been programmed a special way. Consequently, 71041502Swpaul * we need to read the node address from the PAR0 and PAR1 71141502Swpaul * registers. 71241502Swpaul */ 71341502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 71441502Swpaul DELAY(200); 71541502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 71641502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 71741502Swpaul 71841502Swpaul sc->vr_unit = unit; 71941502Swpaul 72051432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 72151657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 72251432Swpaul 72351432Swpaul if (sc->vr_ldata == NULL) { 72441502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 72549610Swpaul error = ENXIO; 72649610Swpaul goto fail; 72741502Swpaul } 72841502Swpaul 72941502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 73041502Swpaul 731147256Sbrooks ifp = sc->vr_ifp = if_alloc(IFT_ETHER); 732147256Sbrooks if (ifp == NULL) { 733147256Sbrooks printf("vr%d: can not if_alloc()\n", unit); 734147256Sbrooks error = ENOSPC; 735147256Sbrooks goto fail; 736147256Sbrooks } 73741502Swpaul ifp->if_softc = sc; 738121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 73941502Swpaul ifp->if_mtu = ETHERMTU; 74041502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 74141502Swpaul ifp->if_ioctl = vr_ioctl; 74241502Swpaul ifp->if_start = vr_start; 74341502Swpaul ifp->if_watchdog = vr_watchdog; 74441502Swpaul ifp->if_init = vr_init; 74541502Swpaul ifp->if_baudrate = 10000000; 746132986Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1); 74743515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 748132986Smlaier IFQ_SET_READY(&ifp->if_snd); 749150789Sglebius ifp->if_capenable = ifp->if_capabilities; 750128118Sru#ifdef DEVICE_POLLING 751128118Sru ifp->if_capabilities |= IFCAP_POLLING; 752128118Sru#endif 75341502Swpaul 754131503Sbms /* Do MII setup. */ 75551432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 75651432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 75741502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 75849610Swpaul error = ENXIO; 75941502Swpaul goto fail; 76041502Swpaul } 76141502Swpaul 76251432Swpaul callout_handle_init(&sc->vr_stat_ch); 76341502Swpaul 764131503Sbms /* Call MI attach routine. */ 765106936Ssam ether_ifattach(ifp, eaddr); 76641502Swpaul 767131844Sbms sc->suspended = 0; 768131844Sbms 769113609Snjl /* Hook interrupt last to avoid having to lock softc */ 770131518Sbms error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, 771112872Snjl vr_intr, sc, &sc->vr_intrhand); 772112872Snjl 773112872Snjl if (error) { 774112872Snjl printf("vr%d: couldn't set up irq\n", unit); 775113609Snjl ether_ifdetach(ifp); 776112872Snjl goto fail; 777112872Snjl } 778112872Snjl 77941502Swpaulfail: 780112872Snjl if (error) 781112872Snjl vr_detach(dev); 78267087Swpaul 783131503Sbms return (error); 78441502Swpaul} 78541502Swpaul 786113609Snjl/* 787113609Snjl * Shutdown hardware and free up resources. This can be called any 788113609Snjl * time after the mutex has been initialized. It is called in both 789113609Snjl * the error case in attach and the normal detach case so it needs 790113609Snjl * to be careful about only freeing resources that have actually been 791113609Snjl * allocated. 792113609Snjl */ 793102336Salfredstatic int 794131503Sbmsvr_detach(device_t dev) 79549610Swpaul{ 796131503Sbms struct vr_softc *sc = device_get_softc(dev); 797147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 79849610Swpaul 799112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 800131518Sbms 801150789Sglebius#ifdef DEVICE_POLLING 802150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 803150789Sglebius ether_poll_deregister(ifp); 804150789Sglebius#endif 805150789Sglebius 80667087Swpaul VR_LOCK(sc); 80749610Swpaul 808131844Sbms sc->suspended = 1; 809131844Sbms 810113609Snjl /* These should only be active if attach succeeded */ 811113812Simp if (device_is_attached(dev)) { 812113609Snjl vr_stop(sc); 813136976Sbms VR_UNLOCK(sc); /* XXX: Avoid recursive acquire. */ 814112872Snjl ether_ifdetach(ifp); 815136976Sbms VR_LOCK(sc); 816113609Snjl } 817113609Snjl if (sc->vr_miibus) 818112872Snjl device_delete_child(dev, sc->vr_miibus); 819113609Snjl bus_generic_detach(dev); 82049610Swpaul 821112872Snjl if (sc->vr_intrhand) 822112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 823112872Snjl if (sc->vr_irq) 824112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 825112872Snjl if (sc->vr_res) 826112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 82751432Swpaul 828151297Sru if (ifp) 829151297Sru if_free(ifp); 830151297Sru 831112872Snjl if (sc->vr_ldata) 832112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 83349610Swpaul 83467087Swpaul VR_UNLOCK(sc); 83567087Swpaul mtx_destroy(&sc->vr_mtx); 83649610Swpaul 837131503Sbms return (0); 83849610Swpaul} 83949610Swpaul 84041502Swpaul/* 84141502Swpaul * Initialize the transmit descriptors. 84241502Swpaul */ 843102336Salfredstatic int 844131503Sbmsvr_list_tx_init(struct vr_softc *sc) 84541502Swpaul{ 84641502Swpaul struct vr_chain_data *cd; 84741502Swpaul struct vr_list_data *ld; 84841502Swpaul int i; 84941502Swpaul 85041502Swpaul cd = &sc->vr_cdata; 85141502Swpaul ld = sc->vr_ldata; 85241502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 85341502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 85441502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 855131503Sbms cd->vr_tx_chain[i].vr_nextdesc = 85641502Swpaul &cd->vr_tx_chain[0]; 85741502Swpaul else 85841502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 85941502Swpaul &cd->vr_tx_chain[i + 1]; 86041502Swpaul } 861127901Sru cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0]; 86241502Swpaul 863131503Sbms return (0); 86441502Swpaul} 86541502Swpaul 86641502Swpaul 86741502Swpaul/* 86841502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 86941502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 87041502Swpaul * points back to the first. 87141502Swpaul */ 872102336Salfredstatic int 873131503Sbmsvr_list_rx_init(struct vr_softc *sc) 87441502Swpaul{ 87541502Swpaul struct vr_chain_data *cd; 87641502Swpaul struct vr_list_data *ld; 87741502Swpaul int i; 87841502Swpaul 879131518Sbms VR_LOCK_ASSERT(sc); 880131518Sbms 88141502Swpaul cd = &sc->vr_cdata; 88241502Swpaul ld = sc->vr_ldata; 88341502Swpaul 88441502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 88541502Swpaul cd->vr_rx_chain[i].vr_ptr = 88641502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 88749610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 888131503Sbms return (ENOBUFS); 88941502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 89041502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 89141502Swpaul &cd->vr_rx_chain[0]; 89241502Swpaul ld->vr_rx_list[i].vr_next = 89341502Swpaul vtophys(&ld->vr_rx_list[0]); 89441502Swpaul } else { 89541502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 89641502Swpaul &cd->vr_rx_chain[i + 1]; 89741502Swpaul ld->vr_rx_list[i].vr_next = 89841502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 89941502Swpaul } 90041502Swpaul } 90141502Swpaul 90241502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 90341502Swpaul 904131503Sbms return (0); 90541502Swpaul} 90641502Swpaul 90741502Swpaul/* 90841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 90941502Swpaul * Note: the length fields are only 11 bits wide, which means the 91041502Swpaul * largest size we can specify is 2047. This is important because 91141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 91241502Swpaul * overflow the field and make a mess. 91341502Swpaul */ 914102336Salfredstatic int 915131503Sbmsvr_newbuf(struct vr_softc *sc, struct vr_chain_onefrag *c, struct mbuf *m) 91641502Swpaul{ 91741502Swpaul struct mbuf *m_new = NULL; 91841502Swpaul 91949610Swpaul if (m == NULL) { 920111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 92187846Sluigi if (m_new == NULL) 922131503Sbms return (ENOBUFS); 92341502Swpaul 924111119Simp MCLGET(m_new, M_DONTWAIT); 92549610Swpaul if (!(m_new->m_flags & M_EXT)) { 92649610Swpaul m_freem(m_new); 927131503Sbms return (ENOBUFS); 92849610Swpaul } 92949610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 93049610Swpaul } else { 93149610Swpaul m_new = m; 93249610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 93349610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 93441502Swpaul } 93541502Swpaul 936131503Sbms m_adj(m_new, sizeof(uint64_t)); 93749610Swpaul 93841502Swpaul c->vr_mbuf = m_new; 93941502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 94041502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 94142491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 94241502Swpaul 943131503Sbms return (0); 94441502Swpaul} 94541502Swpaul 94641502Swpaul/* 94741502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 94841502Swpaul * the higher level protocols. 94941502Swpaul */ 950102336Salfredstatic void 951131503Sbmsvr_rxeof(struct vr_softc *sc) 95241502Swpaul{ 953131503Sbms struct mbuf *m, *m0; 954131503Sbms struct ifnet *ifp; 95541502Swpaul struct vr_chain_onefrag *cur_rx; 95641502Swpaul int total_len = 0; 957131503Sbms uint32_t rxstat; 95841502Swpaul 959122689Ssam VR_LOCK_ASSERT(sc); 960147256Sbrooks ifp = sc->vr_ifp; 96141502Swpaul 962131503Sbms while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 963131503Sbms VR_RXSTAT_OWN)) { 964127901Sru#ifdef DEVICE_POLLING 965150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 966127901Sru if (sc->rxcycles <= 0) 967127901Sru break; 968127901Sru sc->rxcycles--; 969127901Sru } 970150789Sglebius#endif 971127901Sru m0 = NULL; 97241502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 97341502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 97449610Swpaul m = cur_rx->vr_mbuf; 97541502Swpaul 97641502Swpaul /* 97741502Swpaul * If an error occurs, update stats, clear the 97841502Swpaul * status word and leave the mbuf cluster in place: 97941502Swpaul * it should simply get re-used next time this descriptor 980131503Sbms * comes up in the ring. 98141502Swpaul */ 98241502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 98341502Swpaul ifp->if_ierrors++; 984131503Sbms printf("vr%d: rx error (%02x):", sc->vr_unit, 985131503Sbms rxstat & 0x000000ff); 986110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 987110131Ssilby printf(" crc error"); 988110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 989110131Ssilby printf(" frame alignment error\n"); 990110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 991110131Ssilby printf(" FIFO overflow"); 992110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 993110131Ssilby printf(" received giant packet"); 994110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 995110131Ssilby printf(" received runt packet"); 996110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 997110131Ssilby printf(" system bus error"); 998110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 999110131Ssilby printf("rx buffer error"); 1000110131Ssilby printf("\n"); 100149610Swpaul vr_newbuf(sc, cur_rx, m); 100241502Swpaul continue; 100341502Swpaul } 100441502Swpaul 1005131503Sbms /* No errors; receive the packet. */ 100641502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 100741502Swpaul 100841502Swpaul /* 100942048Swpaul * XXX The VIA Rhine chip includes the CRC with every 101042048Swpaul * received frame, and there's no way to turn this 101142048Swpaul * behavior off (at least, I can't find anything in 1012131503Sbms * the manual that explains how to do it) so we have 101342048Swpaul * to trim off the CRC manually. 101442048Swpaul */ 101542048Swpaul total_len -= ETHER_CRC_LEN; 101642048Swpaul 101778508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 101878508Sbmilekic NULL); 101949610Swpaul vr_newbuf(sc, cur_rx, m); 102049610Swpaul if (m0 == NULL) { 102141502Swpaul ifp->if_ierrors++; 102241502Swpaul continue; 102341502Swpaul } 102449610Swpaul m = m0; 102541502Swpaul 102641502Swpaul ifp->if_ipackets++; 1027122689Ssam VR_UNLOCK(sc); 1028106936Ssam (*ifp->if_input)(ifp, m); 1029122689Ssam VR_LOCK(sc); 103041502Swpaul } 103141502Swpaul} 103241502Swpaul 1033105221Sphkstatic void 1034131503Sbmsvr_rxeoc(struct vr_softc *sc) 103541502Swpaul{ 1036147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1037110131Ssilby int i; 103841502Swpaul 1039131518Sbms VR_LOCK_ASSERT(sc); 1040131518Sbms 1041110131Ssilby ifp->if_ierrors++; 1042110131Ssilby 1043131503Sbms VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1044131503Sbms DELAY(10000); 1045110131Ssilby 1046131503Sbms /* Wait for receiver to stop */ 1047110131Ssilby for (i = 0x400; 1048110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1049131503Sbms i--) { 1050131503Sbms ; 1051131503Sbms } 1052110131Ssilby 1053110131Ssilby if (!i) { 1054110131Ssilby printf("vr%d: rx shutdown error!\n", sc->vr_unit); 1055110131Ssilby sc->vr_flags |= VR_F_RESTART; 1056110131Ssilby return; 1057131503Sbms } 1058110131Ssilby 105941502Swpaul vr_rxeof(sc); 1060110131Ssilby 106141502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 106241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 106341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 106441502Swpaul} 106541502Swpaul 106641502Swpaul/* 106741502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 106841502Swpaul * the list buffers. 106941502Swpaul */ 1070102336Salfredstatic void 1071131503Sbmsvr_txeof(struct vr_softc *sc) 107241502Swpaul{ 107341502Swpaul struct vr_chain *cur_tx; 1074147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 107541502Swpaul 1076131518Sbms VR_LOCK_ASSERT(sc); 107741502Swpaul 107841502Swpaul /* 107941502Swpaul * Go through our tx list and free mbufs for those 108041502Swpaul * frames that have been transmitted. 108141502Swpaul */ 1082127901Sru cur_tx = sc->vr_cdata.vr_tx_cons; 1083127901Sru while (cur_tx->vr_mbuf != NULL) { 1084131503Sbms uint32_t txstat; 1085110131Ssilby int i; 108641502Swpaul 108741502Swpaul txstat = cur_tx->vr_ptr->vr_status; 108841502Swpaul 1089101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1090101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1091110131Ssilby for (i = 0x400; 1092110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1093110131Ssilby i--) 1094101896Ssilby ; /* Wait for chip to shutdown */ 1095110131Ssilby if (!i) { 1096131503Sbms printf("vr%d: tx shutdown timeout\n", 1097131503Sbms sc->vr_unit); 1098110131Ssilby sc->vr_flags |= VR_F_RESTART; 1099110131Ssilby break; 1100110131Ssilby } 1101101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1102101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1103101896Ssilby break; 1104101896Ssilby } 1105101896Ssilby 110642491Swpaul if (txstat & VR_TXSTAT_OWN) 110741502Swpaul break; 110841502Swpaul 110941502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 111041502Swpaul ifp->if_oerrors++; 111141502Swpaul if (txstat & VR_TXSTAT_DEFER) 111241502Swpaul ifp->if_collisions++; 111341502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 111441502Swpaul ifp->if_collisions++; 111541502Swpaul } 111641502Swpaul 111741502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 111841502Swpaul 111941502Swpaul ifp->if_opackets++; 1120127901Sru m_freem(cur_tx->vr_mbuf); 1121127901Sru cur_tx->vr_mbuf = NULL; 1122148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 112341502Swpaul 1124127901Sru cur_tx = cur_tx->vr_nextdesc; 112541502Swpaul } 1126127901Sru sc->vr_cdata.vr_tx_cons = cur_tx; 1127127901Sru if (cur_tx->vr_mbuf == NULL) 112896677Ssilby ifp->if_timer = 0; 112941502Swpaul} 113041502Swpaul 1131102336Salfredstatic void 1132131503Sbmsvr_tick(void *xsc) 113351432Swpaul{ 1134131503Sbms struct vr_softc *sc = xsc; 113551432Swpaul struct mii_data *mii; 113651432Swpaul 113767087Swpaul VR_LOCK(sc); 1138131517Sbms 1139110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1140110131Ssilby printf("vr%d: restarting\n", sc->vr_unit); 1141110131Ssilby vr_stop(sc); 1142110131Ssilby vr_reset(sc); 1143131844Sbms vr_init_locked(sc); 1144110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1145110131Ssilby } 1146110131Ssilby 114751432Swpaul mii = device_get_softc(sc->vr_miibus); 114851432Swpaul mii_tick(mii); 114951432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 115051432Swpaul 115167087Swpaul VR_UNLOCK(sc); 115251432Swpaul} 115351432Swpaul 1154127901Sru#ifdef DEVICE_POLLING 1155127901Srustatic poll_handler_t vr_poll; 1156131844Sbmsstatic poll_handler_t vr_poll_locked; 1157127901Sru 1158102336Salfredstatic void 1159127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1160127901Sru{ 1161127901Sru struct vr_softc *sc = ifp->if_softc; 1162127901Sru 1163127901Sru VR_LOCK(sc); 1164150789Sglebius if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1165150789Sglebius vr_poll_locked(ifp, cmd, count); 1166131844Sbms VR_UNLOCK(sc); 1167131844Sbms} 1168131517Sbms 1169131844Sbmsstatic void 1170131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1171131844Sbms{ 1172131844Sbms struct vr_softc *sc = ifp->if_softc; 1173131844Sbms 1174131844Sbms VR_LOCK_ASSERT(sc); 1175131844Sbms 1176127901Sru sc->rxcycles = count; 1177127901Sru vr_rxeof(sc); 1178127901Sru vr_txeof(sc); 1179133006Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1180131844Sbms vr_start_locked(ifp); 1181127901Sru 1182131503Sbms if (cmd == POLL_AND_CHECK_STATUS) { 1183131503Sbms uint16_t status; 1184127901Sru 1185131503Sbms /* Also check status register. */ 1186127901Sru status = CSR_READ_2(sc, VR_ISR); 1187127901Sru if (status) 1188127901Sru CSR_WRITE_2(sc, VR_ISR, status); 1189127901Sru 1190127901Sru if ((status & VR_INTRS) == 0) 1191131844Sbms return; 1192127901Sru 1193127901Sru if (status & VR_ISR_RX_DROPPED) { 1194127901Sru printf("vr%d: rx packet lost\n", sc->vr_unit); 1195127901Sru ifp->if_ierrors++; 1196127901Sru } 1197127901Sru 1198127901Sru if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1199127901Sru (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1200127901Sru printf("vr%d: receive error (%04x)", 1201127901Sru sc->vr_unit, status); 1202127901Sru if (status & VR_ISR_RX_NOBUF) 1203127901Sru printf(" no buffers"); 1204127901Sru if (status & VR_ISR_RX_OFLOW) 1205127901Sru printf(" overflow"); 1206127901Sru if (status & VR_ISR_RX_DROPPED) 1207127901Sru printf(" packet lost"); 1208127901Sru printf("\n"); 1209127901Sru vr_rxeoc(sc); 1210127901Sru } 1211127901Sru 1212131503Sbms if ((status & VR_ISR_BUSERR) || 1213131503Sbms (status & VR_ISR_TX_UNDERRUN)) { 1214127901Sru vr_reset(sc); 1215131844Sbms vr_init_locked(sc); 1216131518Sbms return; 1217127901Sru } 1218127901Sru 1219127901Sru if ((status & VR_ISR_UDFI) || 1220127901Sru (status & VR_ISR_TX_ABRT2) || 1221127901Sru (status & VR_ISR_TX_ABRT)) { 1222127901Sru ifp->if_oerrors++; 1223127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1224127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1225127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1226127901Sru } 1227127901Sru } 1228127901Sru } 1229127901Sru} 1230127901Sru#endif /* DEVICE_POLLING */ 1231127901Sru 1232127901Srustatic void 1233131503Sbmsvr_intr(void *arg) 123441502Swpaul{ 1235131503Sbms struct vr_softc *sc = arg; 1236147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1237131503Sbms uint16_t status; 123841502Swpaul 123967087Swpaul VR_LOCK(sc); 1240131844Sbms 1241136997Sbms if (sc->suspended) { 1242136997Sbms /* 1243136997Sbms * Forcibly disable interrupts. 1244136997Sbms * XXX: Mobile VIA based platforms may need 1245136997Sbms * interrupt re-enable on resume. 1246136997Sbms */ 1247136997Sbms CSR_WRITE_2(sc, VR_IMR, 0x0000); 1248131844Sbms goto done_locked; 1249136997Sbms } 1250131844Sbms 1251127901Sru#ifdef DEVICE_POLLING 1252150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1253131844Sbms goto done_locked; 1254150789Sglebius#endif 1255131844Sbms 1256131844Sbms /* Suppress unwanted interrupts. */ 125741502Swpaul if (!(ifp->if_flags & IFF_UP)) { 125841502Swpaul vr_stop(sc); 1259131844Sbms goto done_locked; 126041502Swpaul } 126141502Swpaul 126241502Swpaul /* Disable interrupts. */ 126341502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 126441502Swpaul 126541502Swpaul for (;;) { 126641502Swpaul status = CSR_READ_2(sc, VR_ISR); 126741502Swpaul if (status) 126841502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 126941502Swpaul 127041502Swpaul if ((status & VR_INTRS) == 0) 127141502Swpaul break; 127241502Swpaul 127341502Swpaul if (status & VR_ISR_RX_OK) 127441502Swpaul vr_rxeof(sc); 127541502Swpaul 1276110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1277110131Ssilby printf("vr%d: rx packet lost\n", sc->vr_unit); 1278110131Ssilby ifp->if_ierrors++; 1279131503Sbms } 1280110131Ssilby 128141502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1282110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1283110131Ssilby printf("vr%d: receive error (%04x)", 1284110131Ssilby sc->vr_unit, status); 1285110131Ssilby if (status & VR_ISR_RX_NOBUF) 1286110131Ssilby printf(" no buffers"); 1287110131Ssilby if (status & VR_ISR_RX_OFLOW) 1288110131Ssilby printf(" overflow"); 1289110131Ssilby if (status & VR_ISR_RX_DROPPED) 1290110131Ssilby printf(" packet lost"); 1291110131Ssilby printf("\n"); 129241502Swpaul vr_rxeoc(sc); 129341502Swpaul } 129441502Swpaul 1295101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1296101896Ssilby vr_reset(sc); 1297131844Sbms vr_init_locked(sc); 1298101896Ssilby break; 129941502Swpaul } 130041502Swpaul 1301101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1302101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 130341502Swpaul vr_txeof(sc); 1304101896Ssilby if ((status & VR_ISR_UDFI) || 1305101896Ssilby (status & VR_ISR_TX_ABRT2) || 1306101896Ssilby (status & VR_ISR_TX_ABRT)) { 1307101896Ssilby ifp->if_oerrors++; 1308127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1309131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1310131503Sbms VR_CMD_TX_ON); 1311131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1312131503Sbms VR_CMD_TX_GO); 1313101896Ssilby } 1314127901Sru } 131541502Swpaul } 131641502Swpaul } 131741502Swpaul 131841502Swpaul /* Re-enable interrupts. */ 131941502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 132041502Swpaul 1321132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1322131844Sbms vr_start_locked(ifp); 1323131844Sbms 1324131844Sbmsdone_locked: 1325131844Sbms VR_UNLOCK(sc); 132641502Swpaul} 132741502Swpaul 132841502Swpaul/* 132941502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 133041502Swpaul * pointers to the fragment pointers. 133141502Swpaul */ 1332102336Salfredstatic int 1333131503Sbmsvr_encap(struct vr_softc *sc, struct vr_chain *c, struct mbuf *m_head) 133441502Swpaul{ 133541502Swpaul struct vr_desc *f = NULL; 133641502Swpaul struct mbuf *m; 133741502Swpaul 1338131518Sbms VR_LOCK_ASSERT(sc); 133941502Swpaul /* 134041502Swpaul * The VIA Rhine wants packet buffers to be longword 134141502Swpaul * aligned, but very often our mbufs aren't. Rather than 134241502Swpaul * waste time trying to decide when to copy and when not 134341502Swpaul * to copy, just do it all the time. 134441502Swpaul */ 1345127901Sru m = m_defrag(m_head, M_DONTWAIT); 1346131503Sbms if (m == NULL) 1347131503Sbms return (1); 134841502Swpaul 1349127901Sru /* 1350127901Sru * The Rhine chip doesn't auto-pad, so we have to make 1351127901Sru * sure to pad short frames out to the minimum frame length 1352127901Sru * ourselves. 1353127901Sru */ 1354127901Sru if (m->m_len < VR_MIN_FRAMELEN) { 1355127901Sru m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len; 1356127901Sru m->m_len = m->m_pkthdr.len; 135741502Swpaul } 135841502Swpaul 1359127901Sru c->vr_mbuf = m; 1360127901Sru f = c->vr_ptr; 1361127901Sru f->vr_data = vtophys(mtod(m, caddr_t)); 1362127901Sru f->vr_ctl = m->m_len; 1363127901Sru f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 1364127901Sru f->vr_status = 0; 1365127901Sru f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 1366127901Sru f->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 136741502Swpaul 1368131503Sbms return (0); 136941502Swpaul} 137041502Swpaul 137141502Swpaul/* 137241502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 137341502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 137441502Swpaul * copy of the pointers since the transmit list fragment pointers are 137541502Swpaul * physical addresses. 137641502Swpaul */ 137741502Swpaul 1378102336Salfredstatic void 1379131503Sbmsvr_start(struct ifnet *ifp) 138041502Swpaul{ 1381131518Sbms struct vr_softc *sc = ifp->if_softc; 1382131844Sbms 1383131844Sbms VR_LOCK(sc); 1384131844Sbms vr_start_locked(ifp); 1385131844Sbms VR_UNLOCK(sc); 1386131844Sbms} 1387131844Sbms 1388131844Sbmsstatic void 1389131844Sbmsvr_start_locked(struct ifnet *ifp) 1390131844Sbms{ 1391131844Sbms struct vr_softc *sc = ifp->if_softc; 1392127901Sru struct mbuf *m_head; 1393127901Sru struct vr_chain *cur_tx; 139441502Swpaul 1395148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 1396127901Sru return; 1397127901Sru 1398127901Sru cur_tx = sc->vr_cdata.vr_tx_prod; 1399127901Sru while (cur_tx->vr_mbuf == NULL) { 1400132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 140141502Swpaul if (m_head == NULL) 140241502Swpaul break; 140341502Swpaul 140441502Swpaul /* Pack the data into the descriptor. */ 140571271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 1406113274Ssilby /* Rollback, send what we were able to encap. */ 1407132986Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 140871271Swpaul break; 140971271Swpaul } 141041502Swpaul 1411127901Sru VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 141241502Swpaul 141341502Swpaul /* 141441502Swpaul * If there's a BPF listener, bounce a copy of this frame 141541502Swpaul * to him. 141641502Swpaul */ 1417106936Ssam BPF_MTAP(ifp, cur_tx->vr_mbuf); 141851583Swpaul 1419127901Sru cur_tx = cur_tx->vr_nextdesc; 142041502Swpaul } 1421127901Sru if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) { 1422127901Sru sc->vr_cdata.vr_tx_prod = cur_tx; 142341502Swpaul 1424127901Sru /* Tell the chip to start transmitting. */ 1425131517Sbms VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO); 142641526Swpaul 1427127901Sru /* Set a timeout in case the chip goes out to lunch. */ 1428127901Sru ifp->if_timer = 5; 142941502Swpaul 1430127901Sru if (cur_tx->vr_mbuf != NULL) 1431148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1432127901Sru } 1433131844Sbms} 143441502Swpaul 1435131844Sbmsstatic void 1436131844Sbmsvr_init(void *xsc) 1437131844Sbms{ 1438131844Sbms struct vr_softc *sc = xsc; 1439131844Sbms 1440131844Sbms VR_LOCK(sc); 1441131844Sbms vr_init_locked(sc); 144267087Swpaul VR_UNLOCK(sc); 144341502Swpaul} 144441502Swpaul 1445102336Salfredstatic void 1446131844Sbmsvr_init_locked(struct vr_softc *sc) 144741502Swpaul{ 1448147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 144951432Swpaul struct mii_data *mii; 145073963Swpaul int i; 145141502Swpaul 1452131844Sbms VR_LOCK_ASSERT(sc); 145341502Swpaul 145451432Swpaul mii = device_get_softc(sc->vr_miibus); 145541502Swpaul 1456131503Sbms /* Cancel pending I/O and free all RX/TX buffers. */ 145741502Swpaul vr_stop(sc); 145841502Swpaul vr_reset(sc); 145941502Swpaul 1460131503Sbms /* Set our station address. */ 146173963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 1462147256Sbrooks CSR_WRITE_1(sc, VR_PAR0 + i, IFP2ENADDR(sc->vr_ifp)[i]); 1463131503Sbms 1464131503Sbms /* Set DMA size. */ 1465101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1466101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 146773963Swpaul 1468131503Sbms /* 1469101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1470101108Ssilby * so we must set both. 1471101108Ssilby */ 1472101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1473110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1474101108Ssilby 1475101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1476101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1477101108Ssilby 147841502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1479110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 148041502Swpaul 148141502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 148241502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 148341502Swpaul 148441502Swpaul /* Init circular RX list. */ 148541502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 1486131503Sbms printf( 1487131503Sbms"vr%d: initialization failed: no memory for rx buffers\n", sc->vr_unit); 148841502Swpaul vr_stop(sc); 148941502Swpaul return; 149041502Swpaul } 149141502Swpaul 1492131503Sbms /* Init tx descriptors. */ 149341502Swpaul vr_list_tx_init(sc); 149441502Swpaul 149541502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 149641502Swpaul if (ifp->if_flags & IFF_PROMISC) 149741502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 149841502Swpaul else 149941502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 150041502Swpaul 150141502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 150241502Swpaul if (ifp->if_flags & IFF_BROADCAST) 150341502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 150441502Swpaul else 150541502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 150641502Swpaul 150741502Swpaul /* 150841502Swpaul * Program the multicast filter, if necessary. 150941502Swpaul */ 151041502Swpaul vr_setmulti(sc); 151141502Swpaul 151241502Swpaul /* 151341502Swpaul * Load the address of the RX list. 151441502Swpaul */ 151541502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 151641502Swpaul 151741502Swpaul /* Enable receiver and transmitter. */ 151841502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 151941502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 152041502Swpaul VR_CMD_RX_GO); 152141502Swpaul 152241502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 152341502Swpaul 1524127901Sru CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 1525127901Sru#ifdef DEVICE_POLLING 152641502Swpaul /* 1527127901Sru * Disable interrupts if we are polling. 1528127901Sru */ 1529150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1530127901Sru CSR_WRITE_2(sc, VR_IMR, 0); 1531131503Sbms else 1532150789Sglebius#endif 1533127901Sru /* 153441502Swpaul * Enable interrupts. 153541502Swpaul */ 153641502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 153741502Swpaul 153851432Swpaul mii_mediachg(mii); 153941502Swpaul 1540148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1541148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 154241502Swpaul 154351432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 154441502Swpaul} 154541502Swpaul 154641502Swpaul/* 154741502Swpaul * Set media options. 154841502Swpaul */ 1549102336Salfredstatic int 1550131503Sbmsvr_ifmedia_upd(struct ifnet *ifp) 155141502Swpaul{ 1552131503Sbms struct vr_softc *sc = ifp->if_softc; 155341502Swpaul 155451432Swpaul if (ifp->if_flags & IFF_UP) 155551432Swpaul vr_init(sc); 155641502Swpaul 1557131503Sbms return (0); 155841502Swpaul} 155941502Swpaul 156041502Swpaul/* 156141502Swpaul * Report current media status. 156241502Swpaul */ 1563102336Salfredstatic void 1564131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 156541502Swpaul{ 1566131518Sbms struct vr_softc *sc = ifp->if_softc; 156751432Swpaul struct mii_data *mii; 156841502Swpaul 156951432Swpaul mii = device_get_softc(sc->vr_miibus); 1570133468Sscottl VR_LOCK(sc); 157151432Swpaul mii_pollstat(mii); 1572133468Sscottl VR_UNLOCK(sc); 157351432Swpaul ifmr->ifm_active = mii->mii_media_active; 157451432Swpaul ifmr->ifm_status = mii->mii_media_status; 157541502Swpaul} 157641502Swpaul 1577102336Salfredstatic int 1578131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 157941502Swpaul{ 158041502Swpaul struct vr_softc *sc = ifp->if_softc; 158141502Swpaul struct ifreq *ifr = (struct ifreq *) data; 158251432Swpaul struct mii_data *mii; 158367087Swpaul int error = 0; 158441502Swpaul 1585131503Sbms switch (command) { 158641502Swpaul case SIOCSIFFLAGS: 1587131844Sbms VR_LOCK(sc); 158841502Swpaul if (ifp->if_flags & IFF_UP) { 1589131844Sbms vr_init_locked(sc); 159041502Swpaul } else { 1591148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 159241502Swpaul vr_stop(sc); 159341502Swpaul } 1594131844Sbms VR_UNLOCK(sc); 159541502Swpaul error = 0; 159641502Swpaul break; 159741502Swpaul case SIOCADDMULTI: 159841502Swpaul case SIOCDELMULTI: 1599131518Sbms VR_LOCK(sc); 160041502Swpaul vr_setmulti(sc); 1601131518Sbms VR_UNLOCK(sc); 160241502Swpaul error = 0; 160341502Swpaul break; 160441502Swpaul case SIOCGIFMEDIA: 160541502Swpaul case SIOCSIFMEDIA: 160651432Swpaul mii = device_get_softc(sc->vr_miibus); 160751432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 160841502Swpaul break; 1609128118Sru case SIOCSIFCAP: 1610150789Sglebius#ifdef DEVICE_POLLING 1611150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 1612150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 1613150789Sglebius error = ether_poll_register(vr_poll, ifp); 1614150789Sglebius if (error) 1615150789Sglebius return(error); 1616150789Sglebius VR_LOCK(sc); 1617150789Sglebius /* Disable interrupts */ 1618150789Sglebius CSR_WRITE_2(sc, VR_IMR, 0x0000); 1619150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 1620150789Sglebius VR_UNLOCK(sc); 1621150789Sglebius return (error); 1622150789Sglebius 1623150789Sglebius } 1624150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 1625150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 1626150789Sglebius error = ether_poll_deregister(ifp); 1627150789Sglebius /* Enable interrupts. */ 1628150789Sglebius VR_LOCK(sc); 1629150789Sglebius CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 1630150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 1631150789Sglebius VR_UNLOCK(sc); 1632150789Sglebius return (error); 1633150789Sglebius } 1634150789Sglebius#endif /* DEVICE_POLLING */ 1635128118Sru break; 163641502Swpaul default: 1637106936Ssam error = ether_ioctl(ifp, command, data); 163841502Swpaul break; 163941502Swpaul } 164041502Swpaul 1641131503Sbms return (error); 164241502Swpaul} 164341502Swpaul 1644102336Salfredstatic void 1645131503Sbmsvr_watchdog(struct ifnet *ifp) 164641502Swpaul{ 1647131518Sbms struct vr_softc *sc = ifp->if_softc; 164841502Swpaul 164967087Swpaul VR_LOCK(sc); 1650131844Sbms 165141502Swpaul ifp->if_oerrors++; 165241502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 165341502Swpaul 165441502Swpaul vr_stop(sc); 165541502Swpaul vr_reset(sc); 1656131844Sbms vr_init_locked(sc); 1657131518Sbms 1658132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1659131844Sbms vr_start_locked(ifp); 1660131844Sbms 1661131844Sbms VR_UNLOCK(sc); 166241502Swpaul} 166341502Swpaul 166441502Swpaul/* 166541502Swpaul * Stop the adapter and free any mbufs allocated to the 166641502Swpaul * RX and TX lists. 166741502Swpaul */ 1668102336Salfredstatic void 1669131503Sbmsvr_stop(struct vr_softc *sc) 167041502Swpaul{ 1671131503Sbms register int i; 1672131503Sbms struct ifnet *ifp; 167341502Swpaul 1674131518Sbms VR_LOCK_ASSERT(sc); 167567087Swpaul 1676147256Sbrooks ifp = sc->vr_ifp; 167741502Swpaul ifp->if_timer = 0; 167841502Swpaul 167951432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 1680148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 168151432Swpaul 168241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 168341502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 168441502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 168541502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 168641502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 168741502Swpaul 168841502Swpaul /* 168941502Swpaul * Free data in the RX lists. 169041502Swpaul */ 169141502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 169241502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 169341502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 169441502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 169541502Swpaul } 169641502Swpaul } 169741502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 1698131517Sbms sizeof(sc->vr_ldata->vr_rx_list)); 169941502Swpaul 170041502Swpaul /* 170141502Swpaul * Free the TX list buffers. 170241502Swpaul */ 170341502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 170441502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 170541502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 170641502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 170741502Swpaul } 170841502Swpaul } 170941502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 1710131517Sbms sizeof(sc->vr_ldata->vr_tx_list)); 171141502Swpaul} 171241502Swpaul 171341502Swpaul/* 171441502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 171541502Swpaul * get confused by errant DMAs when rebooting. 171641502Swpaul */ 1717102336Salfredstatic void 1718131503Sbmsvr_shutdown(device_t dev) 171941502Swpaul{ 172041502Swpaul 1721136696Sbms vr_detach(dev); 172241502Swpaul} 1723