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)) { 450bfc788c2SDavid E. O'Brien nfe_stop(ifp, 1); 451bfc788c2SDavid E. O'Brien ifp->if_flags &= ~IFF_UP; 452bfc788c2SDavid E. O'Brien callout_drain(&sc->nfe_stat_ch); 453bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 454257c5577SDavid E. O'Brien } 455257c5577SDavid E. O'Brien 456bfc788c2SDavid E. O'Brien if (ifp) 457bfc788c2SDavid E. O'Brien if_free(ifp); 458bfc788c2SDavid E. O'Brien if (sc->nfe_miibus) 459bfc788c2SDavid E. O'Brien device_delete_child(dev, sc->nfe_miibus); 460bfc788c2SDavid E. O'Brien bus_generic_detach(dev); 461bfc788c2SDavid E. O'Brien 462bfc788c2SDavid E. O'Brien if (sc->nfe_intrhand) 463bfc788c2SDavid E. O'Brien bus_teardown_intr(dev, sc->nfe_irq, sc->nfe_intrhand); 464bfc788c2SDavid E. O'Brien if (sc->nfe_irq) 465bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nfe_irq); 466bfc788c2SDavid E. O'Brien if (sc->nfe_res) 467bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_MEMORY, NV_RID, sc->nfe_res); 468bfc788c2SDavid E. O'Brien 469bfc788c2SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 470bfc788c2SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 471bfc788c2SDavid E. O'Brien 472bfc788c2SDavid E. O'Brien if (sc->nfe_parent_tag) 473bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(sc->nfe_parent_tag); 474bfc788c2SDavid E. O'Brien 475bfc788c2SDavid E. O'Brien mtx_destroy(&sc->nfe_mtx); 476bfc788c2SDavid E. O'Brien 477bfc788c2SDavid E. O'Brien return (0); 478bfc788c2SDavid E. O'Brien } 479bfc788c2SDavid E. O'Brien 480bfc788c2SDavid E. O'Brien 481bfc788c2SDavid E. O'Brien static void 482bfc788c2SDavid E. O'Brien nfe_miibus_statchg(device_t dev) 483257c5577SDavid E. O'Brien { 484bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 485bfc788c2SDavid E. O'Brien struct mii_data *mii; 486bfc788c2SDavid E. O'Brien u_int32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 487bfc788c2SDavid E. O'Brien 488bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 489bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 490257c5577SDavid E. O'Brien 491257c5577SDavid E. O'Brien phy = NFE_READ(sc, NFE_PHY_IFACE); 492257c5577SDavid E. O'Brien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 493257c5577SDavid E. O'Brien 494257c5577SDavid E. O'Brien seed = NFE_READ(sc, NFE_RNDSEED); 495257c5577SDavid E. O'Brien seed &= ~NFE_SEED_MASK; 496257c5577SDavid E. O'Brien 497257c5577SDavid E. O'Brien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 498257c5577SDavid E. O'Brien phy |= NFE_PHY_HDX; /* half-duplex */ 499257c5577SDavid E. O'Brien misc |= NFE_MISC1_HDX; 500257c5577SDavid E. O'Brien } 501257c5577SDavid E. O'Brien 502257c5577SDavid E. O'Brien switch (IFM_SUBTYPE(mii->mii_media_active)) { 503257c5577SDavid E. O'Brien case IFM_1000_T: /* full-duplex only */ 504257c5577SDavid E. O'Brien link |= NFE_MEDIA_1000T; 505257c5577SDavid E. O'Brien seed |= NFE_SEED_1000T; 506257c5577SDavid E. O'Brien phy |= NFE_PHY_1000T; 507257c5577SDavid E. O'Brien break; 508257c5577SDavid E. O'Brien case IFM_100_TX: 509257c5577SDavid E. O'Brien link |= NFE_MEDIA_100TX; 510257c5577SDavid E. O'Brien seed |= NFE_SEED_100TX; 511257c5577SDavid E. O'Brien phy |= NFE_PHY_100TX; 512257c5577SDavid E. O'Brien break; 513257c5577SDavid E. O'Brien case IFM_10_T: 514257c5577SDavid E. O'Brien link |= NFE_MEDIA_10T; 515257c5577SDavid E. O'Brien seed |= NFE_SEED_10T; 516257c5577SDavid E. O'Brien break; 517257c5577SDavid E. O'Brien } 518257c5577SDavid E. O'Brien 519257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 520257c5577SDavid E. O'Brien 521257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 522257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MISC1, misc); 523257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_LINKSPEED, link); 524257c5577SDavid E. O'Brien } 525257c5577SDavid E. O'Brien 5262c3adf61SDavid E. O'Brien 527bfc788c2SDavid E. O'Brien static int 528bfc788c2SDavid E. O'Brien nfe_miibus_readreg(device_t dev, int phy, int reg) 529257c5577SDavid E. O'Brien { 530bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 531bfc788c2SDavid E. O'Brien u_int32_t val; 532257c5577SDavid E. O'Brien int ntries; 533257c5577SDavid E. O'Brien 534257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 535257c5577SDavid E. O'Brien 536257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 537257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 538257c5577SDavid E. O'Brien DELAY(100); 539257c5577SDavid E. O'Brien } 540257c5577SDavid E. O'Brien 541257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 542257c5577SDavid E. O'Brien 543257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 544257c5577SDavid E. O'Brien DELAY(100); 545257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 546257c5577SDavid E. O'Brien break; 547257c5577SDavid E. O'Brien } 548257c5577SDavid E. O'Brien if (ntries == 1000) { 549bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: timeout waiting for PHY\n", sc->nfe_unit)); 550257c5577SDavid E. O'Brien return 0; 551257c5577SDavid E. O'Brien } 552257c5577SDavid E. O'Brien 553257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 554bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: could not read PHY\n", sc->nfe_unit)); 555257c5577SDavid E. O'Brien return 0; 556257c5577SDavid E. O'Brien } 557257c5577SDavid E. O'Brien 558257c5577SDavid E. O'Brien val = NFE_READ(sc, NFE_PHY_DATA); 559257c5577SDavid E. O'Brien if (val != 0xffffffff && val != 0) 560257c5577SDavid E. O'Brien sc->mii_phyaddr = phy; 561257c5577SDavid E. O'Brien 5622c3adf61SDavid E. O'Brien DPRINTFN(2, ("nfe%d: mii read phy %d reg 0x%x ret 0x%x\n", 5632c3adf61SDavid E. O'Brien sc->nfe_unit, phy, reg, val)); 564257c5577SDavid E. O'Brien 565257c5577SDavid E. O'Brien return val; 566257c5577SDavid E. O'Brien } 567257c5577SDavid E. O'Brien 5682c3adf61SDavid E. O'Brien 569bfc788c2SDavid E. O'Brien static int 570bfc788c2SDavid E. O'Brien nfe_miibus_writereg(device_t dev, int phy, int reg, int val) 571257c5577SDavid E. O'Brien { 572bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 573bfc788c2SDavid E. O'Brien u_int32_t ctl; 574257c5577SDavid E. O'Brien int ntries; 575257c5577SDavid E. O'Brien 576257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 577257c5577SDavid E. O'Brien 578257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 579257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 580257c5577SDavid E. O'Brien DELAY(100); 581257c5577SDavid E. O'Brien } 582257c5577SDavid E. O'Brien 583257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_DATA, val); 584257c5577SDavid E. O'Brien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 585257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 586257c5577SDavid E. O'Brien 587257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 588257c5577SDavid E. O'Brien DELAY(100); 589257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 590257c5577SDavid E. O'Brien break; 591257c5577SDavid E. O'Brien } 592257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 593257c5577SDavid E. O'Brien if (nfedebug >= 2 && ntries == 1000) 594257c5577SDavid E. O'Brien printf("could not write to PHY\n"); 595257c5577SDavid E. O'Brien #endif 596bfc788c2SDavid E. O'Brien return 0; 597257c5577SDavid E. O'Brien } 598257c5577SDavid E. O'Brien 5992c3adf61SDavid E. O'Brien 600bfc788c2SDavid E. O'Brien static int 601bfc788c2SDavid E. O'Brien nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 602bfc788c2SDavid E. O'Brien { 603bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32; 604bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64; 605bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 606bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 607bfc788c2SDavid E. O'Brien void **desc; 608bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 609bfc788c2SDavid E. O'Brien int i, error, descsize; 610bfc788c2SDavid E. O'Brien 611bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 612bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 613bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 614bfc788c2SDavid E. O'Brien } else { 615bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 616bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 617bfc788c2SDavid E. O'Brien } 618bfc788c2SDavid E. O'Brien 619bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 620bfc788c2SDavid E. O'Brien ring->bufsz = MCLBYTES; 621bfc788c2SDavid E. O'Brien 622bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 623bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 624bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 625bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 626bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 627bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 628bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 629bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 630bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 631bfc788c2SDavid E. O'Brien &ring->rx_desc_tag); 632bfc788c2SDavid E. O'Brien if (error != 0) { 633bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 634bfc788c2SDavid E. O'Brien goto fail; 635bfc788c2SDavid E. O'Brien } 636bfc788c2SDavid E. O'Brien 637bfc788c2SDavid E. O'Brien /* allocate memory to desc */ 6382c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_desc_tag, (void **)desc, 6392c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->rx_desc_map); 640bfc788c2SDavid E. O'Brien if (error != 0) { 641bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 642bfc788c2SDavid E. O'Brien goto fail; 643bfc788c2SDavid E. O'Brien } 644bfc788c2SDavid E. O'Brien 645bfc788c2SDavid E. O'Brien /* map desc to device visible address space */ 646bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, *desc, 6472c3adf61SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, 6482c3adf61SDavid E. O'Brien &ring->rx_desc_segs, BUS_DMA_NOWAIT); 649bfc788c2SDavid E. O'Brien if (error != 0) { 650bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 651bfc788c2SDavid E. O'Brien goto fail; 652bfc788c2SDavid E. O'Brien } 653bfc788c2SDavid E. O'Brien 654bfc788c2SDavid E. O'Brien bzero(*desc, NFE_RX_RING_COUNT * descsize); 655bfc788c2SDavid E. O'Brien ring->rx_desc_addr = ring->rx_desc_segs.ds_addr; 656bfc788c2SDavid E. O'Brien ring->physaddr = ring->rx_desc_addr; 657bfc788c2SDavid E. O'Brien 658bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 659bfc788c2SDavid E. O'Brien ring->bufsz = NFE_JBYTES; 660bfc788c2SDavid E. O'Brien if ((error = nfe_jpool_alloc(sc)) != 0) { 6612c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate jumbo frames\n", 6622c3adf61SDavid E. O'Brien sc->nfe_unit); 663bfc788c2SDavid E. O'Brien goto fail; 664bfc788c2SDavid E. O'Brien } 665bfc788c2SDavid E. O'Brien } 666bfc788c2SDavid E. O'Brien 667bfc788c2SDavid E. O'Brien /* 668bfc788c2SDavid E. O'Brien * Pre-allocate Rx buffers and populate Rx ring. 669bfc788c2SDavid E. O'Brien */ 670bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 671bfc788c2SDavid E. O'Brien data = &sc->rxq.data[i]; 672bfc788c2SDavid E. O'Brien 673bfc788c2SDavid E. O'Brien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 674bfc788c2SDavid E. O'Brien if (data->m == NULL) { 6752c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate rx mbuf\n", 6762c3adf61SDavid E. O'Brien sc->nfe_unit); 677bfc788c2SDavid E. O'Brien error = ENOMEM; 678bfc788c2SDavid E. O'Brien goto fail; 679bfc788c2SDavid E. O'Brien } 680bfc788c2SDavid E. O'Brien 681bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 682bfc788c2SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 6832c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate jumbo buffer\n", 6842c3adf61SDavid E. O'Brien sc->nfe_unit); 685bfc788c2SDavid E. O'Brien goto fail; 686bfc788c2SDavid E. O'Brien } 687bfc788c2SDavid E. O'Brien data->m->m_data = (void *)jbuf->buf; 688bfc788c2SDavid E. O'Brien data->m->m_len = data->m->m_pkthdr.len = NFE_JBYTES; 6892c3adf61SDavid E. O'Brien MEXTADD(data->m, jbuf->buf, NFE_JBYTES, nfe_jfree, 6902c3adf61SDavid E. O'Brien (struct nfe_softc *)sc, 0, EXT_NET_DRV); 691bfc788c2SDavid E. O'Brien /* m_adj(data->m, ETHER_ALIGN); */ 692bfc788c2SDavid E. O'Brien physaddr = jbuf->physaddr; 693bfc788c2SDavid E. O'Brien } else { 694bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 695d0220c83SRuslan Ermilov ETHER_ALIGN, 0, /* alignment, boundary */ 696bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 697bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 698bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 699bfc788c2SDavid E. O'Brien MCLBYTES, 1, /* maxsize, nsegments */ 700bfc788c2SDavid E. O'Brien MCLBYTES, /* maxsegsize */ 701bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 702bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 703bfc788c2SDavid E. O'Brien &data->rx_data_tag); 704bfc788c2SDavid E. O'Brien if (error != 0) { 7052c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 7062c3adf61SDavid E. O'Brien sc->nfe_unit); 707bfc788c2SDavid E. O'Brien goto fail; 708bfc788c2SDavid E. O'Brien } 709bfc788c2SDavid E. O'Brien 7102c3adf61SDavid E. O'Brien error = bus_dmamap_create(data->rx_data_tag, 0, 7112c3adf61SDavid E. O'Brien &data->rx_data_map); 712bfc788c2SDavid E. O'Brien if (error != 0) { 7132c3adf61SDavid E. O'Brien printf("nfe%d: could not allocate mbuf cluster\n", 7142c3adf61SDavid E. O'Brien sc->nfe_unit); 715bfc788c2SDavid E. O'Brien goto fail; 716bfc788c2SDavid E. O'Brien } 717bfc788c2SDavid E. O'Brien 718bfc788c2SDavid E. O'Brien MCLGET(data->m, M_DONTWAIT); 719bfc788c2SDavid E. O'Brien if (!(data->m->m_flags & M_EXT)) { 720bfc788c2SDavid E. O'Brien error = ENOMEM; 721bfc788c2SDavid E. O'Brien goto fail; 722bfc788c2SDavid E. O'Brien } 723bfc788c2SDavid E. O'Brien 7242c3adf61SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 7252c3adf61SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), MCLBYTES, 7262c3adf61SDavid E. O'Brien nfe_dma_map_segs, &data->rx_data_segs, 7272c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 728bfc788c2SDavid E. O'Brien if (error != 0) { 7292c3adf61SDavid E. O'Brien printf("nfe%d: could not load rx buf DMA map\n", 7302c3adf61SDavid E. O'Brien sc->nfe_unit); 731bfc788c2SDavid E. O'Brien goto fail; 732bfc788c2SDavid E. O'Brien } 733bfc788c2SDavid E. O'Brien 734bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 735bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 736bfc788c2SDavid E. O'Brien 737bfc788c2SDavid E. O'Brien } 738bfc788c2SDavid E. O'Brien 739bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 740bfc788c2SDavid E. O'Brien desc64 = &sc->rxq.desc64[i]; 741bfc788c2SDavid E. O'Brien #if defined(__LP64__) 742bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 743bfc788c2SDavid E. O'Brien #endif 744bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 745bfc788c2SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 746bfc788c2SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 747bfc788c2SDavid E. O'Brien } else { 748bfc788c2SDavid E. O'Brien desc32 = &sc->rxq.desc32[i]; 749bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 750bfc788c2SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 751bfc788c2SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 752bfc788c2SDavid E. O'Brien } 753bfc788c2SDavid E. O'Brien 754bfc788c2SDavid E. O'Brien } 755bfc788c2SDavid E. O'Brien 7562c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 7572c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 758bfc788c2SDavid E. O'Brien 759bfc788c2SDavid E. O'Brien return 0; 760bfc788c2SDavid E. O'Brien 761bfc788c2SDavid E. O'Brien fail: nfe_free_rx_ring(sc, ring); 762bfc788c2SDavid E. O'Brien 763bfc788c2SDavid E. O'Brien return error; 764bfc788c2SDavid E. O'Brien } 765bfc788c2SDavid E. O'Brien 7662c3adf61SDavid E. O'Brien 767bfc788c2SDavid E. O'Brien static int 768bfc788c2SDavid E. O'Brien nfe_jpool_alloc(struct nfe_softc *sc) 769bfc788c2SDavid E. O'Brien { 770bfc788c2SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 771bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 772bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 773bfc788c2SDavid E. O'Brien caddr_t buf; 774bfc788c2SDavid E. O'Brien int i, error; 775bfc788c2SDavid E. O'Brien 776bfc788c2SDavid E. O'Brien /* 777bfc788c2SDavid E. O'Brien * Allocate a big chunk of DMA'able memory. 778bfc788c2SDavid E. O'Brien */ 779bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 780bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 781bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 782bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 783bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 784bfc788c2SDavid E. O'Brien NFE_JPOOL_SIZE, 1, /* maxsize, nsegments */ 785bfc788c2SDavid E. O'Brien NFE_JPOOL_SIZE, /* maxsegsize */ 786bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 787bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 788bfc788c2SDavid E. O'Brien &ring->rx_jumbo_tag); 789bfc788c2SDavid E. O'Brien if (error != 0) { 790bfc788c2SDavid E. O'Brien printf("nfe%d: could not create jumbo DMA tag\n", sc->nfe_unit); 791bfc788c2SDavid E. O'Brien goto fail; 792bfc788c2SDavid E. O'Brien } 7932c3adf61SDavid E. O'Brien 7942c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_jumbo_tag, (void **)&ring->jpool, 7952c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->rx_jumbo_map); 796bfc788c2SDavid E. O'Brien if (error != 0) { 7972c3adf61SDavid E. O'Brien printf("nfe%d: could not create jumbo DMA memory\n", 7982c3adf61SDavid E. O'Brien sc->nfe_unit); 799bfc788c2SDavid E. O'Brien goto fail; 800bfc788c2SDavid E. O'Brien } 801bfc788c2SDavid E. O'Brien 8022c3adf61SDavid E. O'Brien error = bus_dmamap_load(ring->rx_jumbo_tag, ring->rx_jumbo_map, 8032c3adf61SDavid E. O'Brien ring->jpool, NFE_JPOOL_SIZE, nfe_dma_map_segs, &ring->rx_jumbo_segs, 8042c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 805bfc788c2SDavid E. O'Brien if (error != 0) { 806bfc788c2SDavid E. O'Brien printf("nfe%d: could not load jumbo DMA map\n", sc->nfe_unit); 807bfc788c2SDavid E. O'Brien goto fail; 808bfc788c2SDavid E. O'Brien } 809bfc788c2SDavid E. O'Brien 810bfc788c2SDavid E. O'Brien /* ..and split it into 9KB chunks */ 811bfc788c2SDavid E. O'Brien SLIST_INIT(&ring->jfreelist); 812bfc788c2SDavid E. O'Brien 813bfc788c2SDavid E. O'Brien buf = ring->jpool; 814bfc788c2SDavid E. O'Brien ring->rx_jumbo_addr = ring->rx_jumbo_segs.ds_addr; 815bfc788c2SDavid E. O'Brien physaddr = ring->rx_jumbo_addr; 816bfc788c2SDavid E. O'Brien 817bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_JPOOL_COUNT; i++) { 818bfc788c2SDavid E. O'Brien jbuf = &ring->jbuf[i]; 819bfc788c2SDavid E. O'Brien 820bfc788c2SDavid E. O'Brien jbuf->buf = buf; 821bfc788c2SDavid E. O'Brien jbuf->physaddr = physaddr; 822bfc788c2SDavid E. O'Brien 823bfc788c2SDavid E. O'Brien SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 824bfc788c2SDavid E. O'Brien 825bfc788c2SDavid E. O'Brien buf += NFE_JBYTES; 826bfc788c2SDavid E. O'Brien physaddr += NFE_JBYTES; 827bfc788c2SDavid E. O'Brien } 828bfc788c2SDavid E. O'Brien 829bfc788c2SDavid E. O'Brien return 0; 830bfc788c2SDavid E. O'Brien 831bfc788c2SDavid E. O'Brien fail: nfe_jpool_free(sc); 832bfc788c2SDavid E. O'Brien return error; 833bfc788c2SDavid E. O'Brien } 834bfc788c2SDavid E. O'Brien 835bfc788c2SDavid E. O'Brien 836bfc788c2SDavid E. O'Brien static void 837bfc788c2SDavid E. O'Brien nfe_jpool_free(struct nfe_softc *sc) 838bfc788c2SDavid E. O'Brien { 839bfc788c2SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 840bfc788c2SDavid E. O'Brien 841bfc788c2SDavid E. O'Brien if (ring->jpool != NULL) { 842bfc788c2SDavid E. O'Brien #if 0 8432c3adf61SDavid E. O'Brien bus_dmamem_unmap(ring->rx_jumbo_tag, ring->jpool, 8442c3adf61SDavid E. O'Brien NFE_JPOOL_SIZE); 845bfc788c2SDavid E. O'Brien #endif 8462c3adf61SDavid E. O'Brien bus_dmamem_free(ring->rx_jumbo_tag, &ring->rx_jumbo_segs, 8472c3adf61SDavid E. O'Brien ring->rx_jumbo_map); 848bfc788c2SDavid E. O'Brien } 849bfc788c2SDavid E. O'Brien if (ring->rx_jumbo_map != NULL) { 8502c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_jumbo_tag, ring->rx_jumbo_map, 8512c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 852bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_jumbo_tag, ring->rx_jumbo_map); 853bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->rx_jumbo_tag, ring->rx_jumbo_map); 854bfc788c2SDavid E. O'Brien } 855bfc788c2SDavid E. O'Brien } 856bfc788c2SDavid E. O'Brien 8572c3adf61SDavid E. O'Brien 858bfc788c2SDavid E. O'Brien static struct nfe_jbuf * 859bfc788c2SDavid E. O'Brien nfe_jalloc(struct nfe_softc *sc) 860bfc788c2SDavid E. O'Brien { 861bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 862bfc788c2SDavid E. O'Brien 863bfc788c2SDavid E. O'Brien jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 864bfc788c2SDavid E. O'Brien if (jbuf == NULL) 865bfc788c2SDavid E. O'Brien return NULL; 866bfc788c2SDavid E. O'Brien SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 867bfc788c2SDavid E. O'Brien return jbuf; 868bfc788c2SDavid E. O'Brien } 869bfc788c2SDavid E. O'Brien 8702c3adf61SDavid E. O'Brien 871bfc788c2SDavid E. O'Brien /* 872bfc788c2SDavid E. O'Brien * This is called automatically by the network stack when the mbuf is freed. 873bfc788c2SDavid E. O'Brien * Caution must be taken that the NIC might be reset by the time the mbuf is 874bfc788c2SDavid E. O'Brien * freed. 875bfc788c2SDavid E. O'Brien */ 876bfc788c2SDavid E. O'Brien static void 877bfc788c2SDavid E. O'Brien nfe_jfree(void *buf, void *arg) 878257c5577SDavid E. O'Brien { 879257c5577SDavid E. O'Brien struct nfe_softc *sc = arg; 880bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 881bfc788c2SDavid E. O'Brien int i; 882257c5577SDavid E. O'Brien 883bfc788c2SDavid E. O'Brien /* find the jbuf from the base pointer */ 884bfc788c2SDavid E. O'Brien i = ((vm_offset_t)buf - (vm_offset_t)sc->rxq.jpool) / NFE_JBYTES; 885bfc788c2SDavid E. O'Brien if (i < 0 || i >= NFE_JPOOL_COUNT) { 8862c3adf61SDavid E. O'Brien printf("nfe%d: request to free a buffer (%p) not managed by us\n", 8872c3adf61SDavid E. O'Brien sc->nfe_unit, buf); 888bfc788c2SDavid E. O'Brien return; 889bfc788c2SDavid E. O'Brien } 890bfc788c2SDavid E. O'Brien jbuf = &sc->rxq.jbuf[i]; 891bfc788c2SDavid E. O'Brien 892bfc788c2SDavid E. O'Brien /* ..and put it back in the free list */ 893bfc788c2SDavid E. O'Brien SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext); 894bfc788c2SDavid E. O'Brien } 895bfc788c2SDavid E. O'Brien 896bfc788c2SDavid E. O'Brien 897bfc788c2SDavid E. O'Brien static void 898bfc788c2SDavid E. O'Brien nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 899bfc788c2SDavid E. O'Brien { 900bfc788c2SDavid E. O'Brien int i; 901bfc788c2SDavid E. O'Brien 902bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 903bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 904bfc788c2SDavid E. O'Brien ring->desc64[i].length = htole16(ring->bufsz); 905bfc788c2SDavid E. O'Brien ring->desc64[i].flags = htole16(NFE_RX_READY); 906bfc788c2SDavid E. O'Brien } else { 907bfc788c2SDavid E. O'Brien ring->desc32[i].length = htole16(ring->bufsz); 908bfc788c2SDavid E. O'Brien ring->desc32[i].flags = htole16(NFE_RX_READY); 909bfc788c2SDavid E. O'Brien } 910bfc788c2SDavid E. O'Brien } 911bfc788c2SDavid E. O'Brien 9122c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 9132c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 914bfc788c2SDavid E. O'Brien 915bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 916bfc788c2SDavid E. O'Brien } 917bfc788c2SDavid E. O'Brien 918bfc788c2SDavid E. O'Brien 919bfc788c2SDavid E. O'Brien static void 920bfc788c2SDavid E. O'Brien nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 921bfc788c2SDavid E. O'Brien { 922bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 923bfc788c2SDavid E. O'Brien void *desc; 924bfc788c2SDavid E. O'Brien int i, descsize; 925bfc788c2SDavid E. O'Brien 926bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 927bfc788c2SDavid E. O'Brien desc = ring->desc64; 928bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 929bfc788c2SDavid E. O'Brien } else { 930bfc788c2SDavid E. O'Brien desc = ring->desc32; 931bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 932bfc788c2SDavid E. O'Brien } 933bfc788c2SDavid E. O'Brien 934bfc788c2SDavid E. O'Brien if (desc != NULL) { 9352c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 9362c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 937bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 938bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 939bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->rx_desc_tag); 940bfc788c2SDavid E. O'Brien } 941bfc788c2SDavid E. O'Brien 942bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 943bfc788c2SDavid E. O'Brien nfe_jpool_free(sc); 944bfc788c2SDavid E. O'Brien } else { 945bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 946bfc788c2SDavid E. O'Brien data = &ring->data[i]; 947bfc788c2SDavid E. O'Brien 948bfc788c2SDavid E. O'Brien if (data->rx_data_map != NULL) { 9492c3adf61SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, 9502c3adf61SDavid E. O'Brien data->rx_data_map, BUS_DMASYNC_POSTREAD); 9512c3adf61SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, 9522c3adf61SDavid E. O'Brien data->rx_data_map); 9532c3adf61SDavid E. O'Brien bus_dmamap_destroy(data->rx_data_tag, 9542c3adf61SDavid E. O'Brien data->rx_data_map); 955bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(data->rx_data_tag); 956bfc788c2SDavid E. O'Brien } 9572c3adf61SDavid E. O'Brien 958bfc788c2SDavid E. O'Brien if (data->m != NULL) 959bfc788c2SDavid E. O'Brien m_freem(data->m); 960bfc788c2SDavid E. O'Brien } 961bfc788c2SDavid E. O'Brien } 962bfc788c2SDavid E. O'Brien } 963bfc788c2SDavid E. O'Brien 9642c3adf61SDavid E. O'Brien 965bfc788c2SDavid E. O'Brien static int 966bfc788c2SDavid E. O'Brien nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 967bfc788c2SDavid E. O'Brien { 968bfc788c2SDavid E. O'Brien int i, error; 969bfc788c2SDavid E. O'Brien void **desc; 970bfc788c2SDavid E. O'Brien int descsize; 971bfc788c2SDavid E. O'Brien 972bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 973bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 974bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 975bfc788c2SDavid E. O'Brien } else { 976bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 977bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 978bfc788c2SDavid E. O'Brien } 979bfc788c2SDavid E. O'Brien 980bfc788c2SDavid E. O'Brien ring->queued = 0; 981bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 982bfc788c2SDavid E. O'Brien 983bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 984bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 985bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 986bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 987bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 988bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 989bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 990bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 991bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 992bfc788c2SDavid E. O'Brien &ring->tx_desc_tag); 993bfc788c2SDavid E. O'Brien if (error != 0) { 994bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 995bfc788c2SDavid E. O'Brien goto fail; 996bfc788c2SDavid E. O'Brien } 997bfc788c2SDavid E. O'Brien 9982c3adf61SDavid E. O'Brien error = bus_dmamem_alloc(ring->tx_desc_tag, (void **)desc, 9992c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT, &ring->tx_desc_map); 1000bfc788c2SDavid E. O'Brien if (error != 0) { 1001bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 1002bfc788c2SDavid E. O'Brien goto fail; 1003bfc788c2SDavid E. O'Brien } 1004bfc788c2SDavid E. O'Brien 1005bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, *desc, 10062c3adf61SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->tx_desc_segs, 10072c3adf61SDavid E. O'Brien BUS_DMA_NOWAIT); 1008bfc788c2SDavid E. O'Brien if (error != 0) { 1009bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 1010bfc788c2SDavid E. O'Brien goto fail; 1011bfc788c2SDavid E. O'Brien } 1012bfc788c2SDavid E. O'Brien 1013bfc788c2SDavid E. O'Brien bzero(*desc, NFE_TX_RING_COUNT * descsize); 1014bfc788c2SDavid E. O'Brien 1015bfc788c2SDavid E. O'Brien ring->tx_desc_addr = ring->tx_desc_segs.ds_addr; 1016bfc788c2SDavid E. O'Brien ring->physaddr = ring->tx_desc_addr; 1017bfc788c2SDavid E. O'Brien 1018bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 1019bfc788c2SDavid E. O'Brien ETHER_ALIGN, 0, 1020bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, 1021bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, 1022bfc788c2SDavid E. O'Brien NULL, NULL, 1023bfc788c2SDavid E. O'Brien NFE_JBYTES, NFE_MAX_SCATTER, 1024bfc788c2SDavid E. O'Brien NFE_JBYTES, 1025bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, 1026bfc788c2SDavid E. O'Brien NULL, NULL, 1027bfc788c2SDavid E. O'Brien &ring->tx_data_tag); 1028bfc788c2SDavid E. O'Brien if (error != 0) { 1029bfc788c2SDavid E. O'Brien printf("nfe%d: could not create DMA tag\n", sc->nfe_unit); 1030bfc788c2SDavid E. O'Brien goto fail; 1031bfc788c2SDavid E. O'Brien } 1032bfc788c2SDavid E. O'Brien 1033bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 10342c3adf61SDavid E. O'Brien error = bus_dmamap_create(ring->tx_data_tag, 0, 10352c3adf61SDavid E. O'Brien &ring->data[i].tx_data_map); 1036bfc788c2SDavid E. O'Brien if (error != 0) { 10372c3adf61SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", 10382c3adf61SDavid E. O'Brien sc->nfe_unit); 1039bfc788c2SDavid E. O'Brien goto fail; 1040bfc788c2SDavid E. O'Brien } 1041bfc788c2SDavid E. O'Brien } 1042bfc788c2SDavid E. O'Brien 1043bfc788c2SDavid E. O'Brien return 0; 1044bfc788c2SDavid E. O'Brien 1045bfc788c2SDavid E. O'Brien fail: nfe_free_tx_ring(sc, ring); 1046bfc788c2SDavid E. O'Brien return error; 1047bfc788c2SDavid E. O'Brien } 1048bfc788c2SDavid E. O'Brien 1049bfc788c2SDavid E. O'Brien 1050bfc788c2SDavid E. O'Brien static void 1051bfc788c2SDavid E. O'Brien nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1052bfc788c2SDavid E. O'Brien { 1053bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 1054bfc788c2SDavid E. O'Brien int i; 1055bfc788c2SDavid E. O'Brien 1056bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1057bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1058bfc788c2SDavid E. O'Brien ring->desc64[i].flags = 0; 1059bfc788c2SDavid E. O'Brien else 1060bfc788c2SDavid E. O'Brien ring->desc32[i].flags = 0; 1061bfc788c2SDavid E. O'Brien 1062bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1063bfc788c2SDavid E. O'Brien 1064bfc788c2SDavid E. O'Brien if (data->m != NULL) { 10652c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 10662c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1067bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 1068bfc788c2SDavid E. O'Brien m_freem(data->m); 1069bfc788c2SDavid E. O'Brien data->m = NULL; 1070bfc788c2SDavid E. O'Brien } 1071bfc788c2SDavid E. O'Brien } 1072bfc788c2SDavid E. O'Brien 10732c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 10742c3adf61SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 1075bfc788c2SDavid E. O'Brien 1076bfc788c2SDavid E. O'Brien ring->queued = 0; 1077bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 1078bfc788c2SDavid E. O'Brien } 1079bfc788c2SDavid E. O'Brien 10802c3adf61SDavid E. O'Brien 1081bfc788c2SDavid E. O'Brien static void 1082bfc788c2SDavid E. O'Brien nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1083bfc788c2SDavid E. O'Brien { 1084bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 1085bfc788c2SDavid E. O'Brien void *desc; 1086bfc788c2SDavid E. O'Brien int i, descsize; 1087bfc788c2SDavid E. O'Brien 1088bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1089bfc788c2SDavid E. O'Brien desc = ring->desc64; 1090bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1091bfc788c2SDavid E. O'Brien } else { 1092bfc788c2SDavid E. O'Brien desc = ring->desc32; 1093bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1094bfc788c2SDavid E. O'Brien } 1095bfc788c2SDavid E. O'Brien 1096bfc788c2SDavid E. O'Brien if (desc != NULL) { 10972c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 10982c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1099bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1100bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1101bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_desc_tag); 1102bfc788c2SDavid E. O'Brien } 1103bfc788c2SDavid E. O'Brien 1104bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1105bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1106bfc788c2SDavid E. O'Brien 1107bfc788c2SDavid E. O'Brien if (data->m != NULL) { 11082c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, 11092c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1110bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 1111bfc788c2SDavid E. O'Brien m_freem(data->m); 1112bfc788c2SDavid E. O'Brien } 1113bfc788c2SDavid E. O'Brien } 1114bfc788c2SDavid E. O'Brien 1115bfc788c2SDavid E. O'Brien /* ..and now actually destroy the DMA mappings */ 1116bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1117bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1118bfc788c2SDavid E. O'Brien if (data->tx_data_map == NULL) 1119bfc788c2SDavid E. O'Brien continue; 1120bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->tx_data_tag, data->tx_data_map); 1121bfc788c2SDavid E. O'Brien } 1122bfc788c2SDavid E. O'Brien 1123bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_data_tag); 1124bfc788c2SDavid E. O'Brien } 1125bfc788c2SDavid E. O'Brien 1126bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1127bfc788c2SDavid E. O'Brien static poll_handler_t nfe_poll; 1128bfc788c2SDavid E. O'Brien 11292c3adf61SDavid E. O'Brien 1130bfc788c2SDavid E. O'Brien static void 1131bfc788c2SDavid E. O'Brien nfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1132bfc788c2SDavid E. O'Brien { 1133bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1134bfc788c2SDavid E. O'Brien 1135bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1136bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1137bfc788c2SDavid E. O'Brien nfe_poll_locked(ifp, cmd, count); 1138bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1139bfc788c2SDavid E. O'Brien } 1140bfc788c2SDavid E. O'Brien 1141bfc788c2SDavid E. O'Brien 1142bfc788c2SDavid E. O'Brien static void 1143bfc788c2SDavid E. O'Brien nfe_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1144bfc788c2SDavid E. O'Brien { 1145bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1146bfc788c2SDavid E. O'Brien u_int32_t r; 1147bfc788c2SDavid E. O'Brien 1148bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1149bfc788c2SDavid E. O'Brien 1150bfc788c2SDavid E. O'Brien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1151bfc788c2SDavid E. O'Brien return; 1152bfc788c2SDavid E. O'Brien } 1153bfc788c2SDavid E. O'Brien 1154bfc788c2SDavid E. O'Brien sc->rxcycles = count; 1155bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1156bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1157bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1158bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1159bfc788c2SDavid E. O'Brien 1160bfc788c2SDavid E. O'Brien if (cmd == POLL_AND_CHECK_STATUS) { 1161bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1162bfc788c2SDavid E. O'Brien return; 1163bfc788c2SDavid E. O'Brien } 1164257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1165257c5577SDavid E. O'Brien 1166257c5577SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1167257c5577SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1168257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1169bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1170257c5577SDavid E. O'Brien } 1171257c5577SDavid E. O'Brien } 1172257c5577SDavid E. O'Brien } 1173bfc788c2SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1174257c5577SDavid E. O'Brien 1175bfc788c2SDavid E. O'Brien 1176bfc788c2SDavid E. O'Brien static int 1177257c5577SDavid E. O'Brien nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1178257c5577SDavid E. O'Brien { 1179257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1180257c5577SDavid E. O'Brien struct ifreq *ifr = (struct ifreq *) data; 1181bfc788c2SDavid E. O'Brien struct mii_data *mii; 11822c3adf61SDavid E. O'Brien int error = 0; 1183257c5577SDavid E. O'Brien 1184257c5577SDavid E. O'Brien switch (cmd) { 1185257c5577SDavid E. O'Brien case SIOCSIFMTU: 1186257c5577SDavid E. O'Brien if (ifr->ifr_mtu < ETHERMIN || 1187bfc788c2SDavid E. O'Brien ((sc->nfe_flags & NFE_USE_JUMBO) && 1188257c5577SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU_JUMBO) || 1189bfc788c2SDavid E. O'Brien (!(sc->nfe_flags & NFE_USE_JUMBO) && 11902c3adf61SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU)) { 1191257c5577SDavid E. O'Brien error = EINVAL; 11922c3adf61SDavid E. O'Brien } else if (ifp->if_mtu != ifr->ifr_mtu) { 1193257c5577SDavid E. O'Brien ifp->if_mtu = ifr->ifr_mtu; 1194bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1195bfc788c2SDavid E. O'Brien nfe_init(sc); 1196bfc788c2SDavid E. O'Brien } 1197257c5577SDavid E. O'Brien break; 1198257c5577SDavid E. O'Brien case SIOCSIFFLAGS: 1199bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1200257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 1201257c5577SDavid E. O'Brien /* 1202257c5577SDavid E. O'Brien * If only the PROMISC or ALLMULTI flag changes, then 1203257c5577SDavid E. O'Brien * don't do a full re-init of the chip, just update 1204257c5577SDavid E. O'Brien * the Rx filter. 1205257c5577SDavid E. O'Brien */ 1206bfc788c2SDavid E. O'Brien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1207bfc788c2SDavid E. O'Brien ((ifp->if_flags ^ sc->nfe_if_flags) & 1208bfc788c2SDavid E. O'Brien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1209257c5577SDavid E. O'Brien nfe_setmulti(sc); 1210bfc788c2SDavid E. O'Brien else 1211bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1212257c5577SDavid E. O'Brien } else { 1213bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1214257c5577SDavid E. O'Brien nfe_stop(ifp, 1); 1215257c5577SDavid E. O'Brien } 1216bfc788c2SDavid E. O'Brien sc->nfe_if_flags = ifp->if_flags; 1217bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1218bfc788c2SDavid E. O'Brien error = 0; 1219257c5577SDavid E. O'Brien break; 1220257c5577SDavid E. O'Brien case SIOCADDMULTI: 1221257c5577SDavid E. O'Brien case SIOCDELMULTI: 1222bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1223bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1224257c5577SDavid E. O'Brien nfe_setmulti(sc); 1225bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1226257c5577SDavid E. O'Brien error = 0; 1227257c5577SDavid E. O'Brien } 1228257c5577SDavid E. O'Brien break; 1229257c5577SDavid E. O'Brien case SIOCSIFMEDIA: 1230257c5577SDavid E. O'Brien case SIOCGIFMEDIA: 1231bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1232bfc788c2SDavid E. O'Brien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1233257c5577SDavid E. O'Brien break; 1234bfc788c2SDavid E. O'Brien case SIOCSIFCAP: 1235bfc788c2SDavid E. O'Brien { 1236bfc788c2SDavid E. O'Brien int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1237bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1238bfc788c2SDavid E. O'Brien if (mask & IFCAP_POLLING) { 1239bfc788c2SDavid E. O'Brien if (ifr->ifr_reqcap & IFCAP_POLLING) { 1240bfc788c2SDavid E. O'Brien error = ether_poll_register(nfe_poll, ifp); 1241bfc788c2SDavid E. O'Brien if (error) 1242bfc788c2SDavid E. O'Brien return(error); 1243bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1244bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1245bfc788c2SDavid E. O'Brien ifp->if_capenable |= IFCAP_POLLING; 1246bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1247bfc788c2SDavid E. O'Brien } else { 1248bfc788c2SDavid E. O'Brien error = ether_poll_deregister(ifp); 1249bfc788c2SDavid E. O'Brien /* Enable interrupt even in error case */ 1250bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1251bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1252bfc788c2SDavid E. O'Brien ifp->if_capenable &= ~IFCAP_POLLING; 1253bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1254257c5577SDavid E. O'Brien } 1255bfc788c2SDavid E. O'Brien } 12562c3adf61SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1257bfc788c2SDavid E. O'Brien if (mask & IFCAP_HWCSUM) { 1258bfc788c2SDavid E. O'Brien ifp->if_capenable ^= IFCAP_HWCSUM; 1259bfc788c2SDavid E. O'Brien if (IFCAP_HWCSUM & ifp->if_capenable && 1260bfc788c2SDavid E. O'Brien IFCAP_HWCSUM & ifp->if_capabilities) 1261bfc788c2SDavid E. O'Brien ifp->if_hwassist = NFE_CSUM_FEATURES; 1262bfc788c2SDavid E. O'Brien else 1263bfc788c2SDavid E. O'Brien ifp->if_hwassist = 0; 1264bfc788c2SDavid E. O'Brien } 1265bfc788c2SDavid E. O'Brien } 1266bfc788c2SDavid E. O'Brien break; 1267257c5577SDavid E. O'Brien 1268bfc788c2SDavid E. O'Brien default: 1269bfc788c2SDavid E. O'Brien error = ether_ioctl(ifp, cmd, data); 1270bfc788c2SDavid E. O'Brien break; 1271bfc788c2SDavid E. O'Brien } 1272257c5577SDavid E. O'Brien 1273257c5577SDavid E. O'Brien return error; 1274257c5577SDavid E. O'Brien } 1275257c5577SDavid E. O'Brien 1276bfc788c2SDavid E. O'Brien 12772c3adf61SDavid E. O'Brien static void 12782c3adf61SDavid E. O'Brien nfe_intr(void *arg) 1279bfc788c2SDavid E. O'Brien { 1280bfc788c2SDavid E. O'Brien struct nfe_softc *sc = arg; 1281bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1282bfc788c2SDavid E. O'Brien u_int32_t r; 1283bfc788c2SDavid E. O'Brien 1284bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1285bfc788c2SDavid E. O'Brien 1286bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1287bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1288bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1289bfc788c2SDavid E. O'Brien return; 1290bfc788c2SDavid E. O'Brien } 1291bfc788c2SDavid E. O'Brien #endif 1292bfc788c2SDavid E. O'Brien 1293bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1294bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1295bfc788c2SDavid E. O'Brien return; /* not for us */ 1296bfc788c2SDavid E. O'Brien } 1297bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1298bfc788c2SDavid E. O'Brien 1299bfc788c2SDavid E. O'Brien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 1300bfc788c2SDavid E. O'Brien 1301bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1302bfc788c2SDavid E. O'Brien 1303bfc788c2SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1304bfc788c2SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1305bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1306bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1307bfc788c2SDavid E. O'Brien } 1308bfc788c2SDavid E. O'Brien 1309bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1310bfc788c2SDavid E. O'Brien /* check Rx ring */ 1311bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1312bfc788c2SDavid E. O'Brien /* check Tx ring */ 1313bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1314bfc788c2SDavid E. O'Brien } 1315bfc788c2SDavid E. O'Brien 1316bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1317bfc788c2SDavid E. O'Brien 1318bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1319bfc788c2SDavid E. O'Brien !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1320bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1321bfc788c2SDavid E. O'Brien 1322bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1323bfc788c2SDavid E. O'Brien 1324bfc788c2SDavid E. O'Brien return; 1325bfc788c2SDavid E. O'Brien } 1326bfc788c2SDavid E. O'Brien 13272c3adf61SDavid E. O'Brien 1328bfc788c2SDavid E. O'Brien static void 1329257c5577SDavid E. O'Brien nfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1330257c5577SDavid E. O'Brien { 13312c3adf61SDavid E. O'Brien 1332bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1333257c5577SDavid E. O'Brien } 1334257c5577SDavid E. O'Brien 13352c3adf61SDavid E. O'Brien 1336bfc788c2SDavid E. O'Brien static void 1337257c5577SDavid E. O'Brien nfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1338257c5577SDavid E. O'Brien { 13392c3adf61SDavid E. O'Brien 1340bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1341257c5577SDavid E. O'Brien } 1342257c5577SDavid E. O'Brien 13432c3adf61SDavid E. O'Brien 1344bfc788c2SDavid E. O'Brien static void 1345257c5577SDavid E. O'Brien nfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 1346257c5577SDavid E. O'Brien { 13472c3adf61SDavid E. O'Brien 1348bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1349257c5577SDavid E. O'Brien } 1350257c5577SDavid E. O'Brien 13512c3adf61SDavid E. O'Brien 1352bfc788c2SDavid E. O'Brien static void 1353257c5577SDavid E. O'Brien nfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 1354257c5577SDavid E. O'Brien { 13552c3adf61SDavid E. O'Brien 1356bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1357257c5577SDavid E. O'Brien } 1358257c5577SDavid E. O'Brien 13592c3adf61SDavid E. O'Brien 1360bfc788c2SDavid E. O'Brien static void 1361257c5577SDavid E. O'Brien nfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1362257c5577SDavid E. O'Brien { 13632c3adf61SDavid E. O'Brien 1364bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1365257c5577SDavid E. O'Brien } 1366257c5577SDavid E. O'Brien 13672c3adf61SDavid E. O'Brien 1368bfc788c2SDavid E. O'Brien static void 1369257c5577SDavid E. O'Brien nfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1370257c5577SDavid E. O'Brien { 1371bfc788c2SDavid E. O'Brien 1372bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1373257c5577SDavid E. O'Brien } 1374257c5577SDavid E. O'Brien 13752c3adf61SDavid E. O'Brien 13762c3adf61SDavid E. O'Brien static void 13772c3adf61SDavid E. O'Brien nfe_rxeof(struct nfe_softc *sc) 1378257c5577SDavid E. O'Brien { 1379bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1380bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1381bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1382257c5577SDavid E. O'Brien struct nfe_rx_data *data; 1383257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 1384257c5577SDavid E. O'Brien struct mbuf *m, *mnew; 1385257c5577SDavid E. O'Brien bus_addr_t physaddr; 1386bfc788c2SDavid E. O'Brien u_int16_t flags; 1387257c5577SDavid E. O'Brien int error, len; 1388bfc788c2SDavid E. O'Brien #if NVLAN > 1 1389bfc788c2SDavid E. O'Brien u_int16_t vlan_tag = 0; 1390bfc788c2SDavid E. O'Brien int have_tag = 0; 1391bfc788c2SDavid E. O'Brien #endif 1392bfc788c2SDavid E. O'Brien 1393bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1394257c5577SDavid E. O'Brien 1395257c5577SDavid E. O'Brien for (;;) { 1396bfc788c2SDavid E. O'Brien 1397bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1398bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1399bfc788c2SDavid E. O'Brien if (sc->rxcycles <= 0) 1400bfc788c2SDavid E. O'Brien break; 1401bfc788c2SDavid E. O'Brien sc->rxcycles--; 1402bfc788c2SDavid E. O'Brien } 1403bfc788c2SDavid E. O'Brien #endif 1404bfc788c2SDavid E. O'Brien 1405257c5577SDavid E. O'Brien data = &sc->rxq.data[sc->rxq.cur]; 1406257c5577SDavid E. O'Brien 1407bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1408257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 1409257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1410257c5577SDavid E. O'Brien 1411257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1412257c5577SDavid E. O'Brien len = letoh16(desc64->length) & 0x3fff; 1413bfc788c2SDavid E. O'Brien 1414bfc788c2SDavid E. O'Brien #if NVLAN > 1 1415bfc788c2SDavid E. O'Brien if (flags & NFE_TX_VLAN_TAG) { 1416bfc788c2SDavid E. O'Brien have_tag = 1; 1417bfc788c2SDavid E. O'Brien vlan_tag = desc64->vtag; 1418bfc788c2SDavid E. O'Brien } 1419bfc788c2SDavid E. O'Brien #endif 1420bfc788c2SDavid E. O'Brien 1421257c5577SDavid E. O'Brien } else { 1422257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 1423257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1424257c5577SDavid E. O'Brien 1425257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1426257c5577SDavid E. O'Brien len = letoh16(desc32->length) & 0x3fff; 1427257c5577SDavid E. O'Brien } 1428257c5577SDavid E. O'Brien 1429257c5577SDavid E. O'Brien if (flags & NFE_RX_READY) 1430257c5577SDavid E. O'Brien break; 1431257c5577SDavid E. O'Brien 1432bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1433257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V1)) 1434257c5577SDavid E. O'Brien goto skip; 1435257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 1436257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1437257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1438257c5577SDavid E. O'Brien } 1439257c5577SDavid E. O'Brien } else { 1440257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V2)) 1441257c5577SDavid E. O'Brien goto skip; 1442257c5577SDavid E. O'Brien 1443257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 1444257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1445257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1446257c5577SDavid E. O'Brien } 1447257c5577SDavid E. O'Brien } 1448257c5577SDavid E. O'Brien 1449257c5577SDavid E. O'Brien if (flags & NFE_RX_ERROR) { 1450257c5577SDavid E. O'Brien ifp->if_ierrors++; 1451257c5577SDavid E. O'Brien goto skip; 1452257c5577SDavid E. O'Brien } 1453257c5577SDavid E. O'Brien 1454257c5577SDavid E. O'Brien /* 1455257c5577SDavid E. O'Brien * Try to allocate a new mbuf for this ring element and load 1456257c5577SDavid E. O'Brien * it before processing the current mbuf. If the ring element 1457257c5577SDavid E. O'Brien * cannot be loaded, drop the received packet and reuse the 1458257c5577SDavid E. O'Brien * old mbuf. In the unlikely case that the old mbuf can't be 1459257c5577SDavid E. O'Brien * reloaded either, explicitly panic. 1460257c5577SDavid E. O'Brien */ 1461257c5577SDavid E. O'Brien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 1462257c5577SDavid E. O'Brien if (mnew == NULL) { 1463257c5577SDavid E. O'Brien ifp->if_ierrors++; 1464257c5577SDavid E. O'Brien goto skip; 1465257c5577SDavid E. O'Brien } 1466257c5577SDavid E. O'Brien 1467bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 1468257c5577SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 1469257c5577SDavid E. O'Brien m_freem(mnew); 1470257c5577SDavid E. O'Brien ifp->if_ierrors++; 1471257c5577SDavid E. O'Brien goto skip; 1472257c5577SDavid E. O'Brien } 1473bfc788c2SDavid E. O'Brien mnew->m_data = (void *)jbuf->buf; 1474bfc788c2SDavid E. O'Brien mnew->m_len = mnew->m_pkthdr.len = NFE_JBYTES; 1475bfc788c2SDavid E. O'Brien MEXTADD(mnew, jbuf->buf, NFE_JBYTES, nfe_jfree, 1476bfc788c2SDavid E. O'Brien (struct nfe_softc *)sc, 0 , EXT_NET_DRV); 1477257c5577SDavid E. O'Brien 1478bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_jumbo_tag, 1479bfc788c2SDavid E. O'Brien sc->rxq.rx_jumbo_map, BUS_DMASYNC_POSTREAD); 1480257c5577SDavid E. O'Brien physaddr = jbuf->physaddr; 1481257c5577SDavid E. O'Brien } else { 1482257c5577SDavid E. O'Brien MCLGET(mnew, M_DONTWAIT); 1483257c5577SDavid E. O'Brien if (!(mnew->m_flags & M_EXT)) { 1484257c5577SDavid E. O'Brien m_freem(mnew); 1485257c5577SDavid E. O'Brien ifp->if_ierrors++; 1486257c5577SDavid E. O'Brien goto skip; 1487257c5577SDavid E. O'Brien } 1488257c5577SDavid E. O'Brien 1489bfc788c2SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, 1490bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTREAD); 1491bfc788c2SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 1492bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1493bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(mnew, void *), MCLBYTES, 1494bfc788c2SDavid E. O'Brien nfe_dma_map_segs, &data->rx_data_segs, 1495bfc788c2SDavid E. O'Brien BUS_DMA_NOWAIT); 1496257c5577SDavid E. O'Brien if (error != 0) { 1497257c5577SDavid E. O'Brien m_freem(mnew); 1498257c5577SDavid E. O'Brien 1499257c5577SDavid E. O'Brien /* try to reload the old mbuf */ 1500bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1501bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), 1502bfc788c2SDavid E. O'Brien MCLBYTES, nfe_dma_map_segs, 1503bfc788c2SDavid E. O'Brien &data->rx_data_segs, BUS_DMA_NOWAIT); 1504257c5577SDavid E. O'Brien if (error != 0) { 1505257c5577SDavid E. O'Brien /* very unlikely that it will fail.. */ 1506bfc788c2SDavid E. O'Brien panic("nfe%d: could not load old rx mbuf", 1507bfc788c2SDavid E. O'Brien sc->nfe_unit); 1508257c5577SDavid E. O'Brien } 1509257c5577SDavid E. O'Brien ifp->if_ierrors++; 1510257c5577SDavid E. O'Brien goto skip; 1511257c5577SDavid E. O'Brien } 1512bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 1513bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 1514257c5577SDavid E. O'Brien } 1515257c5577SDavid E. O'Brien 1516257c5577SDavid E. O'Brien /* 1517257c5577SDavid E. O'Brien * New mbuf successfully loaded, update Rx ring and continue 1518257c5577SDavid E. O'Brien * processing. 1519257c5577SDavid E. O'Brien */ 1520257c5577SDavid E. O'Brien m = data->m; 1521257c5577SDavid E. O'Brien data->m = mnew; 1522257c5577SDavid E. O'Brien 1523257c5577SDavid E. O'Brien /* finalize mbuf */ 1524257c5577SDavid E. O'Brien m->m_pkthdr.len = m->m_len = len; 1525257c5577SDavid E. O'Brien m->m_pkthdr.rcvif = ifp; 1526257c5577SDavid E. O'Brien 1527bfc788c2SDavid E. O'Brien 1528bfc788c2SDavid E. O'Brien #if defined(NFE_CSUM) 1529bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) { 1530bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1531bfc788c2SDavid E. O'Brien if (flags & NFE_RX_IP_CSUMOK_V2) { 1532bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1533257c5577SDavid E. O'Brien } 1534bfc788c2SDavid E. O'Brien if (flags & NFE_RX_UDP_CSUMOK_V2 || 1535bfc788c2SDavid E. O'Brien flags & NFE_RX_TCP_CSUMOK_V2) { 1536bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= 1537bfc788c2SDavid E. O'Brien CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 1538bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_data = 0xffff; 1539bfc788c2SDavid E. O'Brien } 1540bfc788c2SDavid E. O'Brien } 1541257c5577SDavid E. O'Brien #endif 1542257c5577SDavid E. O'Brien 1543bfc788c2SDavid E. O'Brien #if NVLAN > 1 1544bfc788c2SDavid E. O'Brien if (have_tag) { 154578ba57b9SAndre Oppermann m->m_pkthdr.ether_vtag = vlan_tag; 154678ba57b9SAndre Oppermann m->m_flags |= M_VLANTAG; 1547bfc788c2SDavid E. O'Brien } 1548257c5577SDavid E. O'Brien #endif 1549bfc788c2SDavid E. O'Brien 1550257c5577SDavid E. O'Brien ifp->if_ipackets++; 1551bfc788c2SDavid E. O'Brien 1552bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1553bfc788c2SDavid E. O'Brien (*ifp->if_input)(ifp, m); 1554bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1555257c5577SDavid E. O'Brien 1556257c5577SDavid E. O'Brien /* update mapping address in h/w descriptor */ 1557bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1558257c5577SDavid E. O'Brien #if defined(__LP64__) 1559257c5577SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 1560257c5577SDavid E. O'Brien #endif 1561257c5577SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1562257c5577SDavid E. O'Brien } else { 1563257c5577SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 1564257c5577SDavid E. O'Brien } 1565257c5577SDavid E. O'Brien 1566bfc788c2SDavid E. O'Brien skip: if (sc->nfe_flags & NFE_40BIT_ADDR) { 1567257c5577SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 1568257c5577SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 1569257c5577SDavid E. O'Brien 1570257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 1571257c5577SDavid E. O'Brien } else { 1572257c5577SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 1573257c5577SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 1574257c5577SDavid E. O'Brien 1575257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 1576257c5577SDavid E. O'Brien } 1577257c5577SDavid E. O'Brien 1578257c5577SDavid E. O'Brien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 1579257c5577SDavid E. O'Brien } 1580257c5577SDavid E. O'Brien } 1581257c5577SDavid E. O'Brien 15822c3adf61SDavid E. O'Brien 15832c3adf61SDavid E. O'Brien static void 15842c3adf61SDavid E. O'Brien nfe_txeof(struct nfe_softc *sc) 1585257c5577SDavid E. O'Brien { 1586bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1587257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 1588257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 1589257c5577SDavid E. O'Brien struct nfe_tx_data *data = NULL; 1590bfc788c2SDavid E. O'Brien u_int16_t flags; 1591bfc788c2SDavid E. O'Brien 1592bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1593257c5577SDavid E. O'Brien 1594257c5577SDavid E. O'Brien while (sc->txq.next != sc->txq.cur) { 1595bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1596257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.next]; 1597257c5577SDavid E. O'Brien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1598257c5577SDavid E. O'Brien 1599257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1600257c5577SDavid E. O'Brien } else { 1601257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.next]; 1602257c5577SDavid E. O'Brien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1603257c5577SDavid E. O'Brien 1604257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1605257c5577SDavid E. O'Brien } 1606257c5577SDavid E. O'Brien 1607257c5577SDavid E. O'Brien if (flags & NFE_TX_VALID) 1608257c5577SDavid E. O'Brien break; 1609257c5577SDavid E. O'Brien 1610257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.next]; 1611257c5577SDavid E. O'Brien 1612bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1613257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 1614257c5577SDavid E. O'Brien goto skip; 1615257c5577SDavid E. O'Brien 1616257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V1) != 0) { 1617bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1618bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V1_TXERR); 1619bfc788c2SDavid E. O'Brien 1620257c5577SDavid E. O'Brien ifp->if_oerrors++; 1621257c5577SDavid E. O'Brien } else 1622257c5577SDavid E. O'Brien ifp->if_opackets++; 1623257c5577SDavid E. O'Brien } else { 1624257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 1625257c5577SDavid E. O'Brien goto skip; 1626257c5577SDavid E. O'Brien 1627257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V2) != 0) { 1628bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1629bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V2_TXERR); 1630bfc788c2SDavid E. O'Brien 1631257c5577SDavid E. O'Brien ifp->if_oerrors++; 1632257c5577SDavid E. O'Brien } else 1633257c5577SDavid E. O'Brien ifp->if_opackets++; 1634257c5577SDavid E. O'Brien } 1635257c5577SDavid E. O'Brien 1636257c5577SDavid E. O'Brien if (data->m == NULL) { /* should not get there */ 1637bfc788c2SDavid E. O'Brien printf("nfe%d: last fragment bit w/o associated mbuf!\n", 1638bfc788c2SDavid E. O'Brien sc->nfe_unit); 1639257c5577SDavid E. O'Brien goto skip; 1640257c5577SDavid E. O'Brien } 1641257c5577SDavid E. O'Brien 1642257c5577SDavid E. O'Brien /* last fragment of the mbuf chain transmitted */ 1643bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, data->active, 1644bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1645bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, data->active); 1646257c5577SDavid E. O'Brien m_freem(data->m); 1647257c5577SDavid E. O'Brien data->m = NULL; 1648257c5577SDavid E. O'Brien 1649257c5577SDavid E. O'Brien ifp->if_timer = 0; 1650257c5577SDavid E. O'Brien 1651257c5577SDavid E. O'Brien skip: sc->txq.queued--; 1652257c5577SDavid E. O'Brien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 1653257c5577SDavid E. O'Brien } 1654257c5577SDavid E. O'Brien 1655257c5577SDavid E. O'Brien if (data != NULL) { /* at least one slot freed */ 1656bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1657bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1658257c5577SDavid E. O'Brien } 1659257c5577SDavid E. O'Brien } 1660257c5577SDavid E. O'Brien 16612c3adf61SDavid E. O'Brien 16622c3adf61SDavid E. O'Brien static int 16632c3adf61SDavid E. O'Brien nfe_encap(struct nfe_softc *sc, struct mbuf *m0) 1664257c5577SDavid E. O'Brien { 1665bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1666bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1667bfc788c2SDavid E. O'Brien struct nfe_tx_data *data=NULL; 1668257c5577SDavid E. O'Brien bus_dmamap_t map; 1669bfc788c2SDavid E. O'Brien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 16702c3adf61SDavid E. O'Brien int error, i, nsegs; 16712c3adf61SDavid E. O'Brien u_int16_t flags = NFE_TX_VALID; 1672257c5577SDavid E. O'Brien 1673bfc788c2SDavid E. O'Brien map = sc->txq.data[sc->txq.cur].tx_data_map; 1674257c5577SDavid E. O'Brien 1675bfc788c2SDavid E. O'Brien error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, m0, segs, 1676bfc788c2SDavid E. O'Brien &nsegs, BUS_DMA_NOWAIT); 1677bfc788c2SDavid E. O'Brien 1678257c5577SDavid E. O'Brien if (error != 0) { 1679bfc788c2SDavid E. O'Brien printf("nfe%d: could not map mbuf (error %d)\n", sc->nfe_unit, 1680bfc788c2SDavid E. O'Brien error); 1681257c5577SDavid E. O'Brien return error; 1682257c5577SDavid E. O'Brien } 1683257c5577SDavid E. O'Brien 1684bfc788c2SDavid E. O'Brien if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 1) { 1685bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, map); 1686257c5577SDavid E. O'Brien return ENOBUFS; 1687257c5577SDavid E. O'Brien } 1688257c5577SDavid E. O'Brien 1689bfc788c2SDavid E. O'Brien 1690257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1691bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_IP) 1692257c5577SDavid E. O'Brien flags |= NFE_TX_IP_CSUM; 1693bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_TCP) 1694bfc788c2SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1695bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_UDP) 1696257c5577SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1697257c5577SDavid E. O'Brien #endif 1698257c5577SDavid E. O'Brien 1699bfc788c2SDavid E. O'Brien for (i = 0; i < nsegs; i++) { 1700257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.cur]; 1701257c5577SDavid E. O'Brien 1702bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1703257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.cur]; 1704257c5577SDavid E. O'Brien #if defined(__LP64__) 1705bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(segs[i].ds_addr >> 32); 1706257c5577SDavid E. O'Brien #endif 1707bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(segs[i].ds_addr & 1708bfc788c2SDavid E. O'Brien 0xffffffff); 1709bfc788c2SDavid E. O'Brien desc64->length = htole16(segs[i].ds_len - 1); 1710257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1711257c5577SDavid E. O'Brien #if NVLAN > 0 171278ba57b9SAndre Oppermann if (m0->m_flags & M_VLANTAG) 1713bfc788c2SDavid E. O'Brien desc64->vtag = htole32(NFE_TX_VTAG | 171478ba57b9SAndre Oppermann m0->m_pkthdr.ether_vtag); 1715257c5577SDavid E. O'Brien #endif 1716257c5577SDavid E. O'Brien } else { 1717257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.cur]; 1718257c5577SDavid E. O'Brien 1719bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(segs[i].ds_addr); 1720bfc788c2SDavid E. O'Brien desc32->length = htole16(segs[i].ds_len - 1); 1721257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1722257c5577SDavid E. O'Brien } 1723257c5577SDavid E. O'Brien 1724257c5577SDavid E. O'Brien /* csum flags and vtag belong to the first fragment only */ 1725bfc788c2SDavid E. O'Brien if (nsegs > 1) { 1726257c5577SDavid E. O'Brien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 1727257c5577SDavid E. O'Brien } 1728257c5577SDavid E. O'Brien 1729257c5577SDavid E. O'Brien sc->txq.queued++; 1730257c5577SDavid E. O'Brien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 1731257c5577SDavid E. O'Brien } 1732257c5577SDavid E. O'Brien 1733257c5577SDavid E. O'Brien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 1734bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1735257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1736257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1737257c5577SDavid E. O'Brien } else { 1738bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 1739257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1740257c5577SDavid E. O'Brien else 1741257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V1; 1742257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1743257c5577SDavid E. O'Brien } 1744257c5577SDavid E. O'Brien 1745257c5577SDavid E. O'Brien data->m = m0; 1746257c5577SDavid E. O'Brien data->active = map; 1747bfc788c2SDavid E. O'Brien data->nsegs = nsegs; 1748257c5577SDavid E. O'Brien 1749bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 1750257c5577SDavid E. O'Brien 1751257c5577SDavid E. O'Brien return 0; 1752257c5577SDavid E. O'Brien } 1753257c5577SDavid E. O'Brien 1754bfc788c2SDavid E. O'Brien 17552c3adf61SDavid E. O'Brien static void 17562c3adf61SDavid E. O'Brien nfe_setmulti(struct nfe_softc *sc) 1757bfc788c2SDavid E. O'Brien { 1758bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1759bfc788c2SDavid E. O'Brien struct ifmultiaddr *ifma; 1760bfc788c2SDavid E. O'Brien int i; 17612c3adf61SDavid E. O'Brien u_int32_t filter = NFE_RXFILTER_MAGIC; 17622c3adf61SDavid E. O'Brien u_int8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 17632c3adf61SDavid E. O'Brien u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 17642c3adf61SDavid E. O'Brien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 17652c3adf61SDavid E. O'Brien }; 1766bfc788c2SDavid E. O'Brien 1767bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1768bfc788c2SDavid E. O'Brien 1769bfc788c2SDavid E. O'Brien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1770bfc788c2SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 1771bfc788c2SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 1772bfc788c2SDavid E. O'Brien goto done; 1773bfc788c2SDavid E. O'Brien } 1774bfc788c2SDavid E. O'Brien 1775bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1776bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1777bfc788c2SDavid E. O'Brien 1778bfc788c2SDavid E. O'Brien IF_ADDR_LOCK(ifp); 1779bfc788c2SDavid E. O'Brien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1780bfc788c2SDavid E. O'Brien u_char *addrp; 1781bfc788c2SDavid E. O'Brien 1782bfc788c2SDavid E. O'Brien if (ifma->ifma_addr->sa_family != AF_LINK) 1783bfc788c2SDavid E. O'Brien continue; 1784bfc788c2SDavid E. O'Brien 1785bfc788c2SDavid E. O'Brien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 1786bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1787bfc788c2SDavid E. O'Brien u_int8_t mcaddr = addrp[i]; 1788bfc788c2SDavid E. O'Brien addr[i] &= mcaddr; 1789bfc788c2SDavid E. O'Brien mask[i] &= ~mcaddr; 1790bfc788c2SDavid E. O'Brien } 1791bfc788c2SDavid E. O'Brien } 1792bfc788c2SDavid E. O'Brien IF_ADDR_UNLOCK(ifp); 1793bfc788c2SDavid E. O'Brien 1794bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1795bfc788c2SDavid E. O'Brien mask[i] |= addr[i]; 1796bfc788c2SDavid E. O'Brien } 1797bfc788c2SDavid E. O'Brien 1798bfc788c2SDavid E. O'Brien done: 1799bfc788c2SDavid E. O'Brien addr[0] |= 0x01; /* make sure multicast bit is set */ 1800bfc788c2SDavid E. O'Brien 1801bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1802bfc788c2SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1803bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1804bfc788c2SDavid E. O'Brien addr[5] << 8 | addr[4]); 1805bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1806bfc788c2SDavid E. O'Brien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1807bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1808bfc788c2SDavid E. O'Brien mask[5] << 8 | mask[4]); 1809bfc788c2SDavid E. O'Brien 1810bfc788c2SDavid E. O'Brien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1811bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_RXFILTER, filter); 1812bfc788c2SDavid E. O'Brien } 1813bfc788c2SDavid E. O'Brien 18142c3adf61SDavid E. O'Brien 18152c3adf61SDavid E. O'Brien static void 18162c3adf61SDavid E. O'Brien nfe_start(struct ifnet *ifp) 1817bfc788c2SDavid E. O'Brien { 1818bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1819bfc788c2SDavid E. O'Brien 1820bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 1821bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1822bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1823bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1824bfc788c2SDavid E. O'Brien } 1825bfc788c2SDavid E. O'Brien 18262c3adf61SDavid E. O'Brien 18272c3adf61SDavid E. O'Brien static void 18282c3adf61SDavid E. O'Brien nfe_start_locked(struct ifnet *ifp) 1829257c5577SDavid E. O'Brien { 1830257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1831257c5577SDavid E. O'Brien struct mbuf *m0; 18322c3adf61SDavid E. O'Brien int old = sc->txq.cur; 1833257c5577SDavid E. O'Brien 1834bfc788c2SDavid E. O'Brien if (!sc->nfe_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1835bfc788c2SDavid E. O'Brien return; 1836bfc788c2SDavid E. O'Brien } 1837bfc788c2SDavid E. O'Brien 1838257c5577SDavid E. O'Brien for (;;) { 1839257c5577SDavid E. O'Brien IFQ_POLL(&ifp->if_snd, m0); 1840257c5577SDavid E. O'Brien if (m0 == NULL) 1841257c5577SDavid E. O'Brien break; 1842257c5577SDavid E. O'Brien 1843257c5577SDavid E. O'Brien if (nfe_encap(sc, m0) != 0) { 1844bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1845257c5577SDavid E. O'Brien break; 1846257c5577SDavid E. O'Brien } 1847257c5577SDavid E. O'Brien 1848257c5577SDavid E. O'Brien /* packet put in h/w queue, remove from s/w queue */ 1849257c5577SDavid E. O'Brien IFQ_DEQUEUE(&ifp->if_snd, m0); 1850257c5577SDavid E. O'Brien 1851bfc788c2SDavid E. O'Brien BPF_MTAP(ifp, m0); 1852257c5577SDavid E. O'Brien } 1853bfc788c2SDavid E. O'Brien if (sc->txq.cur == old) { /* nothing sent */ 1854257c5577SDavid E. O'Brien return; 1855bfc788c2SDavid E. O'Brien } 1856257c5577SDavid E. O'Brien 1857bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1858257c5577SDavid E. O'Brien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1859257c5577SDavid E. O'Brien else 1860257c5577SDavid E. O'Brien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1861257c5577SDavid E. O'Brien 1862257c5577SDavid E. O'Brien /* kick Tx */ 1863257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1864257c5577SDavid E. O'Brien 1865257c5577SDavid E. O'Brien /* 1866257c5577SDavid E. O'Brien * Set a timeout in case the chip goes out to lunch. 1867257c5577SDavid E. O'Brien */ 1868257c5577SDavid E. O'Brien ifp->if_timer = 5; 1869bfc788c2SDavid E. O'Brien 1870bfc788c2SDavid E. O'Brien return; 1871257c5577SDavid E. O'Brien } 1872257c5577SDavid E. O'Brien 18732c3adf61SDavid E. O'Brien 18742c3adf61SDavid E. O'Brien static void 18752c3adf61SDavid E. O'Brien nfe_watchdog(struct ifnet *ifp) 1876257c5577SDavid E. O'Brien { 1877257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1878257c5577SDavid E. O'Brien 1879bfc788c2SDavid E. O'Brien printf("nfe%d: watchdog timeout\n", sc->nfe_unit); 1880257c5577SDavid E. O'Brien 1881bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1882bfc788c2SDavid E. O'Brien nfe_init(sc); 1883257c5577SDavid E. O'Brien ifp->if_oerrors++; 1884bfc788c2SDavid E. O'Brien 1885bfc788c2SDavid E. O'Brien return; 1886257c5577SDavid E. O'Brien } 1887257c5577SDavid E. O'Brien 18882c3adf61SDavid E. O'Brien 18892c3adf61SDavid E. O'Brien static void 18902c3adf61SDavid E. O'Brien nfe_init(void *xsc) 1891257c5577SDavid E. O'Brien { 1892bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1893bfc788c2SDavid E. O'Brien 1894bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1895bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1896bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1897bfc788c2SDavid E. O'Brien 1898bfc788c2SDavid E. O'Brien return; 1899bfc788c2SDavid E. O'Brien } 1900bfc788c2SDavid E. O'Brien 19012c3adf61SDavid E. O'Brien 19022c3adf61SDavid E. O'Brien static void 19032c3adf61SDavid E. O'Brien nfe_init_locked(void *xsc) 1904bfc788c2SDavid E. O'Brien { 1905bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1906bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1907bfc788c2SDavid E. O'Brien struct mii_data *mii; 1908bfc788c2SDavid E. O'Brien u_int32_t tmp; 1909bfc788c2SDavid E. O'Brien 1910bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1911bfc788c2SDavid E. O'Brien 1912bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1913bfc788c2SDavid E. O'Brien 1914bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1915bfc788c2SDavid E. O'Brien return; 1916bfc788c2SDavid E. O'Brien } 1917257c5577SDavid E. O'Brien 1918257c5577SDavid E. O'Brien nfe_stop(ifp, 0); 1919257c5577SDavid E. O'Brien 1920257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_UNK, 0); 1921257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, 0); 1922257c5577SDavid E. O'Brien 1923257c5577SDavid E. O'Brien sc->rxtxctl = NFE_RXTX_BIT2; 1924bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1925257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1926bfc788c2SDavid E. O'Brien else if (sc->nfe_flags & NFE_JUMBO_SUP) 1927257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 1928257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1929bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) 1930257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1931257c5577SDavid E. O'Brien #endif 1932bfc788c2SDavid E. O'Brien 1933257c5577SDavid E. O'Brien #if NVLAN > 0 1934257c5577SDavid E. O'Brien /* 1935257c5577SDavid E. O'Brien * Although the adapter is capable of stripping VLAN tags from received 1936257c5577SDavid E. O'Brien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1937257c5577SDavid E. O'Brien * purpose. This will be done in software by our network stack. 1938257c5577SDavid E. O'Brien */ 1939bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1940257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1941257c5577SDavid E. O'Brien #endif 1942bfc788c2SDavid E. O'Brien 1943257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1944257c5577SDavid E. O'Brien DELAY(10); 1945257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1946257c5577SDavid E. O'Brien 1947257c5577SDavid E. O'Brien #if NVLAN 1948bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1949257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1950257c5577SDavid E. O'Brien #endif 1951257c5577SDavid E. O'Brien 1952257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1953257c5577SDavid E. O'Brien 1954257c5577SDavid E. O'Brien /* set MAC address */ 1955bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, sc->eaddr); 1956257c5577SDavid E. O'Brien 1957257c5577SDavid E. O'Brien /* tell MAC where rings are in memory */ 1958257c5577SDavid E. O'Brien #ifdef __LP64__ 1959257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1960257c5577SDavid E. O'Brien #endif 1961257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1962257c5577SDavid E. O'Brien #ifdef __LP64__ 1963257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1964257c5577SDavid E. O'Brien #endif 1965257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1966257c5577SDavid E. O'Brien 1967257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RING_SIZE, 1968257c5577SDavid E. O'Brien (NFE_RX_RING_COUNT - 1) << 16 | 1969257c5577SDavid E. O'Brien (NFE_TX_RING_COUNT - 1)); 1970257c5577SDavid E. O'Brien 1971257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1972257c5577SDavid E. O'Brien 1973257c5577SDavid E. O'Brien /* force MAC to wakeup */ 1974257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1975257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1976257c5577SDavid E. O'Brien DELAY(10); 1977257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1978257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1979257c5577SDavid E. O'Brien 1980257c5577SDavid E. O'Brien #if 1 1981257c5577SDavid E. O'Brien /* configure interrupts coalescing/mitigation */ 1982257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1983257c5577SDavid E. O'Brien #else 1984257c5577SDavid E. O'Brien /* no interrupt mitigation: one interrupt per packet */ 1985257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, 970); 1986257c5577SDavid E. O'Brien #endif 1987257c5577SDavid E. O'Brien 1988257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1989257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1990257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1991257c5577SDavid E. O'Brien 1992257c5577SDavid E. O'Brien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1993257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1994257c5577SDavid E. O'Brien 1995257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1996257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1997257c5577SDavid E. O'Brien 1998257c5577SDavid E. O'Brien sc->rxtxctl &= ~NFE_RXTX_BIT2; 1999257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2000257c5577SDavid E. O'Brien DELAY(10); 2001257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2002257c5577SDavid E. O'Brien 2003257c5577SDavid E. O'Brien /* set Rx filter */ 2004257c5577SDavid E. O'Brien nfe_setmulti(sc); 2005257c5577SDavid E. O'Brien 2006257c5577SDavid E. O'Brien nfe_ifmedia_upd(ifp); 2007257c5577SDavid E. O'Brien 2008bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 2009bfc788c2SDavid E. O'Brien 2010257c5577SDavid E. O'Brien /* enable Rx */ 2011257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2012257c5577SDavid E. O'Brien 2013257c5577SDavid E. O'Brien /* enable Tx */ 2014257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2015257c5577SDavid E. O'Brien 2016257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2017257c5577SDavid E. O'Brien 2018bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 2019bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 2020bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 2021bfc788c2SDavid E. O'Brien else 2022bfc788c2SDavid E. O'Brien #endif 2023bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); /* enable interrupts */ 2024257c5577SDavid E. O'Brien 2025bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2026bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2027257c5577SDavid E. O'Brien 2028bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 2029257c5577SDavid E. O'Brien 2030bfc788c2SDavid E. O'Brien return; 2031257c5577SDavid E. O'Brien } 2032257c5577SDavid E. O'Brien 20332c3adf61SDavid E. O'Brien 20342c3adf61SDavid E. O'Brien static void 20352c3adf61SDavid E. O'Brien nfe_stop(struct ifnet *ifp, int disable) 2036257c5577SDavid E. O'Brien { 2037257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2038bfc788c2SDavid E. O'Brien struct mii_data *mii; 2039257c5577SDavid E. O'Brien 2040bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2041257c5577SDavid E. O'Brien 2042257c5577SDavid E. O'Brien ifp->if_timer = 0; 2043bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2044257c5577SDavid E. O'Brien 2045bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2046bfc788c2SDavid E. O'Brien 2047bfc788c2SDavid E. O'Brien callout_stop(&sc->nfe_stat_ch); 2048257c5577SDavid E. O'Brien 2049257c5577SDavid E. O'Brien /* abort Tx */ 2050257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, 0); 2051257c5577SDavid E. O'Brien 2052257c5577SDavid E. O'Brien /* disable Rx */ 2053257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, 0); 2054257c5577SDavid E. O'Brien 2055257c5577SDavid E. O'Brien /* disable interrupts */ 2056257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 2057257c5577SDavid E. O'Brien 2058bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 2059bfc788c2SDavid E. O'Brien 2060257c5577SDavid E. O'Brien /* reset Tx and Rx rings */ 2061257c5577SDavid E. O'Brien nfe_reset_tx_ring(sc, &sc->txq); 2062257c5577SDavid E. O'Brien nfe_reset_rx_ring(sc, &sc->rxq); 2063257c5577SDavid E. O'Brien 2064257c5577SDavid E. O'Brien return; 2065257c5577SDavid E. O'Brien } 2066257c5577SDavid E. O'Brien 20672c3adf61SDavid E. O'Brien 20682c3adf61SDavid E. O'Brien static int 20692c3adf61SDavid E. O'Brien nfe_ifmedia_upd(struct ifnet *ifp) 2070257c5577SDavid E. O'Brien { 2071257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2072257c5577SDavid E. O'Brien 2073bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2074bfc788c2SDavid E. O'Brien nfe_ifmedia_upd_locked(ifp); 2075bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2076bfc788c2SDavid E. O'Brien return (0); 2077bfc788c2SDavid E. O'Brien } 2078bfc788c2SDavid E. O'Brien 20792c3adf61SDavid E. O'Brien 20802c3adf61SDavid E. O'Brien static int 20812c3adf61SDavid E. O'Brien nfe_ifmedia_upd_locked(struct ifnet *ifp) 2082bfc788c2SDavid E. O'Brien { 2083bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2084bfc788c2SDavid E. O'Brien struct mii_data *mii; 2085bfc788c2SDavid E. O'Brien 2086bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2087bfc788c2SDavid E. O'Brien 2088bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2089bfc788c2SDavid E. O'Brien 2090bfc788c2SDavid E. O'Brien if (mii->mii_instance) { 2091bfc788c2SDavid E. O'Brien struct mii_softc *miisc; 2092bfc788c2SDavid E. O'Brien for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 2093bfc788c2SDavid E. O'Brien miisc = LIST_NEXT(miisc, mii_list)) { 2094257c5577SDavid E. O'Brien mii_phy_reset(miisc); 2095257c5577SDavid E. O'Brien } 2096bfc788c2SDavid E. O'Brien } 2097bfc788c2SDavid E. O'Brien mii_mediachg(mii); 2098bfc788c2SDavid E. O'Brien 2099bfc788c2SDavid E. O'Brien return (0); 2100257c5577SDavid E. O'Brien } 2101257c5577SDavid E. O'Brien 21022c3adf61SDavid E. O'Brien 21032c3adf61SDavid E. O'Brien static void 21042c3adf61SDavid E. O'Brien nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2105257c5577SDavid E. O'Brien { 2106bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2107bfc788c2SDavid E. O'Brien struct mii_data *mii; 2108257c5577SDavid E. O'Brien 2109bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 2110bfc788c2SDavid E. O'Brien 2111bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2112bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2113257c5577SDavid E. O'Brien mii_pollstat(mii); 2114bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2115bfc788c2SDavid E. O'Brien 2116257c5577SDavid E. O'Brien ifmr->ifm_active = mii->mii_media_active; 2117bfc788c2SDavid E. O'Brien ifmr->ifm_status = mii->mii_media_status; 2118bfc788c2SDavid E. O'Brien 2119bfc788c2SDavid E. O'Brien return; 2120257c5577SDavid E. O'Brien } 2121257c5577SDavid E. O'Brien 21222c3adf61SDavid E. O'Brien 2123bfc788c2SDavid E. O'Brien static void 2124bfc788c2SDavid E. O'Brien nfe_tick(void *xsc) 2125257c5577SDavid E. O'Brien { 2126bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2127257c5577SDavid E. O'Brien 2128bfc788c2SDavid E. O'Brien sc = xsc; 2129bfc788c2SDavid E. O'Brien 2130bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2131bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 2132bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2133257c5577SDavid E. O'Brien } 2134257c5577SDavid E. O'Brien 2135257c5577SDavid E. O'Brien 21362c3adf61SDavid E. O'Brien void 21372c3adf61SDavid E. O'Brien nfe_tick_locked(struct nfe_softc *arg) 2138bfc788c2SDavid E. O'Brien { 2139bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2140bfc788c2SDavid E. O'Brien struct mii_data *mii; 2141bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2142bfc788c2SDavid E. O'Brien 2143bfc788c2SDavid E. O'Brien sc = arg; 2144bfc788c2SDavid E. O'Brien 2145bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2146bfc788c2SDavid E. O'Brien 2147bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2148bfc788c2SDavid E. O'Brien 2149bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2150bfc788c2SDavid E. O'Brien mii_tick(mii); 2151bfc788c2SDavid E. O'Brien 2152bfc788c2SDavid E. O'Brien if (!sc->nfe_link) { 2153bfc788c2SDavid E. O'Brien if (mii->mii_media_status & IFM_ACTIVE && 2154bfc788c2SDavid E. O'Brien IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 2155bfc788c2SDavid E. O'Brien sc->nfe_link++; 2156bfc788c2SDavid E. O'Brien if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T 2157bfc788c2SDavid E. O'Brien && bootverbose) 2158bfc788c2SDavid E. O'Brien if_printf(sc->nfe_ifp, "gigabit link up\n"); 2159bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2160bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 2161257c5577SDavid E. O'Brien } 2162257c5577SDavid E. O'Brien } 2163bfc788c2SDavid E. O'Brien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2164257c5577SDavid E. O'Brien 2165bfc788c2SDavid E. O'Brien return; 2166257c5577SDavid E. O'Brien } 2167257c5577SDavid E. O'Brien 2168bfc788c2SDavid E. O'Brien 21692c3adf61SDavid E. O'Brien static void 21702c3adf61SDavid E. O'Brien nfe_shutdown(device_t dev) 2171bfc788c2SDavid E. O'Brien { 2172bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2173bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2174bfc788c2SDavid E. O'Brien 2175bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 2176bfc788c2SDavid E. O'Brien 2177bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2178bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2179bfc788c2SDavid E. O'Brien nfe_stop(ifp,0); 2180bfc788c2SDavid E. O'Brien /* nfe_reset(sc); */ 2181bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2182bfc788c2SDavid E. O'Brien 2183bfc788c2SDavid E. O'Brien return; 2184bfc788c2SDavid E. O'Brien } 2185bfc788c2SDavid E. O'Brien 2186bfc788c2SDavid E. O'Brien 21872c3adf61SDavid E. O'Brien static void 21882c3adf61SDavid E. O'Brien nfe_get_macaddr(struct nfe_softc *sc, u_char *addr) 2189257c5577SDavid E. O'Brien { 2190257c5577SDavid E. O'Brien uint32_t tmp; 2191257c5577SDavid E. O'Brien 2192257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_LO); 2193257c5577SDavid E. O'Brien addr[0] = (tmp >> 8) & 0xff; 2194257c5577SDavid E. O'Brien addr[1] = (tmp & 0xff); 2195257c5577SDavid E. O'Brien 2196257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_HI); 2197257c5577SDavid E. O'Brien addr[2] = (tmp >> 24) & 0xff; 2198257c5577SDavid E. O'Brien addr[3] = (tmp >> 16) & 0xff; 2199257c5577SDavid E. O'Brien addr[4] = (tmp >> 8) & 0xff; 2200257c5577SDavid E. O'Brien addr[5] = (tmp & 0xff); 2201257c5577SDavid E. O'Brien } 2202257c5577SDavid E. O'Brien 22032c3adf61SDavid E. O'Brien 22042c3adf61SDavid E. O'Brien static void 22052c3adf61SDavid E. O'Brien nfe_set_macaddr(struct nfe_softc *sc, u_char *addr) 2206257c5577SDavid E. O'Brien { 2207bfc788c2SDavid E. O'Brien 2208bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 2209bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 2210bfc788c2SDavid E. O'Brien addr[1] << 8 | addr[0]); 2211257c5577SDavid E. O'Brien } 2212257c5577SDavid E. O'Brien 22132c3adf61SDavid E. O'Brien 2214bfc788c2SDavid E. O'Brien /* 2215bfc788c2SDavid E. O'Brien * Map a single buffer address. 2216bfc788c2SDavid E. O'Brien */ 2217bfc788c2SDavid E. O'Brien 2218bfc788c2SDavid E. O'Brien static void 2219bfc788c2SDavid E. O'Brien nfe_dma_map_segs(arg, segs, nseg, error) 2220bfc788c2SDavid E. O'Brien void *arg; 2221bfc788c2SDavid E. O'Brien bus_dma_segment_t *segs; 2222bfc788c2SDavid E. O'Brien int error, nseg; 2223257c5577SDavid E. O'Brien { 2224257c5577SDavid E. O'Brien 2225bfc788c2SDavid E. O'Brien if (error) 2226bfc788c2SDavid E. O'Brien return; 2227257c5577SDavid E. O'Brien 2228bfc788c2SDavid E. O'Brien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2229bfc788c2SDavid E. O'Brien 2230bfc788c2SDavid E. O'Brien *(bus_dma_segment_t *)arg = *segs; 2231bfc788c2SDavid E. O'Brien 2232bfc788c2SDavid E. O'Brien return; 2233257c5577SDavid E. O'Brien } 2234