1216829Syongari/*- 2216829Syongari * Copyright (c) 2010, Pyun YongHyeon <yongari@FreeBSD.org> 3216829Syongari * All rights reserved. 4216829Syongari * 5216829Syongari * Redistribution and use in source and binary forms, with or without 6216829Syongari * modification, are permitted provided that the following conditions 7216829Syongari * are met: 8216829Syongari * 1. Redistributions of source code must retain the above copyright 9216829Syongari * notice unmodified, this list of conditions, and the following 10216829Syongari * disclaimer. 11216829Syongari * 2. Redistributions in binary form must reproduce the above copyright 12216829Syongari * notice, this list of conditions and the following disclaimer in the 13216829Syongari * documentation and/or other materials provided with the distribution. 14216829Syongari * 15216829Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16216829Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17216829Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18216829Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19216829Syongari * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20216829Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21216829Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22216829Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23216829Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24216829Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25216829Syongari * SUCH DAMAGE. 26216829Syongari */ 27216829Syongari 28216829Syongari/* Driver for DM&P Electronics, Inc, Vortex86 RDC R6040 FastEthernet. */ 29216829Syongari 30216829Syongari#include <sys/cdefs.h> 31216829Syongari__FBSDID("$FreeBSD$"); 32216829Syongari 33216829Syongari#include <sys/param.h> 34216829Syongari#include <sys/systm.h> 35216829Syongari#include <sys/bus.h> 36216829Syongari#include <sys/endian.h> 37216829Syongari#include <sys/kernel.h> 38216829Syongari#include <sys/lock.h> 39216829Syongari#include <sys/malloc.h> 40216829Syongari#include <sys/mbuf.h> 41216829Syongari#include <sys/module.h> 42216829Syongari#include <sys/mutex.h> 43216829Syongari#include <sys/rman.h> 44216829Syongari#include <sys/socket.h> 45216829Syongari#include <sys/sockio.h> 46216829Syongari#include <sys/sysctl.h> 47216829Syongari 48216829Syongari#include <net/bpf.h> 49216829Syongari#include <net/if.h> 50257176Sglebius#include <net/if_var.h> 51216829Syongari#include <net/if_arp.h> 52216829Syongari#include <net/ethernet.h> 53216829Syongari#include <net/if_dl.h> 54216829Syongari#include <net/if_llc.h> 55216829Syongari#include <net/if_media.h> 56216829Syongari#include <net/if_types.h> 57216829Syongari#include <net/if_vlan_var.h> 58216829Syongari 59216829Syongari#include <netinet/in.h> 60216829Syongari#include <netinet/in_systm.h> 61216829Syongari 62216829Syongari#include <dev/mii/mii.h> 63216829Syongari#include <dev/mii/miivar.h> 64216829Syongari 65216829Syongari#include <dev/pci/pcireg.h> 66216829Syongari#include <dev/pci/pcivar.h> 67216829Syongari 68216829Syongari#include <machine/bus.h> 69216829Syongari 70216829Syongari#include <dev/vte/if_vtereg.h> 71216829Syongari#include <dev/vte/if_vtevar.h> 72216829Syongari 73216829Syongari/* "device miibus" required. See GENERIC if you get errors here. */ 74216829Syongari#include "miibus_if.h" 75216829Syongari 76216829SyongariMODULE_DEPEND(vte, pci, 1, 1, 1); 77216829SyongariMODULE_DEPEND(vte, ether, 1, 1, 1); 78216829SyongariMODULE_DEPEND(vte, miibus, 1, 1, 1); 79216829Syongari 80216829Syongari/* Tunables. */ 81216829Syongaristatic int tx_deep_copy = 1; 82216829SyongariTUNABLE_INT("hw.vte.tx_deep_copy", &tx_deep_copy); 83216829Syongari 84216829Syongari/* 85216829Syongari * Devices supported by this driver. 86216829Syongari */ 87216829Syongaristatic const struct vte_ident vte_ident_table[] = { 88216829Syongari { VENDORID_RDC, DEVICEID_RDC_R6040, "RDC R6040 FastEthernet"}, 89216829Syongari { 0, 0, NULL} 90216829Syongari}; 91216829Syongari 92216829Syongaristatic int vte_attach(device_t); 93216829Syongaristatic int vte_detach(device_t); 94216829Syongaristatic int vte_dma_alloc(struct vte_softc *); 95216829Syongaristatic void vte_dma_free(struct vte_softc *); 96216829Syongaristatic void vte_dmamap_cb(void *, bus_dma_segment_t *, int, int); 97216829Syongaristatic struct vte_txdesc * 98216829Syongari vte_encap(struct vte_softc *, struct mbuf **); 99216829Syongaristatic const struct vte_ident * 100216829Syongari vte_find_ident(device_t); 101216829Syongari#ifndef __NO_STRICT_ALIGNMENT 102216829Syongaristatic struct mbuf * 103216829Syongari vte_fixup_rx(struct ifnet *, struct mbuf *); 104216829Syongari#endif 105216829Syongaristatic void vte_get_macaddr(struct vte_softc *); 106216829Syongaristatic void vte_init(void *); 107216829Syongaristatic void vte_init_locked(struct vte_softc *); 108216829Syongaristatic int vte_init_rx_ring(struct vte_softc *); 109216829Syongaristatic int vte_init_tx_ring(struct vte_softc *); 110216829Syongaristatic void vte_intr(void *); 111216829Syongaristatic int vte_ioctl(struct ifnet *, u_long, caddr_t); 112272065Sglebiusstatic uint64_t vte_get_counter(struct ifnet *, ift_counter); 113216829Syongaristatic void vte_mac_config(struct vte_softc *); 114216829Syongaristatic int vte_miibus_readreg(device_t, int, int); 115216829Syongaristatic void vte_miibus_statchg(device_t); 116216829Syongaristatic int vte_miibus_writereg(device_t, int, int, int); 117216829Syongaristatic int vte_mediachange(struct ifnet *); 118216829Syongaristatic int vte_mediachange_locked(struct ifnet *); 119216829Syongaristatic void vte_mediastatus(struct ifnet *, struct ifmediareq *); 120216829Syongaristatic int vte_newbuf(struct vte_softc *, struct vte_rxdesc *); 121216829Syongaristatic int vte_probe(device_t); 122216829Syongaristatic void vte_reset(struct vte_softc *); 123216829Syongaristatic int vte_resume(device_t); 124216829Syongaristatic void vte_rxeof(struct vte_softc *); 125216829Syongaristatic void vte_rxfilter(struct vte_softc *); 126216829Syongaristatic int vte_shutdown(device_t); 127216829Syongaristatic void vte_start(struct ifnet *); 128216829Syongaristatic void vte_start_locked(struct vte_softc *); 129216829Syongaristatic void vte_start_mac(struct vte_softc *); 130216829Syongaristatic void vte_stats_clear(struct vte_softc *); 131216829Syongaristatic void vte_stats_update(struct vte_softc *); 132216829Syongaristatic void vte_stop(struct vte_softc *); 133216829Syongaristatic void vte_stop_mac(struct vte_softc *); 134216829Syongaristatic int vte_suspend(device_t); 135216829Syongaristatic void vte_sysctl_node(struct vte_softc *); 136216829Syongaristatic void vte_tick(void *); 137216829Syongaristatic void vte_txeof(struct vte_softc *); 138216829Syongaristatic void vte_watchdog(struct vte_softc *); 139216829Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 140216829Syongaristatic int sysctl_hw_vte_int_mod(SYSCTL_HANDLER_ARGS); 141216829Syongari 142216829Syongaristatic device_method_t vte_methods[] = { 143216829Syongari /* Device interface. */ 144216829Syongari DEVMETHOD(device_probe, vte_probe), 145216829Syongari DEVMETHOD(device_attach, vte_attach), 146216829Syongari DEVMETHOD(device_detach, vte_detach), 147216829Syongari DEVMETHOD(device_shutdown, vte_shutdown), 148216829Syongari DEVMETHOD(device_suspend, vte_suspend), 149216829Syongari DEVMETHOD(device_resume, vte_resume), 150216829Syongari 151216829Syongari /* MII interface. */ 152216829Syongari DEVMETHOD(miibus_readreg, vte_miibus_readreg), 153216829Syongari DEVMETHOD(miibus_writereg, vte_miibus_writereg), 154216829Syongari DEVMETHOD(miibus_statchg, vte_miibus_statchg), 155216829Syongari 156227848Smarius DEVMETHOD_END 157216829Syongari}; 158216829Syongari 159216829Syongaristatic driver_t vte_driver = { 160216829Syongari "vte", 161216829Syongari vte_methods, 162216829Syongari sizeof(struct vte_softc) 163216829Syongari}; 164216829Syongari 165216829Syongaristatic devclass_t vte_devclass; 166216829Syongari 167216829SyongariDRIVER_MODULE(vte, pci, vte_driver, vte_devclass, 0, 0); 168216829SyongariDRIVER_MODULE(miibus, vte, miibus_driver, miibus_devclass, 0, 0); 169216829Syongari 170216829Syongaristatic int 171216829Syongarivte_miibus_readreg(device_t dev, int phy, int reg) 172216829Syongari{ 173216829Syongari struct vte_softc *sc; 174216829Syongari int i; 175216829Syongari 176216829Syongari sc = device_get_softc(dev); 177216829Syongari 178216829Syongari CSR_WRITE_2(sc, VTE_MMDIO, MMDIO_READ | 179216829Syongari (phy << MMDIO_PHY_ADDR_SHIFT) | (reg << MMDIO_REG_ADDR_SHIFT)); 180216829Syongari for (i = VTE_PHY_TIMEOUT; i > 0; i--) { 181216829Syongari DELAY(5); 182216829Syongari if ((CSR_READ_2(sc, VTE_MMDIO) & MMDIO_READ) == 0) 183216829Syongari break; 184216829Syongari } 185216829Syongari 186216829Syongari if (i == 0) { 187216829Syongari device_printf(sc->vte_dev, "phy read timeout : %d\n", reg); 188216829Syongari return (0); 189216829Syongari } 190216829Syongari 191216829Syongari return (CSR_READ_2(sc, VTE_MMRD)); 192216829Syongari} 193216829Syongari 194216829Syongaristatic int 195216829Syongarivte_miibus_writereg(device_t dev, int phy, int reg, int val) 196216829Syongari{ 197216829Syongari struct vte_softc *sc; 198216829Syongari int i; 199216829Syongari 200216829Syongari sc = device_get_softc(dev); 201216829Syongari 202216829Syongari CSR_WRITE_2(sc, VTE_MMWD, val); 203216829Syongari CSR_WRITE_2(sc, VTE_MMDIO, MMDIO_WRITE | 204216829Syongari (phy << MMDIO_PHY_ADDR_SHIFT) | (reg << MMDIO_REG_ADDR_SHIFT)); 205216829Syongari for (i = VTE_PHY_TIMEOUT; i > 0; i--) { 206216829Syongari DELAY(5); 207216829Syongari if ((CSR_READ_2(sc, VTE_MMDIO) & MMDIO_WRITE) == 0) 208216829Syongari break; 209216829Syongari } 210216829Syongari 211216829Syongari if (i == 0) 212216829Syongari device_printf(sc->vte_dev, "phy write timeout : %d\n", reg); 213216829Syongari 214216829Syongari return (0); 215216829Syongari} 216216829Syongari 217216829Syongaristatic void 218216829Syongarivte_miibus_statchg(device_t dev) 219216829Syongari{ 220216829Syongari struct vte_softc *sc; 221216829Syongari struct mii_data *mii; 222216829Syongari struct ifnet *ifp; 223216829Syongari uint16_t val; 224216829Syongari 225216829Syongari sc = device_get_softc(dev); 226216829Syongari 227216829Syongari mii = device_get_softc(sc->vte_miibus); 228216829Syongari ifp = sc->vte_ifp; 229216829Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 230216829Syongari return; 231216829Syongari 232216829Syongari sc->vte_flags &= ~VTE_FLAG_LINK; 233216829Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 234216829Syongari (IFM_ACTIVE | IFM_AVALID)) { 235216829Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 236216829Syongari case IFM_10_T: 237216829Syongari case IFM_100_TX: 238216829Syongari sc->vte_flags |= VTE_FLAG_LINK; 239216829Syongari break; 240216829Syongari default: 241216829Syongari break; 242216829Syongari } 243216829Syongari } 244216829Syongari 245216829Syongari /* Stop RX/TX MACs. */ 246216829Syongari vte_stop_mac(sc); 247216829Syongari /* Program MACs with resolved duplex and flow control. */ 248216829Syongari if ((sc->vte_flags & VTE_FLAG_LINK) != 0) { 249216829Syongari /* 250216829Syongari * Timer waiting time : (63 + TIMER * 64) MII clock. 251216829Syongari * MII clock : 25MHz(100Mbps) or 2.5MHz(10Mbps). 252216829Syongari */ 253216829Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 254216829Syongari val = 18 << VTE_IM_TIMER_SHIFT; 255216829Syongari else 256216829Syongari val = 1 << VTE_IM_TIMER_SHIFT; 257216829Syongari val |= sc->vte_int_rx_mod << VTE_IM_BUNDLE_SHIFT; 258216829Syongari /* 48.6us for 100Mbps, 50.8us for 10Mbps */ 259216829Syongari CSR_WRITE_2(sc, VTE_MRICR, val); 260216829Syongari 261216829Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 262216829Syongari val = 18 << VTE_IM_TIMER_SHIFT; 263216829Syongari else 264216829Syongari val = 1 << VTE_IM_TIMER_SHIFT; 265216829Syongari val |= sc->vte_int_tx_mod << VTE_IM_BUNDLE_SHIFT; 266216829Syongari /* 48.6us for 100Mbps, 50.8us for 10Mbps */ 267216829Syongari CSR_WRITE_2(sc, VTE_MTICR, val); 268216829Syongari 269216829Syongari vte_mac_config(sc); 270216829Syongari vte_start_mac(sc); 271216829Syongari } 272216829Syongari} 273216829Syongari 274216829Syongaristatic void 275216829Syongarivte_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 276216829Syongari{ 277216829Syongari struct vte_softc *sc; 278216829Syongari struct mii_data *mii; 279216829Syongari 280216829Syongari sc = ifp->if_softc; 281216829Syongari VTE_LOCK(sc); 282216829Syongari if ((ifp->if_flags & IFF_UP) == 0) { 283216829Syongari VTE_UNLOCK(sc); 284216829Syongari return; 285216829Syongari } 286216829Syongari mii = device_get_softc(sc->vte_miibus); 287216829Syongari 288216829Syongari mii_pollstat(mii); 289216829Syongari ifmr->ifm_status = mii->mii_media_status; 290216829Syongari ifmr->ifm_active = mii->mii_media_active; 291226478Syongari VTE_UNLOCK(sc); 292216829Syongari} 293216829Syongari 294216829Syongaristatic int 295216829Syongarivte_mediachange(struct ifnet *ifp) 296216829Syongari{ 297216829Syongari struct vte_softc *sc; 298216829Syongari int error; 299216829Syongari 300216829Syongari sc = ifp->if_softc; 301216829Syongari VTE_LOCK(sc); 302216829Syongari error = vte_mediachange_locked(ifp); 303216829Syongari VTE_UNLOCK(sc); 304216829Syongari return (error); 305216829Syongari} 306216829Syongari 307216829Syongaristatic int 308216829Syongarivte_mediachange_locked(struct ifnet *ifp) 309216829Syongari{ 310216829Syongari struct vte_softc *sc; 311216829Syongari struct mii_data *mii; 312216829Syongari struct mii_softc *miisc; 313216829Syongari int error; 314216829Syongari 315216829Syongari sc = ifp->if_softc; 316216829Syongari mii = device_get_softc(sc->vte_miibus); 317221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 318221407Smarius PHY_RESET(miisc); 319216829Syongari error = mii_mediachg(mii); 320216829Syongari 321216829Syongari return (error); 322216829Syongari} 323216829Syongari 324216829Syongaristatic const struct vte_ident * 325216829Syongarivte_find_ident(device_t dev) 326216829Syongari{ 327216829Syongari const struct vte_ident *ident; 328216829Syongari uint16_t vendor, devid; 329216829Syongari 330216829Syongari vendor = pci_get_vendor(dev); 331216829Syongari devid = pci_get_device(dev); 332216829Syongari for (ident = vte_ident_table; ident->name != NULL; ident++) { 333216829Syongari if (vendor == ident->vendorid && devid == ident->deviceid) 334216829Syongari return (ident); 335216829Syongari } 336216829Syongari 337216829Syongari return (NULL); 338216829Syongari} 339216829Syongari 340216829Syongaristatic int 341216829Syongarivte_probe(device_t dev) 342216829Syongari{ 343216829Syongari const struct vte_ident *ident; 344216829Syongari 345216829Syongari ident = vte_find_ident(dev); 346216829Syongari if (ident != NULL) { 347216829Syongari device_set_desc(dev, ident->name); 348216829Syongari return (BUS_PROBE_DEFAULT); 349216829Syongari } 350216829Syongari 351216829Syongari return (ENXIO); 352216829Syongari} 353216829Syongari 354216829Syongaristatic void 355216829Syongarivte_get_macaddr(struct vte_softc *sc) 356216829Syongari{ 357216829Syongari uint16_t mid; 358216829Syongari 359216829Syongari /* 360216829Syongari * It seems there is no way to reload station address and 361216829Syongari * it is supposed to be set by BIOS. 362216829Syongari */ 363216829Syongari mid = CSR_READ_2(sc, VTE_MID0L); 364216829Syongari sc->vte_eaddr[0] = (mid >> 0) & 0xFF; 365216829Syongari sc->vte_eaddr[1] = (mid >> 8) & 0xFF; 366216829Syongari mid = CSR_READ_2(sc, VTE_MID0M); 367216829Syongari sc->vte_eaddr[2] = (mid >> 0) & 0xFF; 368216829Syongari sc->vte_eaddr[3] = (mid >> 8) & 0xFF; 369216829Syongari mid = CSR_READ_2(sc, VTE_MID0H); 370216829Syongari sc->vte_eaddr[4] = (mid >> 0) & 0xFF; 371216829Syongari sc->vte_eaddr[5] = (mid >> 8) & 0xFF; 372216829Syongari} 373216829Syongari 374216829Syongaristatic int 375216829Syongarivte_attach(device_t dev) 376216829Syongari{ 377216829Syongari struct vte_softc *sc; 378216829Syongari struct ifnet *ifp; 379216829Syongari uint16_t macid; 380216829Syongari int error, rid; 381216829Syongari 382216829Syongari error = 0; 383216829Syongari sc = device_get_softc(dev); 384216829Syongari sc->vte_dev = dev; 385216829Syongari 386216829Syongari mtx_init(&sc->vte_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 387216829Syongari MTX_DEF); 388216829Syongari callout_init_mtx(&sc->vte_tick_ch, &sc->vte_mtx, 0); 389216829Syongari sc->vte_ident = vte_find_ident(dev); 390216829Syongari 391216829Syongari /* Map the device. */ 392216829Syongari pci_enable_busmaster(dev); 393216829Syongari sc->vte_res_id = PCIR_BAR(1); 394216829Syongari sc->vte_res_type = SYS_RES_MEMORY; 395216829Syongari sc->vte_res = bus_alloc_resource_any(dev, sc->vte_res_type, 396216829Syongari &sc->vte_res_id, RF_ACTIVE); 397216829Syongari if (sc->vte_res == NULL) { 398216829Syongari sc->vte_res_id = PCIR_BAR(0); 399216829Syongari sc->vte_res_type = SYS_RES_IOPORT; 400216829Syongari sc->vte_res = bus_alloc_resource_any(dev, sc->vte_res_type, 401216829Syongari &sc->vte_res_id, RF_ACTIVE); 402216829Syongari if (sc->vte_res == NULL) { 403216829Syongari device_printf(dev, "cannot map memory/ports.\n"); 404216829Syongari mtx_destroy(&sc->vte_mtx); 405216829Syongari return (ENXIO); 406216829Syongari } 407216829Syongari } 408216829Syongari if (bootverbose) { 409216829Syongari device_printf(dev, "using %s space register mapping\n", 410216829Syongari sc->vte_res_type == SYS_RES_MEMORY ? "memory" : "I/O"); 411216829Syongari device_printf(dev, "MAC Identifier : 0x%04x\n", 412216829Syongari CSR_READ_2(sc, VTE_MACID)); 413216829Syongari macid = CSR_READ_2(sc, VTE_MACID_REV); 414216829Syongari device_printf(dev, "MAC Id. 0x%02x, Rev. 0x%02x\n", 415216829Syongari (macid & VTE_MACID_MASK) >> VTE_MACID_SHIFT, 416216829Syongari (macid & VTE_MACID_REV_MASK) >> VTE_MACID_REV_SHIFT); 417216829Syongari } 418216829Syongari 419216829Syongari rid = 0; 420216829Syongari sc->vte_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 421216829Syongari RF_SHAREABLE | RF_ACTIVE); 422216829Syongari if (sc->vte_irq == NULL) { 423216829Syongari device_printf(dev, "cannot allocate IRQ resources.\n"); 424216829Syongari error = ENXIO; 425216829Syongari goto fail; 426216829Syongari } 427216829Syongari 428216829Syongari /* Reset the ethernet controller. */ 429216829Syongari vte_reset(sc); 430216829Syongari 431295735Syongari if ((error = vte_dma_alloc(sc)) != 0) 432216829Syongari goto fail; 433216829Syongari 434216829Syongari /* Create device sysctl node. */ 435216829Syongari vte_sysctl_node(sc); 436216829Syongari 437216829Syongari /* Load station address. */ 438216829Syongari vte_get_macaddr(sc); 439216829Syongari 440216829Syongari ifp = sc->vte_ifp = if_alloc(IFT_ETHER); 441216829Syongari if (ifp == NULL) { 442216829Syongari device_printf(dev, "cannot allocate ifnet structure.\n"); 443216829Syongari error = ENXIO; 444216829Syongari goto fail; 445216829Syongari } 446216829Syongari 447216829Syongari ifp->if_softc = sc; 448216829Syongari if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 449216829Syongari ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 450216829Syongari ifp->if_ioctl = vte_ioctl; 451216829Syongari ifp->if_start = vte_start; 452216829Syongari ifp->if_init = vte_init; 453272065Sglebius ifp->if_get_counter = vte_get_counter; 454216829Syongari ifp->if_snd.ifq_drv_maxlen = VTE_TX_RING_CNT - 1; 455216829Syongari IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 456216829Syongari IFQ_SET_READY(&ifp->if_snd); 457216829Syongari 458216829Syongari /* 459216829Syongari * Set up MII bus. 460216829Syongari * BIOS would have initialized VTE_MPSCCR to catch PHY 461216829Syongari * status changes so driver may be able to extract 462216829Syongari * configured PHY address. Since it's common to see BIOS 463216829Syongari * fails to initialize the register(including the sample 464216829Syongari * board I have), let mii(4) probe it. This is more 465216829Syongari * reliable than relying on BIOS's initialization. 466216829Syongari * 467216829Syongari * Advertising flow control capability to mii(4) was 468216829Syongari * intentionally disabled due to severe problems in TX 469216829Syongari * pause frame generation. See vte_rxeof() for more 470216829Syongari * details. 471216829Syongari */ 472216829Syongari error = mii_attach(dev, &sc->vte_miibus, ifp, vte_mediachange, 473216829Syongari vte_mediastatus, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 474216829Syongari if (error != 0) { 475216829Syongari device_printf(dev, "attaching PHYs failed\n"); 476216829Syongari goto fail; 477216829Syongari } 478216829Syongari 479216829Syongari ether_ifattach(ifp, sc->vte_eaddr); 480216829Syongari 481216829Syongari /* VLAN capability setup. */ 482216829Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 483216829Syongari ifp->if_capenable = ifp->if_capabilities; 484216829Syongari /* Tell the upper layer we support VLAN over-sized frames. */ 485216829Syongari ifp->if_hdrlen = sizeof(struct ether_vlan_header); 486216829Syongari 487216829Syongari error = bus_setup_intr(dev, sc->vte_irq, INTR_TYPE_NET | INTR_MPSAFE, 488216829Syongari NULL, vte_intr, sc, &sc->vte_intrhand); 489216829Syongari if (error != 0) { 490216829Syongari device_printf(dev, "could not set up interrupt handler.\n"); 491216829Syongari ether_ifdetach(ifp); 492216829Syongari goto fail; 493216829Syongari } 494216829Syongari 495216829Syongarifail: 496216829Syongari if (error != 0) 497216829Syongari vte_detach(dev); 498216829Syongari 499216829Syongari return (error); 500216829Syongari} 501216829Syongari 502216829Syongaristatic int 503216829Syongarivte_detach(device_t dev) 504216829Syongari{ 505216829Syongari struct vte_softc *sc; 506216829Syongari struct ifnet *ifp; 507216829Syongari 508216829Syongari sc = device_get_softc(dev); 509216829Syongari 510216829Syongari ifp = sc->vte_ifp; 511216829Syongari if (device_is_attached(dev)) { 512216829Syongari VTE_LOCK(sc); 513216829Syongari vte_stop(sc); 514216829Syongari VTE_UNLOCK(sc); 515216829Syongari callout_drain(&sc->vte_tick_ch); 516216829Syongari ether_ifdetach(ifp); 517216829Syongari } 518216829Syongari 519216829Syongari if (sc->vte_miibus != NULL) { 520216829Syongari device_delete_child(dev, sc->vte_miibus); 521216829Syongari sc->vte_miibus = NULL; 522216829Syongari } 523216829Syongari bus_generic_detach(dev); 524216829Syongari 525216829Syongari if (sc->vte_intrhand != NULL) { 526216829Syongari bus_teardown_intr(dev, sc->vte_irq, sc->vte_intrhand); 527216829Syongari sc->vte_intrhand = NULL; 528216829Syongari } 529216829Syongari if (sc->vte_irq != NULL) { 530216829Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vte_irq); 531216829Syongari sc->vte_irq = NULL; 532216829Syongari } 533216829Syongari if (sc->vte_res != NULL) { 534216829Syongari bus_release_resource(dev, sc->vte_res_type, sc->vte_res_id, 535216829Syongari sc->vte_res); 536216829Syongari sc->vte_res = NULL; 537216829Syongari } 538216829Syongari if (ifp != NULL) { 539216829Syongari if_free(ifp); 540216829Syongari sc->vte_ifp = NULL; 541216829Syongari } 542216829Syongari vte_dma_free(sc); 543216829Syongari mtx_destroy(&sc->vte_mtx); 544216829Syongari 545216829Syongari return (0); 546216829Syongari} 547216829Syongari 548216829Syongari#define VTE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 549216829Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 550216829Syongari 551216829Syongaristatic void 552216829Syongarivte_sysctl_node(struct vte_softc *sc) 553216829Syongari{ 554216829Syongari struct sysctl_ctx_list *ctx; 555216829Syongari struct sysctl_oid_list *child, *parent; 556216829Syongari struct sysctl_oid *tree; 557216829Syongari struct vte_hw_stats *stats; 558216829Syongari int error; 559216829Syongari 560216829Syongari stats = &sc->vte_stats; 561216829Syongari ctx = device_get_sysctl_ctx(sc->vte_dev); 562216829Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vte_dev)); 563216829Syongari 564216829Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_rx_mod", 565216829Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->vte_int_rx_mod, 0, 566216829Syongari sysctl_hw_vte_int_mod, "I", "vte RX interrupt moderation"); 567216829Syongari SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_tx_mod", 568216829Syongari CTLTYPE_INT | CTLFLAG_RW, &sc->vte_int_tx_mod, 0, 569216829Syongari sysctl_hw_vte_int_mod, "I", "vte TX interrupt moderation"); 570216829Syongari /* Pull in device tunables. */ 571216829Syongari sc->vte_int_rx_mod = VTE_IM_RX_BUNDLE_DEFAULT; 572216829Syongari error = resource_int_value(device_get_name(sc->vte_dev), 573216829Syongari device_get_unit(sc->vte_dev), "int_rx_mod", &sc->vte_int_rx_mod); 574216829Syongari if (error == 0) { 575216829Syongari if (sc->vte_int_rx_mod < VTE_IM_BUNDLE_MIN || 576216829Syongari sc->vte_int_rx_mod > VTE_IM_BUNDLE_MAX) { 577216829Syongari device_printf(sc->vte_dev, "int_rx_mod value out of " 578216829Syongari "range; using default: %d\n", 579216829Syongari VTE_IM_RX_BUNDLE_DEFAULT); 580216829Syongari sc->vte_int_rx_mod = VTE_IM_RX_BUNDLE_DEFAULT; 581216829Syongari } 582216829Syongari } 583216829Syongari 584216829Syongari sc->vte_int_tx_mod = VTE_IM_TX_BUNDLE_DEFAULT; 585216829Syongari error = resource_int_value(device_get_name(sc->vte_dev), 586216829Syongari device_get_unit(sc->vte_dev), "int_tx_mod", &sc->vte_int_tx_mod); 587216829Syongari if (error == 0) { 588216829Syongari if (sc->vte_int_tx_mod < VTE_IM_BUNDLE_MIN || 589216829Syongari sc->vte_int_tx_mod > VTE_IM_BUNDLE_MAX) { 590216829Syongari device_printf(sc->vte_dev, "int_tx_mod value out of " 591216829Syongari "range; using default: %d\n", 592216829Syongari VTE_IM_TX_BUNDLE_DEFAULT); 593216829Syongari sc->vte_int_tx_mod = VTE_IM_TX_BUNDLE_DEFAULT; 594216829Syongari } 595216829Syongari } 596216829Syongari 597216829Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 598216829Syongari NULL, "VTE statistics"); 599216829Syongari parent = SYSCTL_CHILDREN(tree); 600216829Syongari 601216829Syongari /* RX statistics. */ 602216829Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 603216829Syongari NULL, "RX MAC statistics"); 604216829Syongari child = SYSCTL_CHILDREN(tree); 605216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 606216829Syongari &stats->rx_frames, "Good frames"); 607216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames", 608216829Syongari &stats->rx_bcast_frames, "Good broadcast frames"); 609216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames", 610216829Syongari &stats->rx_mcast_frames, "Good multicast frames"); 611216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "runt", 612216829Syongari &stats->rx_runts, "Too short frames"); 613216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "crc_errs", 614216829Syongari &stats->rx_crcerrs, "CRC errors"); 615216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "long_frames", 616216829Syongari &stats->rx_long_frames, 617216829Syongari "Frames that have longer length than maximum packet length"); 618216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "fifo_full", 619216829Syongari &stats->rx_fifo_full, "FIFO full"); 620216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "desc_unavail", 621216829Syongari &stats->rx_desc_unavail, "Descriptor unavailable frames"); 622216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 623216829Syongari &stats->rx_pause_frames, "Pause control frames"); 624216829Syongari 625216829Syongari /* TX statistics. */ 626216829Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 627216829Syongari NULL, "TX MAC statistics"); 628216829Syongari child = SYSCTL_CHILDREN(tree); 629216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "good_frames", 630216829Syongari &stats->tx_frames, "Good frames"); 631216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "underruns", 632216829Syongari &stats->tx_underruns, "FIFO underruns"); 633216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "late_colls", 634216829Syongari &stats->tx_late_colls, "Late collisions"); 635216829Syongari VTE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames", 636216829Syongari &stats->tx_pause_frames, "Pause control frames"); 637216829Syongari} 638216829Syongari 639216829Syongari#undef VTE_SYSCTL_STAT_ADD32 640216829Syongari 641216829Syongaristruct vte_dmamap_arg { 642216829Syongari bus_addr_t vte_busaddr; 643216829Syongari}; 644216829Syongari 645216829Syongaristatic void 646216829Syongarivte_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 647216829Syongari{ 648216829Syongari struct vte_dmamap_arg *ctx; 649216829Syongari 650216829Syongari if (error != 0) 651216829Syongari return; 652216829Syongari 653216829Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 654216829Syongari 655216829Syongari ctx = (struct vte_dmamap_arg *)arg; 656216829Syongari ctx->vte_busaddr = segs[0].ds_addr; 657216829Syongari} 658216829Syongari 659216829Syongaristatic int 660216829Syongarivte_dma_alloc(struct vte_softc *sc) 661216829Syongari{ 662216829Syongari struct vte_txdesc *txd; 663216829Syongari struct vte_rxdesc *rxd; 664216829Syongari struct vte_dmamap_arg ctx; 665216829Syongari int error, i; 666216829Syongari 667216829Syongari /* Create parent DMA tag. */ 668216829Syongari error = bus_dma_tag_create( 669216829Syongari bus_get_dma_tag(sc->vte_dev), /* parent */ 670216829Syongari 1, 0, /* alignment, boundary */ 671216829Syongari BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 672216829Syongari BUS_SPACE_MAXADDR, /* highaddr */ 673216829Syongari NULL, NULL, /* filter, filterarg */ 674216829Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 675216829Syongari 0, /* nsegments */ 676216829Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 677216829Syongari 0, /* flags */ 678216829Syongari NULL, NULL, /* lockfunc, lockarg */ 679216829Syongari &sc->vte_cdata.vte_parent_tag); 680216829Syongari if (error != 0) { 681216829Syongari device_printf(sc->vte_dev, 682216829Syongari "could not create parent DMA tag.\n"); 683216829Syongari goto fail; 684216829Syongari } 685216829Syongari 686216829Syongari /* Create DMA tag for TX descriptor ring. */ 687216829Syongari error = bus_dma_tag_create( 688216829Syongari sc->vte_cdata.vte_parent_tag, /* parent */ 689216829Syongari VTE_TX_RING_ALIGN, 0, /* alignment, boundary */ 690216829Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 691216829Syongari BUS_SPACE_MAXADDR, /* highaddr */ 692216829Syongari NULL, NULL, /* filter, filterarg */ 693216829Syongari VTE_TX_RING_SZ, /* maxsize */ 694216829Syongari 1, /* nsegments */ 695216829Syongari VTE_TX_RING_SZ, /* maxsegsize */ 696216829Syongari 0, /* flags */ 697216829Syongari NULL, NULL, /* lockfunc, lockarg */ 698216829Syongari &sc->vte_cdata.vte_tx_ring_tag); 699216829Syongari if (error != 0) { 700216829Syongari device_printf(sc->vte_dev, 701216829Syongari "could not create TX ring DMA tag.\n"); 702216829Syongari goto fail; 703216829Syongari } 704216829Syongari 705216829Syongari /* Create DMA tag for RX free descriptor ring. */ 706216829Syongari error = bus_dma_tag_create( 707216829Syongari sc->vte_cdata.vte_parent_tag, /* parent */ 708216829Syongari VTE_RX_RING_ALIGN, 0, /* alignment, boundary */ 709216829Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 710216829Syongari BUS_SPACE_MAXADDR, /* highaddr */ 711216829Syongari NULL, NULL, /* filter, filterarg */ 712216829Syongari VTE_RX_RING_SZ, /* maxsize */ 713216829Syongari 1, /* nsegments */ 714216829Syongari VTE_RX_RING_SZ, /* maxsegsize */ 715216829Syongari 0, /* flags */ 716216829Syongari NULL, NULL, /* lockfunc, lockarg */ 717216829Syongari &sc->vte_cdata.vte_rx_ring_tag); 718216829Syongari if (error != 0) { 719216829Syongari device_printf(sc->vte_dev, 720216829Syongari "could not create RX ring DMA tag.\n"); 721216829Syongari goto fail; 722216829Syongari } 723216829Syongari 724216829Syongari /* Allocate DMA'able memory and load the DMA map for TX ring. */ 725216829Syongari error = bus_dmamem_alloc(sc->vte_cdata.vte_tx_ring_tag, 726216829Syongari (void **)&sc->vte_cdata.vte_tx_ring, 727216829Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 728216829Syongari &sc->vte_cdata.vte_tx_ring_map); 729216829Syongari if (error != 0) { 730216829Syongari device_printf(sc->vte_dev, 731216829Syongari "could not allocate DMA'able memory for TX ring.\n"); 732216829Syongari goto fail; 733216829Syongari } 734216829Syongari ctx.vte_busaddr = 0; 735216829Syongari error = bus_dmamap_load(sc->vte_cdata.vte_tx_ring_tag, 736216829Syongari sc->vte_cdata.vte_tx_ring_map, sc->vte_cdata.vte_tx_ring, 737216829Syongari VTE_TX_RING_SZ, vte_dmamap_cb, &ctx, 0); 738216829Syongari if (error != 0 || ctx.vte_busaddr == 0) { 739216829Syongari device_printf(sc->vte_dev, 740216829Syongari "could not load DMA'able memory for TX ring.\n"); 741216829Syongari goto fail; 742216829Syongari } 743216829Syongari sc->vte_cdata.vte_tx_ring_paddr = ctx.vte_busaddr; 744216829Syongari 745216829Syongari /* Allocate DMA'able memory and load the DMA map for RX ring. */ 746216829Syongari error = bus_dmamem_alloc(sc->vte_cdata.vte_rx_ring_tag, 747216829Syongari (void **)&sc->vte_cdata.vte_rx_ring, 748216829Syongari BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, 749216829Syongari &sc->vte_cdata.vte_rx_ring_map); 750216829Syongari if (error != 0) { 751216829Syongari device_printf(sc->vte_dev, 752216829Syongari "could not allocate DMA'able memory for RX ring.\n"); 753216829Syongari goto fail; 754216829Syongari } 755216829Syongari ctx.vte_busaddr = 0; 756216829Syongari error = bus_dmamap_load(sc->vte_cdata.vte_rx_ring_tag, 757216829Syongari sc->vte_cdata.vte_rx_ring_map, sc->vte_cdata.vte_rx_ring, 758216829Syongari VTE_RX_RING_SZ, vte_dmamap_cb, &ctx, 0); 759216829Syongari if (error != 0 || ctx.vte_busaddr == 0) { 760216829Syongari device_printf(sc->vte_dev, 761216829Syongari "could not load DMA'able memory for RX ring.\n"); 762216829Syongari goto fail; 763216829Syongari } 764216829Syongari sc->vte_cdata.vte_rx_ring_paddr = ctx.vte_busaddr; 765216829Syongari 766216829Syongari /* Create TX buffer parent tag. */ 767216829Syongari error = bus_dma_tag_create( 768216829Syongari bus_get_dma_tag(sc->vte_dev), /* parent */ 769216829Syongari 1, 0, /* alignment, boundary */ 770216829Syongari BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 771216829Syongari BUS_SPACE_MAXADDR, /* highaddr */ 772216829Syongari NULL, NULL, /* filter, filterarg */ 773216829Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 774216829Syongari 0, /* nsegments */ 775216829Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 776216829Syongari 0, /* flags */ 777216829Syongari NULL, NULL, /* lockfunc, lockarg */ 778216829Syongari &sc->vte_cdata.vte_buffer_tag); 779216829Syongari if (error != 0) { 780216829Syongari device_printf(sc->vte_dev, 781216829Syongari "could not create parent buffer DMA tag.\n"); 782216829Syongari goto fail; 783216829Syongari } 784216829Syongari 785216829Syongari /* Create DMA tag for TX buffers. */ 786216829Syongari error = bus_dma_tag_create( 787216829Syongari sc->vte_cdata.vte_buffer_tag, /* parent */ 788216829Syongari 1, 0, /* alignment, boundary */ 789216829Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 790216829Syongari BUS_SPACE_MAXADDR, /* highaddr */ 791216829Syongari NULL, NULL, /* filter, filterarg */ 792216829Syongari MCLBYTES, /* maxsize */ 793216829Syongari 1, /* nsegments */ 794216829Syongari MCLBYTES, /* maxsegsize */ 795216829Syongari 0, /* flags */ 796216829Syongari NULL, NULL, /* lockfunc, lockarg */ 797216829Syongari &sc->vte_cdata.vte_tx_tag); 798216829Syongari if (error != 0) { 799216829Syongari device_printf(sc->vte_dev, "could not create TX DMA tag.\n"); 800216829Syongari goto fail; 801216829Syongari } 802216829Syongari 803216829Syongari /* Create DMA tag for RX buffers. */ 804216829Syongari error = bus_dma_tag_create( 805216829Syongari sc->vte_cdata.vte_buffer_tag, /* parent */ 806216829Syongari VTE_RX_BUF_ALIGN, 0, /* alignment, boundary */ 807216829Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 808216829Syongari BUS_SPACE_MAXADDR, /* highaddr */ 809216829Syongari NULL, NULL, /* filter, filterarg */ 810216829Syongari MCLBYTES, /* maxsize */ 811216829Syongari 1, /* nsegments */ 812216829Syongari MCLBYTES, /* maxsegsize */ 813216829Syongari 0, /* flags */ 814216829Syongari NULL, NULL, /* lockfunc, lockarg */ 815216829Syongari &sc->vte_cdata.vte_rx_tag); 816216829Syongari if (error != 0) { 817216829Syongari device_printf(sc->vte_dev, "could not create RX DMA tag.\n"); 818216829Syongari goto fail; 819216829Syongari } 820216829Syongari /* Create DMA maps for TX buffers. */ 821216829Syongari for (i = 0; i < VTE_TX_RING_CNT; i++) { 822216829Syongari txd = &sc->vte_cdata.vte_txdesc[i]; 823216829Syongari txd->tx_m = NULL; 824216829Syongari txd->tx_dmamap = NULL; 825216829Syongari error = bus_dmamap_create(sc->vte_cdata.vte_tx_tag, 0, 826216829Syongari &txd->tx_dmamap); 827216829Syongari if (error != 0) { 828216829Syongari device_printf(sc->vte_dev, 829216829Syongari "could not create TX dmamap.\n"); 830216829Syongari goto fail; 831216829Syongari } 832216829Syongari } 833216829Syongari /* Create DMA maps for RX buffers. */ 834216829Syongari if ((error = bus_dmamap_create(sc->vte_cdata.vte_rx_tag, 0, 835216829Syongari &sc->vte_cdata.vte_rx_sparemap)) != 0) { 836216829Syongari device_printf(sc->vte_dev, 837216829Syongari "could not create spare RX dmamap.\n"); 838216829Syongari goto fail; 839216829Syongari } 840216829Syongari for (i = 0; i < VTE_RX_RING_CNT; i++) { 841216829Syongari rxd = &sc->vte_cdata.vte_rxdesc[i]; 842216829Syongari rxd->rx_m = NULL; 843216829Syongari rxd->rx_dmamap = NULL; 844216829Syongari error = bus_dmamap_create(sc->vte_cdata.vte_rx_tag, 0, 845216829Syongari &rxd->rx_dmamap); 846216829Syongari if (error != 0) { 847216829Syongari device_printf(sc->vte_dev, 848216829Syongari "could not create RX dmamap.\n"); 849216829Syongari goto fail; 850216829Syongari } 851216829Syongari } 852216829Syongari 853216829Syongarifail: 854216829Syongari return (error); 855216829Syongari} 856216829Syongari 857216829Syongaristatic void 858216829Syongarivte_dma_free(struct vte_softc *sc) 859216829Syongari{ 860216829Syongari struct vte_txdesc *txd; 861216829Syongari struct vte_rxdesc *rxd; 862216829Syongari int i; 863216829Syongari 864216829Syongari /* TX buffers. */ 865216829Syongari if (sc->vte_cdata.vte_tx_tag != NULL) { 866216829Syongari for (i = 0; i < VTE_TX_RING_CNT; i++) { 867216829Syongari txd = &sc->vte_cdata.vte_txdesc[i]; 868216829Syongari if (txd->tx_dmamap != NULL) { 869216829Syongari bus_dmamap_destroy(sc->vte_cdata.vte_tx_tag, 870216829Syongari txd->tx_dmamap); 871216829Syongari txd->tx_dmamap = NULL; 872216829Syongari } 873216829Syongari } 874216829Syongari bus_dma_tag_destroy(sc->vte_cdata.vte_tx_tag); 875216829Syongari sc->vte_cdata.vte_tx_tag = NULL; 876216829Syongari } 877216829Syongari /* RX buffers */ 878216829Syongari if (sc->vte_cdata.vte_rx_tag != NULL) { 879216829Syongari for (i = 0; i < VTE_RX_RING_CNT; i++) { 880216829Syongari rxd = &sc->vte_cdata.vte_rxdesc[i]; 881216829Syongari if (rxd->rx_dmamap != NULL) { 882216829Syongari bus_dmamap_destroy(sc->vte_cdata.vte_rx_tag, 883216829Syongari rxd->rx_dmamap); 884216829Syongari rxd->rx_dmamap = NULL; 885216829Syongari } 886216829Syongari } 887216829Syongari if (sc->vte_cdata.vte_rx_sparemap != NULL) { 888216829Syongari bus_dmamap_destroy(sc->vte_cdata.vte_rx_tag, 889216829Syongari sc->vte_cdata.vte_rx_sparemap); 890216829Syongari sc->vte_cdata.vte_rx_sparemap = NULL; 891216829Syongari } 892216829Syongari bus_dma_tag_destroy(sc->vte_cdata.vte_rx_tag); 893216829Syongari sc->vte_cdata.vte_rx_tag = NULL; 894216829Syongari } 895216829Syongari /* TX descriptor ring. */ 896216829Syongari if (sc->vte_cdata.vte_tx_ring_tag != NULL) { 897267363Sjhb if (sc->vte_cdata.vte_tx_ring_paddr != 0) 898216829Syongari bus_dmamap_unload(sc->vte_cdata.vte_tx_ring_tag, 899216829Syongari sc->vte_cdata.vte_tx_ring_map); 900267363Sjhb if (sc->vte_cdata.vte_tx_ring != NULL) 901216829Syongari bus_dmamem_free(sc->vte_cdata.vte_tx_ring_tag, 902216829Syongari sc->vte_cdata.vte_tx_ring, 903216829Syongari sc->vte_cdata.vte_tx_ring_map); 904216829Syongari sc->vte_cdata.vte_tx_ring = NULL; 905267363Sjhb sc->vte_cdata.vte_tx_ring_paddr = 0; 906216829Syongari bus_dma_tag_destroy(sc->vte_cdata.vte_tx_ring_tag); 907216829Syongari sc->vte_cdata.vte_tx_ring_tag = NULL; 908216829Syongari } 909216829Syongari /* RX ring. */ 910216829Syongari if (sc->vte_cdata.vte_rx_ring_tag != NULL) { 911267363Sjhb if (sc->vte_cdata.vte_rx_ring_paddr != 0) 912216829Syongari bus_dmamap_unload(sc->vte_cdata.vte_rx_ring_tag, 913216829Syongari sc->vte_cdata.vte_rx_ring_map); 914267363Sjhb if (sc->vte_cdata.vte_rx_ring != NULL) 915216829Syongari bus_dmamem_free(sc->vte_cdata.vte_rx_ring_tag, 916216829Syongari sc->vte_cdata.vte_rx_ring, 917216829Syongari sc->vte_cdata.vte_rx_ring_map); 918216829Syongari sc->vte_cdata.vte_rx_ring = NULL; 919267363Sjhb sc->vte_cdata.vte_rx_ring_paddr = 0; 920216829Syongari bus_dma_tag_destroy(sc->vte_cdata.vte_rx_ring_tag); 921216829Syongari sc->vte_cdata.vte_rx_ring_tag = NULL; 922216829Syongari } 923216829Syongari if (sc->vte_cdata.vte_buffer_tag != NULL) { 924216829Syongari bus_dma_tag_destroy(sc->vte_cdata.vte_buffer_tag); 925216829Syongari sc->vte_cdata.vte_buffer_tag = NULL; 926216829Syongari } 927216829Syongari if (sc->vte_cdata.vte_parent_tag != NULL) { 928216829Syongari bus_dma_tag_destroy(sc->vte_cdata.vte_parent_tag); 929216829Syongari sc->vte_cdata.vte_parent_tag = NULL; 930216829Syongari } 931216829Syongari} 932216829Syongari 933216829Syongaristatic int 934216829Syongarivte_shutdown(device_t dev) 935216829Syongari{ 936216829Syongari 937216829Syongari return (vte_suspend(dev)); 938216829Syongari} 939216829Syongari 940216829Syongaristatic int 941216829Syongarivte_suspend(device_t dev) 942216829Syongari{ 943216829Syongari struct vte_softc *sc; 944216829Syongari struct ifnet *ifp; 945216829Syongari 946216829Syongari sc = device_get_softc(dev); 947216829Syongari 948216829Syongari VTE_LOCK(sc); 949216829Syongari ifp = sc->vte_ifp; 950216829Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 951216829Syongari vte_stop(sc); 952216829Syongari VTE_UNLOCK(sc); 953216829Syongari 954216829Syongari return (0); 955216829Syongari} 956216829Syongari 957216829Syongaristatic int 958216829Syongarivte_resume(device_t dev) 959216829Syongari{ 960216829Syongari struct vte_softc *sc; 961216829Syongari struct ifnet *ifp; 962216829Syongari 963216829Syongari sc = device_get_softc(dev); 964216829Syongari 965216829Syongari VTE_LOCK(sc); 966216829Syongari ifp = sc->vte_ifp; 967216829Syongari if ((ifp->if_flags & IFF_UP) != 0) { 968216829Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 969216829Syongari vte_init_locked(sc); 970216829Syongari } 971216829Syongari VTE_UNLOCK(sc); 972216829Syongari 973216829Syongari return (0); 974216829Syongari} 975216829Syongari 976216829Syongaristatic struct vte_txdesc * 977216829Syongarivte_encap(struct vte_softc *sc, struct mbuf **m_head) 978216829Syongari{ 979216829Syongari struct vte_txdesc *txd; 980216829Syongari struct mbuf *m, *n; 981216829Syongari bus_dma_segment_t txsegs[1]; 982216829Syongari int copy, error, nsegs, padlen; 983216829Syongari 984216829Syongari VTE_LOCK_ASSERT(sc); 985216829Syongari 986216829Syongari M_ASSERTPKTHDR((*m_head)); 987216829Syongari 988216829Syongari txd = &sc->vte_cdata.vte_txdesc[sc->vte_cdata.vte_tx_prod]; 989216829Syongari m = *m_head; 990216829Syongari /* 991216829Syongari * Controller doesn't auto-pad, so we have to make sure pad 992216829Syongari * short frames out to the minimum frame length. 993216829Syongari */ 994216829Syongari if (m->m_pkthdr.len < VTE_MIN_FRAMELEN) 995216829Syongari padlen = VTE_MIN_FRAMELEN - m->m_pkthdr.len; 996216829Syongari else 997216829Syongari padlen = 0; 998216829Syongari 999216829Syongari /* 1000216829Syongari * Controller does not support multi-fragmented TX buffers. 1001216829Syongari * Controller spends most of its TX processing time in 1002216829Syongari * de-fragmenting TX buffers. Either faster CPU or more 1003216829Syongari * advanced controller DMA engine is required to speed up 1004216829Syongari * TX path processing. 1005216829Syongari * To mitigate the de-fragmenting issue, perform deep copy 1006216829Syongari * from fragmented mbuf chains to a pre-allocated mbuf 1007216829Syongari * cluster with extra cost of kernel memory. For frames 1008216829Syongari * that is composed of single TX buffer, the deep copy is 1009216829Syongari * bypassed. 1010216829Syongari */ 1011216829Syongari if (tx_deep_copy != 0) { 1012216829Syongari copy = 0; 1013216829Syongari if (m->m_next != NULL) 1014216829Syongari copy++; 1015216829Syongari if (padlen > 0 && (M_WRITABLE(m) == 0 || 1016216829Syongari padlen > M_TRAILINGSPACE(m))) 1017216829Syongari copy++; 1018216829Syongari if (copy != 0) { 1019216829Syongari /* Avoid expensive m_defrag(9) and do deep copy. */ 1020216829Syongari n = sc->vte_cdata.vte_txmbufs[sc->vte_cdata.vte_tx_prod]; 1021216829Syongari m_copydata(m, 0, m->m_pkthdr.len, mtod(n, char *)); 1022216829Syongari n->m_pkthdr.len = m->m_pkthdr.len; 1023216829Syongari n->m_len = m->m_pkthdr.len; 1024216829Syongari m = n; 1025216829Syongari txd->tx_flags |= VTE_TXMBUF; 1026216829Syongari } 1027216829Syongari 1028216829Syongari if (padlen > 0) { 1029216829Syongari /* Zero out the bytes in the pad area. */ 1030216829Syongari bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); 1031216829Syongari m->m_pkthdr.len += padlen; 1032216829Syongari m->m_len = m->m_pkthdr.len; 1033216829Syongari } 1034216829Syongari } else { 1035216829Syongari if (M_WRITABLE(m) == 0) { 1036216829Syongari if (m->m_next != NULL || padlen > 0) { 1037216829Syongari /* Get a writable copy. */ 1038243857Sglebius m = m_dup(*m_head, M_NOWAIT); 1039216829Syongari /* Release original mbuf chains. */ 1040216829Syongari m_freem(*m_head); 1041216829Syongari if (m == NULL) { 1042216829Syongari *m_head = NULL; 1043216829Syongari return (NULL); 1044216829Syongari } 1045216829Syongari *m_head = m; 1046216829Syongari } 1047216829Syongari } 1048216829Syongari 1049216829Syongari if (m->m_next != NULL) { 1050243857Sglebius m = m_defrag(*m_head, M_NOWAIT); 1051216829Syongari if (m == NULL) { 1052216829Syongari m_freem(*m_head); 1053216829Syongari *m_head = NULL; 1054216829Syongari return (NULL); 1055216829Syongari } 1056216829Syongari *m_head = m; 1057216829Syongari } 1058216829Syongari 1059216829Syongari if (padlen > 0) { 1060216829Syongari if (M_TRAILINGSPACE(m) < padlen) { 1061243857Sglebius m = m_defrag(*m_head, M_NOWAIT); 1062216829Syongari if (m == NULL) { 1063216829Syongari m_freem(*m_head); 1064216829Syongari *m_head = NULL; 1065216829Syongari return (NULL); 1066216829Syongari } 1067216829Syongari *m_head = m; 1068216829Syongari } 1069216829Syongari /* Zero out the bytes in the pad area. */ 1070216829Syongari bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); 1071216829Syongari m->m_pkthdr.len += padlen; 1072216829Syongari m->m_len = m->m_pkthdr.len; 1073216829Syongari } 1074216829Syongari } 1075216829Syongari 1076216829Syongari error = bus_dmamap_load_mbuf_sg(sc->vte_cdata.vte_tx_tag, 1077216829Syongari txd->tx_dmamap, m, txsegs, &nsegs, 0); 1078216829Syongari if (error != 0) { 1079216829Syongari txd->tx_flags &= ~VTE_TXMBUF; 1080216829Syongari return (NULL); 1081216829Syongari } 1082216829Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1083216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_tx_tag, txd->tx_dmamap, 1084216829Syongari BUS_DMASYNC_PREWRITE); 1085216829Syongari 1086216829Syongari txd->tx_desc->dtlen = htole16(VTE_TX_LEN(txsegs[0].ds_len)); 1087216829Syongari txd->tx_desc->dtbp = htole32(txsegs[0].ds_addr); 1088216829Syongari sc->vte_cdata.vte_tx_cnt++; 1089216829Syongari /* Update producer index. */ 1090216829Syongari VTE_DESC_INC(sc->vte_cdata.vte_tx_prod, VTE_TX_RING_CNT); 1091216829Syongari 1092216829Syongari /* Finally hand over ownership to controller. */ 1093216829Syongari txd->tx_desc->dtst = htole16(VTE_DTST_TX_OWN); 1094216829Syongari txd->tx_m = m; 1095216829Syongari 1096216829Syongari return (txd); 1097216829Syongari} 1098216829Syongari 1099216829Syongaristatic void 1100216829Syongarivte_start(struct ifnet *ifp) 1101216829Syongari{ 1102216829Syongari struct vte_softc *sc; 1103216829Syongari 1104216829Syongari sc = ifp->if_softc; 1105216829Syongari VTE_LOCK(sc); 1106216829Syongari vte_start_locked(sc); 1107216829Syongari VTE_UNLOCK(sc); 1108216829Syongari} 1109216829Syongari 1110216829Syongaristatic void 1111216829Syongarivte_start_locked(struct vte_softc *sc) 1112216829Syongari{ 1113216829Syongari struct ifnet *ifp; 1114216829Syongari struct vte_txdesc *txd; 1115216829Syongari struct mbuf *m_head; 1116216829Syongari int enq; 1117216829Syongari 1118216829Syongari ifp = sc->vte_ifp; 1119216829Syongari 1120216829Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1121216829Syongari IFF_DRV_RUNNING || (sc->vte_flags & VTE_FLAG_LINK) == 0) 1122216829Syongari return; 1123216829Syongari 1124216829Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { 1125216829Syongari /* Reserve one free TX descriptor. */ 1126216829Syongari if (sc->vte_cdata.vte_tx_cnt >= VTE_TX_RING_CNT - 1) { 1127216829Syongari ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1128216829Syongari break; 1129216829Syongari } 1130216829Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1131216829Syongari if (m_head == NULL) 1132216829Syongari break; 1133216829Syongari /* 1134216829Syongari * Pack the data into the transmit ring. If we 1135216829Syongari * don't have room, set the OACTIVE flag and wait 1136216829Syongari * for the NIC to drain the ring. 1137216829Syongari */ 1138216829Syongari if ((txd = vte_encap(sc, &m_head)) == NULL) { 1139216829Syongari if (m_head != NULL) 1140216829Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1141216829Syongari break; 1142216829Syongari } 1143216829Syongari 1144216829Syongari enq++; 1145216829Syongari /* 1146216829Syongari * If there's a BPF listener, bounce a copy of this frame 1147216829Syongari * to him. 1148216829Syongari */ 1149216829Syongari ETHER_BPF_MTAP(ifp, m_head); 1150216829Syongari /* Free consumed TX frame. */ 1151216829Syongari if ((txd->tx_flags & VTE_TXMBUF) != 0) 1152216829Syongari m_freem(m_head); 1153216829Syongari } 1154216829Syongari 1155216829Syongari if (enq > 0) { 1156216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_tx_ring_tag, 1157216829Syongari sc->vte_cdata.vte_tx_ring_map, BUS_DMASYNC_PREREAD | 1158216829Syongari BUS_DMASYNC_PREWRITE); 1159216829Syongari CSR_WRITE_2(sc, VTE_TX_POLL, TX_POLL_START); 1160216829Syongari sc->vte_watchdog_timer = VTE_TX_TIMEOUT; 1161216829Syongari } 1162216829Syongari} 1163216829Syongari 1164216829Syongaristatic void 1165216829Syongarivte_watchdog(struct vte_softc *sc) 1166216829Syongari{ 1167216829Syongari struct ifnet *ifp; 1168216829Syongari 1169216829Syongari VTE_LOCK_ASSERT(sc); 1170216829Syongari 1171216829Syongari if (sc->vte_watchdog_timer == 0 || --sc->vte_watchdog_timer) 1172216829Syongari return; 1173216829Syongari 1174216829Syongari ifp = sc->vte_ifp; 1175216829Syongari if_printf(sc->vte_ifp, "watchdog timeout -- resetting\n"); 1176272065Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1177216829Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1178216829Syongari vte_init_locked(sc); 1179216829Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1180216829Syongari vte_start_locked(sc); 1181216829Syongari} 1182216829Syongari 1183216829Syongaristatic int 1184216829Syongarivte_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1185216829Syongari{ 1186216829Syongari struct vte_softc *sc; 1187216829Syongari struct ifreq *ifr; 1188216829Syongari struct mii_data *mii; 1189216829Syongari int error; 1190216829Syongari 1191216829Syongari sc = ifp->if_softc; 1192216829Syongari ifr = (struct ifreq *)data; 1193216829Syongari error = 0; 1194216829Syongari switch (cmd) { 1195216829Syongari case SIOCSIFFLAGS: 1196216829Syongari VTE_LOCK(sc); 1197216829Syongari if ((ifp->if_flags & IFF_UP) != 0) { 1198216829Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 1199216829Syongari ((ifp->if_flags ^ sc->vte_if_flags) & 1200216829Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 1201216829Syongari vte_rxfilter(sc); 1202216829Syongari else 1203216829Syongari vte_init_locked(sc); 1204216829Syongari } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1205216829Syongari vte_stop(sc); 1206216829Syongari sc->vte_if_flags = ifp->if_flags; 1207216829Syongari VTE_UNLOCK(sc); 1208216829Syongari break; 1209216829Syongari case SIOCADDMULTI: 1210216829Syongari case SIOCDELMULTI: 1211216829Syongari VTE_LOCK(sc); 1212216829Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1213216829Syongari vte_rxfilter(sc); 1214216829Syongari VTE_UNLOCK(sc); 1215216829Syongari break; 1216216829Syongari case SIOCSIFMEDIA: 1217216829Syongari case SIOCGIFMEDIA: 1218216829Syongari mii = device_get_softc(sc->vte_miibus); 1219216829Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1220216829Syongari break; 1221216829Syongari default: 1222216829Syongari error = ether_ioctl(ifp, cmd, data); 1223216829Syongari break; 1224216829Syongari } 1225216829Syongari 1226216829Syongari return (error); 1227216829Syongari} 1228216829Syongari 1229216829Syongaristatic void 1230216829Syongarivte_mac_config(struct vte_softc *sc) 1231216829Syongari{ 1232216829Syongari struct mii_data *mii; 1233216829Syongari uint16_t mcr; 1234216829Syongari 1235216829Syongari VTE_LOCK_ASSERT(sc); 1236216829Syongari 1237216829Syongari mii = device_get_softc(sc->vte_miibus); 1238216829Syongari mcr = CSR_READ_2(sc, VTE_MCR0); 1239216829Syongari mcr &= ~(MCR0_FC_ENB | MCR0_FULL_DUPLEX); 1240216829Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 1241216829Syongari mcr |= MCR0_FULL_DUPLEX; 1242216829Syongari#ifdef notyet 1243216829Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) 1244216829Syongari mcr |= MCR0_FC_ENB; 1245216829Syongari /* 1246216829Syongari * The data sheet is not clear whether the controller 1247216829Syongari * honors received pause frames or not. The is no 1248216829Syongari * separate control bit for RX pause frame so just 1249216829Syongari * enable MCR0_FC_ENB bit. 1250216829Syongari */ 1251216829Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) 1252216829Syongari mcr |= MCR0_FC_ENB; 1253216829Syongari#endif 1254216829Syongari } 1255216829Syongari CSR_WRITE_2(sc, VTE_MCR0, mcr); 1256216829Syongari} 1257216829Syongari 1258216829Syongaristatic void 1259216829Syongarivte_stats_clear(struct vte_softc *sc) 1260216829Syongari{ 1261216829Syongari 1262216829Syongari /* Reading counter registers clears its contents. */ 1263216829Syongari CSR_READ_2(sc, VTE_CNT_RX_DONE); 1264216829Syongari CSR_READ_2(sc, VTE_CNT_MECNT0); 1265216829Syongari CSR_READ_2(sc, VTE_CNT_MECNT1); 1266216829Syongari CSR_READ_2(sc, VTE_CNT_MECNT2); 1267216829Syongari CSR_READ_2(sc, VTE_CNT_MECNT3); 1268216829Syongari CSR_READ_2(sc, VTE_CNT_TX_DONE); 1269216829Syongari CSR_READ_2(sc, VTE_CNT_MECNT4); 1270216829Syongari CSR_READ_2(sc, VTE_CNT_PAUSE); 1271216829Syongari} 1272216829Syongari 1273216829Syongaristatic void 1274216829Syongarivte_stats_update(struct vte_softc *sc) 1275216829Syongari{ 1276216829Syongari struct vte_hw_stats *stat; 1277216829Syongari uint16_t value; 1278216829Syongari 1279216829Syongari VTE_LOCK_ASSERT(sc); 1280216829Syongari 1281216829Syongari stat = &sc->vte_stats; 1282216829Syongari 1283216829Syongari CSR_READ_2(sc, VTE_MECISR); 1284216829Syongari /* RX stats. */ 1285216829Syongari stat->rx_frames += CSR_READ_2(sc, VTE_CNT_RX_DONE); 1286216829Syongari value = CSR_READ_2(sc, VTE_CNT_MECNT0); 1287216829Syongari stat->rx_bcast_frames += (value >> 8); 1288216829Syongari stat->rx_mcast_frames += (value & 0xFF); 1289216829Syongari value = CSR_READ_2(sc, VTE_CNT_MECNT1); 1290216829Syongari stat->rx_runts += (value >> 8); 1291216829Syongari stat->rx_crcerrs += (value & 0xFF); 1292216829Syongari value = CSR_READ_2(sc, VTE_CNT_MECNT2); 1293216829Syongari stat->rx_long_frames += (value & 0xFF); 1294216829Syongari value = CSR_READ_2(sc, VTE_CNT_MECNT3); 1295216829Syongari stat->rx_fifo_full += (value >> 8); 1296216829Syongari stat->rx_desc_unavail += (value & 0xFF); 1297216829Syongari 1298216829Syongari /* TX stats. */ 1299216829Syongari stat->tx_frames += CSR_READ_2(sc, VTE_CNT_TX_DONE); 1300216829Syongari value = CSR_READ_2(sc, VTE_CNT_MECNT4); 1301216829Syongari stat->tx_underruns += (value >> 8); 1302216829Syongari stat->tx_late_colls += (value & 0xFF); 1303216829Syongari 1304216829Syongari value = CSR_READ_2(sc, VTE_CNT_PAUSE); 1305216829Syongari stat->tx_pause_frames += (value >> 8); 1306216829Syongari stat->rx_pause_frames += (value & 0xFF); 1307272065Sglebius} 1308216829Syongari 1309272065Sglebiusstatic uint64_t 1310272065Sglebiusvte_get_counter(struct ifnet *ifp, ift_counter cnt) 1311272065Sglebius{ 1312272065Sglebius struct vte_softc *sc; 1313272065Sglebius struct vte_hw_stats *stat; 1314272065Sglebius 1315272065Sglebius sc = if_getsoftc(ifp); 1316272065Sglebius stat = &sc->vte_stats; 1317272065Sglebius 1318272065Sglebius switch (cnt) { 1319272065Sglebius case IFCOUNTER_OPACKETS: 1320272065Sglebius return (stat->tx_frames); 1321272065Sglebius case IFCOUNTER_COLLISIONS: 1322272065Sglebius return (stat->tx_late_colls); 1323272065Sglebius case IFCOUNTER_OERRORS: 1324272065Sglebius return (stat->tx_late_colls + stat->tx_underruns); 1325272065Sglebius case IFCOUNTER_IPACKETS: 1326272065Sglebius return (stat->rx_frames); 1327272065Sglebius case IFCOUNTER_IERRORS: 1328272065Sglebius return (stat->rx_crcerrs + stat->rx_runts + 1329272065Sglebius stat->rx_long_frames + stat->rx_fifo_full); 1330272065Sglebius default: 1331272065Sglebius return (if_get_counter_default(ifp, cnt)); 1332272065Sglebius } 1333216829Syongari} 1334216829Syongari 1335216829Syongaristatic void 1336216829Syongarivte_intr(void *arg) 1337216829Syongari{ 1338216829Syongari struct vte_softc *sc; 1339216829Syongari struct ifnet *ifp; 1340216829Syongari uint16_t status; 1341216829Syongari int n; 1342216829Syongari 1343216829Syongari sc = (struct vte_softc *)arg; 1344216829Syongari VTE_LOCK(sc); 1345216829Syongari 1346216829Syongari ifp = sc->vte_ifp; 1347216829Syongari /* Reading VTE_MISR acknowledges interrupts. */ 1348216829Syongari status = CSR_READ_2(sc, VTE_MISR); 1349216829Syongari if ((status & VTE_INTRS) == 0) { 1350216829Syongari /* Not ours. */ 1351216829Syongari VTE_UNLOCK(sc); 1352216829Syongari return; 1353216829Syongari } 1354216829Syongari 1355216829Syongari /* Disable interrupts. */ 1356216829Syongari CSR_WRITE_2(sc, VTE_MIER, 0); 1357216829Syongari for (n = 8; (status & VTE_INTRS) != 0;) { 1358216829Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1359216829Syongari break; 1360216829Syongari if ((status & (MISR_RX_DONE | MISR_RX_DESC_UNAVAIL | 1361216829Syongari MISR_RX_FIFO_FULL)) != 0) 1362216829Syongari vte_rxeof(sc); 1363216829Syongari if ((status & MISR_TX_DONE) != 0) 1364216829Syongari vte_txeof(sc); 1365216829Syongari if ((status & MISR_EVENT_CNT_OFLOW) != 0) 1366216829Syongari vte_stats_update(sc); 1367216829Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1368216829Syongari vte_start_locked(sc); 1369216829Syongari if (--n > 0) 1370216829Syongari status = CSR_READ_2(sc, VTE_MISR); 1371216829Syongari else 1372216829Syongari break; 1373216829Syongari } 1374216829Syongari 1375216829Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1376216829Syongari /* Re-enable interrupts. */ 1377216829Syongari CSR_WRITE_2(sc, VTE_MIER, VTE_INTRS); 1378216829Syongari } 1379216829Syongari VTE_UNLOCK(sc); 1380216829Syongari} 1381216829Syongari 1382216829Syongaristatic void 1383216829Syongarivte_txeof(struct vte_softc *sc) 1384216829Syongari{ 1385216829Syongari struct ifnet *ifp; 1386216829Syongari struct vte_txdesc *txd; 1387216829Syongari uint16_t status; 1388216829Syongari int cons, prog; 1389216829Syongari 1390216829Syongari VTE_LOCK_ASSERT(sc); 1391216829Syongari 1392216829Syongari ifp = sc->vte_ifp; 1393216829Syongari 1394216829Syongari if (sc->vte_cdata.vte_tx_cnt == 0) 1395216829Syongari return; 1396216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_tx_ring_tag, 1397216829Syongari sc->vte_cdata.vte_tx_ring_map, BUS_DMASYNC_POSTREAD | 1398216829Syongari BUS_DMASYNC_POSTWRITE); 1399216829Syongari cons = sc->vte_cdata.vte_tx_cons; 1400216829Syongari /* 1401216829Syongari * Go through our TX list and free mbufs for those 1402216829Syongari * frames which have been transmitted. 1403216829Syongari */ 1404216829Syongari for (prog = 0; sc->vte_cdata.vte_tx_cnt > 0; prog++) { 1405216829Syongari txd = &sc->vte_cdata.vte_txdesc[cons]; 1406216829Syongari status = le16toh(txd->tx_desc->dtst); 1407216829Syongari if ((status & VTE_DTST_TX_OWN) != 0) 1408216829Syongari break; 1409216829Syongari sc->vte_cdata.vte_tx_cnt--; 1410216829Syongari /* Reclaim transmitted mbufs. */ 1411216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_tx_tag, txd->tx_dmamap, 1412216829Syongari BUS_DMASYNC_POSTWRITE); 1413216829Syongari bus_dmamap_unload(sc->vte_cdata.vte_tx_tag, txd->tx_dmamap); 1414216829Syongari if ((txd->tx_flags & VTE_TXMBUF) == 0) 1415216829Syongari m_freem(txd->tx_m); 1416216829Syongari txd->tx_flags &= ~VTE_TXMBUF; 1417216829Syongari txd->tx_m = NULL; 1418216829Syongari prog++; 1419216829Syongari VTE_DESC_INC(cons, VTE_TX_RING_CNT); 1420216829Syongari } 1421216829Syongari 1422216829Syongari if (prog > 0) { 1423216829Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1424216829Syongari sc->vte_cdata.vte_tx_cons = cons; 1425216829Syongari /* 1426216829Syongari * Unarm watchdog timer only when there is no pending 1427216829Syongari * frames in TX queue. 1428216829Syongari */ 1429216829Syongari if (sc->vte_cdata.vte_tx_cnt == 0) 1430216829Syongari sc->vte_watchdog_timer = 0; 1431216829Syongari } 1432216829Syongari} 1433216829Syongari 1434216829Syongaristatic int 1435216829Syongarivte_newbuf(struct vte_softc *sc, struct vte_rxdesc *rxd) 1436216829Syongari{ 1437216829Syongari struct mbuf *m; 1438216829Syongari bus_dma_segment_t segs[1]; 1439216829Syongari bus_dmamap_t map; 1440216829Syongari int nsegs; 1441216829Syongari 1442243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1443216829Syongari if (m == NULL) 1444216829Syongari return (ENOBUFS); 1445216829Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 1446216829Syongari m_adj(m, sizeof(uint32_t)); 1447216829Syongari 1448216829Syongari if (bus_dmamap_load_mbuf_sg(sc->vte_cdata.vte_rx_tag, 1449216829Syongari sc->vte_cdata.vte_rx_sparemap, m, segs, &nsegs, 0) != 0) { 1450216829Syongari m_freem(m); 1451216829Syongari return (ENOBUFS); 1452216829Syongari } 1453216829Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1454216829Syongari 1455216829Syongari if (rxd->rx_m != NULL) { 1456216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_rx_tag, rxd->rx_dmamap, 1457216829Syongari BUS_DMASYNC_POSTREAD); 1458216829Syongari bus_dmamap_unload(sc->vte_cdata.vte_rx_tag, rxd->rx_dmamap); 1459216829Syongari } 1460216829Syongari map = rxd->rx_dmamap; 1461216829Syongari rxd->rx_dmamap = sc->vte_cdata.vte_rx_sparemap; 1462216829Syongari sc->vte_cdata.vte_rx_sparemap = map; 1463216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_rx_tag, rxd->rx_dmamap, 1464216829Syongari BUS_DMASYNC_PREREAD); 1465216829Syongari rxd->rx_m = m; 1466216829Syongari rxd->rx_desc->drbp = htole32(segs[0].ds_addr); 1467216829Syongari rxd->rx_desc->drlen = htole16(VTE_RX_LEN(segs[0].ds_len)); 1468216829Syongari rxd->rx_desc->drst = htole16(VTE_DRST_RX_OWN); 1469216829Syongari 1470216829Syongari return (0); 1471216829Syongari} 1472216829Syongari 1473216829Syongari/* 1474216829Syongari * It's not supposed to see this controller on strict-alignment 1475216829Syongari * architectures but make it work for completeness. 1476216829Syongari */ 1477216829Syongari#ifndef __NO_STRICT_ALIGNMENT 1478216829Syongaristatic struct mbuf * 1479216829Syongarivte_fixup_rx(struct ifnet *ifp, struct mbuf *m) 1480216829Syongari{ 1481216829Syongari uint16_t *src, *dst; 1482216829Syongari int i; 1483216829Syongari 1484216829Syongari src = mtod(m, uint16_t *); 1485216829Syongari dst = src - 1; 1486216829Syongari 1487216829Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1488216829Syongari *dst++ = *src++; 1489216829Syongari m->m_data -= ETHER_ALIGN; 1490216829Syongari return (m); 1491216829Syongari} 1492216829Syongari#endif 1493216829Syongari 1494216829Syongaristatic void 1495216829Syongarivte_rxeof(struct vte_softc *sc) 1496216829Syongari{ 1497216829Syongari struct ifnet *ifp; 1498216829Syongari struct vte_rxdesc *rxd; 1499216829Syongari struct mbuf *m; 1500216829Syongari uint16_t status, total_len; 1501216829Syongari int cons, prog; 1502216829Syongari 1503216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag, 1504216829Syongari sc->vte_cdata.vte_rx_ring_map, BUS_DMASYNC_POSTREAD | 1505216829Syongari BUS_DMASYNC_POSTWRITE); 1506216829Syongari cons = sc->vte_cdata.vte_rx_cons; 1507216829Syongari ifp = sc->vte_ifp; 1508216829Syongari for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; prog++, 1509216829Syongari VTE_DESC_INC(cons, VTE_RX_RING_CNT)) { 1510216829Syongari rxd = &sc->vte_cdata.vte_rxdesc[cons]; 1511216829Syongari status = le16toh(rxd->rx_desc->drst); 1512216829Syongari if ((status & VTE_DRST_RX_OWN) != 0) 1513216829Syongari break; 1514216829Syongari total_len = VTE_RX_LEN(le16toh(rxd->rx_desc->drlen)); 1515216829Syongari m = rxd->rx_m; 1516216829Syongari if ((status & VTE_DRST_RX_OK) == 0) { 1517216829Syongari /* Discard errored frame. */ 1518216829Syongari rxd->rx_desc->drlen = 1519216829Syongari htole16(MCLBYTES - sizeof(uint32_t)); 1520216829Syongari rxd->rx_desc->drst = htole16(VTE_DRST_RX_OWN); 1521216829Syongari continue; 1522216829Syongari } 1523216829Syongari if (vte_newbuf(sc, rxd) != 0) { 1524272065Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 1525216829Syongari rxd->rx_desc->drlen = 1526216829Syongari htole16(MCLBYTES - sizeof(uint32_t)); 1527216829Syongari rxd->rx_desc->drst = htole16(VTE_DRST_RX_OWN); 1528216829Syongari continue; 1529216829Syongari } 1530216829Syongari 1531216829Syongari /* 1532216829Syongari * It seems there is no way to strip FCS bytes. 1533216829Syongari */ 1534216829Syongari m->m_pkthdr.len = m->m_len = total_len - ETHER_CRC_LEN; 1535216829Syongari m->m_pkthdr.rcvif = ifp; 1536216829Syongari#ifndef __NO_STRICT_ALIGNMENT 1537216829Syongari vte_fixup_rx(ifp, m); 1538216829Syongari#endif 1539216829Syongari VTE_UNLOCK(sc); 1540216829Syongari (*ifp->if_input)(ifp, m); 1541216829Syongari VTE_LOCK(sc); 1542216829Syongari } 1543216829Syongari 1544216829Syongari if (prog > 0) { 1545216829Syongari /* Update the consumer index. */ 1546216829Syongari sc->vte_cdata.vte_rx_cons = cons; 1547216829Syongari /* 1548216829Syongari * Sync updated RX descriptors such that controller see 1549216829Syongari * modified RX buffer addresses. 1550216829Syongari */ 1551216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag, 1552216829Syongari sc->vte_cdata.vte_rx_ring_map, 1553216829Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1554216829Syongari#ifdef notyet 1555216829Syongari /* 1556216829Syongari * Update residue counter. Controller does not 1557216829Syongari * keep track of number of available RX descriptors 1558216829Syongari * such that driver should have to update VTE_MRDCR 1559216829Syongari * to make controller know how many free RX 1560216829Syongari * descriptors were added to controller. This is 1561216829Syongari * a similar mechanism used in VIA velocity 1562216829Syongari * controllers and it indicates controller just 1563216829Syongari * polls OWN bit of current RX descriptor pointer. 1564216829Syongari * A couple of severe issues were seen on sample 1565216829Syongari * board where the controller continuously emits TX 1566216829Syongari * pause frames once RX pause threshold crossed. 1567216829Syongari * Once triggered it never recovered form that 1568216829Syongari * state, I couldn't find a way to make it back to 1569216829Syongari * work at least. This issue effectively 1570216829Syongari * disconnected the system from network. Also, the 1571216829Syongari * controller used 00:00:00:00:00:00 as source 1572216829Syongari * station address of TX pause frame. Probably this 1573216829Syongari * is one of reason why vendor recommends not to 1574216829Syongari * enable flow control on R6040 controller. 1575216829Syongari */ 1576216829Syongari CSR_WRITE_2(sc, VTE_MRDCR, prog | 1577216829Syongari (((VTE_RX_RING_CNT * 2) / 10) << 1578216829Syongari VTE_MRDCR_RX_PAUSE_THRESH_SHIFT)); 1579216829Syongari#endif 1580216829Syongari } 1581216829Syongari} 1582216829Syongari 1583216829Syongaristatic void 1584216829Syongarivte_tick(void *arg) 1585216829Syongari{ 1586216829Syongari struct vte_softc *sc; 1587216829Syongari struct mii_data *mii; 1588216829Syongari 1589216829Syongari sc = (struct vte_softc *)arg; 1590216829Syongari 1591216829Syongari VTE_LOCK_ASSERT(sc); 1592216829Syongari 1593216829Syongari mii = device_get_softc(sc->vte_miibus); 1594216829Syongari mii_tick(mii); 1595216829Syongari vte_stats_update(sc); 1596216829Syongari vte_txeof(sc); 1597216829Syongari vte_watchdog(sc); 1598216829Syongari callout_reset(&sc->vte_tick_ch, hz, vte_tick, sc); 1599216829Syongari} 1600216829Syongari 1601216829Syongaristatic void 1602216829Syongarivte_reset(struct vte_softc *sc) 1603216829Syongari{ 1604216829Syongari uint16_t mcr; 1605216829Syongari int i; 1606216829Syongari 1607216829Syongari mcr = CSR_READ_2(sc, VTE_MCR1); 1608216829Syongari CSR_WRITE_2(sc, VTE_MCR1, mcr | MCR1_MAC_RESET); 1609216829Syongari for (i = VTE_RESET_TIMEOUT; i > 0; i--) { 1610216829Syongari DELAY(10); 1611216829Syongari if ((CSR_READ_2(sc, VTE_MCR1) & MCR1_MAC_RESET) == 0) 1612216829Syongari break; 1613216829Syongari } 1614216829Syongari if (i == 0) 1615216829Syongari device_printf(sc->vte_dev, "reset timeout(0x%04x)!\n", mcr); 1616216829Syongari /* 1617216829Syongari * Follow the guide of vendor recommended way to reset MAC. 1618216829Syongari * Vendor confirms relying on MCR1_MAC_RESET of VTE_MCR1 is 1619216829Syongari * not reliable so manually reset internal state machine. 1620216829Syongari */ 1621216829Syongari CSR_WRITE_2(sc, VTE_MACSM, 0x0002); 1622216829Syongari CSR_WRITE_2(sc, VTE_MACSM, 0); 1623216829Syongari DELAY(5000); 1624216829Syongari} 1625216829Syongari 1626216829Syongaristatic void 1627216829Syongarivte_init(void *xsc) 1628216829Syongari{ 1629216829Syongari struct vte_softc *sc; 1630216829Syongari 1631216829Syongari sc = (struct vte_softc *)xsc; 1632216829Syongari VTE_LOCK(sc); 1633216829Syongari vte_init_locked(sc); 1634216829Syongari VTE_UNLOCK(sc); 1635216829Syongari} 1636216829Syongari 1637216829Syongaristatic void 1638216829Syongarivte_init_locked(struct vte_softc *sc) 1639216829Syongari{ 1640216829Syongari struct ifnet *ifp; 1641216829Syongari bus_addr_t paddr; 1642216829Syongari uint8_t *eaddr; 1643216829Syongari 1644216829Syongari VTE_LOCK_ASSERT(sc); 1645216829Syongari 1646216829Syongari ifp = sc->vte_ifp; 1647216829Syongari 1648216829Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1649216829Syongari return; 1650216829Syongari /* 1651216829Syongari * Cancel any pending I/O. 1652216829Syongari */ 1653216829Syongari vte_stop(sc); 1654216829Syongari /* 1655216829Syongari * Reset the chip to a known state. 1656216829Syongari */ 1657216829Syongari vte_reset(sc); 1658216829Syongari 1659216829Syongari /* Initialize RX descriptors. */ 1660216829Syongari if (vte_init_rx_ring(sc) != 0) { 1661216829Syongari device_printf(sc->vte_dev, "no memory for RX buffers.\n"); 1662216829Syongari vte_stop(sc); 1663216829Syongari return; 1664216829Syongari } 1665216829Syongari if (vte_init_tx_ring(sc) != 0) { 1666216829Syongari device_printf(sc->vte_dev, "no memory for TX buffers.\n"); 1667216829Syongari vte_stop(sc); 1668216829Syongari return; 1669216829Syongari } 1670216829Syongari 1671216829Syongari /* 1672216829Syongari * Reprogram the station address. Controller supports up 1673216829Syongari * to 4 different station addresses so driver programs the 1674216829Syongari * first station address as its own ethernet address and 1675216829Syongari * configure the remaining three addresses as perfect 1676216829Syongari * multicast addresses. 1677216829Syongari */ 1678216829Syongari eaddr = IF_LLADDR(sc->vte_ifp); 1679216829Syongari CSR_WRITE_2(sc, VTE_MID0L, eaddr[1] << 8 | eaddr[0]); 1680216829Syongari CSR_WRITE_2(sc, VTE_MID0M, eaddr[3] << 8 | eaddr[2]); 1681216829Syongari CSR_WRITE_2(sc, VTE_MID0H, eaddr[5] << 8 | eaddr[4]); 1682216829Syongari 1683216829Syongari /* Set TX descriptor base addresses. */ 1684216829Syongari paddr = sc->vte_cdata.vte_tx_ring_paddr; 1685216829Syongari CSR_WRITE_2(sc, VTE_MTDSA1, paddr >> 16); 1686216829Syongari CSR_WRITE_2(sc, VTE_MTDSA0, paddr & 0xFFFF); 1687216829Syongari /* Set RX descriptor base addresses. */ 1688216829Syongari paddr = sc->vte_cdata.vte_rx_ring_paddr; 1689216829Syongari CSR_WRITE_2(sc, VTE_MRDSA1, paddr >> 16); 1690216829Syongari CSR_WRITE_2(sc, VTE_MRDSA0, paddr & 0xFFFF); 1691216829Syongari /* 1692216829Syongari * Initialize RX descriptor residue counter and set RX 1693216829Syongari * pause threshold to 20% of available RX descriptors. 1694216829Syongari * See comments on vte_rxeof() for details on flow control 1695216829Syongari * issues. 1696216829Syongari */ 1697216829Syongari CSR_WRITE_2(sc, VTE_MRDCR, (VTE_RX_RING_CNT & VTE_MRDCR_RESIDUE_MASK) | 1698216829Syongari (((VTE_RX_RING_CNT * 2) / 10) << VTE_MRDCR_RX_PAUSE_THRESH_SHIFT)); 1699216829Syongari 1700216829Syongari /* 1701216829Syongari * Always use maximum frame size that controller can 1702216829Syongari * support. Otherwise received frames that has longer 1703216829Syongari * frame length than vte(4) MTU would be silently dropped 1704216829Syongari * in controller. This would break path-MTU discovery as 1705216829Syongari * sender wouldn't get any responses from receiver. The 1706216829Syongari * RX buffer size should be multiple of 4. 1707216829Syongari * Note, jumbo frames are silently ignored by controller 1708216829Syongari * and even MAC counters do not detect them. 1709216829Syongari */ 1710216829Syongari CSR_WRITE_2(sc, VTE_MRBSR, VTE_RX_BUF_SIZE_MAX); 1711216829Syongari 1712216829Syongari /* Configure FIFO. */ 1713216829Syongari CSR_WRITE_2(sc, VTE_MBCR, MBCR_FIFO_XFER_LENGTH_16 | 1714216829Syongari MBCR_TX_FIFO_THRESH_64 | MBCR_RX_FIFO_THRESH_16 | 1715216829Syongari MBCR_SDRAM_BUS_REQ_TIMER_DEFAULT); 1716216829Syongari 1717216829Syongari /* 1718216829Syongari * Configure TX/RX MACs. Actual resolved duplex and flow 1719216829Syongari * control configuration is done after detecting a valid 1720216829Syongari * link. Note, we don't generate early interrupt here 1721216829Syongari * as well since FreeBSD does not have interrupt latency 1722216829Syongari * problems like Windows. 1723216829Syongari */ 1724216829Syongari CSR_WRITE_2(sc, VTE_MCR0, MCR0_ACCPT_LONG_PKT); 1725216829Syongari /* 1726216829Syongari * We manually keep track of PHY status changes to 1727216829Syongari * configure resolved duplex and flow control since only 1728216829Syongari * duplex configuration can be automatically reflected to 1729216829Syongari * MCR0. 1730216829Syongari */ 1731216829Syongari CSR_WRITE_2(sc, VTE_MCR1, MCR1_PKT_LENGTH_1537 | 1732216829Syongari MCR1_EXCESS_COL_RETRY_16); 1733216829Syongari 1734216829Syongari /* Initialize RX filter. */ 1735216829Syongari vte_rxfilter(sc); 1736216829Syongari 1737216829Syongari /* Disable TX/RX interrupt moderation control. */ 1738216829Syongari CSR_WRITE_2(sc, VTE_MRICR, 0); 1739216829Syongari CSR_WRITE_2(sc, VTE_MTICR, 0); 1740216829Syongari 1741216829Syongari /* Enable MAC event counter interrupts. */ 1742216829Syongari CSR_WRITE_2(sc, VTE_MECIER, VTE_MECIER_INTRS); 1743216829Syongari /* Clear MAC statistics. */ 1744216829Syongari vte_stats_clear(sc); 1745216829Syongari 1746216829Syongari /* Acknowledge all pending interrupts and clear it. */ 1747216829Syongari CSR_WRITE_2(sc, VTE_MIER, VTE_INTRS); 1748216829Syongari CSR_WRITE_2(sc, VTE_MISR, 0); 1749216829Syongari 1750216829Syongari sc->vte_flags &= ~VTE_FLAG_LINK; 1751216829Syongari /* Switch to the current media. */ 1752216829Syongari vte_mediachange_locked(ifp); 1753216829Syongari 1754216829Syongari callout_reset(&sc->vte_tick_ch, hz, vte_tick, sc); 1755216829Syongari 1756216829Syongari ifp->if_drv_flags |= IFF_DRV_RUNNING; 1757216829Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1758216829Syongari} 1759216829Syongari 1760216829Syongaristatic void 1761216829Syongarivte_stop(struct vte_softc *sc) 1762216829Syongari{ 1763216829Syongari struct ifnet *ifp; 1764216829Syongari struct vte_txdesc *txd; 1765216829Syongari struct vte_rxdesc *rxd; 1766216829Syongari int i; 1767216829Syongari 1768216829Syongari VTE_LOCK_ASSERT(sc); 1769216829Syongari /* 1770216829Syongari * Mark the interface down and cancel the watchdog timer. 1771216829Syongari */ 1772216829Syongari ifp = sc->vte_ifp; 1773216829Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1774216829Syongari sc->vte_flags &= ~VTE_FLAG_LINK; 1775216829Syongari callout_stop(&sc->vte_tick_ch); 1776216829Syongari sc->vte_watchdog_timer = 0; 1777216829Syongari vte_stats_update(sc); 1778216829Syongari /* Disable interrupts. */ 1779216829Syongari CSR_WRITE_2(sc, VTE_MIER, 0); 1780216829Syongari CSR_WRITE_2(sc, VTE_MECIER, 0); 1781216829Syongari /* Stop RX/TX MACs. */ 1782216829Syongari vte_stop_mac(sc); 1783216829Syongari /* Clear interrupts. */ 1784216829Syongari CSR_READ_2(sc, VTE_MISR); 1785216829Syongari /* 1786216829Syongari * Free TX/RX mbufs still in the queues. 1787216829Syongari */ 1788216829Syongari for (i = 0; i < VTE_RX_RING_CNT; i++) { 1789216829Syongari rxd = &sc->vte_cdata.vte_rxdesc[i]; 1790216829Syongari if (rxd->rx_m != NULL) { 1791216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_rx_tag, 1792216829Syongari rxd->rx_dmamap, BUS_DMASYNC_POSTREAD); 1793216829Syongari bus_dmamap_unload(sc->vte_cdata.vte_rx_tag, 1794216829Syongari rxd->rx_dmamap); 1795216829Syongari m_freem(rxd->rx_m); 1796216829Syongari rxd->rx_m = NULL; 1797216829Syongari } 1798216829Syongari } 1799216829Syongari for (i = 0; i < VTE_TX_RING_CNT; i++) { 1800216829Syongari txd = &sc->vte_cdata.vte_txdesc[i]; 1801216829Syongari if (txd->tx_m != NULL) { 1802216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_tx_tag, 1803216829Syongari txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); 1804216829Syongari bus_dmamap_unload(sc->vte_cdata.vte_tx_tag, 1805216829Syongari txd->tx_dmamap); 1806216829Syongari if ((txd->tx_flags & VTE_TXMBUF) == 0) 1807216829Syongari m_freem(txd->tx_m); 1808216829Syongari txd->tx_m = NULL; 1809216829Syongari txd->tx_flags &= ~VTE_TXMBUF; 1810216829Syongari } 1811216829Syongari } 1812216829Syongari /* Free TX mbuf pools used for deep copy. */ 1813216829Syongari for (i = 0; i < VTE_TX_RING_CNT; i++) { 1814216829Syongari if (sc->vte_cdata.vte_txmbufs[i] != NULL) { 1815216829Syongari m_freem(sc->vte_cdata.vte_txmbufs[i]); 1816216829Syongari sc->vte_cdata.vte_txmbufs[i] = NULL; 1817216829Syongari } 1818216829Syongari } 1819216829Syongari} 1820216829Syongari 1821216829Syongaristatic void 1822216829Syongarivte_start_mac(struct vte_softc *sc) 1823216829Syongari{ 1824216829Syongari uint16_t mcr; 1825216829Syongari int i; 1826216829Syongari 1827216829Syongari VTE_LOCK_ASSERT(sc); 1828216829Syongari 1829216829Syongari /* Enable RX/TX MACs. */ 1830216829Syongari mcr = CSR_READ_2(sc, VTE_MCR0); 1831216829Syongari if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) != 1832216829Syongari (MCR0_RX_ENB | MCR0_TX_ENB)) { 1833216829Syongari mcr |= MCR0_RX_ENB | MCR0_TX_ENB; 1834216829Syongari CSR_WRITE_2(sc, VTE_MCR0, mcr); 1835216829Syongari for (i = VTE_TIMEOUT; i > 0; i--) { 1836216829Syongari mcr = CSR_READ_2(sc, VTE_MCR0); 1837216829Syongari if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) == 1838216829Syongari (MCR0_RX_ENB | MCR0_TX_ENB)) 1839216829Syongari break; 1840216829Syongari DELAY(10); 1841216829Syongari } 1842216829Syongari if (i == 0) 1843216829Syongari device_printf(sc->vte_dev, 1844216829Syongari "could not enable RX/TX MAC(0x%04x)!\n", mcr); 1845216829Syongari } 1846216829Syongari} 1847216829Syongari 1848216829Syongaristatic void 1849216829Syongarivte_stop_mac(struct vte_softc *sc) 1850216829Syongari{ 1851216829Syongari uint16_t mcr; 1852216829Syongari int i; 1853216829Syongari 1854216829Syongari VTE_LOCK_ASSERT(sc); 1855216829Syongari 1856216829Syongari /* Disable RX/TX MACs. */ 1857216829Syongari mcr = CSR_READ_2(sc, VTE_MCR0); 1858216829Syongari if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) != 0) { 1859216829Syongari mcr &= ~(MCR0_RX_ENB | MCR0_TX_ENB); 1860216829Syongari CSR_WRITE_2(sc, VTE_MCR0, mcr); 1861216829Syongari for (i = VTE_TIMEOUT; i > 0; i--) { 1862216829Syongari mcr = CSR_READ_2(sc, VTE_MCR0); 1863216829Syongari if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) == 0) 1864216829Syongari break; 1865216829Syongari DELAY(10); 1866216829Syongari } 1867216829Syongari if (i == 0) 1868216829Syongari device_printf(sc->vte_dev, 1869216829Syongari "could not disable RX/TX MAC(0x%04x)!\n", mcr); 1870216829Syongari } 1871216829Syongari} 1872216829Syongari 1873216829Syongaristatic int 1874216829Syongarivte_init_tx_ring(struct vte_softc *sc) 1875216829Syongari{ 1876216829Syongari struct vte_tx_desc *desc; 1877216829Syongari struct vte_txdesc *txd; 1878216829Syongari bus_addr_t addr; 1879216829Syongari int i; 1880216829Syongari 1881216829Syongari VTE_LOCK_ASSERT(sc); 1882216829Syongari 1883216829Syongari sc->vte_cdata.vte_tx_prod = 0; 1884216829Syongari sc->vte_cdata.vte_tx_cons = 0; 1885216829Syongari sc->vte_cdata.vte_tx_cnt = 0; 1886216829Syongari 1887216829Syongari /* Pre-allocate TX mbufs for deep copy. */ 1888216829Syongari if (tx_deep_copy != 0) { 1889216829Syongari for (i = 0; i < VTE_TX_RING_CNT; i++) { 1890243857Sglebius sc->vte_cdata.vte_txmbufs[i] = m_getcl(M_NOWAIT, 1891216829Syongari MT_DATA, M_PKTHDR); 1892216829Syongari if (sc->vte_cdata.vte_txmbufs[i] == NULL) 1893216829Syongari return (ENOBUFS); 1894216829Syongari sc->vte_cdata.vte_txmbufs[i]->m_pkthdr.len = MCLBYTES; 1895216829Syongari sc->vte_cdata.vte_txmbufs[i]->m_len = MCLBYTES; 1896216829Syongari } 1897216829Syongari } 1898216829Syongari desc = sc->vte_cdata.vte_tx_ring; 1899216829Syongari bzero(desc, VTE_TX_RING_SZ); 1900216829Syongari for (i = 0; i < VTE_TX_RING_CNT; i++) { 1901216829Syongari txd = &sc->vte_cdata.vte_txdesc[i]; 1902216829Syongari txd->tx_m = NULL; 1903216829Syongari if (i != VTE_TX_RING_CNT - 1) 1904216829Syongari addr = sc->vte_cdata.vte_tx_ring_paddr + 1905216829Syongari sizeof(struct vte_tx_desc) * (i + 1); 1906216829Syongari else 1907216829Syongari addr = sc->vte_cdata.vte_tx_ring_paddr + 1908216829Syongari sizeof(struct vte_tx_desc) * 0; 1909216829Syongari desc = &sc->vte_cdata.vte_tx_ring[i]; 1910216829Syongari desc->dtnp = htole32(addr); 1911216829Syongari txd->tx_desc = desc; 1912216829Syongari } 1913216829Syongari 1914216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_tx_ring_tag, 1915216829Syongari sc->vte_cdata.vte_tx_ring_map, BUS_DMASYNC_PREREAD | 1916216829Syongari BUS_DMASYNC_PREWRITE); 1917216829Syongari return (0); 1918216829Syongari} 1919216829Syongari 1920216829Syongaristatic int 1921216829Syongarivte_init_rx_ring(struct vte_softc *sc) 1922216829Syongari{ 1923216829Syongari struct vte_rx_desc *desc; 1924216829Syongari struct vte_rxdesc *rxd; 1925216829Syongari bus_addr_t addr; 1926216829Syongari int i; 1927216829Syongari 1928216829Syongari VTE_LOCK_ASSERT(sc); 1929216829Syongari 1930216829Syongari sc->vte_cdata.vte_rx_cons = 0; 1931216829Syongari desc = sc->vte_cdata.vte_rx_ring; 1932216829Syongari bzero(desc, VTE_RX_RING_SZ); 1933216829Syongari for (i = 0; i < VTE_RX_RING_CNT; i++) { 1934216829Syongari rxd = &sc->vte_cdata.vte_rxdesc[i]; 1935216829Syongari rxd->rx_m = NULL; 1936216829Syongari if (i != VTE_RX_RING_CNT - 1) 1937216829Syongari addr = sc->vte_cdata.vte_rx_ring_paddr + 1938216829Syongari sizeof(struct vte_rx_desc) * (i + 1); 1939216829Syongari else 1940216829Syongari addr = sc->vte_cdata.vte_rx_ring_paddr + 1941216829Syongari sizeof(struct vte_rx_desc) * 0; 1942216829Syongari desc = &sc->vte_cdata.vte_rx_ring[i]; 1943216829Syongari desc->drnp = htole32(addr); 1944216829Syongari rxd->rx_desc = desc; 1945216829Syongari if (vte_newbuf(sc, rxd) != 0) 1946216829Syongari return (ENOBUFS); 1947216829Syongari } 1948216829Syongari 1949216829Syongari bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag, 1950216829Syongari sc->vte_cdata.vte_rx_ring_map, BUS_DMASYNC_PREREAD | 1951216829Syongari BUS_DMASYNC_PREWRITE); 1952216829Syongari 1953216829Syongari return (0); 1954216829Syongari} 1955216829Syongari 1956216829Syongaristatic void 1957216829Syongarivte_rxfilter(struct vte_softc *sc) 1958216829Syongari{ 1959216829Syongari struct ifnet *ifp; 1960216829Syongari struct ifmultiaddr *ifma; 1961216829Syongari uint8_t *eaddr; 1962216829Syongari uint32_t crc; 1963216829Syongari uint16_t rxfilt_perf[VTE_RXFILT_PERFECT_CNT][3]; 1964216829Syongari uint16_t mchash[4], mcr; 1965216829Syongari int i, nperf; 1966216829Syongari 1967216829Syongari VTE_LOCK_ASSERT(sc); 1968216829Syongari 1969216829Syongari ifp = sc->vte_ifp; 1970216829Syongari 1971216829Syongari bzero(mchash, sizeof(mchash)); 1972216829Syongari for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { 1973216829Syongari rxfilt_perf[i][0] = 0xFFFF; 1974216829Syongari rxfilt_perf[i][1] = 0xFFFF; 1975216829Syongari rxfilt_perf[i][2] = 0xFFFF; 1976216829Syongari } 1977216829Syongari 1978216829Syongari mcr = CSR_READ_2(sc, VTE_MCR0); 1979219787Syongari mcr &= ~(MCR0_PROMISC | MCR0_MULTICAST); 1980219787Syongari mcr |= MCR0_BROADCAST_DIS; 1981216829Syongari if ((ifp->if_flags & IFF_BROADCAST) != 0) 1982219787Syongari mcr &= ~MCR0_BROADCAST_DIS; 1983216829Syongari if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 1984216829Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 1985216829Syongari mcr |= MCR0_PROMISC; 1986216829Syongari if ((ifp->if_flags & IFF_ALLMULTI) != 0) 1987216829Syongari mcr |= MCR0_MULTICAST; 1988216829Syongari mchash[0] = 0xFFFF; 1989216829Syongari mchash[1] = 0xFFFF; 1990216829Syongari mchash[2] = 0xFFFF; 1991216829Syongari mchash[3] = 0xFFFF; 1992216829Syongari goto chipit; 1993216829Syongari } 1994216829Syongari 1995216829Syongari nperf = 0; 1996216829Syongari if_maddr_rlock(ifp); 1997216829Syongari TAILQ_FOREACH(ifma, &sc->vte_ifp->if_multiaddrs, ifma_link) { 1998216829Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 1999216829Syongari continue; 2000216829Syongari /* 2001216829Syongari * Program the first 3 multicast groups into 2002216829Syongari * the perfect filter. For all others, use the 2003216829Syongari * hash table. 2004216829Syongari */ 2005216829Syongari if (nperf < VTE_RXFILT_PERFECT_CNT) { 2006216829Syongari eaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2007216829Syongari rxfilt_perf[nperf][0] = eaddr[1] << 8 | eaddr[0]; 2008216829Syongari rxfilt_perf[nperf][1] = eaddr[3] << 8 | eaddr[2]; 2009216829Syongari rxfilt_perf[nperf][2] = eaddr[5] << 8 | eaddr[4]; 2010216829Syongari nperf++; 2011216829Syongari continue; 2012216829Syongari } 2013216829Syongari crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) 2014216829Syongari ifma->ifma_addr), ETHER_ADDR_LEN); 2015216829Syongari mchash[crc >> 30] |= 1 << ((crc >> 26) & 0x0F); 2016216829Syongari } 2017216829Syongari if_maddr_runlock(ifp); 2018216829Syongari if (mchash[0] != 0 || mchash[1] != 0 || mchash[2] != 0 || 2019216829Syongari mchash[3] != 0) 2020216829Syongari mcr |= MCR0_MULTICAST; 2021216829Syongari 2022216829Syongarichipit: 2023216829Syongari /* Program multicast hash table. */ 2024216829Syongari CSR_WRITE_2(sc, VTE_MAR0, mchash[0]); 2025216829Syongari CSR_WRITE_2(sc, VTE_MAR1, mchash[1]); 2026216829Syongari CSR_WRITE_2(sc, VTE_MAR2, mchash[2]); 2027216829Syongari CSR_WRITE_2(sc, VTE_MAR3, mchash[3]); 2028216829Syongari /* Program perfect filter table. */ 2029216829Syongari for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { 2030216829Syongari CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 0, 2031216829Syongari rxfilt_perf[i][0]); 2032216829Syongari CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 2, 2033216829Syongari rxfilt_perf[i][1]); 2034216829Syongari CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 4, 2035216829Syongari rxfilt_perf[i][2]); 2036216829Syongari } 2037216829Syongari CSR_WRITE_2(sc, VTE_MCR0, mcr); 2038216829Syongari CSR_READ_2(sc, VTE_MCR0); 2039216829Syongari} 2040216829Syongari 2041216829Syongaristatic int 2042216829Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 2043216829Syongari{ 2044216829Syongari int error, value; 2045216829Syongari 2046216829Syongari if (arg1 == NULL) 2047216829Syongari return (EINVAL); 2048216829Syongari value = *(int *)arg1; 2049216829Syongari error = sysctl_handle_int(oidp, &value, 0, req); 2050216829Syongari if (error || req->newptr == NULL) 2051216829Syongari return (error); 2052216829Syongari if (value < low || value > high) 2053216829Syongari return (EINVAL); 2054216829Syongari *(int *)arg1 = value; 2055216829Syongari 2056216829Syongari return (0); 2057216829Syongari} 2058216829Syongari 2059216829Syongaristatic int 2060216829Syongarisysctl_hw_vte_int_mod(SYSCTL_HANDLER_ARGS) 2061216829Syongari{ 2062216829Syongari 2063216829Syongari return (sysctl_int_range(oidp, arg1, arg2, req, 2064216829Syongari VTE_IM_BUNDLE_MIN, VTE_IM_BUNDLE_MAX)); 2065216829Syongari} 2066