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 NFE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 32bfc788c2SDavid E. O'Brien #define NVLAN 0 33bfc788c2SDavid E. O'Brien 34bfc788c2SDavid E. O'Brien #ifdef HAVE_KERNEL_OPTION_HEADERS 35bfc788c2SDavid E. O'Brien #include "opt_device_polling.h" 36bfc788c2SDavid E. O'Brien #endif 37257c5577SDavid E. O'Brien 38257c5577SDavid E. O'Brien #include <sys/param.h> 39257c5577SDavid E. O'Brien #include <sys/endian.h> 40257c5577SDavid E. O'Brien #include <sys/systm.h> 41257c5577SDavid E. O'Brien #include <sys/sockio.h> 42257c5577SDavid E. O'Brien #include <sys/mbuf.h> 43257c5577SDavid E. O'Brien #include <sys/malloc.h> 44bfc788c2SDavid E. O'Brien #include <sys/module.h> 45257c5577SDavid E. O'Brien #include <sys/kernel.h> 46257c5577SDavid E. O'Brien #include <sys/socket.h> 47bfc788c2SDavid E. O'Brien #include <sys/taskqueue.h> 48257c5577SDavid E. O'Brien 49257c5577SDavid E. O'Brien #include <net/if.h> 50bfc788c2SDavid E. O'Brien #include <net/if_arp.h> 51bfc788c2SDavid E. O'Brien #include <net/ethernet.h> 52257c5577SDavid E. O'Brien #include <net/if_dl.h> 53257c5577SDavid E. O'Brien #include <net/if_media.h> 54257c5577SDavid E. O'Brien #include <net/if_types.h> 55257c5577SDavid E. O'Brien #include <net/if_vlan_var.h> 56257c5577SDavid E. O'Brien 57257c5577SDavid E. O'Brien #include <net/bpf.h> 58bfc788c2SDavid E. O'Brien 59bfc788c2SDavid E. O'Brien #include <machine/bus.h> 60bfc788c2SDavid E. O'Brien #include <machine/resource.h> 61bfc788c2SDavid E. O'Brien #include <sys/bus.h> 62bfc788c2SDavid E. O'Brien #include <sys/rman.h> 63257c5577SDavid E. O'Brien 64257c5577SDavid E. O'Brien #include <dev/mii/mii.h> 65257c5577SDavid E. O'Brien #include <dev/mii/miivar.h> 66257c5577SDavid E. O'Brien 67257c5577SDavid E. O'Brien #include <dev/pci/pcireg.h> 68257c5577SDavid E. O'Brien #include <dev/pci/pcivar.h> 69257c5577SDavid E. O'Brien 70bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfereg.h> 71bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfevar.h> 72257c5577SDavid E. O'Brien 73bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, pci, 1, 1, 1); 74bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, ether, 1, 1, 1); 75bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, miibus, 1, 1, 1); 76bfc788c2SDavid E. O'Brien #include "miibus_if.h" 77257c5577SDavid E. O'Brien 78bfc788c2SDavid E. O'Brien static int nfe_probe(device_t); 79bfc788c2SDavid E. O'Brien static int nfe_attach(device_t); 80bfc788c2SDavid E. O'Brien static int nfe_detach(device_t); 81bfc788c2SDavid E. O'Brien static void nfe_shutdown(device_t); 82bfc788c2SDavid E. O'Brien static int nfe_miibus_readreg(device_t, int, int); 83bfc788c2SDavid E. O'Brien static int nfe_miibus_writereg(device_t, int, int, int); 84bfc788c2SDavid E. O'Brien static void nfe_miibus_statchg(device_t); 85bfc788c2SDavid E. O'Brien static int nfe_ioctl(struct ifnet *, u_long, caddr_t); 86bfc788c2SDavid E. O'Brien static void nfe_intr(void *); 87bfc788c2SDavid E. O'Brien static void nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 88bfc788c2SDavid E. O'Brien static void nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 89bfc788c2SDavid E. O'Brien static void nfe_txdesc32_rsync(struct nfe_softc *, int, int, int); 90bfc788c2SDavid E. O'Brien static void nfe_txdesc64_rsync(struct nfe_softc *, int, int, int); 91bfc788c2SDavid E. O'Brien static void nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 92bfc788c2SDavid E. O'Brien static void nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 93bfc788c2SDavid E. O'Brien static void nfe_rxeof(struct nfe_softc *); 94bfc788c2SDavid E. O'Brien static void nfe_txeof(struct nfe_softc *); 95bfc788c2SDavid E. O'Brien static int nfe_encap(struct nfe_softc *, struct mbuf *); 96bfc788c2SDavid E. O'Brien static void nfe_setmulti(struct nfe_softc *); 97bfc788c2SDavid E. O'Brien static void nfe_start(struct ifnet *); 98bfc788c2SDavid E. O'Brien static void nfe_start_locked(struct ifnet *); 99bfc788c2SDavid E. O'Brien static void nfe_watchdog(struct ifnet *); 100bfc788c2SDavid E. O'Brien static void nfe_init(void *); 101bfc788c2SDavid E. O'Brien static void nfe_init_locked(void *); 102bfc788c2SDavid E. O'Brien static void nfe_stop(struct ifnet *, int); 103bfc788c2SDavid E. O'Brien static int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 104bfc788c2SDavid E. O'Brien static void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 105bfc788c2SDavid E. O'Brien static void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 106bfc788c2SDavid E. O'Brien static int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 107bfc788c2SDavid E. O'Brien static void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 108bfc788c2SDavid E. O'Brien static void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 109bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd(struct ifnet *); 110bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd_locked(struct ifnet *); 111bfc788c2SDavid E. O'Brien static void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 112bfc788c2SDavid E. O'Brien static void nfe_tick(void *); 113bfc788c2SDavid E. O'Brien static void nfe_tick_locked(struct nfe_softc *); 114bfc788c2SDavid E. O'Brien static void nfe_get_macaddr(struct nfe_softc *, u_char *); 115bfc788c2SDavid E. O'Brien static void nfe_set_macaddr(struct nfe_softc *, u_char *); 116bfc788c2SDavid E. O'Brien static void nfe_dma_map_segs (void *, bus_dma_segment_t *, int, int); 117bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 118bfc788c2SDavid E. O'Brien static void nfe_poll_locked(struct ifnet *, enum poll_cmd, int); 119bfc788c2SDavid E. O'Brien #endif 120257c5577SDavid E. O'Brien 121257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 122257c5577SDavid E. O'Brien int nfedebug = 0; 123257c5577SDavid E. O'Brien #define DPRINTF(x) do { if (nfedebug) printf x; } while (0) 124257c5577SDavid E. O'Brien #define DPRINTFN(n,x) do { if (nfedebug >= (n)) printf x; } while (0) 125257c5577SDavid E. O'Brien #else 126257c5577SDavid E. O'Brien #define DPRINTF(x) 127257c5577SDavid E. O'Brien #define DPRINTFN(n,x) 128257c5577SDavid E. O'Brien #endif 129257c5577SDavid E. O'Brien 130bfc788c2SDavid E. O'Brien #define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 131bfc788c2SDavid E. O'Brien #define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 132bfc788c2SDavid E. O'Brien #define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 133bfc788c2SDavid E. O'Brien 134bfc788c2SDavid E. O'Brien #define letoh16(x) le16toh(x) 135bfc788c2SDavid E. O'Brien 136bfc788c2SDavid E. O'Brien #define NV_RID 0x10 137bfc788c2SDavid E. O'Brien 138bfc788c2SDavid E. O'Brien static device_method_t nfe_methods[] = { 139bfc788c2SDavid E. O'Brien /* Device interface */ 140bfc788c2SDavid E. O'Brien DEVMETHOD(device_probe, nfe_probe), 141bfc788c2SDavid E. O'Brien DEVMETHOD(device_attach, nfe_attach), 142bfc788c2SDavid E. O'Brien DEVMETHOD(device_detach, nfe_detach), 143bfc788c2SDavid E. O'Brien DEVMETHOD(device_shutdown, nfe_shutdown), 144bfc788c2SDavid E. O'Brien 145bfc788c2SDavid E. O'Brien /* bus interface */ 146bfc788c2SDavid E. O'Brien DEVMETHOD(bus_print_child, bus_generic_print_child), 147bfc788c2SDavid E. O'Brien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 148bfc788c2SDavid E. O'Brien 149bfc788c2SDavid E. O'Brien /* MII interface */ 150bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 151bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 152bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 153bfc788c2SDavid E. O'Brien 154bfc788c2SDavid E. O'Brien { 0, 0 } 155257c5577SDavid E. O'Brien }; 156257c5577SDavid E. O'Brien 157bfc788c2SDavid E. O'Brien static driver_t nfe_driver = { 158bfc788c2SDavid E. O'Brien "nfe", 159bfc788c2SDavid E. O'Brien nfe_methods, 160bfc788c2SDavid E. O'Brien sizeof(struct nfe_softc) 161bfc788c2SDavid E. O'Brien }; 162bfc788c2SDavid E. O'Brien 163bfc788c2SDavid E. O'Brien static devclass_t nfe_devclass; 164bfc788c2SDavid E. O'Brien 165bfc788c2SDavid E. O'Brien DRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 166bfc788c2SDavid E. O'Brien DRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 167bfc788c2SDavid E. O'Brien 168bfc788c2SDavid E. O'Brien static struct nfe_type nfe_devs[] = { 169bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 1706bec3967SDavid E. O'Brien "NVIDIA nForce MCP Networking Adapter"}, 171bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 1726bec3967SDavid E. O'Brien "NVIDIA nForce2 MCP2 Networking Adapter"}, 173bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 1746bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 175bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 1766bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 1776bec3967SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 1786bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP3 Networking Adapter"}, 179bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 1806bec3967SDavid E. O'Brien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 181bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 1826bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP7 Networking Adapter"}, 183bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 1846bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 185bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 1866bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 187bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 1886bec3967SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, // MCP10 189bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 1906bec3967SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, // MCP11 191bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 1926bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 193bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 1946bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 195bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 196bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 197bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 198bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 1993e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 2003e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2013e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2023e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2033e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 2043e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2053e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2063e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2073e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 2083e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2093e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2103e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2113e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 2123e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2133e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2143e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 215bfc788c2SDavid E. O'Brien {0, 0, NULL} 216bfc788c2SDavid E. O'Brien }; 217bfc788c2SDavid E. O'Brien 218bfc788c2SDavid E. O'Brien 219bfc788c2SDavid E. O'Brien /* Probe for supported hardware ID's */ 220bfc788c2SDavid E. O'Brien static int 221bfc788c2SDavid E. O'Brien nfe_probe(device_t dev) 222257c5577SDavid E. O'Brien { 223bfc788c2SDavid E. O'Brien struct nfe_type *t; 224bfc788c2SDavid E. O'Brien 225bfc788c2SDavid E. O'Brien t = nfe_devs; 226bfc788c2SDavid E. O'Brien /* Check for matching PCI DEVICE ID's */ 227bfc788c2SDavid E. O'Brien while (t->name != NULL) { 228bfc788c2SDavid E. O'Brien if ((pci_get_vendor(dev) == t->vid_id) && 229bfc788c2SDavid E. O'Brien (pci_get_device(dev) == t->dev_id)) { 230bfc788c2SDavid E. O'Brien device_set_desc(dev, t->name); 231bfc788c2SDavid E. O'Brien return (0); 232bfc788c2SDavid E. O'Brien } 233bfc788c2SDavid E. O'Brien t++; 234257c5577SDavid E. O'Brien } 235257c5577SDavid E. O'Brien 236bfc788c2SDavid E. O'Brien return (ENXIO); 237bfc788c2SDavid E. O'Brien } 238bfc788c2SDavid E. O'Brien 2392c3adf61SDavid E. O'Brien 240bfc788c2SDavid E. O'Brien static int 241bfc788c2SDavid E. O'Brien nfe_attach(device_t dev) 242257c5577SDavid E. O'Brien { 243bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 244257c5577SDavid E. O'Brien struct ifnet *ifp; 245bfc788c2SDavid E. O'Brien int unit, error = 0, rid; 246257c5577SDavid E. O'Brien 247bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 248bfc788c2SDavid E. O'Brien unit = device_get_unit(dev); 249bfc788c2SDavid E. O'Brien sc->nfe_dev = dev; 250bfc788c2SDavid E. O'Brien sc->nfe_unit = unit; 251bfc788c2SDavid E. O'Brien 252bfc788c2SDavid E. O'Brien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 253bfc788c2SDavid E. O'Brien MTX_DEF | MTX_RECURSE); 254bfc788c2SDavid E. O'Brien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 255bfc788c2SDavid E. O'Brien 256bfc788c2SDavid E. O'Brien pci_enable_busmaster(dev); 257bfc788c2SDavid E. O'Brien 258bfc788c2SDavid E. O'Brien rid = NV_RID; 259bfc788c2SDavid E. O'Brien sc->nfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 260bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_ACTIVE); 261bfc788c2SDavid E. O'Brien 262bfc788c2SDavid E. O'Brien if (sc->nfe_res == NULL) { 263bfc788c2SDavid E. O'Brien printf ("nfe%d: couldn't map ports/memory\n", unit); 264bfc788c2SDavid E. O'Brien error = ENXIO; 265bfc788c2SDavid E. O'Brien goto fail; 266257c5577SDavid E. O'Brien } 267257c5577SDavid E. O'Brien 268bfc788c2SDavid E. O'Brien sc->nfe_memt = rman_get_bustag(sc->nfe_res); 269bfc788c2SDavid E. O'Brien sc->nfe_memh = rman_get_bushandle(sc->nfe_res); 270bfc788c2SDavid E. O'Brien 271bfc788c2SDavid E. O'Brien /* Allocate interrupt */ 272bfc788c2SDavid E. O'Brien rid = 0; 273bfc788c2SDavid E. O'Brien sc->nfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 274bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 275bfc788c2SDavid E. O'Brien 276bfc788c2SDavid E. O'Brien if (sc->nfe_irq == NULL) { 277bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't map interrupt\n", unit); 278bfc788c2SDavid E. O'Brien error = ENXIO; 279bfc788c2SDavid E. O'Brien goto fail; 280257c5577SDavid E. O'Brien } 281257c5577SDavid E. O'Brien 282bfc788c2SDavid E. O'Brien nfe_get_macaddr(sc, sc->eaddr); 283257c5577SDavid E. O'Brien 284bfc788c2SDavid E. O'Brien sc->nfe_flags = 0; 285257c5577SDavid E. O'Brien 286bfc788c2SDavid E. O'Brien switch (pci_get_device(dev)) { 287257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 288257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 289257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 290257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 291bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 292257c5577SDavid E. O'Brien break; 293257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 294257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 295bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 296257c5577SDavid E. O'Brien break; 297257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 298257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 299257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 300257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 301bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 302257c5577SDavid E. O'Brien break; 303257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 304257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 3052c3adf61SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 3062c3adf61SDavid E. O'Brien NFE_HW_VLAN; 307257c5577SDavid E. O'Brien break; 3083e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 3093e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 3103e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 3113e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 3123e232000SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 3133e232000SDavid E. O'Brien break; 3143e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 3153e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 3163e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 3173e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 3183e232000SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 3193e232000SDavid E. O'Brien break; 320257c5577SDavid E. O'Brien } 321257c5577SDavid E. O'Brien 322257c5577SDavid E. O'Brien /* 323bfc788c2SDavid E. O'Brien * Allocate the parent bus DMA tag appropriate for PCI. 324bfc788c2SDavid E. O'Brien */ 325bfc788c2SDavid E. O'Brien #define NFE_NSEG_NEW 32 326bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(NULL, /* parent */ 327bfc788c2SDavid E. O'Brien 1, 0, /* alignment, boundary */ 328bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 329bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 330bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 331bfc788c2SDavid E. O'Brien MAXBSIZE, NFE_NSEG_NEW, /* maxsize, nsegments */ 332bfc788c2SDavid E. O'Brien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 333bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 334bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 335bfc788c2SDavid E. O'Brien &sc->nfe_parent_tag); 336bfc788c2SDavid E. O'Brien if (error) 337bfc788c2SDavid E. O'Brien goto fail; 338bfc788c2SDavid E. O'Brien 3396124fe21SDavid E. O'Brien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 3406124fe21SDavid E. O'Brien if (ifp == NULL) { 3416124fe21SDavid E. O'Brien printf("nfe%d: can not if_alloc()\n", unit); 3426124fe21SDavid E. O'Brien error = ENOSPC; 3436124fe21SDavid E. O'Brien goto fail; 3446124fe21SDavid E. O'Brien } 3456124fe21SDavid E. O'Brien sc->nfe_mtu = ifp->if_mtu = ETHERMTU; 3466124fe21SDavid E. O'Brien 347bfc788c2SDavid E. O'Brien /* 348257c5577SDavid E. O'Brien * Allocate Tx and Rx rings. 349257c5577SDavid E. O'Brien */ 350257c5577SDavid E. O'Brien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 351bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Tx ring\n", unit); 352bfc788c2SDavid E. O'Brien error = ENXIO; 353bfc788c2SDavid E. O'Brien goto fail; 354257c5577SDavid E. O'Brien } 355257c5577SDavid E. O'Brien 356257c5577SDavid E. O'Brien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 357bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Rx ring\n", unit); 358257c5577SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 359bfc788c2SDavid E. O'Brien error = ENXIO; 360bfc788c2SDavid E. O'Brien goto fail; 361257c5577SDavid E. O'Brien } 362257c5577SDavid E. O'Brien 363257c5577SDavid E. O'Brien ifp->if_softc = sc; 364bfc788c2SDavid E. O'Brien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 365257c5577SDavid E. O'Brien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 366257c5577SDavid E. O'Brien ifp->if_ioctl = nfe_ioctl; 367257c5577SDavid E. O'Brien ifp->if_start = nfe_start; 368bfc788c2SDavid E. O'Brien /* ifp->if_hwassist = NFE_CSUM_FEATURES; */ 369257c5577SDavid E. O'Brien ifp->if_watchdog = nfe_watchdog; 370257c5577SDavid E. O'Brien ifp->if_init = nfe_init; 371257c5577SDavid E. O'Brien ifp->if_baudrate = IF_Gbps(1); 372bfc788c2SDavid E. O'Brien ifp->if_snd.ifq_maxlen = NFE_IFQ_MAXLEN; 373257c5577SDavid E. O'Brien 374257c5577SDavid E. O'Brien ifp->if_capabilities = IFCAP_VLAN_MTU; 3756124fe21SDavid E. O'Brien 3766124fe21SDavid E. O'Brien #ifdef NFE_JUMBO 3776124fe21SDavid E. O'Brien ifp->if_capabilities |= IFCAP_JUMBO_MTU; 3786124fe21SDavid E. O'Brien #else 3796124fe21SDavid E. O'Brien ifp->if_capabilities &= ~IFCAP_JUMBO_MTU; 3806124fe21SDavid E. O'Brien sc->nfe_flags &= ~NFE_JUMBO_SUP; 3816124fe21SDavid E. O'Brien #endif 3826124fe21SDavid E. O'Brien 383257c5577SDavid E. O'Brien #if NVLAN > 0 384bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 385257c5577SDavid E. O'Brien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 386257c5577SDavid E. O'Brien #endif 387257c5577SDavid E. O'Brien #ifdef NFE_CSUM 388bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) { 389bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_HWCSUM; 390257c5577SDavid E. O'Brien } 391257c5577SDavid E. O'Brien #endif 392bfc788c2SDavid E. O'Brien ifp->if_capenable = ifp->if_capabilities; 393257c5577SDavid E. O'Brien 394bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 395bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_POLLING; 396bfc788c2SDavid E. O'Brien #endif 397257c5577SDavid E. O'Brien 398bfc788c2SDavid E. O'Brien /* Do MII setup */ 3992c3adf61SDavid E. O'Brien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, 4002c3adf61SDavid E. O'Brien nfe_ifmedia_sts)) { 401bfc788c2SDavid E. O'Brien printf("nfe%d: MII without any phy!\n", unit); 402bfc788c2SDavid E. O'Brien error = ENXIO; 403bfc788c2SDavid E. O'Brien goto fail; 404257c5577SDavid E. O'Brien } 405257c5577SDavid E. O'Brien 406bfc788c2SDavid E. O'Brien ether_ifattach(ifp, sc->eaddr); 407bfc788c2SDavid E. O'Brien 408bfc788c2SDavid E. O'Brien error = bus_setup_intr(dev, sc->nfe_irq, INTR_TYPE_NET | INTR_MPSAFE, 409bfc788c2SDavid E. O'Brien nfe_intr, sc, &sc->nfe_intrhand); 410bfc788c2SDavid E. O'Brien 411bfc788c2SDavid E. O'Brien if (error) { 412bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't set up irq\n", unit); 413bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 414bfc788c2SDavid E. O'Brien goto fail; 415bfc788c2SDavid E. O'Brien } 416bfc788c2SDavid E. O'Brien 417bfc788c2SDavid E. O'Brien fail: 418bfc788c2SDavid E. O'Brien if (error) 419bfc788c2SDavid E. O'Brien nfe_detach(dev); 420bfc788c2SDavid E. O'Brien 421bfc788c2SDavid E. O'Brien return (error); 422bfc788c2SDavid E. O'Brien } 423bfc788c2SDavid E. O'Brien 424bfc788c2SDavid E. O'Brien 425bfc788c2SDavid E. O'Brien static int 426bfc788c2SDavid E. O'Brien nfe_detach(device_t dev) 427257c5577SDavid E. O'Brien { 428bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 429257c5577SDavid E. O'Brien struct ifnet *ifp; 430bfc788c2SDavid E. O'Brien u_char eaddr[ETHER_ADDR_LEN]; 431bfc788c2SDavid E. O'Brien int i; 432257c5577SDavid E. O'Brien 433bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 434bfc788c2SDavid E. O'Brien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 435bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 436bfc788c2SDavid E. O'Brien 437bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 438bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 439bfc788c2SDavid E. O'Brien ether_poll_deregister(ifp); 440bfc788c2SDavid E. O'Brien #endif 441bfc788c2SDavid E. O'Brien 442bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 443bfc788c2SDavid E. O'Brien eaddr[i] = sc->eaddr[5 - i]; 444257c5577SDavid E. O'Brien } 445bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, eaddr); 446bfc788c2SDavid E. O'Brien 447bfc788c2SDavid E. O'Brien if (device_is_attached(dev)) { 44896058696SDavid E. O'Brien NFE_LOCK(sc); 449bfc788c2SDavid E. O'Brien nfe_stop(ifp, 1); 450bfc788c2SDavid E. O'Brien ifp->if_flags &= ~IFF_UP; 45196058696SDavid E. O'Brien NFE_UNLOCK(sc); 452bfc788c2SDavid E. O'Brien callout_drain(&sc->nfe_stat_ch); 453bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 454257c5577SDavid E. O'Brien } 455257c5577SDavid E. O'Brien 456bfc788c2SDavid E. O'Brien if (ifp) 457bfc788c2SDavid E. O'Brien if_free(ifp); 458bfc788c2SDavid E. O'Brien if (sc->nfe_miibus) 459bfc788c2SDavid E. O'Brien device_delete_child(dev, sc->nfe_miibus); 460bfc788c2SDavid E. O'Brien bus_generic_detach(dev); 461bfc788c2SDavid E. O'Brien 462bfc788c2SDavid E. O'Brien if (sc->nfe_intrhand) 463bfc788c2SDavid E. O'Brien bus_teardown_intr(dev, sc->nfe_irq, sc->nfe_intrhand); 464bfc788c2SDavid E. O'Brien if (sc->nfe_irq) 465bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nfe_irq); 466bfc788c2SDavid E. O'Brien if (sc->nfe_res) 467bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_MEMORY, NV_RID, sc->nfe_res); 468bfc788c2SDavid E. O'Brien 469bfc788c2SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 470bfc788c2SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 471bfc788c2SDavid E. O'Brien 472bfc788c2SDavid E. O'Brien if (sc->nfe_parent_tag) 473bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(sc->nfe_parent_tag); 474bfc788c2SDavid E. O'Brien 475bfc788c2SDavid E. O'Brien mtx_destroy(&sc->nfe_mtx); 476bfc788c2SDavid E. O'Brien 477bfc788c2SDavid E. O'Brien return (0); 478bfc788c2SDavid E. O'Brien } 479bfc788c2SDavid E. O'Brien 480bfc788c2SDavid E. O'Brien 481bfc788c2SDavid E. O'Brien static void 482bfc788c2SDavid E. O'Brien nfe_miibus_statchg(device_t dev) 483257c5577SDavid E. O'Brien { 484bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 485bfc788c2SDavid E. O'Brien struct mii_data *mii; 486bfc788c2SDavid E. O'Brien u_int32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 487bfc788c2SDavid E. O'Brien 488bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 489bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 490257c5577SDavid E. O'Brien 491257c5577SDavid E. O'Brien phy = NFE_READ(sc, NFE_PHY_IFACE); 492257c5577SDavid E. O'Brien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 493257c5577SDavid E. O'Brien 494257c5577SDavid E. O'Brien seed = NFE_READ(sc, NFE_RNDSEED); 495257c5577SDavid E. O'Brien seed &= ~NFE_SEED_MASK; 496257c5577SDavid E. O'Brien 497257c5577SDavid E. O'Brien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 498257c5577SDavid E. O'Brien phy |= NFE_PHY_HDX; /* half-duplex */ 499257c5577SDavid E. O'Brien misc |= NFE_MISC1_HDX; 500257c5577SDavid E. O'Brien } 501257c5577SDavid E. O'Brien 502257c5577SDavid E. O'Brien switch (IFM_SUBTYPE(mii->mii_media_active)) { 503257c5577SDavid E. O'Brien case IFM_1000_T: /* full-duplex only */ 504257c5577SDavid E. O'Brien link |= NFE_MEDIA_1000T; 505257c5577SDavid E. O'Brien seed |= NFE_SEED_1000T; 506257c5577SDavid E. O'Brien phy |= NFE_PHY_1000T; 507257c5577SDavid E. O'Brien break; 508257c5577SDavid E. O'Brien case IFM_100_TX: 509257c5577SDavid E. O'Brien link |= NFE_MEDIA_100TX; 510257c5577SDavid E. O'Brien seed |= NFE_SEED_100TX; 511257c5577SDavid E. O'Brien phy |= NFE_PHY_100TX; 512257c5577SDavid E. O'Brien break; 513257c5577SDavid E. O'Brien case IFM_10_T: 514257c5577SDavid E. O'Brien link |= NFE_MEDIA_10T; 515257c5577SDavid E. O'Brien seed |= NFE_SEED_10T; 516257c5577SDavid E. O'Brien break; 517257c5577SDavid E. O'Brien } 518257c5577SDavid E. O'Brien 519257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 520257c5577SDavid E. O'Brien 521257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 522257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MISC1, misc); 523257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_LINKSPEED, link); 524257c5577SDavid E. O'Brien } 525257c5577SDavid E. O'Brien 5262c3adf61SDavid E. O'Brien 527bfc788c2SDavid E. O'Brien static int 528bfc788c2SDavid E. O'Brien nfe_miibus_readreg(device_t dev, int phy, int reg) 529257c5577SDavid E. O'Brien { 530bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 531bfc788c2SDavid E. O'Brien u_int32_t val; 532257c5577SDavid E. O'Brien int ntries; 533257c5577SDavid E. O'Brien 534257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 535257c5577SDavid E. O'Brien 536257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 537257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 538257c5577SDavid E. O'Brien DELAY(100); 539257c5577SDavid E. O'Brien } 540257c5577SDavid E. O'Brien 541257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 542257c5577SDavid E. O'Brien 543257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 544257c5577SDavid E. O'Brien DELAY(100); 545257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 546257c5577SDavid E. O'Brien break; 547257c5577SDavid E. O'Brien } 548257c5577SDavid E. O'Brien if (ntries == 1000) { 549bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: timeout waiting for PHY\n", sc->nfe_unit)); 550257c5577SDavid E. O'Brien return 0; 551257c5577SDavid E. O'Brien } 552257c5577SDavid E. O'Brien 553257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 554bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: could not read PHY\n", sc->nfe_unit)); 555257c5577SDavid E. O'Brien return 0; 556257c5577SDavid E. O'Brien } 557257c5577SDavid E. O'Brien 558257c5577SDavid E. O'Brien val = NFE_READ(sc, NFE_PHY_DATA); 559257c5577SDavid E. O'Brien if (val != 0xffffffff && val != 0) 560257c5577SDavid E. O'Brien sc->mii_phyaddr = phy; 561257c5577SDavid E. O'Brien 5622c3adf61SDavid E. O'Brien DPRINTFN(2, ("nfe%d: mii read phy %d reg 0x%x ret 0x%x\n", 5632c3adf61SDavid E. O'Brien sc->nfe_unit, phy, reg, val)); 564257c5577SDavid E. O'Brien 565257c5577SDavid E. O'Brien return val; 566257c5577SDavid E. O'Brien } 567257c5577SDavid E. O'Brien 5682c3adf61SDavid E. O'Brien 569bfc788c2SDavid E. O'Brien static int 570bfc788c2SDavid E. O'Brien nfe_miibus_writereg(device_t dev, int phy, int reg, int val) 571257c5577SDavid E. O'Brien { 572bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 573bfc788c2SDavid E. O'Brien u_int32_t ctl; 574257c5577SDavid E. O'Brien int ntries; 575257c5577SDavid E. O'Brien 576257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 577257c5577SDavid E. O'Brien 578257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 579257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 580257c5577SDavid E. O'Brien DELAY(100); 581257c5577SDavid E. O'Brien } 582257c5577SDavid E. O'Brien 583257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_DATA, val); 584257c5577SDavid E. O'Brien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 585257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 586257c5577SDavid E. O'Brien 587257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 588257c5577SDavid E. O'Brien DELAY(100); 589257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 590257c5577SDavid E. O'Brien break; 591257c5577SDavid E. O'Brien } 592257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 593257c5577SDavid E. O'Brien if (nfedebug >= 2 && ntries == 1000) 594257c5577SDavid E. O'Brien printf("could not write to PHY\n"); 595257c5577SDavid E. O'Brien #endif 596bfc788c2SDavid E. O'Brien return 0; 597257c5577SDavid E. O'Brien } 598257c5577SDavid E. O'Brien 5992c3adf61SDavid E. O'Brien 600bfc788c2SDavid E. O'Brien static int 601bfc788c2SDavid E. O'Brien nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 602bfc788c2SDavid E. O'Brien { 603bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32; 604bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64; 605bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 606bfc788c2SDavid E. O'Brien void **desc; 607bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 608bfc788c2SDavid E. O'Brien int i, error, descsize; 609bfc788c2SDavid E. O'Brien 610bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 611bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 612bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 613bfc788c2SDavid E. O'Brien } else { 614bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 615bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 616bfc788c2SDavid E. O'Brien } 617bfc788c2SDavid E. O'Brien 618bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 6196124fe21SDavid E. O'Brien ring->bufsz = (sc->nfe_mtu + NFE_RX_HEADERS <= MCLBYTES) ? 6206124fe21SDavid E. O'Brien MCLBYTES : MJUM9BYTES; 621bfc788c2SDavid E. O'Brien 622bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 623bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 624bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 625bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 626bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 627bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 628bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 629bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 630bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 631bfc788c2SDavid E. O'Brien &ring->rx_desc_tag); 632bfc788c2SDavid E. O'Brien if (error != 0) { 633bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 634bfc788c2SDavid E. O'Brien goto fail; 635bfc788c2SDavid E. O'Brien } 636bfc788c2SDavid E. O'Brien 637bfc788c2SDavid E. O'Brien /* allocate memory to desc */ 6382c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_desc_tag, (void **)desc, 6392c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->rx_desc_map); 640bfc788c2SDavid E. O'Brien if (error != 0) { 641bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 642bfc788c2SDavid E. O'Brien goto fail; 643bfc788c2SDavid E. O'Brien } 644bfc788c2SDavid E. O'Brien 645bfc788c2SDavid E. O'Brien /* map desc to device visible address space */ 646bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, *desc, 6472c3adf61SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, 6482c3adf61SDavid E. O'Brien &ring->rx_desc_segs, BUS_DMA_NOWAIT); 649bfc788c2SDavid E. O'Brien if (error != 0) { 650bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 651bfc788c2SDavid E. O'Brien goto fail; 652bfc788c2SDavid E. O'Brien } 653bfc788c2SDavid E. O'Brien 654bfc788c2SDavid E. O'Brien bzero(*desc, NFE_RX_RING_COUNT * descsize); 655bfc788c2SDavid E. O'Brien ring->rx_desc_addr = ring->rx_desc_segs.ds_addr; 656bfc788c2SDavid E. O'Brien ring->physaddr = ring->rx_desc_addr; 657bfc788c2SDavid E. O'Brien 658bfc788c2SDavid E. O'Brien /* 659bfc788c2SDavid E. O'Brien * Pre-allocate Rx buffers and populate Rx ring. 660bfc788c2SDavid E. O'Brien */ 661bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 662bfc788c2SDavid E. O'Brien data = &sc->rxq.data[i]; 663bfc788c2SDavid E. O'Brien 664bfc788c2SDavid E. O'Brien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 665bfc788c2SDavid E. O'Brien if (data->m == NULL) { 6662c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate rx mbuf\n", 6672c3adf61SDavid E. O'Brien sc->nfe_unit); 668bfc788c2SDavid E. O'Brien error = ENOMEM; 669bfc788c2SDavid E. O'Brien goto fail; 670bfc788c2SDavid E. O'Brien } 671bfc788c2SDavid E. O'Brien 672bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 673d0220c83SRuslan Ermilov ETHER_ALIGN, 0, /* alignment, boundary */ 674bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 675bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 676bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 677bfc788c2SDavid E. O'Brien MCLBYTES, 1, /* maxsize, nsegments */ 678bfc788c2SDavid E. O'Brien MCLBYTES, /* maxsegsize */ 679bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 680bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 681bfc788c2SDavid E. O'Brien &data->rx_data_tag); 682bfc788c2SDavid E. O'Brien if (error != 0) { 6832c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 6842c3adf61SDavid E. O'Brien sc->nfe_unit); 685bfc788c2SDavid E. O'Brien goto fail; 686bfc788c2SDavid E. O'Brien } 687bfc788c2SDavid E. O'Brien 6882c3adf61SDavid E. O'Brien error = bus_dmamap_create(data->rx_data_tag, 0, 6892c3adf61SDavid E. O'Brien &data->rx_data_map); 690bfc788c2SDavid E. O'Brien if (error != 0) { 6912c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate mbuf cluster\n", 6922c3adf61SDavid E. O'Brien sc->nfe_unit); 693bfc788c2SDavid E. O'Brien goto fail; 694bfc788c2SDavid E. O'Brien } 695bfc788c2SDavid E. O'Brien 696bfc788c2SDavid E. O'Brien MCLGET(data->m, M_DONTWAIT); 697bfc788c2SDavid E. O'Brien if (!(data->m->m_flags & M_EXT)) { 698bfc788c2SDavid E. O'Brien error = ENOMEM; 699bfc788c2SDavid E. O'Brien goto fail; 700bfc788c2SDavid E. O'Brien } 701bfc788c2SDavid E. O'Brien 7022c3adf61SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 7036124fe21SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), 7046124fe21SDavid E. O'Brien /*DEO,MCLBYTES*/ring->bufsz, nfe_dma_map_segs, &data->rx_data_segs, 7052c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 706bfc788c2SDavid E. O'Brien if (error != 0) { 7072c3adf61SDavid E. O'Brien printf("nfe%d: could not load rx buf DMA map\n", 7082c3adf61SDavid E. O'Brien sc->nfe_unit); 709bfc788c2SDavid E. O'Brien goto fail; 710bfc788c2SDavid E. O'Brien } 711bfc788c2SDavid E. O'Brien 712bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 713bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 714bfc788c2SDavid E. O'Brien 715bfc788c2SDavid E. O'Brien 716bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 717bfc788c2SDavid E. O'Brien desc64 = &sc->rxq.desc64[i]; 718bfc788c2SDavid E. O'Brien #if defined(__LP64__) 719bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 720bfc788c2SDavid E. O'Brien #endif 721bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 722bfc788c2SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 723bfc788c2SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 724bfc788c2SDavid E. O'Brien } else { 725bfc788c2SDavid E. O'Brien desc32 = &sc->rxq.desc32[i]; 726bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 727bfc788c2SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 728bfc788c2SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 729bfc788c2SDavid E. O'Brien } 730bfc788c2SDavid E. O'Brien 731bfc788c2SDavid E. O'Brien } 732bfc788c2SDavid E. O'Brien 7332c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7342c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 735bfc788c2SDavid E. O'Brien 736bfc788c2SDavid E. O'Brien return 0; 737bfc788c2SDavid E. O'Brien 738bfc788c2SDavid E. O'Brien fail: nfe_free_rx_ring(sc, ring); 739bfc788c2SDavid E. O'Brien 740bfc788c2SDavid E. O'Brien return error; 741bfc788c2SDavid E. O'Brien } 742bfc788c2SDavid E. O'Brien 7432c3adf61SDavid E. O'Brien 744bfc788c2SDavid E. O'Brien static void 745bfc788c2SDavid E. O'Brien nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 746bfc788c2SDavid E. O'Brien { 747bfc788c2SDavid E. O'Brien int i; 748bfc788c2SDavid E. O'Brien 749bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 750bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 751bfc788c2SDavid E. O'Brien ring->desc64[i].length = htole16(ring->bufsz); 752bfc788c2SDavid E. O'Brien ring->desc64[i].flags = htole16(NFE_RX_READY); 753bfc788c2SDavid E. O'Brien } else { 754bfc788c2SDavid E. O'Brien ring->desc32[i].length = htole16(ring->bufsz); 755bfc788c2SDavid E. O'Brien ring->desc32[i].flags = htole16(NFE_RX_READY); 756bfc788c2SDavid E. O'Brien } 757bfc788c2SDavid E. O'Brien } 758bfc788c2SDavid E. O'Brien 7592c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7602c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 761bfc788c2SDavid E. O'Brien 762bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 763bfc788c2SDavid E. O'Brien } 764bfc788c2SDavid E. O'Brien 765bfc788c2SDavid E. O'Brien 766bfc788c2SDavid E. O'Brien static void 767bfc788c2SDavid E. O'Brien nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 768bfc788c2SDavid E. O'Brien { 769bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 770bfc788c2SDavid E. O'Brien void *desc; 771bfc788c2SDavid E. O'Brien int i, descsize; 772bfc788c2SDavid E. O'Brien 773bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 774bfc788c2SDavid E. O'Brien desc = ring->desc64; 775bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 776bfc788c2SDavid E. O'Brien } else { 777bfc788c2SDavid E. O'Brien desc = ring->desc32; 778bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 779bfc788c2SDavid E. O'Brien } 780bfc788c2SDavid E. O'Brien 781bfc788c2SDavid E. O'Brien if (desc != NULL) { 7822c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7832c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 784bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 785bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 786bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->rx_desc_tag); 787bfc788c2SDavid E. O'Brien } 788bfc788c2SDavid E. O'Brien 7896124fe21SDavid E. O'Brien 790bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 791bfc788c2SDavid E. O'Brien data = &ring->data[i]; 792bfc788c2SDavid E. O'Brien 793bfc788c2SDavid E. O'Brien if (data->rx_data_map != NULL) { 7942c3adf61SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, 7952c3adf61SDavid E. O'Brien data->rx_data_map, BUS_DMASYNC_POSTREAD); 7962c3adf61SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, 7972c3adf61SDavid E. O'Brien data->rx_data_map); 7982c3adf61SDavid E. O'Brien bus_dmamap_destroy(data->rx_data_tag, 7992c3adf61SDavid E. O'Brien data->rx_data_map); 800bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(data->rx_data_tag); 801bfc788c2SDavid E. O'Brien } 8022c3adf61SDavid E. O'Brien 803bfc788c2SDavid E. O'Brien if (data->m != NULL) 804bfc788c2SDavid E. O'Brien m_freem(data->m); 805bfc788c2SDavid E. O'Brien } 806bfc788c2SDavid E. O'Brien } 807bfc788c2SDavid E. O'Brien 8082c3adf61SDavid E. O'Brien 809bfc788c2SDavid E. O'Brien static int 810bfc788c2SDavid E. O'Brien nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 811bfc788c2SDavid E. O'Brien { 812bfc788c2SDavid E. O'Brien int i, error; 813bfc788c2SDavid E. O'Brien void **desc; 814bfc788c2SDavid E. O'Brien int descsize; 815bfc788c2SDavid E. O'Brien 816bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 817bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 818bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 819bfc788c2SDavid E. O'Brien } else { 820bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 821bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 822bfc788c2SDavid E. O'Brien } 823bfc788c2SDavid E. O'Brien 824bfc788c2SDavid E. O'Brien ring->queued = 0; 825bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 826bfc788c2SDavid E. O'Brien 827bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 828bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 829bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 830bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 831bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 832bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 833bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 834bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 835bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 836bfc788c2SDavid E. O'Brien &ring->tx_desc_tag); 837bfc788c2SDavid E. O'Brien if (error != 0) { 838bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 839bfc788c2SDavid E. O'Brien goto fail; 840bfc788c2SDavid E. O'Brien } 841bfc788c2SDavid E. O'Brien 8422c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->tx_desc_tag, (void **)desc, 8432c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->tx_desc_map); 844bfc788c2SDavid E. O'Brien if (error != 0) { 845bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 846bfc788c2SDavid E. O'Brien goto fail; 847bfc788c2SDavid E. O'Brien } 848bfc788c2SDavid E. O'Brien 849bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, *desc, 8502c3adf61SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->tx_desc_segs, 8512c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 852bfc788c2SDavid E. O'Brien if (error != 0) { 853bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 854bfc788c2SDavid E. O'Brien goto fail; 855bfc788c2SDavid E. O'Brien } 856bfc788c2SDavid E. O'Brien 857bfc788c2SDavid E. O'Brien bzero(*desc, NFE_TX_RING_COUNT * descsize); 858bfc788c2SDavid E. O'Brien 859bfc788c2SDavid E. O'Brien ring->tx_desc_addr = ring->tx_desc_segs.ds_addr; 860bfc788c2SDavid E. O'Brien ring->physaddr = ring->tx_desc_addr; 861bfc788c2SDavid E. O'Brien 862bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 863bfc788c2SDavid E. O'Brien ETHER_ALIGN, 0, 864bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, 865bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, 866bfc788c2SDavid E. O'Brien NULL, NULL, 867bfc788c2SDavid E. O'Brien NFE_JBYTES, NFE_MAX_SCATTER, 868bfc788c2SDavid E. O'Brien NFE_JBYTES, 869bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, 870bfc788c2SDavid E. O'Brien NULL, NULL, 871bfc788c2SDavid E. O'Brien &ring->tx_data_tag); 872bfc788c2SDavid E. O'Brien if (error != 0) { 873bfc788c2SDavid E. O'Brien printf("nfe%d: could not create DMA tag\n", sc->nfe_unit); 874bfc788c2SDavid E. O'Brien goto fail; 875bfc788c2SDavid E. O'Brien } 876bfc788c2SDavid E. O'Brien 877bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 8782c3adf61SDavid E. O'Brien error = bus_dmamap_create(ring->tx_data_tag, 0, 8792c3adf61SDavid E. O'Brien &ring->data[i].tx_data_map); 880bfc788c2SDavid E. O'Brien if (error != 0) { 8812c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 8822c3adf61SDavid E. O'Brien sc->nfe_unit); 883bfc788c2SDavid E. O'Brien goto fail; 884bfc788c2SDavid E. O'Brien } 885bfc788c2SDavid E. O'Brien } 886bfc788c2SDavid E. O'Brien 887bfc788c2SDavid E. O'Brien return 0; 888bfc788c2SDavid E. O'Brien 889bfc788c2SDavid E. O'Brien fail: nfe_free_tx_ring(sc, ring); 890bfc788c2SDavid E. O'Brien return error; 891bfc788c2SDavid E. O'Brien } 892bfc788c2SDavid E. O'Brien 893bfc788c2SDavid E. O'Brien 894bfc788c2SDavid E. O'Brien static void 895bfc788c2SDavid E. O'Brien nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 896bfc788c2SDavid E. O'Brien { 897bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 898bfc788c2SDavid E. O'Brien int i; 899bfc788c2SDavid E. O'Brien 900bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 901bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 902bfc788c2SDavid E. O'Brien ring->desc64[i].flags = 0; 903bfc788c2SDavid E. O'Brien else 904bfc788c2SDavid E. O'Brien ring->desc32[i].flags = 0; 905bfc788c2SDavid E. O'Brien 906bfc788c2SDavid E. O'Brien data = &ring->data[i]; 907bfc788c2SDavid E. O'Brien 908bfc788c2SDavid E. O'Brien if (data->m != NULL) { 9092c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 9102c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 911bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 912bfc788c2SDavid E. O'Brien m_freem(data->m); 913bfc788c2SDavid E. O'Brien data->m = NULL; 914bfc788c2SDavid E. O'Brien } 915bfc788c2SDavid E. O'Brien } 916bfc788c2SDavid E. O'Brien 9172c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 9182c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 919bfc788c2SDavid E. O'Brien 920bfc788c2SDavid E. O'Brien ring->queued = 0; 921bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 922bfc788c2SDavid E. O'Brien } 923bfc788c2SDavid E. O'Brien 9242c3adf61SDavid E. O'Brien 925bfc788c2SDavid E. O'Brien static void 926bfc788c2SDavid E. O'Brien nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 927bfc788c2SDavid E. O'Brien { 928bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 929bfc788c2SDavid E. O'Brien void *desc; 930bfc788c2SDavid E. O'Brien int i, descsize; 931bfc788c2SDavid E. O'Brien 932bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 933bfc788c2SDavid E. O'Brien desc = ring->desc64; 934bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 935bfc788c2SDavid E. O'Brien } else { 936bfc788c2SDavid E. O'Brien desc = ring->desc32; 937bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 938bfc788c2SDavid E. O'Brien } 939bfc788c2SDavid E. O'Brien 940bfc788c2SDavid E. O'Brien if (desc != NULL) { 9412c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 9422c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 943bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 944bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 945bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_desc_tag); 946bfc788c2SDavid E. O'Brien } 947bfc788c2SDavid E. O'Brien 948bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 949bfc788c2SDavid E. O'Brien data = &ring->data[i]; 950bfc788c2SDavid E. O'Brien 951bfc788c2SDavid E. O'Brien if (data->m != NULL) { 9522c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 9532c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 954bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 955bfc788c2SDavid E. O'Brien m_freem(data->m); 956bfc788c2SDavid E. O'Brien } 957bfc788c2SDavid E. O'Brien } 958bfc788c2SDavid E. O'Brien 959bfc788c2SDavid E. O'Brien /* ..and now actually destroy the DMA mappings */ 960bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 961bfc788c2SDavid E. O'Brien data = &ring->data[i]; 962bfc788c2SDavid E. O'Brien if (data->tx_data_map == NULL) 963bfc788c2SDavid E. O'Brien continue; 964bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->tx_data_tag, data->tx_data_map); 965bfc788c2SDavid E. O'Brien } 966bfc788c2SDavid E. O'Brien 967bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_data_tag); 968bfc788c2SDavid E. O'Brien } 969bfc788c2SDavid E. O'Brien 970bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 971bfc788c2SDavid E. O'Brien static poll_handler_t nfe_poll; 972bfc788c2SDavid E. O'Brien 9732c3adf61SDavid E. O'Brien 974bfc788c2SDavid E. O'Brien static void 975bfc788c2SDavid E. O'Brien nfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 976bfc788c2SDavid E. O'Brien { 977bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 978bfc788c2SDavid E. O'Brien 979bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 980bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 981bfc788c2SDavid E. O'Brien nfe_poll_locked(ifp, cmd, count); 982bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 983bfc788c2SDavid E. O'Brien } 984bfc788c2SDavid E. O'Brien 985bfc788c2SDavid E. O'Brien 986bfc788c2SDavid E. O'Brien static void 987bfc788c2SDavid E. O'Brien nfe_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 988bfc788c2SDavid E. O'Brien { 989bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 990bfc788c2SDavid E. O'Brien u_int32_t r; 991bfc788c2SDavid E. O'Brien 992bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 993bfc788c2SDavid E. O'Brien 994bfc788c2SDavid E. O'Brien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 995bfc788c2SDavid E. O'Brien return; 996bfc788c2SDavid E. O'Brien } 997bfc788c2SDavid E. O'Brien 998bfc788c2SDavid E. O'Brien sc->rxcycles = count; 999bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1000bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1001bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1002bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1003bfc788c2SDavid E. O'Brien 1004bfc788c2SDavid E. O'Brien if (cmd == POLL_AND_CHECK_STATUS) { 1005bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1006bfc788c2SDavid E. O'Brien return; 1007bfc788c2SDavid E. O'Brien } 1008257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1009257c5577SDavid E. O'Brien 1010257c5577SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1011257c5577SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1012257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1013bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1014257c5577SDavid E. O'Brien } 1015257c5577SDavid E. O'Brien } 1016257c5577SDavid E. O'Brien } 1017bfc788c2SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1018257c5577SDavid E. O'Brien 1019bfc788c2SDavid E. O'Brien 1020bfc788c2SDavid E. O'Brien static int 1021257c5577SDavid E. O'Brien nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1022257c5577SDavid E. O'Brien { 1023257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1024257c5577SDavid E. O'Brien struct ifreq *ifr = (struct ifreq *) data; 1025bfc788c2SDavid E. O'Brien struct mii_data *mii; 10262c3adf61SDavid E. O'Brien int error = 0; 1027257c5577SDavid E. O'Brien 1028257c5577SDavid E. O'Brien switch (cmd) { 1029257c5577SDavid E. O'Brien case SIOCSIFMTU: 10306124fe21SDavid E. O'Brien if (ifr->ifr_mtu == ifp->if_mtu) { 1031257c5577SDavid E. O'Brien error = EINVAL; 10326124fe21SDavid E. O'Brien break; 10336124fe21SDavid E. O'Brien } 10346124fe21SDavid E. O'Brien if ((sc->nfe_flags & NFE_JUMBO_SUP) && (ifr->ifr_mtu >= 10356124fe21SDavid E. O'Brien ETHERMIN && ifr->ifr_mtu <= NV_PKTLIMIT_2)) { 10366124fe21SDavid E. O'Brien NFE_LOCK(sc); 10376124fe21SDavid E. O'Brien sc->nfe_mtu = ifp->if_mtu = ifr->ifr_mtu; 10386124fe21SDavid E. O'Brien nfe_stop(ifp, 1); 10396124fe21SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 10406124fe21SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 10416124fe21SDavid E. O'Brien NFE_UNLOCK(sc); 10426124fe21SDavid E. O'Brien 10436124fe21SDavid E. O'Brien /* Reallocate Tx and Rx rings. */ 10446124fe21SDavid E. O'Brien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 10456124fe21SDavid E. O'Brien printf("nfe%d: could not allocate Tx ring\n", 10466124fe21SDavid E. O'Brien sc->nfe_unit); 10476124fe21SDavid E. O'Brien error = ENXIO; 10486124fe21SDavid E. O'Brien break; 10496124fe21SDavid E. O'Brien } 10506124fe21SDavid E. O'Brien 10516124fe21SDavid E. O'Brien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 10526124fe21SDavid E. O'Brien printf("nfe%d: could not allocate Rx ring\n", 10536124fe21SDavid E. O'Brien sc->nfe_unit); 10546124fe21SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 10556124fe21SDavid E. O'Brien error = ENXIO; 10566124fe21SDavid E. O'Brien break; 10576124fe21SDavid E. O'Brien } 10586124fe21SDavid E. O'Brien NFE_LOCK(sc); 10596124fe21SDavid E. O'Brien nfe_init_locked(sc); 10606124fe21SDavid E. O'Brien NFE_UNLOCK(sc); 10616124fe21SDavid E. O'Brien } else { 10626124fe21SDavid E. O'Brien error = EINVAL; 1063bfc788c2SDavid E. O'Brien } 1064257c5577SDavid E. O'Brien break; 1065257c5577SDavid E. O'Brien case SIOCSIFFLAGS: 1066bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1067257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 1068257c5577SDavid E. O'Brien /* 1069257c5577SDavid E. O'Brien * If only the PROMISC or ALLMULTI flag changes, then 1070257c5577SDavid E. O'Brien * don't do a full re-init of the chip, just update 1071257c5577SDavid E. O'Brien * the Rx filter. 1072257c5577SDavid E. O'Brien */ 1073bfc788c2SDavid E. O'Brien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1074bfc788c2SDavid E. O'Brien ((ifp->if_flags ^ sc->nfe_if_flags) & 1075bfc788c2SDavid E. O'Brien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1076257c5577SDavid E. O'Brien nfe_setmulti(sc); 1077bfc788c2SDavid E. O'Brien else 1078bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1079257c5577SDavid E. O'Brien } else { 1080bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1081257c5577SDavid E. O'Brien nfe_stop(ifp, 1); 1082257c5577SDavid E. O'Brien } 1083bfc788c2SDavid E. O'Brien sc->nfe_if_flags = ifp->if_flags; 1084bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1085bfc788c2SDavid E. O'Brien error = 0; 1086257c5577SDavid E. O'Brien break; 1087257c5577SDavid E. O'Brien case SIOCADDMULTI: 1088257c5577SDavid E. O'Brien case SIOCDELMULTI: 1089bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1090bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1091257c5577SDavid E. O'Brien nfe_setmulti(sc); 1092bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1093257c5577SDavid E. O'Brien error = 0; 1094257c5577SDavid E. O'Brien } 1095257c5577SDavid E. O'Brien break; 1096257c5577SDavid E. O'Brien case SIOCSIFMEDIA: 1097257c5577SDavid E. O'Brien case SIOCGIFMEDIA: 1098bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1099bfc788c2SDavid E. O'Brien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1100257c5577SDavid E. O'Brien break; 1101bfc788c2SDavid E. O'Brien case SIOCSIFCAP: 1102bfc788c2SDavid E. O'Brien { 1103bfc788c2SDavid E. O'Brien int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1104bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1105bfc788c2SDavid E. O'Brien if (mask & IFCAP_POLLING) { 1106bfc788c2SDavid E. O'Brien if (ifr->ifr_reqcap & IFCAP_POLLING) { 1107bfc788c2SDavid E. O'Brien error = ether_poll_register(nfe_poll, ifp); 1108bfc788c2SDavid E. O'Brien if (error) 1109bfc788c2SDavid E. O'Brien return(error); 1110bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1111bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1112bfc788c2SDavid E. O'Brien ifp->if_capenable |= IFCAP_POLLING; 1113bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1114bfc788c2SDavid E. O'Brien } else { 1115bfc788c2SDavid E. O'Brien error = ether_poll_deregister(ifp); 1116bfc788c2SDavid E. O'Brien /* Enable interrupt even in error case */ 1117bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1118bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1119bfc788c2SDavid E. O'Brien ifp->if_capenable &= ~IFCAP_POLLING; 1120bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1121257c5577SDavid E. O'Brien } 1122bfc788c2SDavid E. O'Brien } 11232c3adf61SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1124bfc788c2SDavid E. O'Brien if (mask & IFCAP_HWCSUM) { 1125bfc788c2SDavid E. O'Brien ifp->if_capenable ^= IFCAP_HWCSUM; 1126bfc788c2SDavid E. O'Brien if (IFCAP_HWCSUM & ifp->if_capenable && 1127bfc788c2SDavid E. O'Brien IFCAP_HWCSUM & ifp->if_capabilities) 1128bfc788c2SDavid E. O'Brien ifp->if_hwassist = NFE_CSUM_FEATURES; 1129bfc788c2SDavid E. O'Brien else 1130bfc788c2SDavid E. O'Brien ifp->if_hwassist = 0; 1131bfc788c2SDavid E. O'Brien } 1132bfc788c2SDavid E. O'Brien } 1133bfc788c2SDavid E. O'Brien break; 1134257c5577SDavid E. O'Brien 1135bfc788c2SDavid E. O'Brien default: 1136bfc788c2SDavid E. O'Brien error = ether_ioctl(ifp, cmd, data); 1137bfc788c2SDavid E. O'Brien break; 1138bfc788c2SDavid E. O'Brien } 1139257c5577SDavid E. O'Brien 1140257c5577SDavid E. O'Brien return error; 1141257c5577SDavid E. O'Brien } 1142257c5577SDavid E. O'Brien 1143bfc788c2SDavid E. O'Brien 11442c3adf61SDavid E. O'Brien static void 11452c3adf61SDavid E. O'Brien nfe_intr(void *arg) 1146bfc788c2SDavid E. O'Brien { 1147bfc788c2SDavid E. O'Brien struct nfe_softc *sc = arg; 1148bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1149bfc788c2SDavid E. O'Brien u_int32_t r; 1150bfc788c2SDavid E. O'Brien 1151bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1152bfc788c2SDavid E. O'Brien 1153bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1154bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1155bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1156bfc788c2SDavid E. O'Brien return; 1157bfc788c2SDavid E. O'Brien } 1158bfc788c2SDavid E. O'Brien #endif 1159bfc788c2SDavid E. O'Brien 1160bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1161bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1162bfc788c2SDavid E. O'Brien return; /* not for us */ 1163bfc788c2SDavid E. O'Brien } 1164bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1165bfc788c2SDavid E. O'Brien 1166bfc788c2SDavid E. O'Brien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 1167bfc788c2SDavid E. O'Brien 1168bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1169bfc788c2SDavid E. O'Brien 1170bfc788c2SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1171bfc788c2SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1172bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1173bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1174bfc788c2SDavid E. O'Brien } 1175bfc788c2SDavid E. O'Brien 1176bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1177bfc788c2SDavid E. O'Brien /* check Rx ring */ 1178bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1179bfc788c2SDavid E. O'Brien /* check Tx ring */ 1180bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1181bfc788c2SDavid E. O'Brien } 1182bfc788c2SDavid E. O'Brien 1183bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1184bfc788c2SDavid E. O'Brien 1185bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1186bfc788c2SDavid E. O'Brien !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1187bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1188bfc788c2SDavid E. O'Brien 1189bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1190bfc788c2SDavid E. O'Brien 1191bfc788c2SDavid E. O'Brien return; 1192bfc788c2SDavid E. O'Brien } 1193bfc788c2SDavid E. O'Brien 11942c3adf61SDavid E. O'Brien 1195bfc788c2SDavid E. O'Brien static void 1196257c5577SDavid E. O'Brien nfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1197257c5577SDavid E. O'Brien { 11982c3adf61SDavid E. O'Brien 1199bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1200257c5577SDavid E. O'Brien } 1201257c5577SDavid E. O'Brien 12022c3adf61SDavid E. O'Brien 1203bfc788c2SDavid E. O'Brien static void 1204257c5577SDavid E. O'Brien nfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1205257c5577SDavid E. O'Brien { 12062c3adf61SDavid E. O'Brien 1207bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1208257c5577SDavid E. O'Brien } 1209257c5577SDavid E. O'Brien 12102c3adf61SDavid E. O'Brien 1211bfc788c2SDavid E. O'Brien static void 1212257c5577SDavid E. O'Brien nfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 1213257c5577SDavid E. O'Brien { 12142c3adf61SDavid E. O'Brien 1215bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1216257c5577SDavid E. O'Brien } 1217257c5577SDavid E. O'Brien 12182c3adf61SDavid E. O'Brien 1219bfc788c2SDavid E. O'Brien static void 1220257c5577SDavid E. O'Brien nfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 1221257c5577SDavid E. O'Brien { 12222c3adf61SDavid E. O'Brien 1223bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1224257c5577SDavid E. O'Brien } 1225257c5577SDavid E. O'Brien 12262c3adf61SDavid E. O'Brien 1227bfc788c2SDavid E. O'Brien static void 1228257c5577SDavid E. O'Brien nfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1229257c5577SDavid E. O'Brien { 12302c3adf61SDavid E. O'Brien 1231bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1232257c5577SDavid E. O'Brien } 1233257c5577SDavid E. O'Brien 12342c3adf61SDavid E. O'Brien 1235bfc788c2SDavid E. O'Brien static void 1236257c5577SDavid E. O'Brien nfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1237257c5577SDavid E. O'Brien { 1238bfc788c2SDavid E. O'Brien 1239bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1240257c5577SDavid E. O'Brien } 1241257c5577SDavid E. O'Brien 12422c3adf61SDavid E. O'Brien 12432c3adf61SDavid E. O'Brien static void 12442c3adf61SDavid E. O'Brien nfe_rxeof(struct nfe_softc *sc) 1245257c5577SDavid E. O'Brien { 1246bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1247bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1248bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1249257c5577SDavid E. O'Brien struct nfe_rx_data *data; 1250257c5577SDavid E. O'Brien struct mbuf *m, *mnew; 1251257c5577SDavid E. O'Brien bus_addr_t physaddr; 1252bfc788c2SDavid E. O'Brien u_int16_t flags; 1253257c5577SDavid E. O'Brien int error, len; 1254bfc788c2SDavid E. O'Brien #if NVLAN > 1 1255bfc788c2SDavid E. O'Brien u_int16_t vlan_tag = 0; 1256bfc788c2SDavid E. O'Brien int have_tag = 0; 1257bfc788c2SDavid E. O'Brien #endif 1258bfc788c2SDavid E. O'Brien 1259bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1260257c5577SDavid E. O'Brien 1261257c5577SDavid E. O'Brien for (;;) { 1262bfc788c2SDavid E. O'Brien 1263bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1264bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1265bfc788c2SDavid E. O'Brien if (sc->rxcycles <= 0) 1266bfc788c2SDavid E. O'Brien break; 1267bfc788c2SDavid E. O'Brien sc->rxcycles--; 1268bfc788c2SDavid E. O'Brien } 1269bfc788c2SDavid E. O'Brien #endif 1270bfc788c2SDavid E. O'Brien 1271257c5577SDavid E. O'Brien data = &sc->rxq.data[sc->rxq.cur]; 1272257c5577SDavid E. O'Brien 1273bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1274257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 1275257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1276257c5577SDavid E. O'Brien 1277257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1278257c5577SDavid E. O'Brien len = letoh16(desc64->length) & 0x3fff; 1279bfc788c2SDavid E. O'Brien 1280bfc788c2SDavid E. O'Brien #if NVLAN > 1 1281bfc788c2SDavid E. O'Brien if (flags & NFE_TX_VLAN_TAG) { 1282bfc788c2SDavid E. O'Brien have_tag = 1; 1283bfc788c2SDavid E. O'Brien vlan_tag = desc64->vtag; 1284bfc788c2SDavid E. O'Brien } 1285bfc788c2SDavid E. O'Brien #endif 1286bfc788c2SDavid E. O'Brien 1287257c5577SDavid E. O'Brien } else { 1288257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 1289257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1290257c5577SDavid E. O'Brien 1291257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1292257c5577SDavid E. O'Brien len = letoh16(desc32->length) & 0x3fff; 1293257c5577SDavid E. O'Brien } 1294257c5577SDavid E. O'Brien 1295257c5577SDavid E. O'Brien if (flags & NFE_RX_READY) 1296257c5577SDavid E. O'Brien break; 1297257c5577SDavid E. O'Brien 1298bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1299257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V1)) 1300257c5577SDavid E. O'Brien goto skip; 1301257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 1302257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1303257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1304257c5577SDavid E. O'Brien } 1305257c5577SDavid E. O'Brien } else { 1306257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V2)) 1307257c5577SDavid E. O'Brien goto skip; 1308257c5577SDavid E. O'Brien 1309257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 1310257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1311257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1312257c5577SDavid E. O'Brien } 1313257c5577SDavid E. O'Brien } 1314257c5577SDavid E. O'Brien 1315257c5577SDavid E. O'Brien if (flags & NFE_RX_ERROR) { 1316257c5577SDavid E. O'Brien ifp->if_ierrors++; 1317257c5577SDavid E. O'Brien goto skip; 1318257c5577SDavid E. O'Brien } 1319257c5577SDavid E. O'Brien 1320257c5577SDavid E. O'Brien /* 1321257c5577SDavid E. O'Brien * Try to allocate a new mbuf for this ring element and load 1322257c5577SDavid E. O'Brien * it before processing the current mbuf. If the ring element 1323257c5577SDavid E. O'Brien * cannot be loaded, drop the received packet and reuse the 1324257c5577SDavid E. O'Brien * old mbuf. In the unlikely case that the old mbuf can't be 1325257c5577SDavid E. O'Brien * reloaded either, explicitly panic. 1326257c5577SDavid E. O'Brien */ 1327257c5577SDavid E. O'Brien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 1328257c5577SDavid E. O'Brien if (mnew == NULL) { 1329257c5577SDavid E. O'Brien ifp->if_ierrors++; 1330257c5577SDavid E. O'Brien goto skip; 1331257c5577SDavid E. O'Brien } 1332257c5577SDavid E. O'Brien 1333257c5577SDavid E. O'Brien MCLGET(mnew, M_DONTWAIT); 1334257c5577SDavid E. O'Brien if (!(mnew->m_flags & M_EXT)) { 1335257c5577SDavid E. O'Brien m_freem(mnew); 1336257c5577SDavid E. O'Brien ifp->if_ierrors++; 1337257c5577SDavid E. O'Brien goto skip; 1338257c5577SDavid E. O'Brien } 1339257c5577SDavid E. O'Brien 1340bfc788c2SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, 1341bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTREAD); 1342bfc788c2SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 1343bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1344bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(mnew, void *), MCLBYTES, 1345bfc788c2SDavid E. O'Brien nfe_dma_map_segs, &data->rx_data_segs, 1346bfc788c2SDavid E. O'Brien BUS_DMA_NOWAIT); 1347257c5577SDavid E. O'Brien if (error != 0) { 1348257c5577SDavid E. O'Brien m_freem(mnew); 1349257c5577SDavid E. O'Brien 1350257c5577SDavid E. O'Brien /* try to reload the old mbuf */ 1351bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1352bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), 1353bfc788c2SDavid E. O'Brien MCLBYTES, nfe_dma_map_segs, 1354bfc788c2SDavid E. O'Brien &data->rx_data_segs, BUS_DMA_NOWAIT); 1355257c5577SDavid E. O'Brien if (error != 0) { 1356257c5577SDavid E. O'Brien /* very unlikely that it will fail.. */ 1357bfc788c2SDavid E. O'Brien panic("nfe%d: could not load old rx mbuf", 1358bfc788c2SDavid E. O'Brien sc->nfe_unit); 1359257c5577SDavid E. O'Brien } 1360257c5577SDavid E. O'Brien ifp->if_ierrors++; 1361257c5577SDavid E. O'Brien goto skip; 1362257c5577SDavid E. O'Brien } 1363bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 1364bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 1365257c5577SDavid E. O'Brien 1366257c5577SDavid E. O'Brien /* 1367257c5577SDavid E. O'Brien * New mbuf successfully loaded, update Rx ring and continue 1368257c5577SDavid E. O'Brien * processing. 1369257c5577SDavid E. O'Brien */ 1370257c5577SDavid E. O'Brien m = data->m; 1371257c5577SDavid E. O'Brien data->m = mnew; 1372257c5577SDavid E. O'Brien 1373257c5577SDavid E. O'Brien /* finalize mbuf */ 1374257c5577SDavid E. O'Brien m->m_pkthdr.len = m->m_len = len; 1375257c5577SDavid E. O'Brien m->m_pkthdr.rcvif = ifp; 1376257c5577SDavid E. O'Brien 1377bfc788c2SDavid E. O'Brien 1378bfc788c2SDavid E. O'Brien #if defined(NFE_CSUM) 1379bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) { 1380bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1381bfc788c2SDavid E. O'Brien if (flags & NFE_RX_IP_CSUMOK_V2) { 1382bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1383257c5577SDavid E. O'Brien } 1384bfc788c2SDavid E. O'Brien if (flags & NFE_RX_UDP_CSUMOK_V2 || 1385bfc788c2SDavid E. O'Brien flags & NFE_RX_TCP_CSUMOK_V2) { 1386bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= 1387bfc788c2SDavid E. O'Brien CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 1388bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_data = 0xffff; 1389bfc788c2SDavid E. O'Brien } 1390bfc788c2SDavid E. O'Brien } 1391257c5577SDavid E. O'Brien #endif 1392257c5577SDavid E. O'Brien 1393bfc788c2SDavid E. O'Brien #if NVLAN > 1 1394bfc788c2SDavid E. O'Brien if (have_tag) { 139578ba57b9SAndre Oppermann m->m_pkthdr.ether_vtag = vlan_tag; 139678ba57b9SAndre Oppermann m->m_flags |= M_VLANTAG; 1397bfc788c2SDavid E. O'Brien } 1398257c5577SDavid E. O'Brien #endif 1399bfc788c2SDavid E. O'Brien 1400257c5577SDavid E. O'Brien ifp->if_ipackets++; 1401bfc788c2SDavid E. O'Brien 1402bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1403bfc788c2SDavid E. O'Brien (*ifp->if_input)(ifp, m); 1404bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1405257c5577SDavid E. O'Brien 1406257c5577SDavid E. O'Brien /* update mapping address in h/w descriptor */ 1407bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1408257c5577SDavid E. O'Brien #if defined(__LP64__) 1409257c5577SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 1410257c5577SDavid E. O'Brien #endif 1411257c5577SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1412257c5577SDavid E. O'Brien } else { 1413257c5577SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 1414257c5577SDavid E. O'Brien } 1415257c5577SDavid E. O'Brien 1416bfc788c2SDavid E. O'Brien skip: if (sc->nfe_flags & NFE_40BIT_ADDR) { 1417257c5577SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 1418257c5577SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 1419257c5577SDavid E. O'Brien 1420257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 1421257c5577SDavid E. O'Brien } else { 1422257c5577SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 1423257c5577SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 1424257c5577SDavid E. O'Brien 1425257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 1426257c5577SDavid E. O'Brien } 1427257c5577SDavid E. O'Brien 1428257c5577SDavid E. O'Brien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 1429257c5577SDavid E. O'Brien } 1430257c5577SDavid E. O'Brien } 1431257c5577SDavid E. O'Brien 14322c3adf61SDavid E. O'Brien 14332c3adf61SDavid E. O'Brien static void 14342c3adf61SDavid E. O'Brien nfe_txeof(struct nfe_softc *sc) 1435257c5577SDavid E. O'Brien { 1436bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1437257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 1438257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 1439257c5577SDavid E. O'Brien struct nfe_tx_data *data = NULL; 1440bfc788c2SDavid E. O'Brien u_int16_t flags; 1441bfc788c2SDavid E. O'Brien 1442bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1443257c5577SDavid E. O'Brien 1444257c5577SDavid E. O'Brien while (sc->txq.next != sc->txq.cur) { 1445bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1446257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.next]; 1447257c5577SDavid E. O'Brien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1448257c5577SDavid E. O'Brien 1449257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1450257c5577SDavid E. O'Brien } else { 1451257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.next]; 1452257c5577SDavid E. O'Brien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1453257c5577SDavid E. O'Brien 1454257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1455257c5577SDavid E. O'Brien } 1456257c5577SDavid E. O'Brien 1457257c5577SDavid E. O'Brien if (flags & NFE_TX_VALID) 1458257c5577SDavid E. O'Brien break; 1459257c5577SDavid E. O'Brien 1460257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.next]; 1461257c5577SDavid E. O'Brien 1462bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1463257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 1464257c5577SDavid E. O'Brien goto skip; 1465257c5577SDavid E. O'Brien 1466257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V1) != 0) { 1467bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1468bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V1_TXERR); 1469bfc788c2SDavid E. O'Brien 1470257c5577SDavid E. O'Brien ifp->if_oerrors++; 1471257c5577SDavid E. O'Brien } else 1472257c5577SDavid E. O'Brien ifp->if_opackets++; 1473257c5577SDavid E. O'Brien } else { 1474257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 1475257c5577SDavid E. O'Brien goto skip; 1476257c5577SDavid E. O'Brien 1477257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V2) != 0) { 1478bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1479bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V2_TXERR); 1480bfc788c2SDavid E. O'Brien 1481257c5577SDavid E. O'Brien ifp->if_oerrors++; 1482257c5577SDavid E. O'Brien } else 1483257c5577SDavid E. O'Brien ifp->if_opackets++; 1484257c5577SDavid E. O'Brien } 1485257c5577SDavid E. O'Brien 1486257c5577SDavid E. O'Brien if (data->m == NULL) { /* should not get there */ 1487bfc788c2SDavid E. O'Brien printf("nfe%d: last fragment bit w/o associated mbuf!\n", 1488bfc788c2SDavid E. O'Brien sc->nfe_unit); 1489257c5577SDavid E. O'Brien goto skip; 1490257c5577SDavid E. O'Brien } 1491257c5577SDavid E. O'Brien 1492257c5577SDavid E. O'Brien /* last fragment of the mbuf chain transmitted */ 1493bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, data->active, 1494bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1495bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, data->active); 1496257c5577SDavid E. O'Brien m_freem(data->m); 1497257c5577SDavid E. O'Brien data->m = NULL; 1498257c5577SDavid E. O'Brien 1499257c5577SDavid E. O'Brien ifp->if_timer = 0; 1500257c5577SDavid E. O'Brien 1501257c5577SDavid E. O'Brien skip: sc->txq.queued--; 1502257c5577SDavid E. O'Brien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 1503257c5577SDavid E. O'Brien } 1504257c5577SDavid E. O'Brien 1505257c5577SDavid E. O'Brien if (data != NULL) { /* at least one slot freed */ 1506bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1507bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1508257c5577SDavid E. O'Brien } 1509257c5577SDavid E. O'Brien } 1510257c5577SDavid E. O'Brien 15112c3adf61SDavid E. O'Brien 15122c3adf61SDavid E. O'Brien static int 15132c3adf61SDavid E. O'Brien nfe_encap(struct nfe_softc *sc, struct mbuf *m0) 1514257c5577SDavid E. O'Brien { 1515bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1516bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1517bfc788c2SDavid E. O'Brien struct nfe_tx_data *data=NULL; 1518257c5577SDavid E. O'Brien bus_dmamap_t map; 1519bfc788c2SDavid E. O'Brien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 15202c3adf61SDavid E. O'Brien int error, i, nsegs; 15212c3adf61SDavid E. O'Brien u_int16_t flags = NFE_TX_VALID; 1522257c5577SDavid E. O'Brien 1523bfc788c2SDavid E. O'Brien map = sc->txq.data[sc->txq.cur].tx_data_map; 1524257c5577SDavid E. O'Brien 1525bfc788c2SDavid E. O'Brien error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, m0, segs, 1526bfc788c2SDavid E. O'Brien &nsegs, BUS_DMA_NOWAIT); 1527bfc788c2SDavid E. O'Brien 1528257c5577SDavid E. O'Brien if (error != 0) { 1529bfc788c2SDavid E. O'Brien printf("nfe%d: could not map mbuf (error %d)\n", sc->nfe_unit, 1530bfc788c2SDavid E. O'Brien error); 1531257c5577SDavid E. O'Brien return error; 1532257c5577SDavid E. O'Brien } 1533257c5577SDavid E. O'Brien 1534bfc788c2SDavid E. O'Brien if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 1) { 1535bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, map); 1536257c5577SDavid E. O'Brien return ENOBUFS; 1537257c5577SDavid E. O'Brien } 1538257c5577SDavid E. O'Brien 1539bfc788c2SDavid E. O'Brien 1540257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1541bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_IP) 1542257c5577SDavid E. O'Brien flags |= NFE_TX_IP_CSUM; 1543bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_TCP) 1544bfc788c2SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1545bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_UDP) 1546257c5577SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1547257c5577SDavid E. O'Brien #endif 1548257c5577SDavid E. O'Brien 1549bfc788c2SDavid E. O'Brien for (i = 0; i < nsegs; i++) { 1550257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.cur]; 1551257c5577SDavid E. O'Brien 1552bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1553257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.cur]; 1554257c5577SDavid E. O'Brien #if defined(__LP64__) 1555bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(segs[i].ds_addr >> 32); 1556257c5577SDavid E. O'Brien #endif 1557bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(segs[i].ds_addr & 1558bfc788c2SDavid E. O'Brien 0xffffffff); 1559bfc788c2SDavid E. O'Brien desc64->length = htole16(segs[i].ds_len - 1); 1560257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1561257c5577SDavid E. O'Brien #if NVLAN > 0 156278ba57b9SAndre Oppermann if (m0->m_flags & M_VLANTAG) 1563bfc788c2SDavid E. O'Brien desc64->vtag = htole32(NFE_TX_VTAG | 156478ba57b9SAndre Oppermann m0->m_pkthdr.ether_vtag); 1565257c5577SDavid E. O'Brien #endif 1566257c5577SDavid E. O'Brien } else { 1567257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.cur]; 1568257c5577SDavid E. O'Brien 1569bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(segs[i].ds_addr); 1570bfc788c2SDavid E. O'Brien desc32->length = htole16(segs[i].ds_len - 1); 1571257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1572257c5577SDavid E. O'Brien } 1573257c5577SDavid E. O'Brien 1574257c5577SDavid E. O'Brien /* csum flags and vtag belong to the first fragment only */ 1575bfc788c2SDavid E. O'Brien if (nsegs > 1) { 1576257c5577SDavid E. O'Brien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 1577257c5577SDavid E. O'Brien } 1578257c5577SDavid E. O'Brien 1579257c5577SDavid E. O'Brien sc->txq.queued++; 1580257c5577SDavid E. O'Brien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 1581257c5577SDavid E. O'Brien } 1582257c5577SDavid E. O'Brien 1583257c5577SDavid E. O'Brien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 1584bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1585257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1586257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1587257c5577SDavid E. O'Brien } else { 1588bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 1589257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1590257c5577SDavid E. O'Brien else 1591257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V1; 1592257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1593257c5577SDavid E. O'Brien } 1594257c5577SDavid E. O'Brien 1595257c5577SDavid E. O'Brien data->m = m0; 1596257c5577SDavid E. O'Brien data->active = map; 1597bfc788c2SDavid E. O'Brien data->nsegs = nsegs; 1598257c5577SDavid E. O'Brien 1599bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 1600257c5577SDavid E. O'Brien 1601257c5577SDavid E. O'Brien return 0; 1602257c5577SDavid E. O'Brien } 1603257c5577SDavid E. O'Brien 1604bfc788c2SDavid E. O'Brien 16052c3adf61SDavid E. O'Brien static void 16062c3adf61SDavid E. O'Brien nfe_setmulti(struct nfe_softc *sc) 1607bfc788c2SDavid E. O'Brien { 1608bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1609bfc788c2SDavid E. O'Brien struct ifmultiaddr *ifma; 1610bfc788c2SDavid E. O'Brien int i; 16112c3adf61SDavid E. O'Brien u_int32_t filter = NFE_RXFILTER_MAGIC; 16122c3adf61SDavid E. O'Brien u_int8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 16132c3adf61SDavid E. O'Brien u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 16142c3adf61SDavid E. O'Brien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 16152c3adf61SDavid E. O'Brien }; 1616bfc788c2SDavid E. O'Brien 1617bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1618bfc788c2SDavid E. O'Brien 1619bfc788c2SDavid E. O'Brien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1620bfc788c2SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 1621bfc788c2SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 1622bfc788c2SDavid E. O'Brien goto done; 1623bfc788c2SDavid E. O'Brien } 1624bfc788c2SDavid E. O'Brien 1625bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1626bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1627bfc788c2SDavid E. O'Brien 1628bfc788c2SDavid E. O'Brien IF_ADDR_LOCK(ifp); 1629bfc788c2SDavid E. O'Brien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1630bfc788c2SDavid E. O'Brien u_char *addrp; 1631bfc788c2SDavid E. O'Brien 1632bfc788c2SDavid E. O'Brien if (ifma->ifma_addr->sa_family != AF_LINK) 1633bfc788c2SDavid E. O'Brien continue; 1634bfc788c2SDavid E. O'Brien 1635bfc788c2SDavid E. O'Brien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 1636bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1637bfc788c2SDavid E. O'Brien u_int8_t mcaddr = addrp[i]; 1638bfc788c2SDavid E. O'Brien addr[i] &= mcaddr; 1639bfc788c2SDavid E. O'Brien mask[i] &= ~mcaddr; 1640bfc788c2SDavid E. O'Brien } 1641bfc788c2SDavid E. O'Brien } 1642bfc788c2SDavid E. O'Brien IF_ADDR_UNLOCK(ifp); 1643bfc788c2SDavid E. O'Brien 1644bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1645bfc788c2SDavid E. O'Brien mask[i] |= addr[i]; 1646bfc788c2SDavid E. O'Brien } 1647bfc788c2SDavid E. O'Brien 1648bfc788c2SDavid E. O'Brien done: 1649bfc788c2SDavid E. O'Brien addr[0] |= 0x01; /* make sure multicast bit is set */ 1650bfc788c2SDavid E. O'Brien 1651bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1652bfc788c2SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1653bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1654bfc788c2SDavid E. O'Brien addr[5] << 8 | addr[4]); 1655bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1656bfc788c2SDavid E. O'Brien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1657bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1658bfc788c2SDavid E. O'Brien mask[5] << 8 | mask[4]); 1659bfc788c2SDavid E. O'Brien 1660bfc788c2SDavid E. O'Brien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1661bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_RXFILTER, filter); 1662bfc788c2SDavid E. O'Brien } 1663bfc788c2SDavid E. O'Brien 16642c3adf61SDavid E. O'Brien 16652c3adf61SDavid E. O'Brien static void 16662c3adf61SDavid E. O'Brien nfe_start(struct ifnet *ifp) 1667bfc788c2SDavid E. O'Brien { 1668bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1669bfc788c2SDavid E. O'Brien 1670bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 1671bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1672bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1673bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1674bfc788c2SDavid E. O'Brien } 1675bfc788c2SDavid E. O'Brien 16762c3adf61SDavid E. O'Brien 16772c3adf61SDavid E. O'Brien static void 16782c3adf61SDavid E. O'Brien nfe_start_locked(struct ifnet *ifp) 1679257c5577SDavid E. O'Brien { 1680257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1681257c5577SDavid E. O'Brien struct mbuf *m0; 16822c3adf61SDavid E. O'Brien int old = sc->txq.cur; 1683257c5577SDavid E. O'Brien 1684bfc788c2SDavid E. O'Brien if (!sc->nfe_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1685bfc788c2SDavid E. O'Brien return; 1686bfc788c2SDavid E. O'Brien } 1687bfc788c2SDavid E. O'Brien 1688257c5577SDavid E. O'Brien for (;;) { 1689257c5577SDavid E. O'Brien IFQ_POLL(&ifp->if_snd, m0); 1690257c5577SDavid E. O'Brien if (m0 == NULL) 1691257c5577SDavid E. O'Brien break; 1692257c5577SDavid E. O'Brien 1693257c5577SDavid E. O'Brien if (nfe_encap(sc, m0) != 0) { 1694bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1695257c5577SDavid E. O'Brien break; 1696257c5577SDavid E. O'Brien } 1697257c5577SDavid E. O'Brien 1698257c5577SDavid E. O'Brien /* packet put in h/w queue, remove from s/w queue */ 1699257c5577SDavid E. O'Brien IFQ_DEQUEUE(&ifp->if_snd, m0); 1700257c5577SDavid E. O'Brien 1701bfc788c2SDavid E. O'Brien BPF_MTAP(ifp, m0); 1702257c5577SDavid E. O'Brien } 1703bfc788c2SDavid E. O'Brien if (sc->txq.cur == old) { /* nothing sent */ 1704257c5577SDavid E. O'Brien return; 1705bfc788c2SDavid E. O'Brien } 1706257c5577SDavid E. O'Brien 1707bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1708257c5577SDavid E. O'Brien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1709257c5577SDavid E. O'Brien else 1710257c5577SDavid E. O'Brien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1711257c5577SDavid E. O'Brien 1712257c5577SDavid E. O'Brien /* kick Tx */ 1713257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1714257c5577SDavid E. O'Brien 1715257c5577SDavid E. O'Brien /* 1716257c5577SDavid E. O'Brien * Set a timeout in case the chip goes out to lunch. 1717257c5577SDavid E. O'Brien */ 1718257c5577SDavid E. O'Brien ifp->if_timer = 5; 1719bfc788c2SDavid E. O'Brien 1720bfc788c2SDavid E. O'Brien return; 1721257c5577SDavid E. O'Brien } 1722257c5577SDavid E. O'Brien 17232c3adf61SDavid E. O'Brien 17242c3adf61SDavid E. O'Brien static void 17252c3adf61SDavid E. O'Brien nfe_watchdog(struct ifnet *ifp) 1726257c5577SDavid E. O'Brien { 1727257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1728257c5577SDavid E. O'Brien 1729bfc788c2SDavid E. O'Brien printf("nfe%d: watchdog timeout\n", sc->nfe_unit); 1730257c5577SDavid E. O'Brien 1731bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1732bfc788c2SDavid E. O'Brien nfe_init(sc); 1733257c5577SDavid E. O'Brien ifp->if_oerrors++; 1734bfc788c2SDavid E. O'Brien 1735bfc788c2SDavid E. O'Brien return; 1736257c5577SDavid E. O'Brien } 1737257c5577SDavid E. O'Brien 17382c3adf61SDavid E. O'Brien 17392c3adf61SDavid E. O'Brien static void 17402c3adf61SDavid E. O'Brien nfe_init(void *xsc) 1741257c5577SDavid E. O'Brien { 1742bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1743bfc788c2SDavid E. O'Brien 1744bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1745bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1746bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1747bfc788c2SDavid E. O'Brien 1748bfc788c2SDavid E. O'Brien return; 1749bfc788c2SDavid E. O'Brien } 1750bfc788c2SDavid E. O'Brien 17512c3adf61SDavid E. O'Brien 17522c3adf61SDavid E. O'Brien static void 17532c3adf61SDavid E. O'Brien nfe_init_locked(void *xsc) 1754bfc788c2SDavid E. O'Brien { 1755bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1756bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1757bfc788c2SDavid E. O'Brien struct mii_data *mii; 1758bfc788c2SDavid E. O'Brien u_int32_t tmp; 1759bfc788c2SDavid E. O'Brien 1760bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1761bfc788c2SDavid E. O'Brien 1762bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1763bfc788c2SDavid E. O'Brien 1764bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1765bfc788c2SDavid E. O'Brien return; 1766bfc788c2SDavid E. O'Brien } 1767257c5577SDavid E. O'Brien 1768257c5577SDavid E. O'Brien nfe_stop(ifp, 0); 1769257c5577SDavid E. O'Brien 1770257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_UNK, 0); 1771257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, 0); 1772257c5577SDavid E. O'Brien 1773257c5577SDavid E. O'Brien sc->rxtxctl = NFE_RXTX_BIT2; 1774bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1775257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1776bfc788c2SDavid E. O'Brien else if (sc->nfe_flags & NFE_JUMBO_SUP) 1777257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 1778257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1779bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) 1780257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1781257c5577SDavid E. O'Brien #endif 1782bfc788c2SDavid E. O'Brien 1783257c5577SDavid E. O'Brien #if NVLAN > 0 1784257c5577SDavid E. O'Brien /* 1785257c5577SDavid E. O'Brien * Although the adapter is capable of stripping VLAN tags from received 1786257c5577SDavid E. O'Brien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1787257c5577SDavid E. O'Brien * purpose. This will be done in software by our network stack. 1788257c5577SDavid E. O'Brien */ 1789bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1790257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1791257c5577SDavid E. O'Brien #endif 1792bfc788c2SDavid E. O'Brien 1793257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1794257c5577SDavid E. O'Brien DELAY(10); 1795257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1796257c5577SDavid E. O'Brien 1797257c5577SDavid E. O'Brien #if NVLAN 1798bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1799257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1800257c5577SDavid E. O'Brien #endif 1801257c5577SDavid E. O'Brien 1802257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1803257c5577SDavid E. O'Brien 1804257c5577SDavid E. O'Brien /* set MAC address */ 1805bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, sc->eaddr); 1806257c5577SDavid E. O'Brien 1807257c5577SDavid E. O'Brien /* tell MAC where rings are in memory */ 1808257c5577SDavid E. O'Brien #ifdef __LP64__ 1809257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1810257c5577SDavid E. O'Brien #endif 1811257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1812257c5577SDavid E. O'Brien #ifdef __LP64__ 1813257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1814257c5577SDavid E. O'Brien #endif 1815257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1816257c5577SDavid E. O'Brien 1817257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RING_SIZE, 1818257c5577SDavid E. O'Brien (NFE_RX_RING_COUNT - 1) << 16 | 1819257c5577SDavid E. O'Brien (NFE_TX_RING_COUNT - 1)); 1820257c5577SDavid E. O'Brien 1821257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1822257c5577SDavid E. O'Brien 1823257c5577SDavid E. O'Brien /* force MAC to wakeup */ 1824257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1825257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1826257c5577SDavid E. O'Brien DELAY(10); 1827257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1828257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1829257c5577SDavid E. O'Brien 1830257c5577SDavid E. O'Brien #if 1 1831257c5577SDavid E. O'Brien /* configure interrupts coalescing/mitigation */ 1832257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1833257c5577SDavid E. O'Brien #else 1834257c5577SDavid E. O'Brien /* no interrupt mitigation: one interrupt per packet */ 1835257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, 970); 1836257c5577SDavid E. O'Brien #endif 1837257c5577SDavid E. O'Brien 1838257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1839257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1840257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1841257c5577SDavid E. O'Brien 1842257c5577SDavid E. O'Brien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1843257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1844257c5577SDavid E. O'Brien 1845257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1846257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1847257c5577SDavid E. O'Brien 1848257c5577SDavid E. O'Brien sc->rxtxctl &= ~NFE_RXTX_BIT2; 1849257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1850257c5577SDavid E. O'Brien DELAY(10); 1851257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1852257c5577SDavid E. O'Brien 1853257c5577SDavid E. O'Brien /* set Rx filter */ 1854257c5577SDavid E. O'Brien nfe_setmulti(sc); 1855257c5577SDavid E. O'Brien 1856257c5577SDavid E. O'Brien nfe_ifmedia_upd(ifp); 1857257c5577SDavid E. O'Brien 1858bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 1859bfc788c2SDavid E. O'Brien 1860257c5577SDavid E. O'Brien /* enable Rx */ 1861257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1862257c5577SDavid E. O'Brien 1863257c5577SDavid E. O'Brien /* enable Tx */ 1864257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1865257c5577SDavid E. O'Brien 1866257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1867257c5577SDavid E. O'Brien 1868bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1869bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 1870bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1871bfc788c2SDavid E. O'Brien else 1872bfc788c2SDavid E. O'Brien #endif 1873bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); /* enable interrupts */ 1874257c5577SDavid E. O'Brien 1875bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_RUNNING; 1876bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1877257c5577SDavid E. O'Brien 1878bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 1879257c5577SDavid E. O'Brien 1880bfc788c2SDavid E. O'Brien return; 1881257c5577SDavid E. O'Brien } 1882257c5577SDavid E. O'Brien 18832c3adf61SDavid E. O'Brien 18842c3adf61SDavid E. O'Brien static void 18852c3adf61SDavid E. O'Brien nfe_stop(struct ifnet *ifp, int disable) 1886257c5577SDavid E. O'Brien { 1887257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1888bfc788c2SDavid E. O'Brien struct mii_data *mii; 1889257c5577SDavid E. O'Brien 1890bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1891257c5577SDavid E. O'Brien 1892257c5577SDavid E. O'Brien ifp->if_timer = 0; 1893bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1894257c5577SDavid E. O'Brien 1895bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1896bfc788c2SDavid E. O'Brien 1897bfc788c2SDavid E. O'Brien callout_stop(&sc->nfe_stat_ch); 1898257c5577SDavid E. O'Brien 1899257c5577SDavid E. O'Brien /* abort Tx */ 1900257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, 0); 1901257c5577SDavid E. O'Brien 1902257c5577SDavid E. O'Brien /* disable Rx */ 1903257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, 0); 1904257c5577SDavid E. O'Brien 1905257c5577SDavid E. O'Brien /* disable interrupts */ 1906257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1907257c5577SDavid E. O'Brien 1908bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 1909bfc788c2SDavid E. O'Brien 1910257c5577SDavid E. O'Brien /* reset Tx and Rx rings */ 1911257c5577SDavid E. O'Brien nfe_reset_tx_ring(sc, &sc->txq); 1912257c5577SDavid E. O'Brien nfe_reset_rx_ring(sc, &sc->rxq); 1913257c5577SDavid E. O'Brien 1914257c5577SDavid E. O'Brien return; 1915257c5577SDavid E. O'Brien } 1916257c5577SDavid E. O'Brien 19172c3adf61SDavid E. O'Brien 19182c3adf61SDavid E. O'Brien static int 19192c3adf61SDavid E. O'Brien nfe_ifmedia_upd(struct ifnet *ifp) 1920257c5577SDavid E. O'Brien { 1921257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1922257c5577SDavid E. O'Brien 1923bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1924bfc788c2SDavid E. O'Brien nfe_ifmedia_upd_locked(ifp); 1925bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1926bfc788c2SDavid E. O'Brien return (0); 1927bfc788c2SDavid E. O'Brien } 1928bfc788c2SDavid E. O'Brien 19292c3adf61SDavid E. O'Brien 19302c3adf61SDavid E. O'Brien static int 19312c3adf61SDavid E. O'Brien nfe_ifmedia_upd_locked(struct ifnet *ifp) 1932bfc788c2SDavid E. O'Brien { 1933bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1934bfc788c2SDavid E. O'Brien struct mii_data *mii; 1935bfc788c2SDavid E. O'Brien 1936bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1937bfc788c2SDavid E. O'Brien 1938bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1939bfc788c2SDavid E. O'Brien 1940bfc788c2SDavid E. O'Brien if (mii->mii_instance) { 1941bfc788c2SDavid E. O'Brien struct mii_softc *miisc; 1942bfc788c2SDavid E. O'Brien for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 1943bfc788c2SDavid E. O'Brien miisc = LIST_NEXT(miisc, mii_list)) { 1944257c5577SDavid E. O'Brien mii_phy_reset(miisc); 1945257c5577SDavid E. O'Brien } 1946bfc788c2SDavid E. O'Brien } 1947bfc788c2SDavid E. O'Brien mii_mediachg(mii); 1948bfc788c2SDavid E. O'Brien 1949bfc788c2SDavid E. O'Brien return (0); 1950257c5577SDavid E. O'Brien } 1951257c5577SDavid E. O'Brien 19522c3adf61SDavid E. O'Brien 19532c3adf61SDavid E. O'Brien static void 19542c3adf61SDavid E. O'Brien nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1955257c5577SDavid E. O'Brien { 1956bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1957bfc788c2SDavid E. O'Brien struct mii_data *mii; 1958257c5577SDavid E. O'Brien 1959bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 1960bfc788c2SDavid E. O'Brien 1961bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1962bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1963257c5577SDavid E. O'Brien mii_pollstat(mii); 1964bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1965bfc788c2SDavid E. O'Brien 1966257c5577SDavid E. O'Brien ifmr->ifm_active = mii->mii_media_active; 1967bfc788c2SDavid E. O'Brien ifmr->ifm_status = mii->mii_media_status; 1968bfc788c2SDavid E. O'Brien 1969bfc788c2SDavid E. O'Brien return; 1970257c5577SDavid E. O'Brien } 1971257c5577SDavid E. O'Brien 19722c3adf61SDavid E. O'Brien 1973bfc788c2SDavid E. O'Brien static void 1974bfc788c2SDavid E. O'Brien nfe_tick(void *xsc) 1975257c5577SDavid E. O'Brien { 1976bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1977257c5577SDavid E. O'Brien 1978bfc788c2SDavid E. O'Brien sc = xsc; 1979bfc788c2SDavid E. O'Brien 1980bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1981bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 1982bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1983257c5577SDavid E. O'Brien } 1984257c5577SDavid E. O'Brien 1985257c5577SDavid E. O'Brien 19862c3adf61SDavid E. O'Brien void 19872c3adf61SDavid E. O'Brien nfe_tick_locked(struct nfe_softc *arg) 1988bfc788c2SDavid E. O'Brien { 1989bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1990bfc788c2SDavid E. O'Brien struct mii_data *mii; 1991bfc788c2SDavid E. O'Brien struct ifnet *ifp; 1992bfc788c2SDavid E. O'Brien 1993bfc788c2SDavid E. O'Brien sc = arg; 1994bfc788c2SDavid E. O'Brien 1995bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1996bfc788c2SDavid E. O'Brien 1997bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 1998bfc788c2SDavid E. O'Brien 1999bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2000bfc788c2SDavid E. O'Brien mii_tick(mii); 2001bfc788c2SDavid E. O'Brien 2002bfc788c2SDavid E. O'Brien if (!sc->nfe_link) { 2003bfc788c2SDavid E. O'Brien if (mii->mii_media_status & IFM_ACTIVE && 2004bfc788c2SDavid E. O'Brien IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 2005bfc788c2SDavid E. O'Brien sc->nfe_link++; 2006bfc788c2SDavid E. O'Brien if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T 2007bfc788c2SDavid E. O'Brien && bootverbose) 2008bfc788c2SDavid E. O'Brien if_printf(sc->nfe_ifp, "gigabit link up\n"); 2009bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2010bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 2011257c5577SDavid E. O'Brien } 2012257c5577SDavid E. O'Brien } 2013bfc788c2SDavid E. O'Brien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2014257c5577SDavid E. O'Brien 2015bfc788c2SDavid E. O'Brien return; 2016257c5577SDavid E. O'Brien } 2017257c5577SDavid E. O'Brien 2018bfc788c2SDavid E. O'Brien 20192c3adf61SDavid E. O'Brien static void 20202c3adf61SDavid E. O'Brien nfe_shutdown(device_t dev) 2021bfc788c2SDavid E. O'Brien { 2022bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2023bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2024bfc788c2SDavid E. O'Brien 2025bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 2026bfc788c2SDavid E. O'Brien 2027bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2028bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2029bfc788c2SDavid E. O'Brien nfe_stop(ifp,0); 2030bfc788c2SDavid E. O'Brien /* nfe_reset(sc); */ 2031bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2032bfc788c2SDavid E. O'Brien 2033bfc788c2SDavid E. O'Brien return; 2034bfc788c2SDavid E. O'Brien } 2035bfc788c2SDavid E. O'Brien 2036bfc788c2SDavid E. O'Brien 20372c3adf61SDavid E. O'Brien static void 20382c3adf61SDavid E. O'Brien nfe_get_macaddr(struct nfe_softc *sc, u_char *addr) 2039257c5577SDavid E. O'Brien { 2040257c5577SDavid E. O'Brien uint32_t tmp; 2041257c5577SDavid E. O'Brien 2042257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_LO); 2043257c5577SDavid E. O'Brien addr[0] = (tmp >> 8) & 0xff; 2044257c5577SDavid E. O'Brien addr[1] = (tmp & 0xff); 2045257c5577SDavid E. O'Brien 2046257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_HI); 2047257c5577SDavid E. O'Brien addr[2] = (tmp >> 24) & 0xff; 2048257c5577SDavid E. O'Brien addr[3] = (tmp >> 16) & 0xff; 2049257c5577SDavid E. O'Brien addr[4] = (tmp >> 8) & 0xff; 2050257c5577SDavid E. O'Brien addr[5] = (tmp & 0xff); 2051257c5577SDavid E. O'Brien } 2052257c5577SDavid E. O'Brien 20532c3adf61SDavid E. O'Brien 20542c3adf61SDavid E. O'Brien static void 20552c3adf61SDavid E. O'Brien nfe_set_macaddr(struct nfe_softc *sc, u_char *addr) 2056257c5577SDavid E. O'Brien { 2057bfc788c2SDavid E. O'Brien 2058bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 2059bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 2060bfc788c2SDavid E. O'Brien addr[1] << 8 | addr[0]); 2061257c5577SDavid E. O'Brien } 2062257c5577SDavid E. O'Brien 20632c3adf61SDavid E. O'Brien 2064bfc788c2SDavid E. O'Brien /* 2065bfc788c2SDavid E. O'Brien * Map a single buffer address. 2066bfc788c2SDavid E. O'Brien */ 2067bfc788c2SDavid E. O'Brien 2068bfc788c2SDavid E. O'Brien static void 2069bfc788c2SDavid E. O'Brien nfe_dma_map_segs(arg, segs, nseg, error) 2070bfc788c2SDavid E. O'Brien void *arg; 2071bfc788c2SDavid E. O'Brien bus_dma_segment_t *segs; 2072bfc788c2SDavid E. O'Brien int error, nseg; 2073257c5577SDavid E. O'Brien { 2074257c5577SDavid E. O'Brien 2075bfc788c2SDavid E. O'Brien if (error) 2076bfc788c2SDavid E. O'Brien return; 2077257c5577SDavid E. O'Brien 2078bfc788c2SDavid E. O'Brien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2079bfc788c2SDavid E. O'Brien 2080bfc788c2SDavid E. O'Brien *(bus_dma_segment_t *)arg = *segs; 2081bfc788c2SDavid E. O'Brien 2082bfc788c2SDavid E. O'Brien return; 2083257c5577SDavid E. O'Brien } 2084