if_vr.c revision 168953
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 168953 2007-04-22 15:58:56Z 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 578151773Sjhb ifp->if_capenable = ifp->if_capabilities; 579168827Sphk if (ifp->if_capenable & IFCAP_TXCSUM) 580168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 581168827Sphk else 582168827Sphk ifp->if_hwassist = 0; 583168827Sphk 584151773Sjhb#ifdef DEVICE_POLLING 585151773Sjhb ifp->if_capabilities |= IFCAP_POLLING; 586151773Sjhb#endif 587151773Sjhb 58876586Swpaul /* 58976586Swpaul * Windows may put the chip in suspend mode when it 59076586Swpaul * shuts down. Be sure to kick it in the head to wake it 59176586Swpaul * up again. 59276586Swpaul */ 59376586Swpaul VR_CLRBIT(sc, VR_STICKHW, (VR_STICKHW_DS0|VR_STICKHW_DS1)); 59476586Swpaul 59541502Swpaul /* Reset the adapter. */ 59641502Swpaul vr_reset(sc); 59741502Swpaul 598131503Sbms /* 599110168Ssilby * Turn on bit2 (MIION) in PCI configuration register 0x53 during 600110168Ssilby * initialization and disable AUTOPOLL. 601110168Ssilby */ 602131503Sbms pci_write_config(dev, VR_PCI_MODE, 603110168Ssilby pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); 604110168Ssilby VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); 605110168Ssilby 60641502Swpaul /* 60741502Swpaul * Get station address. The way the Rhine chips work, 60841502Swpaul * you're not allowed to directly access the EEPROM once 60941502Swpaul * they've been programmed a special way. Consequently, 61041502Swpaul * we need to read the node address from the PAR0 and PAR1 61141502Swpaul * registers. 61241502Swpaul */ 61341502Swpaul VR_SETBIT(sc, VR_EECSR, VR_EECSR_LOAD); 61441502Swpaul DELAY(200); 61541502Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 61641502Swpaul eaddr[i] = CSR_READ_1(sc, VR_PAR0 + i); 61741502Swpaul 61851432Swpaul sc->vr_ldata = contigmalloc(sizeof(struct vr_list_data), M_DEVBUF, 619151773Sjhb M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0); 62051432Swpaul 62151432Swpaul if (sc->vr_ldata == NULL) { 622151773Sjhb device_printf(dev, "no memory for list buffers!\n"); 62349610Swpaul error = ENXIO; 62449610Swpaul goto fail; 62541502Swpaul } 62641502Swpaul 627131503Sbms /* Do MII setup. */ 62851432Swpaul if (mii_phy_probe(dev, &sc->vr_miibus, 62951432Swpaul vr_ifmedia_upd, vr_ifmedia_sts)) { 630151773Sjhb device_printf(dev, "MII without any phy!\n"); 63149610Swpaul error = ENXIO; 63241502Swpaul goto fail; 63341502Swpaul } 63441502Swpaul 635131503Sbms /* Call MI attach routine. */ 636106936Ssam ether_ifattach(ifp, eaddr); 63741502Swpaul 638168948Sphk sc->vr_suspended = 0; 639131844Sbms 640113609Snjl /* Hook interrupt last to avoid having to lock softc */ 641131518Sbms error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, 642166901Spiso NULL, vr_intr, sc, &sc->vr_intrhand); 643112872Snjl 644112872Snjl if (error) { 645151773Sjhb device_printf(dev, "couldn't set up irq\n"); 646113609Snjl ether_ifdetach(ifp); 647112872Snjl goto fail; 648112872Snjl } 649112872Snjl 65041502Swpaulfail: 651112872Snjl if (error) 652112872Snjl vr_detach(dev); 65367087Swpaul 654131503Sbms return (error); 65541502Swpaul} 65641502Swpaul 657113609Snjl/* 658113609Snjl * Shutdown hardware and free up resources. This can be called any 659113609Snjl * time after the mutex has been initialized. It is called in both 660113609Snjl * the error case in attach and the normal detach case so it needs 661113609Snjl * to be careful about only freeing resources that have actually been 662113609Snjl * allocated. 663113609Snjl */ 664102336Salfredstatic int 665131503Sbmsvr_detach(device_t dev) 66649610Swpaul{ 667131503Sbms struct vr_softc *sc = device_get_softc(dev); 668147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 66949610Swpaul 670112880Sjhb KASSERT(mtx_initialized(&sc->vr_mtx), ("vr mutex not initialized")); 671131518Sbms 672150789Sglebius#ifdef DEVICE_POLLING 673150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 674150789Sglebius ether_poll_deregister(ifp); 675150789Sglebius#endif 676150789Sglebius 677113609Snjl /* These should only be active if attach succeeded */ 678113812Simp if (device_is_attached(dev)) { 679151911Sjhb VR_LOCK(sc); 680168948Sphk sc->vr_suspended = 1; 681113609Snjl vr_stop(sc); 682151911Sjhb VR_UNLOCK(sc); 683151911Sjhb callout_drain(&sc->vr_stat_callout); 684112872Snjl ether_ifdetach(ifp); 685113609Snjl } 686113609Snjl if (sc->vr_miibus) 687112872Snjl device_delete_child(dev, sc->vr_miibus); 688113609Snjl bus_generic_detach(dev); 68949610Swpaul 690112872Snjl if (sc->vr_intrhand) 691112872Snjl bus_teardown_intr(dev, sc->vr_irq, sc->vr_intrhand); 692112872Snjl if (sc->vr_irq) 693112872Snjl bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vr_irq); 694112872Snjl if (sc->vr_res) 695112872Snjl bus_release_resource(dev, VR_RES, VR_RID, sc->vr_res); 69651432Swpaul 697151297Sru if (ifp) 698151297Sru if_free(ifp); 699151297Sru 700112872Snjl if (sc->vr_ldata) 701112872Snjl contigfree(sc->vr_ldata, sizeof(struct vr_list_data), M_DEVBUF); 70249610Swpaul 70367087Swpaul mtx_destroy(&sc->vr_mtx); 70449610Swpaul 705131503Sbms return (0); 70649610Swpaul} 70749610Swpaul 70841502Swpaul/* 70941502Swpaul * Initialize the transmit descriptors. 71041502Swpaul */ 711102336Salfredstatic int 712131503Sbmsvr_list_tx_init(struct vr_softc *sc) 71341502Swpaul{ 71441502Swpaul struct vr_list_data *ld; 71541502Swpaul int i; 71641502Swpaul 71741502Swpaul ld = sc->vr_ldata; 71841502Swpaul for (i = 0; i < VR_TX_LIST_CNT; i++) { 719168950Sphk if (i == (VR_TX_LIST_CNT - 1)) { 720168952Sphk ld->vr_tx_list[i].vr_next = 721168952Sphk &ld->vr_tx_list[0]; 722168950Sphk ld->vr_tx_list[i].vr_nextphys = 723168950Sphk vtophys(&ld->vr_tx_list[0]); 724168950Sphk } else { 725168952Sphk ld->vr_tx_list[i].vr_next = 726168952Sphk &ld->vr_tx_list[i + 1]; 727168950Sphk ld->vr_tx_list[i].vr_nextphys = 728168950Sphk vtophys(&ld->vr_tx_list[i + 1]); 729168950Sphk } 73041502Swpaul } 731168952Sphk sc->vr_tx_cons = sc->vr_tx_prod = &ld->vr_tx_list[0]; 73241502Swpaul 733131503Sbms return (0); 73441502Swpaul} 73541502Swpaul 73641502Swpaul 73741502Swpaul/* 73841502Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 73941502Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 74041502Swpaul * points back to the first. 74141502Swpaul */ 742102336Salfredstatic int 743131503Sbmsvr_list_rx_init(struct vr_softc *sc) 74441502Swpaul{ 74541502Swpaul struct vr_list_data *ld; 74641502Swpaul int i; 74741502Swpaul 748131518Sbms VR_LOCK_ASSERT(sc); 749131518Sbms 75041502Swpaul ld = sc->vr_ldata; 75141502Swpaul 75241502Swpaul for (i = 0; i < VR_RX_LIST_CNT; i++) { 753168952Sphk if (vr_newbuf(&ld->vr_rx_list[i], NULL) == ENOBUFS) 754131503Sbms return (ENOBUFS); 75541502Swpaul if (i == (VR_RX_LIST_CNT - 1)) { 756168952Sphk ld->vr_rx_list[i].vr_next = &ld->vr_rx_list[0]; 757168948Sphk ld->vr_rx_list[i].vr_nextphys = 75841502Swpaul vtophys(&ld->vr_rx_list[0]); 75941502Swpaul } else { 760168952Sphk ld->vr_rx_list[i].vr_next = 761168952Sphk &ld->vr_rx_list[i + 1]; 762168948Sphk ld->vr_rx_list[i].vr_nextphys = 76341502Swpaul vtophys(&ld->vr_rx_list[i + 1]); 76441502Swpaul } 76541502Swpaul } 76641502Swpaul 767168952Sphk sc->vr_rx_head = &ld->vr_rx_list[0]; 76841502Swpaul 769131503Sbms return (0); 77041502Swpaul} 77141502Swpaul 77241502Swpaul/* 77341502Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 77441502Swpaul * Note: the length fields are only 11 bits wide, which means the 77541502Swpaul * largest size we can specify is 2047. This is important because 77641502Swpaul * MCLBYTES is 2048, so we have to subtract one otherwise we'll 77741502Swpaul * overflow the field and make a mess. 77841502Swpaul */ 779102336Salfredstatic int 780168952Sphkvr_newbuf(struct vr_desc *c, struct mbuf *m) 78141502Swpaul{ 78241502Swpaul struct mbuf *m_new = NULL; 78341502Swpaul 78449610Swpaul if (m == NULL) { 785168952Sphk m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 78687846Sluigi if (m_new == NULL) 787131503Sbms return (ENOBUFS); 78849610Swpaul } else { 78949610Swpaul m_new = m; 79049610Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 79149610Swpaul m_new->m_data = m_new->m_ext.ext_buf; 79241502Swpaul } 79341502Swpaul 794131503Sbms m_adj(m_new, sizeof(uint64_t)); 79549610Swpaul 79641502Swpaul c->vr_mbuf = m_new; 797168952Sphk c->vr_status = VR_RXSTAT; 798168952Sphk c->vr_data = vtophys(mtod(m_new, caddr_t)); 799168952Sphk c->vr_ctl = VR_RXCTL | VR_RXLEN; 80041502Swpaul 801131503Sbms return (0); 80241502Swpaul} 80341502Swpaul 80441502Swpaul/* 80541502Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 80641502Swpaul * the higher level protocols. 80741502Swpaul */ 808102336Salfredstatic void 809131503Sbmsvr_rxeof(struct vr_softc *sc) 81041502Swpaul{ 811131503Sbms struct mbuf *m, *m0; 812131503Sbms struct ifnet *ifp; 813168952Sphk struct vr_desc *cur_rx; 81441502Swpaul int total_len = 0; 815168827Sphk uint32_t rxstat, rxctl; 81641502Swpaul 817122689Ssam VR_LOCK_ASSERT(sc); 818147256Sbrooks ifp = sc->vr_ifp; 81941502Swpaul 820168952Sphk while (!((rxstat = sc->vr_rx_head->vr_status) & 821131503Sbms VR_RXSTAT_OWN)) { 822127901Sru#ifdef DEVICE_POLLING 823150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 824127901Sru if (sc->rxcycles <= 0) 825127901Sru break; 826127901Sru sc->rxcycles--; 827127901Sru } 828150789Sglebius#endif 829127901Sru m0 = NULL; 830168952Sphk cur_rx = sc->vr_rx_head; 831168952Sphk sc->vr_rx_head = cur_rx->vr_next; 83249610Swpaul m = cur_rx->vr_mbuf; 83341502Swpaul 83441502Swpaul /* 83541502Swpaul * If an error occurs, update stats, clear the 83641502Swpaul * status word and leave the mbuf cluster in place: 83741502Swpaul * it should simply get re-used next time this descriptor 838131503Sbms * comes up in the ring. 83941502Swpaul */ 84041502Swpaul if (rxstat & VR_RXSTAT_RXERR) { 84141502Swpaul ifp->if_ierrors++; 842162315Sglebius device_printf(sc->vr_dev, 843162315Sglebius "rx error (%02x):", rxstat & 0x000000ff); 844110131Ssilby if (rxstat & VR_RXSTAT_CRCERR) 845110131Ssilby printf(" crc error"); 846110131Ssilby if (rxstat & VR_RXSTAT_FRAMEALIGNERR) 847110131Ssilby printf(" frame alignment error\n"); 848110131Ssilby if (rxstat & VR_RXSTAT_FIFOOFLOW) 849110131Ssilby printf(" FIFO overflow"); 850110131Ssilby if (rxstat & VR_RXSTAT_GIANT) 851110131Ssilby printf(" received giant packet"); 852110131Ssilby if (rxstat & VR_RXSTAT_RUNT) 853110131Ssilby printf(" received runt packet"); 854110131Ssilby if (rxstat & VR_RXSTAT_BUSERR) 855110131Ssilby printf(" system bus error"); 856110131Ssilby if (rxstat & VR_RXSTAT_BUFFERR) 857110131Ssilby printf("rx buffer error"); 858110131Ssilby printf("\n"); 859168946Sphk vr_newbuf(cur_rx, m); 86041502Swpaul continue; 86141502Swpaul } 86241502Swpaul 863131503Sbms /* No errors; receive the packet. */ 864168952Sphk total_len = VR_RXBYTES(cur_rx->vr_status); 865168827Sphk if (ifp->if_capenable & IFCAP_RXCSUM) { 866168952Sphk rxctl = cur_rx->vr_ctl; 867168827Sphk if ((rxctl & VR_RXCTL_GOODIP) == VR_RXCTL_GOODIP) 868168827Sphk m->m_pkthdr.csum_flags |= 869168827Sphk CSUM_IP_CHECKED | CSUM_IP_VALID; 870168827Sphk if ((rxctl & VR_RXCTL_GOODTCPUDP)) { 871168827Sphk m->m_pkthdr.csum_flags |= 872168827Sphk CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 873168827Sphk m->m_pkthdr.csum_data = 0xffff; 874168827Sphk } 875168827Sphk } 87641502Swpaul 87741502Swpaul /* 87842048Swpaul * XXX The VIA Rhine chip includes the CRC with every 87942048Swpaul * received frame, and there's no way to turn this 88042048Swpaul * behavior off (at least, I can't find anything in 881131503Sbms * the manual that explains how to do it) so we have 88242048Swpaul * to trim off the CRC manually. 88342048Swpaul */ 88442048Swpaul total_len -= ETHER_CRC_LEN; 88542048Swpaul 88678508Sbmilekic m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, 88778508Sbmilekic NULL); 888168946Sphk vr_newbuf(cur_rx, m); 88949610Swpaul if (m0 == NULL) { 89041502Swpaul ifp->if_ierrors++; 89141502Swpaul continue; 89241502Swpaul } 89349610Swpaul m = m0; 89441502Swpaul 89541502Swpaul ifp->if_ipackets++; 896122689Ssam VR_UNLOCK(sc); 897106936Ssam (*ifp->if_input)(ifp, m); 898122689Ssam VR_LOCK(sc); 89941502Swpaul } 90041502Swpaul} 90141502Swpaul 902105221Sphkstatic void 903131503Sbmsvr_rxeoc(struct vr_softc *sc) 90441502Swpaul{ 905147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 906110131Ssilby int i; 90741502Swpaul 908131518Sbms VR_LOCK_ASSERT(sc); 909131518Sbms 910110131Ssilby ifp->if_ierrors++; 911110131Ssilby 912131503Sbms VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 913131503Sbms DELAY(10000); 914110131Ssilby 915131503Sbms /* Wait for receiver to stop */ 916110131Ssilby for (i = 0x400; 917110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); 918131503Sbms i--) { 919131503Sbms ; 920131503Sbms } 921110131Ssilby 922110131Ssilby if (!i) { 923162315Sglebius device_printf(sc->vr_dev, "rx shutdown error!\n"); 924110131Ssilby sc->vr_flags |= VR_F_RESTART; 925110131Ssilby return; 926131503Sbms } 927110131Ssilby 92841502Swpaul vr_rxeof(sc); 929110131Ssilby 930168952Sphk CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head)); 93141502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); 93241502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); 93341502Swpaul} 93441502Swpaul 93541502Swpaul/* 93641502Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 93741502Swpaul * the list buffers. 93841502Swpaul */ 939102336Salfredstatic void 940131503Sbmsvr_txeof(struct vr_softc *sc) 94141502Swpaul{ 942168952Sphk struct vr_desc *cur_tx; 943147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 94441502Swpaul 945131518Sbms VR_LOCK_ASSERT(sc); 94641502Swpaul 94741502Swpaul /* 94841502Swpaul * Go through our tx list and free mbufs for those 94941502Swpaul * frames that have been transmitted. 95041502Swpaul */ 951168952Sphk cur_tx = sc->vr_tx_cons; 952168952Sphk while (cur_tx != sc->vr_tx_prod) { 953131503Sbms uint32_t txstat; 954110131Ssilby int i; 95541502Swpaul 956168952Sphk txstat = cur_tx->vr_status; 95741502Swpaul 958101896Ssilby if ((txstat & VR_TXSTAT_ABRT) || 959101896Ssilby (txstat & VR_TXSTAT_UDF)) { 960110131Ssilby for (i = 0x400; 961110131Ssilby i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); 962110131Ssilby i--) 963101896Ssilby ; /* Wait for chip to shutdown */ 964110131Ssilby if (!i) { 965162315Sglebius device_printf(sc->vr_dev, "tx shutdown timeout\n"); 966110131Ssilby sc->vr_flags |= VR_F_RESTART; 967110131Ssilby break; 968110131Ssilby } 969168952Sphk atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN); 970168952Sphk CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx)); 971101896Ssilby break; 972101896Ssilby } 973101896Ssilby 97442491Swpaul if (txstat & VR_TXSTAT_OWN) 97541502Swpaul break; 97641502Swpaul 97741502Swpaul if (txstat & VR_TXSTAT_ERRSUM) { 97841502Swpaul ifp->if_oerrors++; 97941502Swpaul if (txstat & VR_TXSTAT_DEFER) 98041502Swpaul ifp->if_collisions++; 98141502Swpaul if (txstat & VR_TXSTAT_LATECOLL) 98241502Swpaul ifp->if_collisions++; 98341502Swpaul } 98441502Swpaul 98541502Swpaul ifp->if_collisions +=(txstat & VR_TXSTAT_COLLCNT) >> 3; 98641502Swpaul 98741502Swpaul ifp->if_opackets++; 988168813Sphk if (cur_tx->vr_mbuf != NULL) 989168813Sphk m_freem(cur_tx->vr_mbuf); 990127901Sru cur_tx->vr_mbuf = NULL; 991148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 99241502Swpaul 993168952Sphk cur_tx = cur_tx->vr_next; 99441502Swpaul } 995168952Sphk sc->vr_tx_cons = cur_tx; 996127901Sru if (cur_tx->vr_mbuf == NULL) 99796677Ssilby ifp->if_timer = 0; 99841502Swpaul} 99941502Swpaul 1000102336Salfredstatic void 1001131503Sbmsvr_tick(void *xsc) 100251432Swpaul{ 1003131503Sbms struct vr_softc *sc = xsc; 100451432Swpaul struct mii_data *mii; 100551432Swpaul 1006151911Sjhb VR_LOCK_ASSERT(sc); 1007131517Sbms 1008110131Ssilby if (sc->vr_flags & VR_F_RESTART) { 1009162315Sglebius device_printf(sc->vr_dev, "restarting\n"); 1010110131Ssilby vr_stop(sc); 1011110131Ssilby vr_reset(sc); 1012131844Sbms vr_init_locked(sc); 1013110131Ssilby sc->vr_flags &= ~VR_F_RESTART; 1014110131Ssilby } 1015110131Ssilby 101651432Swpaul mii = device_get_softc(sc->vr_miibus); 101751432Swpaul mii_tick(mii); 1018151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 101951432Swpaul} 102051432Swpaul 1021127901Sru#ifdef DEVICE_POLLING 1022127901Srustatic poll_handler_t vr_poll; 1023131844Sbmsstatic poll_handler_t vr_poll_locked; 1024127901Sru 1025102336Salfredstatic void 1026127901Sruvr_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1027127901Sru{ 1028127901Sru struct vr_softc *sc = ifp->if_softc; 1029127901Sru 1030127901Sru VR_LOCK(sc); 1031150789Sglebius if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1032150789Sglebius vr_poll_locked(ifp, cmd, count); 1033131844Sbms VR_UNLOCK(sc); 1034131844Sbms} 1035131517Sbms 1036131844Sbmsstatic void 1037131844Sbmsvr_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1038131844Sbms{ 1039131844Sbms struct vr_softc *sc = ifp->if_softc; 1040131844Sbms 1041131844Sbms VR_LOCK_ASSERT(sc); 1042131844Sbms 1043127901Sru sc->rxcycles = count; 1044127901Sru vr_rxeof(sc); 1045127901Sru vr_txeof(sc); 1046133006Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1047131844Sbms vr_start_locked(ifp); 1048127901Sru 1049131503Sbms if (cmd == POLL_AND_CHECK_STATUS) { 1050131503Sbms uint16_t status; 1051127901Sru 1052131503Sbms /* Also check status register. */ 1053127901Sru status = CSR_READ_2(sc, VR_ISR); 1054127901Sru if (status) 1055127901Sru CSR_WRITE_2(sc, VR_ISR, status); 1056127901Sru 1057127901Sru if ((status & VR_INTRS) == 0) 1058131844Sbms return; 1059127901Sru 1060127901Sru if (status & VR_ISR_RX_DROPPED) { 1061151773Sjhb if_printf(ifp, "rx packet lost\n"); 1062127901Sru ifp->if_ierrors++; 1063127901Sru } 1064127901Sru 1065127901Sru if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1066127901Sru (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1067151773Sjhb if_printf(ifp, "receive error (%04x)", status); 1068127901Sru if (status & VR_ISR_RX_NOBUF) 1069127901Sru printf(" no buffers"); 1070127901Sru if (status & VR_ISR_RX_OFLOW) 1071127901Sru printf(" overflow"); 1072127901Sru if (status & VR_ISR_RX_DROPPED) 1073127901Sru printf(" packet lost"); 1074127901Sru printf("\n"); 1075127901Sru vr_rxeoc(sc); 1076127901Sru } 1077127901Sru 1078131503Sbms if ((status & VR_ISR_BUSERR) || 1079131503Sbms (status & VR_ISR_TX_UNDERRUN)) { 1080127901Sru vr_reset(sc); 1081131844Sbms vr_init_locked(sc); 1082131518Sbms return; 1083127901Sru } 1084127901Sru 1085127901Sru if ((status & VR_ISR_UDFI) || 1086127901Sru (status & VR_ISR_TX_ABRT2) || 1087127901Sru (status & VR_ISR_TX_ABRT)) { 1088127901Sru ifp->if_oerrors++; 1089168952Sphk if (sc->vr_tx_cons->vr_mbuf != NULL) { 1090127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); 1091127901Sru VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); 1092127901Sru } 1093127901Sru } 1094127901Sru } 1095127901Sru} 1096127901Sru#endif /* DEVICE_POLLING */ 1097127901Sru 1098127901Srustatic void 1099131503Sbmsvr_intr(void *arg) 110041502Swpaul{ 1101131503Sbms struct vr_softc *sc = arg; 1102147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 1103131503Sbms uint16_t status; 110441502Swpaul 110567087Swpaul VR_LOCK(sc); 1106131844Sbms 1107168948Sphk if (sc->vr_suspended) { 1108136997Sbms /* 1109136997Sbms * Forcibly disable interrupts. 1110136997Sbms * XXX: Mobile VIA based platforms may need 1111136997Sbms * interrupt re-enable on resume. 1112136997Sbms */ 1113136997Sbms CSR_WRITE_2(sc, VR_IMR, 0x0000); 1114131844Sbms goto done_locked; 1115136997Sbms } 1116131844Sbms 1117127901Sru#ifdef DEVICE_POLLING 1118150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1119131844Sbms goto done_locked; 1120150789Sglebius#endif 1121131844Sbms 1122131844Sbms /* Suppress unwanted interrupts. */ 112341502Swpaul if (!(ifp->if_flags & IFF_UP)) { 112441502Swpaul vr_stop(sc); 1125131844Sbms goto done_locked; 112641502Swpaul } 112741502Swpaul 112841502Swpaul /* Disable interrupts. */ 112941502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 113041502Swpaul 113141502Swpaul for (;;) { 113241502Swpaul status = CSR_READ_2(sc, VR_ISR); 1133168813Sphk 113441502Swpaul if (status) 113541502Swpaul CSR_WRITE_2(sc, VR_ISR, status); 113641502Swpaul 113741502Swpaul if ((status & VR_INTRS) == 0) 113841502Swpaul break; 113941502Swpaul 114041502Swpaul if (status & VR_ISR_RX_OK) 114141502Swpaul vr_rxeof(sc); 114241502Swpaul 1143110131Ssilby if (status & VR_ISR_RX_DROPPED) { 1144162315Sglebius device_printf(sc->vr_dev, "rx packet lost\n"); 1145110131Ssilby ifp->if_ierrors++; 1146131503Sbms } 1147110131Ssilby 114841502Swpaul if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || 1149110131Ssilby (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { 1150162315Sglebius device_printf(sc->vr_dev, "receive error (%04x)", status); 1151110131Ssilby if (status & VR_ISR_RX_NOBUF) 1152110131Ssilby printf(" no buffers"); 1153110131Ssilby if (status & VR_ISR_RX_OFLOW) 1154110131Ssilby printf(" overflow"); 1155110131Ssilby if (status & VR_ISR_RX_DROPPED) 1156110131Ssilby printf(" packet lost"); 1157110131Ssilby printf("\n"); 115841502Swpaul vr_rxeoc(sc); 115941502Swpaul } 116041502Swpaul 1161101896Ssilby if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { 1162101896Ssilby vr_reset(sc); 1163131844Sbms vr_init_locked(sc); 1164101896Ssilby break; 116541502Swpaul } 116641502Swpaul 1167101896Ssilby if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || 1168101896Ssilby (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { 116941502Swpaul vr_txeof(sc); 1170101896Ssilby if ((status & VR_ISR_UDFI) || 1171101896Ssilby (status & VR_ISR_TX_ABRT2) || 1172101896Ssilby (status & VR_ISR_TX_ABRT)) { 1173101896Ssilby ifp->if_oerrors++; 1174168952Sphk if (sc->vr_tx_cons->vr_mbuf != NULL) { 1175131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1176131503Sbms VR_CMD_TX_ON); 1177131503Sbms VR_SETBIT16(sc, VR_COMMAND, 1178131503Sbms VR_CMD_TX_GO); 1179101896Ssilby } 1180127901Sru } 118141502Swpaul } 118241502Swpaul } 118341502Swpaul 118441502Swpaul /* Re-enable interrupts. */ 118541502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 118641502Swpaul 1187132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1188131844Sbms vr_start_locked(ifp); 1189131844Sbms 1190131844Sbmsdone_locked: 1191131844Sbms VR_UNLOCK(sc); 119241502Swpaul} 119341502Swpaul 119441502Swpaul/* 119541502Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 119641502Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 119741502Swpaul * copy of the pointers since the transmit list fragment pointers are 119841502Swpaul * physical addresses. 119941502Swpaul */ 120041502Swpaul 1201102336Salfredstatic void 1202131503Sbmsvr_start(struct ifnet *ifp) 120341502Swpaul{ 1204131518Sbms struct vr_softc *sc = ifp->if_softc; 1205131844Sbms 1206131844Sbms VR_LOCK(sc); 1207131844Sbms vr_start_locked(ifp); 1208131844Sbms VR_UNLOCK(sc); 1209131844Sbms} 1210131844Sbms 1211131844Sbmsstatic void 1212131844Sbmsvr_start_locked(struct ifnet *ifp) 1213131844Sbms{ 1214131844Sbms struct vr_softc *sc = ifp->if_softc; 1215168813Sphk struct mbuf *m, *m_head; 1216168952Sphk struct vr_desc *cur_tx, *n_tx; 1217168813Sphk struct vr_desc *f = NULL; 1218168813Sphk uint32_t cval; 121941502Swpaul 1220148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 1221127901Sru return; 1222127901Sru 1223168952Sphk for (cur_tx = sc->vr_tx_prod; 1224168952Sphk cur_tx->vr_next != sc->vr_tx_cons; ) { 1225132986Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 122641502Swpaul if (m_head == NULL) 122741502Swpaul break; 122841502Swpaul 1229168813Sphk VR_LOCK_ASSERT(sc); 1230168813Sphk /* 1231168813Sphk * Some VIA Rhine wants packet buffers to be longword 1232168813Sphk * aligned, but very often our mbufs aren't. Rather than 1233168813Sphk * waste time trying to decide when to copy and when not 1234168813Sphk * to copy, just do it all the time. 1235168813Sphk */ 1236168827Sphk if (sc->vr_quirks & VR_Q_NEEDALIGN) { 1237168813Sphk m = m_defrag(m_head, M_DONTWAIT); 1238168813Sphk if (m == NULL) { 1239168813Sphk /* Rollback, send what we were able to encap. */ 1240168813Sphk IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1241168813Sphk break; 1242168813Sphk } 1243168813Sphk m_head = m; 1244168813Sphk } 124541502Swpaul 124641502Swpaul /* 1247168813Sphk * The Rhine chip doesn't auto-pad, so we have to make 1248168813Sphk * sure to pad short frames out to the minimum frame length 1249168813Sphk * ourselves. 125041502Swpaul */ 1251168813Sphk if (m_head->m_pkthdr.len < VR_MIN_FRAMELEN) { 1252168813Sphk if (m_head->m_next != NULL) 1253168813Sphk m_head = m_defrag(m_head, M_DONTWAIT); 1254168813Sphk m_head->m_pkthdr.len += VR_MIN_FRAMELEN - m_head->m_len; 1255168813Sphk m_head->m_len = m_head->m_pkthdr.len; 1256168813Sphk /* XXX: bzero the padding bytes */ 1257168813Sphk } 125851583Swpaul 1259168813Sphk n_tx = cur_tx; 1260168813Sphk for (m = m_head; m != NULL; m = m->m_next) { 1261168813Sphk if (m->m_len == 0) 1262168813Sphk continue; 1263168952Sphk if (n_tx->vr_next == sc->vr_tx_cons) { 1264168813Sphk IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1265168952Sphk sc->vr_tx_prod = cur_tx; 1266168813Sphk return; 1267168813Sphk } 1268168813Sphk KASSERT(n_tx->vr_mbuf == NULL, ("if_vr_tx overrun")); 1269168813Sphk 1270168952Sphk f = n_tx; 1271168813Sphk f->vr_data = vtophys(mtod(m, caddr_t)); 1272168813Sphk cval = m->m_len; 1273168813Sphk cval |= VR_TXCTL_TLINK; 1274168827Sphk 1275168827Sphk if ((ifp->if_capenable & IFCAP_TXCSUM) && 1276168827Sphk m_head->m_pkthdr.csum_flags) { 1277168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_IP) 1278168827Sphk cval |= VR_TXCTL_IPCSUM; 1279168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 1280168827Sphk cval |= VR_TXCTL_TCPCSUM; 1281168827Sphk if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 1282168827Sphk cval |= VR_TXCTL_UDPCSUM; 1283168827Sphk } 1284168827Sphk 1285168813Sphk if (m == m_head) 1286168813Sphk cval |= VR_TXCTL_FIRSTFRAG; 1287168813Sphk f->vr_ctl = cval; 1288168813Sphk f->vr_status = 0; 1289168952Sphk n_tx = n_tx->vr_next; 1290168813Sphk } 129141502Swpaul 1292168946Sphk KASSERT(f != NULL, ("if_vr: no packet processed")); 1293168813Sphk f->vr_ctl |= VR_TXCTL_LASTFRAG|VR_TXCTL_FINT; 1294168813Sphk cur_tx->vr_mbuf = m_head; 1295168952Sphk atomic_set_acq_32(&cur_tx->vr_status, VR_TXSTAT_OWN); 1296168813Sphk 1297127901Sru /* Tell the chip to start transmitting. */ 1298131517Sbms VR_SETBIT16(sc, VR_COMMAND, /*VR_CMD_TX_ON|*/ VR_CMD_TX_GO); 129941526Swpaul 1300168813Sphk ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1301127901Sru ifp->if_timer = 5; 130241502Swpaul 1303168813Sphk /* 1304168813Sphk * If there's a BPF listener, bounce a copy of this frame 1305168813Sphk * to him. 1306168813Sphk */ 1307168813Sphk BPF_MTAP(ifp, m_head); 1308168813Sphk cur_tx = n_tx; 1309127901Sru } 1310168952Sphk sc->vr_tx_prod = cur_tx; 1311131844Sbms} 131241502Swpaul 1313131844Sbmsstatic void 1314131844Sbmsvr_init(void *xsc) 1315131844Sbms{ 1316131844Sbms struct vr_softc *sc = xsc; 1317131844Sbms 1318131844Sbms VR_LOCK(sc); 1319131844Sbms vr_init_locked(sc); 132067087Swpaul VR_UNLOCK(sc); 132141502Swpaul} 132241502Swpaul 1323102336Salfredstatic void 1324131844Sbmsvr_init_locked(struct vr_softc *sc) 132541502Swpaul{ 1326147256Sbrooks struct ifnet *ifp = sc->vr_ifp; 132751432Swpaul struct mii_data *mii; 132873963Swpaul int i; 132941502Swpaul 1330131844Sbms VR_LOCK_ASSERT(sc); 133141502Swpaul 133251432Swpaul mii = device_get_softc(sc->vr_miibus); 133341502Swpaul 1334131503Sbms /* Cancel pending I/O and free all RX/TX buffers. */ 133541502Swpaul vr_stop(sc); 133641502Swpaul vr_reset(sc); 133741502Swpaul 1338131503Sbms /* Set our station address. */ 133973963Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) 1340152315Sru CSR_WRITE_1(sc, VR_PAR0 + i, IF_LLADDR(sc->vr_ifp)[i]); 1341131503Sbms 1342131503Sbms /* Set DMA size. */ 1343101375Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); 1344101375Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); 134573963Swpaul 1346131503Sbms /* 1347101375Ssilby * BCR0 and BCR1 can override the RXCFG and TXCFG registers, 1348101108Ssilby * so we must set both. 1349101108Ssilby */ 1350101108Ssilby VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); 1351110131Ssilby VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); 1352101108Ssilby 1353101108Ssilby VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); 1354101108Ssilby VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); 1355101108Ssilby 135641502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); 1357110131Ssilby VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); 135841502Swpaul 135941502Swpaul VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); 136041502Swpaul VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); 136141502Swpaul 136241502Swpaul /* Init circular RX list. */ 136341502Swpaul if (vr_list_rx_init(sc) == ENOBUFS) { 1364162315Sglebius device_printf(sc->vr_dev, 1365151773Sjhb "initialization failed: no memory for rx buffers\n"); 136641502Swpaul vr_stop(sc); 136741502Swpaul return; 136841502Swpaul } 136941502Swpaul 1370131503Sbms /* Init tx descriptors. */ 137141502Swpaul vr_list_tx_init(sc); 137241502Swpaul 137341502Swpaul /* If we want promiscuous mode, set the allframes bit. */ 137441502Swpaul if (ifp->if_flags & IFF_PROMISC) 137541502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 137641502Swpaul else 137741502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_PROMISC); 137841502Swpaul 137941502Swpaul /* Set capture broadcast bit to capture broadcast frames. */ 138041502Swpaul if (ifp->if_flags & IFF_BROADCAST) 138141502Swpaul VR_SETBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 138241502Swpaul else 138341502Swpaul VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_BROAD); 138441502Swpaul 138541502Swpaul /* 138641502Swpaul * Program the multicast filter, if necessary. 138741502Swpaul */ 138841502Swpaul vr_setmulti(sc); 138941502Swpaul 139041502Swpaul /* 139141502Swpaul * Load the address of the RX list. 139241502Swpaul */ 1393168952Sphk CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_rx_head)); 139441502Swpaul 139541502Swpaul /* Enable receiver and transmitter. */ 139641502Swpaul CSR_WRITE_2(sc, VR_COMMAND, VR_CMD_TX_NOPOLL|VR_CMD_START| 139741502Swpaul VR_CMD_TX_ON|VR_CMD_RX_ON| 139841502Swpaul VR_CMD_RX_GO); 139941502Swpaul 140041502Swpaul CSR_WRITE_4(sc, VR_TXADDR, vtophys(&sc->vr_ldata->vr_tx_list[0])); 140141502Swpaul 1402127901Sru CSR_WRITE_2(sc, VR_ISR, 0xFFFF); 1403127901Sru#ifdef DEVICE_POLLING 140441502Swpaul /* 1405127901Sru * Disable interrupts if we are polling. 1406127901Sru */ 1407150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1408127901Sru CSR_WRITE_2(sc, VR_IMR, 0); 1409131503Sbms else 1410150789Sglebius#endif 1411127901Sru /* 141241502Swpaul * Enable interrupts. 141341502Swpaul */ 141441502Swpaul CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 141541502Swpaul 141651432Swpaul mii_mediachg(mii); 141741502Swpaul 1418148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1419148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 142041502Swpaul 1421151911Sjhb callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); 142241502Swpaul} 142341502Swpaul 142441502Swpaul/* 142541502Swpaul * Set media options. 142641502Swpaul */ 1427102336Salfredstatic int 1428131503Sbmsvr_ifmedia_upd(struct ifnet *ifp) 142941502Swpaul{ 1430131503Sbms struct vr_softc *sc = ifp->if_softc; 143141502Swpaul 143251432Swpaul if (ifp->if_flags & IFF_UP) 143351432Swpaul vr_init(sc); 143441502Swpaul 1435131503Sbms return (0); 143641502Swpaul} 143741502Swpaul 143841502Swpaul/* 143941502Swpaul * Report current media status. 144041502Swpaul */ 1441102336Salfredstatic void 1442131503Sbmsvr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 144341502Swpaul{ 1444131518Sbms struct vr_softc *sc = ifp->if_softc; 144551432Swpaul struct mii_data *mii; 144641502Swpaul 144751432Swpaul mii = device_get_softc(sc->vr_miibus); 1448133468Sscottl VR_LOCK(sc); 144951432Swpaul mii_pollstat(mii); 1450133468Sscottl VR_UNLOCK(sc); 145151432Swpaul ifmr->ifm_active = mii->mii_media_active; 145251432Swpaul ifmr->ifm_status = mii->mii_media_status; 145341502Swpaul} 145441502Swpaul 1455102336Salfredstatic int 1456131503Sbmsvr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 145741502Swpaul{ 145841502Swpaul struct vr_softc *sc = ifp->if_softc; 145941502Swpaul struct ifreq *ifr = (struct ifreq *) data; 146051432Swpaul struct mii_data *mii; 146167087Swpaul int error = 0; 146241502Swpaul 1463131503Sbms switch (command) { 146441502Swpaul case SIOCSIFFLAGS: 1465131844Sbms VR_LOCK(sc); 146641502Swpaul if (ifp->if_flags & IFF_UP) { 1467131844Sbms vr_init_locked(sc); 146841502Swpaul } else { 1469148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 147041502Swpaul vr_stop(sc); 147141502Swpaul } 1472131844Sbms VR_UNLOCK(sc); 147341502Swpaul error = 0; 147441502Swpaul break; 147541502Swpaul case SIOCADDMULTI: 147641502Swpaul case SIOCDELMULTI: 1477131518Sbms VR_LOCK(sc); 147841502Swpaul vr_setmulti(sc); 1479131518Sbms VR_UNLOCK(sc); 148041502Swpaul error = 0; 148141502Swpaul break; 148241502Swpaul case SIOCGIFMEDIA: 148341502Swpaul case SIOCSIFMEDIA: 148451432Swpaul mii = device_get_softc(sc->vr_miibus); 148551432Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 148641502Swpaul break; 1487128118Sru case SIOCSIFCAP: 1488150789Sglebius#ifdef DEVICE_POLLING 1489150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 1490150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 1491150789Sglebius error = ether_poll_register(vr_poll, ifp); 1492150789Sglebius if (error) 1493150789Sglebius return(error); 1494150789Sglebius VR_LOCK(sc); 1495150789Sglebius /* Disable interrupts */ 1496150789Sglebius CSR_WRITE_2(sc, VR_IMR, 0x0000); 1497150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 1498150789Sglebius VR_UNLOCK(sc); 1499150789Sglebius return (error); 1500150789Sglebius 1501150789Sglebius } 1502150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 1503150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 1504150789Sglebius error = ether_poll_deregister(ifp); 1505150789Sglebius /* Enable interrupts. */ 1506150789Sglebius VR_LOCK(sc); 1507150789Sglebius CSR_WRITE_2(sc, VR_IMR, VR_INTRS); 1508150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 1509150789Sglebius VR_UNLOCK(sc); 1510150789Sglebius return (error); 1511150789Sglebius } 1512150789Sglebius#endif /* DEVICE_POLLING */ 1513168827Sphk ifp->if_capenable = ifr->ifr_reqcap; 1514168827Sphk if (ifp->if_capenable & IFCAP_TXCSUM) 1515168827Sphk ifp->if_hwassist = (CSUM_IP | CSUM_TCP | CSUM_UDP); 1516168827Sphk else 1517168827Sphk ifp->if_hwassist = 0; 1518128118Sru break; 151941502Swpaul default: 1520106936Ssam error = ether_ioctl(ifp, command, data); 152141502Swpaul break; 152241502Swpaul } 152341502Swpaul 1524131503Sbms return (error); 152541502Swpaul} 152641502Swpaul 1527102336Salfredstatic void 1528131503Sbmsvr_watchdog(struct ifnet *ifp) 152941502Swpaul{ 1530131518Sbms struct vr_softc *sc = ifp->if_softc; 153141502Swpaul 153267087Swpaul VR_LOCK(sc); 1533131844Sbms 153441502Swpaul ifp->if_oerrors++; 1535151773Sjhb if_printf(ifp, "watchdog timeout\n"); 153641502Swpaul 153741502Swpaul vr_stop(sc); 153841502Swpaul vr_reset(sc); 1539131844Sbms vr_init_locked(sc); 1540131518Sbms 1541132986Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1542131844Sbms vr_start_locked(ifp); 1543131844Sbms 1544131844Sbms VR_UNLOCK(sc); 154541502Swpaul} 154641502Swpaul 154741502Swpaul/* 154841502Swpaul * Stop the adapter and free any mbufs allocated to the 154941502Swpaul * RX and TX lists. 155041502Swpaul */ 1551102336Salfredstatic void 1552131503Sbmsvr_stop(struct vr_softc *sc) 155341502Swpaul{ 1554131503Sbms register int i; 1555131503Sbms struct ifnet *ifp; 155641502Swpaul 1557131518Sbms VR_LOCK_ASSERT(sc); 155867087Swpaul 1559147256Sbrooks ifp = sc->vr_ifp; 156041502Swpaul ifp->if_timer = 0; 156141502Swpaul 1562151911Sjhb callout_stop(&sc->vr_stat_callout); 1563148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 156451432Swpaul 156541502Swpaul VR_SETBIT16(sc, VR_COMMAND, VR_CMD_STOP); 156641502Swpaul VR_CLRBIT16(sc, VR_COMMAND, (VR_CMD_RX_ON|VR_CMD_TX_ON)); 156741502Swpaul CSR_WRITE_2(sc, VR_IMR, 0x0000); 156841502Swpaul CSR_WRITE_4(sc, VR_TXADDR, 0x00000000); 156941502Swpaul CSR_WRITE_4(sc, VR_RXADDR, 0x00000000); 157041502Swpaul 157141502Swpaul /* 157241502Swpaul * Free data in the RX lists. 157341502Swpaul */ 1574168952Sphk for (i = 0; i < VR_RX_LIST_CNT; i++) 1575168952Sphk if (sc->vr_ldata->vr_rx_list[i].vr_mbuf != NULL) 1576168952Sphk m_freem(sc->vr_ldata->vr_rx_list[i].vr_mbuf); 157741502Swpaul bzero((char *)&sc->vr_ldata->vr_rx_list, 1578131517Sbms sizeof(sc->vr_ldata->vr_rx_list)); 157941502Swpaul 158041502Swpaul /* 158141502Swpaul * Free the TX list buffers. 158241502Swpaul */ 1583168952Sphk for (i = 0; i < VR_TX_LIST_CNT; i++) 1584168952Sphk if (sc->vr_ldata->vr_tx_list[i].vr_mbuf != NULL) 1585168952Sphk m_freem(sc->vr_ldata->vr_tx_list[i].vr_mbuf); 158641502Swpaul bzero((char *)&sc->vr_ldata->vr_tx_list, 1587131517Sbms sizeof(sc->vr_ldata->vr_tx_list)); 158841502Swpaul} 158941502Swpaul 159041502Swpaul/* 159141502Swpaul * Stop all chip I/O so that the kernel's probe routines don't 159241502Swpaul * get confused by errant DMAs when rebooting. 159341502Swpaul */ 1594102336Salfredstatic void 1595131503Sbmsvr_shutdown(device_t dev) 159641502Swpaul{ 159741502Swpaul 1598136696Sbms vr_detach(dev); 159941502Swpaul} 1600