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 29bfc788c2SDavid E. O'Brien #define NFE_NO_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 struct nfe_jbuf *nfe_jalloc(struct nfe_softc *); 97bfc788c2SDavid E. O'Brien static void nfe_jfree(void *, void *); 98bfc788c2SDavid E. O'Brien static int nfe_jpool_alloc(struct nfe_softc *); 99bfc788c2SDavid E. O'Brien static void nfe_jpool_free(struct nfe_softc *); 100bfc788c2SDavid E. O'Brien static void nfe_setmulti(struct nfe_softc *); 101bfc788c2SDavid E. O'Brien static void nfe_start(struct ifnet *); 102bfc788c2SDavid E. O'Brien static void nfe_start_locked(struct ifnet *); 103bfc788c2SDavid E. O'Brien static void nfe_watchdog(struct ifnet *); 104bfc788c2SDavid E. O'Brien static void nfe_init(void *); 105bfc788c2SDavid E. O'Brien static void nfe_init_locked(void *); 106bfc788c2SDavid E. O'Brien static void nfe_stop(struct ifnet *, int); 107bfc788c2SDavid E. O'Brien static int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 108bfc788c2SDavid E. O'Brien static void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 109bfc788c2SDavid E. O'Brien static void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 110bfc788c2SDavid E. O'Brien static int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 111bfc788c2SDavid E. O'Brien static void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 112bfc788c2SDavid E. O'Brien static void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 113bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd(struct ifnet *); 114bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd_locked(struct ifnet *); 115bfc788c2SDavid E. O'Brien static void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 116bfc788c2SDavid E. O'Brien static void nfe_tick(void *); 117bfc788c2SDavid E. O'Brien static void nfe_tick_locked(struct nfe_softc *); 118bfc788c2SDavid E. O'Brien static void nfe_get_macaddr(struct nfe_softc *, u_char *); 119bfc788c2SDavid E. O'Brien static void nfe_set_macaddr(struct nfe_softc *, u_char *); 120bfc788c2SDavid E. O'Brien static void nfe_dma_map_segs (void *, bus_dma_segment_t *, int, int); 121bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 122bfc788c2SDavid E. O'Brien static void nfe_poll_locked(struct ifnet *, enum poll_cmd, int); 123bfc788c2SDavid E. O'Brien #endif 124257c5577SDavid E. O'Brien 125257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 126257c5577SDavid E. O'Brien int nfedebug = 0; 127257c5577SDavid E. O'Brien #define DPRINTF(x) do { if (nfedebug) printf x; } while (0) 128257c5577SDavid E. O'Brien #define DPRINTFN(n,x) do { if (nfedebug >= (n)) printf x; } while (0) 129257c5577SDavid E. O'Brien #else 130257c5577SDavid E. O'Brien #define DPRINTF(x) 131257c5577SDavid E. O'Brien #define DPRINTFN(n,x) 132257c5577SDavid E. O'Brien #endif 133257c5577SDavid E. O'Brien 134bfc788c2SDavid E. O'Brien #define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 135bfc788c2SDavid E. O'Brien #define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 136bfc788c2SDavid E. O'Brien #define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 137bfc788c2SDavid E. O'Brien 138bfc788c2SDavid E. O'Brien #define letoh16(x) le16toh(x) 139bfc788c2SDavid E. O'Brien 140bfc788c2SDavid E. O'Brien #define NV_RID 0x10 141bfc788c2SDavid E. O'Brien 142bfc788c2SDavid E. O'Brien static device_method_t nfe_methods[] = { 143bfc788c2SDavid E. O'Brien /* Device interface */ 144bfc788c2SDavid E. O'Brien DEVMETHOD(device_probe, nfe_probe), 145bfc788c2SDavid E. O'Brien DEVMETHOD(device_attach, nfe_attach), 146bfc788c2SDavid E. O'Brien DEVMETHOD(device_detach, nfe_detach), 147bfc788c2SDavid E. O'Brien DEVMETHOD(device_shutdown, nfe_shutdown), 148bfc788c2SDavid E. O'Brien 149bfc788c2SDavid E. O'Brien /* bus interface */ 150bfc788c2SDavid E. O'Brien DEVMETHOD(bus_print_child, bus_generic_print_child), 151bfc788c2SDavid E. O'Brien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 152bfc788c2SDavid E. O'Brien 153bfc788c2SDavid E. O'Brien /* MII interface */ 154bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 155bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 156bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 157bfc788c2SDavid E. O'Brien 158bfc788c2SDavid E. O'Brien { 0, 0 } 159257c5577SDavid E. O'Brien }; 160257c5577SDavid E. O'Brien 161bfc788c2SDavid E. O'Brien static driver_t nfe_driver = { 162bfc788c2SDavid E. O'Brien "nfe", 163bfc788c2SDavid E. O'Brien nfe_methods, 164bfc788c2SDavid E. O'Brien sizeof(struct nfe_softc) 165bfc788c2SDavid E. O'Brien }; 166bfc788c2SDavid E. O'Brien 167bfc788c2SDavid E. O'Brien static devclass_t nfe_devclass; 168bfc788c2SDavid E. O'Brien 169bfc788c2SDavid E. O'Brien DRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 170bfc788c2SDavid E. O'Brien DRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 171bfc788c2SDavid E. O'Brien 172bfc788c2SDavid E. O'Brien static struct nfe_type nfe_devs[] = { 173bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 1746bec3967SDavid E. O'Brien "NVIDIA nForce MCP Networking Adapter"}, 175bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 1766bec3967SDavid E. O'Brien "NVIDIA nForce2 MCP2 Networking Adapter"}, 177bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 1786bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 179bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 1806bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 1816bec3967SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 1826bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP3 Networking Adapter"}, 183bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 1846bec3967SDavid E. O'Brien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 185bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 1866bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP7 Networking Adapter"}, 187bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 1886bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 189bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 1906bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 191bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 1926bec3967SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, // MCP10 193bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 1946bec3967SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, // MCP11 195bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 1966bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 197bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 1986bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 199bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 200bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 201bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 202bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 2033e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 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_MCP61_LAN3, 2083e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2093e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2103e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2113e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 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"}, 2153e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 2163e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2173e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2183e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 219bfc788c2SDavid E. O'Brien {0, 0, NULL} 220bfc788c2SDavid E. O'Brien }; 221bfc788c2SDavid E. O'Brien 222bfc788c2SDavid E. O'Brien 223bfc788c2SDavid E. O'Brien /* Probe for supported hardware ID's */ 224bfc788c2SDavid E. O'Brien static int 225bfc788c2SDavid E. O'Brien nfe_probe(device_t dev) 226257c5577SDavid E. O'Brien { 227bfc788c2SDavid E. O'Brien struct nfe_type *t; 228bfc788c2SDavid E. O'Brien 229bfc788c2SDavid E. O'Brien t = nfe_devs; 230bfc788c2SDavid E. O'Brien /* Check for matching PCI DEVICE ID's */ 231bfc788c2SDavid E. O'Brien while (t->name != NULL) { 232bfc788c2SDavid E. O'Brien if ((pci_get_vendor(dev) == t->vid_id) && 233bfc788c2SDavid E. O'Brien (pci_get_device(dev) == t->dev_id)) { 234bfc788c2SDavid E. O'Brien device_set_desc(dev, t->name); 235bfc788c2SDavid E. O'Brien return (0); 236bfc788c2SDavid E. O'Brien } 237bfc788c2SDavid E. O'Brien t++; 238257c5577SDavid E. O'Brien } 239257c5577SDavid E. O'Brien 240bfc788c2SDavid E. O'Brien return (ENXIO); 241bfc788c2SDavid E. O'Brien } 242bfc788c2SDavid E. O'Brien 2432c3adf61SDavid E. O'Brien 244bfc788c2SDavid E. O'Brien static int 245bfc788c2SDavid E. O'Brien nfe_attach(device_t dev) 246257c5577SDavid E. O'Brien { 247bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 248257c5577SDavid E. O'Brien struct ifnet *ifp; 249bfc788c2SDavid E. O'Brien int unit, error = 0, rid; 250257c5577SDavid E. O'Brien 251bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 252bfc788c2SDavid E. O'Brien unit = device_get_unit(dev); 253bfc788c2SDavid E. O'Brien sc->nfe_dev = dev; 254bfc788c2SDavid E. O'Brien sc->nfe_unit = unit; 255bfc788c2SDavid E. O'Brien 256bfc788c2SDavid E. O'Brien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 257bfc788c2SDavid E. O'Brien MTX_DEF | MTX_RECURSE); 258bfc788c2SDavid E. O'Brien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 259bfc788c2SDavid E. O'Brien 260bfc788c2SDavid E. O'Brien pci_enable_busmaster(dev); 261bfc788c2SDavid E. O'Brien 262bfc788c2SDavid E. O'Brien rid = NV_RID; 263bfc788c2SDavid E. O'Brien sc->nfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 264bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_ACTIVE); 265bfc788c2SDavid E. O'Brien 266bfc788c2SDavid E. O'Brien if (sc->nfe_res == NULL) { 267bfc788c2SDavid E. O'Brien printf ("nfe%d: couldn't map ports/memory\n", unit); 268bfc788c2SDavid E. O'Brien error = ENXIO; 269bfc788c2SDavid E. O'Brien goto fail; 270257c5577SDavid E. O'Brien } 271257c5577SDavid E. O'Brien 272bfc788c2SDavid E. O'Brien sc->nfe_memt = rman_get_bustag(sc->nfe_res); 273bfc788c2SDavid E. O'Brien sc->nfe_memh = rman_get_bushandle(sc->nfe_res); 274bfc788c2SDavid E. O'Brien 275bfc788c2SDavid E. O'Brien /* Allocate interrupt */ 276bfc788c2SDavid E. O'Brien rid = 0; 277bfc788c2SDavid E. O'Brien sc->nfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 278bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 279bfc788c2SDavid E. O'Brien 280bfc788c2SDavid E. O'Brien if (sc->nfe_irq == NULL) { 281bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't map interrupt\n", unit); 282bfc788c2SDavid E. O'Brien error = ENXIO; 283bfc788c2SDavid E. O'Brien goto fail; 284257c5577SDavid E. O'Brien } 285257c5577SDavid E. O'Brien 286bfc788c2SDavid E. O'Brien nfe_get_macaddr(sc, sc->eaddr); 287257c5577SDavid E. O'Brien 288bfc788c2SDavid E. O'Brien sc->nfe_flags = 0; 289257c5577SDavid E. O'Brien 290bfc788c2SDavid E. O'Brien switch (pci_get_device(dev)) { 291257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 292257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 293257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 294257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 295bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 296257c5577SDavid E. O'Brien break; 297257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 298257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 299bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 300257c5577SDavid E. O'Brien break; 301257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 302257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 303257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 304257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 305bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 306257c5577SDavid E. O'Brien break; 307257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 308257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 3092c3adf61SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 3102c3adf61SDavid E. O'Brien NFE_HW_VLAN; 311257c5577SDavid E. O'Brien break; 3123e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 3133e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 3143e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 3153e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 3163e232000SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 3173e232000SDavid E. O'Brien break; 3183e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 3193e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 3203e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 3213e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 3223e232000SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 3233e232000SDavid E. O'Brien break; 324257c5577SDavid E. O'Brien } 325257c5577SDavid E. O'Brien 326257c5577SDavid E. O'Brien #ifndef NFE_NO_JUMBO 327257c5577SDavid E. O'Brien /* enable jumbo frames for adapters that support it */ 328bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 329bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_USE_JUMBO; 330257c5577SDavid E. O'Brien #endif 331257c5577SDavid E. O'Brien 332257c5577SDavid E. O'Brien /* 333bfc788c2SDavid E. O'Brien * Allocate the parent bus DMA tag appropriate for PCI. 334bfc788c2SDavid E. O'Brien */ 335bfc788c2SDavid E. O'Brien #define NFE_NSEG_NEW 32 336bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(NULL, /* parent */ 337bfc788c2SDavid E. O'Brien 1, 0, /* alignment, boundary */ 338bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 339bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 340bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 341bfc788c2SDavid E. O'Brien MAXBSIZE, NFE_NSEG_NEW, /* maxsize, nsegments */ 342bfc788c2SDavid E. O'Brien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 343bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 344bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 345bfc788c2SDavid E. O'Brien &sc->nfe_parent_tag); 346bfc788c2SDavid E. O'Brien if (error) 347bfc788c2SDavid E. O'Brien goto fail; 348bfc788c2SDavid E. O'Brien 349bfc788c2SDavid E. O'Brien /* 350257c5577SDavid E. O'Brien * Allocate Tx and Rx rings. 351257c5577SDavid E. O'Brien */ 352257c5577SDavid E. O'Brien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 353bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Tx ring\n", unit); 354bfc788c2SDavid E. O'Brien error = ENXIO; 355bfc788c2SDavid E. O'Brien goto fail; 356257c5577SDavid E. O'Brien } 357257c5577SDavid E. O'Brien 358257c5577SDavid E. O'Brien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 359bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Rx ring\n", unit); 360257c5577SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 361bfc788c2SDavid E. O'Brien error = ENXIO; 362bfc788c2SDavid E. O'Brien goto fail; 363257c5577SDavid E. O'Brien } 364257c5577SDavid E. O'Brien 365bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 366bfc788c2SDavid E. O'Brien if (ifp == NULL) { 367bfc788c2SDavid E. O'Brien printf("nfe%d: can not if_alloc()\n", unit); 368bfc788c2SDavid E. O'Brien error = ENOSPC; 369bfc788c2SDavid E. O'Brien goto fail; 370bfc788c2SDavid E. O'Brien } 371bfc788c2SDavid E. O'Brien 372257c5577SDavid E. O'Brien ifp->if_softc = sc; 373bfc788c2SDavid E. O'Brien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 374bfc788c2SDavid E. O'Brien ifp->if_mtu = ETHERMTU; 375257c5577SDavid E. O'Brien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 376257c5577SDavid E. O'Brien ifp->if_ioctl = nfe_ioctl; 377257c5577SDavid E. O'Brien ifp->if_start = nfe_start; 378bfc788c2SDavid E. O'Brien /* ifp->if_hwassist = NFE_CSUM_FEATURES; */ 379257c5577SDavid E. O'Brien ifp->if_watchdog = nfe_watchdog; 380257c5577SDavid E. O'Brien ifp->if_init = nfe_init; 381257c5577SDavid E. O'Brien ifp->if_baudrate = IF_Gbps(1); 382bfc788c2SDavid E. O'Brien ifp->if_snd.ifq_maxlen = NFE_IFQ_MAXLEN; 383257c5577SDavid E. O'Brien 384257c5577SDavid E. O'Brien ifp->if_capabilities = IFCAP_VLAN_MTU; 385257c5577SDavid E. O'Brien #if NVLAN > 0 386bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 387257c5577SDavid E. O'Brien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 388257c5577SDavid E. O'Brien #endif 389257c5577SDavid E. O'Brien #ifdef NFE_CSUM 390bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) { 391bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_HWCSUM; 392257c5577SDavid E. O'Brien } 393257c5577SDavid E. O'Brien #endif 394bfc788c2SDavid E. O'Brien ifp->if_capenable = ifp->if_capabilities; 395257c5577SDavid E. O'Brien 396bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 397bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_POLLING; 398bfc788c2SDavid E. O'Brien #endif 399257c5577SDavid E. O'Brien 400bfc788c2SDavid E. O'Brien /* Do MII setup */ 4012c3adf61SDavid E. O'Brien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, 4022c3adf61SDavid E. O'Brien nfe_ifmedia_sts)) { 403bfc788c2SDavid E. O'Brien printf("nfe%d: MII without any phy!\n", unit); 404bfc788c2SDavid E. O'Brien error = ENXIO; 405bfc788c2SDavid E. O'Brien goto fail; 406257c5577SDavid E. O'Brien } 407257c5577SDavid E. O'Brien 408bfc788c2SDavid E. O'Brien ether_ifattach(ifp, sc->eaddr); 409bfc788c2SDavid E. O'Brien 410bfc788c2SDavid E. O'Brien error = bus_setup_intr(dev, sc->nfe_irq, INTR_TYPE_NET | INTR_MPSAFE, 411bfc788c2SDavid E. O'Brien nfe_intr, sc, &sc->nfe_intrhand); 412bfc788c2SDavid E. O'Brien 413bfc788c2SDavid E. O'Brien if (error) { 414bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't set up irq\n", unit); 415bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 416bfc788c2SDavid E. O'Brien goto fail; 417bfc788c2SDavid E. O'Brien } 418bfc788c2SDavid E. O'Brien 419bfc788c2SDavid E. O'Brien fail: 420bfc788c2SDavid E. O'Brien if (error) 421bfc788c2SDavid E. O'Brien nfe_detach(dev); 422bfc788c2SDavid E. O'Brien 423bfc788c2SDavid E. O'Brien return (error); 424bfc788c2SDavid E. O'Brien } 425bfc788c2SDavid E. O'Brien 426bfc788c2SDavid E. O'Brien 427bfc788c2SDavid E. O'Brien static int 428bfc788c2SDavid E. O'Brien nfe_detach(device_t dev) 429257c5577SDavid E. O'Brien { 430bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 431257c5577SDavid E. O'Brien struct ifnet *ifp; 432bfc788c2SDavid E. O'Brien u_char eaddr[ETHER_ADDR_LEN]; 433bfc788c2SDavid E. O'Brien int i; 434257c5577SDavid E. O'Brien 435bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 436bfc788c2SDavid E. O'Brien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 437bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 438bfc788c2SDavid E. O'Brien 439bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 440bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 441bfc788c2SDavid E. O'Brien ether_poll_deregister(ifp); 442bfc788c2SDavid E. O'Brien #endif 443bfc788c2SDavid E. O'Brien 444bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 445bfc788c2SDavid E. O'Brien eaddr[i] = sc->eaddr[5 - i]; 446257c5577SDavid E. O'Brien } 447bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, eaddr); 448bfc788c2SDavid E. O'Brien 449bfc788c2SDavid E. O'Brien if (device_is_attached(dev)) { 45096058696SDavid E. O'Brien NFE_LOCK(sc); 451bfc788c2SDavid E. O'Brien nfe_stop(ifp, 1); 452bfc788c2SDavid E. O'Brien ifp->if_flags &= ~IFF_UP; 45396058696SDavid E. O'Brien NFE_UNLOCK(sc); 454bfc788c2SDavid E. O'Brien callout_drain(&sc->nfe_stat_ch); 455bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 456257c5577SDavid E. O'Brien } 457257c5577SDavid E. O'Brien 458bfc788c2SDavid E. O'Brien if (ifp) 459bfc788c2SDavid E. O'Brien if_free(ifp); 460bfc788c2SDavid E. O'Brien if (sc->nfe_miibus) 461bfc788c2SDavid E. O'Brien device_delete_child(dev, sc->nfe_miibus); 462bfc788c2SDavid E. O'Brien bus_generic_detach(dev); 463bfc788c2SDavid E. O'Brien 464bfc788c2SDavid E. O'Brien if (sc->nfe_intrhand) 465bfc788c2SDavid E. O'Brien bus_teardown_intr(dev, sc->nfe_irq, sc->nfe_intrhand); 466bfc788c2SDavid E. O'Brien if (sc->nfe_irq) 467bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nfe_irq); 468bfc788c2SDavid E. O'Brien if (sc->nfe_res) 469bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_MEMORY, NV_RID, sc->nfe_res); 470bfc788c2SDavid E. O'Brien 471bfc788c2SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 472bfc788c2SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 473bfc788c2SDavid E. O'Brien 474bfc788c2SDavid E. O'Brien if (sc->nfe_parent_tag) 475bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(sc->nfe_parent_tag); 476bfc788c2SDavid E. O'Brien 477bfc788c2SDavid E. O'Brien mtx_destroy(&sc->nfe_mtx); 478bfc788c2SDavid E. O'Brien 479bfc788c2SDavid E. O'Brien return (0); 480bfc788c2SDavid E. O'Brien } 481bfc788c2SDavid E. O'Brien 482bfc788c2SDavid E. O'Brien 483bfc788c2SDavid E. O'Brien static void 484bfc788c2SDavid E. O'Brien nfe_miibus_statchg(device_t dev) 485257c5577SDavid E. O'Brien { 486bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 487bfc788c2SDavid E. O'Brien struct mii_data *mii; 488bfc788c2SDavid E. O'Brien u_int32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 489bfc788c2SDavid E. O'Brien 490bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 491bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 492257c5577SDavid E. O'Brien 493257c5577SDavid E. O'Brien phy = NFE_READ(sc, NFE_PHY_IFACE); 494257c5577SDavid E. O'Brien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 495257c5577SDavid E. O'Brien 496257c5577SDavid E. O'Brien seed = NFE_READ(sc, NFE_RNDSEED); 497257c5577SDavid E. O'Brien seed &= ~NFE_SEED_MASK; 498257c5577SDavid E. O'Brien 499257c5577SDavid E. O'Brien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 500257c5577SDavid E. O'Brien phy |= NFE_PHY_HDX; /* half-duplex */ 501257c5577SDavid E. O'Brien misc |= NFE_MISC1_HDX; 502257c5577SDavid E. O'Brien } 503257c5577SDavid E. O'Brien 504257c5577SDavid E. O'Brien switch (IFM_SUBTYPE(mii->mii_media_active)) { 505257c5577SDavid E. O'Brien case IFM_1000_T: /* full-duplex only */ 506257c5577SDavid E. O'Brien link |= NFE_MEDIA_1000T; 507257c5577SDavid E. O'Brien seed |= NFE_SEED_1000T; 508257c5577SDavid E. O'Brien phy |= NFE_PHY_1000T; 509257c5577SDavid E. O'Brien break; 510257c5577SDavid E. O'Brien case IFM_100_TX: 511257c5577SDavid E. O'Brien link |= NFE_MEDIA_100TX; 512257c5577SDavid E. O'Brien seed |= NFE_SEED_100TX; 513257c5577SDavid E. O'Brien phy |= NFE_PHY_100TX; 514257c5577SDavid E. O'Brien break; 515257c5577SDavid E. O'Brien case IFM_10_T: 516257c5577SDavid E. O'Brien link |= NFE_MEDIA_10T; 517257c5577SDavid E. O'Brien seed |= NFE_SEED_10T; 518257c5577SDavid E. O'Brien break; 519257c5577SDavid E. O'Brien } 520257c5577SDavid E. O'Brien 521257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 522257c5577SDavid E. O'Brien 523257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 524257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MISC1, misc); 525257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_LINKSPEED, link); 526257c5577SDavid E. O'Brien } 527257c5577SDavid E. O'Brien 5282c3adf61SDavid E. O'Brien 529bfc788c2SDavid E. O'Brien static int 530bfc788c2SDavid E. O'Brien nfe_miibus_readreg(device_t dev, int phy, int reg) 531257c5577SDavid E. O'Brien { 532bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 533bfc788c2SDavid E. O'Brien u_int32_t val; 534257c5577SDavid E. O'Brien int ntries; 535257c5577SDavid E. O'Brien 536257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 537257c5577SDavid E. O'Brien 538257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 539257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 540257c5577SDavid E. O'Brien DELAY(100); 541257c5577SDavid E. O'Brien } 542257c5577SDavid E. O'Brien 543257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 544257c5577SDavid E. O'Brien 545257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 546257c5577SDavid E. O'Brien DELAY(100); 547257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 548257c5577SDavid E. O'Brien break; 549257c5577SDavid E. O'Brien } 550257c5577SDavid E. O'Brien if (ntries == 1000) { 551bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: timeout waiting for PHY\n", sc->nfe_unit)); 552257c5577SDavid E. O'Brien return 0; 553257c5577SDavid E. O'Brien } 554257c5577SDavid E. O'Brien 555257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 556bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: could not read PHY\n", sc->nfe_unit)); 557257c5577SDavid E. O'Brien return 0; 558257c5577SDavid E. O'Brien } 559257c5577SDavid E. O'Brien 560257c5577SDavid E. O'Brien val = NFE_READ(sc, NFE_PHY_DATA); 561257c5577SDavid E. O'Brien if (val != 0xffffffff && val != 0) 562257c5577SDavid E. O'Brien sc->mii_phyaddr = phy; 563257c5577SDavid E. O'Brien 5642c3adf61SDavid E. O'Brien DPRINTFN(2, ("nfe%d: mii read phy %d reg 0x%x ret 0x%x\n", 5652c3adf61SDavid E. O'Brien sc->nfe_unit, phy, reg, val)); 566257c5577SDavid E. O'Brien 567257c5577SDavid E. O'Brien return val; 568257c5577SDavid E. O'Brien } 569257c5577SDavid E. O'Brien 5702c3adf61SDavid E. O'Brien 571bfc788c2SDavid E. O'Brien static int 572bfc788c2SDavid E. O'Brien nfe_miibus_writereg(device_t dev, int phy, int reg, int val) 573257c5577SDavid E. O'Brien { 574bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 575bfc788c2SDavid E. O'Brien u_int32_t ctl; 576257c5577SDavid E. O'Brien int ntries; 577257c5577SDavid E. O'Brien 578257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 579257c5577SDavid E. O'Brien 580257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 581257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 582257c5577SDavid E. O'Brien DELAY(100); 583257c5577SDavid E. O'Brien } 584257c5577SDavid E. O'Brien 585257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_DATA, val); 586257c5577SDavid E. O'Brien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 587257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 588257c5577SDavid E. O'Brien 589257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 590257c5577SDavid E. O'Brien DELAY(100); 591257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 592257c5577SDavid E. O'Brien break; 593257c5577SDavid E. O'Brien } 594257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 595257c5577SDavid E. O'Brien if (nfedebug >= 2 && ntries == 1000) 596257c5577SDavid E. O'Brien printf("could not write to PHY\n"); 597257c5577SDavid E. O'Brien #endif 598bfc788c2SDavid E. O'Brien return 0; 599257c5577SDavid E. O'Brien } 600257c5577SDavid E. O'Brien 6012c3adf61SDavid E. O'Brien 602bfc788c2SDavid E. O'Brien static int 603bfc788c2SDavid E. O'Brien nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 604bfc788c2SDavid E. O'Brien { 605bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32; 606bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64; 607bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 608bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 609bfc788c2SDavid E. O'Brien void **desc; 610bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 611bfc788c2SDavid E. O'Brien int i, error, descsize; 612bfc788c2SDavid E. O'Brien 613bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 614bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 615bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 616bfc788c2SDavid E. O'Brien } else { 617bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 618bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 619bfc788c2SDavid E. O'Brien } 620bfc788c2SDavid E. O'Brien 621bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 622bfc788c2SDavid E. O'Brien ring->bufsz = MCLBYTES; 623bfc788c2SDavid E. O'Brien 624bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 625bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 626bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 627bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 628bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 629bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 630bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 631bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 632bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 633bfc788c2SDavid E. O'Brien &ring->rx_desc_tag); 634bfc788c2SDavid E. O'Brien if (error != 0) { 635bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 636bfc788c2SDavid E. O'Brien goto fail; 637bfc788c2SDavid E. O'Brien } 638bfc788c2SDavid E. O'Brien 639bfc788c2SDavid E. O'Brien /* allocate memory to desc */ 6402c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_desc_tag, (void **)desc, 6412c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->rx_desc_map); 642bfc788c2SDavid E. O'Brien if (error != 0) { 643bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 644bfc788c2SDavid E. O'Brien goto fail; 645bfc788c2SDavid E. O'Brien } 646bfc788c2SDavid E. O'Brien 647bfc788c2SDavid E. O'Brien /* map desc to device visible address space */ 648bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, *desc, 6492c3adf61SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, 6502c3adf61SDavid E. O'Brien &ring->rx_desc_segs, BUS_DMA_NOWAIT); 651bfc788c2SDavid E. O'Brien if (error != 0) { 652bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 653bfc788c2SDavid E. O'Brien goto fail; 654bfc788c2SDavid E. O'Brien } 655bfc788c2SDavid E. O'Brien 656bfc788c2SDavid E. O'Brien bzero(*desc, NFE_RX_RING_COUNT * descsize); 657bfc788c2SDavid E. O'Brien ring->rx_desc_addr = ring->rx_desc_segs.ds_addr; 658bfc788c2SDavid E. O'Brien ring->physaddr = ring->rx_desc_addr; 659bfc788c2SDavid E. O'Brien 660bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 661bfc788c2SDavid E. O'Brien ring->bufsz = NFE_JBYTES; 662bfc788c2SDavid E. O'Brien if ((error = nfe_jpool_alloc(sc)) != 0) { 6632c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate jumbo frames\n", 6642c3adf61SDavid E. O'Brien sc->nfe_unit); 665bfc788c2SDavid E. O'Brien goto fail; 666bfc788c2SDavid E. O'Brien } 667bfc788c2SDavid E. O'Brien } 668bfc788c2SDavid E. O'Brien 669bfc788c2SDavid E. O'Brien /* 670bfc788c2SDavid E. O'Brien * Pre-allocate Rx buffers and populate Rx ring. 671bfc788c2SDavid E. O'Brien */ 672bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 673bfc788c2SDavid E. O'Brien data = &sc->rxq.data[i]; 674bfc788c2SDavid E. O'Brien 675bfc788c2SDavid E. O'Brien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 676bfc788c2SDavid E. O'Brien if (data->m == NULL) { 6772c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate rx mbuf\n", 6782c3adf61SDavid E. O'Brien sc->nfe_unit); 679bfc788c2SDavid E. O'Brien error = ENOMEM; 680bfc788c2SDavid E. O'Brien goto fail; 681bfc788c2SDavid E. O'Brien } 682bfc788c2SDavid E. O'Brien 683bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 684bfc788c2SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 6852c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate jumbo buffer\n", 6862c3adf61SDavid E. O'Brien sc->nfe_unit); 687bfc788c2SDavid E. O'Brien goto fail; 688bfc788c2SDavid E. O'Brien } 689bfc788c2SDavid E. O'Brien data->m->m_data = (void *)jbuf->buf; 690bfc788c2SDavid E. O'Brien data->m->m_len = data->m->m_pkthdr.len = NFE_JBYTES; 6912c3adf61SDavid E. O'Brien MEXTADD(data->m, jbuf->buf, NFE_JBYTES, nfe_jfree, 6922c3adf61SDavid E. O'Brien (struct nfe_softc *)sc, 0, EXT_NET_DRV); 693bfc788c2SDavid E. O'Brien /* m_adj(data->m, ETHER_ALIGN); */ 694bfc788c2SDavid E. O'Brien physaddr = jbuf->physaddr; 695bfc788c2SDavid E. O'Brien } else { 696bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 697d0220c83SRuslan Ermilov ETHER_ALIGN, 0, /* alignment, boundary */ 698bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 699bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 700bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 701bfc788c2SDavid E. O'Brien MCLBYTES, 1, /* maxsize, nsegments */ 702bfc788c2SDavid E. O'Brien MCLBYTES, /* maxsegsize */ 703bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 704bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 705bfc788c2SDavid E. O'Brien &data->rx_data_tag); 706bfc788c2SDavid E. O'Brien if (error != 0) { 7072c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 7082c3adf61SDavid E. O'Brien sc->nfe_unit); 709bfc788c2SDavid E. O'Brien goto fail; 710bfc788c2SDavid E. O'Brien } 711bfc788c2SDavid E. O'Brien 7122c3adf61SDavid E. O'Brien error = bus_dmamap_create(data->rx_data_tag, 0, 7132c3adf61SDavid E. O'Brien &data->rx_data_map); 714bfc788c2SDavid E. O'Brien if (error != 0) { 7152c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate mbuf cluster\n", 7162c3adf61SDavid E. O'Brien sc->nfe_unit); 717bfc788c2SDavid E. O'Brien goto fail; 718bfc788c2SDavid E. O'Brien } 719bfc788c2SDavid E. O'Brien 720bfc788c2SDavid E. O'Brien MCLGET(data->m, M_DONTWAIT); 721bfc788c2SDavid E. O'Brien if (!(data->m->m_flags & M_EXT)) { 722bfc788c2SDavid E. O'Brien error = ENOMEM; 723bfc788c2SDavid E. O'Brien goto fail; 724bfc788c2SDavid E. O'Brien } 725bfc788c2SDavid E. O'Brien 7262c3adf61SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 7272c3adf61SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), MCLBYTES, 7282c3adf61SDavid E. O'Brien nfe_dma_map_segs, &data->rx_data_segs, 7292c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 730bfc788c2SDavid E. O'Brien if (error != 0) { 7312c3adf61SDavid E. O'Brien printf("nfe%d: could not load rx buf DMA map\n", 7322c3adf61SDavid E. O'Brien sc->nfe_unit); 733bfc788c2SDavid E. O'Brien goto fail; 734bfc788c2SDavid E. O'Brien } 735bfc788c2SDavid E. O'Brien 736bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 737bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 738bfc788c2SDavid E. O'Brien 739bfc788c2SDavid E. O'Brien } 740bfc788c2SDavid E. O'Brien 741bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 742bfc788c2SDavid E. O'Brien desc64 = &sc->rxq.desc64[i]; 743bfc788c2SDavid E. O'Brien #if defined(__LP64__) 744bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 745bfc788c2SDavid E. O'Brien #endif 746bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 747bfc788c2SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 748bfc788c2SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 749bfc788c2SDavid E. O'Brien } else { 750bfc788c2SDavid E. O'Brien desc32 = &sc->rxq.desc32[i]; 751bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 752bfc788c2SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 753bfc788c2SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 754bfc788c2SDavid E. O'Brien } 755bfc788c2SDavid E. O'Brien 756bfc788c2SDavid E. O'Brien } 757bfc788c2SDavid E. O'Brien 7582c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7592c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 760bfc788c2SDavid E. O'Brien 761bfc788c2SDavid E. O'Brien return 0; 762bfc788c2SDavid E. O'Brien 763bfc788c2SDavid E. O'Brien fail: nfe_free_rx_ring(sc, ring); 764bfc788c2SDavid E. O'Brien 765bfc788c2SDavid E. O'Brien return error; 766bfc788c2SDavid E. O'Brien } 767bfc788c2SDavid E. O'Brien 7682c3adf61SDavid E. O'Brien 769bfc788c2SDavid E. O'Brien static int 770bfc788c2SDavid E. O'Brien nfe_jpool_alloc(struct nfe_softc *sc) 771bfc788c2SDavid E. O'Brien { 772bfc788c2SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 773bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 774bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 775bfc788c2SDavid E. O'Brien caddr_t buf; 776bfc788c2SDavid E. O'Brien int i, error; 777bfc788c2SDavid E. O'Brien 778bfc788c2SDavid E. O'Brien /* 779bfc788c2SDavid E. O'Brien * Allocate a big chunk of DMA'able memory. 780bfc788c2SDavid E. O'Brien */ 781bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 782bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 783bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 784bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 785bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 786bfc788c2SDavid E. O'Brien NFE_JPOOL_SIZE, 1, /* maxsize, nsegments */ 787bfc788c2SDavid E. O'Brien NFE_JPOOL_SIZE, /* maxsegsize */ 788bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 789bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 790bfc788c2SDavid E. O'Brien &ring->rx_jumbo_tag); 791bfc788c2SDavid E. O'Brien if (error != 0) { 792bfc788c2SDavid E. O'Brien printf("nfe%d: could not create jumbo DMA tag\n", sc->nfe_unit); 793bfc788c2SDavid E. O'Brien goto fail; 794bfc788c2SDavid E. O'Brien } 7952c3adf61SDavid E. O'Brien 7962c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_jumbo_tag, (void **)&ring->jpool, 7972c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->rx_jumbo_map); 798bfc788c2SDavid E. O'Brien if (error != 0) { 7992c3adf61SDavid E. O'Brien printf("nfe%d: could not create jumbo DMA memory\n", 8002c3adf61SDavid E. O'Brien sc->nfe_unit); 801bfc788c2SDavid E. O'Brien goto fail; 802bfc788c2SDavid E. O'Brien } 803bfc788c2SDavid E. O'Brien 8042c3adf61SDavid E. O'Brien error = bus_dmamap_load(ring->rx_jumbo_tag, ring->rx_jumbo_map, 8052c3adf61SDavid E. O'Brien ring->jpool, NFE_JPOOL_SIZE, nfe_dma_map_segs, &ring->rx_jumbo_segs, 8062c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 807bfc788c2SDavid E. O'Brien if (error != 0) { 808bfc788c2SDavid E. O'Brien printf("nfe%d: could not load jumbo DMA map\n", sc->nfe_unit); 809bfc788c2SDavid E. O'Brien goto fail; 810bfc788c2SDavid E. O'Brien } 811bfc788c2SDavid E. O'Brien 812bfc788c2SDavid E. O'Brien /* ..and split it into 9KB chunks */ 813bfc788c2SDavid E. O'Brien SLIST_INIT(&ring->jfreelist); 814bfc788c2SDavid E. O'Brien 815bfc788c2SDavid E. O'Brien buf = ring->jpool; 816bfc788c2SDavid E. O'Brien ring->rx_jumbo_addr = ring->rx_jumbo_segs.ds_addr; 817bfc788c2SDavid E. O'Brien physaddr = ring->rx_jumbo_addr; 818bfc788c2SDavid E. O'Brien 819bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_JPOOL_COUNT; i++) { 820bfc788c2SDavid E. O'Brien jbuf = &ring->jbuf[i]; 821bfc788c2SDavid E. O'Brien 822bfc788c2SDavid E. O'Brien jbuf->buf = buf; 823bfc788c2SDavid E. O'Brien jbuf->physaddr = physaddr; 824bfc788c2SDavid E. O'Brien 825bfc788c2SDavid E. O'Brien SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 826bfc788c2SDavid E. O'Brien 827bfc788c2SDavid E. O'Brien buf += NFE_JBYTES; 828bfc788c2SDavid E. O'Brien physaddr += NFE_JBYTES; 829bfc788c2SDavid E. O'Brien } 830bfc788c2SDavid E. O'Brien 831bfc788c2SDavid E. O'Brien return 0; 832bfc788c2SDavid E. O'Brien 833bfc788c2SDavid E. O'Brien fail: nfe_jpool_free(sc); 834bfc788c2SDavid E. O'Brien return error; 835bfc788c2SDavid E. O'Brien } 836bfc788c2SDavid E. O'Brien 837bfc788c2SDavid E. O'Brien 838bfc788c2SDavid E. O'Brien static void 839bfc788c2SDavid E. O'Brien nfe_jpool_free(struct nfe_softc *sc) 840bfc788c2SDavid E. O'Brien { 841bfc788c2SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 842bfc788c2SDavid E. O'Brien 843bfc788c2SDavid E. O'Brien if (ring->jpool != NULL) { 844bfc788c2SDavid E. O'Brien #if 0 8452c3adf61SDavid E. O'Brien bus_dmamem_unmap(ring->rx_jumbo_tag, ring->jpool, 8462c3adf61SDavid E. O'Brien NFE_JPOOL_SIZE); 847bfc788c2SDavid E. O'Brien #endif 8482c3adf61SDavid E. O'Brien bus_dmamem_free(ring->rx_jumbo_tag, &ring->rx_jumbo_segs, 8492c3adf61SDavid E. O'Brien ring->rx_jumbo_map); 850bfc788c2SDavid E. O'Brien } 851bfc788c2SDavid E. O'Brien if (ring->rx_jumbo_map != NULL) { 8522c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_jumbo_tag, ring->rx_jumbo_map, 8532c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 854bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_jumbo_tag, ring->rx_jumbo_map); 855bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->rx_jumbo_tag, ring->rx_jumbo_map); 856bfc788c2SDavid E. O'Brien } 857bfc788c2SDavid E. O'Brien } 858bfc788c2SDavid E. O'Brien 8592c3adf61SDavid E. O'Brien 860bfc788c2SDavid E. O'Brien static struct nfe_jbuf * 861bfc788c2SDavid E. O'Brien nfe_jalloc(struct nfe_softc *sc) 862bfc788c2SDavid E. O'Brien { 863bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 864bfc788c2SDavid E. O'Brien 865bfc788c2SDavid E. O'Brien jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 866bfc788c2SDavid E. O'Brien if (jbuf == NULL) 867bfc788c2SDavid E. O'Brien return NULL; 868bfc788c2SDavid E. O'Brien SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 869bfc788c2SDavid E. O'Brien return jbuf; 870bfc788c2SDavid E. O'Brien } 871bfc788c2SDavid E. O'Brien 8722c3adf61SDavid E. O'Brien 873bfc788c2SDavid E. O'Brien /* 874bfc788c2SDavid E. O'Brien * This is called automatically by the network stack when the mbuf is freed. 875bfc788c2SDavid E. O'Brien * Caution must be taken that the NIC might be reset by the time the mbuf is 876bfc788c2SDavid E. O'Brien * freed. 877bfc788c2SDavid E. O'Brien */ 878bfc788c2SDavid E. O'Brien static void 879bfc788c2SDavid E. O'Brien nfe_jfree(void *buf, void *arg) 880257c5577SDavid E. O'Brien { 881257c5577SDavid E. O'Brien struct nfe_softc *sc = arg; 882bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 883bfc788c2SDavid E. O'Brien int i; 884257c5577SDavid E. O'Brien 885bfc788c2SDavid E. O'Brien /* find the jbuf from the base pointer */ 886bfc788c2SDavid E. O'Brien i = ((vm_offset_t)buf - (vm_offset_t)sc->rxq.jpool) / NFE_JBYTES; 887bfc788c2SDavid E. O'Brien if (i < 0 || i >= NFE_JPOOL_COUNT) { 8882c3adf61SDavid E. O'Brien printf("nfe%d: request to free a buffer (%p) not managed by us\n", 8892c3adf61SDavid E. O'Brien sc->nfe_unit, buf); 890bfc788c2SDavid E. O'Brien return; 891bfc788c2SDavid E. O'Brien } 892bfc788c2SDavid E. O'Brien jbuf = &sc->rxq.jbuf[i]; 893bfc788c2SDavid E. O'Brien 894bfc788c2SDavid E. O'Brien /* ..and put it back in the free list */ 895bfc788c2SDavid E. O'Brien SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext); 896bfc788c2SDavid E. O'Brien } 897bfc788c2SDavid E. O'Brien 898bfc788c2SDavid E. O'Brien 899bfc788c2SDavid E. O'Brien static void 900bfc788c2SDavid E. O'Brien nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 901bfc788c2SDavid E. O'Brien { 902bfc788c2SDavid E. O'Brien int i; 903bfc788c2SDavid E. O'Brien 904bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 905bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 906bfc788c2SDavid E. O'Brien ring->desc64[i].length = htole16(ring->bufsz); 907bfc788c2SDavid E. O'Brien ring->desc64[i].flags = htole16(NFE_RX_READY); 908bfc788c2SDavid E. O'Brien } else { 909bfc788c2SDavid E. O'Brien ring->desc32[i].length = htole16(ring->bufsz); 910bfc788c2SDavid E. O'Brien ring->desc32[i].flags = htole16(NFE_RX_READY); 911bfc788c2SDavid E. O'Brien } 912bfc788c2SDavid E. O'Brien } 913bfc788c2SDavid E. O'Brien 9142c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 9152c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 916bfc788c2SDavid E. O'Brien 917bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 918bfc788c2SDavid E. O'Brien } 919bfc788c2SDavid E. O'Brien 920bfc788c2SDavid E. O'Brien 921bfc788c2SDavid E. O'Brien static void 922bfc788c2SDavid E. O'Brien nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 923bfc788c2SDavid E. O'Brien { 924bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 925bfc788c2SDavid E. O'Brien void *desc; 926bfc788c2SDavid E. O'Brien int i, descsize; 927bfc788c2SDavid E. O'Brien 928bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 929bfc788c2SDavid E. O'Brien desc = ring->desc64; 930bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 931bfc788c2SDavid E. O'Brien } else { 932bfc788c2SDavid E. O'Brien desc = ring->desc32; 933bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 934bfc788c2SDavid E. O'Brien } 935bfc788c2SDavid E. O'Brien 936bfc788c2SDavid E. O'Brien if (desc != NULL) { 9372c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 9382c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 939bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 940bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 941bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->rx_desc_tag); 942bfc788c2SDavid E. O'Brien } 943bfc788c2SDavid E. O'Brien 944bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 945bfc788c2SDavid E. O'Brien nfe_jpool_free(sc); 946bfc788c2SDavid E. O'Brien } else { 947bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 948bfc788c2SDavid E. O'Brien data = &ring->data[i]; 949bfc788c2SDavid E. O'Brien 950bfc788c2SDavid E. O'Brien if (data->rx_data_map != NULL) { 9512c3adf61SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, 9522c3adf61SDavid E. O'Brien data->rx_data_map, BUS_DMASYNC_POSTREAD); 9532c3adf61SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, 9542c3adf61SDavid E. O'Brien data->rx_data_map); 9552c3adf61SDavid E. O'Brien bus_dmamap_destroy(data->rx_data_tag, 9562c3adf61SDavid E. O'Brien data->rx_data_map); 957bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(data->rx_data_tag); 958bfc788c2SDavid E. O'Brien } 9592c3adf61SDavid E. O'Brien 960bfc788c2SDavid E. O'Brien if (data->m != NULL) 961bfc788c2SDavid E. O'Brien m_freem(data->m); 962bfc788c2SDavid E. O'Brien } 963bfc788c2SDavid E. O'Brien } 964bfc788c2SDavid E. O'Brien } 965bfc788c2SDavid E. O'Brien 9662c3adf61SDavid E. O'Brien 967bfc788c2SDavid E. O'Brien static int 968bfc788c2SDavid E. O'Brien nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 969bfc788c2SDavid E. O'Brien { 970bfc788c2SDavid E. O'Brien int i, error; 971bfc788c2SDavid E. O'Brien void **desc; 972bfc788c2SDavid E. O'Brien int descsize; 973bfc788c2SDavid E. O'Brien 974bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 975bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 976bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 977bfc788c2SDavid E. O'Brien } else { 978bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 979bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 980bfc788c2SDavid E. O'Brien } 981bfc788c2SDavid E. O'Brien 982bfc788c2SDavid E. O'Brien ring->queued = 0; 983bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 984bfc788c2SDavid E. O'Brien 985bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 986bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 987bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 988bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 989bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 990bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 991bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 992bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 993bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 994bfc788c2SDavid E. O'Brien &ring->tx_desc_tag); 995bfc788c2SDavid E. O'Brien if (error != 0) { 996bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 997bfc788c2SDavid E. O'Brien goto fail; 998bfc788c2SDavid E. O'Brien } 999bfc788c2SDavid E. O'Brien 10002c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->tx_desc_tag, (void **)desc, 10012c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->tx_desc_map); 1002bfc788c2SDavid E. O'Brien if (error != 0) { 1003bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 1004bfc788c2SDavid E. O'Brien goto fail; 1005bfc788c2SDavid E. O'Brien } 1006bfc788c2SDavid E. O'Brien 1007bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, *desc, 10082c3adf61SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->tx_desc_segs, 10092c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 1010bfc788c2SDavid E. O'Brien if (error != 0) { 1011bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 1012bfc788c2SDavid E. O'Brien goto fail; 1013bfc788c2SDavid E. O'Brien } 1014bfc788c2SDavid E. O'Brien 1015bfc788c2SDavid E. O'Brien bzero(*desc, NFE_TX_RING_COUNT * descsize); 1016bfc788c2SDavid E. O'Brien 1017bfc788c2SDavid E. O'Brien ring->tx_desc_addr = ring->tx_desc_segs.ds_addr; 1018bfc788c2SDavid E. O'Brien ring->physaddr = ring->tx_desc_addr; 1019bfc788c2SDavid E. O'Brien 1020bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 1021bfc788c2SDavid E. O'Brien ETHER_ALIGN, 0, 1022bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, 1023bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, 1024bfc788c2SDavid E. O'Brien NULL, NULL, 1025bfc788c2SDavid E. O'Brien NFE_JBYTES, NFE_MAX_SCATTER, 1026bfc788c2SDavid E. O'Brien NFE_JBYTES, 1027bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, 1028bfc788c2SDavid E. O'Brien NULL, NULL, 1029bfc788c2SDavid E. O'Brien &ring->tx_data_tag); 1030bfc788c2SDavid E. O'Brien if (error != 0) { 1031bfc788c2SDavid E. O'Brien printf("nfe%d: could not create DMA tag\n", sc->nfe_unit); 1032bfc788c2SDavid E. O'Brien goto fail; 1033bfc788c2SDavid E. O'Brien } 1034bfc788c2SDavid E. O'Brien 1035bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 10362c3adf61SDavid E. O'Brien error = bus_dmamap_create(ring->tx_data_tag, 0, 10372c3adf61SDavid E. O'Brien &ring->data[i].tx_data_map); 1038bfc788c2SDavid E. O'Brien if (error != 0) { 10392c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 10402c3adf61SDavid E. O'Brien sc->nfe_unit); 1041bfc788c2SDavid E. O'Brien goto fail; 1042bfc788c2SDavid E. O'Brien } 1043bfc788c2SDavid E. O'Brien } 1044bfc788c2SDavid E. O'Brien 1045bfc788c2SDavid E. O'Brien return 0; 1046bfc788c2SDavid E. O'Brien 1047bfc788c2SDavid E. O'Brien fail: nfe_free_tx_ring(sc, ring); 1048bfc788c2SDavid E. O'Brien return error; 1049bfc788c2SDavid E. O'Brien } 1050bfc788c2SDavid E. O'Brien 1051bfc788c2SDavid E. O'Brien 1052bfc788c2SDavid E. O'Brien static void 1053bfc788c2SDavid E. O'Brien nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1054bfc788c2SDavid E. O'Brien { 1055bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 1056bfc788c2SDavid E. O'Brien int i; 1057bfc788c2SDavid E. O'Brien 1058bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1059bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1060bfc788c2SDavid E. O'Brien ring->desc64[i].flags = 0; 1061bfc788c2SDavid E. O'Brien else 1062bfc788c2SDavid E. O'Brien ring->desc32[i].flags = 0; 1063bfc788c2SDavid E. O'Brien 1064bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1065bfc788c2SDavid E. O'Brien 1066bfc788c2SDavid E. O'Brien if (data->m != NULL) { 10672c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 10682c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1069bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 1070bfc788c2SDavid E. O'Brien m_freem(data->m); 1071bfc788c2SDavid E. O'Brien data->m = NULL; 1072bfc788c2SDavid E. O'Brien } 1073bfc788c2SDavid E. O'Brien } 1074bfc788c2SDavid E. O'Brien 10752c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 10762c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 1077bfc788c2SDavid E. O'Brien 1078bfc788c2SDavid E. O'Brien ring->queued = 0; 1079bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 1080bfc788c2SDavid E. O'Brien } 1081bfc788c2SDavid E. O'Brien 10822c3adf61SDavid E. O'Brien 1083bfc788c2SDavid E. O'Brien static void 1084bfc788c2SDavid E. O'Brien nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1085bfc788c2SDavid E. O'Brien { 1086bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 1087bfc788c2SDavid E. O'Brien void *desc; 1088bfc788c2SDavid E. O'Brien int i, descsize; 1089bfc788c2SDavid E. O'Brien 1090bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1091bfc788c2SDavid E. O'Brien desc = ring->desc64; 1092bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1093bfc788c2SDavid E. O'Brien } else { 1094bfc788c2SDavid E. O'Brien desc = ring->desc32; 1095bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1096bfc788c2SDavid E. O'Brien } 1097bfc788c2SDavid E. O'Brien 1098bfc788c2SDavid E. O'Brien if (desc != NULL) { 10992c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 11002c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1101bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1102bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1103bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_desc_tag); 1104bfc788c2SDavid E. O'Brien } 1105bfc788c2SDavid E. O'Brien 1106bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1107bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1108bfc788c2SDavid E. O'Brien 1109bfc788c2SDavid E. O'Brien if (data->m != NULL) { 11102c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 11112c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1112bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 1113bfc788c2SDavid E. O'Brien m_freem(data->m); 1114bfc788c2SDavid E. O'Brien } 1115bfc788c2SDavid E. O'Brien } 1116bfc788c2SDavid E. O'Brien 1117bfc788c2SDavid E. O'Brien /* ..and now actually destroy the DMA mappings */ 1118bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1119bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1120bfc788c2SDavid E. O'Brien if (data->tx_data_map == NULL) 1121bfc788c2SDavid E. O'Brien continue; 1122bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->tx_data_tag, data->tx_data_map); 1123bfc788c2SDavid E. O'Brien } 1124bfc788c2SDavid E. O'Brien 1125bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_data_tag); 1126bfc788c2SDavid E. O'Brien } 1127bfc788c2SDavid E. O'Brien 1128bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1129bfc788c2SDavid E. O'Brien static poll_handler_t nfe_poll; 1130bfc788c2SDavid E. O'Brien 11312c3adf61SDavid E. O'Brien 1132bfc788c2SDavid E. O'Brien static void 1133bfc788c2SDavid E. O'Brien nfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1134bfc788c2SDavid E. O'Brien { 1135bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1136bfc788c2SDavid E. O'Brien 1137bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1138bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1139bfc788c2SDavid E. O'Brien nfe_poll_locked(ifp, cmd, count); 1140bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1141bfc788c2SDavid E. O'Brien } 1142bfc788c2SDavid E. O'Brien 1143bfc788c2SDavid E. O'Brien 1144bfc788c2SDavid E. O'Brien static void 1145bfc788c2SDavid E. O'Brien nfe_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1146bfc788c2SDavid E. O'Brien { 1147bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1148bfc788c2SDavid E. O'Brien u_int32_t r; 1149bfc788c2SDavid E. O'Brien 1150bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1151bfc788c2SDavid E. O'Brien 1152bfc788c2SDavid E. O'Brien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1153bfc788c2SDavid E. O'Brien return; 1154bfc788c2SDavid E. O'Brien } 1155bfc788c2SDavid E. O'Brien 1156bfc788c2SDavid E. O'Brien sc->rxcycles = count; 1157bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1158bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1159bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1160bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1161bfc788c2SDavid E. O'Brien 1162bfc788c2SDavid E. O'Brien if (cmd == POLL_AND_CHECK_STATUS) { 1163bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1164bfc788c2SDavid E. O'Brien return; 1165bfc788c2SDavid E. O'Brien } 1166257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1167257c5577SDavid E. O'Brien 1168257c5577SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1169257c5577SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1170257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1171bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1172257c5577SDavid E. O'Brien } 1173257c5577SDavid E. O'Brien } 1174257c5577SDavid E. O'Brien } 1175bfc788c2SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1176257c5577SDavid E. O'Brien 1177bfc788c2SDavid E. O'Brien 1178bfc788c2SDavid E. O'Brien static int 1179257c5577SDavid E. O'Brien nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1180257c5577SDavid E. O'Brien { 1181257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1182257c5577SDavid E. O'Brien struct ifreq *ifr = (struct ifreq *) data; 1183bfc788c2SDavid E. O'Brien struct mii_data *mii; 11842c3adf61SDavid E. O'Brien int error = 0; 1185257c5577SDavid E. O'Brien 1186257c5577SDavid E. O'Brien switch (cmd) { 1187257c5577SDavid E. O'Brien case SIOCSIFMTU: 1188257c5577SDavid E. O'Brien if (ifr->ifr_mtu < ETHERMIN || 1189bfc788c2SDavid E. O'Brien ((sc->nfe_flags & NFE_USE_JUMBO) && 1190257c5577SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU_JUMBO) || 1191bfc788c2SDavid E. O'Brien (!(sc->nfe_flags & NFE_USE_JUMBO) && 11922c3adf61SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU)) { 1193257c5577SDavid E. O'Brien error = EINVAL; 11942c3adf61SDavid E. O'Brien } else if (ifp->if_mtu != ifr->ifr_mtu) { 1195257c5577SDavid E. O'Brien ifp->if_mtu = ifr->ifr_mtu; 1196bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1197bfc788c2SDavid E. O'Brien nfe_init(sc); 1198bfc788c2SDavid E. O'Brien } 1199257c5577SDavid E. O'Brien break; 1200257c5577SDavid E. O'Brien case SIOCSIFFLAGS: 1201bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1202257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 1203257c5577SDavid E. O'Brien /* 1204257c5577SDavid E. O'Brien * If only the PROMISC or ALLMULTI flag changes, then 1205257c5577SDavid E. O'Brien * don't do a full re-init of the chip, just update 1206257c5577SDavid E. O'Brien * the Rx filter. 1207257c5577SDavid E. O'Brien */ 1208bfc788c2SDavid E. O'Brien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1209bfc788c2SDavid E. O'Brien ((ifp->if_flags ^ sc->nfe_if_flags) & 1210bfc788c2SDavid E. O'Brien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1211257c5577SDavid E. O'Brien nfe_setmulti(sc); 1212bfc788c2SDavid E. O'Brien else 1213bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1214257c5577SDavid E. O'Brien } else { 1215bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1216257c5577SDavid E. O'Brien nfe_stop(ifp, 1); 1217257c5577SDavid E. O'Brien } 1218bfc788c2SDavid E. O'Brien sc->nfe_if_flags = ifp->if_flags; 1219bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1220bfc788c2SDavid E. O'Brien error = 0; 1221257c5577SDavid E. O'Brien break; 1222257c5577SDavid E. O'Brien case SIOCADDMULTI: 1223257c5577SDavid E. O'Brien case SIOCDELMULTI: 1224bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1225bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1226257c5577SDavid E. O'Brien nfe_setmulti(sc); 1227bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1228257c5577SDavid E. O'Brien error = 0; 1229257c5577SDavid E. O'Brien } 1230257c5577SDavid E. O'Brien break; 1231257c5577SDavid E. O'Brien case SIOCSIFMEDIA: 1232257c5577SDavid E. O'Brien case SIOCGIFMEDIA: 1233bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1234bfc788c2SDavid E. O'Brien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1235257c5577SDavid E. O'Brien break; 1236bfc788c2SDavid E. O'Brien case SIOCSIFCAP: 1237bfc788c2SDavid E. O'Brien { 1238bfc788c2SDavid E. O'Brien int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1239bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1240bfc788c2SDavid E. O'Brien if (mask & IFCAP_POLLING) { 1241bfc788c2SDavid E. O'Brien if (ifr->ifr_reqcap & IFCAP_POLLING) { 1242bfc788c2SDavid E. O'Brien error = ether_poll_register(nfe_poll, ifp); 1243bfc788c2SDavid E. O'Brien if (error) 1244bfc788c2SDavid E. O'Brien return(error); 1245bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1246bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1247bfc788c2SDavid E. O'Brien ifp->if_capenable |= IFCAP_POLLING; 1248bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1249bfc788c2SDavid E. O'Brien } else { 1250bfc788c2SDavid E. O'Brien error = ether_poll_deregister(ifp); 1251bfc788c2SDavid E. O'Brien /* Enable interrupt even in error case */ 1252bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1253bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1254bfc788c2SDavid E. O'Brien ifp->if_capenable &= ~IFCAP_POLLING; 1255bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1256257c5577SDavid E. O'Brien } 1257bfc788c2SDavid E. O'Brien } 12582c3adf61SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1259bfc788c2SDavid E. O'Brien if (mask & IFCAP_HWCSUM) { 1260bfc788c2SDavid E. O'Brien ifp->if_capenable ^= IFCAP_HWCSUM; 1261bfc788c2SDavid E. O'Brien if (IFCAP_HWCSUM & ifp->if_capenable && 1262bfc788c2SDavid E. O'Brien IFCAP_HWCSUM & ifp->if_capabilities) 1263bfc788c2SDavid E. O'Brien ifp->if_hwassist = NFE_CSUM_FEATURES; 1264bfc788c2SDavid E. O'Brien else 1265bfc788c2SDavid E. O'Brien ifp->if_hwassist = 0; 1266bfc788c2SDavid E. O'Brien } 1267bfc788c2SDavid E. O'Brien } 1268bfc788c2SDavid E. O'Brien break; 1269257c5577SDavid E. O'Brien 1270bfc788c2SDavid E. O'Brien default: 1271bfc788c2SDavid E. O'Brien error = ether_ioctl(ifp, cmd, data); 1272bfc788c2SDavid E. O'Brien break; 1273bfc788c2SDavid E. O'Brien } 1274257c5577SDavid E. O'Brien 1275257c5577SDavid E. O'Brien return error; 1276257c5577SDavid E. O'Brien } 1277257c5577SDavid E. O'Brien 1278bfc788c2SDavid E. O'Brien 12792c3adf61SDavid E. O'Brien static void 12802c3adf61SDavid E. O'Brien nfe_intr(void *arg) 1281bfc788c2SDavid E. O'Brien { 1282bfc788c2SDavid E. O'Brien struct nfe_softc *sc = arg; 1283bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1284bfc788c2SDavid E. O'Brien u_int32_t r; 1285bfc788c2SDavid E. O'Brien 1286bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1287bfc788c2SDavid E. O'Brien 1288bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1289bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1290bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1291bfc788c2SDavid E. O'Brien return; 1292bfc788c2SDavid E. O'Brien } 1293bfc788c2SDavid E. O'Brien #endif 1294bfc788c2SDavid E. O'Brien 1295bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1296bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1297bfc788c2SDavid E. O'Brien return; /* not for us */ 1298bfc788c2SDavid E. O'Brien } 1299bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1300bfc788c2SDavid E. O'Brien 1301bfc788c2SDavid E. O'Brien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 1302bfc788c2SDavid E. O'Brien 1303bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1304bfc788c2SDavid E. O'Brien 1305bfc788c2SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1306bfc788c2SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1307bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1308bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1309bfc788c2SDavid E. O'Brien } 1310bfc788c2SDavid E. O'Brien 1311bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1312bfc788c2SDavid E. O'Brien /* check Rx ring */ 1313bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1314bfc788c2SDavid E. O'Brien /* check Tx ring */ 1315bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1316bfc788c2SDavid E. O'Brien } 1317bfc788c2SDavid E. O'Brien 1318bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1319bfc788c2SDavid E. O'Brien 1320bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1321bfc788c2SDavid E. O'Brien !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1322bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1323bfc788c2SDavid E. O'Brien 1324bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1325bfc788c2SDavid E. O'Brien 1326bfc788c2SDavid E. O'Brien return; 1327bfc788c2SDavid E. O'Brien } 1328bfc788c2SDavid E. O'Brien 13292c3adf61SDavid E. O'Brien 1330bfc788c2SDavid E. O'Brien static void 1331257c5577SDavid E. O'Brien nfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1332257c5577SDavid E. O'Brien { 13332c3adf61SDavid E. O'Brien 1334bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1335257c5577SDavid E. O'Brien } 1336257c5577SDavid E. O'Brien 13372c3adf61SDavid E. O'Brien 1338bfc788c2SDavid E. O'Brien static void 1339257c5577SDavid E. O'Brien nfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1340257c5577SDavid E. O'Brien { 13412c3adf61SDavid E. O'Brien 1342bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1343257c5577SDavid E. O'Brien } 1344257c5577SDavid E. O'Brien 13452c3adf61SDavid E. O'Brien 1346bfc788c2SDavid E. O'Brien static void 1347257c5577SDavid E. O'Brien nfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 1348257c5577SDavid E. O'Brien { 13492c3adf61SDavid E. O'Brien 1350bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1351257c5577SDavid E. O'Brien } 1352257c5577SDavid E. O'Brien 13532c3adf61SDavid E. O'Brien 1354bfc788c2SDavid E. O'Brien static void 1355257c5577SDavid E. O'Brien nfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 1356257c5577SDavid E. O'Brien { 13572c3adf61SDavid E. O'Brien 1358bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1359257c5577SDavid E. O'Brien } 1360257c5577SDavid E. O'Brien 13612c3adf61SDavid E. O'Brien 1362bfc788c2SDavid E. O'Brien static void 1363257c5577SDavid E. O'Brien nfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1364257c5577SDavid E. O'Brien { 13652c3adf61SDavid E. O'Brien 1366bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1367257c5577SDavid E. O'Brien } 1368257c5577SDavid E. O'Brien 13692c3adf61SDavid E. O'Brien 1370bfc788c2SDavid E. O'Brien static void 1371257c5577SDavid E. O'Brien nfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1372257c5577SDavid E. O'Brien { 1373bfc788c2SDavid E. O'Brien 1374bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1375257c5577SDavid E. O'Brien } 1376257c5577SDavid E. O'Brien 13772c3adf61SDavid E. O'Brien 13782c3adf61SDavid E. O'Brien static void 13792c3adf61SDavid E. O'Brien nfe_rxeof(struct nfe_softc *sc) 1380257c5577SDavid E. O'Brien { 1381bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1382bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1383bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1384257c5577SDavid E. O'Brien struct nfe_rx_data *data; 1385257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 1386257c5577SDavid E. O'Brien struct mbuf *m, *mnew; 1387257c5577SDavid E. O'Brien bus_addr_t physaddr; 1388bfc788c2SDavid E. O'Brien u_int16_t flags; 1389257c5577SDavid E. O'Brien int error, len; 1390bfc788c2SDavid E. O'Brien #if NVLAN > 1 1391bfc788c2SDavid E. O'Brien u_int16_t vlan_tag = 0; 1392bfc788c2SDavid E. O'Brien int have_tag = 0; 1393bfc788c2SDavid E. O'Brien #endif 1394bfc788c2SDavid E. O'Brien 1395bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1396257c5577SDavid E. O'Brien 1397257c5577SDavid E. O'Brien for (;;) { 1398bfc788c2SDavid E. O'Brien 1399bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1400bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1401bfc788c2SDavid E. O'Brien if (sc->rxcycles <= 0) 1402bfc788c2SDavid E. O'Brien break; 1403bfc788c2SDavid E. O'Brien sc->rxcycles--; 1404bfc788c2SDavid E. O'Brien } 1405bfc788c2SDavid E. O'Brien #endif 1406bfc788c2SDavid E. O'Brien 1407257c5577SDavid E. O'Brien data = &sc->rxq.data[sc->rxq.cur]; 1408257c5577SDavid E. O'Brien 1409bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1410257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 1411257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1412257c5577SDavid E. O'Brien 1413257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1414257c5577SDavid E. O'Brien len = letoh16(desc64->length) & 0x3fff; 1415bfc788c2SDavid E. O'Brien 1416bfc788c2SDavid E. O'Brien #if NVLAN > 1 1417bfc788c2SDavid E. O'Brien if (flags & NFE_TX_VLAN_TAG) { 1418bfc788c2SDavid E. O'Brien have_tag = 1; 1419bfc788c2SDavid E. O'Brien vlan_tag = desc64->vtag; 1420bfc788c2SDavid E. O'Brien } 1421bfc788c2SDavid E. O'Brien #endif 1422bfc788c2SDavid E. O'Brien 1423257c5577SDavid E. O'Brien } else { 1424257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 1425257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1426257c5577SDavid E. O'Brien 1427257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1428257c5577SDavid E. O'Brien len = letoh16(desc32->length) & 0x3fff; 1429257c5577SDavid E. O'Brien } 1430257c5577SDavid E. O'Brien 1431257c5577SDavid E. O'Brien if (flags & NFE_RX_READY) 1432257c5577SDavid E. O'Brien break; 1433257c5577SDavid E. O'Brien 1434bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1435257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V1)) 1436257c5577SDavid E. O'Brien goto skip; 1437257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 1438257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1439257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1440257c5577SDavid E. O'Brien } 1441257c5577SDavid E. O'Brien } else { 1442257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V2)) 1443257c5577SDavid E. O'Brien goto skip; 1444257c5577SDavid E. O'Brien 1445257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 1446257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1447257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1448257c5577SDavid E. O'Brien } 1449257c5577SDavid E. O'Brien } 1450257c5577SDavid E. O'Brien 1451257c5577SDavid E. O'Brien if (flags & NFE_RX_ERROR) { 1452257c5577SDavid E. O'Brien ifp->if_ierrors++; 1453257c5577SDavid E. O'Brien goto skip; 1454257c5577SDavid E. O'Brien } 1455257c5577SDavid E. O'Brien 1456257c5577SDavid E. O'Brien /* 1457257c5577SDavid E. O'Brien * Try to allocate a new mbuf for this ring element and load 1458257c5577SDavid E. O'Brien * it before processing the current mbuf. If the ring element 1459257c5577SDavid E. O'Brien * cannot be loaded, drop the received packet and reuse the 1460257c5577SDavid E. O'Brien * old mbuf. In the unlikely case that the old mbuf can't be 1461257c5577SDavid E. O'Brien * reloaded either, explicitly panic. 1462257c5577SDavid E. O'Brien */ 1463257c5577SDavid E. O'Brien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 1464257c5577SDavid E. O'Brien if (mnew == NULL) { 1465257c5577SDavid E. O'Brien ifp->if_ierrors++; 1466257c5577SDavid E. O'Brien goto skip; 1467257c5577SDavid E. O'Brien } 1468257c5577SDavid E. O'Brien 1469bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 1470257c5577SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 1471257c5577SDavid E. O'Brien m_freem(mnew); 1472257c5577SDavid E. O'Brien ifp->if_ierrors++; 1473257c5577SDavid E. O'Brien goto skip; 1474257c5577SDavid E. O'Brien } 1475bfc788c2SDavid E. O'Brien mnew->m_data = (void *)jbuf->buf; 1476bfc788c2SDavid E. O'Brien mnew->m_len = mnew->m_pkthdr.len = NFE_JBYTES; 1477bfc788c2SDavid E. O'Brien MEXTADD(mnew, jbuf->buf, NFE_JBYTES, nfe_jfree, 1478bfc788c2SDavid E. O'Brien (struct nfe_softc *)sc, 0 , EXT_NET_DRV); 1479257c5577SDavid E. O'Brien 1480bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_jumbo_tag, 1481bfc788c2SDavid E. O'Brien sc->rxq.rx_jumbo_map, BUS_DMASYNC_POSTREAD); 1482257c5577SDavid E. O'Brien physaddr = jbuf->physaddr; 1483257c5577SDavid E. O'Brien } else { 1484257c5577SDavid E. O'Brien MCLGET(mnew, M_DONTWAIT); 1485257c5577SDavid E. O'Brien if (!(mnew->m_flags & M_EXT)) { 1486257c5577SDavid E. O'Brien m_freem(mnew); 1487257c5577SDavid E. O'Brien ifp->if_ierrors++; 1488257c5577SDavid E. O'Brien goto skip; 1489257c5577SDavid E. O'Brien } 1490257c5577SDavid E. O'Brien 1491bfc788c2SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, 1492bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTREAD); 1493bfc788c2SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 1494bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1495bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(mnew, void *), MCLBYTES, 1496bfc788c2SDavid E. O'Brien nfe_dma_map_segs, &data->rx_data_segs, 1497bfc788c2SDavid E. O'Brien BUS_DMA_NOWAIT); 1498257c5577SDavid E. O'Brien if (error != 0) { 1499257c5577SDavid E. O'Brien m_freem(mnew); 1500257c5577SDavid E. O'Brien 1501257c5577SDavid E. O'Brien /* try to reload the old mbuf */ 1502bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1503bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), 1504bfc788c2SDavid E. O'Brien MCLBYTES, nfe_dma_map_segs, 1505bfc788c2SDavid E. O'Brien &data->rx_data_segs, BUS_DMA_NOWAIT); 1506257c5577SDavid E. O'Brien if (error != 0) { 1507257c5577SDavid E. O'Brien /* very unlikely that it will fail.. */ 1508bfc788c2SDavid E. O'Brien panic("nfe%d: could not load old rx mbuf", 1509bfc788c2SDavid E. O'Brien sc->nfe_unit); 1510257c5577SDavid E. O'Brien } 1511257c5577SDavid E. O'Brien ifp->if_ierrors++; 1512257c5577SDavid E. O'Brien goto skip; 1513257c5577SDavid E. O'Brien } 1514bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 1515bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 1516257c5577SDavid E. O'Brien } 1517257c5577SDavid E. O'Brien 1518257c5577SDavid E. O'Brien /* 1519257c5577SDavid E. O'Brien * New mbuf successfully loaded, update Rx ring and continue 1520257c5577SDavid E. O'Brien * processing. 1521257c5577SDavid E. O'Brien */ 1522257c5577SDavid E. O'Brien m = data->m; 1523257c5577SDavid E. O'Brien data->m = mnew; 1524257c5577SDavid E. O'Brien 1525257c5577SDavid E. O'Brien /* finalize mbuf */ 1526257c5577SDavid E. O'Brien m->m_pkthdr.len = m->m_len = len; 1527257c5577SDavid E. O'Brien m->m_pkthdr.rcvif = ifp; 1528257c5577SDavid E. O'Brien 1529bfc788c2SDavid E. O'Brien 1530bfc788c2SDavid E. O'Brien #if defined(NFE_CSUM) 1531bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) { 1532bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1533bfc788c2SDavid E. O'Brien if (flags & NFE_RX_IP_CSUMOK_V2) { 1534bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1535257c5577SDavid E. O'Brien } 1536bfc788c2SDavid E. O'Brien if (flags & NFE_RX_UDP_CSUMOK_V2 || 1537bfc788c2SDavid E. O'Brien flags & NFE_RX_TCP_CSUMOK_V2) { 1538bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= 1539bfc788c2SDavid E. O'Brien CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 1540bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_data = 0xffff; 1541bfc788c2SDavid E. O'Brien } 1542bfc788c2SDavid E. O'Brien } 1543257c5577SDavid E. O'Brien #endif 1544257c5577SDavid E. O'Brien 1545bfc788c2SDavid E. O'Brien #if NVLAN > 1 1546bfc788c2SDavid E. O'Brien if (have_tag) { 154778ba57b9SAndre Oppermann m->m_pkthdr.ether_vtag = vlan_tag; 154878ba57b9SAndre Oppermann m->m_flags |= M_VLANTAG; 1549bfc788c2SDavid E. O'Brien } 1550257c5577SDavid E. O'Brien #endif 1551bfc788c2SDavid E. O'Brien 1552257c5577SDavid E. O'Brien ifp->if_ipackets++; 1553bfc788c2SDavid E. O'Brien 1554bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1555bfc788c2SDavid E. O'Brien (*ifp->if_input)(ifp, m); 1556bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1557257c5577SDavid E. O'Brien 1558257c5577SDavid E. O'Brien /* update mapping address in h/w descriptor */ 1559bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1560257c5577SDavid E. O'Brien #if defined(__LP64__) 1561257c5577SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 1562257c5577SDavid E. O'Brien #endif 1563257c5577SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1564257c5577SDavid E. O'Brien } else { 1565257c5577SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 1566257c5577SDavid E. O'Brien } 1567257c5577SDavid E. O'Brien 1568bfc788c2SDavid E. O'Brien skip: if (sc->nfe_flags & NFE_40BIT_ADDR) { 1569257c5577SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 1570257c5577SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 1571257c5577SDavid E. O'Brien 1572257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 1573257c5577SDavid E. O'Brien } else { 1574257c5577SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 1575257c5577SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 1576257c5577SDavid E. O'Brien 1577257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 1578257c5577SDavid E. O'Brien } 1579257c5577SDavid E. O'Brien 1580257c5577SDavid E. O'Brien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 1581257c5577SDavid E. O'Brien } 1582257c5577SDavid E. O'Brien } 1583257c5577SDavid E. O'Brien 15842c3adf61SDavid E. O'Brien 15852c3adf61SDavid E. O'Brien static void 15862c3adf61SDavid E. O'Brien nfe_txeof(struct nfe_softc *sc) 1587257c5577SDavid E. O'Brien { 1588bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1589257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 1590257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 1591257c5577SDavid E. O'Brien struct nfe_tx_data *data = NULL; 1592bfc788c2SDavid E. O'Brien u_int16_t flags; 1593bfc788c2SDavid E. O'Brien 1594bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1595257c5577SDavid E. O'Brien 1596257c5577SDavid E. O'Brien while (sc->txq.next != sc->txq.cur) { 1597bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1598257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.next]; 1599257c5577SDavid E. O'Brien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1600257c5577SDavid E. O'Brien 1601257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1602257c5577SDavid E. O'Brien } else { 1603257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.next]; 1604257c5577SDavid E. O'Brien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1605257c5577SDavid E. O'Brien 1606257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1607257c5577SDavid E. O'Brien } 1608257c5577SDavid E. O'Brien 1609257c5577SDavid E. O'Brien if (flags & NFE_TX_VALID) 1610257c5577SDavid E. O'Brien break; 1611257c5577SDavid E. O'Brien 1612257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.next]; 1613257c5577SDavid E. O'Brien 1614bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1615257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 1616257c5577SDavid E. O'Brien goto skip; 1617257c5577SDavid E. O'Brien 1618257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V1) != 0) { 1619bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1620bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V1_TXERR); 1621bfc788c2SDavid E. O'Brien 1622257c5577SDavid E. O'Brien ifp->if_oerrors++; 1623257c5577SDavid E. O'Brien } else 1624257c5577SDavid E. O'Brien ifp->if_opackets++; 1625257c5577SDavid E. O'Brien } else { 1626257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 1627257c5577SDavid E. O'Brien goto skip; 1628257c5577SDavid E. O'Brien 1629257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V2) != 0) { 1630bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1631bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V2_TXERR); 1632bfc788c2SDavid E. O'Brien 1633257c5577SDavid E. O'Brien ifp->if_oerrors++; 1634257c5577SDavid E. O'Brien } else 1635257c5577SDavid E. O'Brien ifp->if_opackets++; 1636257c5577SDavid E. O'Brien } 1637257c5577SDavid E. O'Brien 1638257c5577SDavid E. O'Brien if (data->m == NULL) { /* should not get there */ 1639bfc788c2SDavid E. O'Brien printf("nfe%d: last fragment bit w/o associated mbuf!\n", 1640bfc788c2SDavid E. O'Brien sc->nfe_unit); 1641257c5577SDavid E. O'Brien goto skip; 1642257c5577SDavid E. O'Brien } 1643257c5577SDavid E. O'Brien 1644257c5577SDavid E. O'Brien /* last fragment of the mbuf chain transmitted */ 1645bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, data->active, 1646bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1647bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, data->active); 1648257c5577SDavid E. O'Brien m_freem(data->m); 1649257c5577SDavid E. O'Brien data->m = NULL; 1650257c5577SDavid E. O'Brien 1651257c5577SDavid E. O'Brien ifp->if_timer = 0; 1652257c5577SDavid E. O'Brien 1653257c5577SDavid E. O'Brien skip: sc->txq.queued--; 1654257c5577SDavid E. O'Brien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 1655257c5577SDavid E. O'Brien } 1656257c5577SDavid E. O'Brien 1657257c5577SDavid E. O'Brien if (data != NULL) { /* at least one slot freed */ 1658bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1659bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1660257c5577SDavid E. O'Brien } 1661257c5577SDavid E. O'Brien } 1662257c5577SDavid E. O'Brien 16632c3adf61SDavid E. O'Brien 16642c3adf61SDavid E. O'Brien static int 16652c3adf61SDavid E. O'Brien nfe_encap(struct nfe_softc *sc, struct mbuf *m0) 1666257c5577SDavid E. O'Brien { 1667bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1668bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1669bfc788c2SDavid E. O'Brien struct nfe_tx_data *data=NULL; 1670257c5577SDavid E. O'Brien bus_dmamap_t map; 1671bfc788c2SDavid E. O'Brien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 16722c3adf61SDavid E. O'Brien int error, i, nsegs; 16732c3adf61SDavid E. O'Brien u_int16_t flags = NFE_TX_VALID; 1674257c5577SDavid E. O'Brien 1675bfc788c2SDavid E. O'Brien map = sc->txq.data[sc->txq.cur].tx_data_map; 1676257c5577SDavid E. O'Brien 1677bfc788c2SDavid E. O'Brien error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, m0, segs, 1678bfc788c2SDavid E. O'Brien &nsegs, BUS_DMA_NOWAIT); 1679bfc788c2SDavid E. O'Brien 1680257c5577SDavid E. O'Brien if (error != 0) { 1681bfc788c2SDavid E. O'Brien printf("nfe%d: could not map mbuf (error %d)\n", sc->nfe_unit, 1682bfc788c2SDavid E. O'Brien error); 1683257c5577SDavid E. O'Brien return error; 1684257c5577SDavid E. O'Brien } 1685257c5577SDavid E. O'Brien 1686bfc788c2SDavid E. O'Brien if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 1) { 1687bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, map); 1688257c5577SDavid E. O'Brien return ENOBUFS; 1689257c5577SDavid E. O'Brien } 1690257c5577SDavid E. O'Brien 1691bfc788c2SDavid E. O'Brien 1692257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1693bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_IP) 1694257c5577SDavid E. O'Brien flags |= NFE_TX_IP_CSUM; 1695bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_TCP) 1696bfc788c2SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1697bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_UDP) 1698257c5577SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1699257c5577SDavid E. O'Brien #endif 1700257c5577SDavid E. O'Brien 1701bfc788c2SDavid E. O'Brien for (i = 0; i < nsegs; i++) { 1702257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.cur]; 1703257c5577SDavid E. O'Brien 1704bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1705257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.cur]; 1706257c5577SDavid E. O'Brien #if defined(__LP64__) 1707bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(segs[i].ds_addr >> 32); 1708257c5577SDavid E. O'Brien #endif 1709bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(segs[i].ds_addr & 1710bfc788c2SDavid E. O'Brien 0xffffffff); 1711bfc788c2SDavid E. O'Brien desc64->length = htole16(segs[i].ds_len - 1); 1712257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1713257c5577SDavid E. O'Brien #if NVLAN > 0 171478ba57b9SAndre Oppermann if (m0->m_flags & M_VLANTAG) 1715bfc788c2SDavid E. O'Brien desc64->vtag = htole32(NFE_TX_VTAG | 171678ba57b9SAndre Oppermann m0->m_pkthdr.ether_vtag); 1717257c5577SDavid E. O'Brien #endif 1718257c5577SDavid E. O'Brien } else { 1719257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.cur]; 1720257c5577SDavid E. O'Brien 1721bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(segs[i].ds_addr); 1722bfc788c2SDavid E. O'Brien desc32->length = htole16(segs[i].ds_len - 1); 1723257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1724257c5577SDavid E. O'Brien } 1725257c5577SDavid E. O'Brien 1726257c5577SDavid E. O'Brien /* csum flags and vtag belong to the first fragment only */ 1727bfc788c2SDavid E. O'Brien if (nsegs > 1) { 1728257c5577SDavid E. O'Brien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 1729257c5577SDavid E. O'Brien } 1730257c5577SDavid E. O'Brien 1731257c5577SDavid E. O'Brien sc->txq.queued++; 1732257c5577SDavid E. O'Brien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 1733257c5577SDavid E. O'Brien } 1734257c5577SDavid E. O'Brien 1735257c5577SDavid E. O'Brien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 1736bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1737257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1738257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1739257c5577SDavid E. O'Brien } else { 1740bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 1741257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1742257c5577SDavid E. O'Brien else 1743257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V1; 1744257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1745257c5577SDavid E. O'Brien } 1746257c5577SDavid E. O'Brien 1747257c5577SDavid E. O'Brien data->m = m0; 1748257c5577SDavid E. O'Brien data->active = map; 1749bfc788c2SDavid E. O'Brien data->nsegs = nsegs; 1750257c5577SDavid E. O'Brien 1751bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 1752257c5577SDavid E. O'Brien 1753257c5577SDavid E. O'Brien return 0; 1754257c5577SDavid E. O'Brien } 1755257c5577SDavid E. O'Brien 1756bfc788c2SDavid E. O'Brien 17572c3adf61SDavid E. O'Brien static void 17582c3adf61SDavid E. O'Brien nfe_setmulti(struct nfe_softc *sc) 1759bfc788c2SDavid E. O'Brien { 1760bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1761bfc788c2SDavid E. O'Brien struct ifmultiaddr *ifma; 1762bfc788c2SDavid E. O'Brien int i; 17632c3adf61SDavid E. O'Brien u_int32_t filter = NFE_RXFILTER_MAGIC; 17642c3adf61SDavid E. O'Brien u_int8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 17652c3adf61SDavid E. O'Brien u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 17662c3adf61SDavid E. O'Brien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 17672c3adf61SDavid E. O'Brien }; 1768bfc788c2SDavid E. O'Brien 1769bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1770bfc788c2SDavid E. O'Brien 1771bfc788c2SDavid E. O'Brien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1772bfc788c2SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 1773bfc788c2SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 1774bfc788c2SDavid E. O'Brien goto done; 1775bfc788c2SDavid E. O'Brien } 1776bfc788c2SDavid E. O'Brien 1777bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1778bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1779bfc788c2SDavid E. O'Brien 1780bfc788c2SDavid E. O'Brien IF_ADDR_LOCK(ifp); 1781bfc788c2SDavid E. O'Brien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1782bfc788c2SDavid E. O'Brien u_char *addrp; 1783bfc788c2SDavid E. O'Brien 1784bfc788c2SDavid E. O'Brien if (ifma->ifma_addr->sa_family != AF_LINK) 1785bfc788c2SDavid E. O'Brien continue; 1786bfc788c2SDavid E. O'Brien 1787bfc788c2SDavid E. O'Brien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 1788bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1789bfc788c2SDavid E. O'Brien u_int8_t mcaddr = addrp[i]; 1790bfc788c2SDavid E. O'Brien addr[i] &= mcaddr; 1791bfc788c2SDavid E. O'Brien mask[i] &= ~mcaddr; 1792bfc788c2SDavid E. O'Brien } 1793bfc788c2SDavid E. O'Brien } 1794bfc788c2SDavid E. O'Brien IF_ADDR_UNLOCK(ifp); 1795bfc788c2SDavid E. O'Brien 1796bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1797bfc788c2SDavid E. O'Brien mask[i] |= addr[i]; 1798bfc788c2SDavid E. O'Brien } 1799bfc788c2SDavid E. O'Brien 1800bfc788c2SDavid E. O'Brien done: 1801bfc788c2SDavid E. O'Brien addr[0] |= 0x01; /* make sure multicast bit is set */ 1802bfc788c2SDavid E. O'Brien 1803bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1804bfc788c2SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1805bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1806bfc788c2SDavid E. O'Brien addr[5] << 8 | addr[4]); 1807bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1808bfc788c2SDavid E. O'Brien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1809bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1810bfc788c2SDavid E. O'Brien mask[5] << 8 | mask[4]); 1811bfc788c2SDavid E. O'Brien 1812bfc788c2SDavid E. O'Brien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1813bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_RXFILTER, filter); 1814bfc788c2SDavid E. O'Brien } 1815bfc788c2SDavid E. O'Brien 18162c3adf61SDavid E. O'Brien 18172c3adf61SDavid E. O'Brien static void 18182c3adf61SDavid E. O'Brien nfe_start(struct ifnet *ifp) 1819bfc788c2SDavid E. O'Brien { 1820bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1821bfc788c2SDavid E. O'Brien 1822bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 1823bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1824bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1825bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1826bfc788c2SDavid E. O'Brien } 1827bfc788c2SDavid E. O'Brien 18282c3adf61SDavid E. O'Brien 18292c3adf61SDavid E. O'Brien static void 18302c3adf61SDavid E. O'Brien nfe_start_locked(struct ifnet *ifp) 1831257c5577SDavid E. O'Brien { 1832257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1833257c5577SDavid E. O'Brien struct mbuf *m0; 18342c3adf61SDavid E. O'Brien int old = sc->txq.cur; 1835257c5577SDavid E. O'Brien 1836bfc788c2SDavid E. O'Brien if (!sc->nfe_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1837bfc788c2SDavid E. O'Brien return; 1838bfc788c2SDavid E. O'Brien } 1839bfc788c2SDavid E. O'Brien 1840257c5577SDavid E. O'Brien for (;;) { 1841257c5577SDavid E. O'Brien IFQ_POLL(&ifp->if_snd, m0); 1842257c5577SDavid E. O'Brien if (m0 == NULL) 1843257c5577SDavid E. O'Brien break; 1844257c5577SDavid E. O'Brien 1845257c5577SDavid E. O'Brien if (nfe_encap(sc, m0) != 0) { 1846bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1847257c5577SDavid E. O'Brien break; 1848257c5577SDavid E. O'Brien } 1849257c5577SDavid E. O'Brien 1850257c5577SDavid E. O'Brien /* packet put in h/w queue, remove from s/w queue */ 1851257c5577SDavid E. O'Brien IFQ_DEQUEUE(&ifp->if_snd, m0); 1852257c5577SDavid E. O'Brien 1853bfc788c2SDavid E. O'Brien BPF_MTAP(ifp, m0); 1854257c5577SDavid E. O'Brien } 1855bfc788c2SDavid E. O'Brien if (sc->txq.cur == old) { /* nothing sent */ 1856257c5577SDavid E. O'Brien return; 1857bfc788c2SDavid E. O'Brien } 1858257c5577SDavid E. O'Brien 1859bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1860257c5577SDavid E. O'Brien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1861257c5577SDavid E. O'Brien else 1862257c5577SDavid E. O'Brien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1863257c5577SDavid E. O'Brien 1864257c5577SDavid E. O'Brien /* kick Tx */ 1865257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1866257c5577SDavid E. O'Brien 1867257c5577SDavid E. O'Brien /* 1868257c5577SDavid E. O'Brien * Set a timeout in case the chip goes out to lunch. 1869257c5577SDavid E. O'Brien */ 1870257c5577SDavid E. O'Brien ifp->if_timer = 5; 1871bfc788c2SDavid E. O'Brien 1872bfc788c2SDavid E. O'Brien return; 1873257c5577SDavid E. O'Brien } 1874257c5577SDavid E. O'Brien 18752c3adf61SDavid E. O'Brien 18762c3adf61SDavid E. O'Brien static void 18772c3adf61SDavid E. O'Brien nfe_watchdog(struct ifnet *ifp) 1878257c5577SDavid E. O'Brien { 1879257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1880257c5577SDavid E. O'Brien 1881bfc788c2SDavid E. O'Brien printf("nfe%d: watchdog timeout\n", sc->nfe_unit); 1882257c5577SDavid E. O'Brien 1883bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1884bfc788c2SDavid E. O'Brien nfe_init(sc); 1885257c5577SDavid E. O'Brien ifp->if_oerrors++; 1886bfc788c2SDavid E. O'Brien 1887bfc788c2SDavid E. O'Brien return; 1888257c5577SDavid E. O'Brien } 1889257c5577SDavid E. O'Brien 18902c3adf61SDavid E. O'Brien 18912c3adf61SDavid E. O'Brien static void 18922c3adf61SDavid E. O'Brien nfe_init(void *xsc) 1893257c5577SDavid E. O'Brien { 1894bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1895bfc788c2SDavid E. O'Brien 1896bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1897bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1898bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1899bfc788c2SDavid E. O'Brien 1900bfc788c2SDavid E. O'Brien return; 1901bfc788c2SDavid E. O'Brien } 1902bfc788c2SDavid E. O'Brien 19032c3adf61SDavid E. O'Brien 19042c3adf61SDavid E. O'Brien static void 19052c3adf61SDavid E. O'Brien nfe_init_locked(void *xsc) 1906bfc788c2SDavid E. O'Brien { 1907bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1908bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1909bfc788c2SDavid E. O'Brien struct mii_data *mii; 1910bfc788c2SDavid E. O'Brien u_int32_t tmp; 1911bfc788c2SDavid E. O'Brien 1912bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1913bfc788c2SDavid E. O'Brien 1914bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1915bfc788c2SDavid E. O'Brien 1916bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1917bfc788c2SDavid E. O'Brien return; 1918bfc788c2SDavid E. O'Brien } 1919257c5577SDavid E. O'Brien 1920257c5577SDavid E. O'Brien nfe_stop(ifp, 0); 1921257c5577SDavid E. O'Brien 1922257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_UNK, 0); 1923257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, 0); 1924257c5577SDavid E. O'Brien 1925257c5577SDavid E. O'Brien sc->rxtxctl = NFE_RXTX_BIT2; 1926bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1927257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1928bfc788c2SDavid E. O'Brien else if (sc->nfe_flags & NFE_JUMBO_SUP) 1929257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 1930257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1931bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) 1932257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1933257c5577SDavid E. O'Brien #endif 1934bfc788c2SDavid E. O'Brien 1935257c5577SDavid E. O'Brien #if NVLAN > 0 1936257c5577SDavid E. O'Brien /* 1937257c5577SDavid E. O'Brien * Although the adapter is capable of stripping VLAN tags from received 1938257c5577SDavid E. O'Brien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1939257c5577SDavid E. O'Brien * purpose. This will be done in software by our network stack. 1940257c5577SDavid E. O'Brien */ 1941bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1942257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1943257c5577SDavid E. O'Brien #endif 1944bfc788c2SDavid E. O'Brien 1945257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1946257c5577SDavid E. O'Brien DELAY(10); 1947257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1948257c5577SDavid E. O'Brien 1949257c5577SDavid E. O'Brien #if NVLAN 1950bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1951257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1952257c5577SDavid E. O'Brien #endif 1953257c5577SDavid E. O'Brien 1954257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1955257c5577SDavid E. O'Brien 1956257c5577SDavid E. O'Brien /* set MAC address */ 1957bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, sc->eaddr); 1958257c5577SDavid E. O'Brien 1959257c5577SDavid E. O'Brien /* tell MAC where rings are in memory */ 1960257c5577SDavid E. O'Brien #ifdef __LP64__ 1961257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1962257c5577SDavid E. O'Brien #endif 1963257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1964257c5577SDavid E. O'Brien #ifdef __LP64__ 1965257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1966257c5577SDavid E. O'Brien #endif 1967257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1968257c5577SDavid E. O'Brien 1969257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RING_SIZE, 1970257c5577SDavid E. O'Brien (NFE_RX_RING_COUNT - 1) << 16 | 1971257c5577SDavid E. O'Brien (NFE_TX_RING_COUNT - 1)); 1972257c5577SDavid E. O'Brien 1973257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1974257c5577SDavid E. O'Brien 1975257c5577SDavid E. O'Brien /* force MAC to wakeup */ 1976257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1977257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1978257c5577SDavid E. O'Brien DELAY(10); 1979257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1980257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1981257c5577SDavid E. O'Brien 1982257c5577SDavid E. O'Brien #if 1 1983257c5577SDavid E. O'Brien /* configure interrupts coalescing/mitigation */ 1984257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1985257c5577SDavid E. O'Brien #else 1986257c5577SDavid E. O'Brien /* no interrupt mitigation: one interrupt per packet */ 1987257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, 970); 1988257c5577SDavid E. O'Brien #endif 1989257c5577SDavid E. O'Brien 1990257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1991257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1992257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1993257c5577SDavid E. O'Brien 1994257c5577SDavid E. O'Brien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1995257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1996257c5577SDavid E. O'Brien 1997257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1998257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1999257c5577SDavid E. O'Brien 2000257c5577SDavid E. O'Brien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2001257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2002257c5577SDavid E. O'Brien DELAY(10); 2003257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2004257c5577SDavid E. O'Brien 2005257c5577SDavid E. O'Brien /* set Rx filter */ 2006257c5577SDavid E. O'Brien nfe_setmulti(sc); 2007257c5577SDavid E. O'Brien 2008257c5577SDavid E. O'Brien nfe_ifmedia_upd(ifp); 2009257c5577SDavid E. O'Brien 2010bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 2011bfc788c2SDavid E. O'Brien 2012257c5577SDavid E. O'Brien /* enable Rx */ 2013257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2014257c5577SDavid E. O'Brien 2015257c5577SDavid E. O'Brien /* enable Tx */ 2016257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2017257c5577SDavid E. O'Brien 2018257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2019257c5577SDavid E. O'Brien 2020bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 2021bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 2022bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 2023bfc788c2SDavid E. O'Brien else 2024bfc788c2SDavid E. O'Brien #endif 2025bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); /* enable interrupts */ 2026257c5577SDavid E. O'Brien 2027bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2028bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2029257c5577SDavid E. O'Brien 2030bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 2031257c5577SDavid E. O'Brien 2032bfc788c2SDavid E. O'Brien return; 2033257c5577SDavid E. O'Brien } 2034257c5577SDavid E. O'Brien 20352c3adf61SDavid E. O'Brien 20362c3adf61SDavid E. O'Brien static void 20372c3adf61SDavid E. O'Brien nfe_stop(struct ifnet *ifp, int disable) 2038257c5577SDavid E. O'Brien { 2039257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2040bfc788c2SDavid E. O'Brien struct mii_data *mii; 2041257c5577SDavid E. O'Brien 2042bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2043257c5577SDavid E. O'Brien 2044257c5577SDavid E. O'Brien ifp->if_timer = 0; 2045bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2046257c5577SDavid E. O'Brien 2047bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2048bfc788c2SDavid E. O'Brien 2049bfc788c2SDavid E. O'Brien callout_stop(&sc->nfe_stat_ch); 2050257c5577SDavid E. O'Brien 2051257c5577SDavid E. O'Brien /* abort Tx */ 2052257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, 0); 2053257c5577SDavid E. O'Brien 2054257c5577SDavid E. O'Brien /* disable Rx */ 2055257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, 0); 2056257c5577SDavid E. O'Brien 2057257c5577SDavid E. O'Brien /* disable interrupts */ 2058257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 2059257c5577SDavid E. O'Brien 2060bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 2061bfc788c2SDavid E. O'Brien 2062257c5577SDavid E. O'Brien /* reset Tx and Rx rings */ 2063257c5577SDavid E. O'Brien nfe_reset_tx_ring(sc, &sc->txq); 2064257c5577SDavid E. O'Brien nfe_reset_rx_ring(sc, &sc->rxq); 2065257c5577SDavid E. O'Brien 2066257c5577SDavid E. O'Brien return; 2067257c5577SDavid E. O'Brien } 2068257c5577SDavid E. O'Brien 20692c3adf61SDavid E. O'Brien 20702c3adf61SDavid E. O'Brien static int 20712c3adf61SDavid E. O'Brien nfe_ifmedia_upd(struct ifnet *ifp) 2072257c5577SDavid E. O'Brien { 2073257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2074257c5577SDavid E. O'Brien 2075bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2076bfc788c2SDavid E. O'Brien nfe_ifmedia_upd_locked(ifp); 2077bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2078bfc788c2SDavid E. O'Brien return (0); 2079bfc788c2SDavid E. O'Brien } 2080bfc788c2SDavid E. O'Brien 20812c3adf61SDavid E. O'Brien 20822c3adf61SDavid E. O'Brien static int 20832c3adf61SDavid E. O'Brien nfe_ifmedia_upd_locked(struct ifnet *ifp) 2084bfc788c2SDavid E. O'Brien { 2085bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2086bfc788c2SDavid E. O'Brien struct mii_data *mii; 2087bfc788c2SDavid E. O'Brien 2088bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2089bfc788c2SDavid E. O'Brien 2090bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2091bfc788c2SDavid E. O'Brien 2092bfc788c2SDavid E. O'Brien if (mii->mii_instance) { 2093bfc788c2SDavid E. O'Brien struct mii_softc *miisc; 2094bfc788c2SDavid E. O'Brien for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 2095bfc788c2SDavid E. O'Brien miisc = LIST_NEXT(miisc, mii_list)) { 2096257c5577SDavid E. O'Brien mii_phy_reset(miisc); 2097257c5577SDavid E. O'Brien } 2098bfc788c2SDavid E. O'Brien } 2099bfc788c2SDavid E. O'Brien mii_mediachg(mii); 2100bfc788c2SDavid E. O'Brien 2101bfc788c2SDavid E. O'Brien return (0); 2102257c5577SDavid E. O'Brien } 2103257c5577SDavid E. O'Brien 21042c3adf61SDavid E. O'Brien 21052c3adf61SDavid E. O'Brien static void 21062c3adf61SDavid E. O'Brien nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2107257c5577SDavid E. O'Brien { 2108bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2109bfc788c2SDavid E. O'Brien struct mii_data *mii; 2110257c5577SDavid E. O'Brien 2111bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 2112bfc788c2SDavid E. O'Brien 2113bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2114bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2115257c5577SDavid E. O'Brien mii_pollstat(mii); 2116bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2117bfc788c2SDavid E. O'Brien 2118257c5577SDavid E. O'Brien ifmr->ifm_active = mii->mii_media_active; 2119bfc788c2SDavid E. O'Brien ifmr->ifm_status = mii->mii_media_status; 2120bfc788c2SDavid E. O'Brien 2121bfc788c2SDavid E. O'Brien return; 2122257c5577SDavid E. O'Brien } 2123257c5577SDavid E. O'Brien 21242c3adf61SDavid E. O'Brien 2125bfc788c2SDavid E. O'Brien static void 2126bfc788c2SDavid E. O'Brien nfe_tick(void *xsc) 2127257c5577SDavid E. O'Brien { 2128bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2129257c5577SDavid E. O'Brien 2130bfc788c2SDavid E. O'Brien sc = xsc; 2131bfc788c2SDavid E. O'Brien 2132bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2133bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 2134bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2135257c5577SDavid E. O'Brien } 2136257c5577SDavid E. O'Brien 2137257c5577SDavid E. O'Brien 21382c3adf61SDavid E. O'Brien void 21392c3adf61SDavid E. O'Brien nfe_tick_locked(struct nfe_softc *arg) 2140bfc788c2SDavid E. O'Brien { 2141bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2142bfc788c2SDavid E. O'Brien struct mii_data *mii; 2143bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2144bfc788c2SDavid E. O'Brien 2145bfc788c2SDavid E. O'Brien sc = arg; 2146bfc788c2SDavid E. O'Brien 2147bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2148bfc788c2SDavid E. O'Brien 2149bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2150bfc788c2SDavid E. O'Brien 2151bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2152bfc788c2SDavid E. O'Brien mii_tick(mii); 2153bfc788c2SDavid E. O'Brien 2154bfc788c2SDavid E. O'Brien if (!sc->nfe_link) { 2155bfc788c2SDavid E. O'Brien if (mii->mii_media_status & IFM_ACTIVE && 2156bfc788c2SDavid E. O'Brien IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 2157bfc788c2SDavid E. O'Brien sc->nfe_link++; 2158bfc788c2SDavid E. O'Brien if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T 2159bfc788c2SDavid E. O'Brien && bootverbose) 2160bfc788c2SDavid E. O'Brien if_printf(sc->nfe_ifp, "gigabit link up\n"); 2161bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2162bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 2163257c5577SDavid E. O'Brien } 2164257c5577SDavid E. O'Brien } 2165bfc788c2SDavid E. O'Brien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2166257c5577SDavid E. O'Brien 2167bfc788c2SDavid E. O'Brien return; 2168257c5577SDavid E. O'Brien } 2169257c5577SDavid E. O'Brien 2170bfc788c2SDavid E. O'Brien 21712c3adf61SDavid E. O'Brien static void 21722c3adf61SDavid E. O'Brien nfe_shutdown(device_t dev) 2173bfc788c2SDavid E. O'Brien { 2174bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2175bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2176bfc788c2SDavid E. O'Brien 2177bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 2178bfc788c2SDavid E. O'Brien 2179bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2180bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2181bfc788c2SDavid E. O'Brien nfe_stop(ifp,0); 2182bfc788c2SDavid E. O'Brien /* nfe_reset(sc); */ 2183bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2184bfc788c2SDavid E. O'Brien 2185bfc788c2SDavid E. O'Brien return; 2186bfc788c2SDavid E. O'Brien } 2187bfc788c2SDavid E. O'Brien 2188bfc788c2SDavid E. O'Brien 21892c3adf61SDavid E. O'Brien static void 21902c3adf61SDavid E. O'Brien nfe_get_macaddr(struct nfe_softc *sc, u_char *addr) 2191257c5577SDavid E. O'Brien { 2192257c5577SDavid E. O'Brien uint32_t tmp; 2193257c5577SDavid E. O'Brien 2194257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_LO); 2195257c5577SDavid E. O'Brien addr[0] = (tmp >> 8) & 0xff; 2196257c5577SDavid E. O'Brien addr[1] = (tmp & 0xff); 2197257c5577SDavid E. O'Brien 2198257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_HI); 2199257c5577SDavid E. O'Brien addr[2] = (tmp >> 24) & 0xff; 2200257c5577SDavid E. O'Brien addr[3] = (tmp >> 16) & 0xff; 2201257c5577SDavid E. O'Brien addr[4] = (tmp >> 8) & 0xff; 2202257c5577SDavid E. O'Brien addr[5] = (tmp & 0xff); 2203257c5577SDavid E. O'Brien } 2204257c5577SDavid E. O'Brien 22052c3adf61SDavid E. O'Brien 22062c3adf61SDavid E. O'Brien static void 22072c3adf61SDavid E. O'Brien nfe_set_macaddr(struct nfe_softc *sc, u_char *addr) 2208257c5577SDavid E. O'Brien { 2209bfc788c2SDavid E. O'Brien 2210bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 2211bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 2212bfc788c2SDavid E. O'Brien addr[1] << 8 | addr[0]); 2213257c5577SDavid E. O'Brien } 2214257c5577SDavid E. O'Brien 22152c3adf61SDavid E. O'Brien 2216bfc788c2SDavid E. O'Brien /* 2217bfc788c2SDavid E. O'Brien * Map a single buffer address. 2218bfc788c2SDavid E. O'Brien */ 2219bfc788c2SDavid E. O'Brien 2220bfc788c2SDavid E. O'Brien static void 2221bfc788c2SDavid E. O'Brien nfe_dma_map_segs(arg, segs, nseg, error) 2222bfc788c2SDavid E. O'Brien void *arg; 2223bfc788c2SDavid E. O'Brien bus_dma_segment_t *segs; 2224bfc788c2SDavid E. O'Brien int error, nseg; 2225257c5577SDavid E. O'Brien { 2226257c5577SDavid E. O'Brien 2227bfc788c2SDavid E. O'Brien if (error) 2228bfc788c2SDavid E. O'Brien return; 2229257c5577SDavid E. O'Brien 2230bfc788c2SDavid E. O'Brien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2231bfc788c2SDavid E. O'Brien 2232bfc788c2SDavid E. O'Brien *(bus_dma_segment_t *)arg = *segs; 2233bfc788c2SDavid E. O'Brien 2234bfc788c2SDavid E. O'Brien return; 2235257c5577SDavid E. O'Brien } 2236