if_vr.c revision 168950
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 168950 2007-04-22 15:09:03Z phk $"); 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/ethernet.h> 7841502Swpaul#include <net/if_dl.h> 7941502Swpaul#include <net/if_media.h> 80147256Sbrooks#include <net/if_types.h> 8141502Swpaul 8241502Swpaul#include <net/bpf.h> 8341502Swpaul 84131503Sbms#include <vm/vm.h> /* for vtophys */ 85131503Sbms#include <vm/pmap.h> /* for vtophys */ 8641502Swpaul#include <machine/bus.h> 8749610Swpaul#include <machine/resource.h> 8849610Swpaul#include <sys/bus.h> 8949610Swpaul#include <sys/rman.h> 9041502Swpaul 9151432Swpaul#include <dev/mii/miivar.h> 9251432Swpaul 93119288Simp#include <dev/pci/pcivar.h> 9441502Swpaul 9541502Swpaul#define VR_USEIOSPACE 9641502Swpaul 9741502Swpaul#include <pci/if_vrreg.h> 9841502Swpaul 99113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1); 100113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1); 10159758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 10259758Speter 103151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 10451432Swpaul#include "miibus_if.h" 10551432Swpaul 106110168Ssilby#undef VR_USESWSHIFT 107110168Ssilby 10841502Swpaul/* 10941502Swpaul * Various supported device vendors/types and their names. 11041502Swpaul */ 11141502Swpaulstatic struct vr_type vr_devs[] = { 112168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE, 113168827Sphk VR_Q_NEEDALIGN, 114168827Sphk "VIA VT3043 Rhine I 10/100BaseTX" }, 115168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 116168827Sphk VR_Q_NEEDALIGN, 117168827Sphk "VIA VT86C100A Rhine II 10/100BaseTX" }, 118168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 119168827Sphk 0, 120168827Sphk "VIA VT6102 Rhine II 10/100BaseTX" }, 121168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_III, 122168827Sphk 0, 123168827Sphk "VIA VT6105 Rhine III 10/100BaseTX" }, 124168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, 125168827Sphk VR_Q_CSUM, 126168827Sphk "VIA VT6105M Rhine III 10/100BaseTX" }, 127168827Sphk { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 128168827Sphk VR_Q_NEEDALIGN, 129168827Sphk "Delta Electronics Rhine II 10/100BaseTX" }, 130168827Sphk { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 131168827Sphk VR_Q_NEEDALIGN, 132168827Sphk "Addtron Technology Rhine II 10/100BaseTX" }, 133168813Sphk { 0, 0, 0, NULL } 13441502Swpaul}; 13541502Swpaul 136168946Sphk 137168946Sphkstruct vr_softc { 138168946Sphk struct ifnet *vr_ifp; /* interface info */ 139168946Sphk device_t vr_dev; 140168946Sphk struct resource *vr_res; 141168946Sphk struct resource *vr_irq; 142168946Sphk void *vr_intrhand; 143168946Sphk device_t vr_miibus; 144168946Sphk u_int8_t vr_revid; /* Rhine chip revision */ 145168946Sphk u_int8_t vr_flags; /* See VR_F_* below */ 146168946Sphk struct vr_list_data *vr_ldata; 147168946Sphk struct vr_chain_data vr_cdata; 148168946Sphk struct callout vr_stat_callout; 149168946Sphk struct mtx vr_mtx; 150168948Sphk int vr_suspended; /* if 1, sleeping/detaching */ 151168946Sphk int vr_quirks; 152168946Sphk#ifdef DEVICE_POLLING 153168946Sphk int rxcycles; 154168946Sphk#endif 155168946Sphk}; 156168946Sphk 157142407Simpstatic int vr_probe(device_t); 158142407Simpstatic int vr_attach(device_t); 159142407Simpstatic int vr_detach(device_t); 16041502Swpaul 161168948Sphkstatic int vr_newbuf(struct vr_chain *, struct mbuf *); 16241502Swpaul 163142407Simpstatic void vr_rxeof(struct vr_softc *); 164142407Simpstatic void vr_rxeoc(struct vr_softc *); 165142407Simpstatic void vr_txeof(struct vr_softc *); 166142407Simpstatic void vr_tick(void *); 167142407Simpstatic void vr_intr(void *); 168142407Simpstatic void vr_start(struct ifnet *); 169142407Simpstatic void vr_start_locked(struct ifnet *); 170142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t); 171142407Simpstatic void vr_init(void *); 172142407Simpstatic void vr_init_locked(struct vr_softc *); 173142407Simpstatic void vr_stop(struct vr_softc *); 174142407Simpstatic void vr_watchdog(struct ifnet *); 175142407Simpstatic void vr_shutdown(device_t); 176142407Simpstatic int vr_ifmedia_upd(struct ifnet *); 177142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *); 17841502Swpaul 179110168Ssilby#ifdef VR_USESWSHIFT 180142407Simpstatic void vr_mii_sync(struct vr_softc *); 181142407Simpstatic void vr_mii_send(struct vr_softc *, uint32_t, int); 182110168Ssilby#endif 183168946Sphkstatic int vr_mii_readreg(const struct vr_softc *, struct vr_mii_frame *); 184168946Sphkstatic int vr_mii_writereg(const struct vr_softc *, const struct vr_mii_frame *); 185142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t); 186142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t); 187142407Simpstatic void vr_miibus_statchg(device_t); 18841502Swpaul 189142407Simpstatic void vr_setcfg(struct vr_softc *, int); 190142407Simpstatic void vr_setmulti(struct vr_softc *); 191168946Sphkstatic void vr_reset(const struct vr_softc *); 192142407Simpstatic int vr_list_rx_init(struct vr_softc *); 193142407Simpstatic int vr_list_tx_init(struct vr_softc *); 19441502Swpaul 19549610Swpaul#ifdef VR_USEIOSPACE 19649610Swpaul#define VR_RES SYS_RES_IOPORT 19749610Swpaul#define VR_RID VR_PCI_LOIO 19849610Swpaul#else 19949610Swpaul#define VR_RES SYS_RES_MEMORY 20049610Swpaul#define VR_RID VR_PCI_LOMEM 20149610Swpaul#endif 20249610Swpaul 20349610Swpaulstatic device_method_t vr_methods[] = { 20449610Swpaul /* Device interface */ 20549610Swpaul DEVMETHOD(device_probe, vr_probe), 20649610Swpaul DEVMETHOD(device_attach, vr_attach), 20749610Swpaul DEVMETHOD(device_detach, vr_detach), 20849610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 20951432Swpaul 21051432Swpaul /* bus interface */ 21151432Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21251432Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21351432Swpaul 21451432Swpaul /* MII interface */ 21551432Swpaul DEVMETHOD(miibus_readreg, vr_miibus_readreg), 21651432Swpaul DEVMETHOD(miibus_writereg, vr_miibus_writereg), 21751432Swpaul DEVMETHOD(miibus_statchg, vr_miibus_statchg), 21851432Swpaul 21949610Swpaul { 0, 0 } 22049610Swpaul}; 22149610Swpaul 22249610Swpaulstatic driver_t vr_driver = { 22351455Swpaul "vr", 22449610Swpaul vr_methods, 22549610Swpaul sizeof(struct vr_softc) 22649610Swpaul}; 22749610Swpaul 22849610Swpaulstatic devclass_t vr_devclass; 22949610Swpaul 230113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0); 23151473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0); 232168946Sphk#define VR_F_RESTART 0x01 /* Restart unit on next tick */ 23349610Swpaul 234168946Sphk#define VR_LOCK(_sc) mtx_lock(&(_sc)->vr_mtx) 235168946Sphk#define VR_UNLOCK(_sc) mtx_unlock(&(_sc)->vr_mtx) 236168946Sphk#define VR_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->vr_mtx, MA_OWNED) 23741502Swpaul 238168946Sphk/* 239168946Sphk * register space access macros 240168946Sphk */ 241168946Sphk#define CSR_WRITE_4(sc, reg, val) bus_write_4(sc->vr_res, reg, val) 242168946Sphk#define CSR_WRITE_2(sc, reg, val) bus_write_2(sc->vr_res, reg, val) 243168946Sphk#define CSR_WRITE_1(sc, reg, val) bus_write_1(sc->vr_res, reg, val) 24441502Swpaul 245168946Sphk#define CSR_READ_2(sc, reg) bus_read_2(sc->vr_res, reg) 246168946Sphk#define CSR_READ_1(sc, reg) bus_read_1(sc->vr_res, reg) 24741502Swpaul 248168946Sphk#define VR_SETBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | (x)) 249168946Sphk#define VR_CLRBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~(x)) 25041502Swpaul 251168946Sphk#define VR_SETBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | (x)) 252168946Sphk#define VR_CLRBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~(x)) 25341502Swpaul 254168946Sphk#ifdef VR_USESWSHIFT 25541502Swpaul 256168946Sphk#define CSR_READ_4(sc, reg) bus_read_4(sc->vr_res, reg) 257168946Sphk#define SIO_SET(x) CSR_WRITE_1(sc, VR_MIICMD, CSR_READ_1(sc, VR_MIICMD) | (x)) 258168946Sphk#define SIO_CLR(x) CSR_WRITE_1(sc, VR_MIICMD, CSR_READ_1(sc, VR_MIICMD) & ~(x)) 25941502Swpaul 26041502Swpaul/* 26141502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 26241502Swpaul */ 263102336Salfredstatic void 264131503Sbmsvr_mii_sync(struct vr_softc *sc) 26541502Swpaul{ 266131503Sbms register int i; 26741502Swpaul 26841502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 26941502Swpaul 27041502Swpaul for (i = 0; i < 32; i++) { 27141502Swpaul SIO_SET(VR_MIICMD_CLK); 27241502Swpaul DELAY(1); 27341502Swpaul SIO_CLR(VR_MIICMD_CLK); 27441502Swpaul DELAY(1); 27541502Swpaul } 27641502Swpaul} 27741502Swpaul 27841502Swpaul/* 27941502Swpaul * Clock a series of bits through the MII. 28041502Swpaul */ 281102336Salfredstatic void 282131503Sbmsvr_mii_send(struct vr_softc *sc, uint32_t bits, int cnt) 28341502Swpaul{ 284131503Sbms int i; 28541502Swpaul 28641502Swpaul SIO_CLR(VR_MIICMD_CLK); 28741502Swpaul 28841502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 289131503Sbms if (bits & i) { 29041502Swpaul SIO_SET(VR_MIICMD_DATAIN); 291131503Sbms } else { 29241502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 293131503Sbms } 29441502Swpaul DELAY(1); 29541502Swpaul SIO_CLR(VR_MIICMD_CLK); 29641502Swpaul DELAY(1); 29741502Swpaul SIO_SET(VR_MIICMD_CLK); 29841502Swpaul } 29941502Swpaul} 300110168Ssilby#endif 30141502Swpaul 30241502Swpaul/* 30341502Swpaul * Read an PHY register through the MII. 30441502Swpaul */ 305102336Salfredstatic int 306168946Sphkvr_mii_readreg(const struct vr_softc *sc, struct vr_mii_frame *frame) 307131503Sbms#ifdef VR_USESWSHIFT 30841502Swpaul{ 309131503Sbms int i, ack; 31041502Swpaul 311131503Sbms /* Set up frame for RX. */ 31241502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 31341502Swpaul frame->mii_opcode = VR_MII_READOP; 31441502Swpaul frame->mii_turnaround = 0; 31541502Swpaul frame->mii_data = 0; 316131503Sbms 31741502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 31841502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 31941502Swpaul 320131503Sbms /* Turn on data xmit. */ 32141502Swpaul SIO_SET(VR_MIICMD_DIR); 32241502Swpaul 32341502Swpaul vr_mii_sync(sc); 32441502Swpaul 325131503Sbms /* Send command/address info. */ 32641502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 32741502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 32841502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 32941502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 33041502Swpaul 331131503Sbms /* Idle bit. */ 33241502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 33341502Swpaul DELAY(1); 33441502Swpaul SIO_SET(VR_MIICMD_CLK); 33541502Swpaul DELAY(1); 33641502Swpaul 33741502Swpaul /* Turn off xmit. */ 33841502Swpaul SIO_CLR(VR_MIICMD_DIR); 33941502Swpaul 34041502Swpaul /* Check for ack */ 34141502Swpaul SIO_CLR(VR_MIICMD_CLK); 34241502Swpaul DELAY(1); 343109058Smbr ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 34441502Swpaul SIO_SET(VR_MIICMD_CLK); 34541502Swpaul DELAY(1); 34641502Swpaul 34741502Swpaul /* 34841502Swpaul * Now try reading data bits. If the ack failed, we still 34941502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 35041502Swpaul */ 35141502Swpaul if (ack) { 35241502Swpaul for(i = 0; i < 16; i++) { 35341502Swpaul SIO_CLR(VR_MIICMD_CLK); 35441502Swpaul DELAY(1); 35541502Swpaul SIO_SET(VR_MIICMD_CLK); 35641502Swpaul DELAY(1); 35741502Swpaul } 35841502Swpaul goto fail; 35941502Swpaul } 36041502Swpaul 36141502Swpaul for (i = 0x8000; i; i >>= 1) { 36241502Swpaul SIO_CLR(VR_MIICMD_CLK); 36341502Swpaul DELAY(1); 36441502Swpaul if (!ack) { 36541502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 36641502Swpaul frame->mii_data |= i; 36741502Swpaul DELAY(1); 36841502Swpaul } 36941502Swpaul SIO_SET(VR_MIICMD_CLK); 37041502Swpaul DELAY(1); 37141502Swpaul } 37241502Swpaul 37341502Swpaulfail: 37441502Swpaul SIO_CLR(VR_MIICMD_CLK); 37541502Swpaul DELAY(1); 37641502Swpaul SIO_SET(VR_MIICMD_CLK); 37741502Swpaul DELAY(1); 37841502Swpaul 37941502Swpaul if (ack) 380131503Sbms return (1); 381131503Sbms return (0); 38241502Swpaul} 383110168Ssilby#else 384110168Ssilby{ 385131518Sbms int i; 38641502Swpaul 387131503Sbms /* Set the PHY address. */ 388110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 389110168Ssilby frame->mii_phyaddr); 390110168Ssilby 391131503Sbms /* Set the register address. */ 392110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 393110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB); 394131503Sbms 395110168Ssilby for (i = 0; i < 10000; i++) { 396110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0) 397110168Ssilby break; 398110168Ssilby DELAY(1); 399110168Ssilby } 400110168Ssilby frame->mii_data = CSR_READ_2(sc, VR_MIIDATA); 401110168Ssilby 402131503Sbms return (0); 403110168Ssilby} 404110168Ssilby#endif 405110168Ssilby 406110168Ssilby 40741502Swpaul/* 40841502Swpaul * Write to a PHY register through the MII. 40941502Swpaul */ 410102336Salfredstatic int 411168946Sphkvr_mii_writereg(const struct vr_softc *sc, const struct vr_mii_frame *frame) 412131503Sbms#ifdef VR_USESWSHIFT 41341502Swpaul{ 41441502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 41541502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 41641502Swpaul 417131503Sbms /* Set up frame for TX. */ 41841502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 41941502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 42041502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 421131503Sbms 422131503Sbms /* Turn on data output. */ 42341502Swpaul SIO_SET(VR_MIICMD_DIR); 42441502Swpaul 42541502Swpaul vr_mii_sync(sc); 42641502Swpaul 42741502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 42841502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 42941502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 43041502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 43141502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 43241502Swpaul vr_mii_send(sc, frame->mii_data, 16); 43341502Swpaul 43441502Swpaul /* Idle bit. */ 43541502Swpaul SIO_SET(VR_MIICMD_CLK); 43641502Swpaul DELAY(1); 43741502Swpaul SIO_CLR(VR_MIICMD_CLK); 43841502Swpaul DELAY(1); 43941502Swpaul 440131503Sbms /* Turn off xmit. */ 44141502Swpaul SIO_CLR(VR_MIICMD_DIR); 44241502Swpaul 443131503Sbms return (0); 44441502Swpaul} 445110168Ssilby#else 446110168Ssilby{ 447131518Sbms int i; 44841502Swpaul 449131503Sbms /* Set the PHY address. */ 450110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 451131503Sbms frame->mii_phyaddr); 452110168Ssilby 453131503Sbms /* Set the register address and data to write. */ 454110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 455110168Ssilby CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data); 456110168Ssilby 457110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB); 458110168Ssilby 459110168Ssilby for (i = 0; i < 10000; i++) { 460110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0) 461110168Ssilby break; 462110168Ssilby DELAY(1); 463110168Ssilby } 464110168Ssilby 465131503Sbms return (0); 466110168Ssilby} 467110168Ssilby#endif 468110168Ssilby 469102336Salfredstatic int 470131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg) 47151432Swpaul{ 47241502Swpaul struct vr_mii_frame frame; 473131503Sbms struct vr_softc *sc = device_get_softc(dev); 47441502Swpaul 475168946Sphk if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1) 476168946Sphk return (0); 477110168Ssilby 47841502Swpaul bzero((char *)&frame, sizeof(frame)); 47951432Swpaul frame.mii_phyaddr = phy; 48041502Swpaul frame.mii_regaddr = reg; 48141502Swpaul vr_mii_readreg(sc, &frame); 482131503Sbms return (frame.mii_data); 48341502Swpaul} 48441502Swpaul 485102336Salfredstatic int 486131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data) 48751432Swpaul{ 48841502Swpaul struct vr_mii_frame frame; 489131503Sbms struct vr_softc *sc = device_get_softc(dev); 49041502Swpaul 491168946Sphk if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1) 492168946Sphk return (0); 493110168Ssilby 49441502Swpaul bzero((char *)&frame, sizeof(frame)); 49551432Swpaul frame.mii_phyaddr = phy; 49641502Swpaul frame.mii_regaddr = reg; 49741502Swpaul frame.mii_data = data; 49841502Swpaul vr_mii_writereg(sc, &frame); 49941502Swpaul 500131503Sbms return (0); 50151432Swpaul} 50251432Swpaul 503102336Salfredstatic void 504131503Sbmsvr_miibus_statchg(device_t dev) 50551432Swpaul{ 50651432Swpaul struct mii_data *mii; 507131503Sbms struct vr_softc *sc = device_get_softc(dev); 50851432Swpaul 50951432Swpaul mii = device_get_softc(sc->vr_miibus); 51051432Swpaul vr_setcfg(sc, mii->mii_media_active); 51141502Swpaul} 51241502Swpaul 51341502Swpaul/* 51441502Swpaul * Program the 64-bit multicast hash filter. 51541502Swpaul */ 516102336Salfredstatic void 517131503Sbmsvr_setmulti(struct vr_softc *sc) 51841502Swpaul{ 519147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 52041502Swpaul int h = 0; 521131503Sbms uint32_t hashes[2] = { 0, 0 }; 52241502Swpaul struct ifmultiaddr *ifma; 523131503Sbms uint8_t rxfilt; 52441502Swpaul int mcnt = 0; 52541502Swpaul 526131518Sbms VR_LOCK_ASSERT(sc); 52741502Swpaul 52841502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 52941502Swpaul 53041502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 53141502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 53241502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 53341502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 53441502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 53541502Swpaul return; 53641502Swpaul } 53741502Swpaul 538131503Sbms /* First, zero out all the existing hash bits. */ 53941502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 54041502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 54141502Swpaul 542131503Sbms /* Now program new ones. */ 543148654Srwatson IF_ADDR_LOCK(ifp); 54472084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 54541502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 54641502Swpaul continue; 547130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 548130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 54941502Swpaul if (h < 32) 55041502Swpaul hashes[0] |= (1 << h); 55141502Swpaul else 55241502Swpaul hashes[1] |= (1 << (h - 32)); 55341502Swpaul mcnt++; 55441502Swpaul } 555148654Srwatson IF_ADDR_UNLOCK(ifp); 55641502Swpaul 55741502Swpaul if (mcnt) 55841502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 55941502Swpaul else 56041502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 56141502Swpaul 56241502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 56341502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 56441502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 56541502Swpaul} 56641502Swpaul 56741502Swpaul/* 56841502Swpaul * In order to fiddle with the 56941502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 57041502Swpaul * first have to put the transmit and/or receive logic in the idle state. 57141502Swpaul */ 572102336Salfredstatic void 573131503Sbmsvr_setcfg(struct vr_softc *sc, int media) 57441502Swpaul{ 575131517Sbms int restart = 0; 57641502Swpaul 577131518Sbms VR_LOCK_ASSERT(sc); 578131518Sbms 57941502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 58041502Swpaul restart = 1; 58141502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 58241502Swpaul } 58341502Swpaul 58451432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 58541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 58641502Swpaul else 58741502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 58841502Swpaul 58941502Swpaul if (restart) 59041502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 59141502Swpaul} 59241502Swpaul 593102336Salfredstatic void 594168946Sphkvr_reset(const struct vr_softc *sc) 59541502Swpaul{ 596131517Sbms register int i; 59741502Swpaul 598151773Sjhb /*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */ 599131518Sbms 60041502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 60141502Swpaul 60241502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 60341502Swpaul DELAY(10); 60441502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 60541502Swpaul break; 60641502Swpaul } 607107220Ssilby if (i == VR_TIMEOUT) { 608107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 609162315Sglebius device_printf(sc->vr_dev, "reset never completed!\n"); 610107220Ssilby else { 611107220Ssilby /* Use newer force reset command */ 612162315Sglebius device_printf(sc->vr_dev, "Using force reset command.\n"); 613107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 614107220Ssilby } 615107220Ssilby } 61641502Swpaul 61741502Swpaul /* Wait a little while for the chip to get its brains in order. */ 61841502Swpaul DELAY(1000); 61941502Swpaul} 62041502Swpaul 62141502Swpaul/* 62241502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 623168813Sphk * IDs against our list and return a match or NULL 624168813Sphk */ 625168813Sphkstatic struct vr_type * 626168813Sphkvr_match(device_t dev) 627168813Sphk{ 628168813Sphk struct vr_type *t = vr_devs; 629168813Sphk 630168813Sphk for (t = vr_devs; t->vr_name != NULL; t++) 631168813Sphk if ((pci_get_vendor(dev) == t->vr_vid) && 632168813Sphk (pci_get_device(dev) == t->vr_did)) 633168813Sphk return (t); 634168813Sphk return (NULL); 635168813Sphk} 636168813Sphk 637168813Sphk/* 638168813Sphk * Probe for a VIA Rhine chip. Check the PCI vendor and device 63941502Swpaul * IDs against our list and return a device name if we find a match. 64041502Swpaul */ 641102336Salfredstatic int 642131503Sbmsvr_probe(device_t dev) 64341502Swpaul{ 644168813Sphk struct vr_type *t; 64541502Swpaul 646168813Sphk t = vr_match(dev); 647168813Sphk if (t != NULL) { 648168813Sphk device_set_desc(dev, t->vr_name); 649168813Sphk return (BUS_PROBE_DEFAULT); 65041502Swpaul } 651131503Sbms return (ENXIO); 65241502Swpaul} 65341502Swpaul 65441502Swpaul/* 65541502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 65641502Swpaul * setup and ethernet/BPF attach. 65741502Swpaul */ 658102336Salfredstatic int 659168946Sphkvr_attach(device_t dev) 66041502Swpaul{ 66167087Swpaul int i; 66241502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 66341502Swpaul struct vr_softc *sc; 66441502Swpaul struct ifnet *ifp; 665168946Sphk int error = 0, rid; 666168813Sphk struct vr_type *t; 66741502Swpaul 66849610Swpaul sc = device_get_softc(dev); 669162315Sglebius sc->vr_dev = dev; 670168813Sphk t = vr_match(dev); 671168813Sphk KASSERT(t != NULL, ("Lost if_vr device match")); 672168813Sphk sc->vr_quirks = t->vr_quirks; 673168813Sphk device_printf(dev, "Quirks: 0x%x\n", sc->vr_quirks); 67441502Swpaul 67593818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 676131518Sbms MTX_DEF); 677151911Sjhb callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0); 678151911Sjhb 67941502Swpaul /* 68041502Swpaul * Map control/status registers. 68141502Swpaul */ 68272813Swpaul pci_enable_busmaster(dev); 683107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 68441502Swpaul 68549610Swpaul rid = VR_RID; 686127135Snjl sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE); 68749610Swpaul 68849610Swpaul if (sc->vr_res == NULL) { 689151773Sjhb device_printf(dev, "couldn't map ports/memory\n"); 69049610Swpaul error = ENXIO; 69141502Swpaul goto fail; 69241502Swpaul } 69341502Swpaul 69441502Swpaul /* Allocate interrupt */ 69549610Swpaul rid = 0; 696127135Snjl sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 69749610Swpaul RF_SHAREABLE | RF_ACTIVE); 69849610Swpaul 69949610Swpaul if (sc->vr_irq == NULL) { 700151773Sjhb device_printf(dev, "couldn't map interrupt\n"); 70149610Swpaul error = ENXIO; 70241502Swpaul goto fail; 70341502Swpaul } 70441502Swpaul 705151773Sjhb /* Allocate ifnet structure. */ 706151773Sjhb ifp = sc->vr_ifp = if_alloc(IFT_ETHER); 707151773Sjhb if (ifp == NULL) { 708151773Sjhb device_printf(dev, "can not if_alloc()\n"); 709151773Sjhb error = ENOSPC; 710151773Sjhb goto fail; 711151773Sjhb } 712151773Sjhb ifp->if_softc = sc; 713151773Sjhb if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 714151773Sjhb ifp->if_mtu = ETHERMTU; 715151773Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 716151773Sjhb ifp->if_ioctl = vr_ioctl; 717151773Sjhb ifp->if_start = vr_start; 718151773Sjhb ifp->if_watchdog = vr_watchdog; 719151773Sjhb ifp->if_init = vr_init; 720151773Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1); 721151773Sjhb ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 722151773Sjhb IFQ_SET_READY(&ifp->if_snd); 723168827Sphk 724168827Sphk if (sc->vr_quirks & VR_Q_CSUM) { 725168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 726168827Sphk ifp->if_capabilities |= IFCAP_HWCSUM; 727168827Sphk } 728168827Sphk 729151773Sjhb ifp->if_capenable = ifp->if_capabilities; 730168827Sphk if (ifp->if_capenable & IFCAP_TXCSUM) 731168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 732168827Sphk else 733168827Sphk ifp->if_hwassist = 0; 734168827Sphk 735151773Sjhb#ifdef DEVICE_POLLING 736151773Sjhb ifp->if_capabilities |= IFCAP_POLLING; 737151773Sjhb#endif 738151773Sjhb 73976586Swpaul /* 74076586Swpaul * Windows may put the chip in suspend mode when it 74176586Swpaul * shuts down. Be sure to kick it in the head to wake it 74276586Swpaul * up again. 74376586Swpaul */ 74476586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 74576586Swpaul 74641502Swpaul /* Reset the adapter. */ 74741502Swpaul vr_reset(sc); 74841502Swpaul 749131503Sbms /* 750110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 751110168Ssilby * initialization and disable AUTOPOLL. 752110168Ssilby */ 753131503Sbms pci_write_config(dev, VR_PCI_MODE, 754110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 755110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 756110168Ssilby 75741502Swpaul /* 75841502Swpaul * Get station address. The way the Rhine chips work, 75941502Swpaul * you're not allowed to directly access the EEPROM once 76041502Swpaul * they've been programmed a special way. Consequently, 76141502Swpaul * we need to read the node address from the PAR0 and PAR1 76241502Swpaul * registers. 76341502Swpaul */ 76441502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 76541502Swpaul DELAY(200); 76641502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 76741502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 76841502Swpaul 76951432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 770151773Sjhb M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0); 77151432Swpaul 77251432Swpaul if (sc->vr_ldata == NULL) { 773151773Sjhb device_printf(dev, "no memory for list buffers!\n"); 77449610Swpaul error = ENXIO; 77549610Swpaul goto fail; 77641502Swpaul } 77741502Swpaul 778131503Sbms /* Do MII setup. */ 77951432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 78051432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 781151773Sjhb device_printf(dev, "MII without any phy!\n"); 78249610Swpaul error = ENXIO; 78341502Swpaul goto fail; 78441502Swpaul } 78541502Swpaul 786131503Sbms /* Call MI attach routine. */ 787106936Ssam ether_ifattach(ifp, eaddr); 78841502Swpaul 789168948Sphk sc->vr_suspended = 0; 790131844Sbms 791113609Snjl /* Hook interrupt last to avoid having to lock softc */ 792131518Sbms error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, 793166901Spiso NULL, vr_intr, sc, &sc->vr_intrhand); 794112872Snjl 795112872Snjl if (error) { 796151773Sjhb device_printf(dev, "couldn't set up irq\n"); 797113609Snjl ether_ifdetach(ifp); 798112872Snjl goto fail; 799112872Snjl } 800112872Snjl 80141502Swpaulfail: 802112872Snjl if (error) 803112872Snjl vr_detach(dev); 80467087Swpaul 805131503Sbms return (error); 80641502Swpaul} 80741502Swpaul 808113609Snjl/* 809113609Snjl * Shutdown hardware and free up resources. This can be called any 810113609Snjl * time after the mutex has been initialized. It is called in both 811113609Snjl * the error case in attach and the normal detach case so it needs 812113609Snjl * to be careful about only freeing resources that have actually been 813113609Snjl * allocated. 814113609Snjl */ 815102336Salfredstatic int 816131503Sbmsvr_detach(device_t dev) 81749610Swpaul{ 818131503Sbms struct vr_softc *sc = device_get_softc(dev); 819147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 82049610Swpaul 821112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 822131518Sbms 823150789Sglebius#ifdef DEVICE_POLLING 824150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 825150789Sglebius ether_poll_deregister(ifp); 826150789Sglebius#endif 827150789Sglebius 828113609Snjl /* These should only be active if attach succeeded */ 829113812Simp if (device_is_attached(dev)) { 830151911Sjhb VR_LOCK(sc); 831168948Sphk sc->vr_suspended = 1; 832113609Snjl vr_stop(sc); 833151911Sjhb VR_UNLOCK(sc); 834151911Sjhb callout_drain(&sc->vr_stat_callout); 835112872Snjl ether_ifdetach(ifp); 836113609Snjl } 837113609Snjl if (sc->vr_miibus) 838112872Snjl device_delete_child(dev, sc->vr_miibus); 839113609Snjl bus_generic_detach(dev); 84049610Swpaul 841112872Snjl if (sc->vr_intrhand) 842112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 843112872Snjl if (sc->vr_irq) 844112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 845112872Snjl if (sc->vr_res) 846112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 84751432Swpaul 848151297Sru if (ifp) 849151297Sru if_free(ifp); 850151297Sru 851112872Snjl if (sc->vr_ldata) 852112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 85349610Swpaul 85467087Swpaul mtx_destroy(&sc->vr_mtx); 85549610Swpaul 856131503Sbms return (0); 85749610Swpaul} 85849610Swpaul 85941502Swpaul/* 86041502Swpaul * Initialize the transmit descriptors. 86141502Swpaul */ 862102336Salfredstatic int 863131503Sbmsvr_list_tx_init(struct vr_softc *sc) 86441502Swpaul{ 86541502Swpaul struct vr_chain_data *cd; 86641502Swpaul struct vr_list_data *ld; 86741502Swpaul int i; 86841502Swpaul 86941502Swpaul cd = &sc->vr_cdata; 87041502Swpaul ld = sc->vr_ldata; 87141502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 87241502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 873168950Sphk if (i == (VR_TX_LIST_CNT - 1)) { 874131503Sbms cd->vr_tx_chain[i].vr_nextdesc = 875168950Sphk &cd->vr_tx_chain[0]; 876168950Sphk ld->vr_tx_list[i].vr_nextphys = 877168950Sphk vtophys(&ld->vr_tx_list[0]); 878168950Sphk } else { 87941502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 88041502Swpaul &cd->vr_tx_chain[i + 1]; 881168950Sphk ld->vr_tx_list[i].vr_nextphys = 882168950Sphk vtophys(&ld->vr_tx_list[i + 1]); 883168950Sphk } 88441502Swpaul } 885127901Sru cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0]; 88641502Swpaul 887131503Sbms return (0); 88841502Swpaul} 88941502Swpaul 89041502Swpaul 89141502Swpaul/* 89241502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 89341502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 89441502Swpaul * points back to the first. 89541502Swpaul */ 896102336Salfredstatic int 897131503Sbmsvr_list_rx_init(struct vr_softc *sc) 89841502Swpaul{ 89941502Swpaul struct vr_chain_data *cd; 90041502Swpaul struct vr_list_data *ld; 90141502Swpaul int i; 90241502Swpaul 903131518Sbms VR_LOCK_ASSERT(sc); 904131518Sbms 90541502Swpaul cd = &sc->vr_cdata; 90641502Swpaul ld = sc->vr_ldata; 90741502Swpaul 90841502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 909168948Sphk cd->vr_rx_chain[i].vr_ptr = &ld->vr_rx_list[i]; 910168946Sphk if (vr_newbuf(&cd->vr_rx_chain[i], NULL) == ENOBUFS) 911131503Sbms return (ENOBUFS); 91241502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 91341502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 91441502Swpaul &cd->vr_rx_chain[0]; 915168948Sphk ld->vr_rx_list[i].vr_nextphys = 91641502Swpaul vtophys(&ld->vr_rx_list[0]); 91741502Swpaul } else { 91841502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 91941502Swpaul &cd->vr_rx_chain[i + 1]; 920168948Sphk ld->vr_rx_list[i].vr_nextphys = 92141502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 92241502Swpaul } 92341502Swpaul } 92441502Swpaul 92541502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 92641502Swpaul 927131503Sbms return (0); 92841502Swpaul} 92941502Swpaul 93041502Swpaul/* 93141502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 93241502Swpaul * Note: the length fields are only 11 bits wide, which means the 93341502Swpaul * largest size we can specify is 2047. This is important because 93441502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 93541502Swpaul * overflow the field and make a mess. 93641502Swpaul */ 937102336Salfredstatic int 938168948Sphkvr_newbuf(struct vr_chain *c, struct mbuf *m) 93941502Swpaul{ 94041502Swpaul struct mbuf *m_new = NULL; 94141502Swpaul 94249610Swpaul if (m == NULL) { 943111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 94487846Sluigi if (m_new == NULL) 945131503Sbms return (ENOBUFS); 94641502Swpaul 947111119Simp MCLGET(m_new, M_DONTWAIT); 94849610Swpaul if (!(m_new->m_flags & M_EXT)) { 94949610Swpaul m_freem(m_new); 950131503Sbms return (ENOBUFS); 95149610Swpaul } 95249610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 95349610Swpaul } else { 95449610Swpaul m_new = m; 95549610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 95649610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 95741502Swpaul } 95841502Swpaul 959131503Sbms m_adj(m_new, sizeof(uint64_t)); 96049610Swpaul 96141502Swpaul c->vr_mbuf = m_new; 96241502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 96341502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 96442491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 96541502Swpaul 966131503Sbms return (0); 96741502Swpaul} 96841502Swpaul 96941502Swpaul/* 97041502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 97141502Swpaul * the higher level protocols. 97241502Swpaul */ 973102336Salfredstatic void 974131503Sbmsvr_rxeof(struct vr_softc *sc) 97541502Swpaul{ 976131503Sbms struct mbuf *m, *m0; 977131503Sbms struct ifnet *ifp; 978168948Sphk struct vr_chain *cur_rx; 97941502Swpaul int total_len = 0; 980168827Sphk uint32_t rxstat, rxctl; 98141502Swpaul 982122689Ssam VR_LOCK_ASSERT(sc); 983147256Sbrooks ifp = sc->vr_ifp; 98441502Swpaul 985131503Sbms while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 986131503Sbms VR_RXSTAT_OWN)) { 987127901Sru#ifdef DEVICE_POLLING 988150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 989127901Sru if (sc->rxcycles <= 0) 990127901Sru break; 991127901Sru sc->rxcycles--; 992127901Sru } 993150789Sglebius#endif 994127901Sru m0 = NULL; 99541502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 99641502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 99749610Swpaul m = cur_rx->vr_mbuf; 99841502Swpaul 99941502Swpaul /* 100041502Swpaul * If an error occurs, update stats, clear the 100141502Swpaul * status word and leave the mbuf cluster in place: 100241502Swpaul * it should simply get re-used next time this descriptor 1003131503Sbms * comes up in the ring. 100441502Swpaul */ 100541502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 100641502Swpaul ifp->if_ierrors++; 1007162315Sglebius device_printf(sc->vr_dev, 1008162315Sglebius "rx error (%02x):", rxstat & 0x000000ff); 1009110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 1010110131Ssilby printf(" crc error"); 1011110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 1012110131Ssilby printf(" frame alignment error\n"); 1013110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 1014110131Ssilby printf(" FIFO overflow"); 1015110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 1016110131Ssilby printf(" received giant packet"); 1017110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 1018110131Ssilby printf(" received runt packet"); 1019110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 1020110131Ssilby printf(" system bus error"); 1021110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 1022110131Ssilby printf("rx buffer error"); 1023110131Ssilby printf("\n"); 1024168946Sphk vr_newbuf(cur_rx, m); 102541502Swpaul continue; 102641502Swpaul } 102741502Swpaul 1028131503Sbms /* No errors; receive the packet. */ 102941502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 1030168827Sphk if (ifp->if_capenable & IFCAP_RXCSUM) { 1031168827Sphk rxctl = cur_rx->vr_ptr->vr_ctl; 1032168827Sphk if ((rxctl & VR_RXCTL_GOODIP) == VR_RXCTL_GOODIP) 1033168827Sphk m->m_pkthdr.csum_flags |= 1034168827Sphk CSUM_IP_CHECKED | CSUM_IP_VALID; 1035168827Sphk if ((rxctl & VR_RXCTL_GOODTCPUDP)) { 1036168827Sphk m->m_pkthdr.csum_flags |= 1037168827Sphk CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 1038168827Sphk m->m_pkthdr.csum_data = 0xffff; 1039168827Sphk } 1040168827Sphk } 104141502Swpaul 104241502Swpaul /* 104342048Swpaul * XXX The VIA Rhine chip includes the CRC with every 104442048Swpaul * received frame, and there's no way to turn this 104542048Swpaul * behavior off (at least, I can't find anything in 1046131503Sbms * the manual that explains how to do it) so we have 104742048Swpaul * to trim off the CRC manually. 104842048Swpaul */ 104942048Swpaul total_len -= ETHER_CRC_LEN; 105042048Swpaul 105178508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 105278508Sbmilekic NULL); 1053168946Sphk vr_newbuf(cur_rx, m); 105449610Swpaul if (m0 == NULL) { 105541502Swpaul ifp->if_ierrors++; 105641502Swpaul continue; 105741502Swpaul } 105849610Swpaul m = m0; 105941502Swpaul 106041502Swpaul ifp->if_ipackets++; 1061122689Ssam VR_UNLOCK(sc); 1062106936Ssam (*ifp->if_input)(ifp, m); 1063122689Ssam VR_LOCK(sc); 106441502Swpaul } 106541502Swpaul} 106641502Swpaul 1067105221Sphkstatic void 1068131503Sbmsvr_rxeoc(struct vr_softc *sc) 106941502Swpaul{ 1070147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1071110131Ssilby int i; 107241502Swpaul 1073131518Sbms VR_LOCK_ASSERT(sc); 1074131518Sbms 1075110131Ssilby ifp->if_ierrors++; 1076110131Ssilby 1077131503Sbms VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1078131503Sbms DELAY(10000); 1079110131Ssilby 1080131503Sbms /* Wait for receiver to stop */ 1081110131Ssilby for (i = 0x400; 1082110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1083131503Sbms i--) { 1084131503Sbms ; 1085131503Sbms } 1086110131Ssilby 1087110131Ssilby if (!i) { 1088162315Sglebius device_printf(sc->vr_dev, "rx shutdown error!\n"); 1089110131Ssilby sc->vr_flags |= VR_F_RESTART; 1090110131Ssilby return; 1091131503Sbms } 1092110131Ssilby 109341502Swpaul vr_rxeof(sc); 1094110131Ssilby 109541502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 109641502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 109741502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 109841502Swpaul} 109941502Swpaul 110041502Swpaul/* 110141502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 110241502Swpaul * the list buffers. 110341502Swpaul */ 1104102336Salfredstatic void 1105131503Sbmsvr_txeof(struct vr_softc *sc) 110641502Swpaul{ 110741502Swpaul struct vr_chain *cur_tx; 1108147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 110941502Swpaul 1110131518Sbms VR_LOCK_ASSERT(sc); 111141502Swpaul 111241502Swpaul /* 111341502Swpaul * Go through our tx list and free mbufs for those 111441502Swpaul * frames that have been transmitted. 111541502Swpaul */ 1116127901Sru cur_tx = sc->vr_cdata.vr_tx_cons; 1117168813Sphk while (cur_tx != sc->vr_cdata.vr_tx_prod) { 1118131503Sbms uint32_t txstat; 1119110131Ssilby int i; 112041502Swpaul 112141502Swpaul txstat = cur_tx->vr_ptr->vr_status; 112241502Swpaul 1123101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1124101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1125110131Ssilby for (i = 0x400; 1126110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1127110131Ssilby i--) 1128101896Ssilby ; /* Wait for chip to shutdown */ 1129110131Ssilby if (!i) { 1130162315Sglebius device_printf(sc->vr_dev, "tx shutdown timeout\n"); 1131110131Ssilby sc->vr_flags |= VR_F_RESTART; 1132110131Ssilby break; 1133110131Ssilby } 1134168813Sphk atomic_set_acq_32(&VR_TXOWN(cur_tx), VR_TXSTAT_OWN); 1135101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1136101896Ssilby break; 1137101896Ssilby } 1138101896Ssilby 113942491Swpaul if (txstat & VR_TXSTAT_OWN) 114041502Swpaul break; 114141502Swpaul 114241502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 114341502Swpaul ifp->if_oerrors++; 114441502Swpaul if (txstat & VR_TXSTAT_DEFER) 114541502Swpaul ifp->if_collisions++; 114641502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 114741502Swpaul ifp->if_collisions++; 114841502Swpaul } 114941502Swpaul 115041502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 115141502Swpaul 115241502Swpaul ifp->if_opackets++; 1153168813Sphk if (cur_tx->vr_mbuf != NULL) 1154168813Sphk m_freem(cur_tx->vr_mbuf); 1155127901Sru cur_tx->vr_mbuf = NULL; 1156148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 115741502Swpaul 1158127901Sru cur_tx = cur_tx->vr_nextdesc; 115941502Swpaul } 1160127901Sru sc->vr_cdata.vr_tx_cons = cur_tx; 1161127901Sru if (cur_tx->vr_mbuf == NULL) 116296677Ssilby ifp->if_timer = 0; 116341502Swpaul} 116441502Swpaul 1165102336Salfredstatic void 1166131503Sbmsvr_tick(void *xsc) 116751432Swpaul{ 1168131503Sbms struct vr_softc *sc = xsc; 116951432Swpaul struct mii_data *mii; 117051432Swpaul 1171151911Sjhb VR_LOCK_ASSERT(sc); 1172131517Sbms 1173110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1174162315Sglebius device_printf(sc->vr_dev, "restarting\n"); 1175110131Ssilby vr_stop(sc); 1176110131Ssilby vr_reset(sc); 1177131844Sbms vr_init_locked(sc); 1178110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1179110131Ssilby } 1180110131Ssilby 118151432Swpaul mii = device_get_softc(sc->vr_miibus); 118251432Swpaul mii_tick(mii); 1183151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 118451432Swpaul} 118551432Swpaul 1186127901Sru#ifdef DEVICE_POLLING 1187127901Srustatic poll_handler_t vr_poll; 1188131844Sbmsstatic poll_handler_t vr_poll_locked; 1189127901Sru 1190102336Salfredstatic void 1191127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1192127901Sru{ 1193127901Sru struct vr_softc *sc = ifp->if_softc; 1194127901Sru 1195127901Sru VR_LOCK(sc); 1196150789Sglebius if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1197150789Sglebius vr_poll_locked(ifp, cmd, count); 1198131844Sbms VR_UNLOCK(sc); 1199131844Sbms} 1200131517Sbms 1201131844Sbmsstatic void 1202131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1203131844Sbms{ 1204131844Sbms struct vr_softc *sc = ifp->if_softc; 1205131844Sbms 1206131844Sbms VR_LOCK_ASSERT(sc); 1207131844Sbms 1208127901Sru sc->rxcycles = count; 1209127901Sru vr_rxeof(sc); 1210127901Sru vr_txeof(sc); 1211133006Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1212131844Sbms vr_start_locked(ifp); 1213127901Sru 1214131503Sbms if (cmd == POLL_AND_CHECK_STATUS) { 1215131503Sbms uint16_t status; 1216127901Sru 1217131503Sbms /* Also check status register. */ 1218127901Sru status = CSR_READ_2(sc, VR_ISR); 1219127901Sru if (status) 1220127901Sru CSR_WRITE_2(sc, VR_ISR, status); 1221127901Sru 1222127901Sru if ((status & VR_INTRS) == 0) 1223131844Sbms return; 1224127901Sru 1225127901Sru if (status & VR_ISR_RX_DROPPED) { 1226151773Sjhb if_printf(ifp, "rx packet lost\n"); 1227127901Sru ifp->if_ierrors++; 1228127901Sru } 1229127901Sru 1230127901Sru if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1231127901Sru (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1232151773Sjhb if_printf(ifp, "receive error (%04x)", status); 1233127901Sru if (status & VR_ISR_RX_NOBUF) 1234127901Sru printf(" no buffers"); 1235127901Sru if (status & VR_ISR_RX_OFLOW) 1236127901Sru printf(" overflow"); 1237127901Sru if (status & VR_ISR_RX_DROPPED) 1238127901Sru printf(" packet lost"); 1239127901Sru printf("\n"); 1240127901Sru vr_rxeoc(sc); 1241127901Sru } 1242127901Sru 1243131503Sbms if ((status & VR_ISR_BUSERR) || 1244131503Sbms (status & VR_ISR_TX_UNDERRUN)) { 1245127901Sru vr_reset(sc); 1246131844Sbms vr_init_locked(sc); 1247131518Sbms return; 1248127901Sru } 1249127901Sru 1250127901Sru if ((status & VR_ISR_UDFI) || 1251127901Sru (status & VR_ISR_TX_ABRT2) || 1252127901Sru (status & VR_ISR_TX_ABRT)) { 1253127901Sru ifp->if_oerrors++; 1254127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1255127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1256127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1257127901Sru } 1258127901Sru } 1259127901Sru } 1260127901Sru} 1261127901Sru#endif /* DEVICE_POLLING */ 1262127901Sru 1263127901Srustatic void 1264131503Sbmsvr_intr(void *arg) 126541502Swpaul{ 1266131503Sbms struct vr_softc *sc = arg; 1267147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1268131503Sbms uint16_t status; 126941502Swpaul 127067087Swpaul VR_LOCK(sc); 1271131844Sbms 1272168948Sphk if (sc->vr_suspended) { 1273136997Sbms /* 1274136997Sbms * Forcibly disable interrupts. 1275136997Sbms * XXX: Mobile VIA based platforms may need 1276136997Sbms * interrupt re-enable on resume. 1277136997Sbms */ 1278136997Sbms CSR_WRITE_2(sc, VR_IMR, 0x0000); 1279131844Sbms goto done_locked; 1280136997Sbms } 1281131844Sbms 1282127901Sru#ifdef DEVICE_POLLING 1283150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1284131844Sbms goto done_locked; 1285150789Sglebius#endif 1286131844Sbms 1287131844Sbms /* Suppress unwanted interrupts. */ 128841502Swpaul if (!(ifp->if_flags & IFF_UP)) { 128941502Swpaul vr_stop(sc); 1290131844Sbms goto done_locked; 129141502Swpaul } 129241502Swpaul 129341502Swpaul /* Disable interrupts. */ 129441502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 129541502Swpaul 129641502Swpaul for (;;) { 129741502Swpaul status = CSR_READ_2(sc, VR_ISR); 1298168813Sphk 129941502Swpaul if (status) 130041502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 130141502Swpaul 130241502Swpaul if ((status & VR_INTRS) == 0) 130341502Swpaul break; 130441502Swpaul 130541502Swpaul if (status & VR_ISR_RX_OK) 130641502Swpaul vr_rxeof(sc); 130741502Swpaul 1308110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1309162315Sglebius device_printf(sc->vr_dev, "rx packet lost\n"); 1310110131Ssilby ifp->if_ierrors++; 1311131503Sbms } 1312110131Ssilby 131341502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1314110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1315162315Sglebius device_printf(sc->vr_dev, "receive error (%04x)", status); 1316110131Ssilby if (status & VR_ISR_RX_NOBUF) 1317110131Ssilby printf(" no buffers"); 1318110131Ssilby if (status & VR_ISR_RX_OFLOW) 1319110131Ssilby printf(" overflow"); 1320110131Ssilby if (status & VR_ISR_RX_DROPPED) 1321110131Ssilby printf(" packet lost"); 1322110131Ssilby printf("\n"); 132341502Swpaul vr_rxeoc(sc); 132441502Swpaul } 132541502Swpaul 1326101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1327101896Ssilby vr_reset(sc); 1328131844Sbms vr_init_locked(sc); 1329101896Ssilby break; 133041502Swpaul } 133141502Swpaul 1332101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1333101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 133441502Swpaul vr_txeof(sc); 1335101896Ssilby if ((status & VR_ISR_UDFI) || 1336101896Ssilby (status & VR_ISR_TX_ABRT2) || 1337101896Ssilby (status & VR_ISR_TX_ABRT)) { 1338101896Ssilby ifp->if_oerrors++; 1339127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1340131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1341131503Sbms VR_CMD_TX_ON); 1342131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1343131503Sbms VR_CMD_TX_GO); 1344101896Ssilby } 1345127901Sru } 134641502Swpaul } 134741502Swpaul } 134841502Swpaul 134941502Swpaul /* Re-enable interrupts. */ 135041502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 135141502Swpaul 1352132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1353131844Sbms vr_start_locked(ifp); 1354131844Sbms 1355131844Sbmsdone_locked: 1356131844Sbms VR_UNLOCK(sc); 135741502Swpaul} 135841502Swpaul 135941502Swpaul/* 136041502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 136141502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 136241502Swpaul * copy of the pointers since the transmit list fragment pointers are 136341502Swpaul * physical addresses. 136441502Swpaul */ 136541502Swpaul 1366102336Salfredstatic void 1367131503Sbmsvr_start(struct ifnet *ifp) 136841502Swpaul{ 1369131518Sbms struct vr_softc *sc = ifp->if_softc; 1370131844Sbms 1371131844Sbms VR_LOCK(sc); 1372131844Sbms vr_start_locked(ifp); 1373131844Sbms VR_UNLOCK(sc); 1374131844Sbms} 1375131844Sbms 1376131844Sbmsstatic void 1377131844Sbmsvr_start_locked(struct ifnet *ifp) 1378131844Sbms{ 1379131844Sbms struct vr_softc *sc = ifp->if_softc; 1380168813Sphk struct mbuf *m, *m_head; 1381168813Sphk struct vr_chain *cur_tx, *n_tx; 1382168813Sphk struct vr_desc *f = NULL; 1383168813Sphk uint32_t cval; 138441502Swpaul 1385148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 1386127901Sru return; 1387127901Sru 1388168813Sphk for (cur_tx = sc->vr_cdata.vr_tx_prod; 1389168813Sphk cur_tx->vr_nextdesc != sc->vr_cdata.vr_tx_cons; ) { 1390132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 139141502Swpaul if (m_head == NULL) 139241502Swpaul break; 139341502Swpaul 1394168813Sphk VR_LOCK_ASSERT(sc); 1395168813Sphk /* 1396168813Sphk * Some VIA Rhine wants packet buffers to be longword 1397168813Sphk * aligned, but very often our mbufs aren't. Rather than 1398168813Sphk * waste time trying to decide when to copy and when not 1399168813Sphk * to copy, just do it all the time. 1400168813Sphk */ 1401168827Sphk if (sc->vr_quirks & VR_Q_NEEDALIGN) { 1402168813Sphk m = m_defrag(m_head, M_DONTWAIT); 1403168813Sphk if (m == NULL) { 1404168813Sphk /* Rollback, send what we were able to encap. */ 1405168813Sphk IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1406168813Sphk break; 1407168813Sphk } 1408168813Sphk m_head = m; 1409168813Sphk } 141041502Swpaul 141141502Swpaul /* 1412168813Sphk * The Rhine chip doesn't auto-pad, so we have to make 1413168813Sphk * sure to pad short frames out to the minimum frame length 1414168813Sphk * ourselves. 141541502Swpaul */ 1416168813Sphk if (m_head->m_pkthdr.len < VR_MIN_FRAMELEN) { 1417168813Sphk if (m_head->m_next != NULL) 1418168813Sphk m_head = m_defrag(m_head, M_DONTWAIT); 1419168813Sphk m_head->m_pkthdr.len += VR_MIN_FRAMELEN - m_head->m_len; 1420168813Sphk m_head->m_len = m_head->m_pkthdr.len; 1421168813Sphk /* XXX: bzero the padding bytes */ 1422168813Sphk } 142351583Swpaul 1424168813Sphk n_tx = cur_tx; 1425168813Sphk for (m = m_head; m != NULL; m = m->m_next) { 1426168813Sphk if (m->m_len == 0) 1427168813Sphk continue; 1428168813Sphk if (n_tx->vr_nextdesc == sc->vr_cdata.vr_tx_cons) { 1429168813Sphk IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1430168813Sphk sc->vr_cdata.vr_tx_prod = cur_tx; 1431168813Sphk return; 1432168813Sphk } 1433168813Sphk KASSERT(n_tx->vr_mbuf == NULL, ("if_vr_tx overrun")); 1434168813Sphk 1435168813Sphk f = n_tx->vr_ptr; 1436168813Sphk f->vr_data = vtophys(mtod(m, caddr_t)); 1437168813Sphk cval = m->m_len; 1438168813Sphk cval |= VR_TXCTL_TLINK; 1439168827Sphk 1440168827Sphk if ((ifp->if_capenable & IFCAP_TXCSUM) && 1441168827Sphk m_head->m_pkthdr.csum_flags) { 1442168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_IP) 1443168827Sphk cval |= VR_TXCTL_IPCSUM; 1444168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 1445168827Sphk cval |= VR_TXCTL_TCPCSUM; 1446168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 1447168827Sphk cval |= VR_TXCTL_UDPCSUM; 1448168827Sphk } 1449168827Sphk 1450168813Sphk if (m == m_head) 1451168813Sphk cval |= VR_TXCTL_FIRSTFRAG; 1452168813Sphk f->vr_ctl = cval; 1453168813Sphk f->vr_status = 0; 1454168813Sphk n_tx = n_tx->vr_nextdesc; 1455168813Sphk } 145641502Swpaul 1457168946Sphk KASSERT(f != NULL, ("if_vr: no packet processed")); 1458168813Sphk f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 1459168813Sphk cur_tx->vr_mbuf = m_head; 1460168813Sphk atomic_set_acq_32(&VR_TXOWN(cur_tx), VR_TXSTAT_OWN); 1461168813Sphk 1462127901Sru /* Tell the chip to start transmitting. */ 1463131517Sbms VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO); 146441526Swpaul 1465168813Sphk ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1466127901Sru ifp->if_timer = 5; 146741502Swpaul 1468168813Sphk /* 1469168813Sphk * If there's a BPF listener, bounce a copy of this frame 1470168813Sphk * to him. 1471168813Sphk */ 1472168813Sphk BPF_MTAP(ifp, m_head); 1473168813Sphk cur_tx = n_tx; 1474127901Sru } 1475168813Sphk sc->vr_cdata.vr_tx_prod = cur_tx; 1476131844Sbms} 147741502Swpaul 1478131844Sbmsstatic void 1479131844Sbmsvr_init(void *xsc) 1480131844Sbms{ 1481131844Sbms struct vr_softc *sc = xsc; 1482131844Sbms 1483131844Sbms VR_LOCK(sc); 1484131844Sbms vr_init_locked(sc); 148567087Swpaul VR_UNLOCK(sc); 148641502Swpaul} 148741502Swpaul 1488102336Salfredstatic void 1489131844Sbmsvr_init_locked(struct vr_softc *sc) 149041502Swpaul{ 1491147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 149251432Swpaul struct mii_data *mii; 149373963Swpaul int i; 149441502Swpaul 1495131844Sbms VR_LOCK_ASSERT(sc); 149641502Swpaul 149751432Swpaul mii = device_get_softc(sc->vr_miibus); 149841502Swpaul 1499131503Sbms /* Cancel pending I/O and free all RX/TX buffers. */ 150041502Swpaul vr_stop(sc); 150141502Swpaul vr_reset(sc); 150241502Swpaul 1503131503Sbms /* Set our station address. */ 150473963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 1505152315Sru CSR_WRITE_1(sc, VR_PAR0 + i, IF_LLADDR(sc->vr_ifp)[i]); 1506131503Sbms 1507131503Sbms /* Set DMA size. */ 1508101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1509101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 151073963Swpaul 1511131503Sbms /* 1512101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1513101108Ssilby * so we must set both. 1514101108Ssilby */ 1515101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1516110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1517101108Ssilby 1518101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1519101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1520101108Ssilby 152141502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1522110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 152341502Swpaul 152441502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 152541502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 152641502Swpaul 152741502Swpaul /* Init circular RX list. */ 152841502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 1529162315Sglebius device_printf(sc->vr_dev, 1530151773Sjhb "initialization failed: no memory for rx buffers\n"); 153141502Swpaul vr_stop(sc); 153241502Swpaul return; 153341502Swpaul } 153441502Swpaul 1535131503Sbms /* Init tx descriptors. */ 153641502Swpaul vr_list_tx_init(sc); 153741502Swpaul 153841502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 153941502Swpaul if (ifp->if_flags & IFF_PROMISC) 154041502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 154141502Swpaul else 154241502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 154341502Swpaul 154441502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 154541502Swpaul if (ifp->if_flags & IFF_BROADCAST) 154641502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 154741502Swpaul else 154841502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 154941502Swpaul 155041502Swpaul /* 155141502Swpaul * Program the multicast filter, if necessary. 155241502Swpaul */ 155341502Swpaul vr_setmulti(sc); 155441502Swpaul 155541502Swpaul /* 155641502Swpaul * Load the address of the RX list. 155741502Swpaul */ 155841502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 155941502Swpaul 156041502Swpaul /* Enable receiver and transmitter. */ 156141502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 156241502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 156341502Swpaul VR_CMD_RX_GO); 156441502Swpaul 156541502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 156641502Swpaul 1567127901Sru CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 1568127901Sru#ifdef DEVICE_POLLING 156941502Swpaul /* 1570127901Sru * Disable interrupts if we are polling. 1571127901Sru */ 1572150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1573127901Sru CSR_WRITE_2(sc, VR_IMR, 0); 1574131503Sbms else 1575150789Sglebius#endif 1576127901Sru /* 157741502Swpaul * Enable interrupts. 157841502Swpaul */ 157941502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 158041502Swpaul 158151432Swpaul mii_mediachg(mii); 158241502Swpaul 1583148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1584148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 158541502Swpaul 1586151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 158741502Swpaul} 158841502Swpaul 158941502Swpaul/* 159041502Swpaul * Set media options. 159141502Swpaul */ 1592102336Salfredstatic int 1593131503Sbmsvr_ifmedia_upd(struct ifnet *ifp) 159441502Swpaul{ 1595131503Sbms struct vr_softc *sc = ifp->if_softc; 159641502Swpaul 159751432Swpaul if (ifp->if_flags & IFF_UP) 159851432Swpaul vr_init(sc); 159941502Swpaul 1600131503Sbms return (0); 160141502Swpaul} 160241502Swpaul 160341502Swpaul/* 160441502Swpaul * Report current media status. 160541502Swpaul */ 1606102336Salfredstatic void 1607131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 160841502Swpaul{ 1609131518Sbms struct vr_softc *sc = ifp->if_softc; 161051432Swpaul struct mii_data *mii; 161141502Swpaul 161251432Swpaul mii = device_get_softc(sc->vr_miibus); 1613133468Sscottl VR_LOCK(sc); 161451432Swpaul mii_pollstat(mii); 1615133468Sscottl VR_UNLOCK(sc); 161651432Swpaul ifmr->ifm_active = mii->mii_media_active; 161751432Swpaul ifmr->ifm_status = mii->mii_media_status; 161841502Swpaul} 161941502Swpaul 1620102336Salfredstatic int 1621131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 162241502Swpaul{ 162341502Swpaul struct vr_softc *sc = ifp->if_softc; 162441502Swpaul struct ifreq *ifr = (struct ifreq *) data; 162551432Swpaul struct mii_data *mii; 162667087Swpaul int error = 0; 162741502Swpaul 1628131503Sbms switch (command) { 162941502Swpaul case SIOCSIFFLAGS: 1630131844Sbms VR_LOCK(sc); 163141502Swpaul if (ifp->if_flags & IFF_UP) { 1632131844Sbms vr_init_locked(sc); 163341502Swpaul } else { 1634148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 163541502Swpaul vr_stop(sc); 163641502Swpaul } 1637131844Sbms VR_UNLOCK(sc); 163841502Swpaul error = 0; 163941502Swpaul break; 164041502Swpaul case SIOCADDMULTI: 164141502Swpaul case SIOCDELMULTI: 1642131518Sbms VR_LOCK(sc); 164341502Swpaul vr_setmulti(sc); 1644131518Sbms VR_UNLOCK(sc); 164541502Swpaul error = 0; 164641502Swpaul break; 164741502Swpaul case SIOCGIFMEDIA: 164841502Swpaul case SIOCSIFMEDIA: 164951432Swpaul mii = device_get_softc(sc->vr_miibus); 165051432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 165141502Swpaul break; 1652128118Sru case SIOCSIFCAP: 1653150789Sglebius#ifdef DEVICE_POLLING 1654150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 1655150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 1656150789Sglebius error = ether_poll_register(vr_poll, ifp); 1657150789Sglebius if (error) 1658150789Sglebius return(error); 1659150789Sglebius VR_LOCK(sc); 1660150789Sglebius /* Disable interrupts */ 1661150789Sglebius CSR_WRITE_2(sc, VR_IMR, 0x0000); 1662150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 1663150789Sglebius VR_UNLOCK(sc); 1664150789Sglebius return (error); 1665150789Sglebius 1666150789Sglebius } 1667150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 1668150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 1669150789Sglebius error = ether_poll_deregister(ifp); 1670150789Sglebius /* Enable interrupts. */ 1671150789Sglebius VR_LOCK(sc); 1672150789Sglebius CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 1673150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 1674150789Sglebius VR_UNLOCK(sc); 1675150789Sglebius return (error); 1676150789Sglebius } 1677150789Sglebius#endif /* DEVICE_POLLING */ 1678168827Sphk ifp->if_capenable = ifr->ifr_reqcap; 1679168827Sphk if (ifp->if_capenable & IFCAP_TXCSUM) 1680168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 1681168827Sphk else 1682168827Sphk ifp->if_hwassist = 0; 1683128118Sru break; 168441502Swpaul default: 1685106936Ssam error = ether_ioctl(ifp, command, data); 168641502Swpaul break; 168741502Swpaul } 168841502Swpaul 1689131503Sbms return (error); 169041502Swpaul} 169141502Swpaul 1692102336Salfredstatic void 1693131503Sbmsvr_watchdog(struct ifnet *ifp) 169441502Swpaul{ 1695131518Sbms struct vr_softc *sc = ifp->if_softc; 169641502Swpaul 169767087Swpaul VR_LOCK(sc); 1698131844Sbms 169941502Swpaul ifp->if_oerrors++; 1700151773Sjhb if_printf(ifp, "watchdog timeout\n"); 170141502Swpaul 170241502Swpaul vr_stop(sc); 170341502Swpaul vr_reset(sc); 1704131844Sbms vr_init_locked(sc); 1705131518Sbms 1706132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1707131844Sbms vr_start_locked(ifp); 1708131844Sbms 1709131844Sbms VR_UNLOCK(sc); 171041502Swpaul} 171141502Swpaul 171241502Swpaul/* 171341502Swpaul * Stop the adapter and free any mbufs allocated to the 171441502Swpaul * RX and TX lists. 171541502Swpaul */ 1716102336Salfredstatic void 1717131503Sbmsvr_stop(struct vr_softc *sc) 171841502Swpaul{ 1719131503Sbms register int i; 1720131503Sbms struct ifnet *ifp; 172141502Swpaul 1722131518Sbms VR_LOCK_ASSERT(sc); 172367087Swpaul 1724147256Sbrooks ifp = sc->vr_ifp; 172541502Swpaul ifp->if_timer = 0; 172641502Swpaul 1727151911Sjhb callout_stop(&sc->vr_stat_callout); 1728148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 172951432Swpaul 173041502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 173141502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 173241502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 173341502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 173441502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 173541502Swpaul 173641502Swpaul /* 173741502Swpaul * Free data in the RX lists. 173841502Swpaul */ 173941502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 174041502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 174141502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 174241502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 174341502Swpaul } 174441502Swpaul } 174541502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 1746131517Sbms sizeof(sc->vr_ldata->vr_rx_list)); 174741502Swpaul 174841502Swpaul /* 174941502Swpaul * Free the TX list buffers. 175041502Swpaul */ 175141502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 175241502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 175341502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 175441502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 175541502Swpaul } 175641502Swpaul } 175741502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 1758131517Sbms sizeof(sc->vr_ldata->vr_tx_list)); 175941502Swpaul} 176041502Swpaul 176141502Swpaul/* 176241502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 176341502Swpaul * get confused by errant DMAs when rebooting. 176441502Swpaul */ 1765102336Salfredstatic void 1766131503Sbmsvr_shutdown(device_t dev) 176741502Swpaul{ 176841502Swpaul 1769136696Sbms vr_detach(dev); 177041502Swpaul} 1771