1bfc788c2SDavid E. O'Brien /* $OpenBSD: if_nfe.c,v 1.54 2006/04/07 12:38:12 jsg Exp $ */ 2257c5577SDavid E. O'Brien 3257c5577SDavid E. O'Brien /*- 4bfc788c2SDavid E. O'Brien * Copyright (c) 2006 Shigeaki Tagashira <shigeaki@se.hiroshima-u.ac.jp> 5257c5577SDavid E. O'Brien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 6257c5577SDavid E. O'Brien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 7257c5577SDavid E. O'Brien * 8257c5577SDavid E. O'Brien * Permission to use, copy, modify, and distribute this software for any 9257c5577SDavid E. O'Brien * purpose with or without fee is hereby granted, provided that the above 10257c5577SDavid E. O'Brien * copyright notice and this permission notice appear in all copies. 11257c5577SDavid E. O'Brien * 12257c5577SDavid E. O'Brien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13257c5577SDavid E. O'Brien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14257c5577SDavid E. O'Brien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15257c5577SDavid E. O'Brien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16257c5577SDavid E. O'Brien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17257c5577SDavid E. O'Brien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18257c5577SDavid E. O'Brien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19257c5577SDavid E. O'Brien */ 20257c5577SDavid E. O'Brien 21257c5577SDavid E. O'Brien /* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 22257c5577SDavid E. O'Brien 23bfc788c2SDavid E. O'Brien #include <sys/cdefs.h> 24bfc788c2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 25bfc788c2SDavid E. O'Brien 26bfc788c2SDavid E. O'Brien /* Uncomment the following line to enable polling. */ 27bfc788c2SDavid E. O'Brien /* #define DEVICE_POLLING */ 28bfc788c2SDavid E. O'Brien 296124fe21SDavid E. O'Brien #define NFE_JUMBO 30bfc788c2SDavid E. O'Brien #define NFE_CSUM 31bfc788c2SDavid E. O'Brien #define NVLAN 0 32bfc788c2SDavid E. O'Brien 33bfc788c2SDavid E. O'Brien #ifdef HAVE_KERNEL_OPTION_HEADERS 34bfc788c2SDavid E. O'Brien #include "opt_device_polling.h" 35bfc788c2SDavid E. O'Brien #endif 36257c5577SDavid E. O'Brien 37257c5577SDavid E. O'Brien #include <sys/param.h> 38257c5577SDavid E. O'Brien #include <sys/endian.h> 39257c5577SDavid E. O'Brien #include <sys/systm.h> 40257c5577SDavid E. O'Brien #include <sys/sockio.h> 41257c5577SDavid E. O'Brien #include <sys/mbuf.h> 42257c5577SDavid E. O'Brien #include <sys/malloc.h> 43bfc788c2SDavid E. O'Brien #include <sys/module.h> 44257c5577SDavid E. O'Brien #include <sys/kernel.h> 45257c5577SDavid E. O'Brien #include <sys/socket.h> 46bfc788c2SDavid E. O'Brien #include <sys/taskqueue.h> 47257c5577SDavid E. O'Brien 48257c5577SDavid E. O'Brien #include <net/if.h> 49bfc788c2SDavid E. O'Brien #include <net/if_arp.h> 50bfc788c2SDavid E. O'Brien #include <net/ethernet.h> 51257c5577SDavid E. O'Brien #include <net/if_dl.h> 52257c5577SDavid E. O'Brien #include <net/if_media.h> 53257c5577SDavid E. O'Brien #include <net/if_types.h> 54257c5577SDavid E. O'Brien #include <net/if_vlan_var.h> 55257c5577SDavid E. O'Brien 56257c5577SDavid E. O'Brien #include <net/bpf.h> 57bfc788c2SDavid E. O'Brien 58bfc788c2SDavid E. O'Brien #include <machine/bus.h> 59bfc788c2SDavid E. O'Brien #include <machine/resource.h> 60bfc788c2SDavid E. O'Brien #include <sys/bus.h> 61bfc788c2SDavid E. O'Brien #include <sys/rman.h> 62257c5577SDavid E. O'Brien 63257c5577SDavid E. O'Brien #include <dev/mii/mii.h> 64257c5577SDavid E. O'Brien #include <dev/mii/miivar.h> 65257c5577SDavid E. O'Brien 66257c5577SDavid E. O'Brien #include <dev/pci/pcireg.h> 67257c5577SDavid E. O'Brien #include <dev/pci/pcivar.h> 68257c5577SDavid E. O'Brien 69bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfereg.h> 70bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfevar.h> 71257c5577SDavid E. O'Brien 72bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, pci, 1, 1, 1); 73bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, ether, 1, 1, 1); 74bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, miibus, 1, 1, 1); 75bfc788c2SDavid E. O'Brien #include "miibus_if.h" 76257c5577SDavid E. O'Brien 77bfc788c2SDavid E. O'Brien static int nfe_probe(device_t); 78bfc788c2SDavid E. O'Brien static int nfe_attach(device_t); 79bfc788c2SDavid E. O'Brien static int nfe_detach(device_t); 80bfc788c2SDavid E. O'Brien static void nfe_shutdown(device_t); 81bfc788c2SDavid E. O'Brien static int nfe_miibus_readreg(device_t, int, int); 82bfc788c2SDavid E. O'Brien static int nfe_miibus_writereg(device_t, int, int, int); 83bfc788c2SDavid E. O'Brien static void nfe_miibus_statchg(device_t); 84bfc788c2SDavid E. O'Brien static int nfe_ioctl(struct ifnet *, u_long, caddr_t); 85bfc788c2SDavid E. O'Brien static void nfe_intr(void *); 86bfc788c2SDavid E. O'Brien static void nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 87bfc788c2SDavid E. O'Brien static void nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 88bfc788c2SDavid E. O'Brien static void nfe_txdesc32_rsync(struct nfe_softc *, int, int, int); 89bfc788c2SDavid E. O'Brien static void nfe_txdesc64_rsync(struct nfe_softc *, int, int, int); 90bfc788c2SDavid E. O'Brien static void nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 91bfc788c2SDavid E. O'Brien static void nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 92bfc788c2SDavid E. O'Brien static void nfe_rxeof(struct nfe_softc *); 93bfc788c2SDavid E. O'Brien static void nfe_txeof(struct nfe_softc *); 94bfc788c2SDavid E. O'Brien static int nfe_encap(struct nfe_softc *, struct mbuf *); 95bfc788c2SDavid E. O'Brien static void nfe_setmulti(struct nfe_softc *); 96bfc788c2SDavid E. O'Brien static void nfe_start(struct ifnet *); 97bfc788c2SDavid E. O'Brien static void nfe_start_locked(struct ifnet *); 98bfc788c2SDavid E. O'Brien static void nfe_watchdog(struct ifnet *); 99bfc788c2SDavid E. O'Brien static void nfe_init(void *); 100bfc788c2SDavid E. O'Brien static void nfe_init_locked(void *); 101bfc788c2SDavid E. O'Brien static void nfe_stop(struct ifnet *, int); 102bfc788c2SDavid E. O'Brien static int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 103bfc788c2SDavid E. O'Brien static void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 104bfc788c2SDavid E. O'Brien static void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 105bfc788c2SDavid E. O'Brien static int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 106bfc788c2SDavid E. O'Brien static void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 107bfc788c2SDavid E. O'Brien static void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 108bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd(struct ifnet *); 109bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd_locked(struct ifnet *); 110bfc788c2SDavid E. O'Brien static void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 111bfc788c2SDavid E. O'Brien static void nfe_tick(void *); 112bfc788c2SDavid E. O'Brien static void nfe_tick_locked(struct nfe_softc *); 113bfc788c2SDavid E. O'Brien static void nfe_get_macaddr(struct nfe_softc *, u_char *); 114bfc788c2SDavid E. O'Brien static void nfe_set_macaddr(struct nfe_softc *, u_char *); 115bfc788c2SDavid E. O'Brien static void nfe_dma_map_segs (void *, bus_dma_segment_t *, int, int); 116bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 117bfc788c2SDavid E. O'Brien static void nfe_poll_locked(struct ifnet *, enum poll_cmd, int); 118bfc788c2SDavid E. O'Brien #endif 119257c5577SDavid E. O'Brien 120257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 121257c5577SDavid E. O'Brien int nfedebug = 0; 122257c5577SDavid E. O'Brien #define DPRINTF(x) do { if (nfedebug) printf x; } while (0) 123257c5577SDavid E. O'Brien #define DPRINTFN(n,x) do { if (nfedebug >= (n)) printf x; } while (0) 124257c5577SDavid E. O'Brien #else 125257c5577SDavid E. O'Brien #define DPRINTF(x) 126257c5577SDavid E. O'Brien #define DPRINTFN(n,x) 127257c5577SDavid E. O'Brien #endif 128257c5577SDavid E. O'Brien 129bfc788c2SDavid E. O'Brien #define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 130bfc788c2SDavid E. O'Brien #define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 131bfc788c2SDavid E. O'Brien #define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 132bfc788c2SDavid E. O'Brien 133bfc788c2SDavid E. O'Brien #define letoh16(x) le16toh(x) 134bfc788c2SDavid E. O'Brien 135bfc788c2SDavid E. O'Brien #define NV_RID 0x10 136bfc788c2SDavid E. O'Brien 137bfc788c2SDavid E. O'Brien static device_method_t nfe_methods[] = { 138bfc788c2SDavid E. O'Brien /* Device interface */ 139bfc788c2SDavid E. O'Brien DEVMETHOD(device_probe, nfe_probe), 140bfc788c2SDavid E. O'Brien DEVMETHOD(device_attach, nfe_attach), 141bfc788c2SDavid E. O'Brien DEVMETHOD(device_detach, nfe_detach), 142bfc788c2SDavid E. O'Brien DEVMETHOD(device_shutdown, nfe_shutdown), 143bfc788c2SDavid E. O'Brien 144bfc788c2SDavid E. O'Brien /* bus interface */ 145bfc788c2SDavid E. O'Brien DEVMETHOD(bus_print_child, bus_generic_print_child), 146bfc788c2SDavid E. O'Brien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 147bfc788c2SDavid E. O'Brien 148bfc788c2SDavid E. O'Brien /* MII interface */ 149bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 150bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 151bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 152bfc788c2SDavid E. O'Brien 153bfc788c2SDavid E. O'Brien { 0, 0 } 154257c5577SDavid E. O'Brien }; 155257c5577SDavid E. O'Brien 156bfc788c2SDavid E. O'Brien static driver_t nfe_driver = { 157bfc788c2SDavid E. O'Brien "nfe", 158bfc788c2SDavid E. O'Brien nfe_methods, 159bfc788c2SDavid E. O'Brien sizeof(struct nfe_softc) 160bfc788c2SDavid E. O'Brien }; 161bfc788c2SDavid E. O'Brien 162bfc788c2SDavid E. O'Brien static devclass_t nfe_devclass; 163bfc788c2SDavid E. O'Brien 164bfc788c2SDavid E. O'Brien DRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 165bfc788c2SDavid E. O'Brien DRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 166bfc788c2SDavid E. O'Brien 167bfc788c2SDavid E. O'Brien static struct nfe_type nfe_devs[] = { 168bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 1696bec3967SDavid E. O'Brien "NVIDIA nForce MCP Networking Adapter"}, 170bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 1716bec3967SDavid E. O'Brien "NVIDIA nForce2 MCP2 Networking Adapter"}, 172bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 1736bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 174bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 1756bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 1766bec3967SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 1776bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP3 Networking Adapter"}, 178bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 1796bec3967SDavid E. O'Brien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 180bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 1816bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP7 Networking Adapter"}, 182bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 1836bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 184bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 1856bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 186bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 1876bec3967SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, // MCP10 188bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 1896bec3967SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, // MCP11 190bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 1916bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 192bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 1936bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 194bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 195bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 196bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 197bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 1983e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 1993e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2003e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2013e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2023e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 2033e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2043e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2053e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2063e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 2073e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2083e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2093e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2103e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 2113e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2123e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2133e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 214bfc788c2SDavid E. O'Brien {0, 0, NULL} 215bfc788c2SDavid E. O'Brien }; 216bfc788c2SDavid E. O'Brien 217bfc788c2SDavid E. O'Brien 218bfc788c2SDavid E. O'Brien /* Probe for supported hardware ID's */ 219bfc788c2SDavid E. O'Brien static int 220bfc788c2SDavid E. O'Brien nfe_probe(device_t dev) 221257c5577SDavid E. O'Brien { 222bfc788c2SDavid E. O'Brien struct nfe_type *t; 223bfc788c2SDavid E. O'Brien 224bfc788c2SDavid E. O'Brien t = nfe_devs; 225bfc788c2SDavid E. O'Brien /* Check for matching PCI DEVICE ID's */ 226bfc788c2SDavid E. O'Brien while (t->name != NULL) { 227bfc788c2SDavid E. O'Brien if ((pci_get_vendor(dev) == t->vid_id) && 228bfc788c2SDavid E. O'Brien (pci_get_device(dev) == t->dev_id)) { 229bfc788c2SDavid E. O'Brien device_set_desc(dev, t->name); 230bfc788c2SDavid E. O'Brien return (0); 231bfc788c2SDavid E. O'Brien } 232bfc788c2SDavid E. O'Brien t++; 233257c5577SDavid E. O'Brien } 234257c5577SDavid E. O'Brien 235bfc788c2SDavid E. O'Brien return (ENXIO); 236bfc788c2SDavid E. O'Brien } 237bfc788c2SDavid E. O'Brien 2382c3adf61SDavid E. O'Brien 239bfc788c2SDavid E. O'Brien static int 240bfc788c2SDavid E. O'Brien nfe_attach(device_t dev) 241257c5577SDavid E. O'Brien { 242bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 243257c5577SDavid E. O'Brien struct ifnet *ifp; 244bfc788c2SDavid E. O'Brien int unit, error = 0, rid; 245257c5577SDavid E. O'Brien 246bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 247bfc788c2SDavid E. O'Brien unit = device_get_unit(dev); 248bfc788c2SDavid E. O'Brien sc->nfe_dev = dev; 249bfc788c2SDavid E. O'Brien sc->nfe_unit = unit; 250bfc788c2SDavid E. O'Brien 251bfc788c2SDavid E. O'Brien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 252bfc788c2SDavid E. O'Brien MTX_DEF | MTX_RECURSE); 253bfc788c2SDavid E. O'Brien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 254bfc788c2SDavid E. O'Brien 255bfc788c2SDavid E. O'Brien pci_enable_busmaster(dev); 256bfc788c2SDavid E. O'Brien 257bfc788c2SDavid E. O'Brien rid = NV_RID; 258bfc788c2SDavid E. O'Brien sc->nfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 259bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_ACTIVE); 260bfc788c2SDavid E. O'Brien 261bfc788c2SDavid E. O'Brien if (sc->nfe_res == NULL) { 262bfc788c2SDavid E. O'Brien printf ("nfe%d: couldn't map ports/memory\n", unit); 263bfc788c2SDavid E. O'Brien error = ENXIO; 264bfc788c2SDavid E. O'Brien goto fail; 265257c5577SDavid E. O'Brien } 266257c5577SDavid E. O'Brien 267bfc788c2SDavid E. O'Brien sc->nfe_memt = rman_get_bustag(sc->nfe_res); 268bfc788c2SDavid E. O'Brien sc->nfe_memh = rman_get_bushandle(sc->nfe_res); 269bfc788c2SDavid E. O'Brien 270bfc788c2SDavid E. O'Brien /* Allocate interrupt */ 271bfc788c2SDavid E. O'Brien rid = 0; 272bfc788c2SDavid E. O'Brien sc->nfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 273bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 274bfc788c2SDavid E. O'Brien 275bfc788c2SDavid E. O'Brien if (sc->nfe_irq == NULL) { 276bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't map interrupt\n", unit); 277bfc788c2SDavid E. O'Brien error = ENXIO; 278bfc788c2SDavid E. O'Brien goto fail; 279257c5577SDavid E. O'Brien } 280257c5577SDavid E. O'Brien 281bfc788c2SDavid E. O'Brien nfe_get_macaddr(sc, sc->eaddr); 282257c5577SDavid E. O'Brien 283bfc788c2SDavid E. O'Brien sc->nfe_flags = 0; 284257c5577SDavid E. O'Brien 285bfc788c2SDavid E. O'Brien switch (pci_get_device(dev)) { 286257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 287257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 288257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 289257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 290bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 291257c5577SDavid E. O'Brien break; 292257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 293257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 294bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 295257c5577SDavid E. O'Brien break; 296257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 297257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 298257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 299257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 300bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 301257c5577SDavid E. O'Brien break; 302257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 303257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 3042c3adf61SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 3052c3adf61SDavid E. O'Brien NFE_HW_VLAN; 306257c5577SDavid E. O'Brien break; 3073e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 3083e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 3093e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 3103e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 3113e232000SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 3123e232000SDavid E. O'Brien break; 3133e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 3143e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 3153e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 3163e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 3173e232000SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 3183e232000SDavid E. O'Brien break; 319257c5577SDavid E. O'Brien } 320257c5577SDavid E. O'Brien 321257c5577SDavid E. O'Brien /* 322bfc788c2SDavid E. O'Brien * Allocate the parent bus DMA tag appropriate for PCI. 323bfc788c2SDavid E. O'Brien */ 324bfc788c2SDavid E. O'Brien #define NFE_NSEG_NEW 32 325bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(NULL, /* parent */ 326bfc788c2SDavid E. O'Brien 1, 0, /* alignment, boundary */ 327bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 328bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 329bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 330bfc788c2SDavid E. O'Brien MAXBSIZE, NFE_NSEG_NEW, /* maxsize, nsegments */ 331bfc788c2SDavid E. O'Brien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 332bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 333bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 334bfc788c2SDavid E. O'Brien &sc->nfe_parent_tag); 335bfc788c2SDavid E. O'Brien if (error) 336bfc788c2SDavid E. O'Brien goto fail; 337bfc788c2SDavid E. O'Brien 3386124fe21SDavid E. O'Brien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 3396124fe21SDavid E. O'Brien if (ifp == NULL) { 3406124fe21SDavid E. O'Brien printf("nfe%d: can not if_alloc()\n", unit); 3416124fe21SDavid E. O'Brien error = ENOSPC; 3426124fe21SDavid E. O'Brien goto fail; 3436124fe21SDavid E. O'Brien } 3446124fe21SDavid E. O'Brien sc->nfe_mtu = ifp->if_mtu = ETHERMTU; 3456124fe21SDavid E. O'Brien 346bfc788c2SDavid E. O'Brien /* 347257c5577SDavid E. O'Brien * Allocate Tx and Rx rings. 348257c5577SDavid E. O'Brien */ 349257c5577SDavid E. O'Brien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 350bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Tx ring\n", unit); 351bfc788c2SDavid E. O'Brien error = ENXIO; 352bfc788c2SDavid E. O'Brien goto fail; 353257c5577SDavid E. O'Brien } 354257c5577SDavid E. O'Brien 355257c5577SDavid E. O'Brien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 356bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Rx ring\n", unit); 357257c5577SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 358bfc788c2SDavid E. O'Brien error = ENXIO; 359bfc788c2SDavid E. O'Brien goto fail; 360257c5577SDavid E. O'Brien } 361257c5577SDavid E. O'Brien 362257c5577SDavid E. O'Brien ifp->if_softc = sc; 363bfc788c2SDavid E. O'Brien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 364257c5577SDavid E. O'Brien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 365257c5577SDavid E. O'Brien ifp->if_ioctl = nfe_ioctl; 366257c5577SDavid E. O'Brien ifp->if_start = nfe_start; 367bfc788c2SDavid E. O'Brien /* ifp->if_hwassist = NFE_CSUM_FEATURES; */ 368257c5577SDavid E. O'Brien ifp->if_watchdog = nfe_watchdog; 369257c5577SDavid E. O'Brien ifp->if_init = nfe_init; 370257c5577SDavid E. O'Brien ifp->if_baudrate = IF_Gbps(1); 371bfc788c2SDavid E. O'Brien ifp->if_snd.ifq_maxlen = NFE_IFQ_MAXLEN; 372257c5577SDavid E. O'Brien 373257c5577SDavid E. O'Brien ifp->if_capabilities = IFCAP_VLAN_MTU; 3746124fe21SDavid E. O'Brien 3756124fe21SDavid E. O'Brien #ifdef NFE_JUMBO 3766124fe21SDavid E. O'Brien ifp->if_capabilities |= IFCAP_JUMBO_MTU; 3776124fe21SDavid E. O'Brien #else 3786124fe21SDavid E. O'Brien ifp->if_capabilities &= ~IFCAP_JUMBO_MTU; 3796124fe21SDavid E. O'Brien sc->nfe_flags &= ~NFE_JUMBO_SUP; 3806124fe21SDavid E. O'Brien #endif 3816124fe21SDavid E. O'Brien 382257c5577SDavid E. O'Brien #if NVLAN > 0 383bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 384257c5577SDavid E. O'Brien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 385257c5577SDavid E. O'Brien #endif 386257c5577SDavid E. O'Brien #ifdef NFE_CSUM 387bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) { 388bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_HWCSUM; 3897597761aSDavid E. O'Brien ifp->if_capenable |= IFCAP_HWCSUM; 3907597761aSDavid E. O'Brien ifp->if_hwassist = NFE_CSUM_FEATURES; 391257c5577SDavid E. O'Brien } 3927597761aSDavid E. O'Brien #else 3937597761aSDavid E. O'Brien sc->nfe_flags &= ~NFE_HW_CSUM; 394257c5577SDavid E. O'Brien #endif 395bfc788c2SDavid E. O'Brien ifp->if_capenable = ifp->if_capabilities; 396257c5577SDavid E. O'Brien 397bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 398bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_POLLING; 399bfc788c2SDavid E. O'Brien #endif 400257c5577SDavid E. O'Brien 401bfc788c2SDavid E. O'Brien /* Do MII setup */ 4022c3adf61SDavid E. O'Brien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, 4032c3adf61SDavid E. O'Brien nfe_ifmedia_sts)) { 404bfc788c2SDavid E. O'Brien printf("nfe%d: MII without any phy!\n", unit); 405bfc788c2SDavid E. O'Brien error = ENXIO; 406bfc788c2SDavid E. O'Brien goto fail; 407257c5577SDavid E. O'Brien } 408257c5577SDavid E. O'Brien 409bfc788c2SDavid E. O'Brien ether_ifattach(ifp, sc->eaddr); 410bfc788c2SDavid E. O'Brien 411bfc788c2SDavid E. O'Brien error = bus_setup_intr(dev, sc->nfe_irq, INTR_TYPE_NET | INTR_MPSAFE, 412bfc788c2SDavid E. O'Brien nfe_intr, sc, &sc->nfe_intrhand); 413bfc788c2SDavid E. O'Brien 414bfc788c2SDavid E. O'Brien if (error) { 415bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't set up irq\n", unit); 416bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 417bfc788c2SDavid E. O'Brien goto fail; 418bfc788c2SDavid E. O'Brien } 419bfc788c2SDavid E. O'Brien 420bfc788c2SDavid E. O'Brien fail: 421bfc788c2SDavid E. O'Brien if (error) 422bfc788c2SDavid E. O'Brien nfe_detach(dev); 423bfc788c2SDavid E. O'Brien 424bfc788c2SDavid E. O'Brien return (error); 425bfc788c2SDavid E. O'Brien } 426bfc788c2SDavid E. O'Brien 427bfc788c2SDavid E. O'Brien 428bfc788c2SDavid E. O'Brien static int 429bfc788c2SDavid E. O'Brien nfe_detach(device_t dev) 430257c5577SDavid E. O'Brien { 431bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 432257c5577SDavid E. O'Brien struct ifnet *ifp; 433bfc788c2SDavid E. O'Brien u_char eaddr[ETHER_ADDR_LEN]; 434bfc788c2SDavid E. O'Brien int i; 435257c5577SDavid E. O'Brien 436bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 437bfc788c2SDavid E. O'Brien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 438bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 439bfc788c2SDavid E. O'Brien 440bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 441bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 442bfc788c2SDavid E. O'Brien ether_poll_deregister(ifp); 443bfc788c2SDavid E. O'Brien #endif 444bfc788c2SDavid E. O'Brien 445bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 446bfc788c2SDavid E. O'Brien eaddr[i] = sc->eaddr[5 - i]; 447257c5577SDavid E. O'Brien } 448bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, eaddr); 449bfc788c2SDavid E. O'Brien 450bfc788c2SDavid E. O'Brien if (device_is_attached(dev)) { 45196058696SDavid E. O'Brien NFE_LOCK(sc); 452bfc788c2SDavid E. O'Brien nfe_stop(ifp, 1); 453bfc788c2SDavid E. O'Brien ifp->if_flags &= ~IFF_UP; 45496058696SDavid E. O'Brien NFE_UNLOCK(sc); 455bfc788c2SDavid E. O'Brien callout_drain(&sc->nfe_stat_ch); 456bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 457257c5577SDavid E. O'Brien } 458257c5577SDavid E. O'Brien 459bfc788c2SDavid E. O'Brien if (ifp) 460bfc788c2SDavid E. O'Brien if_free(ifp); 461bfc788c2SDavid E. O'Brien if (sc->nfe_miibus) 462bfc788c2SDavid E. O'Brien device_delete_child(dev, sc->nfe_miibus); 463bfc788c2SDavid E. O'Brien bus_generic_detach(dev); 464bfc788c2SDavid E. O'Brien 465bfc788c2SDavid E. O'Brien if (sc->nfe_intrhand) 466bfc788c2SDavid E. O'Brien bus_teardown_intr(dev, sc->nfe_irq, sc->nfe_intrhand); 467bfc788c2SDavid E. O'Brien if (sc->nfe_irq) 468bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nfe_irq); 469bfc788c2SDavid E. O'Brien if (sc->nfe_res) 470bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_MEMORY, NV_RID, sc->nfe_res); 471bfc788c2SDavid E. O'Brien 472bfc788c2SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 473bfc788c2SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 474bfc788c2SDavid E. O'Brien 475bfc788c2SDavid E. O'Brien if (sc->nfe_parent_tag) 476bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(sc->nfe_parent_tag); 477bfc788c2SDavid E. O'Brien 478bfc788c2SDavid E. O'Brien mtx_destroy(&sc->nfe_mtx); 479bfc788c2SDavid E. O'Brien 480bfc788c2SDavid E. O'Brien return (0); 481bfc788c2SDavid E. O'Brien } 482bfc788c2SDavid E. O'Brien 483bfc788c2SDavid E. O'Brien 484bfc788c2SDavid E. O'Brien static void 485bfc788c2SDavid E. O'Brien nfe_miibus_statchg(device_t dev) 486257c5577SDavid E. O'Brien { 487bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 488bfc788c2SDavid E. O'Brien struct mii_data *mii; 489bfc788c2SDavid E. O'Brien u_int32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 490bfc788c2SDavid E. O'Brien 491bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 492bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 493257c5577SDavid E. O'Brien 494257c5577SDavid E. O'Brien phy = NFE_READ(sc, NFE_PHY_IFACE); 495257c5577SDavid E. O'Brien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 496257c5577SDavid E. O'Brien 497257c5577SDavid E. O'Brien seed = NFE_READ(sc, NFE_RNDSEED); 498257c5577SDavid E. O'Brien seed &= ~NFE_SEED_MASK; 499257c5577SDavid E. O'Brien 500257c5577SDavid E. O'Brien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 501257c5577SDavid E. O'Brien phy |= NFE_PHY_HDX; /* half-duplex */ 502257c5577SDavid E. O'Brien misc |= NFE_MISC1_HDX; 503257c5577SDavid E. O'Brien } 504257c5577SDavid E. O'Brien 505257c5577SDavid E. O'Brien switch (IFM_SUBTYPE(mii->mii_media_active)) { 506257c5577SDavid E. O'Brien case IFM_1000_T: /* full-duplex only */ 507257c5577SDavid E. O'Brien link |= NFE_MEDIA_1000T; 508257c5577SDavid E. O'Brien seed |= NFE_SEED_1000T; 509257c5577SDavid E. O'Brien phy |= NFE_PHY_1000T; 510257c5577SDavid E. O'Brien break; 511257c5577SDavid E. O'Brien case IFM_100_TX: 512257c5577SDavid E. O'Brien link |= NFE_MEDIA_100TX; 513257c5577SDavid E. O'Brien seed |= NFE_SEED_100TX; 514257c5577SDavid E. O'Brien phy |= NFE_PHY_100TX; 515257c5577SDavid E. O'Brien break; 516257c5577SDavid E. O'Brien case IFM_10_T: 517257c5577SDavid E. O'Brien link |= NFE_MEDIA_10T; 518257c5577SDavid E. O'Brien seed |= NFE_SEED_10T; 519257c5577SDavid E. O'Brien break; 520257c5577SDavid E. O'Brien } 521257c5577SDavid E. O'Brien 522257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 523257c5577SDavid E. O'Brien 524257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 525257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MISC1, misc); 526257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_LINKSPEED, link); 527257c5577SDavid E. O'Brien } 528257c5577SDavid E. O'Brien 5292c3adf61SDavid E. O'Brien 530bfc788c2SDavid E. O'Brien static int 531bfc788c2SDavid E. O'Brien nfe_miibus_readreg(device_t dev, int phy, int reg) 532257c5577SDavid E. O'Brien { 533bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 534bfc788c2SDavid E. O'Brien u_int32_t val; 535257c5577SDavid E. O'Brien int ntries; 536257c5577SDavid E. O'Brien 537257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 538257c5577SDavid E. O'Brien 539257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 540257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 541257c5577SDavid E. O'Brien DELAY(100); 542257c5577SDavid E. O'Brien } 543257c5577SDavid E. O'Brien 544257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 545257c5577SDavid E. O'Brien 546257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 547257c5577SDavid E. O'Brien DELAY(100); 548257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 549257c5577SDavid E. O'Brien break; 550257c5577SDavid E. O'Brien } 551257c5577SDavid E. O'Brien if (ntries == 1000) { 552bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: timeout waiting for PHY\n", sc->nfe_unit)); 553257c5577SDavid E. O'Brien return 0; 554257c5577SDavid E. O'Brien } 555257c5577SDavid E. O'Brien 556257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 557bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: could not read PHY\n", sc->nfe_unit)); 558257c5577SDavid E. O'Brien return 0; 559257c5577SDavid E. O'Brien } 560257c5577SDavid E. O'Brien 561257c5577SDavid E. O'Brien val = NFE_READ(sc, NFE_PHY_DATA); 562257c5577SDavid E. O'Brien if (val != 0xffffffff && val != 0) 563257c5577SDavid E. O'Brien sc->mii_phyaddr = phy; 564257c5577SDavid E. O'Brien 5652c3adf61SDavid E. O'Brien DPRINTFN(2, ("nfe%d: mii read phy %d reg 0x%x ret 0x%x\n", 5662c3adf61SDavid E. O'Brien sc->nfe_unit, phy, reg, val)); 567257c5577SDavid E. O'Brien 568257c5577SDavid E. O'Brien return val; 569257c5577SDavid E. O'Brien } 570257c5577SDavid E. O'Brien 5712c3adf61SDavid E. O'Brien 572bfc788c2SDavid E. O'Brien static int 573bfc788c2SDavid E. O'Brien nfe_miibus_writereg(device_t dev, int phy, int reg, int val) 574257c5577SDavid E. O'Brien { 575bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 576bfc788c2SDavid E. O'Brien u_int32_t ctl; 577257c5577SDavid E. O'Brien int ntries; 578257c5577SDavid E. O'Brien 579257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 580257c5577SDavid E. O'Brien 581257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 582257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 583257c5577SDavid E. O'Brien DELAY(100); 584257c5577SDavid E. O'Brien } 585257c5577SDavid E. O'Brien 586257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_DATA, val); 587257c5577SDavid E. O'Brien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 588257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 589257c5577SDavid E. O'Brien 590257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 591257c5577SDavid E. O'Brien DELAY(100); 592257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 593257c5577SDavid E. O'Brien break; 594257c5577SDavid E. O'Brien } 595257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 596257c5577SDavid E. O'Brien if (nfedebug >= 2 && ntries == 1000) 597257c5577SDavid E. O'Brien printf("could not write to PHY\n"); 598257c5577SDavid E. O'Brien #endif 599bfc788c2SDavid E. O'Brien return 0; 600257c5577SDavid E. O'Brien } 601257c5577SDavid E. O'Brien 6022c3adf61SDavid E. O'Brien 603bfc788c2SDavid E. O'Brien static int 604bfc788c2SDavid E. O'Brien nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 605bfc788c2SDavid E. O'Brien { 606bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32; 607bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64; 608bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 609bfc788c2SDavid E. O'Brien void **desc; 610bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 611bfc788c2SDavid E. O'Brien int i, error, descsize; 612bfc788c2SDavid E. O'Brien 613bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 614bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 615bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 616bfc788c2SDavid E. O'Brien } else { 617bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 618bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 619bfc788c2SDavid E. O'Brien } 620bfc788c2SDavid E. O'Brien 621bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 6226124fe21SDavid E. O'Brien ring->bufsz = (sc->nfe_mtu + NFE_RX_HEADERS <= MCLBYTES) ? 6236124fe21SDavid E. O'Brien MCLBYTES : MJUM9BYTES; 624bfc788c2SDavid E. O'Brien 625bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 626bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 627bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 628bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 629bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 630bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 631bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 632bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 633bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 634bfc788c2SDavid E. O'Brien &ring->rx_desc_tag); 635bfc788c2SDavid E. O'Brien if (error != 0) { 636bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 637bfc788c2SDavid E. O'Brien goto fail; 638bfc788c2SDavid E. O'Brien } 639bfc788c2SDavid E. O'Brien 640bfc788c2SDavid E. O'Brien /* allocate memory to desc */ 6412c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_desc_tag, (void **)desc, 6422c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->rx_desc_map); 643bfc788c2SDavid E. O'Brien if (error != 0) { 644bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 645bfc788c2SDavid E. O'Brien goto fail; 646bfc788c2SDavid E. O'Brien } 647bfc788c2SDavid E. O'Brien 648bfc788c2SDavid E. O'Brien /* map desc to device visible address space */ 649bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, *desc, 6502c3adf61SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, 6512c3adf61SDavid E. O'Brien &ring->rx_desc_segs, BUS_DMA_NOWAIT); 652bfc788c2SDavid E. O'Brien if (error != 0) { 653bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 654bfc788c2SDavid E. O'Brien goto fail; 655bfc788c2SDavid E. O'Brien } 656bfc788c2SDavid E. O'Brien 657bfc788c2SDavid E. O'Brien bzero(*desc, NFE_RX_RING_COUNT * descsize); 658bfc788c2SDavid E. O'Brien ring->rx_desc_addr = ring->rx_desc_segs.ds_addr; 659bfc788c2SDavid E. O'Brien ring->physaddr = ring->rx_desc_addr; 660bfc788c2SDavid E. O'Brien 661bfc788c2SDavid E. O'Brien /* 662bfc788c2SDavid E. O'Brien * Pre-allocate Rx buffers and populate Rx ring. 663bfc788c2SDavid E. O'Brien */ 664bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 665bfc788c2SDavid E. O'Brien data = &sc->rxq.data[i]; 666bfc788c2SDavid E. O'Brien 667bfc788c2SDavid E. O'Brien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 668bfc788c2SDavid E. O'Brien if (data->m == NULL) { 6692c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate rx mbuf\n", 6702c3adf61SDavid E. O'Brien sc->nfe_unit); 671bfc788c2SDavid E. O'Brien error = ENOMEM; 672bfc788c2SDavid E. O'Brien goto fail; 673bfc788c2SDavid E. O'Brien } 674bfc788c2SDavid E. O'Brien 675bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 676d0220c83SRuslan Ermilov ETHER_ALIGN, 0, /* alignment, boundary */ 677bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 678bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 679bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 680bfc788c2SDavid E. O'Brien MCLBYTES, 1, /* maxsize, nsegments */ 681bfc788c2SDavid E. O'Brien MCLBYTES, /* maxsegsize */ 682bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 683bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 684bfc788c2SDavid E. O'Brien &data->rx_data_tag); 685bfc788c2SDavid E. O'Brien if (error != 0) { 6862c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 6872c3adf61SDavid E. O'Brien sc->nfe_unit); 688bfc788c2SDavid E. O'Brien goto fail; 689bfc788c2SDavid E. O'Brien } 690bfc788c2SDavid E. O'Brien 6912c3adf61SDavid E. O'Brien error = bus_dmamap_create(data->rx_data_tag, 0, 6922c3adf61SDavid E. O'Brien &data->rx_data_map); 693bfc788c2SDavid E. O'Brien if (error != 0) { 6942c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate mbuf cluster\n", 6952c3adf61SDavid E. O'Brien sc->nfe_unit); 696bfc788c2SDavid E. O'Brien goto fail; 697bfc788c2SDavid E. O'Brien } 698bfc788c2SDavid E. O'Brien 699bfc788c2SDavid E. O'Brien MCLGET(data->m, M_DONTWAIT); 700bfc788c2SDavid E. O'Brien if (!(data->m->m_flags & M_EXT)) { 701bfc788c2SDavid E. O'Brien error = ENOMEM; 702bfc788c2SDavid E. O'Brien goto fail; 703bfc788c2SDavid E. O'Brien } 704bfc788c2SDavid E. O'Brien 7052c3adf61SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 7066124fe21SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), 70730ce3a12SDavid E. O'Brien ring->bufsz, nfe_dma_map_segs, &data->rx_data_segs, 7082c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 709bfc788c2SDavid E. O'Brien if (error != 0) { 7102c3adf61SDavid E. O'Brien printf("nfe%d: could not load rx buf DMA map\n", 7112c3adf61SDavid E. O'Brien sc->nfe_unit); 712bfc788c2SDavid E. O'Brien goto fail; 713bfc788c2SDavid E. O'Brien } 714bfc788c2SDavid E. O'Brien 715bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 716bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 717bfc788c2SDavid E. O'Brien 718bfc788c2SDavid E. O'Brien 719bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 720bfc788c2SDavid E. O'Brien desc64 = &sc->rxq.desc64[i]; 721bfc788c2SDavid E. O'Brien #if defined(__LP64__) 722bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 723bfc788c2SDavid E. O'Brien #endif 724bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 725bfc788c2SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 726bfc788c2SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 727bfc788c2SDavid E. O'Brien } else { 728bfc788c2SDavid E. O'Brien desc32 = &sc->rxq.desc32[i]; 729bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 730bfc788c2SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 731bfc788c2SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 732bfc788c2SDavid E. O'Brien } 733bfc788c2SDavid E. O'Brien 734bfc788c2SDavid E. O'Brien } 735bfc788c2SDavid E. O'Brien 7362c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7372c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 738bfc788c2SDavid E. O'Brien 739bfc788c2SDavid E. O'Brien return 0; 740bfc788c2SDavid E. O'Brien 741bfc788c2SDavid E. O'Brien fail: nfe_free_rx_ring(sc, ring); 742bfc788c2SDavid E. O'Brien 743bfc788c2SDavid E. O'Brien return error; 744bfc788c2SDavid E. O'Brien } 745bfc788c2SDavid E. O'Brien 7462c3adf61SDavid E. O'Brien 747bfc788c2SDavid E. O'Brien static void 748bfc788c2SDavid E. O'Brien nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 749bfc788c2SDavid E. O'Brien { 750bfc788c2SDavid E. O'Brien int i; 751bfc788c2SDavid E. O'Brien 752bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 753bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 754bfc788c2SDavid E. O'Brien ring->desc64[i].length = htole16(ring->bufsz); 755bfc788c2SDavid E. O'Brien ring->desc64[i].flags = htole16(NFE_RX_READY); 756bfc788c2SDavid E. O'Brien } else { 757bfc788c2SDavid E. O'Brien ring->desc32[i].length = htole16(ring->bufsz); 758bfc788c2SDavid E. O'Brien ring->desc32[i].flags = htole16(NFE_RX_READY); 759bfc788c2SDavid E. O'Brien } 760bfc788c2SDavid E. O'Brien } 761bfc788c2SDavid E. O'Brien 7622c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7632c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 764bfc788c2SDavid E. O'Brien 765bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 766bfc788c2SDavid E. O'Brien } 767bfc788c2SDavid E. O'Brien 768bfc788c2SDavid E. O'Brien 769bfc788c2SDavid E. O'Brien static void 770bfc788c2SDavid E. O'Brien nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 771bfc788c2SDavid E. O'Brien { 772bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 773bfc788c2SDavid E. O'Brien void *desc; 774bfc788c2SDavid E. O'Brien int i, descsize; 775bfc788c2SDavid E. O'Brien 776bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 777bfc788c2SDavid E. O'Brien desc = ring->desc64; 778bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 779bfc788c2SDavid E. O'Brien } else { 780bfc788c2SDavid E. O'Brien desc = ring->desc32; 781bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 782bfc788c2SDavid E. O'Brien } 783bfc788c2SDavid E. O'Brien 784bfc788c2SDavid E. O'Brien if (desc != NULL) { 7852c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7862c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 787bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 788bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 789bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->rx_desc_tag); 790bfc788c2SDavid E. O'Brien } 791bfc788c2SDavid E. O'Brien 792bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 793bfc788c2SDavid E. O'Brien data = &ring->data[i]; 794bfc788c2SDavid E. O'Brien 795bfc788c2SDavid E. O'Brien if (data->rx_data_map != NULL) { 7962c3adf61SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, 7972c3adf61SDavid E. O'Brien data->rx_data_map, BUS_DMASYNC_POSTREAD); 7982c3adf61SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, 7992c3adf61SDavid E. O'Brien data->rx_data_map); 8002c3adf61SDavid E. O'Brien bus_dmamap_destroy(data->rx_data_tag, 8012c3adf61SDavid E. O'Brien data->rx_data_map); 802bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(data->rx_data_tag); 803bfc788c2SDavid E. O'Brien } 8042c3adf61SDavid E. O'Brien 805bfc788c2SDavid E. O'Brien if (data->m != NULL) 806bfc788c2SDavid E. O'Brien m_freem(data->m); 807bfc788c2SDavid E. O'Brien } 808bfc788c2SDavid E. O'Brien } 809bfc788c2SDavid E. O'Brien 8102c3adf61SDavid E. O'Brien 811bfc788c2SDavid E. O'Brien static int 812bfc788c2SDavid E. O'Brien nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 813bfc788c2SDavid E. O'Brien { 814bfc788c2SDavid E. O'Brien int i, error; 815bfc788c2SDavid E. O'Brien void **desc; 816bfc788c2SDavid E. O'Brien int descsize; 817bfc788c2SDavid E. O'Brien 818bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 819bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 820bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 821bfc788c2SDavid E. O'Brien } else { 822bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 823bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 824bfc788c2SDavid E. O'Brien } 825bfc788c2SDavid E. O'Brien 826bfc788c2SDavid E. O'Brien ring->queued = 0; 827bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 828bfc788c2SDavid E. O'Brien 829bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 830bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 831bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 832bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 833bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 834bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 835bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 836bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 837bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 838bfc788c2SDavid E. O'Brien &ring->tx_desc_tag); 839bfc788c2SDavid E. O'Brien if (error != 0) { 840bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 841bfc788c2SDavid E. O'Brien goto fail; 842bfc788c2SDavid E. O'Brien } 843bfc788c2SDavid E. O'Brien 8442c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->tx_desc_tag, (void **)desc, 8452c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->tx_desc_map); 846bfc788c2SDavid E. O'Brien if (error != 0) { 847bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 848bfc788c2SDavid E. O'Brien goto fail; 849bfc788c2SDavid E. O'Brien } 850bfc788c2SDavid E. O'Brien 851bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, *desc, 8522c3adf61SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->tx_desc_segs, 8532c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 854bfc788c2SDavid E. O'Brien if (error != 0) { 855bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 856bfc788c2SDavid E. O'Brien goto fail; 857bfc788c2SDavid E. O'Brien } 858bfc788c2SDavid E. O'Brien 859bfc788c2SDavid E. O'Brien bzero(*desc, NFE_TX_RING_COUNT * descsize); 860bfc788c2SDavid E. O'Brien 861bfc788c2SDavid E. O'Brien ring->tx_desc_addr = ring->tx_desc_segs.ds_addr; 862bfc788c2SDavid E. O'Brien ring->physaddr = ring->tx_desc_addr; 863bfc788c2SDavid E. O'Brien 864bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 865bfc788c2SDavid E. O'Brien ETHER_ALIGN, 0, 866bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, 867bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, 868bfc788c2SDavid E. O'Brien NULL, NULL, 869bfc788c2SDavid E. O'Brien NFE_JBYTES, NFE_MAX_SCATTER, 870bfc788c2SDavid E. O'Brien NFE_JBYTES, 871bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, 872bfc788c2SDavid E. O'Brien NULL, NULL, 873bfc788c2SDavid E. O'Brien &ring->tx_data_tag); 874bfc788c2SDavid E. O'Brien if (error != 0) { 875bfc788c2SDavid E. O'Brien printf("nfe%d: could not create DMA tag\n", sc->nfe_unit); 876bfc788c2SDavid E. O'Brien goto fail; 877bfc788c2SDavid E. O'Brien } 878bfc788c2SDavid E. O'Brien 879bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 8802c3adf61SDavid E. O'Brien error = bus_dmamap_create(ring->tx_data_tag, 0, 8812c3adf61SDavid E. O'Brien &ring->data[i].tx_data_map); 882bfc788c2SDavid E. O'Brien if (error != 0) { 8832c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 8842c3adf61SDavid E. O'Brien sc->nfe_unit); 885bfc788c2SDavid E. O'Brien goto fail; 886bfc788c2SDavid E. O'Brien } 887bfc788c2SDavid E. O'Brien } 888bfc788c2SDavid E. O'Brien 889bfc788c2SDavid E. O'Brien return 0; 890bfc788c2SDavid E. O'Brien 891bfc788c2SDavid E. O'Brien fail: nfe_free_tx_ring(sc, ring); 892bfc788c2SDavid E. O'Brien return error; 893bfc788c2SDavid E. O'Brien } 894bfc788c2SDavid E. O'Brien 895bfc788c2SDavid E. O'Brien 896bfc788c2SDavid E. O'Brien static void 897bfc788c2SDavid E. O'Brien nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 898bfc788c2SDavid E. O'Brien { 899bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 900bfc788c2SDavid E. O'Brien int i; 901bfc788c2SDavid E. O'Brien 902bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 903bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 904bfc788c2SDavid E. O'Brien ring->desc64[i].flags = 0; 905bfc788c2SDavid E. O'Brien else 906bfc788c2SDavid E. O'Brien ring->desc32[i].flags = 0; 907bfc788c2SDavid E. O'Brien 908bfc788c2SDavid E. O'Brien data = &ring->data[i]; 909bfc788c2SDavid E. O'Brien 910bfc788c2SDavid E. O'Brien if (data->m != NULL) { 9112c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 9122c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 913bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 914bfc788c2SDavid E. O'Brien m_freem(data->m); 915bfc788c2SDavid E. O'Brien data->m = NULL; 916bfc788c2SDavid E. O'Brien } 917bfc788c2SDavid E. O'Brien } 918bfc788c2SDavid E. O'Brien 9192c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 9202c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 921bfc788c2SDavid E. O'Brien 922bfc788c2SDavid E. O'Brien ring->queued = 0; 923bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 924bfc788c2SDavid E. O'Brien } 925bfc788c2SDavid E. O'Brien 9262c3adf61SDavid E. O'Brien 927bfc788c2SDavid E. O'Brien static void 928bfc788c2SDavid E. O'Brien nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 929bfc788c2SDavid E. O'Brien { 930bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 931bfc788c2SDavid E. O'Brien void *desc; 932bfc788c2SDavid E. O'Brien int i, descsize; 933bfc788c2SDavid E. O'Brien 934bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 935bfc788c2SDavid E. O'Brien desc = ring->desc64; 936bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 937bfc788c2SDavid E. O'Brien } else { 938bfc788c2SDavid E. O'Brien desc = ring->desc32; 939bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 940bfc788c2SDavid E. O'Brien } 941bfc788c2SDavid E. O'Brien 942bfc788c2SDavid E. O'Brien if (desc != NULL) { 9432c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 9442c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 945bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 946bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 947bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_desc_tag); 948bfc788c2SDavid E. O'Brien } 949bfc788c2SDavid E. O'Brien 950bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 951bfc788c2SDavid E. O'Brien data = &ring->data[i]; 952bfc788c2SDavid E. O'Brien 953bfc788c2SDavid E. O'Brien if (data->m != NULL) { 9542c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 9552c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 956bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 957bfc788c2SDavid E. O'Brien m_freem(data->m); 958bfc788c2SDavid E. O'Brien } 959bfc788c2SDavid E. O'Brien } 960bfc788c2SDavid E. O'Brien 961bfc788c2SDavid E. O'Brien /* ..and now actually destroy the DMA mappings */ 962bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 963bfc788c2SDavid E. O'Brien data = &ring->data[i]; 964bfc788c2SDavid E. O'Brien if (data->tx_data_map == NULL) 965bfc788c2SDavid E. O'Brien continue; 966bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->tx_data_tag, data->tx_data_map); 967bfc788c2SDavid E. O'Brien } 968bfc788c2SDavid E. O'Brien 969bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_data_tag); 970bfc788c2SDavid E. O'Brien } 971bfc788c2SDavid E. O'Brien 972bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 973bfc788c2SDavid E. O'Brien static poll_handler_t nfe_poll; 974bfc788c2SDavid E. O'Brien 9752c3adf61SDavid E. O'Brien 976bfc788c2SDavid E. O'Brien static void 977bfc788c2SDavid E. O'Brien nfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 978bfc788c2SDavid E. O'Brien { 979bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 980bfc788c2SDavid E. O'Brien 981bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 982bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 983bfc788c2SDavid E. O'Brien nfe_poll_locked(ifp, cmd, count); 984bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 985bfc788c2SDavid E. O'Brien } 986bfc788c2SDavid E. O'Brien 987bfc788c2SDavid E. O'Brien 988bfc788c2SDavid E. O'Brien static void 989bfc788c2SDavid E. O'Brien nfe_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 990bfc788c2SDavid E. O'Brien { 991bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 992bfc788c2SDavid E. O'Brien u_int32_t r; 993bfc788c2SDavid E. O'Brien 994bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 995bfc788c2SDavid E. O'Brien 996bfc788c2SDavid E. O'Brien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 997bfc788c2SDavid E. O'Brien return; 998bfc788c2SDavid E. O'Brien } 999bfc788c2SDavid E. O'Brien 1000bfc788c2SDavid E. O'Brien sc->rxcycles = count; 1001bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1002bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1003bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1004bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1005bfc788c2SDavid E. O'Brien 1006bfc788c2SDavid E. O'Brien if (cmd == POLL_AND_CHECK_STATUS) { 1007bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1008bfc788c2SDavid E. O'Brien return; 1009bfc788c2SDavid E. O'Brien } 1010257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1011257c5577SDavid E. O'Brien 1012257c5577SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1013257c5577SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1014257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1015bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1016257c5577SDavid E. O'Brien } 1017257c5577SDavid E. O'Brien } 1018257c5577SDavid E. O'Brien } 1019bfc788c2SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1020257c5577SDavid E. O'Brien 1021bfc788c2SDavid E. O'Brien 1022bfc788c2SDavid E. O'Brien static int 1023257c5577SDavid E. O'Brien nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1024257c5577SDavid E. O'Brien { 1025257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1026257c5577SDavid E. O'Brien struct ifreq *ifr = (struct ifreq *) data; 1027bfc788c2SDavid E. O'Brien struct mii_data *mii; 10282c3adf61SDavid E. O'Brien int error = 0; 1029257c5577SDavid E. O'Brien 1030257c5577SDavid E. O'Brien switch (cmd) { 1031257c5577SDavid E. O'Brien case SIOCSIFMTU: 10326124fe21SDavid E. O'Brien if (ifr->ifr_mtu == ifp->if_mtu) { 1033257c5577SDavid E. O'Brien error = EINVAL; 10346124fe21SDavid E. O'Brien break; 10356124fe21SDavid E. O'Brien } 10366124fe21SDavid E. O'Brien if ((sc->nfe_flags & NFE_JUMBO_SUP) && (ifr->ifr_mtu >= 10376124fe21SDavid E. O'Brien ETHERMIN && ifr->ifr_mtu <= NV_PKTLIMIT_2)) { 10386124fe21SDavid E. O'Brien NFE_LOCK(sc); 10396124fe21SDavid E. O'Brien sc->nfe_mtu = ifp->if_mtu = ifr->ifr_mtu; 10406124fe21SDavid E. O'Brien nfe_stop(ifp, 1); 10416124fe21SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 10426124fe21SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 10436124fe21SDavid E. O'Brien NFE_UNLOCK(sc); 10446124fe21SDavid E. O'Brien 10456124fe21SDavid E. O'Brien /* Reallocate Tx and Rx rings. */ 10466124fe21SDavid E. O'Brien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 10476124fe21SDavid E. O'Brien printf("nfe%d: could not allocate Tx ring\n", 10486124fe21SDavid E. O'Brien sc->nfe_unit); 10496124fe21SDavid E. O'Brien error = ENXIO; 10506124fe21SDavid E. O'Brien break; 10516124fe21SDavid E. O'Brien } 10526124fe21SDavid E. O'Brien 10536124fe21SDavid E. O'Brien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 10546124fe21SDavid E. O'Brien printf("nfe%d: could not allocate Rx ring\n", 10556124fe21SDavid E. O'Brien sc->nfe_unit); 10566124fe21SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 10576124fe21SDavid E. O'Brien error = ENXIO; 10586124fe21SDavid E. O'Brien break; 10596124fe21SDavid E. O'Brien } 10606124fe21SDavid E. O'Brien NFE_LOCK(sc); 10616124fe21SDavid E. O'Brien nfe_init_locked(sc); 10626124fe21SDavid E. O'Brien NFE_UNLOCK(sc); 10636124fe21SDavid E. O'Brien } else { 10646124fe21SDavid E. O'Brien error = EINVAL; 1065bfc788c2SDavid E. O'Brien } 1066257c5577SDavid E. O'Brien break; 1067257c5577SDavid E. O'Brien case SIOCSIFFLAGS: 1068bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1069257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 1070257c5577SDavid E. O'Brien /* 1071257c5577SDavid E. O'Brien * If only the PROMISC or ALLMULTI flag changes, then 1072257c5577SDavid E. O'Brien * don't do a full re-init of the chip, just update 1073257c5577SDavid E. O'Brien * the Rx filter. 1074257c5577SDavid E. O'Brien */ 1075bfc788c2SDavid E. O'Brien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1076bfc788c2SDavid E. O'Brien ((ifp->if_flags ^ sc->nfe_if_flags) & 1077bfc788c2SDavid E. O'Brien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1078257c5577SDavid E. O'Brien nfe_setmulti(sc); 1079bfc788c2SDavid E. O'Brien else 1080bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1081257c5577SDavid E. O'Brien } else { 1082bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1083257c5577SDavid E. O'Brien nfe_stop(ifp, 1); 1084257c5577SDavid E. O'Brien } 1085bfc788c2SDavid E. O'Brien sc->nfe_if_flags = ifp->if_flags; 1086bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1087bfc788c2SDavid E. O'Brien error = 0; 1088257c5577SDavid E. O'Brien break; 1089257c5577SDavid E. O'Brien case SIOCADDMULTI: 1090257c5577SDavid E. O'Brien case SIOCDELMULTI: 1091bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1092bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1093257c5577SDavid E. O'Brien nfe_setmulti(sc); 1094bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1095257c5577SDavid E. O'Brien error = 0; 1096257c5577SDavid E. O'Brien } 1097257c5577SDavid E. O'Brien break; 1098257c5577SDavid E. O'Brien case SIOCSIFMEDIA: 1099257c5577SDavid E. O'Brien case SIOCGIFMEDIA: 1100bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1101bfc788c2SDavid E. O'Brien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1102257c5577SDavid E. O'Brien break; 1103bfc788c2SDavid E. O'Brien case SIOCSIFCAP: 1104bfc788c2SDavid E. O'Brien { 11057597761aSDavid E. O'Brien int init = 0; 1106bfc788c2SDavid E. O'Brien int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1107bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1108bfc788c2SDavid E. O'Brien if (mask & IFCAP_POLLING) { 1109bfc788c2SDavid E. O'Brien if (ifr->ifr_reqcap & IFCAP_POLLING) { 1110bfc788c2SDavid E. O'Brien error = ether_poll_register(nfe_poll, ifp); 1111bfc788c2SDavid E. O'Brien if (error) 1112bfc788c2SDavid E. O'Brien return(error); 1113bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1114bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1115bfc788c2SDavid E. O'Brien ifp->if_capenable |= IFCAP_POLLING; 1116bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1117bfc788c2SDavid E. O'Brien } else { 1118bfc788c2SDavid E. O'Brien error = ether_poll_deregister(ifp); 1119bfc788c2SDavid E. O'Brien /* Enable interrupt even in error case */ 1120bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1121bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1122bfc788c2SDavid E. O'Brien ifp->if_capenable &= ~IFCAP_POLLING; 1123bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1124257c5577SDavid E. O'Brien } 1125bfc788c2SDavid E. O'Brien } 11262c3adf61SDavid E. O'Brien #endif /* DEVICE_POLLING */ 11277597761aSDavid E. O'Brien #ifdef NFE_CSUM 1128bfc788c2SDavid E. O'Brien if (mask & IFCAP_HWCSUM) { 1129bfc788c2SDavid E. O'Brien ifp->if_capenable ^= IFCAP_HWCSUM; 1130bfc788c2SDavid E. O'Brien if (IFCAP_HWCSUM & ifp->if_capenable && 1131bfc788c2SDavid E. O'Brien IFCAP_HWCSUM & ifp->if_capabilities) 1132bfc788c2SDavid E. O'Brien ifp->if_hwassist = NFE_CSUM_FEATURES; 1133bfc788c2SDavid E. O'Brien else 1134bfc788c2SDavid E. O'Brien ifp->if_hwassist = 0; 11357597761aSDavid E. O'Brien sc->nfe_flags ^= NFE_HW_CSUM; 11367597761aSDavid E. O'Brien init = 1; 1137bfc788c2SDavid E. O'Brien } 11387597761aSDavid E. O'Brien #endif 11397597761aSDavid E. O'Brien if (init && ifp->if_drv_flags & IFF_DRV_RUNNING) 11407597761aSDavid E. O'Brien nfe_init(sc); 1141bfc788c2SDavid E. O'Brien } 1142bfc788c2SDavid E. O'Brien break; 1143257c5577SDavid E. O'Brien 1144bfc788c2SDavid E. O'Brien default: 1145bfc788c2SDavid E. O'Brien error = ether_ioctl(ifp, cmd, data); 1146bfc788c2SDavid E. O'Brien break; 1147bfc788c2SDavid E. O'Brien } 1148257c5577SDavid E. O'Brien 1149257c5577SDavid E. O'Brien return error; 1150257c5577SDavid E. O'Brien } 1151257c5577SDavid E. O'Brien 1152bfc788c2SDavid E. O'Brien 11532c3adf61SDavid E. O'Brien static void 11542c3adf61SDavid E. O'Brien nfe_intr(void *arg) 1155bfc788c2SDavid E. O'Brien { 1156bfc788c2SDavid E. O'Brien struct nfe_softc *sc = arg; 1157bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1158bfc788c2SDavid E. O'Brien u_int32_t r; 1159bfc788c2SDavid E. O'Brien 1160bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1161bfc788c2SDavid E. O'Brien 1162bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1163bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1164bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1165bfc788c2SDavid E. O'Brien return; 1166bfc788c2SDavid E. O'Brien } 1167bfc788c2SDavid E. O'Brien #endif 1168bfc788c2SDavid E. O'Brien 1169bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1170bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1171bfc788c2SDavid E. O'Brien return; /* not for us */ 1172bfc788c2SDavid E. O'Brien } 1173bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1174bfc788c2SDavid E. O'Brien 1175bfc788c2SDavid E. O'Brien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 1176bfc788c2SDavid E. O'Brien 1177bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1178bfc788c2SDavid E. O'Brien 1179bfc788c2SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1180bfc788c2SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1181bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1182bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1183bfc788c2SDavid E. O'Brien } 1184bfc788c2SDavid E. O'Brien 1185bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1186bfc788c2SDavid E. O'Brien /* check Rx ring */ 1187bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1188bfc788c2SDavid E. O'Brien /* check Tx ring */ 1189bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1190bfc788c2SDavid E. O'Brien } 1191bfc788c2SDavid E. O'Brien 1192bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1193bfc788c2SDavid E. O'Brien 1194bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1195bfc788c2SDavid E. O'Brien !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1196bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1197bfc788c2SDavid E. O'Brien 1198bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1199bfc788c2SDavid E. O'Brien 1200bfc788c2SDavid E. O'Brien return; 1201bfc788c2SDavid E. O'Brien } 1202bfc788c2SDavid E. O'Brien 12032c3adf61SDavid E. O'Brien 1204bfc788c2SDavid E. O'Brien static void 1205257c5577SDavid E. O'Brien nfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1206257c5577SDavid E. O'Brien { 12072c3adf61SDavid E. O'Brien 1208bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1209257c5577SDavid E. O'Brien } 1210257c5577SDavid E. O'Brien 12112c3adf61SDavid E. O'Brien 1212bfc788c2SDavid E. O'Brien static void 1213257c5577SDavid E. O'Brien nfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1214257c5577SDavid E. O'Brien { 12152c3adf61SDavid E. O'Brien 1216bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1217257c5577SDavid E. O'Brien } 1218257c5577SDavid E. O'Brien 12192c3adf61SDavid E. O'Brien 1220bfc788c2SDavid E. O'Brien static void 1221257c5577SDavid E. O'Brien nfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 1222257c5577SDavid E. O'Brien { 12232c3adf61SDavid E. O'Brien 1224bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1225257c5577SDavid E. O'Brien } 1226257c5577SDavid E. O'Brien 12272c3adf61SDavid E. O'Brien 1228bfc788c2SDavid E. O'Brien static void 1229257c5577SDavid E. O'Brien nfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 1230257c5577SDavid E. O'Brien { 12312c3adf61SDavid E. O'Brien 1232bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1233257c5577SDavid E. O'Brien } 1234257c5577SDavid E. O'Brien 12352c3adf61SDavid E. O'Brien 1236bfc788c2SDavid E. O'Brien static void 1237257c5577SDavid E. O'Brien nfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1238257c5577SDavid E. O'Brien { 12392c3adf61SDavid E. O'Brien 1240bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1241257c5577SDavid E. O'Brien } 1242257c5577SDavid E. O'Brien 12432c3adf61SDavid E. O'Brien 1244bfc788c2SDavid E. O'Brien static void 1245257c5577SDavid E. O'Brien nfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1246257c5577SDavid E. O'Brien { 1247bfc788c2SDavid E. O'Brien 1248bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1249257c5577SDavid E. O'Brien } 1250257c5577SDavid E. O'Brien 12512c3adf61SDavid E. O'Brien 12522c3adf61SDavid E. O'Brien static void 12532c3adf61SDavid E. O'Brien nfe_rxeof(struct nfe_softc *sc) 1254257c5577SDavid E. O'Brien { 1255bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1256bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1257bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1258257c5577SDavid E. O'Brien struct nfe_rx_data *data; 1259257c5577SDavid E. O'Brien struct mbuf *m, *mnew; 1260257c5577SDavid E. O'Brien bus_addr_t physaddr; 1261bfc788c2SDavid E. O'Brien u_int16_t flags; 1262257c5577SDavid E. O'Brien int error, len; 1263bfc788c2SDavid E. O'Brien #if NVLAN > 1 1264bfc788c2SDavid E. O'Brien u_int16_t vlan_tag = 0; 1265bfc788c2SDavid E. O'Brien int have_tag = 0; 1266bfc788c2SDavid E. O'Brien #endif 1267bfc788c2SDavid E. O'Brien 1268bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1269257c5577SDavid E. O'Brien 1270257c5577SDavid E. O'Brien for (;;) { 1271bfc788c2SDavid E. O'Brien 1272bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1273bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1274bfc788c2SDavid E. O'Brien if (sc->rxcycles <= 0) 1275bfc788c2SDavid E. O'Brien break; 1276bfc788c2SDavid E. O'Brien sc->rxcycles--; 1277bfc788c2SDavid E. O'Brien } 1278bfc788c2SDavid E. O'Brien #endif 1279bfc788c2SDavid E. O'Brien 1280257c5577SDavid E. O'Brien data = &sc->rxq.data[sc->rxq.cur]; 1281257c5577SDavid E. O'Brien 1282bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1283257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 1284257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1285257c5577SDavid E. O'Brien 1286257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1287257c5577SDavid E. O'Brien len = letoh16(desc64->length) & 0x3fff; 1288bfc788c2SDavid E. O'Brien 1289bfc788c2SDavid E. O'Brien #if NVLAN > 1 1290bfc788c2SDavid E. O'Brien if (flags & NFE_TX_VLAN_TAG) { 1291bfc788c2SDavid E. O'Brien have_tag = 1; 1292bfc788c2SDavid E. O'Brien vlan_tag = desc64->vtag; 1293bfc788c2SDavid E. O'Brien } 1294bfc788c2SDavid E. O'Brien #endif 1295bfc788c2SDavid E. O'Brien 1296257c5577SDavid E. O'Brien } else { 1297257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 1298257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1299257c5577SDavid E. O'Brien 1300257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1301257c5577SDavid E. O'Brien len = letoh16(desc32->length) & 0x3fff; 1302257c5577SDavid E. O'Brien } 1303257c5577SDavid E. O'Brien 1304257c5577SDavid E. O'Brien if (flags & NFE_RX_READY) 1305257c5577SDavid E. O'Brien break; 1306257c5577SDavid E. O'Brien 1307bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1308257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V1)) 1309257c5577SDavid E. O'Brien goto skip; 1310257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 1311257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1312257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1313257c5577SDavid E. O'Brien } 1314257c5577SDavid E. O'Brien } else { 1315257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V2)) 1316257c5577SDavid E. O'Brien goto skip; 1317257c5577SDavid E. O'Brien 1318257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 1319257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1320257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1321257c5577SDavid E. O'Brien } 1322257c5577SDavid E. O'Brien } 1323257c5577SDavid E. O'Brien 1324257c5577SDavid E. O'Brien if (flags & NFE_RX_ERROR) { 1325257c5577SDavid E. O'Brien ifp->if_ierrors++; 1326257c5577SDavid E. O'Brien goto skip; 1327257c5577SDavid E. O'Brien } 1328257c5577SDavid E. O'Brien 1329257c5577SDavid E. O'Brien /* 1330257c5577SDavid E. O'Brien * Try to allocate a new mbuf for this ring element and load 1331257c5577SDavid E. O'Brien * it before processing the current mbuf. If the ring element 1332257c5577SDavid E. O'Brien * cannot be loaded, drop the received packet and reuse the 1333257c5577SDavid E. O'Brien * old mbuf. In the unlikely case that the old mbuf can't be 1334257c5577SDavid E. O'Brien * reloaded either, explicitly panic. 1335257c5577SDavid E. O'Brien */ 1336257c5577SDavid E. O'Brien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 1337257c5577SDavid E. O'Brien if (mnew == NULL) { 1338257c5577SDavid E. O'Brien ifp->if_ierrors++; 1339257c5577SDavid E. O'Brien goto skip; 1340257c5577SDavid E. O'Brien } 1341257c5577SDavid E. O'Brien 1342257c5577SDavid E. O'Brien MCLGET(mnew, M_DONTWAIT); 1343257c5577SDavid E. O'Brien if (!(mnew->m_flags & M_EXT)) { 1344257c5577SDavid E. O'Brien m_freem(mnew); 1345257c5577SDavid E. O'Brien ifp->if_ierrors++; 1346257c5577SDavid E. O'Brien goto skip; 1347257c5577SDavid E. O'Brien } 1348257c5577SDavid E. O'Brien 1349bfc788c2SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, 1350bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTREAD); 1351bfc788c2SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 1352bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1353bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(mnew, void *), MCLBYTES, 1354bfc788c2SDavid E. O'Brien nfe_dma_map_segs, &data->rx_data_segs, 1355bfc788c2SDavid E. O'Brien BUS_DMA_NOWAIT); 1356257c5577SDavid E. O'Brien if (error != 0) { 1357257c5577SDavid E. O'Brien m_freem(mnew); 1358257c5577SDavid E. O'Brien 1359257c5577SDavid E. O'Brien /* try to reload the old mbuf */ 1360bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1361bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), 1362bfc788c2SDavid E. O'Brien MCLBYTES, nfe_dma_map_segs, 1363bfc788c2SDavid E. O'Brien &data->rx_data_segs, BUS_DMA_NOWAIT); 1364257c5577SDavid E. O'Brien if (error != 0) { 1365257c5577SDavid E. O'Brien /* very unlikely that it will fail.. */ 1366bfc788c2SDavid E. O'Brien panic("nfe%d: could not load old rx mbuf", 1367bfc788c2SDavid E. O'Brien sc->nfe_unit); 1368257c5577SDavid E. O'Brien } 1369257c5577SDavid E. O'Brien ifp->if_ierrors++; 1370257c5577SDavid E. O'Brien goto skip; 1371257c5577SDavid E. O'Brien } 1372bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 1373bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 1374257c5577SDavid E. O'Brien 1375257c5577SDavid E. O'Brien /* 1376257c5577SDavid E. O'Brien * New mbuf successfully loaded, update Rx ring and continue 1377257c5577SDavid E. O'Brien * processing. 1378257c5577SDavid E. O'Brien */ 1379257c5577SDavid E. O'Brien m = data->m; 1380257c5577SDavid E. O'Brien data->m = mnew; 1381257c5577SDavid E. O'Brien 1382257c5577SDavid E. O'Brien /* finalize mbuf */ 1383257c5577SDavid E. O'Brien m->m_pkthdr.len = m->m_len = len; 1384257c5577SDavid E. O'Brien m->m_pkthdr.rcvif = ifp; 1385257c5577SDavid E. O'Brien 1386bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) { 1387bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1388bfc788c2SDavid E. O'Brien if (flags & NFE_RX_IP_CSUMOK_V2) { 1389bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1390257c5577SDavid E. O'Brien } 1391bfc788c2SDavid E. O'Brien if (flags & NFE_RX_UDP_CSUMOK_V2 || 1392bfc788c2SDavid E. O'Brien flags & NFE_RX_TCP_CSUMOK_V2) { 1393bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= 1394bfc788c2SDavid E. O'Brien CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 1395bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_data = 0xffff; 1396bfc788c2SDavid E. O'Brien } 1397bfc788c2SDavid E. O'Brien } 1398257c5577SDavid E. O'Brien 1399bfc788c2SDavid E. O'Brien #if NVLAN > 1 1400bfc788c2SDavid E. O'Brien if (have_tag) { 140178ba57b9SAndre Oppermann m->m_pkthdr.ether_vtag = vlan_tag; 140278ba57b9SAndre Oppermann m->m_flags |= M_VLANTAG; 1403bfc788c2SDavid E. O'Brien } 1404257c5577SDavid E. O'Brien #endif 1405257c5577SDavid E. O'Brien ifp->if_ipackets++; 1406bfc788c2SDavid E. O'Brien 1407bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1408bfc788c2SDavid E. O'Brien (*ifp->if_input)(ifp, m); 1409bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1410257c5577SDavid E. O'Brien 1411257c5577SDavid E. O'Brien /* update mapping address in h/w descriptor */ 1412bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1413257c5577SDavid E. O'Brien #if defined(__LP64__) 1414257c5577SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 1415257c5577SDavid E. O'Brien #endif 1416257c5577SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1417257c5577SDavid E. O'Brien } else { 1418257c5577SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 1419257c5577SDavid E. O'Brien } 1420257c5577SDavid E. O'Brien 1421bfc788c2SDavid E. O'Brien skip: if (sc->nfe_flags & NFE_40BIT_ADDR) { 1422257c5577SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 1423257c5577SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 1424257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 1425257c5577SDavid E. O'Brien } else { 1426257c5577SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 1427257c5577SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 1428257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 1429257c5577SDavid E. O'Brien } 1430257c5577SDavid E. O'Brien 1431257c5577SDavid E. O'Brien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 143230ce3a12SDavid E. O'Brien } //end for(;;) 1433257c5577SDavid E. O'Brien } 1434257c5577SDavid E. O'Brien 14352c3adf61SDavid E. O'Brien 14362c3adf61SDavid E. O'Brien static void 14372c3adf61SDavid E. O'Brien nfe_txeof(struct nfe_softc *sc) 1438257c5577SDavid E. O'Brien { 1439bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1440257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 1441257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 1442257c5577SDavid E. O'Brien struct nfe_tx_data *data = NULL; 1443bfc788c2SDavid E. O'Brien u_int16_t flags; 1444bfc788c2SDavid E. O'Brien 1445bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1446257c5577SDavid E. O'Brien 1447257c5577SDavid E. O'Brien while (sc->txq.next != sc->txq.cur) { 1448bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1449257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.next]; 1450257c5577SDavid E. O'Brien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1451257c5577SDavid E. O'Brien 1452257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1453257c5577SDavid E. O'Brien } else { 1454257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.next]; 1455257c5577SDavid E. O'Brien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1456257c5577SDavid E. O'Brien 1457257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1458257c5577SDavid E. O'Brien } 1459257c5577SDavid E. O'Brien 1460257c5577SDavid E. O'Brien if (flags & NFE_TX_VALID) 1461257c5577SDavid E. O'Brien break; 1462257c5577SDavid E. O'Brien 1463257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.next]; 1464257c5577SDavid E. O'Brien 1465bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1466257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 1467257c5577SDavid E. O'Brien goto skip; 1468257c5577SDavid E. O'Brien 1469257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V1) != 0) { 1470bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1471bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V1_TXERR); 1472bfc788c2SDavid E. O'Brien 1473257c5577SDavid E. O'Brien ifp->if_oerrors++; 1474257c5577SDavid E. O'Brien } else 1475257c5577SDavid E. O'Brien ifp->if_opackets++; 1476257c5577SDavid E. O'Brien } else { 1477257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 1478257c5577SDavid E. O'Brien goto skip; 1479257c5577SDavid E. O'Brien 1480257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V2) != 0) { 1481bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1482bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V2_TXERR); 1483bfc788c2SDavid E. O'Brien 1484257c5577SDavid E. O'Brien ifp->if_oerrors++; 1485257c5577SDavid E. O'Brien } else 1486257c5577SDavid E. O'Brien ifp->if_opackets++; 1487257c5577SDavid E. O'Brien } 1488257c5577SDavid E. O'Brien 1489257c5577SDavid E. O'Brien if (data->m == NULL) { /* should not get there */ 1490bfc788c2SDavid E. O'Brien printf("nfe%d: last fragment bit w/o associated mbuf!\n", 1491bfc788c2SDavid E. O'Brien sc->nfe_unit); 1492257c5577SDavid E. O'Brien goto skip; 1493257c5577SDavid E. O'Brien } 1494257c5577SDavid E. O'Brien 1495257c5577SDavid E. O'Brien /* last fragment of the mbuf chain transmitted */ 1496bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, data->active, 1497bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1498bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, data->active); 1499257c5577SDavid E. O'Brien m_freem(data->m); 1500257c5577SDavid E. O'Brien data->m = NULL; 1501257c5577SDavid E. O'Brien 1502257c5577SDavid E. O'Brien ifp->if_timer = 0; 1503257c5577SDavid E. O'Brien 1504257c5577SDavid E. O'Brien skip: sc->txq.queued--; 1505257c5577SDavid E. O'Brien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 1506257c5577SDavid E. O'Brien } 1507257c5577SDavid E. O'Brien 1508257c5577SDavid E. O'Brien if (data != NULL) { /* at least one slot freed */ 1509bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1510bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1511257c5577SDavid E. O'Brien } 1512257c5577SDavid E. O'Brien } 1513257c5577SDavid E. O'Brien 15142c3adf61SDavid E. O'Brien 15152c3adf61SDavid E. O'Brien static int 15162c3adf61SDavid E. O'Brien nfe_encap(struct nfe_softc *sc, struct mbuf *m0) 1517257c5577SDavid E. O'Brien { 1518bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1519bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1520bfc788c2SDavid E. O'Brien struct nfe_tx_data *data=NULL; 1521257c5577SDavid E. O'Brien bus_dmamap_t map; 1522bfc788c2SDavid E. O'Brien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 15232c3adf61SDavid E. O'Brien int error, i, nsegs; 15242c3adf61SDavid E. O'Brien u_int16_t flags = NFE_TX_VALID; 1525257c5577SDavid E. O'Brien 1526bfc788c2SDavid E. O'Brien map = sc->txq.data[sc->txq.cur].tx_data_map; 1527257c5577SDavid E. O'Brien 1528bfc788c2SDavid E. O'Brien error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, m0, segs, 1529bfc788c2SDavid E. O'Brien &nsegs, BUS_DMA_NOWAIT); 1530bfc788c2SDavid E. O'Brien 1531257c5577SDavid E. O'Brien if (error != 0) { 1532bfc788c2SDavid E. O'Brien printf("nfe%d: could not map mbuf (error %d)\n", sc->nfe_unit, 1533bfc788c2SDavid E. O'Brien error); 1534257c5577SDavid E. O'Brien return error; 1535257c5577SDavid E. O'Brien } 1536257c5577SDavid E. O'Brien 1537bfc788c2SDavid E. O'Brien if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 1) { 1538bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, map); 1539257c5577SDavid E. O'Brien return ENOBUFS; 1540257c5577SDavid E. O'Brien } 1541257c5577SDavid E. O'Brien 15427597761aSDavid E. O'Brien if(sc->nfe_flags & NFE_HW_CSUM){ 1543bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_IP) 1544257c5577SDavid E. O'Brien flags |= NFE_TX_IP_CSUM; 1545bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_TCP) 1546bfc788c2SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1547bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_UDP) 1548257c5577SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 15497597761aSDavid E. O'Brien } 1550257c5577SDavid E. O'Brien 1551bfc788c2SDavid E. O'Brien for (i = 0; i < nsegs; i++) { 1552257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.cur]; 1553257c5577SDavid E. O'Brien 1554bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1555257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.cur]; 1556257c5577SDavid E. O'Brien #if defined(__LP64__) 1557bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(segs[i].ds_addr >> 32); 1558257c5577SDavid E. O'Brien #endif 1559bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(segs[i].ds_addr & 1560bfc788c2SDavid E. O'Brien 0xffffffff); 1561bfc788c2SDavid E. O'Brien desc64->length = htole16(segs[i].ds_len - 1); 1562257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1563257c5577SDavid E. O'Brien #if NVLAN > 0 156478ba57b9SAndre Oppermann if (m0->m_flags & M_VLANTAG) 1565bfc788c2SDavid E. O'Brien desc64->vtag = htole32(NFE_TX_VTAG | 156678ba57b9SAndre Oppermann m0->m_pkthdr.ether_vtag); 1567257c5577SDavid E. O'Brien #endif 1568257c5577SDavid E. O'Brien } else { 1569257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.cur]; 1570257c5577SDavid E. O'Brien 1571bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(segs[i].ds_addr); 1572bfc788c2SDavid E. O'Brien desc32->length = htole16(segs[i].ds_len - 1); 1573257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1574257c5577SDavid E. O'Brien } 1575257c5577SDavid E. O'Brien 1576257c5577SDavid E. O'Brien /* csum flags and vtag belong to the first fragment only */ 1577bfc788c2SDavid E. O'Brien if (nsegs > 1) { 1578257c5577SDavid E. O'Brien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 1579257c5577SDavid E. O'Brien } 1580257c5577SDavid E. O'Brien 1581257c5577SDavid E. O'Brien sc->txq.queued++; 1582257c5577SDavid E. O'Brien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 1583257c5577SDavid E. O'Brien } 1584257c5577SDavid E. O'Brien 1585257c5577SDavid E. O'Brien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 1586bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1587257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1588257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1589257c5577SDavid E. O'Brien } else { 1590bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 1591257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1592257c5577SDavid E. O'Brien else 1593257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V1; 1594257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1595257c5577SDavid E. O'Brien } 1596257c5577SDavid E. O'Brien 1597257c5577SDavid E. O'Brien data->m = m0; 1598257c5577SDavid E. O'Brien data->active = map; 1599bfc788c2SDavid E. O'Brien data->nsegs = nsegs; 1600257c5577SDavid E. O'Brien 1601bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 1602257c5577SDavid E. O'Brien 1603257c5577SDavid E. O'Brien return 0; 1604257c5577SDavid E. O'Brien } 1605257c5577SDavid E. O'Brien 1606bfc788c2SDavid E. O'Brien 16072c3adf61SDavid E. O'Brien static void 16082c3adf61SDavid E. O'Brien nfe_setmulti(struct nfe_softc *sc) 1609bfc788c2SDavid E. O'Brien { 1610bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1611bfc788c2SDavid E. O'Brien struct ifmultiaddr *ifma; 1612bfc788c2SDavid E. O'Brien int i; 16132c3adf61SDavid E. O'Brien u_int32_t filter = NFE_RXFILTER_MAGIC; 16142c3adf61SDavid E. O'Brien u_int8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 16152c3adf61SDavid E. O'Brien u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 16162c3adf61SDavid E. O'Brien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 16172c3adf61SDavid E. O'Brien }; 1618bfc788c2SDavid E. O'Brien 1619bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1620bfc788c2SDavid E. O'Brien 1621bfc788c2SDavid E. O'Brien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1622bfc788c2SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 1623bfc788c2SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 1624bfc788c2SDavid E. O'Brien goto done; 1625bfc788c2SDavid E. O'Brien } 1626bfc788c2SDavid E. O'Brien 1627bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1628bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1629bfc788c2SDavid E. O'Brien 1630bfc788c2SDavid E. O'Brien IF_ADDR_LOCK(ifp); 1631bfc788c2SDavid E. O'Brien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1632bfc788c2SDavid E. O'Brien u_char *addrp; 1633bfc788c2SDavid E. O'Brien 1634bfc788c2SDavid E. O'Brien if (ifma->ifma_addr->sa_family != AF_LINK) 1635bfc788c2SDavid E. O'Brien continue; 1636bfc788c2SDavid E. O'Brien 1637bfc788c2SDavid E. O'Brien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 1638bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1639bfc788c2SDavid E. O'Brien u_int8_t mcaddr = addrp[i]; 1640bfc788c2SDavid E. O'Brien addr[i] &= mcaddr; 1641bfc788c2SDavid E. O'Brien mask[i] &= ~mcaddr; 1642bfc788c2SDavid E. O'Brien } 1643bfc788c2SDavid E. O'Brien } 1644bfc788c2SDavid E. O'Brien IF_ADDR_UNLOCK(ifp); 1645bfc788c2SDavid E. O'Brien 1646bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1647bfc788c2SDavid E. O'Brien mask[i] |= addr[i]; 1648bfc788c2SDavid E. O'Brien } 1649bfc788c2SDavid E. O'Brien 1650bfc788c2SDavid E. O'Brien done: 1651bfc788c2SDavid E. O'Brien addr[0] |= 0x01; /* make sure multicast bit is set */ 1652bfc788c2SDavid E. O'Brien 1653bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1654bfc788c2SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1655bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1656bfc788c2SDavid E. O'Brien addr[5] << 8 | addr[4]); 1657bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1658bfc788c2SDavid E. O'Brien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1659bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1660bfc788c2SDavid E. O'Brien mask[5] << 8 | mask[4]); 1661bfc788c2SDavid E. O'Brien 1662bfc788c2SDavid E. O'Brien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1663bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_RXFILTER, filter); 1664bfc788c2SDavid E. O'Brien } 1665bfc788c2SDavid E. O'Brien 16662c3adf61SDavid E. O'Brien 16672c3adf61SDavid E. O'Brien static void 16682c3adf61SDavid E. O'Brien nfe_start(struct ifnet *ifp) 1669bfc788c2SDavid E. O'Brien { 1670bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1671bfc788c2SDavid E. O'Brien 1672bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 1673bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1674bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1675bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1676bfc788c2SDavid E. O'Brien } 1677bfc788c2SDavid E. O'Brien 16782c3adf61SDavid E. O'Brien 16792c3adf61SDavid E. O'Brien static void 16802c3adf61SDavid E. O'Brien nfe_start_locked(struct ifnet *ifp) 1681257c5577SDavid E. O'Brien { 1682257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1683257c5577SDavid E. O'Brien struct mbuf *m0; 16842c3adf61SDavid E. O'Brien int old = sc->txq.cur; 1685257c5577SDavid E. O'Brien 1686bfc788c2SDavid E. O'Brien if (!sc->nfe_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1687bfc788c2SDavid E. O'Brien return; 1688bfc788c2SDavid E. O'Brien } 1689bfc788c2SDavid E. O'Brien 1690257c5577SDavid E. O'Brien for (;;) { 1691257c5577SDavid E. O'Brien IFQ_POLL(&ifp->if_snd, m0); 1692257c5577SDavid E. O'Brien if (m0 == NULL) 1693257c5577SDavid E. O'Brien break; 1694257c5577SDavid E. O'Brien 1695257c5577SDavid E. O'Brien if (nfe_encap(sc, m0) != 0) { 1696bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1697257c5577SDavid E. O'Brien break; 1698257c5577SDavid E. O'Brien } 1699257c5577SDavid E. O'Brien 1700257c5577SDavid E. O'Brien /* packet put in h/w queue, remove from s/w queue */ 1701257c5577SDavid E. O'Brien IFQ_DEQUEUE(&ifp->if_snd, m0); 1702257c5577SDavid E. O'Brien 1703bfc788c2SDavid E. O'Brien BPF_MTAP(ifp, m0); 1704257c5577SDavid E. O'Brien } 1705bfc788c2SDavid E. O'Brien if (sc->txq.cur == old) { /* nothing sent */ 1706257c5577SDavid E. O'Brien return; 1707bfc788c2SDavid E. O'Brien } 1708257c5577SDavid E. O'Brien 1709bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1710257c5577SDavid E. O'Brien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1711257c5577SDavid E. O'Brien else 1712257c5577SDavid E. O'Brien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1713257c5577SDavid E. O'Brien 1714257c5577SDavid E. O'Brien /* kick Tx */ 1715257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1716257c5577SDavid E. O'Brien 1717257c5577SDavid E. O'Brien /* 1718257c5577SDavid E. O'Brien * Set a timeout in case the chip goes out to lunch. 1719257c5577SDavid E. O'Brien */ 1720257c5577SDavid E. O'Brien ifp->if_timer = 5; 1721bfc788c2SDavid E. O'Brien 1722bfc788c2SDavid E. O'Brien return; 1723257c5577SDavid E. O'Brien } 1724257c5577SDavid E. O'Brien 17252c3adf61SDavid E. O'Brien 17262c3adf61SDavid E. O'Brien static void 17272c3adf61SDavid E. O'Brien nfe_watchdog(struct ifnet *ifp) 1728257c5577SDavid E. O'Brien { 1729257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1730257c5577SDavid E. O'Brien 1731bfc788c2SDavid E. O'Brien printf("nfe%d: watchdog timeout\n", sc->nfe_unit); 1732257c5577SDavid E. O'Brien 1733bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1734bfc788c2SDavid E. O'Brien nfe_init(sc); 1735257c5577SDavid E. O'Brien ifp->if_oerrors++; 1736bfc788c2SDavid E. O'Brien 1737bfc788c2SDavid E. O'Brien return; 1738257c5577SDavid E. O'Brien } 1739257c5577SDavid E. O'Brien 17402c3adf61SDavid E. O'Brien 17412c3adf61SDavid E. O'Brien static void 17422c3adf61SDavid E. O'Brien nfe_init(void *xsc) 1743257c5577SDavid E. O'Brien { 1744bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1745bfc788c2SDavid E. O'Brien 1746bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1747bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1748bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1749bfc788c2SDavid E. O'Brien 1750bfc788c2SDavid E. O'Brien return; 1751bfc788c2SDavid E. O'Brien } 1752bfc788c2SDavid E. O'Brien 17532c3adf61SDavid E. O'Brien 17542c3adf61SDavid E. O'Brien static void 17552c3adf61SDavid E. O'Brien nfe_init_locked(void *xsc) 1756bfc788c2SDavid E. O'Brien { 1757bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1758bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1759bfc788c2SDavid E. O'Brien struct mii_data *mii; 1760bfc788c2SDavid E. O'Brien u_int32_t tmp; 1761bfc788c2SDavid E. O'Brien 1762bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1763bfc788c2SDavid E. O'Brien 1764bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1765bfc788c2SDavid E. O'Brien 1766bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1767bfc788c2SDavid E. O'Brien return; 1768bfc788c2SDavid E. O'Brien } 1769257c5577SDavid E. O'Brien 1770257c5577SDavid E. O'Brien nfe_stop(ifp, 0); 1771257c5577SDavid E. O'Brien 1772257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_UNK, 0); 1773257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, 0); 1774257c5577SDavid E. O'Brien 1775257c5577SDavid E. O'Brien sc->rxtxctl = NFE_RXTX_BIT2; 1776bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1777257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1778bfc788c2SDavid E. O'Brien else if (sc->nfe_flags & NFE_JUMBO_SUP) 1779257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 17807597761aSDavid E. O'Brien 1781bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) 1782257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1783bfc788c2SDavid E. O'Brien 1784257c5577SDavid E. O'Brien #if NVLAN > 0 1785257c5577SDavid E. O'Brien /* 1786257c5577SDavid E. O'Brien * Although the adapter is capable of stripping VLAN tags from received 1787257c5577SDavid E. O'Brien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1788257c5577SDavid E. O'Brien * purpose. This will be done in software by our network stack. 1789257c5577SDavid E. O'Brien */ 1790bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1791257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1792257c5577SDavid E. O'Brien #endif 1793bfc788c2SDavid E. O'Brien 1794257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1795257c5577SDavid E. O'Brien DELAY(10); 1796257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1797257c5577SDavid E. O'Brien 1798257c5577SDavid E. O'Brien #if NVLAN 1799bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1800257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1801257c5577SDavid E. O'Brien #endif 1802257c5577SDavid E. O'Brien 1803257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1804257c5577SDavid E. O'Brien 1805257c5577SDavid E. O'Brien /* set MAC address */ 1806bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, sc->eaddr); 1807257c5577SDavid E. O'Brien 1808257c5577SDavid E. O'Brien /* tell MAC where rings are in memory */ 1809257c5577SDavid E. O'Brien #ifdef __LP64__ 1810257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1811257c5577SDavid E. O'Brien #endif 1812257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1813257c5577SDavid E. O'Brien #ifdef __LP64__ 1814257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1815257c5577SDavid E. O'Brien #endif 1816257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1817257c5577SDavid E. O'Brien 1818257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RING_SIZE, 1819257c5577SDavid E. O'Brien (NFE_RX_RING_COUNT - 1) << 16 | 1820257c5577SDavid E. O'Brien (NFE_TX_RING_COUNT - 1)); 1821257c5577SDavid E. O'Brien 1822257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1823257c5577SDavid E. O'Brien 1824257c5577SDavid E. O'Brien /* force MAC to wakeup */ 1825257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1826257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1827257c5577SDavid E. O'Brien DELAY(10); 1828257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1829257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1830257c5577SDavid E. O'Brien 1831257c5577SDavid E. O'Brien #if 1 1832257c5577SDavid E. O'Brien /* configure interrupts coalescing/mitigation */ 1833257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1834257c5577SDavid E. O'Brien #else 1835257c5577SDavid E. O'Brien /* no interrupt mitigation: one interrupt per packet */ 1836257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, 970); 1837257c5577SDavid E. O'Brien #endif 1838257c5577SDavid E. O'Brien 1839257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1840257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1841257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1842257c5577SDavid E. O'Brien 1843257c5577SDavid E. O'Brien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1844257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1845257c5577SDavid E. O'Brien 1846257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1847257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1848257c5577SDavid E. O'Brien 1849257c5577SDavid E. O'Brien sc->rxtxctl &= ~NFE_RXTX_BIT2; 1850257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1851257c5577SDavid E. O'Brien DELAY(10); 1852257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1853257c5577SDavid E. O'Brien 1854257c5577SDavid E. O'Brien /* set Rx filter */ 1855257c5577SDavid E. O'Brien nfe_setmulti(sc); 1856257c5577SDavid E. O'Brien 1857257c5577SDavid E. O'Brien nfe_ifmedia_upd(ifp); 1858257c5577SDavid E. O'Brien 1859bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 1860bfc788c2SDavid E. O'Brien 1861257c5577SDavid E. O'Brien /* enable Rx */ 1862257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1863257c5577SDavid E. O'Brien 1864257c5577SDavid E. O'Brien /* enable Tx */ 1865257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1866257c5577SDavid E. O'Brien 1867257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1868257c5577SDavid E. O'Brien 1869bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1870bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 1871bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1872bfc788c2SDavid E. O'Brien else 1873bfc788c2SDavid E. O'Brien #endif 1874bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); /* enable interrupts */ 1875257c5577SDavid E. O'Brien 1876bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_RUNNING; 1877bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1878257c5577SDavid E. O'Brien 1879bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 1880257c5577SDavid E. O'Brien 1881bfc788c2SDavid E. O'Brien return; 1882257c5577SDavid E. O'Brien } 1883257c5577SDavid E. O'Brien 18842c3adf61SDavid E. O'Brien 18852c3adf61SDavid E. O'Brien static void 18862c3adf61SDavid E. O'Brien nfe_stop(struct ifnet *ifp, int disable) 1887257c5577SDavid E. O'Brien { 1888257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1889bfc788c2SDavid E. O'Brien struct mii_data *mii; 1890257c5577SDavid E. O'Brien 1891bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1892257c5577SDavid E. O'Brien 1893257c5577SDavid E. O'Brien ifp->if_timer = 0; 1894bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1895257c5577SDavid E. O'Brien 1896bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1897bfc788c2SDavid E. O'Brien 1898bfc788c2SDavid E. O'Brien callout_stop(&sc->nfe_stat_ch); 1899257c5577SDavid E. O'Brien 1900257c5577SDavid E. O'Brien /* abort Tx */ 1901257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, 0); 1902257c5577SDavid E. O'Brien 1903257c5577SDavid E. O'Brien /* disable Rx */ 1904257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, 0); 1905257c5577SDavid E. O'Brien 1906257c5577SDavid E. O'Brien /* disable interrupts */ 1907257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1908257c5577SDavid E. O'Brien 1909bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 1910bfc788c2SDavid E. O'Brien 1911257c5577SDavid E. O'Brien /* reset Tx and Rx rings */ 1912257c5577SDavid E. O'Brien nfe_reset_tx_ring(sc, &sc->txq); 1913257c5577SDavid E. O'Brien nfe_reset_rx_ring(sc, &sc->rxq); 1914257c5577SDavid E. O'Brien 1915257c5577SDavid E. O'Brien return; 1916257c5577SDavid E. O'Brien } 1917257c5577SDavid E. O'Brien 19182c3adf61SDavid E. O'Brien 19192c3adf61SDavid E. O'Brien static int 19202c3adf61SDavid E. O'Brien nfe_ifmedia_upd(struct ifnet *ifp) 1921257c5577SDavid E. O'Brien { 1922257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1923257c5577SDavid E. O'Brien 1924bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1925bfc788c2SDavid E. O'Brien nfe_ifmedia_upd_locked(ifp); 1926bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1927bfc788c2SDavid E. O'Brien return (0); 1928bfc788c2SDavid E. O'Brien } 1929bfc788c2SDavid E. O'Brien 19302c3adf61SDavid E. O'Brien 19312c3adf61SDavid E. O'Brien static int 19322c3adf61SDavid E. O'Brien nfe_ifmedia_upd_locked(struct ifnet *ifp) 1933bfc788c2SDavid E. O'Brien { 1934bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1935bfc788c2SDavid E. O'Brien struct mii_data *mii; 1936bfc788c2SDavid E. O'Brien 1937bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1938bfc788c2SDavid E. O'Brien 1939bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1940bfc788c2SDavid E. O'Brien 1941bfc788c2SDavid E. O'Brien if (mii->mii_instance) { 1942bfc788c2SDavid E. O'Brien struct mii_softc *miisc; 1943bfc788c2SDavid E. O'Brien for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 1944bfc788c2SDavid E. O'Brien miisc = LIST_NEXT(miisc, mii_list)) { 1945257c5577SDavid E. O'Brien mii_phy_reset(miisc); 1946257c5577SDavid E. O'Brien } 1947bfc788c2SDavid E. O'Brien } 1948bfc788c2SDavid E. O'Brien mii_mediachg(mii); 1949bfc788c2SDavid E. O'Brien 1950bfc788c2SDavid E. O'Brien return (0); 1951257c5577SDavid E. O'Brien } 1952257c5577SDavid E. O'Brien 19532c3adf61SDavid E. O'Brien 19542c3adf61SDavid E. O'Brien static void 19552c3adf61SDavid E. O'Brien nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1956257c5577SDavid E. O'Brien { 1957bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1958bfc788c2SDavid E. O'Brien struct mii_data *mii; 1959257c5577SDavid E. O'Brien 1960bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 1961bfc788c2SDavid E. O'Brien 1962bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1963bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1964257c5577SDavid E. O'Brien mii_pollstat(mii); 1965bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1966bfc788c2SDavid E. O'Brien 1967257c5577SDavid E. O'Brien ifmr->ifm_active = mii->mii_media_active; 1968bfc788c2SDavid E. O'Brien ifmr->ifm_status = mii->mii_media_status; 1969bfc788c2SDavid E. O'Brien 1970bfc788c2SDavid E. O'Brien return; 1971257c5577SDavid E. O'Brien } 1972257c5577SDavid E. O'Brien 19732c3adf61SDavid E. O'Brien 1974bfc788c2SDavid E. O'Brien static void 1975bfc788c2SDavid E. O'Brien nfe_tick(void *xsc) 1976257c5577SDavid E. O'Brien { 1977bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1978257c5577SDavid E. O'Brien 1979bfc788c2SDavid E. O'Brien sc = xsc; 1980bfc788c2SDavid E. O'Brien 1981bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1982bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 1983bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1984257c5577SDavid E. O'Brien } 1985257c5577SDavid E. O'Brien 1986257c5577SDavid E. O'Brien 19872c3adf61SDavid E. O'Brien void 19882c3adf61SDavid E. O'Brien nfe_tick_locked(struct nfe_softc *arg) 1989bfc788c2SDavid E. O'Brien { 1990bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1991bfc788c2SDavid E. O'Brien struct mii_data *mii; 1992bfc788c2SDavid E. O'Brien struct ifnet *ifp; 1993bfc788c2SDavid E. O'Brien 1994bfc788c2SDavid E. O'Brien sc = arg; 1995bfc788c2SDavid E. O'Brien 1996bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1997bfc788c2SDavid E. O'Brien 1998bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 1999bfc788c2SDavid E. O'Brien 2000bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2001bfc788c2SDavid E. O'Brien mii_tick(mii); 2002bfc788c2SDavid E. O'Brien 2003bfc788c2SDavid E. O'Brien if (!sc->nfe_link) { 2004bfc788c2SDavid E. O'Brien if (mii->mii_media_status & IFM_ACTIVE && 2005bfc788c2SDavid E. O'Brien IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 2006bfc788c2SDavid E. O'Brien sc->nfe_link++; 2007bfc788c2SDavid E. O'Brien if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T 2008bfc788c2SDavid E. O'Brien && bootverbose) 2009bfc788c2SDavid E. O'Brien if_printf(sc->nfe_ifp, "gigabit link up\n"); 2010bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2011bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 2012257c5577SDavid E. O'Brien } 2013257c5577SDavid E. O'Brien } 2014bfc788c2SDavid E. O'Brien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2015257c5577SDavid E. O'Brien 2016bfc788c2SDavid E. O'Brien return; 2017257c5577SDavid E. O'Brien } 2018257c5577SDavid E. O'Brien 2019bfc788c2SDavid E. O'Brien 20202c3adf61SDavid E. O'Brien static void 20212c3adf61SDavid E. O'Brien nfe_shutdown(device_t dev) 2022bfc788c2SDavid E. O'Brien { 2023bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2024bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2025bfc788c2SDavid E. O'Brien 2026bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 2027bfc788c2SDavid E. O'Brien 2028bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2029bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2030bfc788c2SDavid E. O'Brien nfe_stop(ifp,0); 2031bfc788c2SDavid E. O'Brien /* nfe_reset(sc); */ 2032bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2033bfc788c2SDavid E. O'Brien 2034bfc788c2SDavid E. O'Brien return; 2035bfc788c2SDavid E. O'Brien } 2036bfc788c2SDavid E. O'Brien 2037bfc788c2SDavid E. O'Brien 20382c3adf61SDavid E. O'Brien static void 20392c3adf61SDavid E. O'Brien nfe_get_macaddr(struct nfe_softc *sc, u_char *addr) 2040257c5577SDavid E. O'Brien { 2041257c5577SDavid E. O'Brien uint32_t tmp; 2042257c5577SDavid E. O'Brien 2043257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_LO); 2044257c5577SDavid E. O'Brien addr[0] = (tmp >> 8) & 0xff; 2045257c5577SDavid E. O'Brien addr[1] = (tmp & 0xff); 2046257c5577SDavid E. O'Brien 2047257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_HI); 2048257c5577SDavid E. O'Brien addr[2] = (tmp >> 24) & 0xff; 2049257c5577SDavid E. O'Brien addr[3] = (tmp >> 16) & 0xff; 2050257c5577SDavid E. O'Brien addr[4] = (tmp >> 8) & 0xff; 2051257c5577SDavid E. O'Brien addr[5] = (tmp & 0xff); 2052257c5577SDavid E. O'Brien } 2053257c5577SDavid E. O'Brien 20542c3adf61SDavid E. O'Brien 20552c3adf61SDavid E. O'Brien static void 20562c3adf61SDavid E. O'Brien nfe_set_macaddr(struct nfe_softc *sc, u_char *addr) 2057257c5577SDavid E. O'Brien { 2058bfc788c2SDavid E. O'Brien 2059bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 2060bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 2061bfc788c2SDavid E. O'Brien addr[1] << 8 | addr[0]); 2062257c5577SDavid E. O'Brien } 2063257c5577SDavid E. O'Brien 20642c3adf61SDavid E. O'Brien 2065bfc788c2SDavid E. O'Brien /* 2066bfc788c2SDavid E. O'Brien * Map a single buffer address. 2067bfc788c2SDavid E. O'Brien */ 2068bfc788c2SDavid E. O'Brien 2069bfc788c2SDavid E. O'Brien static void 2070bfc788c2SDavid E. O'Brien nfe_dma_map_segs(arg, segs, nseg, error) 2071bfc788c2SDavid E. O'Brien void *arg; 2072bfc788c2SDavid E. O'Brien bus_dma_segment_t *segs; 2073bfc788c2SDavid E. O'Brien int error, nseg; 2074257c5577SDavid E. O'Brien { 2075257c5577SDavid E. O'Brien 2076bfc788c2SDavid E. O'Brien if (error) 2077bfc788c2SDavid E. O'Brien return; 2078257c5577SDavid E. O'Brien 2079bfc788c2SDavid E. O'Brien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2080bfc788c2SDavid E. O'Brien 2081bfc788c2SDavid E. O'Brien *(bus_dma_segment_t *)arg = *segs; 2082bfc788c2SDavid E. O'Brien 2083bfc788c2SDavid E. O'Brien return; 2084257c5577SDavid E. O'Brien } 2085