if_vr.c revision 148654
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 148654 2005-08-03 00:18:35Z rwatson $"); 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 6341502Swpaul#include <sys/param.h> 6441502Swpaul#include <sys/systm.h> 6541502Swpaul#include <sys/sockio.h> 6641502Swpaul#include <sys/mbuf.h> 6741502Swpaul#include <sys/malloc.h> 6841502Swpaul#include <sys/kernel.h> 69129878Sphk#include <sys/module.h> 7041502Swpaul#include <sys/socket.h> 7141502Swpaul 7241502Swpaul#include <net/if.h> 7341502Swpaul#include <net/if_arp.h> 7441502Swpaul#include <net/ethernet.h> 7541502Swpaul#include <net/if_dl.h> 7641502Swpaul#include <net/if_media.h> 77147256Sbrooks#include <net/if_types.h> 7841502Swpaul 7941502Swpaul#include <net/bpf.h> 8041502Swpaul 81131503Sbms#include <vm/vm.h> /* for vtophys */ 82131503Sbms#include <vm/pmap.h> /* for vtophys */ 8341502Swpaul#include <machine/bus.h> 8449610Swpaul#include <machine/resource.h> 8549610Swpaul#include <sys/bus.h> 8649610Swpaul#include <sys/rman.h> 8741502Swpaul 8851432Swpaul#include <dev/mii/mii.h> 8951432Swpaul#include <dev/mii/miivar.h> 9051432Swpaul 91119288Simp#include <dev/pci/pcireg.h> 92119288Simp#include <dev/pci/pcivar.h> 9341502Swpaul 9441502Swpaul#define VR_USEIOSPACE 9541502Swpaul 9641502Swpaul#include <pci/if_vrreg.h> 9741502Swpaul 98113506SmdoddMODULE_DEPEND(vr, pci, 1, 1, 1); 99113506SmdoddMODULE_DEPEND(vr, ether, 1, 1, 1); 10059758SpeterMODULE_DEPEND(vr, miibus, 1, 1, 1); 10159758Speter 10251432Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 10351432Swpaul#include "miibus_if.h" 10451432Swpaul 105110168Ssilby#undef VR_USESWSHIFT 106110168Ssilby 10741502Swpaul/* 10841502Swpaul * Various supported device vendors/types and their names. 10941502Swpaul */ 11041502Swpaulstatic struct vr_type vr_devs[] = { 11141502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE, 11241502Swpaul "VIA VT3043 Rhine I 10/100BaseTX" }, 11341502Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 11441502Swpaul "VIA VT86C100A Rhine II 10/100BaseTX" }, 11562653Swpaul { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 11662653Swpaul "VIA VT6102 Rhine II 10/100BaseTX" }, 117110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III, 118110170Ssilby "VIA VT6105 Rhine III 10/100BaseTX" }, 119110170Ssilby { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, 120110170Ssilby "VIA VT6105M Rhine III 10/100BaseTX" }, 12144238Swpaul { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 12244238Swpaul "Delta Electronics Rhine II 10/100BaseTX" }, 12344238Swpaul { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 12444238Swpaul "Addtron Technology Rhine II 10/100BaseTX" }, 12541502Swpaul { 0, 0, NULL } 12641502Swpaul}; 12741502Swpaul 128142407Simpstatic int vr_probe(device_t); 129142407Simpstatic int vr_attach(device_t); 130142407Simpstatic int vr_detach(device_t); 13141502Swpaul 132142407Simpstatic int vr_newbuf(struct vr_softc *, struct vr_chain_onefrag *, 133142407Simp struct mbuf *); 134142407Simpstatic int vr_encap(struct vr_softc *, struct vr_chain *, struct mbuf * ); 13541502Swpaul 136142407Simpstatic void vr_rxeof(struct vr_softc *); 137142407Simpstatic void vr_rxeoc(struct vr_softc *); 138142407Simpstatic void vr_txeof(struct vr_softc *); 139142407Simpstatic void vr_tick(void *); 140142407Simpstatic void vr_intr(void *); 141142407Simpstatic void vr_start(struct ifnet *); 142142407Simpstatic void vr_start_locked(struct ifnet *); 143142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t); 144142407Simpstatic void vr_init(void *); 145142407Simpstatic void vr_init_locked(struct vr_softc *); 146142407Simpstatic void vr_stop(struct vr_softc *); 147142407Simpstatic void vr_watchdog(struct ifnet *); 148142407Simpstatic void vr_shutdown(device_t); 149142407Simpstatic int vr_ifmedia_upd(struct ifnet *); 150142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *); 15141502Swpaul 152110168Ssilby#ifdef VR_USESWSHIFT 153142407Simpstatic void vr_mii_sync(struct vr_softc *); 154142407Simpstatic void vr_mii_send(struct vr_softc *, uint32_t, int); 155110168Ssilby#endif 156142407Simpstatic int vr_mii_readreg(struct vr_softc *, struct vr_mii_frame *); 157142407Simpstatic int vr_mii_writereg(struct vr_softc *, struct vr_mii_frame *); 158142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t); 159142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t); 160142407Simpstatic void vr_miibus_statchg(device_t); 16141502Swpaul 162142407Simpstatic void vr_setcfg(struct vr_softc *, int); 163142407Simpstatic void vr_setmulti(struct vr_softc *); 164142407Simpstatic void vr_reset(struct vr_softc *); 165142407Simpstatic int vr_list_rx_init(struct vr_softc *); 166142407Simpstatic int vr_list_tx_init(struct vr_softc *); 16741502Swpaul 16849610Swpaul#ifdef VR_USEIOSPACE 16949610Swpaul#define VR_RES SYS_RES_IOPORT 17049610Swpaul#define VR_RID VR_PCI_LOIO 17149610Swpaul#else 17249610Swpaul#define VR_RES SYS_RES_MEMORY 17349610Swpaul#define VR_RID VR_PCI_LOMEM 17449610Swpaul#endif 17549610Swpaul 17649610Swpaulstatic device_method_t vr_methods[] = { 17749610Swpaul /* Device interface */ 17849610Swpaul DEVMETHOD(device_probe, vr_probe), 17949610Swpaul DEVMETHOD(device_attach, vr_attach), 18049610Swpaul DEVMETHOD(device_detach, vr_detach), 18149610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 18251432Swpaul 18351432Swpaul /* bus interface */ 18451432Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 18551432Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 18651432Swpaul 18751432Swpaul /* MII interface */ 18851432Swpaul DEVMETHOD(miibus_readreg, vr_miibus_readreg), 18951432Swpaul DEVMETHOD(miibus_writereg, vr_miibus_writereg), 19051432Swpaul DEVMETHOD(miibus_statchg, vr_miibus_statchg), 19151432Swpaul 19249610Swpaul { 0, 0 } 19349610Swpaul}; 19449610Swpaul 19549610Swpaulstatic driver_t vr_driver = { 19651455Swpaul "vr", 19749610Swpaul vr_methods, 19849610Swpaul sizeof(struct vr_softc) 19949610Swpaul}; 20049610Swpaul 20149610Swpaulstatic devclass_t vr_devclass; 20249610Swpaul 203113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0); 20451473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0); 20549610Swpaul 20641502Swpaul#define VR_SETBIT(sc, reg, x) \ 20741502Swpaul CSR_WRITE_1(sc, reg, \ 208105221Sphk CSR_READ_1(sc, reg) | (x)) 20941502Swpaul 21041502Swpaul#define VR_CLRBIT(sc, reg, x) \ 21141502Swpaul CSR_WRITE_1(sc, reg, \ 212105221Sphk CSR_READ_1(sc, reg) & ~(x)) 21341502Swpaul 21441502Swpaul#define VR_SETBIT16(sc, reg, x) \ 21541502Swpaul CSR_WRITE_2(sc, reg, \ 216105221Sphk CSR_READ_2(sc, reg) | (x)) 21741502Swpaul 21841502Swpaul#define VR_CLRBIT16(sc, reg, x) \ 21941502Swpaul CSR_WRITE_2(sc, reg, \ 220105221Sphk CSR_READ_2(sc, reg) & ~(x)) 22141502Swpaul 22241502Swpaul#define VR_SETBIT32(sc, reg, x) \ 22341502Swpaul CSR_WRITE_4(sc, reg, \ 224105221Sphk CSR_READ_4(sc, reg) | (x)) 22541502Swpaul 22641502Swpaul#define VR_CLRBIT32(sc, reg, x) \ 22741502Swpaul CSR_WRITE_4(sc, reg, \ 228105221Sphk CSR_READ_4(sc, reg) & ~(x)) 22941502Swpaul 23041502Swpaul#define SIO_SET(x) \ 23141502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 232105221Sphk CSR_READ_1(sc, VR_MIICMD) | (x)) 23341502Swpaul 23441502Swpaul#define SIO_CLR(x) \ 23541502Swpaul CSR_WRITE_1(sc, VR_MIICMD, \ 236105221Sphk CSR_READ_1(sc, VR_MIICMD) & ~(x)) 23741502Swpaul 238110168Ssilby#ifdef VR_USESWSHIFT 23941502Swpaul/* 24041502Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 24141502Swpaul */ 242102336Salfredstatic void 243131503Sbmsvr_mii_sync(struct vr_softc *sc) 24441502Swpaul{ 245131503Sbms register int i; 24641502Swpaul 24741502Swpaul SIO_SET(VR_MIICMD_DIR|VR_MIICMD_DATAIN); 24841502Swpaul 24941502Swpaul for (i = 0; i < 32; i++) { 25041502Swpaul SIO_SET(VR_MIICMD_CLK); 25141502Swpaul DELAY(1); 25241502Swpaul SIO_CLR(VR_MIICMD_CLK); 25341502Swpaul DELAY(1); 25441502Swpaul } 25541502Swpaul} 25641502Swpaul 25741502Swpaul/* 25841502Swpaul * Clock a series of bits through the MII. 25941502Swpaul */ 260102336Salfredstatic void 261131503Sbmsvr_mii_send(struct vr_softc *sc, uint32_t bits, int cnt) 26241502Swpaul{ 263131503Sbms int i; 26441502Swpaul 26541502Swpaul SIO_CLR(VR_MIICMD_CLK); 26641502Swpaul 26741502Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 268131503Sbms if (bits & i) { 26941502Swpaul SIO_SET(VR_MIICMD_DATAIN); 270131503Sbms } else { 27141502Swpaul SIO_CLR(VR_MIICMD_DATAIN); 272131503Sbms } 27341502Swpaul DELAY(1); 27441502Swpaul SIO_CLR(VR_MIICMD_CLK); 27541502Swpaul DELAY(1); 27641502Swpaul SIO_SET(VR_MIICMD_CLK); 27741502Swpaul } 27841502Swpaul} 279110168Ssilby#endif 28041502Swpaul 28141502Swpaul/* 28241502Swpaul * Read an PHY register through the MII. 28341502Swpaul */ 284102336Salfredstatic int 285131503Sbmsvr_mii_readreg(struct vr_softc *sc, struct vr_mii_frame *frame) 286131503Sbms#ifdef VR_USESWSHIFT 28741502Swpaul{ 288131503Sbms int i, ack; 28941502Swpaul 290131503Sbms /* Set up frame for RX. */ 29141502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 29241502Swpaul frame->mii_opcode = VR_MII_READOP; 29341502Swpaul frame->mii_turnaround = 0; 29441502Swpaul frame->mii_data = 0; 295131503Sbms 29641502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 29741502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 29841502Swpaul 299131503Sbms /* Turn on data xmit. */ 30041502Swpaul SIO_SET(VR_MIICMD_DIR); 30141502Swpaul 30241502Swpaul vr_mii_sync(sc); 30341502Swpaul 304131503Sbms /* Send command/address info. */ 30541502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 30641502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 30741502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 30841502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 30941502Swpaul 310131503Sbms /* Idle bit. */ 31141502Swpaul SIO_CLR((VR_MIICMD_CLK|VR_MIICMD_DATAIN)); 31241502Swpaul DELAY(1); 31341502Swpaul SIO_SET(VR_MIICMD_CLK); 31441502Swpaul DELAY(1); 31541502Swpaul 31641502Swpaul /* Turn off xmit. */ 31741502Swpaul SIO_CLR(VR_MIICMD_DIR); 31841502Swpaul 31941502Swpaul /* Check for ack */ 32041502Swpaul SIO_CLR(VR_MIICMD_CLK); 32141502Swpaul DELAY(1); 322109058Smbr ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; 32341502Swpaul SIO_SET(VR_MIICMD_CLK); 32441502Swpaul DELAY(1); 32541502Swpaul 32641502Swpaul /* 32741502Swpaul * Now try reading data bits. If the ack failed, we still 32841502Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 32941502Swpaul */ 33041502Swpaul if (ack) { 33141502Swpaul for(i = 0; i < 16; i++) { 33241502Swpaul SIO_CLR(VR_MIICMD_CLK); 33341502Swpaul DELAY(1); 33441502Swpaul SIO_SET(VR_MIICMD_CLK); 33541502Swpaul DELAY(1); 33641502Swpaul } 33741502Swpaul goto fail; 33841502Swpaul } 33941502Swpaul 34041502Swpaul for (i = 0x8000; i; i >>= 1) { 34141502Swpaul SIO_CLR(VR_MIICMD_CLK); 34241502Swpaul DELAY(1); 34341502Swpaul if (!ack) { 34441502Swpaul if (CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT) 34541502Swpaul frame->mii_data |= i; 34641502Swpaul DELAY(1); 34741502Swpaul } 34841502Swpaul SIO_SET(VR_MIICMD_CLK); 34941502Swpaul DELAY(1); 35041502Swpaul } 35141502Swpaul 35241502Swpaulfail: 35341502Swpaul SIO_CLR(VR_MIICMD_CLK); 35441502Swpaul DELAY(1); 35541502Swpaul SIO_SET(VR_MIICMD_CLK); 35641502Swpaul DELAY(1); 35741502Swpaul 35841502Swpaul if (ack) 359131503Sbms return (1); 360131503Sbms return (0); 36141502Swpaul} 362110168Ssilby#else 363110168Ssilby{ 364131518Sbms int i; 36541502Swpaul 366131503Sbms /* Set the PHY address. */ 367110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 368110168Ssilby frame->mii_phyaddr); 369110168Ssilby 370131503Sbms /* Set the register address. */ 371110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 372110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB); 373131503Sbms 374110168Ssilby for (i = 0; i < 10000; i++) { 375110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0) 376110168Ssilby break; 377110168Ssilby DELAY(1); 378110168Ssilby } 379110168Ssilby frame->mii_data = CSR_READ_2(sc, VR_MIIDATA); 380110168Ssilby 381131503Sbms return (0); 382110168Ssilby} 383110168Ssilby#endif 384110168Ssilby 385110168Ssilby 38641502Swpaul/* 38741502Swpaul * Write to a PHY register through the MII. 38841502Swpaul */ 389102336Salfredstatic int 390131503Sbmsvr_mii_writereg(struct vr_softc *sc, struct vr_mii_frame *frame) 391131503Sbms#ifdef VR_USESWSHIFT 39241502Swpaul{ 39341502Swpaul CSR_WRITE_1(sc, VR_MIICMD, 0); 39441502Swpaul VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_DIRECTPGM); 39541502Swpaul 396131503Sbms /* Set up frame for TX. */ 39741502Swpaul frame->mii_stdelim = VR_MII_STARTDELIM; 39841502Swpaul frame->mii_opcode = VR_MII_WRITEOP; 39941502Swpaul frame->mii_turnaround = VR_MII_TURNAROUND; 400131503Sbms 401131503Sbms /* Turn on data output. */ 40241502Swpaul SIO_SET(VR_MIICMD_DIR); 40341502Swpaul 40441502Swpaul vr_mii_sync(sc); 40541502Swpaul 40641502Swpaul vr_mii_send(sc, frame->mii_stdelim, 2); 40741502Swpaul vr_mii_send(sc, frame->mii_opcode, 2); 40841502Swpaul vr_mii_send(sc, frame->mii_phyaddr, 5); 40941502Swpaul vr_mii_send(sc, frame->mii_regaddr, 5); 41041502Swpaul vr_mii_send(sc, frame->mii_turnaround, 2); 41141502Swpaul vr_mii_send(sc, frame->mii_data, 16); 41241502Swpaul 41341502Swpaul /* Idle bit. */ 41441502Swpaul SIO_SET(VR_MIICMD_CLK); 41541502Swpaul DELAY(1); 41641502Swpaul SIO_CLR(VR_MIICMD_CLK); 41741502Swpaul DELAY(1); 41841502Swpaul 419131503Sbms /* Turn off xmit. */ 42041502Swpaul SIO_CLR(VR_MIICMD_DIR); 42141502Swpaul 422131503Sbms return (0); 42341502Swpaul} 424110168Ssilby#else 425110168Ssilby{ 426131518Sbms int i; 42741502Swpaul 428131503Sbms /* Set the PHY address. */ 429110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 430131503Sbms frame->mii_phyaddr); 431110168Ssilby 432131503Sbms /* Set the register address and data to write. */ 433110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 434110168Ssilby CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data); 435110168Ssilby 436110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB); 437110168Ssilby 438110168Ssilby for (i = 0; i < 10000; i++) { 439110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0) 440110168Ssilby break; 441110168Ssilby DELAY(1); 442110168Ssilby } 443110168Ssilby 444131503Sbms return (0); 445110168Ssilby} 446110168Ssilby#endif 447110168Ssilby 448102336Salfredstatic int 449131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg) 45051432Swpaul{ 45141502Swpaul struct vr_mii_frame frame; 452131503Sbms struct vr_softc *sc = device_get_softc(dev); 45341502Swpaul 454110168Ssilby switch (sc->vr_revid) { 455131503Sbms case REV_ID_VT6102_APOLLO: 456131518Sbms if (phy != 1) { 457131518Sbms frame.mii_data = 0; 458131518Sbms goto out; 459131518Sbms } 460131503Sbms default: 461131503Sbms break; 462131503Sbms } 463110168Ssilby 46441502Swpaul bzero((char *)&frame, sizeof(frame)); 46551432Swpaul frame.mii_phyaddr = phy; 46641502Swpaul frame.mii_regaddr = reg; 46741502Swpaul vr_mii_readreg(sc, &frame); 46841502Swpaul 469131518Sbmsout: 470131503Sbms return (frame.mii_data); 47141502Swpaul} 47241502Swpaul 473102336Salfredstatic int 474131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data) 47551432Swpaul{ 47641502Swpaul struct vr_mii_frame frame; 477131503Sbms struct vr_softc *sc = device_get_softc(dev); 47841502Swpaul 479110168Ssilby switch (sc->vr_revid) { 480131503Sbms case REV_ID_VT6102_APOLLO: 481131503Sbms if (phy != 1) 482131503Sbms return (0); 483131503Sbms default: 484131503Sbms break; 485131503Sbms } 486110168Ssilby 48741502Swpaul bzero((char *)&frame, sizeof(frame)); 48851432Swpaul frame.mii_phyaddr = phy; 48941502Swpaul frame.mii_regaddr = reg; 49041502Swpaul frame.mii_data = data; 49141502Swpaul vr_mii_writereg(sc, &frame); 49241502Swpaul 493131503Sbms return (0); 49451432Swpaul} 49551432Swpaul 496102336Salfredstatic void 497131503Sbmsvr_miibus_statchg(device_t dev) 49851432Swpaul{ 49951432Swpaul struct mii_data *mii; 500131503Sbms struct vr_softc *sc = device_get_softc(dev); 50151432Swpaul 50251432Swpaul mii = device_get_softc(sc->vr_miibus); 50351432Swpaul vr_setcfg(sc, mii->mii_media_active); 50441502Swpaul} 50541502Swpaul 50641502Swpaul/* 50741502Swpaul * Program the 64-bit multicast hash filter. 50841502Swpaul */ 509102336Salfredstatic void 510131503Sbmsvr_setmulti(struct vr_softc *sc) 51141502Swpaul{ 512147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 51341502Swpaul int h = 0; 514131503Sbms uint32_t hashes[2] = { 0, 0 }; 51541502Swpaul struct ifmultiaddr *ifma; 516131503Sbms uint8_t rxfilt; 51741502Swpaul int mcnt = 0; 51841502Swpaul 519131518Sbms VR_LOCK_ASSERT(sc); 52041502Swpaul 52141502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 52241502Swpaul 52341502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 52441502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 52541502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 52641502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 52741502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 52841502Swpaul return; 52941502Swpaul } 53041502Swpaul 531131503Sbms /* First, zero out all the existing hash bits. */ 53241502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 53341502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 53441502Swpaul 535131503Sbms /* Now program new ones. */ 536148654Srwatson IF_ADDR_LOCK(ifp); 53772084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 53841502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 53941502Swpaul continue; 540130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 541130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 54241502Swpaul if (h < 32) 54341502Swpaul hashes[0] |= (1 << h); 54441502Swpaul else 54541502Swpaul hashes[1] |= (1 << (h - 32)); 54641502Swpaul mcnt++; 54741502Swpaul } 548148654Srwatson IF_ADDR_UNLOCK(ifp); 54941502Swpaul 55041502Swpaul if (mcnt) 55141502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 55241502Swpaul else 55341502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 55441502Swpaul 55541502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 55641502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 55741502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 55841502Swpaul} 55941502Swpaul 56041502Swpaul/* 56141502Swpaul * In order to fiddle with the 56241502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 56341502Swpaul * first have to put the transmit and/or receive logic in the idle state. 56441502Swpaul */ 565102336Salfredstatic void 566131503Sbmsvr_setcfg(struct vr_softc *sc, int media) 56741502Swpaul{ 568131517Sbms int restart = 0; 56941502Swpaul 570131518Sbms VR_LOCK_ASSERT(sc); 571131518Sbms 57241502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 57341502Swpaul restart = 1; 57441502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 57541502Swpaul } 57641502Swpaul 57751432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 57841502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 57941502Swpaul else 58041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 58141502Swpaul 58241502Swpaul if (restart) 58341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 58441502Swpaul} 58541502Swpaul 586102336Salfredstatic void 587131503Sbmsvr_reset(struct vr_softc *sc) 58841502Swpaul{ 589131517Sbms register int i; 59041502Swpaul 591131844Sbms /*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during detach w/o lock. */ 592131518Sbms 59341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 59441502Swpaul 59541502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 59641502Swpaul DELAY(10); 59741502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 59841502Swpaul break; 59941502Swpaul } 600107220Ssilby if (i == VR_TIMEOUT) { 601107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 602107220Ssilby printf("vr%d: reset never completed!\n", sc->vr_unit); 603107220Ssilby else { 604107220Ssilby /* Use newer force reset command */ 605131503Sbms printf("vr%d: Using force reset command.\n", 606131503Sbms sc->vr_unit); 607107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 608107220Ssilby } 609107220Ssilby } 61041502Swpaul 61141502Swpaul /* Wait a little while for the chip to get its brains in order. */ 61241502Swpaul DELAY(1000); 61341502Swpaul} 61441502Swpaul 61541502Swpaul/* 61641502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 61741502Swpaul * IDs against our list and return a device name if we find a match. 61841502Swpaul */ 619102336Salfredstatic int 620131503Sbmsvr_probe(device_t dev) 62141502Swpaul{ 622131503Sbms struct vr_type *t = vr_devs; 62341502Swpaul 624131503Sbms while (t->vr_name != NULL) { 62549610Swpaul if ((pci_get_vendor(dev) == t->vr_vid) && 62649610Swpaul (pci_get_device(dev) == t->vr_did)) { 62749610Swpaul device_set_desc(dev, t->vr_name); 628142398Simp return (BUS_PROBE_DEFAULT); 62941502Swpaul } 63041502Swpaul t++; 63141502Swpaul } 63241502Swpaul 633131503Sbms return (ENXIO); 63441502Swpaul} 63541502Swpaul 63641502Swpaul/* 63741502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 63841502Swpaul * setup and ethernet/BPF attach. 63941502Swpaul */ 640102336Salfredstatic int 641102336Salfredvr_attach(dev) 64249610Swpaul device_t dev; 64341502Swpaul{ 64467087Swpaul int i; 64541502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 64641502Swpaul struct vr_softc *sc; 64741502Swpaul struct ifnet *ifp; 64849610Swpaul int unit, error = 0, rid; 64941502Swpaul 65049610Swpaul sc = device_get_softc(dev); 65149610Swpaul unit = device_get_unit(dev); 65241502Swpaul 65393818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 654131518Sbms MTX_DEF); 65541502Swpaul /* 65641502Swpaul * Map control/status registers. 65741502Swpaul */ 65872813Swpaul pci_enable_busmaster(dev); 659107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 66041502Swpaul 66149610Swpaul rid = VR_RID; 662127135Snjl sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE); 66349610Swpaul 66449610Swpaul if (sc->vr_res == NULL) { 66549610Swpaul printf("vr%d: couldn't map ports/memory\n", unit); 66649610Swpaul error = ENXIO; 66741502Swpaul goto fail; 66841502Swpaul } 66941502Swpaul 67049610Swpaul sc->vr_btag = rman_get_bustag(sc->vr_res); 67149610Swpaul sc->vr_bhandle = rman_get_bushandle(sc->vr_res); 67241502Swpaul 67341502Swpaul /* Allocate interrupt */ 67449610Swpaul rid = 0; 675127135Snjl sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 67649610Swpaul RF_SHAREABLE | RF_ACTIVE); 67749610Swpaul 67849610Swpaul if (sc->vr_irq == NULL) { 67941502Swpaul printf("vr%d: couldn't map interrupt\n", unit); 68049610Swpaul error = ENXIO; 68141502Swpaul goto fail; 68241502Swpaul } 68341502Swpaul 68476586Swpaul /* 68576586Swpaul * Windows may put the chip in suspend mode when it 68676586Swpaul * shuts down. Be sure to kick it in the head to wake it 68776586Swpaul * up again. 68876586Swpaul */ 68976586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 69076586Swpaul 69141502Swpaul /* Reset the adapter. */ 69241502Swpaul vr_reset(sc); 69341502Swpaul 694131503Sbms /* 695110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 696110168Ssilby * initialization and disable AUTOPOLL. 697110168Ssilby */ 698131503Sbms pci_write_config(dev, VR_PCI_MODE, 699110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 700110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 701110168Ssilby 70241502Swpaul /* 70341502Swpaul * Get station address. The way the Rhine chips work, 70441502Swpaul * you're not allowed to directly access the EEPROM once 70541502Swpaul * they've been programmed a special way. Consequently, 70641502Swpaul * we need to read the node address from the PAR0 and PAR1 70741502Swpaul * registers. 70841502Swpaul */ 70941502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 71041502Swpaul DELAY(200); 71141502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 71241502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 71341502Swpaul 71441502Swpaul sc->vr_unit = unit; 71541502Swpaul 71651432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 71751657Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 71851432Swpaul 71951432Swpaul if (sc->vr_ldata == NULL) { 72041502Swpaul printf("vr%d: no memory for list buffers!\n", unit); 72149610Swpaul error = ENXIO; 72249610Swpaul goto fail; 72341502Swpaul } 72441502Swpaul 72541502Swpaul bzero(sc->vr_ldata, sizeof(struct vr_list_data)); 72641502Swpaul 727147256Sbrooks ifp = sc->vr_ifp = if_alloc(IFT_ETHER); 728147256Sbrooks if (ifp == NULL) { 729147256Sbrooks printf("vr%d: can not if_alloc()\n", unit); 730147256Sbrooks error = ENOSPC; 731147256Sbrooks goto fail; 732147256Sbrooks } 73341502Swpaul ifp->if_softc = sc; 734121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 73541502Swpaul ifp->if_mtu = ETHERMTU; 73641502Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 73741502Swpaul ifp->if_ioctl = vr_ioctl; 73841502Swpaul ifp->if_start = vr_start; 73941502Swpaul ifp->if_watchdog = vr_watchdog; 74041502Swpaul ifp->if_init = vr_init; 74141502Swpaul ifp->if_baudrate = 10000000; 742132986Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1); 74343515Swpaul ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 744132986Smlaier IFQ_SET_READY(&ifp->if_snd); 745128118Sru#ifdef DEVICE_POLLING 746128118Sru ifp->if_capabilities |= IFCAP_POLLING; 747128118Sru#endif 748128118Sru ifp->if_capenable = ifp->if_capabilities; 74941502Swpaul 750131503Sbms /* Do MII setup. */ 75151432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 75251432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 75341502Swpaul printf("vr%d: MII without any phy!\n", sc->vr_unit); 75449610Swpaul error = ENXIO; 75541502Swpaul goto fail; 75641502Swpaul } 75741502Swpaul 75851432Swpaul callout_handle_init(&sc->vr_stat_ch); 75941502Swpaul 760131503Sbms /* Call MI attach routine. */ 761106936Ssam ether_ifattach(ifp, eaddr); 76241502Swpaul 763131844Sbms sc->suspended = 0; 764131844Sbms 765113609Snjl /* Hook interrupt last to avoid having to lock softc */ 766131518Sbms error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, 767112872Snjl vr_intr, sc, &sc->vr_intrhand); 768112872Snjl 769112872Snjl if (error) { 770112872Snjl printf("vr%d: couldn't set up irq\n", unit); 771113609Snjl ether_ifdetach(ifp); 772147256Sbrooks if_free(ifp); 773112872Snjl goto fail; 774112872Snjl } 775112872Snjl 77641502Swpaulfail: 777112872Snjl if (error) 778112872Snjl vr_detach(dev); 77967087Swpaul 780131503Sbms return (error); 78141502Swpaul} 78241502Swpaul 783113609Snjl/* 784113609Snjl * Shutdown hardware and free up resources. This can be called any 785113609Snjl * time after the mutex has been initialized. It is called in both 786113609Snjl * the error case in attach and the normal detach case so it needs 787113609Snjl * to be careful about only freeing resources that have actually been 788113609Snjl * allocated. 789113609Snjl */ 790102336Salfredstatic int 791131503Sbmsvr_detach(device_t dev) 79249610Swpaul{ 793131503Sbms struct vr_softc *sc = device_get_softc(dev); 794147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 79549610Swpaul 796112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 797131518Sbms 79867087Swpaul VR_LOCK(sc); 79949610Swpaul 800131844Sbms sc->suspended = 1; 801131844Sbms 802113609Snjl /* These should only be active if attach succeeded */ 803113812Simp if (device_is_attached(dev)) { 804113609Snjl vr_stop(sc); 805136976Sbms VR_UNLOCK(sc); /* XXX: Avoid recursive acquire. */ 806112872Snjl ether_ifdetach(ifp); 807147256Sbrooks if_free(ifp); 808136976Sbms VR_LOCK(sc); 809113609Snjl } 810113609Snjl if (sc->vr_miibus) 811112872Snjl device_delete_child(dev, sc->vr_miibus); 812113609Snjl bus_generic_detach(dev); 81349610Swpaul 814112872Snjl if (sc->vr_intrhand) 815112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 816112872Snjl if (sc->vr_irq) 817112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 818112872Snjl if (sc->vr_res) 819112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 82051432Swpaul 821112872Snjl if (sc->vr_ldata) 822112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 82349610Swpaul 82467087Swpaul VR_UNLOCK(sc); 82567087Swpaul mtx_destroy(&sc->vr_mtx); 82649610Swpaul 827131503Sbms return (0); 82849610Swpaul} 82949610Swpaul 83041502Swpaul/* 83141502Swpaul * Initialize the transmit descriptors. 83241502Swpaul */ 833102336Salfredstatic int 834131503Sbmsvr_list_tx_init(struct vr_softc *sc) 83541502Swpaul{ 83641502Swpaul struct vr_chain_data *cd; 83741502Swpaul struct vr_list_data *ld; 83841502Swpaul int i; 83941502Swpaul 84041502Swpaul cd = &sc->vr_cdata; 84141502Swpaul ld = sc->vr_ldata; 84241502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 84341502Swpaul cd->vr_tx_chain[i].vr_ptr = &ld->vr_tx_list[i]; 84441502Swpaul if (i == (VR_TX_LIST_CNT - 1)) 845131503Sbms cd->vr_tx_chain[i].vr_nextdesc = 84641502Swpaul &cd->vr_tx_chain[0]; 84741502Swpaul else 84841502Swpaul cd->vr_tx_chain[i].vr_nextdesc = 84941502Swpaul &cd->vr_tx_chain[i + 1]; 85041502Swpaul } 851127901Sru cd->vr_tx_cons = cd->vr_tx_prod = &cd->vr_tx_chain[0]; 85241502Swpaul 853131503Sbms return (0); 85441502Swpaul} 85541502Swpaul 85641502Swpaul 85741502Swpaul/* 85841502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 85941502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 86041502Swpaul * points back to the first. 86141502Swpaul */ 862102336Salfredstatic int 863131503Sbmsvr_list_rx_init(struct vr_softc *sc) 86441502Swpaul{ 86541502Swpaul struct vr_chain_data *cd; 86641502Swpaul struct vr_list_data *ld; 86741502Swpaul int i; 86841502Swpaul 869131518Sbms VR_LOCK_ASSERT(sc); 870131518Sbms 87141502Swpaul cd = &sc->vr_cdata; 87241502Swpaul ld = sc->vr_ldata; 87341502Swpaul 87441502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 87541502Swpaul cd->vr_rx_chain[i].vr_ptr = 87641502Swpaul (struct vr_desc *)&ld->vr_rx_list[i]; 87749610Swpaul if (vr_newbuf(sc, &cd->vr_rx_chain[i], NULL) == ENOBUFS) 878131503Sbms return (ENOBUFS); 87941502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 88041502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 88141502Swpaul &cd->vr_rx_chain[0]; 88241502Swpaul ld->vr_rx_list[i].vr_next = 88341502Swpaul vtophys(&ld->vr_rx_list[0]); 88441502Swpaul } else { 88541502Swpaul cd->vr_rx_chain[i].vr_nextdesc = 88641502Swpaul &cd->vr_rx_chain[i + 1]; 88741502Swpaul ld->vr_rx_list[i].vr_next = 88841502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 88941502Swpaul } 89041502Swpaul } 89141502Swpaul 89241502Swpaul cd->vr_rx_head = &cd->vr_rx_chain[0]; 89341502Swpaul 894131503Sbms return (0); 89541502Swpaul} 89641502Swpaul 89741502Swpaul/* 89841502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 89941502Swpaul * Note: the length fields are only 11 bits wide, which means the 90041502Swpaul * largest size we can specify is 2047. This is important because 90141502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 90241502Swpaul * overflow the field and make a mess. 90341502Swpaul */ 904102336Salfredstatic int 905131503Sbmsvr_newbuf(struct vr_softc *sc, struct vr_chain_onefrag *c, struct mbuf *m) 90641502Swpaul{ 90741502Swpaul struct mbuf *m_new = NULL; 90841502Swpaul 90949610Swpaul if (m == NULL) { 910111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 91187846Sluigi if (m_new == NULL) 912131503Sbms return (ENOBUFS); 91341502Swpaul 914111119Simp MCLGET(m_new, M_DONTWAIT); 91549610Swpaul if (!(m_new->m_flags & M_EXT)) { 91649610Swpaul m_freem(m_new); 917131503Sbms return (ENOBUFS); 91849610Swpaul } 91949610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 92049610Swpaul } else { 92149610Swpaul m_new = m; 92249610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 92349610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 92441502Swpaul } 92541502Swpaul 926131503Sbms m_adj(m_new, sizeof(uint64_t)); 92749610Swpaul 92841502Swpaul c->vr_mbuf = m_new; 92941502Swpaul c->vr_ptr->vr_status = VR_RXSTAT; 93041502Swpaul c->vr_ptr->vr_data = vtophys(mtod(m_new, caddr_t)); 93142491Swpaul c->vr_ptr->vr_ctl = VR_RXCTL | VR_RXLEN; 93241502Swpaul 933131503Sbms return (0); 93441502Swpaul} 93541502Swpaul 93641502Swpaul/* 93741502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 93841502Swpaul * the higher level protocols. 93941502Swpaul */ 940102336Salfredstatic void 941131503Sbmsvr_rxeof(struct vr_softc *sc) 94241502Swpaul{ 943131503Sbms struct mbuf *m, *m0; 944131503Sbms struct ifnet *ifp; 94541502Swpaul struct vr_chain_onefrag *cur_rx; 94641502Swpaul int total_len = 0; 947131503Sbms uint32_t rxstat; 94841502Swpaul 949122689Ssam VR_LOCK_ASSERT(sc); 950147256Sbrooks ifp = sc->vr_ifp; 95141502Swpaul 952131503Sbms while (!((rxstat = sc->vr_cdata.vr_rx_head->vr_ptr->vr_status) & 953131503Sbms VR_RXSTAT_OWN)) { 954127901Sru#ifdef DEVICE_POLLING 955127901Sru if (ifp->if_flags & IFF_POLLING) { 956127901Sru if (sc->rxcycles <= 0) 957127901Sru break; 958127901Sru sc->rxcycles--; 959127901Sru } 960127901Sru#endif /* DEVICE_POLLING */ 961127901Sru m0 = NULL; 96241502Swpaul cur_rx = sc->vr_cdata.vr_rx_head; 96341502Swpaul sc->vr_cdata.vr_rx_head = cur_rx->vr_nextdesc; 96449610Swpaul m = cur_rx->vr_mbuf; 96541502Swpaul 96641502Swpaul /* 96741502Swpaul * If an error occurs, update stats, clear the 96841502Swpaul * status word and leave the mbuf cluster in place: 96941502Swpaul * it should simply get re-used next time this descriptor 970131503Sbms * comes up in the ring. 97141502Swpaul */ 97241502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 97341502Swpaul ifp->if_ierrors++; 974131503Sbms printf("vr%d: rx error (%02x):", sc->vr_unit, 975131503Sbms rxstat & 0x000000ff); 976110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 977110131Ssilby printf(" crc error"); 978110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 979110131Ssilby printf(" frame alignment error\n"); 980110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 981110131Ssilby printf(" FIFO overflow"); 982110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 983110131Ssilby printf(" received giant packet"); 984110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 985110131Ssilby printf(" received runt packet"); 986110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 987110131Ssilby printf(" system bus error"); 988110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 989110131Ssilby printf("rx buffer error"); 990110131Ssilby printf("\n"); 99149610Swpaul vr_newbuf(sc, cur_rx, m); 99241502Swpaul continue; 99341502Swpaul } 99441502Swpaul 995131503Sbms /* No errors; receive the packet. */ 99641502Swpaul total_len = VR_RXBYTES(cur_rx->vr_ptr->vr_status); 99741502Swpaul 99841502Swpaul /* 99942048Swpaul * XXX The VIA Rhine chip includes the CRC with every 100042048Swpaul * received frame, and there's no way to turn this 100142048Swpaul * behavior off (at least, I can't find anything in 1002131503Sbms * the manual that explains how to do it) so we have 100342048Swpaul * to trim off the CRC manually. 100442048Swpaul */ 100542048Swpaul total_len -= ETHER_CRC_LEN; 100642048Swpaul 100778508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 100878508Sbmilekic NULL); 100949610Swpaul vr_newbuf(sc, cur_rx, m); 101049610Swpaul if (m0 == NULL) { 101141502Swpaul ifp->if_ierrors++; 101241502Swpaul continue; 101341502Swpaul } 101449610Swpaul m = m0; 101541502Swpaul 101641502Swpaul ifp->if_ipackets++; 1017122689Ssam VR_UNLOCK(sc); 1018106936Ssam (*ifp->if_input)(ifp, m); 1019122689Ssam VR_LOCK(sc); 102041502Swpaul } 102141502Swpaul} 102241502Swpaul 1023105221Sphkstatic void 1024131503Sbmsvr_rxeoc(struct vr_softc *sc) 102541502Swpaul{ 1026147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1027110131Ssilby int i; 102841502Swpaul 1029131518Sbms VR_LOCK_ASSERT(sc); 1030131518Sbms 1031110131Ssilby ifp->if_ierrors++; 1032110131Ssilby 1033131503Sbms VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 1034131503Sbms DELAY(10000); 1035110131Ssilby 1036131503Sbms /* Wait for receiver to stop */ 1037110131Ssilby for (i = 0x400; 1038110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 1039131503Sbms i--) { 1040131503Sbms ; 1041131503Sbms } 1042110131Ssilby 1043110131Ssilby if (!i) { 1044110131Ssilby printf("vr%d: rx shutdown error!\n", sc->vr_unit); 1045110131Ssilby sc->vr_flags |= VR_F_RESTART; 1046110131Ssilby return; 1047131503Sbms } 1048110131Ssilby 104941502Swpaul vr_rxeof(sc); 1050110131Ssilby 105141502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 105241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 105341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 105441502Swpaul} 105541502Swpaul 105641502Swpaul/* 105741502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 105841502Swpaul * the list buffers. 105941502Swpaul */ 1060102336Salfredstatic void 1061131503Sbmsvr_txeof(struct vr_softc *sc) 106241502Swpaul{ 106341502Swpaul struct vr_chain *cur_tx; 1064147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 106541502Swpaul 1066131518Sbms VR_LOCK_ASSERT(sc); 106741502Swpaul 106841502Swpaul /* 106941502Swpaul * Go through our tx list and free mbufs for those 107041502Swpaul * frames that have been transmitted. 107141502Swpaul */ 1072127901Sru cur_tx = sc->vr_cdata.vr_tx_cons; 1073127901Sru while (cur_tx->vr_mbuf != NULL) { 1074131503Sbms uint32_t txstat; 1075110131Ssilby int i; 107641502Swpaul 107741502Swpaul txstat = cur_tx->vr_ptr->vr_status; 107841502Swpaul 1079101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 1080101896Ssilby (txstat & VR_TXSTAT_UDF)) { 1081110131Ssilby for (i = 0x400; 1082110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 1083110131Ssilby i--) 1084101896Ssilby ; /* Wait for chip to shutdown */ 1085110131Ssilby if (!i) { 1086131503Sbms printf("vr%d: tx shutdown timeout\n", 1087131503Sbms sc->vr_unit); 1088110131Ssilby sc->vr_flags |= VR_F_RESTART; 1089110131Ssilby break; 1090110131Ssilby } 1091101896Ssilby VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 1092101896Ssilby CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); 1093101896Ssilby break; 1094101896Ssilby } 1095101896Ssilby 109642491Swpaul if (txstat & VR_TXSTAT_OWN) 109741502Swpaul break; 109841502Swpaul 109941502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 110041502Swpaul ifp->if_oerrors++; 110141502Swpaul if (txstat & VR_TXSTAT_DEFER) 110241502Swpaul ifp->if_collisions++; 110341502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 110441502Swpaul ifp->if_collisions++; 110541502Swpaul } 110641502Swpaul 110741502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 110841502Swpaul 110941502Swpaul ifp->if_opackets++; 1110127901Sru m_freem(cur_tx->vr_mbuf); 1111127901Sru cur_tx->vr_mbuf = NULL; 1112127901Sru ifp->if_flags &= ~IFF_OACTIVE; 111341502Swpaul 1114127901Sru cur_tx = cur_tx->vr_nextdesc; 111541502Swpaul } 1116127901Sru sc->vr_cdata.vr_tx_cons = cur_tx; 1117127901Sru if (cur_tx->vr_mbuf == NULL) 111896677Ssilby ifp->if_timer = 0; 111941502Swpaul} 112041502Swpaul 1121102336Salfredstatic void 1122131503Sbmsvr_tick(void *xsc) 112351432Swpaul{ 1124131503Sbms struct vr_softc *sc = xsc; 112551432Swpaul struct mii_data *mii; 112651432Swpaul 112767087Swpaul VR_LOCK(sc); 1128131517Sbms 1129110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1130110131Ssilby printf("vr%d: restarting\n", sc->vr_unit); 1131110131Ssilby vr_stop(sc); 1132110131Ssilby vr_reset(sc); 1133131844Sbms vr_init_locked(sc); 1134110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1135110131Ssilby } 1136110131Ssilby 113751432Swpaul mii = device_get_softc(sc->vr_miibus); 113851432Swpaul mii_tick(mii); 113951432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 114051432Swpaul 114167087Swpaul VR_UNLOCK(sc); 114251432Swpaul} 114351432Swpaul 1144127901Sru#ifdef DEVICE_POLLING 1145127901Srustatic poll_handler_t vr_poll; 1146131844Sbmsstatic poll_handler_t vr_poll_locked; 1147127901Sru 1148102336Salfredstatic void 1149127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1150127901Sru{ 1151127901Sru struct vr_softc *sc = ifp->if_softc; 1152127901Sru 1153127901Sru VR_LOCK(sc); 1154131844Sbms vr_poll_locked(ifp, cmd, count); 1155131844Sbms VR_UNLOCK(sc); 1156131844Sbms} 1157131517Sbms 1158131844Sbmsstatic void 1159131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1160131844Sbms{ 1161131844Sbms struct vr_softc *sc = ifp->if_softc; 1162131844Sbms 1163131844Sbms VR_LOCK_ASSERT(sc); 1164131844Sbms 1165128118Sru if (!(ifp->if_capenable & IFCAP_POLLING)) { 1166128118Sru ether_poll_deregister(ifp); 1167128118Sru cmd = POLL_DEREGISTER; 1168128118Sru } 1169131517Sbms 1170131503Sbms if (cmd == POLL_DEREGISTER) { 1171131503Sbms /* Final call, enable interrupts. */ 1172127901Sru CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 1173131844Sbms return; 1174127901Sru } 1175127901Sru 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 1252131844Sbms if (ifp->if_flags & IFF_POLLING) 1253131844Sbms goto done_locked; 1254131844Sbms 1255128118Sru if ((ifp->if_capenable & IFCAP_POLLING) && 1256131503Sbms ether_poll_register(vr_poll, ifp)) { 1257131503Sbms /* OK, disable interrupts. */ 1258127901Sru CSR_WRITE_2(sc, VR_IMR, 0x0000); 1259131844Sbms vr_poll_locked(ifp, 0, 1); 1260131844Sbms goto done_locked; 1261127901Sru } 1262127901Sru#endif /* DEVICE_POLLING */ 1263127901Sru 1264131844Sbms /* Suppress unwanted interrupts. */ 126541502Swpaul if (!(ifp->if_flags & IFF_UP)) { 126641502Swpaul vr_stop(sc); 1267131844Sbms goto done_locked; 126841502Swpaul } 126941502Swpaul 127041502Swpaul /* Disable interrupts. */ 127141502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 127241502Swpaul 127341502Swpaul for (;;) { 127441502Swpaul status = CSR_READ_2(sc, VR_ISR); 127541502Swpaul if (status) 127641502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 127741502Swpaul 127841502Swpaul if ((status & VR_INTRS) == 0) 127941502Swpaul break; 128041502Swpaul 128141502Swpaul if (status & VR_ISR_RX_OK) 128241502Swpaul vr_rxeof(sc); 128341502Swpaul 1284110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1285110131Ssilby printf("vr%d: rx packet lost\n", sc->vr_unit); 1286110131Ssilby ifp->if_ierrors++; 1287131503Sbms } 1288110131Ssilby 128941502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1290110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1291110131Ssilby printf("vr%d: receive error (%04x)", 1292110131Ssilby sc->vr_unit, status); 1293110131Ssilby if (status & VR_ISR_RX_NOBUF) 1294110131Ssilby printf(" no buffers"); 1295110131Ssilby if (status & VR_ISR_RX_OFLOW) 1296110131Ssilby printf(" overflow"); 1297110131Ssilby if (status & VR_ISR_RX_DROPPED) 1298110131Ssilby printf(" packet lost"); 1299110131Ssilby printf("\n"); 130041502Swpaul vr_rxeoc(sc); 130141502Swpaul } 130241502Swpaul 1303101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1304101896Ssilby vr_reset(sc); 1305131844Sbms vr_init_locked(sc); 1306101896Ssilby break; 130741502Swpaul } 130841502Swpaul 1309101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1310101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 131141502Swpaul vr_txeof(sc); 1312101896Ssilby if ((status & VR_ISR_UDFI) || 1313101896Ssilby (status & VR_ISR_TX_ABRT2) || 1314101896Ssilby (status & VR_ISR_TX_ABRT)) { 1315101896Ssilby ifp->if_oerrors++; 1316127901Sru if (sc->vr_cdata.vr_tx_cons->vr_mbuf != NULL) { 1317131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1318131503Sbms VR_CMD_TX_ON); 1319131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1320131503Sbms VR_CMD_TX_GO); 1321101896Ssilby } 1322127901Sru } 132341502Swpaul } 132441502Swpaul } 132541502Swpaul 132641502Swpaul /* Re-enable interrupts. */ 132741502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 132841502Swpaul 1329132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1330131844Sbms vr_start_locked(ifp); 1331131844Sbms 1332131844Sbmsdone_locked: 1333131844Sbms VR_UNLOCK(sc); 133441502Swpaul} 133541502Swpaul 133641502Swpaul/* 133741502Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 133841502Swpaul * pointers to the fragment pointers. 133941502Swpaul */ 1340102336Salfredstatic int 1341131503Sbmsvr_encap(struct vr_softc *sc, struct vr_chain *c, struct mbuf *m_head) 134241502Swpaul{ 134341502Swpaul struct vr_desc *f = NULL; 134441502Swpaul struct mbuf *m; 134541502Swpaul 1346131518Sbms VR_LOCK_ASSERT(sc); 134741502Swpaul /* 134841502Swpaul * The VIA Rhine wants packet buffers to be longword 134941502Swpaul * aligned, but very often our mbufs aren't. Rather than 135041502Swpaul * waste time trying to decide when to copy and when not 135141502Swpaul * to copy, just do it all the time. 135241502Swpaul */ 1353127901Sru m = m_defrag(m_head, M_DONTWAIT); 1354131503Sbms if (m == NULL) 1355131503Sbms return (1); 135641502Swpaul 1357127901Sru /* 1358127901Sru * The Rhine chip doesn't auto-pad, so we have to make 1359127901Sru * sure to pad short frames out to the minimum frame length 1360127901Sru * ourselves. 1361127901Sru */ 1362127901Sru if (m->m_len < VR_MIN_FRAMELEN) { 1363127901Sru m->m_pkthdr.len += VR_MIN_FRAMELEN - m->m_len; 1364127901Sru m->m_len = m->m_pkthdr.len; 136541502Swpaul } 136641502Swpaul 1367127901Sru c->vr_mbuf = m; 1368127901Sru f = c->vr_ptr; 1369127901Sru f->vr_data = vtophys(mtod(m, caddr_t)); 1370127901Sru f->vr_ctl = m->m_len; 1371127901Sru f->vr_ctl |= VR_TXCTL_TLINK|VR_TXCTL_FIRSTFRAG; 1372127901Sru f->vr_status = 0; 1373127901Sru f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 1374127901Sru f->vr_next = vtophys(c->vr_nextdesc->vr_ptr); 137541502Swpaul 1376131503Sbms return (0); 137741502Swpaul} 137841502Swpaul 137941502Swpaul/* 138041502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 138141502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 138241502Swpaul * copy of the pointers since the transmit list fragment pointers are 138341502Swpaul * physical addresses. 138441502Swpaul */ 138541502Swpaul 1386102336Salfredstatic void 1387131503Sbmsvr_start(struct ifnet *ifp) 138841502Swpaul{ 1389131518Sbms struct vr_softc *sc = ifp->if_softc; 1390131844Sbms 1391131844Sbms VR_LOCK(sc); 1392131844Sbms vr_start_locked(ifp); 1393131844Sbms VR_UNLOCK(sc); 1394131844Sbms} 1395131844Sbms 1396131844Sbmsstatic void 1397131844Sbmsvr_start_locked(struct ifnet *ifp) 1398131844Sbms{ 1399131844Sbms struct vr_softc *sc = ifp->if_softc; 1400127901Sru struct mbuf *m_head; 1401127901Sru struct vr_chain *cur_tx; 140241502Swpaul 1403127901Sru if (ifp->if_flags & IFF_OACTIVE) 1404127901Sru return; 1405127901Sru 1406127901Sru cur_tx = sc->vr_cdata.vr_tx_prod; 1407127901Sru while (cur_tx->vr_mbuf == NULL) { 1408132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 140941502Swpaul if (m_head == NULL) 141041502Swpaul break; 141141502Swpaul 141241502Swpaul /* Pack the data into the descriptor. */ 141371271Swpaul if (vr_encap(sc, cur_tx, m_head)) { 1414113274Ssilby /* Rollback, send what we were able to encap. */ 1415132986Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 141671271Swpaul break; 141771271Swpaul } 141841502Swpaul 1419127901Sru VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; 142041502Swpaul 142141502Swpaul /* 142241502Swpaul * If there's a BPF listener, bounce a copy of this frame 142341502Swpaul * to him. 142441502Swpaul */ 1425106936Ssam BPF_MTAP(ifp, cur_tx->vr_mbuf); 142651583Swpaul 1427127901Sru cur_tx = cur_tx->vr_nextdesc; 142841502Swpaul } 1429127901Sru if (cur_tx != sc->vr_cdata.vr_tx_prod || cur_tx->vr_mbuf != NULL) { 1430127901Sru sc->vr_cdata.vr_tx_prod = cur_tx; 143141502Swpaul 1432127901Sru /* Tell the chip to start transmitting. */ 1433131517Sbms VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO); 143441526Swpaul 1435127901Sru /* Set a timeout in case the chip goes out to lunch. */ 1436127901Sru ifp->if_timer = 5; 143741502Swpaul 1438127901Sru if (cur_tx->vr_mbuf != NULL) 1439127901Sru ifp->if_flags |= IFF_OACTIVE; 1440127901Sru } 1441131844Sbms} 144241502Swpaul 1443131844Sbmsstatic void 1444131844Sbmsvr_init(void *xsc) 1445131844Sbms{ 1446131844Sbms struct vr_softc *sc = xsc; 1447131844Sbms 1448131844Sbms VR_LOCK(sc); 1449131844Sbms vr_init_locked(sc); 145067087Swpaul VR_UNLOCK(sc); 145141502Swpaul} 145241502Swpaul 1453102336Salfredstatic void 1454131844Sbmsvr_init_locked(struct vr_softc *sc) 145541502Swpaul{ 1456147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 145751432Swpaul struct mii_data *mii; 145873963Swpaul int i; 145941502Swpaul 1460131844Sbms VR_LOCK_ASSERT(sc); 146141502Swpaul 146251432Swpaul mii = device_get_softc(sc->vr_miibus); 146341502Swpaul 1464131503Sbms /* Cancel pending I/O and free all RX/TX buffers. */ 146541502Swpaul vr_stop(sc); 146641502Swpaul vr_reset(sc); 146741502Swpaul 1468131503Sbms /* Set our station address. */ 146973963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 1470147256Sbrooks CSR_WRITE_1(sc, VR_PAR0 + i, IFP2ENADDR(sc->vr_ifp)[i]); 1471131503Sbms 1472131503Sbms /* Set DMA size. */ 1473101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1474101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 147573963Swpaul 1476131503Sbms /* 1477101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1478101108Ssilby * so we must set both. 1479101108Ssilby */ 1480101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1481110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1482101108Ssilby 1483101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1484101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1485101108Ssilby 148641502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1487110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 148841502Swpaul 148941502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 149041502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 149141502Swpaul 149241502Swpaul /* Init circular RX list. */ 149341502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 1494131503Sbms printf( 1495131503Sbms"vr%d: initialization failed: no memory for rx buffers\n", sc->vr_unit); 149641502Swpaul vr_stop(sc); 149741502Swpaul return; 149841502Swpaul } 149941502Swpaul 1500131503Sbms /* Init tx descriptors. */ 150141502Swpaul vr_list_tx_init(sc); 150241502Swpaul 150341502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 150441502Swpaul if (ifp->if_flags & IFF_PROMISC) 150541502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 150641502Swpaul else 150741502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 150841502Swpaul 150941502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 151041502Swpaul if (ifp->if_flags & IFF_BROADCAST) 151141502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 151241502Swpaul else 151341502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 151441502Swpaul 151541502Swpaul /* 151641502Swpaul * Program the multicast filter, if necessary. 151741502Swpaul */ 151841502Swpaul vr_setmulti(sc); 151941502Swpaul 152041502Swpaul /* 152141502Swpaul * Load the address of the RX list. 152241502Swpaul */ 152341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); 152441502Swpaul 152541502Swpaul /* Enable receiver and transmitter. */ 152641502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 152741502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 152841502Swpaul VR_CMD_RX_GO); 152941502Swpaul 153041502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 153141502Swpaul 1532127901Sru CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 1533127901Sru#ifdef DEVICE_POLLING 153441502Swpaul /* 1535127901Sru * Disable interrupts if we are polling. 1536127901Sru */ 1537127901Sru if (ifp->if_flags & IFF_POLLING) 1538127901Sru CSR_WRITE_2(sc, VR_IMR, 0); 1539131503Sbms else 1540127901Sru#endif /* DEVICE_POLLING */ 1541127901Sru /* 154241502Swpaul * Enable interrupts. 154341502Swpaul */ 154441502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 154541502Swpaul 154651432Swpaul mii_mediachg(mii); 154741502Swpaul 154841502Swpaul ifp->if_flags |= IFF_RUNNING; 154941502Swpaul ifp->if_flags &= ~IFF_OACTIVE; 155041502Swpaul 155151432Swpaul sc->vr_stat_ch = timeout(vr_tick, sc, hz); 155241502Swpaul} 155341502Swpaul 155441502Swpaul/* 155541502Swpaul * Set media options. 155641502Swpaul */ 1557102336Salfredstatic int 1558131503Sbmsvr_ifmedia_upd(struct ifnet *ifp) 155941502Swpaul{ 1560131503Sbms struct vr_softc *sc = ifp->if_softc; 156141502Swpaul 156251432Swpaul if (ifp->if_flags & IFF_UP) 156351432Swpaul vr_init(sc); 156441502Swpaul 1565131503Sbms return (0); 156641502Swpaul} 156741502Swpaul 156841502Swpaul/* 156941502Swpaul * Report current media status. 157041502Swpaul */ 1571102336Salfredstatic void 1572131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 157341502Swpaul{ 1574131518Sbms struct vr_softc *sc = ifp->if_softc; 157551432Swpaul struct mii_data *mii; 157641502Swpaul 157751432Swpaul mii = device_get_softc(sc->vr_miibus); 1578133468Sscottl VR_LOCK(sc); 157951432Swpaul mii_pollstat(mii); 1580133468Sscottl VR_UNLOCK(sc); 158151432Swpaul ifmr->ifm_active = mii->mii_media_active; 158251432Swpaul ifmr->ifm_status = mii->mii_media_status; 158341502Swpaul} 158441502Swpaul 1585102336Salfredstatic int 1586131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 158741502Swpaul{ 158841502Swpaul struct vr_softc *sc = ifp->if_softc; 158941502Swpaul struct ifreq *ifr = (struct ifreq *) data; 159051432Swpaul struct mii_data *mii; 159167087Swpaul int error = 0; 159241502Swpaul 1593131503Sbms switch (command) { 159441502Swpaul case SIOCSIFFLAGS: 1595131844Sbms VR_LOCK(sc); 159641502Swpaul if (ifp->if_flags & IFF_UP) { 1597131844Sbms vr_init_locked(sc); 159841502Swpaul } else { 1599131844Sbms if (ifp->if_flags & IFF_RUNNING) 160041502Swpaul vr_stop(sc); 160141502Swpaul } 1602131844Sbms VR_UNLOCK(sc); 160341502Swpaul error = 0; 160441502Swpaul break; 160541502Swpaul case SIOCADDMULTI: 160641502Swpaul case SIOCDELMULTI: 1607131518Sbms VR_LOCK(sc); 160841502Swpaul vr_setmulti(sc); 1609131518Sbms VR_UNLOCK(sc); 161041502Swpaul error = 0; 161141502Swpaul break; 161241502Swpaul case SIOCGIFMEDIA: 161341502Swpaul case SIOCSIFMEDIA: 161451432Swpaul mii = device_get_softc(sc->vr_miibus); 161551432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 161641502Swpaul break; 1617128118Sru case SIOCSIFCAP: 1618128118Sru ifp->if_capenable = ifr->ifr_reqcap; 1619128118Sru break; 162041502Swpaul default: 1621106936Ssam error = ether_ioctl(ifp, command, data); 162241502Swpaul break; 162341502Swpaul } 162441502Swpaul 1625131503Sbms return (error); 162641502Swpaul} 162741502Swpaul 1628102336Salfredstatic void 1629131503Sbmsvr_watchdog(struct ifnet *ifp) 163041502Swpaul{ 1631131518Sbms struct vr_softc *sc = ifp->if_softc; 163241502Swpaul 163367087Swpaul VR_LOCK(sc); 1634131844Sbms 163541502Swpaul ifp->if_oerrors++; 163641502Swpaul printf("vr%d: watchdog timeout\n", sc->vr_unit); 163741502Swpaul 163841502Swpaul vr_stop(sc); 163941502Swpaul vr_reset(sc); 1640131844Sbms vr_init_locked(sc); 1641131518Sbms 1642132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1643131844Sbms vr_start_locked(ifp); 1644131844Sbms 1645131844Sbms VR_UNLOCK(sc); 164641502Swpaul} 164741502Swpaul 164841502Swpaul/* 164941502Swpaul * Stop the adapter and free any mbufs allocated to the 165041502Swpaul * RX and TX lists. 165141502Swpaul */ 1652102336Salfredstatic void 1653131503Sbmsvr_stop(struct vr_softc *sc) 165441502Swpaul{ 1655131503Sbms register int i; 1656131503Sbms struct ifnet *ifp; 165741502Swpaul 1658131518Sbms VR_LOCK_ASSERT(sc); 165967087Swpaul 1660147256Sbrooks ifp = sc->vr_ifp; 166141502Swpaul ifp->if_timer = 0; 166241502Swpaul 166351432Swpaul untimeout(vr_tick, sc, sc->vr_stat_ch); 1664127901Sru ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1665127901Sru#ifdef DEVICE_POLLING 1666127901Sru ether_poll_deregister(ifp); 1667127901Sru#endif /* DEVICE_POLLING */ 166851432Swpaul 166941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 167041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 167141502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 167241502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 167341502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 167441502Swpaul 167541502Swpaul /* 167641502Swpaul * Free data in the RX lists. 167741502Swpaul */ 167841502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 167941502Swpaul if (sc->vr_cdata.vr_rx_chain[i].vr_mbuf != NULL) { 168041502Swpaul m_freem(sc->vr_cdata.vr_rx_chain[i].vr_mbuf); 168141502Swpaul sc->vr_cdata.vr_rx_chain[i].vr_mbuf = NULL; 168241502Swpaul } 168341502Swpaul } 168441502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 1685131517Sbms sizeof(sc->vr_ldata->vr_rx_list)); 168641502Swpaul 168741502Swpaul /* 168841502Swpaul * Free the TX list buffers. 168941502Swpaul */ 169041502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 169141502Swpaul if (sc->vr_cdata.vr_tx_chain[i].vr_mbuf != NULL) { 169241502Swpaul m_freem(sc->vr_cdata.vr_tx_chain[i].vr_mbuf); 169341502Swpaul sc->vr_cdata.vr_tx_chain[i].vr_mbuf = NULL; 169441502Swpaul } 169541502Swpaul } 169641502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 1697131517Sbms sizeof(sc->vr_ldata->vr_tx_list)); 169841502Swpaul} 169941502Swpaul 170041502Swpaul/* 170141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 170241502Swpaul * get confused by errant DMAs when rebooting. 170341502Swpaul */ 1704102336Salfredstatic void 1705131503Sbmsvr_shutdown(device_t dev) 170641502Swpaul{ 170741502Swpaul 1708136696Sbms vr_detach(dev); 170941502Swpaul} 1710