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