if_vr.c revision 168973
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 168973 2007-04-23 12:19:02Z 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 * 56168953Sphk * Some Rhine chips 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 10641502Swpaul/* 107168952Sphk * Various supported device vendors/types, their names & quirks 10841502Swpaul */ 109168952Sphk 110168952Sphk#define VR_Q_NEEDALIGN (1<<0) 111168952Sphk#define VR_Q_CSUM (1<<1) 112168952Sphk 113168952Sphkstatic struct vr_type { 114168952Sphk u_int16_t vr_vid; 115168952Sphk u_int16_t vr_did; 116168952Sphk int vr_quirks; 117168952Sphk char *vr_name; 118168952Sphk} vr_devs[] = { 119168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE, 120168827Sphk VR_Q_NEEDALIGN, 121168827Sphk "VIA VT3043 Rhine I 10/100BaseTX" }, 122168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_II, 123168827Sphk VR_Q_NEEDALIGN, 124168827Sphk "VIA VT86C100A Rhine II 10/100BaseTX" }, 125168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, 126168827Sphk 0, 127168827Sphk "VIA VT6102 Rhine II 10/100BaseTX" }, 128168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_III, 129168827Sphk 0, 130168827Sphk "VIA VT6105 Rhine III 10/100BaseTX" }, 131168827Sphk { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, 132168827Sphk VR_Q_CSUM, 133168827Sphk "VIA VT6105M Rhine III 10/100BaseTX" }, 134168827Sphk { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, 135168827Sphk VR_Q_NEEDALIGN, 136168827Sphk "Delta Electronics Rhine II 10/100BaseTX" }, 137168827Sphk { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, 138168827Sphk VR_Q_NEEDALIGN, 139168827Sphk "Addtron Technology Rhine II 10/100BaseTX" }, 140168813Sphk { 0, 0, 0, NULL } 14141502Swpaul}; 14241502Swpaul 143168952Sphkstruct vr_list_data { 144168952Sphk struct vr_desc vr_rx_list[VR_RX_LIST_CNT]; 145168952Sphk struct vr_desc vr_tx_list[VR_TX_LIST_CNT]; 146168952Sphk}; 147168946Sphk 148168946Sphkstruct vr_softc { 149168946Sphk struct ifnet *vr_ifp; /* interface info */ 150168946Sphk device_t vr_dev; 151168946Sphk struct resource *vr_res; 152168946Sphk struct resource *vr_irq; 153168946Sphk void *vr_intrhand; 154168946Sphk device_t vr_miibus; 155168946Sphk u_int8_t vr_revid; /* Rhine chip revision */ 156168946Sphk u_int8_t vr_flags; /* See VR_F_* below */ 157168946Sphk struct vr_list_data *vr_ldata; 158168946Sphk struct callout vr_stat_callout; 159168946Sphk struct mtx vr_mtx; 160168948Sphk int vr_suspended; /* if 1, sleeping/detaching */ 161168946Sphk int vr_quirks; 162168952Sphk struct vr_desc *vr_rx_head; 163168952Sphk struct vr_desc *vr_tx_cons; 164168952Sphk struct vr_desc *vr_tx_prod; 165168946Sphk#ifdef DEVICE_POLLING 166168946Sphk int rxcycles; 167168946Sphk#endif 168168946Sphk}; 169168946Sphk 170142407Simpstatic int vr_probe(device_t); 171142407Simpstatic int vr_attach(device_t); 172142407Simpstatic int vr_detach(device_t); 17341502Swpaul 174168952Sphkstatic int vr_newbuf(struct vr_desc *, struct mbuf *); 17541502Swpaul 176142407Simpstatic void vr_rxeof(struct vr_softc *); 177142407Simpstatic void vr_rxeoc(struct vr_softc *); 178142407Simpstatic void vr_txeof(struct vr_softc *); 179142407Simpstatic void vr_tick(void *); 180142407Simpstatic void vr_intr(void *); 181142407Simpstatic void vr_start(struct ifnet *); 182142407Simpstatic void vr_start_locked(struct ifnet *); 183142407Simpstatic int vr_ioctl(struct ifnet *, u_long, caddr_t); 184142407Simpstatic void vr_init(void *); 185142407Simpstatic void vr_init_locked(struct vr_softc *); 186142407Simpstatic void vr_stop(struct vr_softc *); 187142407Simpstatic void vr_watchdog(struct ifnet *); 188142407Simpstatic void vr_shutdown(device_t); 189142407Simpstatic int vr_ifmedia_upd(struct ifnet *); 190142407Simpstatic void vr_ifmedia_sts(struct ifnet *, struct ifmediareq *); 19141502Swpaul 192168946Sphkstatic int vr_mii_readreg(const struct vr_softc *, struct vr_mii_frame *); 193168946Sphkstatic int vr_mii_writereg(const struct vr_softc *, const struct vr_mii_frame *); 194142407Simpstatic int vr_miibus_readreg(device_t, uint16_t, uint16_t); 195142407Simpstatic int vr_miibus_writereg(device_t, uint16_t, uint16_t, uint16_t); 196142407Simpstatic void vr_miibus_statchg(device_t); 19741502Swpaul 198142407Simpstatic void vr_setcfg(struct vr_softc *, int); 199142407Simpstatic void vr_setmulti(struct vr_softc *); 200168946Sphkstatic void vr_reset(const struct vr_softc *); 201142407Simpstatic int vr_list_rx_init(struct vr_softc *); 202142407Simpstatic int vr_list_tx_init(struct vr_softc *); 20341502Swpaul 20449610Swpaul#ifdef VR_USEIOSPACE 20549610Swpaul#define VR_RES SYS_RES_IOPORT 20649610Swpaul#define VR_RID VR_PCI_LOIO 20749610Swpaul#else 20849610Swpaul#define VR_RES SYS_RES_MEMORY 20949610Swpaul#define VR_RID VR_PCI_LOMEM 21049610Swpaul#endif 21149610Swpaul 21249610Swpaulstatic device_method_t vr_methods[] = { 21349610Swpaul /* Device interface */ 21449610Swpaul DEVMETHOD(device_probe, vr_probe), 21549610Swpaul DEVMETHOD(device_attach, vr_attach), 21649610Swpaul DEVMETHOD(device_detach, vr_detach), 21749610Swpaul DEVMETHOD(device_shutdown, vr_shutdown), 21851432Swpaul 21951432Swpaul /* bus interface */ 22051432Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 22151432Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 22251432Swpaul 22351432Swpaul /* MII interface */ 22451432Swpaul DEVMETHOD(miibus_readreg, vr_miibus_readreg), 22551432Swpaul DEVMETHOD(miibus_writereg, vr_miibus_writereg), 22651432Swpaul DEVMETHOD(miibus_statchg, vr_miibus_statchg), 22751432Swpaul 22849610Swpaul { 0, 0 } 22949610Swpaul}; 23049610Swpaul 23149610Swpaulstatic driver_t vr_driver = { 23251455Swpaul "vr", 23349610Swpaul vr_methods, 23449610Swpaul sizeof(struct vr_softc) 23549610Swpaul}; 23649610Swpaul 23749610Swpaulstatic devclass_t vr_devclass; 23849610Swpaul 239113506SmdoddDRIVER_MODULE(vr, pci, vr_driver, vr_devclass, 0, 0); 24051473SwpaulDRIVER_MODULE(miibus, vr, miibus_driver, miibus_devclass, 0, 0); 241168946Sphk#define VR_F_RESTART 0x01 /* Restart unit on next tick */ 24249610Swpaul 243168946Sphk#define VR_LOCK(_sc) mtx_lock(&(_sc)->vr_mtx) 244168946Sphk#define VR_UNLOCK(_sc) mtx_unlock(&(_sc)->vr_mtx) 245168946Sphk#define VR_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->vr_mtx, MA_OWNED) 24641502Swpaul 247168946Sphk/* 248168946Sphk * register space access macros 249168946Sphk */ 250168946Sphk#define CSR_WRITE_4(sc, reg, val) bus_write_4(sc->vr_res, reg, val) 251168946Sphk#define CSR_WRITE_2(sc, reg, val) bus_write_2(sc->vr_res, reg, val) 252168946Sphk#define CSR_WRITE_1(sc, reg, val) bus_write_1(sc->vr_res, reg, val) 25341502Swpaul 254168946Sphk#define CSR_READ_2(sc, reg) bus_read_2(sc->vr_res, reg) 255168946Sphk#define CSR_READ_1(sc, reg) bus_read_1(sc->vr_res, reg) 25641502Swpaul 257168946Sphk#define VR_SETBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | (x)) 258168946Sphk#define VR_CLRBIT(sc, reg, x) CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~(x)) 25941502Swpaul 260168946Sphk#define VR_SETBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | (x)) 261168946Sphk#define VR_CLRBIT16(sc, reg, x) CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~(x)) 26241502Swpaul 26341502Swpaul 26441502Swpaul/* 26541502Swpaul * Read an PHY register through the MII. 26641502Swpaul */ 267102336Salfredstatic int 268168946Sphkvr_mii_readreg(const struct vr_softc *sc, struct vr_mii_frame *frame) 26941502Swpaul{ 270131518Sbms int i; 27141502Swpaul 272131503Sbms /* Set the PHY address. */ 273110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 274110168Ssilby frame->mii_phyaddr); 275110168Ssilby 276131503Sbms /* Set the register address. */ 277110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 278110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB); 279131503Sbms 280110168Ssilby for (i = 0; i < 10000; i++) { 281110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0) 282110168Ssilby break; 283110168Ssilby DELAY(1); 284110168Ssilby } 285110168Ssilby frame->mii_data = CSR_READ_2(sc, VR_MIIDATA); 286110168Ssilby 287131503Sbms return (0); 288110168Ssilby} 289110168Ssilby 290110168Ssilby 29141502Swpaul/* 29241502Swpaul * Write to a PHY register through the MII. 29341502Swpaul */ 294102336Salfredstatic int 295168946Sphkvr_mii_writereg(const struct vr_softc *sc, const struct vr_mii_frame *frame) 29641502Swpaul{ 297131518Sbms int i; 29841502Swpaul 299131503Sbms /* Set the PHY address. */ 300110168Ssilby CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| 301131503Sbms frame->mii_phyaddr); 302110168Ssilby 303131503Sbms /* Set the register address and data to write. */ 304110168Ssilby CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); 305110168Ssilby CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data); 306110168Ssilby 307110168Ssilby VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB); 308110168Ssilby 309110168Ssilby for (i = 0; i < 10000; i++) { 310110168Ssilby if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0) 311110168Ssilby break; 312110168Ssilby DELAY(1); 313110168Ssilby } 314110168Ssilby 315131503Sbms return (0); 316110168Ssilby} 317110168Ssilby 318102336Salfredstatic int 319131517Sbmsvr_miibus_readreg(device_t dev, uint16_t phy, uint16_t reg) 32051432Swpaul{ 32141502Swpaul struct vr_mii_frame frame; 322131503Sbms struct vr_softc *sc = device_get_softc(dev); 32341502Swpaul 324168946Sphk if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1) 325168946Sphk return (0); 326110168Ssilby 32741502Swpaul bzero((char *)&frame, sizeof(frame)); 32851432Swpaul frame.mii_phyaddr = phy; 32941502Swpaul frame.mii_regaddr = reg; 33041502Swpaul vr_mii_readreg(sc, &frame); 331131503Sbms return (frame.mii_data); 33241502Swpaul} 33341502Swpaul 334102336Salfredstatic int 335131503Sbmsvr_miibus_writereg(device_t dev, uint16_t phy, uint16_t reg, uint16_t data) 33651432Swpaul{ 33741502Swpaul struct vr_mii_frame frame; 338131503Sbms struct vr_softc *sc = device_get_softc(dev); 33941502Swpaul 340168946Sphk if (sc->vr_revid == REV_ID_VT6102_APOLLO && phy != 1) 341168946Sphk return (0); 342110168Ssilby 34341502Swpaul bzero((char *)&frame, sizeof(frame)); 34451432Swpaul frame.mii_phyaddr = phy; 34541502Swpaul frame.mii_regaddr = reg; 34641502Swpaul frame.mii_data = data; 34741502Swpaul vr_mii_writereg(sc, &frame); 34841502Swpaul 349131503Sbms return (0); 35051432Swpaul} 35151432Swpaul 352102336Salfredstatic void 353131503Sbmsvr_miibus_statchg(device_t dev) 35451432Swpaul{ 35551432Swpaul struct mii_data *mii; 356131503Sbms struct vr_softc *sc = device_get_softc(dev); 35751432Swpaul 35851432Swpaul mii = device_get_softc(sc->vr_miibus); 35951432Swpaul vr_setcfg(sc, mii->mii_media_active); 36041502Swpaul} 36141502Swpaul 36241502Swpaul/* 36341502Swpaul * Program the 64-bit multicast hash filter. 36441502Swpaul */ 365102336Salfredstatic void 366131503Sbmsvr_setmulti(struct vr_softc *sc) 36741502Swpaul{ 368147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 36941502Swpaul int h = 0; 370131503Sbms uint32_t hashes[2] = { 0, 0 }; 37141502Swpaul struct ifmultiaddr *ifma; 372131503Sbms uint8_t rxfilt; 37341502Swpaul int mcnt = 0; 37441502Swpaul 375131518Sbms VR_LOCK_ASSERT(sc); 37641502Swpaul 37741502Swpaul rxfilt = CSR_READ_1(sc, VR_RXCFG); 37841502Swpaul 37941502Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 38041502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 38141502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 38241502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF); 38341502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF); 38441502Swpaul return; 38541502Swpaul } 38641502Swpaul 387131503Sbms /* First, zero out all the existing hash bits. */ 38841502Swpaul CSR_WRITE_4(sc, VR_MAR0, 0); 38941502Swpaul CSR_WRITE_4(sc, VR_MAR1, 0); 39041502Swpaul 391131503Sbms /* Now program new ones. */ 392148654Srwatson IF_ADDR_LOCK(ifp); 39372084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 39441502Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 39541502Swpaul continue; 396130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 397130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 39841502Swpaul if (h < 32) 39941502Swpaul hashes[0] |= (1 << h); 40041502Swpaul else 40141502Swpaul hashes[1] |= (1 << (h - 32)); 40241502Swpaul mcnt++; 40341502Swpaul } 404148654Srwatson IF_ADDR_UNLOCK(ifp); 40541502Swpaul 40641502Swpaul if (mcnt) 40741502Swpaul rxfilt |= VR_RXCFG_RX_MULTI; 40841502Swpaul else 40941502Swpaul rxfilt &= ~VR_RXCFG_RX_MULTI; 41041502Swpaul 41141502Swpaul CSR_WRITE_4(sc, VR_MAR0, hashes[0]); 41241502Swpaul CSR_WRITE_4(sc, VR_MAR1, hashes[1]); 41341502Swpaul CSR_WRITE_1(sc, VR_RXCFG, rxfilt); 41441502Swpaul} 41541502Swpaul 41641502Swpaul/* 41741502Swpaul * In order to fiddle with the 41841502Swpaul * 'full-duplex' and '100Mbps' bits in the netconfig register, we 41941502Swpaul * first have to put the transmit and/or receive logic in the idle state. 42041502Swpaul */ 421102336Salfredstatic void 422131503Sbmsvr_setcfg(struct vr_softc *sc, int media) 42341502Swpaul{ 424131517Sbms int restart = 0; 42541502Swpaul 426131518Sbms VR_LOCK_ASSERT(sc); 427131518Sbms 42841502Swpaul if (CSR_READ_2(sc, VR_COMMAND) & (VR_CMD_TX_ON|VR_CMD_RX_ON)) { 42941502Swpaul restart = 1; 43041502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_TX_ON|VR_CMD_RX_ON)); 43141502Swpaul } 43241502Swpaul 43351432Swpaul if ((media & IFM_GMASK) == IFM_FDX) 43441502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 43541502Swpaul else 43641502Swpaul VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_FULLDUPLEX); 43741502Swpaul 43841502Swpaul if (restart) 43941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON|VR_CMD_RX_ON); 44041502Swpaul} 44141502Swpaul 442102336Salfredstatic void 443168946Sphkvr_reset(const struct vr_softc *sc) 44441502Swpaul{ 445131517Sbms register int i; 44641502Swpaul 447151773Sjhb /*VR_LOCK_ASSERT(sc);*/ /* XXX: Called during attach w/o lock. */ 448131518Sbms 44941502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RESET); 45041502Swpaul 45141502Swpaul for (i = 0; i < VR_TIMEOUT; i++) { 45241502Swpaul DELAY(10); 45341502Swpaul if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) 45441502Swpaul break; 45541502Swpaul } 456107220Ssilby if (i == VR_TIMEOUT) { 457107220Ssilby if (sc->vr_revid < REV_ID_VT3065_A) 458162315Sglebius device_printf(sc->vr_dev, "reset never completed!\n"); 459107220Ssilby else { 460107220Ssilby /* Use newer force reset command */ 461162315Sglebius device_printf(sc->vr_dev, "Using force reset command.\n"); 462107220Ssilby VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); 463107220Ssilby } 464107220Ssilby } 46541502Swpaul 46641502Swpaul /* Wait a little while for the chip to get its brains in order. */ 46741502Swpaul DELAY(1000); 46841502Swpaul} 46941502Swpaul 47041502Swpaul/* 47141502Swpaul * Probe for a VIA Rhine chip. Check the PCI vendor and device 472168813Sphk * IDs against our list and return a match or NULL 473168813Sphk */ 474168813Sphkstatic struct vr_type * 475168813Sphkvr_match(device_t dev) 476168813Sphk{ 477168813Sphk struct vr_type *t = vr_devs; 478168813Sphk 479168813Sphk for (t = vr_devs; t->vr_name != NULL; t++) 480168813Sphk if ((pci_get_vendor(dev) == t->vr_vid) && 481168813Sphk (pci_get_device(dev) == t->vr_did)) 482168813Sphk return (t); 483168813Sphk return (NULL); 484168813Sphk} 485168813Sphk 486168813Sphk/* 487168813Sphk * Probe for a VIA Rhine chip. Check the PCI vendor and device 48841502Swpaul * IDs against our list and return a device name if we find a match. 48941502Swpaul */ 490102336Salfredstatic int 491131503Sbmsvr_probe(device_t dev) 49241502Swpaul{ 493168813Sphk struct vr_type *t; 49441502Swpaul 495168813Sphk t = vr_match(dev); 496168813Sphk if (t != NULL) { 497168813Sphk device_set_desc(dev, t->vr_name); 498168813Sphk return (BUS_PROBE_DEFAULT); 49941502Swpaul } 500131503Sbms return (ENXIO); 50141502Swpaul} 50241502Swpaul 50341502Swpaul/* 50441502Swpaul * Attach the interface. Allocate softc structures, do ifmedia 50541502Swpaul * setup and ethernet/BPF attach. 50641502Swpaul */ 507102336Salfredstatic int 508168946Sphkvr_attach(device_t dev) 50941502Swpaul{ 51067087Swpaul int i; 51141502Swpaul u_char eaddr[ETHER_ADDR_LEN]; 51241502Swpaul struct vr_softc *sc; 51341502Swpaul struct ifnet *ifp; 514168946Sphk int error = 0, rid; 515168813Sphk struct vr_type *t; 51641502Swpaul 51749610Swpaul sc = device_get_softc(dev); 518162315Sglebius sc->vr_dev = dev; 519168813Sphk t = vr_match(dev); 520168813Sphk KASSERT(t != NULL, ("Lost if_vr device match")); 521168813Sphk sc->vr_quirks = t->vr_quirks; 522168813Sphk device_printf(dev, "Quirks: 0x%x\n", sc->vr_quirks); 52341502Swpaul 52493818Sjhb mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 525131518Sbms MTX_DEF); 526151911Sjhb callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0); 527151911Sjhb 52841502Swpaul /* 52941502Swpaul * Map control/status registers. 53041502Swpaul */ 53172813Swpaul pci_enable_busmaster(dev); 532107220Ssilby sc->vr_revid = pci_read_config(dev, VR_PCI_REVID, 4) & 0x000000FF; 53341502Swpaul 53449610Swpaul rid = VR_RID; 535127135Snjl sc->vr_res = bus_alloc_resource_any(dev, VR_RES, &rid, RF_ACTIVE); 53649610Swpaul 53749610Swpaul if (sc->vr_res == NULL) { 538151773Sjhb device_printf(dev, "couldn't map ports/memory\n"); 53949610Swpaul error = ENXIO; 54041502Swpaul goto fail; 54141502Swpaul } 54241502Swpaul 54341502Swpaul /* Allocate interrupt */ 54449610Swpaul rid = 0; 545127135Snjl sc->vr_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 54649610Swpaul RF_SHAREABLE | RF_ACTIVE); 54749610Swpaul 54849610Swpaul if (sc->vr_irq == NULL) { 549151773Sjhb device_printf(dev, "couldn't map interrupt\n"); 55049610Swpaul error = ENXIO; 55141502Swpaul goto fail; 55241502Swpaul } 55341502Swpaul 554151773Sjhb /* Allocate ifnet structure. */ 555151773Sjhb ifp = sc->vr_ifp = if_alloc(IFT_ETHER); 556151773Sjhb if (ifp == NULL) { 557151773Sjhb device_printf(dev, "can not if_alloc()\n"); 558151773Sjhb error = ENOSPC; 559151773Sjhb goto fail; 560151773Sjhb } 561151773Sjhb ifp->if_softc = sc; 562151773Sjhb if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 563151773Sjhb ifp->if_mtu = ETHERMTU; 564151773Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 565151773Sjhb ifp->if_ioctl = vr_ioctl; 566151773Sjhb ifp->if_start = vr_start; 567151773Sjhb ifp->if_watchdog = vr_watchdog; 568151773Sjhb ifp->if_init = vr_init; 569151773Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, VR_TX_LIST_CNT - 1); 570151773Sjhb ifp->if_snd.ifq_maxlen = VR_TX_LIST_CNT - 1; 571151773Sjhb IFQ_SET_READY(&ifp->if_snd); 572168827Sphk 573168827Sphk if (sc->vr_quirks & VR_Q_CSUM) { 574168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 575168827Sphk ifp->if_capabilities |= IFCAP_HWCSUM; 576168827Sphk } 577168827Sphk 578168973Sphk ifp->if_capabilities |= IFCAP_VLAN_MTU; 579151773Sjhb ifp->if_capenable = ifp->if_capabilities; 580168827Sphk if (ifp->if_capenable & IFCAP_TXCSUM) 581168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 582168827Sphk else 583168827Sphk ifp->if_hwassist = 0; 584168827Sphk 585151773Sjhb#ifdef DEVICE_POLLING 586151773Sjhb ifp->if_capabilities |= IFCAP_POLLING; 587151773Sjhb#endif 588151773Sjhb 58976586Swpaul /* 59076586Swpaul * Windows may put the chip in suspend mode when it 59176586Swpaul * shuts down. Be sure to kick it in the head to wake it 59276586Swpaul * up again. 59376586Swpaul */ 59476586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 59576586Swpaul 59641502Swpaul /* Reset the adapter. */ 59741502Swpaul vr_reset(sc); 59841502Swpaul 599131503Sbms /* 600110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 601110168Ssilby * initialization and disable AUTOPOLL. 602110168Ssilby */ 603131503Sbms pci_write_config(dev, VR_PCI_MODE, 604110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 605110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 606110168Ssilby 60741502Swpaul /* 60841502Swpaul * Get station address. The way the Rhine chips work, 60941502Swpaul * you're not allowed to directly access the EEPROM once 61041502Swpaul * they've been programmed a special way. Consequently, 61141502Swpaul * we need to read the node address from the PAR0 and PAR1 61241502Swpaul * registers. 61341502Swpaul */ 61441502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 61541502Swpaul DELAY(200); 61641502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 61741502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 61841502Swpaul 61951432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 620151773Sjhb M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0); 62151432Swpaul 62251432Swpaul if (sc->vr_ldata == NULL) { 623151773Sjhb device_printf(dev, "no memory for list buffers!\n"); 62449610Swpaul error = ENXIO; 62549610Swpaul goto fail; 62641502Swpaul } 62741502Swpaul 628131503Sbms /* Do MII setup. */ 62951432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 63051432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 631151773Sjhb device_printf(dev, "MII without any phy!\n"); 63249610Swpaul error = ENXIO; 63341502Swpaul goto fail; 63441502Swpaul } 63541502Swpaul 636131503Sbms /* Call MI attach routine. */ 637106936Ssam ether_ifattach(ifp, eaddr); 63841502Swpaul 639168948Sphk sc->vr_suspended = 0; 640131844Sbms 641113609Snjl /* Hook interrupt last to avoid having to lock softc */ 642131518Sbms error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, 643166901Spiso NULL, vr_intr, sc, &sc->vr_intrhand); 644112872Snjl 645112872Snjl if (error) { 646151773Sjhb device_printf(dev, "couldn't set up irq\n"); 647113609Snjl ether_ifdetach(ifp); 648112872Snjl goto fail; 649112872Snjl } 650112872Snjl 65141502Swpaulfail: 652112872Snjl if (error) 653112872Snjl vr_detach(dev); 65467087Swpaul 655131503Sbms return (error); 65641502Swpaul} 65741502Swpaul 658113609Snjl/* 659113609Snjl * Shutdown hardware and free up resources. This can be called any 660113609Snjl * time after the mutex has been initialized. It is called in both 661113609Snjl * the error case in attach and the normal detach case so it needs 662113609Snjl * to be careful about only freeing resources that have actually been 663113609Snjl * allocated. 664113609Snjl */ 665102336Salfredstatic int 666131503Sbmsvr_detach(device_t dev) 66749610Swpaul{ 668131503Sbms struct vr_softc *sc = device_get_softc(dev); 669147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 67049610Swpaul 671112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 672131518Sbms 673150789Sglebius#ifdef DEVICE_POLLING 674150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 675150789Sglebius ether_poll_deregister(ifp); 676150789Sglebius#endif 677150789Sglebius 678113609Snjl /* These should only be active if attach succeeded */ 679113812Simp if (device_is_attached(dev)) { 680151911Sjhb VR_LOCK(sc); 681168948Sphk sc->vr_suspended = 1; 682113609Snjl vr_stop(sc); 683151911Sjhb VR_UNLOCK(sc); 684151911Sjhb callout_drain(&sc->vr_stat_callout); 685112872Snjl ether_ifdetach(ifp); 686113609Snjl } 687113609Snjl if (sc->vr_miibus) 688112872Snjl device_delete_child(dev, sc->vr_miibus); 689113609Snjl bus_generic_detach(dev); 69049610Swpaul 691112872Snjl if (sc->vr_intrhand) 692112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 693112872Snjl if (sc->vr_irq) 694112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 695112872Snjl if (sc->vr_res) 696112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 69751432Swpaul 698151297Sru if (ifp) 699151297Sru if_free(ifp); 700151297Sru 701112872Snjl if (sc->vr_ldata) 702112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 70349610Swpaul 70467087Swpaul mtx_destroy(&sc->vr_mtx); 70549610Swpaul 706131503Sbms return (0); 70749610Swpaul} 70849610Swpaul 70941502Swpaul/* 71041502Swpaul * Initialize the transmit descriptors. 71141502Swpaul */ 712102336Salfredstatic int 713131503Sbmsvr_list_tx_init(struct vr_softc *sc) 71441502Swpaul{ 71541502Swpaul struct vr_list_data *ld; 71641502Swpaul int i; 71741502Swpaul 71841502Swpaul ld = sc->vr_ldata; 71941502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 720168950Sphk if (i == (VR_TX_LIST_CNT - 1)) { 721168952Sphk ld->vr_tx_list[i].vr_next = 722168952Sphk &ld->vr_tx_list[0]; 723168950Sphk ld->vr_tx_list[i].vr_nextphys = 724168950Sphk vtophys(&ld->vr_tx_list[0]); 725168950Sphk } else { 726168952Sphk ld->vr_tx_list[i].vr_next = 727168952Sphk &ld->vr_tx_list[i + 1]; 728168950Sphk ld->vr_tx_list[i].vr_nextphys = 729168950Sphk vtophys(&ld->vr_tx_list[i + 1]); 730168950Sphk } 73141502Swpaul } 732168952Sphk sc->vr_tx_cons = sc->vr_tx_prod = &ld->vr_tx_list[0]; 73341502Swpaul 734131503Sbms return (0); 73541502Swpaul} 73641502Swpaul 73741502Swpaul 73841502Swpaul/* 73941502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 74041502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 74141502Swpaul * points back to the first. 74241502Swpaul */ 743102336Salfredstatic int 744131503Sbmsvr_list_rx_init(struct vr_softc *sc) 74541502Swpaul{ 74641502Swpaul struct vr_list_data *ld; 74741502Swpaul int i; 74841502Swpaul 749131518Sbms VR_LOCK_ASSERT(sc); 750131518Sbms 75141502Swpaul ld = sc->vr_ldata; 75241502Swpaul 75341502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 754168952Sphk if (vr_newbuf(&ld->vr_rx_list[i], NULL) == ENOBUFS) 755131503Sbms return (ENOBUFS); 75641502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 757168952Sphk ld->vr_rx_list[i].vr_next = &ld->vr_rx_list[0]; 758168948Sphk ld->vr_rx_list[i].vr_nextphys = 75941502Swpaul vtophys(&ld->vr_rx_list[0]); 76041502Swpaul } else { 761168952Sphk ld->vr_rx_list[i].vr_next = 762168952Sphk &ld->vr_rx_list[i + 1]; 763168948Sphk ld->vr_rx_list[i].vr_nextphys = 76441502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 76541502Swpaul } 76641502Swpaul } 76741502Swpaul 768168952Sphk sc->vr_rx_head = &ld->vr_rx_list[0]; 76941502Swpaul 770131503Sbms return (0); 77141502Swpaul} 77241502Swpaul 77341502Swpaul/* 77441502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 77541502Swpaul * Note: the length fields are only 11 bits wide, which means the 77641502Swpaul * largest size we can specify is 2047. This is important because 77741502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 77841502Swpaul * overflow the field and make a mess. 77941502Swpaul */ 780102336Salfredstatic int 781168952Sphkvr_newbuf(struct vr_desc *c, struct mbuf *m) 78241502Swpaul{ 78341502Swpaul struct mbuf *m_new = NULL; 78441502Swpaul 78549610Swpaul if (m == NULL) { 786168952Sphk m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 78787846Sluigi if (m_new == NULL) 788131503Sbms return (ENOBUFS); 78949610Swpaul } else { 79049610Swpaul m_new = m; 79149610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 79249610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 79341502Swpaul } 79441502Swpaul 795131503Sbms m_adj(m_new, sizeof(uint64_t)); 79649610Swpaul 79741502Swpaul c->vr_mbuf = m_new; 798168952Sphk c->vr_status = VR_RXSTAT; 799168952Sphk c->vr_data = vtophys(mtod(m_new, caddr_t)); 800168952Sphk c->vr_ctl = VR_RXCTL | VR_RXLEN; 80141502Swpaul 802131503Sbms return (0); 80341502Swpaul} 80441502Swpaul 80541502Swpaul/* 80641502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 80741502Swpaul * the higher level protocols. 80841502Swpaul */ 809102336Salfredstatic void 810131503Sbmsvr_rxeof(struct vr_softc *sc) 81141502Swpaul{ 812131503Sbms struct mbuf *m, *m0; 813131503Sbms struct ifnet *ifp; 814168952Sphk struct vr_desc *cur_rx; 81541502Swpaul int total_len = 0; 816168827Sphk uint32_t rxstat, rxctl; 81741502Swpaul 818122689Ssam VR_LOCK_ASSERT(sc); 819147256Sbrooks ifp = sc->vr_ifp; 82041502Swpaul 821168952Sphk while (!((rxstat = sc->vr_rx_head->vr_status) & 822131503Sbms VR_RXSTAT_OWN)) { 823127901Sru#ifdef DEVICE_POLLING 824150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 825127901Sru if (sc->rxcycles <= 0) 826127901Sru break; 827127901Sru sc->rxcycles--; 828127901Sru } 829150789Sglebius#endif 830127901Sru m0 = NULL; 831168952Sphk cur_rx = sc->vr_rx_head; 832168952Sphk sc->vr_rx_head = cur_rx->vr_next; 83349610Swpaul m = cur_rx->vr_mbuf; 83441502Swpaul 83541502Swpaul /* 83641502Swpaul * If an error occurs, update stats, clear the 83741502Swpaul * status word and leave the mbuf cluster in place: 83841502Swpaul * it should simply get re-used next time this descriptor 839131503Sbms * comes up in the ring. 84041502Swpaul */ 84141502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 84241502Swpaul ifp->if_ierrors++; 843162315Sglebius device_printf(sc->vr_dev, 844162315Sglebius "rx error (%02x):", rxstat & 0x000000ff); 845110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 846110131Ssilby printf(" crc error"); 847110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 848110131Ssilby printf(" frame alignment error\n"); 849110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 850110131Ssilby printf(" FIFO overflow"); 851110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 852110131Ssilby printf(" received giant packet"); 853110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 854110131Ssilby printf(" received runt packet"); 855110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 856110131Ssilby printf(" system bus error"); 857110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 858110131Ssilby printf("rx buffer error"); 859110131Ssilby printf("\n"); 860168946Sphk vr_newbuf(cur_rx, m); 86141502Swpaul continue; 86241502Swpaul } 86341502Swpaul 864131503Sbms /* No errors; receive the packet. */ 865168952Sphk total_len = VR_RXBYTES(cur_rx->vr_status); 866168827Sphk if (ifp->if_capenable & IFCAP_RXCSUM) { 867168952Sphk rxctl = cur_rx->vr_ctl; 868168827Sphk if ((rxctl & VR_RXCTL_GOODIP) == VR_RXCTL_GOODIP) 869168827Sphk m->m_pkthdr.csum_flags |= 870168827Sphk CSUM_IP_CHECKED | CSUM_IP_VALID; 871168827Sphk if ((rxctl & VR_RXCTL_GOODTCPUDP)) { 872168827Sphk m->m_pkthdr.csum_flags |= 873168827Sphk CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 874168827Sphk m->m_pkthdr.csum_data = 0xffff; 875168827Sphk } 876168827Sphk } 87741502Swpaul 87841502Swpaul /* 87942048Swpaul * XXX The VIA Rhine chip includes the CRC with every 88042048Swpaul * received frame, and there's no way to turn this 88142048Swpaul * behavior off (at least, I can't find anything in 882131503Sbms * the manual that explains how to do it) so we have 88342048Swpaul * to trim off the CRC manually. 88442048Swpaul */ 88542048Swpaul total_len -= ETHER_CRC_LEN; 88642048Swpaul 88778508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 88878508Sbmilekic NULL); 889168946Sphk vr_newbuf(cur_rx, m); 89049610Swpaul if (m0 == NULL) { 89141502Swpaul ifp->if_ierrors++; 89241502Swpaul continue; 89341502Swpaul } 89449610Swpaul m = m0; 89541502Swpaul 89641502Swpaul ifp->if_ipackets++; 897122689Ssam VR_UNLOCK(sc); 898106936Ssam (*ifp->if_input)(ifp, m); 899122689Ssam VR_LOCK(sc); 90041502Swpaul } 90141502Swpaul} 90241502Swpaul 903105221Sphkstatic void 904131503Sbmsvr_rxeoc(struct vr_softc *sc) 90541502Swpaul{ 906147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 907110131Ssilby int i; 90841502Swpaul 909131518Sbms VR_LOCK_ASSERT(sc); 910131518Sbms 911110131Ssilby ifp->if_ierrors++; 912110131Ssilby 913131503Sbms VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 914131503Sbms DELAY(10000); 915110131Ssilby 916131503Sbms /* Wait for receiver to stop */ 917110131Ssilby for (i = 0x400; 918110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 919131503Sbms i--) { 920131503Sbms ; 921131503Sbms } 922110131Ssilby 923110131Ssilby if (!i) { 924162315Sglebius device_printf(sc->vr_dev, "rx shutdown error!\n"); 925110131Ssilby sc->vr_flags |= VR_F_RESTART; 926110131Ssilby return; 927131503Sbms } 928110131Ssilby 92941502Swpaul vr_rxeof(sc); 930110131Ssilby 931168952Sphk CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head)); 93241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 93341502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 93441502Swpaul} 93541502Swpaul 93641502Swpaul/* 93741502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 93841502Swpaul * the list buffers. 93941502Swpaul */ 940102336Salfredstatic void 941131503Sbmsvr_txeof(struct vr_softc *sc) 94241502Swpaul{ 943168952Sphk struct vr_desc *cur_tx; 944147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 94541502Swpaul 946131518Sbms VR_LOCK_ASSERT(sc); 94741502Swpaul 94841502Swpaul /* 94941502Swpaul * Go through our tx list and free mbufs for those 95041502Swpaul * frames that have been transmitted. 95141502Swpaul */ 952168952Sphk cur_tx = sc->vr_tx_cons; 953168952Sphk while (cur_tx != sc->vr_tx_prod) { 954131503Sbms uint32_t txstat; 955110131Ssilby int i; 95641502Swpaul 957168952Sphk txstat = cur_tx->vr_status; 95841502Swpaul 959101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 960101896Ssilby (txstat & VR_TXSTAT_UDF)) { 961110131Ssilby for (i = 0x400; 962110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 963110131Ssilby i--) 964101896Ssilby ; /* Wait for chip to shutdown */ 965110131Ssilby if (!i) { 966162315Sglebius device_printf(sc->vr_dev, "tx shutdown timeout\n"); 967110131Ssilby sc->vr_flags |= VR_F_RESTART; 968110131Ssilby break; 969110131Ssilby } 970168952Sphk atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN); 971168952Sphk CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx)); 972101896Ssilby break; 973101896Ssilby } 974101896Ssilby 97542491Swpaul if (txstat & VR_TXSTAT_OWN) 97641502Swpaul break; 97741502Swpaul 97841502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 97941502Swpaul ifp->if_oerrors++; 98041502Swpaul if (txstat & VR_TXSTAT_DEFER) 98141502Swpaul ifp->if_collisions++; 98241502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 98341502Swpaul ifp->if_collisions++; 98441502Swpaul } 98541502Swpaul 98641502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 98741502Swpaul 98841502Swpaul ifp->if_opackets++; 989168813Sphk if (cur_tx->vr_mbuf != NULL) 990168813Sphk m_freem(cur_tx->vr_mbuf); 991127901Sru cur_tx->vr_mbuf = NULL; 992148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 99341502Swpaul 994168952Sphk cur_tx = cur_tx->vr_next; 99541502Swpaul } 996168952Sphk sc->vr_tx_cons = cur_tx; 997127901Sru if (cur_tx->vr_mbuf == NULL) 99896677Ssilby ifp->if_timer = 0; 99941502Swpaul} 100041502Swpaul 1001102336Salfredstatic void 1002131503Sbmsvr_tick(void *xsc) 100351432Swpaul{ 1004131503Sbms struct vr_softc *sc = xsc; 100551432Swpaul struct mii_data *mii; 100651432Swpaul 1007151911Sjhb VR_LOCK_ASSERT(sc); 1008131517Sbms 1009110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1010162315Sglebius device_printf(sc->vr_dev, "restarting\n"); 1011110131Ssilby vr_stop(sc); 1012110131Ssilby vr_reset(sc); 1013131844Sbms vr_init_locked(sc); 1014110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1015110131Ssilby } 1016110131Ssilby 101751432Swpaul mii = device_get_softc(sc->vr_miibus); 101851432Swpaul mii_tick(mii); 1019151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 102051432Swpaul} 102151432Swpaul 1022127901Sru#ifdef DEVICE_POLLING 1023127901Srustatic poll_handler_t vr_poll; 1024131844Sbmsstatic poll_handler_t vr_poll_locked; 1025127901Sru 1026102336Salfredstatic void 1027127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1028127901Sru{ 1029127901Sru struct vr_softc *sc = ifp->if_softc; 1030127901Sru 1031127901Sru VR_LOCK(sc); 1032150789Sglebius if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1033150789Sglebius vr_poll_locked(ifp, cmd, count); 1034131844Sbms VR_UNLOCK(sc); 1035131844Sbms} 1036131517Sbms 1037131844Sbmsstatic void 1038131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1039131844Sbms{ 1040131844Sbms struct vr_softc *sc = ifp->if_softc; 1041131844Sbms 1042131844Sbms VR_LOCK_ASSERT(sc); 1043131844Sbms 1044127901Sru sc->rxcycles = count; 1045127901Sru vr_rxeof(sc); 1046127901Sru vr_txeof(sc); 1047133006Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1048131844Sbms vr_start_locked(ifp); 1049127901Sru 1050131503Sbms if (cmd == POLL_AND_CHECK_STATUS) { 1051131503Sbms uint16_t status; 1052127901Sru 1053131503Sbms /* Also check status register. */ 1054127901Sru status = CSR_READ_2(sc, VR_ISR); 1055127901Sru if (status) 1056127901Sru CSR_WRITE_2(sc, VR_ISR, status); 1057127901Sru 1058127901Sru if ((status & VR_INTRS) == 0) 1059131844Sbms return; 1060127901Sru 1061127901Sru if (status & VR_ISR_RX_DROPPED) { 1062151773Sjhb if_printf(ifp, "rx packet lost\n"); 1063127901Sru ifp->if_ierrors++; 1064127901Sru } 1065127901Sru 1066127901Sru if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1067127901Sru (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1068151773Sjhb if_printf(ifp, "receive error (%04x)", status); 1069127901Sru if (status & VR_ISR_RX_NOBUF) 1070127901Sru printf(" no buffers"); 1071127901Sru if (status & VR_ISR_RX_OFLOW) 1072127901Sru printf(" overflow"); 1073127901Sru if (status & VR_ISR_RX_DROPPED) 1074127901Sru printf(" packet lost"); 1075127901Sru printf("\n"); 1076127901Sru vr_rxeoc(sc); 1077127901Sru } 1078127901Sru 1079131503Sbms if ((status & VR_ISR_BUSERR) || 1080131503Sbms (status & VR_ISR_TX_UNDERRUN)) { 1081127901Sru vr_reset(sc); 1082131844Sbms vr_init_locked(sc); 1083131518Sbms return; 1084127901Sru } 1085127901Sru 1086127901Sru if ((status & VR_ISR_UDFI) || 1087127901Sru (status & VR_ISR_TX_ABRT2) || 1088127901Sru (status & VR_ISR_TX_ABRT)) { 1089127901Sru ifp->if_oerrors++; 1090168952Sphk if (sc->vr_tx_cons->vr_mbuf != NULL) { 1091127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1092127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1093127901Sru } 1094127901Sru } 1095127901Sru } 1096127901Sru} 1097127901Sru#endif /* DEVICE_POLLING */ 1098127901Sru 1099127901Srustatic void 1100131503Sbmsvr_intr(void *arg) 110141502Swpaul{ 1102131503Sbms struct vr_softc *sc = arg; 1103147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1104131503Sbms uint16_t status; 110541502Swpaul 110667087Swpaul VR_LOCK(sc); 1107131844Sbms 1108168948Sphk if (sc->vr_suspended) { 1109136997Sbms /* 1110136997Sbms * Forcibly disable interrupts. 1111136997Sbms * XXX: Mobile VIA based platforms may need 1112136997Sbms * interrupt re-enable on resume. 1113136997Sbms */ 1114136997Sbms CSR_WRITE_2(sc, VR_IMR, 0x0000); 1115131844Sbms goto done_locked; 1116136997Sbms } 1117131844Sbms 1118127901Sru#ifdef DEVICE_POLLING 1119150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1120131844Sbms goto done_locked; 1121150789Sglebius#endif 1122131844Sbms 1123131844Sbms /* Suppress unwanted interrupts. */ 112441502Swpaul if (!(ifp->if_flags & IFF_UP)) { 112541502Swpaul vr_stop(sc); 1126131844Sbms goto done_locked; 112741502Swpaul } 112841502Swpaul 112941502Swpaul /* Disable interrupts. */ 113041502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 113141502Swpaul 113241502Swpaul for (;;) { 113341502Swpaul status = CSR_READ_2(sc, VR_ISR); 1134168813Sphk 113541502Swpaul if (status) 113641502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 113741502Swpaul 113841502Swpaul if ((status & VR_INTRS) == 0) 113941502Swpaul break; 114041502Swpaul 114141502Swpaul if (status & VR_ISR_RX_OK) 114241502Swpaul vr_rxeof(sc); 114341502Swpaul 1144110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1145162315Sglebius device_printf(sc->vr_dev, "rx packet lost\n"); 1146110131Ssilby ifp->if_ierrors++; 1147131503Sbms } 1148110131Ssilby 114941502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1150110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1151162315Sglebius device_printf(sc->vr_dev, "receive error (%04x)", status); 1152110131Ssilby if (status & VR_ISR_RX_NOBUF) 1153110131Ssilby printf(" no buffers"); 1154110131Ssilby if (status & VR_ISR_RX_OFLOW) 1155110131Ssilby printf(" overflow"); 1156110131Ssilby if (status & VR_ISR_RX_DROPPED) 1157110131Ssilby printf(" packet lost"); 1158110131Ssilby printf("\n"); 115941502Swpaul vr_rxeoc(sc); 116041502Swpaul } 116141502Swpaul 1162101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1163101896Ssilby vr_reset(sc); 1164131844Sbms vr_init_locked(sc); 1165101896Ssilby break; 116641502Swpaul } 116741502Swpaul 1168101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1169101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 117041502Swpaul vr_txeof(sc); 1171101896Ssilby if ((status & VR_ISR_UDFI) || 1172101896Ssilby (status & VR_ISR_TX_ABRT2) || 1173101896Ssilby (status & VR_ISR_TX_ABRT)) { 1174101896Ssilby ifp->if_oerrors++; 1175168952Sphk if (sc->vr_tx_cons->vr_mbuf != NULL) { 1176131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1177131503Sbms VR_CMD_TX_ON); 1178131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1179131503Sbms VR_CMD_TX_GO); 1180101896Ssilby } 1181127901Sru } 118241502Swpaul } 118341502Swpaul } 118441502Swpaul 118541502Swpaul /* Re-enable interrupts. */ 118641502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 118741502Swpaul 1188132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1189131844Sbms vr_start_locked(ifp); 1190131844Sbms 1191131844Sbmsdone_locked: 1192131844Sbms VR_UNLOCK(sc); 119341502Swpaul} 119441502Swpaul 119541502Swpaul/* 119641502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 119741502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 119841502Swpaul * copy of the pointers since the transmit list fragment pointers are 119941502Swpaul * physical addresses. 120041502Swpaul */ 120141502Swpaul 1202102336Salfredstatic void 1203131503Sbmsvr_start(struct ifnet *ifp) 120441502Swpaul{ 1205131518Sbms struct vr_softc *sc = ifp->if_softc; 1206131844Sbms 1207131844Sbms VR_LOCK(sc); 1208131844Sbms vr_start_locked(ifp); 1209131844Sbms VR_UNLOCK(sc); 1210131844Sbms} 1211131844Sbms 1212131844Sbmsstatic void 1213131844Sbmsvr_start_locked(struct ifnet *ifp) 1214131844Sbms{ 1215131844Sbms struct vr_softc *sc = ifp->if_softc; 1216168813Sphk struct mbuf *m, *m_head; 1217168952Sphk struct vr_desc *cur_tx, *n_tx; 1218168813Sphk struct vr_desc *f = NULL; 1219168813Sphk uint32_t cval; 122041502Swpaul 1221148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 1222127901Sru return; 1223127901Sru 1224168952Sphk for (cur_tx = sc->vr_tx_prod; 1225168952Sphk cur_tx->vr_next != sc->vr_tx_cons; ) { 1226132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 122741502Swpaul if (m_head == NULL) 122841502Swpaul break; 122941502Swpaul 1230168813Sphk VR_LOCK_ASSERT(sc); 1231168813Sphk /* 1232168813Sphk * Some VIA Rhine wants packet buffers to be longword 1233168813Sphk * aligned, but very often our mbufs aren't. Rather than 1234168813Sphk * waste time trying to decide when to copy and when not 1235168813Sphk * to copy, just do it all the time. 1236168813Sphk */ 1237168827Sphk if (sc->vr_quirks & VR_Q_NEEDALIGN) { 1238168813Sphk m = m_defrag(m_head, M_DONTWAIT); 1239168813Sphk if (m == NULL) { 1240168813Sphk /* Rollback, send what we were able to encap. */ 1241168813Sphk IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1242168813Sphk break; 1243168813Sphk } 1244168813Sphk m_head = m; 1245168813Sphk } 124641502Swpaul 124741502Swpaul /* 1248168813Sphk * The Rhine chip doesn't auto-pad, so we have to make 1249168813Sphk * sure to pad short frames out to the minimum frame length 1250168813Sphk * ourselves. 125141502Swpaul */ 1252168813Sphk if (m_head->m_pkthdr.len < VR_MIN_FRAMELEN) { 1253168813Sphk if (m_head->m_next != NULL) 1254168813Sphk m_head = m_defrag(m_head, M_DONTWAIT); 1255168813Sphk m_head->m_pkthdr.len += VR_MIN_FRAMELEN - m_head->m_len; 1256168813Sphk m_head->m_len = m_head->m_pkthdr.len; 1257168813Sphk /* XXX: bzero the padding bytes */ 1258168813Sphk } 125951583Swpaul 1260168813Sphk n_tx = cur_tx; 1261168813Sphk for (m = m_head; m != NULL; m = m->m_next) { 1262168813Sphk if (m->m_len == 0) 1263168813Sphk continue; 1264168952Sphk if (n_tx->vr_next == sc->vr_tx_cons) { 1265168813Sphk IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1266168952Sphk sc->vr_tx_prod = cur_tx; 1267168813Sphk return; 1268168813Sphk } 1269168813Sphk KASSERT(n_tx->vr_mbuf == NULL, ("if_vr_tx overrun")); 1270168813Sphk 1271168952Sphk f = n_tx; 1272168813Sphk f->vr_data = vtophys(mtod(m, caddr_t)); 1273168813Sphk cval = m->m_len; 1274168813Sphk cval |= VR_TXCTL_TLINK; 1275168827Sphk 1276168827Sphk if ((ifp->if_capenable & IFCAP_TXCSUM) && 1277168827Sphk m_head->m_pkthdr.csum_flags) { 1278168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_IP) 1279168827Sphk cval |= VR_TXCTL_IPCSUM; 1280168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 1281168827Sphk cval |= VR_TXCTL_TCPCSUM; 1282168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 1283168827Sphk cval |= VR_TXCTL_UDPCSUM; 1284168827Sphk } 1285168827Sphk 1286168813Sphk if (m == m_head) 1287168813Sphk cval |= VR_TXCTL_FIRSTFRAG; 1288168813Sphk f->vr_ctl = cval; 1289168813Sphk f->vr_status = 0; 1290168952Sphk n_tx = n_tx->vr_next; 1291168813Sphk } 129241502Swpaul 1293168946Sphk KASSERT(f != NULL, ("if_vr: no packet processed")); 1294168813Sphk f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 1295168813Sphk cur_tx->vr_mbuf = m_head; 1296168952Sphk atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN); 1297168813Sphk 1298127901Sru /* Tell the chip to start transmitting. */ 1299131517Sbms VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO); 130041526Swpaul 1301168813Sphk ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1302127901Sru ifp->if_timer = 5; 130341502Swpaul 1304168813Sphk /* 1305168813Sphk * If there's a BPF listener, bounce a copy of this frame 1306168813Sphk * to him. 1307168813Sphk */ 1308168813Sphk BPF_MTAP(ifp, m_head); 1309168813Sphk cur_tx = n_tx; 1310127901Sru } 1311168952Sphk sc->vr_tx_prod = cur_tx; 1312131844Sbms} 131341502Swpaul 1314131844Sbmsstatic void 1315131844Sbmsvr_init(void *xsc) 1316131844Sbms{ 1317131844Sbms struct vr_softc *sc = xsc; 1318131844Sbms 1319131844Sbms VR_LOCK(sc); 1320131844Sbms vr_init_locked(sc); 132167087Swpaul VR_UNLOCK(sc); 132241502Swpaul} 132341502Swpaul 1324102336Salfredstatic void 1325131844Sbmsvr_init_locked(struct vr_softc *sc) 132641502Swpaul{ 1327147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 132851432Swpaul struct mii_data *mii; 132973963Swpaul int i; 133041502Swpaul 1331131844Sbms VR_LOCK_ASSERT(sc); 133241502Swpaul 133351432Swpaul mii = device_get_softc(sc->vr_miibus); 133441502Swpaul 1335131503Sbms /* Cancel pending I/O and free all RX/TX buffers. */ 133641502Swpaul vr_stop(sc); 133741502Swpaul vr_reset(sc); 133841502Swpaul 1339131503Sbms /* Set our station address. */ 134073963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 1341152315Sru CSR_WRITE_1(sc, VR_PAR0 + i, IF_LLADDR(sc->vr_ifp)[i]); 1342131503Sbms 1343131503Sbms /* Set DMA size. */ 1344101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1345101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 134673963Swpaul 1347131503Sbms /* 1348101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1349101108Ssilby * so we must set both. 1350101108Ssilby */ 1351101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1352110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1353101108Ssilby 1354101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1355101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1356101108Ssilby 135741502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1358110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 135941502Swpaul 136041502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 136141502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 136241502Swpaul 136341502Swpaul /* Init circular RX list. */ 136441502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 1365162315Sglebius device_printf(sc->vr_dev, 1366151773Sjhb "initialization failed: no memory for rx buffers\n"); 136741502Swpaul vr_stop(sc); 136841502Swpaul return; 136941502Swpaul } 137041502Swpaul 1371131503Sbms /* Init tx descriptors. */ 137241502Swpaul vr_list_tx_init(sc); 137341502Swpaul 137441502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 137541502Swpaul if (ifp->if_flags & IFF_PROMISC) 137641502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 137741502Swpaul else 137841502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 137941502Swpaul 138041502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 138141502Swpaul if (ifp->if_flags & IFF_BROADCAST) 138241502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 138341502Swpaul else 138441502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 138541502Swpaul 138641502Swpaul /* 138741502Swpaul * Program the multicast filter, if necessary. 138841502Swpaul */ 138941502Swpaul vr_setmulti(sc); 139041502Swpaul 139141502Swpaul /* 139241502Swpaul * Load the address of the RX list. 139341502Swpaul */ 1394168952Sphk CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head)); 139541502Swpaul 139641502Swpaul /* Enable receiver and transmitter. */ 139741502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 139841502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 139941502Swpaul VR_CMD_RX_GO); 140041502Swpaul 140141502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 140241502Swpaul 1403127901Sru CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 1404127901Sru#ifdef DEVICE_POLLING 140541502Swpaul /* 1406127901Sru * Disable interrupts if we are polling. 1407127901Sru */ 1408150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1409127901Sru CSR_WRITE_2(sc, VR_IMR, 0); 1410131503Sbms else 1411150789Sglebius#endif 1412127901Sru /* 141341502Swpaul * Enable interrupts. 141441502Swpaul */ 141541502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 141641502Swpaul 141751432Swpaul mii_mediachg(mii); 141841502Swpaul 1419148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1420148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 142141502Swpaul 1422151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 142341502Swpaul} 142441502Swpaul 142541502Swpaul/* 142641502Swpaul * Set media options. 142741502Swpaul */ 1428102336Salfredstatic int 1429131503Sbmsvr_ifmedia_upd(struct ifnet *ifp) 143041502Swpaul{ 1431131503Sbms struct vr_softc *sc = ifp->if_softc; 143241502Swpaul 143351432Swpaul if (ifp->if_flags & IFF_UP) 143451432Swpaul vr_init(sc); 143541502Swpaul 1436131503Sbms return (0); 143741502Swpaul} 143841502Swpaul 143941502Swpaul/* 144041502Swpaul * Report current media status. 144141502Swpaul */ 1442102336Salfredstatic void 1443131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 144441502Swpaul{ 1445131518Sbms struct vr_softc *sc = ifp->if_softc; 144651432Swpaul struct mii_data *mii; 144741502Swpaul 144851432Swpaul mii = device_get_softc(sc->vr_miibus); 1449133468Sscottl VR_LOCK(sc); 145051432Swpaul mii_pollstat(mii); 1451133468Sscottl VR_UNLOCK(sc); 145251432Swpaul ifmr->ifm_active = mii->mii_media_active; 145351432Swpaul ifmr->ifm_status = mii->mii_media_status; 145441502Swpaul} 145541502Swpaul 1456102336Salfredstatic int 1457131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 145841502Swpaul{ 145941502Swpaul struct vr_softc *sc = ifp->if_softc; 146041502Swpaul struct ifreq *ifr = (struct ifreq *) data; 146151432Swpaul struct mii_data *mii; 146267087Swpaul int error = 0; 146341502Swpaul 1464131503Sbms switch (command) { 146541502Swpaul case SIOCSIFFLAGS: 1466131844Sbms VR_LOCK(sc); 146741502Swpaul if (ifp->if_flags & IFF_UP) { 1468131844Sbms vr_init_locked(sc); 146941502Swpaul } else { 1470148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 147141502Swpaul vr_stop(sc); 147241502Swpaul } 1473131844Sbms VR_UNLOCK(sc); 147441502Swpaul error = 0; 147541502Swpaul break; 147641502Swpaul case SIOCADDMULTI: 147741502Swpaul case SIOCDELMULTI: 1478131518Sbms VR_LOCK(sc); 147941502Swpaul vr_setmulti(sc); 1480131518Sbms VR_UNLOCK(sc); 148141502Swpaul error = 0; 148241502Swpaul break; 148341502Swpaul case SIOCGIFMEDIA: 148441502Swpaul case SIOCSIFMEDIA: 148551432Swpaul mii = device_get_softc(sc->vr_miibus); 148651432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 148741502Swpaul break; 1488128118Sru case SIOCSIFCAP: 1489150789Sglebius#ifdef DEVICE_POLLING 1490150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 1491150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 1492150789Sglebius error = ether_poll_register(vr_poll, ifp); 1493150789Sglebius if (error) 1494150789Sglebius return(error); 1495150789Sglebius VR_LOCK(sc); 1496150789Sglebius /* Disable interrupts */ 1497150789Sglebius CSR_WRITE_2(sc, VR_IMR, 0x0000); 1498150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 1499150789Sglebius VR_UNLOCK(sc); 1500150789Sglebius return (error); 1501150789Sglebius 1502150789Sglebius } 1503150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 1504150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 1505150789Sglebius error = ether_poll_deregister(ifp); 1506150789Sglebius /* Enable interrupts. */ 1507150789Sglebius VR_LOCK(sc); 1508150789Sglebius CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 1509150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 1510150789Sglebius VR_UNLOCK(sc); 1511150789Sglebius return (error); 1512150789Sglebius } 1513150789Sglebius#endif /* DEVICE_POLLING */ 1514168827Sphk ifp->if_capenable = ifr->ifr_reqcap; 1515168827Sphk if (ifp->if_capenable & IFCAP_TXCSUM) 1516168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 1517168827Sphk else 1518168827Sphk ifp->if_hwassist = 0; 1519128118Sru break; 152041502Swpaul default: 1521106936Ssam error = ether_ioctl(ifp, command, data); 152241502Swpaul break; 152341502Swpaul } 152441502Swpaul 1525131503Sbms return (error); 152641502Swpaul} 152741502Swpaul 1528102336Salfredstatic void 1529131503Sbmsvr_watchdog(struct ifnet *ifp) 153041502Swpaul{ 1531131518Sbms struct vr_softc *sc = ifp->if_softc; 153241502Swpaul 153367087Swpaul VR_LOCK(sc); 1534131844Sbms 153541502Swpaul ifp->if_oerrors++; 1536151773Sjhb if_printf(ifp, "watchdog timeout\n"); 153741502Swpaul 153841502Swpaul vr_stop(sc); 153941502Swpaul vr_reset(sc); 1540131844Sbms vr_init_locked(sc); 1541131518Sbms 1542132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1543131844Sbms vr_start_locked(ifp); 1544131844Sbms 1545131844Sbms VR_UNLOCK(sc); 154641502Swpaul} 154741502Swpaul 154841502Swpaul/* 154941502Swpaul * Stop the adapter and free any mbufs allocated to the 155041502Swpaul * RX and TX lists. 155141502Swpaul */ 1552102336Salfredstatic void 1553131503Sbmsvr_stop(struct vr_softc *sc) 155441502Swpaul{ 1555131503Sbms register int i; 1556131503Sbms struct ifnet *ifp; 155741502Swpaul 1558131518Sbms VR_LOCK_ASSERT(sc); 155967087Swpaul 1560147256Sbrooks ifp = sc->vr_ifp; 156141502Swpaul ifp->if_timer = 0; 156241502Swpaul 1563151911Sjhb callout_stop(&sc->vr_stat_callout); 1564148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 156551432Swpaul 156641502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 156741502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 156841502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 156941502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 157041502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 157141502Swpaul 157241502Swpaul /* 157341502Swpaul * Free data in the RX lists. 157441502Swpaul */ 1575168952Sphk for (i = 0; i < VR_RX_LIST_CNT; i++) 1576168952Sphk if (sc->vr_ldata->vr_rx_list[i].vr_mbuf != NULL) 1577168952Sphk m_freem(sc->vr_ldata->vr_rx_list[i].vr_mbuf); 157841502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 1579131517Sbms sizeof(sc->vr_ldata->vr_rx_list)); 158041502Swpaul 158141502Swpaul /* 158241502Swpaul * Free the TX list buffers. 158341502Swpaul */ 1584168952Sphk for (i = 0; i < VR_TX_LIST_CNT; i++) 1585168952Sphk if (sc->vr_ldata->vr_tx_list[i].vr_mbuf != NULL) 1586168952Sphk m_freem(sc->vr_ldata->vr_tx_list[i].vr_mbuf); 158741502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 1588131517Sbms sizeof(sc->vr_ldata->vr_tx_list)); 158941502Swpaul} 159041502Swpaul 159141502Swpaul/* 159241502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 159341502Swpaul * get confused by errant DMAs when rebooting. 159441502Swpaul */ 1595102336Salfredstatic void 1596131503Sbmsvr_shutdown(device_t dev) 159741502Swpaul{ 159841502Swpaul 1599136696Sbms vr_detach(dev); 160041502Swpaul} 1601