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 #ifdef HAVE_KERNEL_OPTION_HEADERS 27bfc788c2SDavid E. O'Brien #include "opt_device_polling.h" 28bfc788c2SDavid E. O'Brien #endif 29257c5577SDavid E. O'Brien 30257c5577SDavid E. O'Brien #include <sys/param.h> 31257c5577SDavid E. O'Brien #include <sys/endian.h> 32257c5577SDavid E. O'Brien #include <sys/systm.h> 33257c5577SDavid E. O'Brien #include <sys/sockio.h> 34257c5577SDavid E. O'Brien #include <sys/mbuf.h> 35257c5577SDavid E. O'Brien #include <sys/malloc.h> 36bfc788c2SDavid E. O'Brien #include <sys/module.h> 37257c5577SDavid E. O'Brien #include <sys/kernel.h> 38aab5582fSPyun YongHyeon #include <sys/queue.h> 39257c5577SDavid E. O'Brien #include <sys/socket.h> 40aab5582fSPyun YongHyeon #include <sys/sysctl.h> 41bfc788c2SDavid E. O'Brien #include <sys/taskqueue.h> 42257c5577SDavid E. O'Brien 43257c5577SDavid E. O'Brien #include <net/if.h> 44bfc788c2SDavid E. O'Brien #include <net/if_arp.h> 45bfc788c2SDavid E. O'Brien #include <net/ethernet.h> 46257c5577SDavid E. O'Brien #include <net/if_dl.h> 47257c5577SDavid E. O'Brien #include <net/if_media.h> 48257c5577SDavid E. O'Brien #include <net/if_types.h> 49257c5577SDavid E. O'Brien #include <net/if_vlan_var.h> 50257c5577SDavid E. O'Brien 51257c5577SDavid E. O'Brien #include <net/bpf.h> 52bfc788c2SDavid E. O'Brien 53bfc788c2SDavid E. O'Brien #include <machine/bus.h> 54bfc788c2SDavid E. O'Brien #include <machine/resource.h> 55bfc788c2SDavid E. O'Brien #include <sys/bus.h> 56bfc788c2SDavid E. O'Brien #include <sys/rman.h> 57257c5577SDavid E. O'Brien 58257c5577SDavid E. O'Brien #include <dev/mii/mii.h> 59257c5577SDavid E. O'Brien #include <dev/mii/miivar.h> 60257c5577SDavid E. O'Brien 61257c5577SDavid E. O'Brien #include <dev/pci/pcireg.h> 62257c5577SDavid E. O'Brien #include <dev/pci/pcivar.h> 63257c5577SDavid E. O'Brien 64bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfereg.h> 65bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfevar.h> 66257c5577SDavid E. O'Brien 67bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, pci, 1, 1, 1); 68bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, ether, 1, 1, 1); 69bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, miibus, 1, 1, 1); 70aab5582fSPyun YongHyeon 71aab5582fSPyun YongHyeon /* "device miibus" required. See GENERIC if you get errors here. */ 72bfc788c2SDavid E. O'Brien #include "miibus_if.h" 73257c5577SDavid E. O'Brien 74bfc788c2SDavid E. O'Brien static int nfe_probe(device_t); 75bfc788c2SDavid E. O'Brien static int nfe_attach(device_t); 76bfc788c2SDavid E. O'Brien static int nfe_detach(device_t); 77aab5582fSPyun YongHyeon static int nfe_suspend(device_t); 78aab5582fSPyun YongHyeon static int nfe_resume(device_t); 79bfc788c2SDavid E. O'Brien static void nfe_shutdown(device_t); 80aab5582fSPyun YongHyeon static void nfe_power(struct nfe_softc *); 81bfc788c2SDavid E. O'Brien static int nfe_miibus_readreg(device_t, int, int); 82bfc788c2SDavid E. O'Brien static int nfe_miibus_writereg(device_t, int, int, int); 83bfc788c2SDavid E. O'Brien static void nfe_miibus_statchg(device_t); 84aab5582fSPyun YongHyeon static void nfe_link_task(void *, int); 85aab5582fSPyun YongHyeon static void nfe_set_intr(struct nfe_softc *); 86aab5582fSPyun YongHyeon static __inline void nfe_enable_intr(struct nfe_softc *); 87aab5582fSPyun YongHyeon static __inline void nfe_disable_intr(struct nfe_softc *); 88bfc788c2SDavid E. O'Brien static int nfe_ioctl(struct ifnet *, u_long, caddr_t); 89aab5582fSPyun YongHyeon static void nfe_alloc_msix(struct nfe_softc *, int); 90aab5582fSPyun YongHyeon static int nfe_intr(void *); 91aab5582fSPyun YongHyeon static void nfe_int_task(void *, int); 92aab5582fSPyun YongHyeon static void *nfe_jalloc(struct nfe_softc *); 93aab5582fSPyun YongHyeon static void nfe_jfree(void *, void *); 94aab5582fSPyun YongHyeon static __inline void nfe_discard_rxbuf(struct nfe_softc *, int); 95aab5582fSPyun YongHyeon static __inline void nfe_discard_jrxbuf(struct nfe_softc *, int); 96aab5582fSPyun YongHyeon static int nfe_newbuf(struct nfe_softc *, int); 97aab5582fSPyun YongHyeon static int nfe_jnewbuf(struct nfe_softc *, int); 98aab5582fSPyun YongHyeon static int nfe_rxeof(struct nfe_softc *, int); 99aab5582fSPyun YongHyeon static int nfe_jrxeof(struct nfe_softc *, int); 100bfc788c2SDavid E. O'Brien static void nfe_txeof(struct nfe_softc *); 101aab5582fSPyun YongHyeon static struct mbuf *nfe_defrag(struct mbuf *, int, int); 102aab5582fSPyun YongHyeon static int nfe_encap(struct nfe_softc *, struct mbuf **); 103bfc788c2SDavid E. O'Brien static void nfe_setmulti(struct nfe_softc *); 104aab5582fSPyun YongHyeon static void nfe_tx_task(void *, int); 105bfc788c2SDavid E. O'Brien static void nfe_start(struct ifnet *); 106bfc788c2SDavid E. O'Brien static void nfe_watchdog(struct ifnet *); 107bfc788c2SDavid E. O'Brien static void nfe_init(void *); 108bfc788c2SDavid E. O'Brien static void nfe_init_locked(void *); 109aab5582fSPyun YongHyeon static void nfe_stop(struct ifnet *); 110bfc788c2SDavid E. O'Brien static int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 111aab5582fSPyun YongHyeon static int nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 112aab5582fSPyun YongHyeon static int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 113aab5582fSPyun YongHyeon static int nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 114bfc788c2SDavid E. O'Brien static void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 115aab5582fSPyun YongHyeon static void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 116bfc788c2SDavid E. O'Brien static int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 117aab5582fSPyun YongHyeon static void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 118bfc788c2SDavid E. O'Brien static void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 119bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd(struct ifnet *); 120bfc788c2SDavid E. O'Brien static void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 121bfc788c2SDavid E. O'Brien static void nfe_tick(void *); 122aab5582fSPyun YongHyeon static void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 123aab5582fSPyun YongHyeon static void nfe_set_macaddr(struct nfe_softc *, uint8_t *); 124bfc788c2SDavid E. O'Brien static void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); 125aab5582fSPyun YongHyeon 126aab5582fSPyun YongHyeon static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 127aab5582fSPyun YongHyeon static int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); 128257c5577SDavid E. O'Brien 129257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 130aab5582fSPyun YongHyeon static int nfedebug = 0; 131aab5582fSPyun YongHyeon #define DPRINTF(sc, ...) do { \ 132aab5582fSPyun YongHyeon if (nfedebug) \ 133aab5582fSPyun YongHyeon device_printf((sc)->nfe_dev, __VA_ARGS__); \ 134aab5582fSPyun YongHyeon } while (0) 135aab5582fSPyun YongHyeon #define DPRINTFN(sc, n, ...) do { \ 136aab5582fSPyun YongHyeon if (nfedebug >= (n)) \ 137aab5582fSPyun YongHyeon device_printf((sc)->nfe_dev, __VA_ARGS__); \ 138aab5582fSPyun YongHyeon } while (0) 139257c5577SDavid E. O'Brien #else 140aab5582fSPyun YongHyeon #define DPRINTF(sc, ...) 141aab5582fSPyun YongHyeon #define DPRINTFN(sc, n, ...) 142257c5577SDavid E. O'Brien #endif 143257c5577SDavid E. O'Brien 144bfc788c2SDavid E. O'Brien #define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 145bfc788c2SDavid E. O'Brien #define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 146bfc788c2SDavid E. O'Brien #define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 147bfc788c2SDavid E. O'Brien 148aab5582fSPyun YongHyeon #define NFE_JLIST_LOCK(_sc) mtx_lock(&(_sc)->nfe_jlist_mtx) 149aab5582fSPyun YongHyeon #define NFE_JLIST_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_jlist_mtx) 150bfc788c2SDavid E. O'Brien 151aab5582fSPyun YongHyeon /* Tunables. */ 152aab5582fSPyun YongHyeon static int msi_disable = 0; 153aab5582fSPyun YongHyeon static int msix_disable = 0; 154aab5582fSPyun YongHyeon TUNABLE_INT("hw.nfe.msi_disable", &msi_disable); 155aab5582fSPyun YongHyeon TUNABLE_INT("hw.nfe.msix_disable", &msix_disable); 156bfc788c2SDavid E. O'Brien 157bfc788c2SDavid E. O'Brien static device_method_t nfe_methods[] = { 158bfc788c2SDavid E. O'Brien /* Device interface */ 159bfc788c2SDavid E. O'Brien DEVMETHOD(device_probe, nfe_probe), 160bfc788c2SDavid E. O'Brien DEVMETHOD(device_attach, nfe_attach), 161bfc788c2SDavid E. O'Brien DEVMETHOD(device_detach, nfe_detach), 162aab5582fSPyun YongHyeon DEVMETHOD(device_suspend, nfe_suspend), 163aab5582fSPyun YongHyeon DEVMETHOD(device_resume, nfe_resume), 164bfc788c2SDavid E. O'Brien DEVMETHOD(device_shutdown, nfe_shutdown), 165bfc788c2SDavid E. O'Brien 166bfc788c2SDavid E. O'Brien /* bus interface */ 167bfc788c2SDavid E. O'Brien DEVMETHOD(bus_print_child, bus_generic_print_child), 168bfc788c2SDavid E. O'Brien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 169bfc788c2SDavid E. O'Brien 170bfc788c2SDavid E. O'Brien /* MII interface */ 171bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 172bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 173bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 174bfc788c2SDavid E. O'Brien 175aab5582fSPyun YongHyeon { NULL, NULL } 176257c5577SDavid E. O'Brien }; 177257c5577SDavid E. O'Brien 178bfc788c2SDavid E. O'Brien static driver_t nfe_driver = { 179bfc788c2SDavid E. O'Brien "nfe", 180bfc788c2SDavid E. O'Brien nfe_methods, 181bfc788c2SDavid E. O'Brien sizeof(struct nfe_softc) 182bfc788c2SDavid E. O'Brien }; 183bfc788c2SDavid E. O'Brien 184bfc788c2SDavid E. O'Brien static devclass_t nfe_devclass; 185bfc788c2SDavid E. O'Brien 186bfc788c2SDavid E. O'Brien DRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 187bfc788c2SDavid E. O'Brien DRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 188bfc788c2SDavid E. O'Brien 189bfc788c2SDavid E. O'Brien static struct nfe_type nfe_devs[] = { 190bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 1916bec3967SDavid E. O'Brien "NVIDIA nForce MCP Networking Adapter"}, 192bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 1936bec3967SDavid E. O'Brien "NVIDIA nForce2 MCP2 Networking Adapter"}, 194bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 1956bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 196bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 1976bec3967SDavid E. O'Brien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 1986bec3967SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 1996bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP3 Networking Adapter"}, 200bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 2016bec3967SDavid E. O'Brien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 202bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 2036bec3967SDavid E. O'Brien "NVIDIA nForce3 MCP7 Networking Adapter"}, 204bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 2056bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 206bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 2076bec3967SDavid E. O'Brien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 208bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 209aab5582fSPyun YongHyeon "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP10 */ 210bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 211aab5582fSPyun YongHyeon "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP11 */ 212bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 2136bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 214bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 2156bec3967SDavid E. O'Brien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 216bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 217bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 218bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 219bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 2203e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 2213e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2223e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2233e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2243e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 2253e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 226aab5582fSPyun YongHyeon {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4, 2273e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2283e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 2293e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2303e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2313e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2323e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 2333e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 234aab5582fSPyun YongHyeon {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4, 2353e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 236aab5582fSPyun YongHyeon {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1, 237aab5582fSPyun YongHyeon "NVIDIA nForce MCP67 Networking Adapter"}, 238aab5582fSPyun YongHyeon {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2, 239aab5582fSPyun YongHyeon "NVIDIA nForce MCP67 Networking Adapter"}, 240aab5582fSPyun YongHyeon {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3, 241aab5582fSPyun YongHyeon "NVIDIA nForce MCP67 Networking Adapter"}, 242aab5582fSPyun YongHyeon {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4, 243aab5582fSPyun YongHyeon "NVIDIA nForce MCP67 Networking Adapter"}, 244bfc788c2SDavid E. O'Brien {0, 0, NULL} 245bfc788c2SDavid E. O'Brien }; 246bfc788c2SDavid E. O'Brien 247bfc788c2SDavid E. O'Brien 248bfc788c2SDavid E. O'Brien /* Probe for supported hardware ID's */ 249bfc788c2SDavid E. O'Brien static int 250bfc788c2SDavid E. O'Brien nfe_probe(device_t dev) 251257c5577SDavid E. O'Brien { 252bfc788c2SDavid E. O'Brien struct nfe_type *t; 253bfc788c2SDavid E. O'Brien 254bfc788c2SDavid E. O'Brien t = nfe_devs; 255bfc788c2SDavid E. O'Brien /* Check for matching PCI DEVICE ID's */ 256bfc788c2SDavid E. O'Brien while (t->name != NULL) { 257bfc788c2SDavid E. O'Brien if ((pci_get_vendor(dev) == t->vid_id) && 258bfc788c2SDavid E. O'Brien (pci_get_device(dev) == t->dev_id)) { 259bfc788c2SDavid E. O'Brien device_set_desc(dev, t->name); 260aab5582fSPyun YongHyeon return (BUS_PROBE_DEFAULT); 261bfc788c2SDavid E. O'Brien } 262bfc788c2SDavid E. O'Brien t++; 263257c5577SDavid E. O'Brien } 264257c5577SDavid E. O'Brien 265bfc788c2SDavid E. O'Brien return (ENXIO); 266bfc788c2SDavid E. O'Brien } 267bfc788c2SDavid E. O'Brien 268aab5582fSPyun YongHyeon static void 269aab5582fSPyun YongHyeon nfe_alloc_msix(struct nfe_softc *sc, int count) 270aab5582fSPyun YongHyeon { 271aab5582fSPyun YongHyeon int rid; 272aab5582fSPyun YongHyeon 273aab5582fSPyun YongHyeon rid = PCIR_BAR(2); 274aab5582fSPyun YongHyeon sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY, 275aab5582fSPyun YongHyeon &rid, RF_ACTIVE); 276aab5582fSPyun YongHyeon if (sc->nfe_msix_res == NULL) { 277aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 278aab5582fSPyun YongHyeon "couldn't allocate MSIX table resource\n"); 279aab5582fSPyun YongHyeon return; 280aab5582fSPyun YongHyeon } 281aab5582fSPyun YongHyeon rid = PCIR_BAR(3); 282aab5582fSPyun YongHyeon sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev, 283aab5582fSPyun YongHyeon SYS_RES_MEMORY, &rid, RF_ACTIVE); 284aab5582fSPyun YongHyeon if (sc->nfe_msix_pba_res == NULL) { 285aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 286aab5582fSPyun YongHyeon "couldn't allocate MSIX PBA resource\n"); 287aab5582fSPyun YongHyeon bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2), 288aab5582fSPyun YongHyeon sc->nfe_msix_res); 289aab5582fSPyun YongHyeon sc->nfe_msix_res = NULL; 290aab5582fSPyun YongHyeon return; 291aab5582fSPyun YongHyeon } 292aab5582fSPyun YongHyeon 293aab5582fSPyun YongHyeon if (pci_alloc_msix(sc->nfe_dev, &count) == 0) { 294aab5582fSPyun YongHyeon if (count == NFE_MSI_MESSAGES) { 295aab5582fSPyun YongHyeon if (bootverbose) 296aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 297aab5582fSPyun YongHyeon "Using %d MSIX messages\n", count); 298aab5582fSPyun YongHyeon sc->nfe_msix = 1; 299aab5582fSPyun YongHyeon } else { 300aab5582fSPyun YongHyeon if (bootverbose) 301aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 302aab5582fSPyun YongHyeon "couldn't allocate MSIX\n"); 303aab5582fSPyun YongHyeon pci_release_msi(sc->nfe_dev); 304aab5582fSPyun YongHyeon bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 305aab5582fSPyun YongHyeon PCIR_BAR(3), sc->nfe_msix_pba_res); 306aab5582fSPyun YongHyeon bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 307aab5582fSPyun YongHyeon PCIR_BAR(2), sc->nfe_msix_res); 308aab5582fSPyun YongHyeon sc->nfe_msix_pba_res = NULL; 309aab5582fSPyun YongHyeon sc->nfe_msix_res = NULL; 310aab5582fSPyun YongHyeon } 311aab5582fSPyun YongHyeon } 312aab5582fSPyun YongHyeon } 3132c3adf61SDavid E. O'Brien 314bfc788c2SDavid E. O'Brien static int 315bfc788c2SDavid E. O'Brien nfe_attach(device_t dev) 316257c5577SDavid E. O'Brien { 317bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 318257c5577SDavid E. O'Brien struct ifnet *ifp; 319aab5582fSPyun YongHyeon bus_addr_t dma_addr_max; 320aab5582fSPyun YongHyeon int error = 0, i, msic, reg, rid; 321257c5577SDavid E. O'Brien 322bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 323bfc788c2SDavid E. O'Brien sc->nfe_dev = dev; 324bfc788c2SDavid E. O'Brien 325bfc788c2SDavid E. O'Brien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 326aab5582fSPyun YongHyeon MTX_DEF); 327aab5582fSPyun YongHyeon mtx_init(&sc->nfe_jlist_mtx, "nfe_jlist_mtx", NULL, MTX_DEF); 328bfc788c2SDavid E. O'Brien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 329aab5582fSPyun YongHyeon TASK_INIT(&sc->nfe_link_task, 0, nfe_link_task, sc); 330aab5582fSPyun YongHyeon SLIST_INIT(&sc->nfe_jfree_listhead); 331aab5582fSPyun YongHyeon SLIST_INIT(&sc->nfe_jinuse_listhead); 332bfc788c2SDavid E. O'Brien 333bfc788c2SDavid E. O'Brien pci_enable_busmaster(dev); 334bfc788c2SDavid E. O'Brien 335aab5582fSPyun YongHyeon rid = PCIR_BAR(0); 336aab5582fSPyun YongHyeon sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 337aab5582fSPyun YongHyeon RF_ACTIVE); 338aab5582fSPyun YongHyeon if (sc->nfe_res[0] == NULL) { 339aab5582fSPyun YongHyeon device_printf(dev, "couldn't map memory resources\n"); 340aab5582fSPyun YongHyeon mtx_destroy(&sc->nfe_mtx); 341aab5582fSPyun YongHyeon return (ENXIO); 342257c5577SDavid E. O'Brien } 343257c5577SDavid E. O'Brien 344aab5582fSPyun YongHyeon if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 345aab5582fSPyun YongHyeon uint16_t v, width; 346aab5582fSPyun YongHyeon 347aab5582fSPyun YongHyeon v = pci_read_config(dev, reg + 0x08, 2); 348aab5582fSPyun YongHyeon /* Change max. read request size to 4096. */ 349aab5582fSPyun YongHyeon v &= ~(7 << 12); 350aab5582fSPyun YongHyeon v |= (5 << 12); 351aab5582fSPyun YongHyeon pci_write_config(dev, reg + 0x08, v, 2); 352aab5582fSPyun YongHyeon 353aab5582fSPyun YongHyeon v = pci_read_config(dev, reg + 0x0c, 2); 354aab5582fSPyun YongHyeon /* link capability */ 355aab5582fSPyun YongHyeon v = (v >> 4) & 0x0f; 356aab5582fSPyun YongHyeon width = pci_read_config(dev, reg + 0x12, 2); 357aab5582fSPyun YongHyeon /* negotiated link width */ 358aab5582fSPyun YongHyeon width = (width >> 4) & 0x3f; 359aab5582fSPyun YongHyeon if (v != width) 360aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 361aab5582fSPyun YongHyeon "warning, negotiated width of link(x%d) != " 362aab5582fSPyun YongHyeon "max. width of link(x%d)\n", width, v); 363aab5582fSPyun YongHyeon } 364bfc788c2SDavid E. O'Brien 365bfc788c2SDavid E. O'Brien /* Allocate interrupt */ 366aab5582fSPyun YongHyeon if (msix_disable == 0 || msi_disable == 0) { 367aab5582fSPyun YongHyeon if (msix_disable == 0 && 368aab5582fSPyun YongHyeon (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES) 369aab5582fSPyun YongHyeon nfe_alloc_msix(sc, msic); 370aab5582fSPyun YongHyeon if (msi_disable == 0 && sc->nfe_msix == 0 && 371aab5582fSPyun YongHyeon (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES && 372aab5582fSPyun YongHyeon pci_alloc_msi(dev, &msic) == 0) { 373aab5582fSPyun YongHyeon if (msic == NFE_MSI_MESSAGES) { 374aab5582fSPyun YongHyeon if (bootverbose) 375aab5582fSPyun YongHyeon device_printf(dev, 376aab5582fSPyun YongHyeon "Using %d MSI messages\n", msic); 377aab5582fSPyun YongHyeon sc->nfe_msi = 1; 378aab5582fSPyun YongHyeon } else 379aab5582fSPyun YongHyeon pci_release_msi(dev); 380aab5582fSPyun YongHyeon } 381aab5582fSPyun YongHyeon } 382bfc788c2SDavid E. O'Brien 383aab5582fSPyun YongHyeon if (sc->nfe_msix == 0 && sc->nfe_msi == 0) { 384aab5582fSPyun YongHyeon rid = 0; 385aab5582fSPyun YongHyeon sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 386aab5582fSPyun YongHyeon RF_SHAREABLE | RF_ACTIVE); 387aab5582fSPyun YongHyeon if (sc->nfe_irq[0] == NULL) { 388aab5582fSPyun YongHyeon device_printf(dev, "couldn't allocate IRQ resources\n"); 389bfc788c2SDavid E. O'Brien error = ENXIO; 390bfc788c2SDavid E. O'Brien goto fail; 391257c5577SDavid E. O'Brien } 392aab5582fSPyun YongHyeon } else { 393aab5582fSPyun YongHyeon for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 394aab5582fSPyun YongHyeon sc->nfe_irq[i] = bus_alloc_resource_any(dev, 395aab5582fSPyun YongHyeon SYS_RES_IRQ, &rid, RF_ACTIVE); 396aab5582fSPyun YongHyeon if (sc->nfe_irq[i] == NULL) { 397aab5582fSPyun YongHyeon device_printf(dev, 398aab5582fSPyun YongHyeon "couldn't allocate IRQ resources for " 399aab5582fSPyun YongHyeon "message %d\n", rid); 400aab5582fSPyun YongHyeon error = ENXIO; 401aab5582fSPyun YongHyeon goto fail; 402aab5582fSPyun YongHyeon } 403aab5582fSPyun YongHyeon } 404aab5582fSPyun YongHyeon /* Map interrupts to vector 0. */ 405aab5582fSPyun YongHyeon if (sc->nfe_msix != 0) { 406aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MSIX_MAP0, 0); 407aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MSIX_MAP1, 0); 408aab5582fSPyun YongHyeon } else if (sc->nfe_msi != 0) { 409aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MSI_MAP0, 0); 410aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MSI_MAP1, 0); 411aab5582fSPyun YongHyeon } 412aab5582fSPyun YongHyeon } 413257c5577SDavid E. O'Brien 414aab5582fSPyun YongHyeon /* Set IRQ status/mask register. */ 415aab5582fSPyun YongHyeon sc->nfe_irq_status = NFE_IRQ_STATUS; 416aab5582fSPyun YongHyeon sc->nfe_irq_mask = NFE_IRQ_MASK; 417aab5582fSPyun YongHyeon sc->nfe_intrs = NFE_IRQ_WANTED; 418aab5582fSPyun YongHyeon sc->nfe_nointrs = 0; 419aab5582fSPyun YongHyeon if (sc->nfe_msix != 0) { 420aab5582fSPyun YongHyeon sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS; 421aab5582fSPyun YongHyeon sc->nfe_nointrs = NFE_IRQ_WANTED; 422aab5582fSPyun YongHyeon } else if (sc->nfe_msi != 0) { 423aab5582fSPyun YongHyeon sc->nfe_irq_mask = NFE_MSI_IRQ_MASK; 424aab5582fSPyun YongHyeon sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED; 425aab5582fSPyun YongHyeon } 426257c5577SDavid E. O'Brien 427aab5582fSPyun YongHyeon sc->nfe_devid = pci_get_device(dev); 428aab5582fSPyun YongHyeon sc->nfe_revid = pci_get_revid(dev); 429bfc788c2SDavid E. O'Brien sc->nfe_flags = 0; 430257c5577SDavid E. O'Brien 431aab5582fSPyun YongHyeon switch (sc->nfe_devid) { 432257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 433257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 434257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 435257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 436bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 437257c5577SDavid E. O'Brien break; 438257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 439257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 440aab5582fSPyun YongHyeon sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT; 441257c5577SDavid E. O'Brien break; 442257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 443257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 444257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 445257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 446bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 447257c5577SDavid E. O'Brien break; 448257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 449257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 4502c3adf61SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 451aab5582fSPyun YongHyeon NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL; 452257c5577SDavid E. O'Brien break; 453aab5582fSPyun YongHyeon 4543e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 4553e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 4563e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 4573e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 458aab5582fSPyun YongHyeon case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 459aab5582fSPyun YongHyeon case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 460aab5582fSPyun YongHyeon case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 461aab5582fSPyun YongHyeon case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 462aab5582fSPyun YongHyeon sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | 463aab5582fSPyun YongHyeon NFE_TX_FLOW_CTRL; 4643e232000SDavid E. O'Brien break; 4653e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 4663e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 4673e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 4683e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 469aab5582fSPyun YongHyeon sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | 470aab5582fSPyun YongHyeon NFE_PWR_MGMT | NFE_TX_FLOW_CTRL; 4713e232000SDavid E. O'Brien break; 472257c5577SDavid E. O'Brien } 473257c5577SDavid E. O'Brien 474aab5582fSPyun YongHyeon nfe_power(sc); 475aab5582fSPyun YongHyeon /* Check for reversed ethernet address */ 476aab5582fSPyun YongHyeon if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0) 477aab5582fSPyun YongHyeon sc->nfe_flags |= NFE_CORRECT_MACADDR; 478aab5582fSPyun YongHyeon nfe_get_macaddr(sc, sc->eaddr); 479257c5577SDavid E. O'Brien /* 480bfc788c2SDavid E. O'Brien * Allocate the parent bus DMA tag appropriate for PCI. 481bfc788c2SDavid E. O'Brien */ 482aab5582fSPyun YongHyeon dma_addr_max = BUS_SPACE_MAXADDR_32BIT; 483aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0) 484aab5582fSPyun YongHyeon dma_addr_max = NFE_DMA_MAXADDR; 485aab5582fSPyun YongHyeon error = bus_dma_tag_create( 486aab5582fSPyun YongHyeon bus_get_dma_tag(sc->nfe_dev), /* parent */ 487bfc788c2SDavid E. O'Brien 1, 0, /* alignment, boundary */ 488aab5582fSPyun YongHyeon dma_addr_max, /* lowaddr */ 489bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 490bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 491aab5582fSPyun YongHyeon BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 492bfc788c2SDavid E. O'Brien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 493aab5582fSPyun YongHyeon 0, /* flags */ 494bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 495bfc788c2SDavid E. O'Brien &sc->nfe_parent_tag); 496bfc788c2SDavid E. O'Brien if (error) 497bfc788c2SDavid E. O'Brien goto fail; 498bfc788c2SDavid E. O'Brien 4996124fe21SDavid E. O'Brien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 5006124fe21SDavid E. O'Brien if (ifp == NULL) { 501aab5582fSPyun YongHyeon device_printf(dev, "can not if_alloc()\n"); 5026124fe21SDavid E. O'Brien error = ENOSPC; 5036124fe21SDavid E. O'Brien goto fail; 5046124fe21SDavid E. O'Brien } 505aab5582fSPyun YongHyeon TASK_INIT(&sc->nfe_tx_task, 1, nfe_tx_task, ifp); 5066124fe21SDavid E. O'Brien 507bfc788c2SDavid E. O'Brien /* 508257c5577SDavid E. O'Brien * Allocate Tx and Rx rings. 509257c5577SDavid E. O'Brien */ 510aab5582fSPyun YongHyeon if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0) 511bfc788c2SDavid E. O'Brien goto fail; 512257c5577SDavid E. O'Brien 513aab5582fSPyun YongHyeon if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0) 514bfc788c2SDavid E. O'Brien goto fail; 515aab5582fSPyun YongHyeon 516aab5582fSPyun YongHyeon if ((error = nfe_alloc_jrx_ring(sc, &sc->jrxq)) != 0) 517aab5582fSPyun YongHyeon goto fail; 518aab5582fSPyun YongHyeon 519aab5582fSPyun YongHyeon SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 520aab5582fSPyun YongHyeon SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 521aab5582fSPyun YongHyeon OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 522aab5582fSPyun YongHyeon &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 523aab5582fSPyun YongHyeon "max number of Rx events to process"); 524aab5582fSPyun YongHyeon 525aab5582fSPyun YongHyeon sc->nfe_process_limit = NFE_PROC_DEFAULT; 526aab5582fSPyun YongHyeon error = resource_int_value(device_get_name(dev), device_get_unit(dev), 527aab5582fSPyun YongHyeon "process_limit", &sc->nfe_process_limit); 528aab5582fSPyun YongHyeon if (error == 0) { 529aab5582fSPyun YongHyeon if (sc->nfe_process_limit < NFE_PROC_MIN || 530aab5582fSPyun YongHyeon sc->nfe_process_limit > NFE_PROC_MAX) { 531aab5582fSPyun YongHyeon device_printf(dev, "process_limit value out of range; " 532aab5582fSPyun YongHyeon "using default: %d\n", NFE_PROC_DEFAULT); 533aab5582fSPyun YongHyeon sc->nfe_process_limit = NFE_PROC_DEFAULT; 534aab5582fSPyun YongHyeon } 535257c5577SDavid E. O'Brien } 536257c5577SDavid E. O'Brien 537257c5577SDavid E. O'Brien ifp->if_softc = sc; 538bfc788c2SDavid E. O'Brien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 539aab5582fSPyun YongHyeon ifp->if_mtu = ETHERMTU; 540257c5577SDavid E. O'Brien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 541257c5577SDavid E. O'Brien ifp->if_ioctl = nfe_ioctl; 542257c5577SDavid E. O'Brien ifp->if_start = nfe_start; 543aab5582fSPyun YongHyeon ifp->if_hwassist = 0; 544aab5582fSPyun YongHyeon ifp->if_capabilities = 0; 545aab5582fSPyun YongHyeon ifp->if_watchdog = NULL; 546257c5577SDavid E. O'Brien ifp->if_init = nfe_init; 547aab5582fSPyun YongHyeon IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1); 548aab5582fSPyun YongHyeon ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1; 549aab5582fSPyun YongHyeon IFQ_SET_READY(&ifp->if_snd); 550257c5577SDavid E. O'Brien 551bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) { 552aab5582fSPyun YongHyeon ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4; 553aab5582fSPyun YongHyeon ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO; 554257c5577SDavid E. O'Brien } 555bfc788c2SDavid E. O'Brien ifp->if_capenable = ifp->if_capabilities; 556257c5577SDavid E. O'Brien 557aab5582fSPyun YongHyeon sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 558aab5582fSPyun YongHyeon /* VLAN capability setup. */ 559aab5582fSPyun YongHyeon ifp->if_capabilities |= IFCAP_VLAN_MTU; 560aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 561aab5582fSPyun YongHyeon ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 562aab5582fSPyun YongHyeon if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0) 563aab5582fSPyun YongHyeon ifp->if_capabilities |= IFCAP_VLAN_HWCSUM; 564aab5582fSPyun YongHyeon } 565aab5582fSPyun YongHyeon ifp->if_capenable = ifp->if_capabilities; 566aab5582fSPyun YongHyeon 567aab5582fSPyun YongHyeon /* 568aab5582fSPyun YongHyeon * Tell the upper layer(s) we support long frames. 569aab5582fSPyun YongHyeon * Must appear after the call to ether_ifattach() because 570aab5582fSPyun YongHyeon * ether_ifattach() sets ifi_hdrlen to the default value. 571aab5582fSPyun YongHyeon */ 572aab5582fSPyun YongHyeon ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 573aab5582fSPyun YongHyeon 574bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 575bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_POLLING; 576bfc788c2SDavid E. O'Brien #endif 577257c5577SDavid E. O'Brien 578bfc788c2SDavid E. O'Brien /* Do MII setup */ 5792c3adf61SDavid E. O'Brien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, 5802c3adf61SDavid E. O'Brien nfe_ifmedia_sts)) { 581aab5582fSPyun YongHyeon device_printf(dev, "MII without any phy!\n"); 582bfc788c2SDavid E. O'Brien error = ENXIO; 583bfc788c2SDavid E. O'Brien goto fail; 584257c5577SDavid E. O'Brien } 585bfc788c2SDavid E. O'Brien ether_ifattach(ifp, sc->eaddr); 586bfc788c2SDavid E. O'Brien 587aab5582fSPyun YongHyeon TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc); 588aab5582fSPyun YongHyeon sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK, 589aab5582fSPyun YongHyeon taskqueue_thread_enqueue, &sc->nfe_tq); 590aab5582fSPyun YongHyeon taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq", 591aab5582fSPyun YongHyeon device_get_nameunit(sc->nfe_dev)); 592aab5582fSPyun YongHyeon error = 0; 593aab5582fSPyun YongHyeon if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 594aab5582fSPyun YongHyeon error = bus_setup_intr(dev, sc->nfe_irq[0], 595aab5582fSPyun YongHyeon INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 596aab5582fSPyun YongHyeon &sc->nfe_intrhand[0]); 597aab5582fSPyun YongHyeon } else { 598aab5582fSPyun YongHyeon for (i = 0; i < NFE_MSI_MESSAGES; i++) { 599aab5582fSPyun YongHyeon error = bus_setup_intr(dev, sc->nfe_irq[i], 600aab5582fSPyun YongHyeon INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 601aab5582fSPyun YongHyeon &sc->nfe_intrhand[i]); 602aab5582fSPyun YongHyeon if (error != 0) 603aab5582fSPyun YongHyeon break; 604aab5582fSPyun YongHyeon } 605aab5582fSPyun YongHyeon } 606bfc788c2SDavid E. O'Brien if (error) { 607aab5582fSPyun YongHyeon device_printf(dev, "couldn't set up irq\n"); 608aab5582fSPyun YongHyeon taskqueue_free(sc->nfe_tq); 609aab5582fSPyun YongHyeon sc->nfe_tq = NULL; 610bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 611bfc788c2SDavid E. O'Brien goto fail; 612bfc788c2SDavid E. O'Brien } 613bfc788c2SDavid E. O'Brien 614bfc788c2SDavid E. O'Brien fail: 615bfc788c2SDavid E. O'Brien if (error) 616bfc788c2SDavid E. O'Brien nfe_detach(dev); 617bfc788c2SDavid E. O'Brien 618bfc788c2SDavid E. O'Brien return (error); 619bfc788c2SDavid E. O'Brien } 620bfc788c2SDavid E. O'Brien 621bfc788c2SDavid E. O'Brien 622bfc788c2SDavid E. O'Brien static int 623bfc788c2SDavid E. O'Brien nfe_detach(device_t dev) 624257c5577SDavid E. O'Brien { 625bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 626257c5577SDavid E. O'Brien struct ifnet *ifp; 627aab5582fSPyun YongHyeon uint8_t eaddr[ETHER_ADDR_LEN]; 628aab5582fSPyun YongHyeon int i, rid; 629257c5577SDavid E. O'Brien 630bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 631bfc788c2SDavid E. O'Brien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 632bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 633bfc788c2SDavid E. O'Brien 634bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 635aab5582fSPyun YongHyeon if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 636bfc788c2SDavid E. O'Brien ether_poll_deregister(ifp); 637bfc788c2SDavid E. O'Brien #endif 638bfc788c2SDavid E. O'Brien if (device_is_attached(dev)) { 63996058696SDavid E. O'Brien NFE_LOCK(sc); 640aab5582fSPyun YongHyeon nfe_stop(ifp); 641bfc788c2SDavid E. O'Brien ifp->if_flags &= ~IFF_UP; 64296058696SDavid E. O'Brien NFE_UNLOCK(sc); 643bfc788c2SDavid E. O'Brien callout_drain(&sc->nfe_stat_ch); 644aab5582fSPyun YongHyeon taskqueue_drain(taskqueue_fast, &sc->nfe_tx_task); 645aab5582fSPyun YongHyeon taskqueue_drain(taskqueue_swi, &sc->nfe_link_task); 646bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 647257c5577SDavid E. O'Brien } 648257c5577SDavid E. O'Brien 649aab5582fSPyun YongHyeon if (ifp) { 650aab5582fSPyun YongHyeon /* restore ethernet address */ 651aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 652aab5582fSPyun YongHyeon for (i = 0; i < ETHER_ADDR_LEN; i++) { 653aab5582fSPyun YongHyeon eaddr[i] = sc->eaddr[5 - i]; 654aab5582fSPyun YongHyeon } 655aab5582fSPyun YongHyeon } else 656aab5582fSPyun YongHyeon bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN); 657aab5582fSPyun YongHyeon nfe_set_macaddr(sc, eaddr); 658bfc788c2SDavid E. O'Brien if_free(ifp); 659aab5582fSPyun YongHyeon } 660bfc788c2SDavid E. O'Brien if (sc->nfe_miibus) 661bfc788c2SDavid E. O'Brien device_delete_child(dev, sc->nfe_miibus); 662bfc788c2SDavid E. O'Brien bus_generic_detach(dev); 663aab5582fSPyun YongHyeon if (sc->nfe_tq != NULL) { 664aab5582fSPyun YongHyeon taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task); 665aab5582fSPyun YongHyeon taskqueue_free(sc->nfe_tq); 666aab5582fSPyun YongHyeon sc->nfe_tq = NULL; 667aab5582fSPyun YongHyeon } 668bfc788c2SDavid E. O'Brien 669aab5582fSPyun YongHyeon for (i = 0; i < NFE_MSI_MESSAGES; i++) { 670aab5582fSPyun YongHyeon if (sc->nfe_intrhand[i] != NULL) { 671aab5582fSPyun YongHyeon bus_teardown_intr(dev, sc->nfe_irq[i], 672aab5582fSPyun YongHyeon sc->nfe_intrhand[i]); 673aab5582fSPyun YongHyeon sc->nfe_intrhand[i] = NULL; 674aab5582fSPyun YongHyeon } 675aab5582fSPyun YongHyeon } 676aab5582fSPyun YongHyeon 677aab5582fSPyun YongHyeon if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 678aab5582fSPyun YongHyeon if (sc->nfe_irq[0] != NULL) 679aab5582fSPyun YongHyeon bus_release_resource(dev, SYS_RES_IRQ, 0, 680aab5582fSPyun YongHyeon sc->nfe_irq[0]); 681aab5582fSPyun YongHyeon } else { 682aab5582fSPyun YongHyeon for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 683aab5582fSPyun YongHyeon if (sc->nfe_irq[i] != NULL) { 684aab5582fSPyun YongHyeon bus_release_resource(dev, SYS_RES_IRQ, rid, 685aab5582fSPyun YongHyeon sc->nfe_irq[i]); 686aab5582fSPyun YongHyeon sc->nfe_irq[i] = NULL; 687aab5582fSPyun YongHyeon } 688aab5582fSPyun YongHyeon } 689aab5582fSPyun YongHyeon pci_release_msi(dev); 690aab5582fSPyun YongHyeon } 691aab5582fSPyun YongHyeon if (sc->nfe_msix_pba_res != NULL) { 692aab5582fSPyun YongHyeon bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3), 693aab5582fSPyun YongHyeon sc->nfe_msix_pba_res); 694aab5582fSPyun YongHyeon sc->nfe_msix_pba_res = NULL; 695aab5582fSPyun YongHyeon } 696aab5582fSPyun YongHyeon if (sc->nfe_msix_res != NULL) { 697aab5582fSPyun YongHyeon bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 698aab5582fSPyun YongHyeon sc->nfe_msix_res); 699aab5582fSPyun YongHyeon sc->nfe_msix_res = NULL; 700aab5582fSPyun YongHyeon } 701aab5582fSPyun YongHyeon if (sc->nfe_res[0] != NULL) { 702aab5582fSPyun YongHyeon bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 703aab5582fSPyun YongHyeon sc->nfe_res[0]); 704aab5582fSPyun YongHyeon sc->nfe_res[0] = NULL; 705aab5582fSPyun YongHyeon } 706bfc788c2SDavid E. O'Brien 707bfc788c2SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 708bfc788c2SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 709aab5582fSPyun YongHyeon nfe_free_jrx_ring(sc, &sc->jrxq); 710bfc788c2SDavid E. O'Brien 711aab5582fSPyun YongHyeon if (sc->nfe_parent_tag) { 712bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(sc->nfe_parent_tag); 713aab5582fSPyun YongHyeon sc->nfe_parent_tag = NULL; 714aab5582fSPyun YongHyeon } 715bfc788c2SDavid E. O'Brien 716aab5582fSPyun YongHyeon mtx_destroy(&sc->nfe_jlist_mtx); 717bfc788c2SDavid E. O'Brien mtx_destroy(&sc->nfe_mtx); 718bfc788c2SDavid E. O'Brien 719bfc788c2SDavid E. O'Brien return (0); 720bfc788c2SDavid E. O'Brien } 721bfc788c2SDavid E. O'Brien 722bfc788c2SDavid E. O'Brien 723aab5582fSPyun YongHyeon static int 724aab5582fSPyun YongHyeon nfe_suspend(device_t dev) 725aab5582fSPyun YongHyeon { 726aab5582fSPyun YongHyeon struct nfe_softc *sc; 727aab5582fSPyun YongHyeon 728aab5582fSPyun YongHyeon sc = device_get_softc(dev); 729aab5582fSPyun YongHyeon 730aab5582fSPyun YongHyeon NFE_LOCK(sc); 731aab5582fSPyun YongHyeon nfe_stop(sc->nfe_ifp); 732aab5582fSPyun YongHyeon sc->nfe_suspended = 1; 733aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 734aab5582fSPyun YongHyeon 735aab5582fSPyun YongHyeon return (0); 736aab5582fSPyun YongHyeon } 737aab5582fSPyun YongHyeon 738aab5582fSPyun YongHyeon 739aab5582fSPyun YongHyeon static int 740aab5582fSPyun YongHyeon nfe_resume(device_t dev) 741aab5582fSPyun YongHyeon { 742aab5582fSPyun YongHyeon struct nfe_softc *sc; 743aab5582fSPyun YongHyeon struct ifnet *ifp; 744aab5582fSPyun YongHyeon 745aab5582fSPyun YongHyeon sc = device_get_softc(dev); 746aab5582fSPyun YongHyeon 747aab5582fSPyun YongHyeon NFE_LOCK(sc); 748aab5582fSPyun YongHyeon ifp = sc->nfe_ifp; 749aab5582fSPyun YongHyeon if (ifp->if_flags & IFF_UP) 750aab5582fSPyun YongHyeon nfe_init_locked(sc); 751aab5582fSPyun YongHyeon sc->nfe_suspended = 0; 752aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 753aab5582fSPyun YongHyeon 754aab5582fSPyun YongHyeon return (0); 755aab5582fSPyun YongHyeon } 756aab5582fSPyun YongHyeon 757aab5582fSPyun YongHyeon 758aab5582fSPyun YongHyeon /* Take PHY/NIC out of powerdown, from Linux */ 759aab5582fSPyun YongHyeon static void 760aab5582fSPyun YongHyeon nfe_power(struct nfe_softc *sc) 761aab5582fSPyun YongHyeon { 762aab5582fSPyun YongHyeon uint32_t pwr; 763aab5582fSPyun YongHyeon 764aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_PWR_MGMT) == 0) 765aab5582fSPyun YongHyeon return; 766aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2); 767aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC); 768aab5582fSPyun YongHyeon DELAY(100); 769aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MAC_RESET, 0); 770aab5582fSPyun YongHyeon DELAY(100); 771aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2); 772aab5582fSPyun YongHyeon pwr = NFE_READ(sc, NFE_PWR2_CTL); 773aab5582fSPyun YongHyeon pwr &= ~NFE_PWR2_WAKEUP_MASK; 774aab5582fSPyun YongHyeon if (sc->nfe_revid >= 0xa3 && 775aab5582fSPyun YongHyeon (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 || 776aab5582fSPyun YongHyeon sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2)) 777aab5582fSPyun YongHyeon pwr |= NFE_PWR2_REVA3; 778aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_PWR2_CTL, pwr); 779aab5582fSPyun YongHyeon } 780aab5582fSPyun YongHyeon 781aab5582fSPyun YongHyeon 782bfc788c2SDavid E. O'Brien static void 783bfc788c2SDavid E. O'Brien nfe_miibus_statchg(device_t dev) 784257c5577SDavid E. O'Brien { 785bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 786bfc788c2SDavid E. O'Brien 787bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 788aab5582fSPyun YongHyeon taskqueue_enqueue(taskqueue_swi, &sc->nfe_link_task); 789aab5582fSPyun YongHyeon } 790aab5582fSPyun YongHyeon 791aab5582fSPyun YongHyeon 792aab5582fSPyun YongHyeon static void 793aab5582fSPyun YongHyeon nfe_link_task(void *arg, int pending) 794aab5582fSPyun YongHyeon { 795aab5582fSPyun YongHyeon struct nfe_softc *sc; 796aab5582fSPyun YongHyeon struct mii_data *mii; 797aab5582fSPyun YongHyeon struct ifnet *ifp; 798aab5582fSPyun YongHyeon uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 799aab5582fSPyun YongHyeon uint32_t gmask, rxctl, txctl, val; 800aab5582fSPyun YongHyeon 801aab5582fSPyun YongHyeon sc = (struct nfe_softc *)arg; 802aab5582fSPyun YongHyeon 803aab5582fSPyun YongHyeon NFE_LOCK(sc); 804aab5582fSPyun YongHyeon 805bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 806aab5582fSPyun YongHyeon ifp = sc->nfe_ifp; 807aab5582fSPyun YongHyeon if (mii == NULL || ifp == NULL) { 808aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 809aab5582fSPyun YongHyeon return; 810aab5582fSPyun YongHyeon } 811aab5582fSPyun YongHyeon 812aab5582fSPyun YongHyeon if (mii->mii_media_status & IFM_ACTIVE) { 813aab5582fSPyun YongHyeon if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) 814aab5582fSPyun YongHyeon sc->nfe_link = 1; 815aab5582fSPyun YongHyeon } else 816aab5582fSPyun YongHyeon sc->nfe_link = 0; 817257c5577SDavid E. O'Brien 818257c5577SDavid E. O'Brien phy = NFE_READ(sc, NFE_PHY_IFACE); 819257c5577SDavid E. O'Brien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 820257c5577SDavid E. O'Brien 821257c5577SDavid E. O'Brien seed = NFE_READ(sc, NFE_RNDSEED); 822257c5577SDavid E. O'Brien seed &= ~NFE_SEED_MASK; 823257c5577SDavid E. O'Brien 824aab5582fSPyun YongHyeon if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) == 0) { 825257c5577SDavid E. O'Brien phy |= NFE_PHY_HDX; /* half-duplex */ 826257c5577SDavid E. O'Brien misc |= NFE_MISC1_HDX; 827257c5577SDavid E. O'Brien } 828257c5577SDavid E. O'Brien 829257c5577SDavid E. O'Brien switch (IFM_SUBTYPE(mii->mii_media_active)) { 830257c5577SDavid E. O'Brien case IFM_1000_T: /* full-duplex only */ 831257c5577SDavid E. O'Brien link |= NFE_MEDIA_1000T; 832257c5577SDavid E. O'Brien seed |= NFE_SEED_1000T; 833257c5577SDavid E. O'Brien phy |= NFE_PHY_1000T; 834257c5577SDavid E. O'Brien break; 835257c5577SDavid E. O'Brien case IFM_100_TX: 836257c5577SDavid E. O'Brien link |= NFE_MEDIA_100TX; 837257c5577SDavid E. O'Brien seed |= NFE_SEED_100TX; 838257c5577SDavid E. O'Brien phy |= NFE_PHY_100TX; 839257c5577SDavid E. O'Brien break; 840257c5577SDavid E. O'Brien case IFM_10_T: 841257c5577SDavid E. O'Brien link |= NFE_MEDIA_10T; 842257c5577SDavid E. O'Brien seed |= NFE_SEED_10T; 843257c5577SDavid E. O'Brien break; 844257c5577SDavid E. O'Brien } 845257c5577SDavid E. O'Brien 846aab5582fSPyun YongHyeon if ((phy & 0x10000000) != 0) { 847aab5582fSPyun YongHyeon if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 848aab5582fSPyun YongHyeon val = NFE_R1_MAGIC_1000; 849aab5582fSPyun YongHyeon else 850aab5582fSPyun YongHyeon val = NFE_R1_MAGIC_10_100; 851aab5582fSPyun YongHyeon } else 852aab5582fSPyun YongHyeon val = NFE_R1_MAGIC_DEFAULT; 853aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_SETUP_R1, val); 854aab5582fSPyun YongHyeon 855257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 856257c5577SDavid E. O'Brien 857257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 858257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MISC1, misc); 859257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_LINKSPEED, link); 860aab5582fSPyun YongHyeon 861aab5582fSPyun YongHyeon gmask = mii->mii_media_active & IFM_GMASK; 862aab5582fSPyun YongHyeon if ((gmask & IFM_FDX) != 0) { 863aab5582fSPyun YongHyeon /* It seems all hardwares supports Rx pause frames. */ 864aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_RXFILTER); 865aab5582fSPyun YongHyeon if ((gmask & IFM_FLAG0) != 0) 866aab5582fSPyun YongHyeon val |= NFE_PFF_RX_PAUSE; 867aab5582fSPyun YongHyeon else 868aab5582fSPyun YongHyeon val &= ~NFE_PFF_RX_PAUSE; 869aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RXFILTER, val); 870aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 871aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_MISC1); 872aab5582fSPyun YongHyeon if ((gmask & IFM_FLAG1) != 0) { 873aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 874aab5582fSPyun YongHyeon NFE_TX_PAUSE_FRAME_ENABLE); 875aab5582fSPyun YongHyeon val |= NFE_MISC1_TX_PAUSE; 876aab5582fSPyun YongHyeon } else { 877aab5582fSPyun YongHyeon val &= ~NFE_MISC1_TX_PAUSE; 878aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 879aab5582fSPyun YongHyeon NFE_TX_PAUSE_FRAME_DISABLE); 880aab5582fSPyun YongHyeon } 881aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MISC1, val); 882aab5582fSPyun YongHyeon } 883aab5582fSPyun YongHyeon } else { 884aab5582fSPyun YongHyeon /* disable rx/tx pause frames */ 885aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_RXFILTER); 886aab5582fSPyun YongHyeon val &= ~NFE_PFF_RX_PAUSE; 887aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RXFILTER, val); 888aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 889aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 890aab5582fSPyun YongHyeon NFE_TX_PAUSE_FRAME_DISABLE); 891aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_MISC1); 892aab5582fSPyun YongHyeon val &= ~NFE_MISC1_TX_PAUSE; 893aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_MISC1, val); 894aab5582fSPyun YongHyeon } 895aab5582fSPyun YongHyeon } 896aab5582fSPyun YongHyeon 897aab5582fSPyun YongHyeon txctl = NFE_READ(sc, NFE_TX_CTL); 898aab5582fSPyun YongHyeon rxctl = NFE_READ(sc, NFE_RX_CTL); 899aab5582fSPyun YongHyeon if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 900aab5582fSPyun YongHyeon txctl |= NFE_TX_START; 901aab5582fSPyun YongHyeon rxctl |= NFE_RX_START; 902aab5582fSPyun YongHyeon } else { 903aab5582fSPyun YongHyeon txctl &= ~NFE_TX_START; 904aab5582fSPyun YongHyeon rxctl &= ~NFE_RX_START; 905aab5582fSPyun YongHyeon } 906aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 907aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 908aab5582fSPyun YongHyeon 909aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 910257c5577SDavid E. O'Brien } 911257c5577SDavid E. O'Brien 9122c3adf61SDavid E. O'Brien 913bfc788c2SDavid E. O'Brien static int 914bfc788c2SDavid E. O'Brien nfe_miibus_readreg(device_t dev, int phy, int reg) 915257c5577SDavid E. O'Brien { 916bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 917aab5582fSPyun YongHyeon uint32_t val; 918257c5577SDavid E. O'Brien int ntries; 919257c5577SDavid E. O'Brien 920257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 921257c5577SDavid E. O'Brien 922257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 923257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 924257c5577SDavid E. O'Brien DELAY(100); 925257c5577SDavid E. O'Brien } 926257c5577SDavid E. O'Brien 927257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 928257c5577SDavid E. O'Brien 929aab5582fSPyun YongHyeon for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 930257c5577SDavid E. O'Brien DELAY(100); 931257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 932257c5577SDavid E. O'Brien break; 933257c5577SDavid E. O'Brien } 934aab5582fSPyun YongHyeon if (ntries == NFE_TIMEOUT) { 935aab5582fSPyun YongHyeon DPRINTFN(sc, 2, "timeout waiting for PHY\n"); 936257c5577SDavid E. O'Brien return 0; 937257c5577SDavid E. O'Brien } 938257c5577SDavid E. O'Brien 939257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 940aab5582fSPyun YongHyeon DPRINTFN(sc, 2, "could not read PHY\n"); 941257c5577SDavid E. O'Brien return 0; 942257c5577SDavid E. O'Brien } 943257c5577SDavid E. O'Brien 944257c5577SDavid E. O'Brien val = NFE_READ(sc, NFE_PHY_DATA); 945257c5577SDavid E. O'Brien if (val != 0xffffffff && val != 0) 946257c5577SDavid E. O'Brien sc->mii_phyaddr = phy; 947257c5577SDavid E. O'Brien 948aab5582fSPyun YongHyeon DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 949257c5577SDavid E. O'Brien 950aab5582fSPyun YongHyeon return (val); 951257c5577SDavid E. O'Brien } 952257c5577SDavid E. O'Brien 9532c3adf61SDavid E. O'Brien 954bfc788c2SDavid E. O'Brien static int 955bfc788c2SDavid E. O'Brien nfe_miibus_writereg(device_t dev, int phy, int reg, int val) 956257c5577SDavid E. O'Brien { 957bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 958aab5582fSPyun YongHyeon uint32_t ctl; 959257c5577SDavid E. O'Brien int ntries; 960257c5577SDavid E. O'Brien 961257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 962257c5577SDavid E. O'Brien 963257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 964257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 965257c5577SDavid E. O'Brien DELAY(100); 966257c5577SDavid E. O'Brien } 967257c5577SDavid E. O'Brien 968257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_DATA, val); 969257c5577SDavid E. O'Brien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 970257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 971257c5577SDavid E. O'Brien 972aab5582fSPyun YongHyeon for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 973257c5577SDavid E. O'Brien DELAY(100); 974257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 975257c5577SDavid E. O'Brien break; 976257c5577SDavid E. O'Brien } 977257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 978aab5582fSPyun YongHyeon if (nfedebug >= 2 && ntries == NFE_TIMEOUT) 979aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not write to PHY\n"); 980257c5577SDavid E. O'Brien #endif 981aab5582fSPyun YongHyeon return (0); 982257c5577SDavid E. O'Brien } 983257c5577SDavid E. O'Brien 984aab5582fSPyun YongHyeon /* 985aab5582fSPyun YongHyeon * Allocate a jumbo buffer. 986aab5582fSPyun YongHyeon */ 987aab5582fSPyun YongHyeon static void * 988aab5582fSPyun YongHyeon nfe_jalloc(struct nfe_softc *sc) 989aab5582fSPyun YongHyeon { 990aab5582fSPyun YongHyeon struct nfe_jpool_entry *entry; 991aab5582fSPyun YongHyeon 992aab5582fSPyun YongHyeon NFE_JLIST_LOCK(sc); 993aab5582fSPyun YongHyeon 994aab5582fSPyun YongHyeon entry = SLIST_FIRST(&sc->nfe_jfree_listhead); 995aab5582fSPyun YongHyeon 996aab5582fSPyun YongHyeon if (entry == NULL) { 997aab5582fSPyun YongHyeon NFE_JLIST_UNLOCK(sc); 998aab5582fSPyun YongHyeon return (NULL); 999aab5582fSPyun YongHyeon } 1000aab5582fSPyun YongHyeon 1001aab5582fSPyun YongHyeon SLIST_REMOVE_HEAD(&sc->nfe_jfree_listhead, jpool_entries); 1002aab5582fSPyun YongHyeon SLIST_INSERT_HEAD(&sc->nfe_jinuse_listhead, entry, jpool_entries); 1003aab5582fSPyun YongHyeon 1004aab5582fSPyun YongHyeon NFE_JLIST_UNLOCK(sc); 1005aab5582fSPyun YongHyeon 1006aab5582fSPyun YongHyeon return (sc->jrxq.jslots[entry->slot]); 1007aab5582fSPyun YongHyeon } 1008aab5582fSPyun YongHyeon 1009aab5582fSPyun YongHyeon /* 1010aab5582fSPyun YongHyeon * Release a jumbo buffer. 1011aab5582fSPyun YongHyeon */ 1012aab5582fSPyun YongHyeon static void 1013aab5582fSPyun YongHyeon nfe_jfree(void *buf, void *args) 1014aab5582fSPyun YongHyeon { 1015aab5582fSPyun YongHyeon struct nfe_softc *sc; 1016aab5582fSPyun YongHyeon struct nfe_jpool_entry *entry; 1017aab5582fSPyun YongHyeon int i; 1018aab5582fSPyun YongHyeon 1019aab5582fSPyun YongHyeon /* Extract the softc struct pointer. */ 1020aab5582fSPyun YongHyeon sc = (struct nfe_softc *)args; 1021aab5582fSPyun YongHyeon KASSERT(sc != NULL, ("%s: can't find softc pointer!", __func__)); 1022aab5582fSPyun YongHyeon 1023aab5582fSPyun YongHyeon NFE_JLIST_LOCK(sc); 1024aab5582fSPyun YongHyeon /* Calculate the slot this buffer belongs to. */ 1025aab5582fSPyun YongHyeon i = ((vm_offset_t)buf 1026aab5582fSPyun YongHyeon - (vm_offset_t)sc->jrxq.jpool) / NFE_JLEN; 1027aab5582fSPyun YongHyeon KASSERT(i >= 0 && i < NFE_JSLOTS, 1028aab5582fSPyun YongHyeon ("%s: asked to free buffer that we don't manage!", __func__)); 1029aab5582fSPyun YongHyeon 1030aab5582fSPyun YongHyeon entry = SLIST_FIRST(&sc->nfe_jinuse_listhead); 1031aab5582fSPyun YongHyeon KASSERT(entry != NULL, ("%s: buffer not in use!", __func__)); 1032aab5582fSPyun YongHyeon entry->slot = i; 1033aab5582fSPyun YongHyeon SLIST_REMOVE_HEAD(&sc->nfe_jinuse_listhead, jpool_entries); 1034aab5582fSPyun YongHyeon SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry, jpool_entries); 1035aab5582fSPyun YongHyeon if (SLIST_EMPTY(&sc->nfe_jinuse_listhead)) 1036aab5582fSPyun YongHyeon wakeup(sc); 1037aab5582fSPyun YongHyeon 1038aab5582fSPyun YongHyeon NFE_JLIST_UNLOCK(sc); 1039aab5582fSPyun YongHyeon } 1040aab5582fSPyun YongHyeon 1041aab5582fSPyun YongHyeon struct nfe_dmamap_arg { 1042aab5582fSPyun YongHyeon bus_addr_t nfe_busaddr; 1043aab5582fSPyun YongHyeon }; 10442c3adf61SDavid E. O'Brien 1045bfc788c2SDavid E. O'Brien static int 1046bfc788c2SDavid E. O'Brien nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1047bfc788c2SDavid E. O'Brien { 1048aab5582fSPyun YongHyeon struct nfe_dmamap_arg ctx; 1049bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 1050aab5582fSPyun YongHyeon void *desc; 1051bfc788c2SDavid E. O'Brien int i, error, descsize; 1052bfc788c2SDavid E. O'Brien 1053bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1054aab5582fSPyun YongHyeon desc = ring->desc64; 1055bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1056bfc788c2SDavid E. O'Brien } else { 1057aab5582fSPyun YongHyeon desc = ring->desc32; 1058bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1059bfc788c2SDavid E. O'Brien } 1060bfc788c2SDavid E. O'Brien 1061bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 1062bfc788c2SDavid E. O'Brien 1063bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 1064aab5582fSPyun YongHyeon NFE_RING_ALIGN, 0, /* alignment, boundary */ 1065aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 1066bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 1067bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 1068bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1069bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 1070aab5582fSPyun YongHyeon 0, /* flags */ 1071bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 1072bfc788c2SDavid E. O'Brien &ring->rx_desc_tag); 1073bfc788c2SDavid E. O'Brien if (error != 0) { 1074aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1075bfc788c2SDavid E. O'Brien goto fail; 1076bfc788c2SDavid E. O'Brien } 1077bfc788c2SDavid E. O'Brien 1078bfc788c2SDavid E. O'Brien /* allocate memory to desc */ 1079aab5582fSPyun YongHyeon error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK | 1080aab5582fSPyun YongHyeon BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map); 1081bfc788c2SDavid E. O'Brien if (error != 0) { 1082aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1083bfc788c2SDavid E. O'Brien goto fail; 1084bfc788c2SDavid E. O'Brien } 1085aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) 1086aab5582fSPyun YongHyeon ring->desc64 = desc; 1087aab5582fSPyun YongHyeon else 1088aab5582fSPyun YongHyeon ring->desc32 = desc; 1089bfc788c2SDavid E. O'Brien 1090bfc788c2SDavid E. O'Brien /* map desc to device visible address space */ 1091aab5582fSPyun YongHyeon ctx.nfe_busaddr = 0; 1092aab5582fSPyun YongHyeon error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc, 1093aab5582fSPyun YongHyeon NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1094bfc788c2SDavid E. O'Brien if (error != 0) { 1095aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1096aab5582fSPyun YongHyeon goto fail; 1097aab5582fSPyun YongHyeon } 1098aab5582fSPyun YongHyeon ring->physaddr = ctx.nfe_busaddr; 1099aab5582fSPyun YongHyeon 1100aab5582fSPyun YongHyeon error = bus_dma_tag_create(sc->nfe_parent_tag, 1101aab5582fSPyun YongHyeon 1, 0, /* alignment, boundary */ 1102aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 1103aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 1104aab5582fSPyun YongHyeon NULL, NULL, /* filter, filterarg */ 1105aab5582fSPyun YongHyeon MCLBYTES, 1, /* maxsize, nsegments */ 1106aab5582fSPyun YongHyeon MCLBYTES, /* maxsegsize */ 1107aab5582fSPyun YongHyeon 0, /* flags */ 1108aab5582fSPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 1109aab5582fSPyun YongHyeon &ring->rx_data_tag); 1110aab5582fSPyun YongHyeon if (error != 0) { 1111aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not create Rx DMA tag\n"); 1112bfc788c2SDavid E. O'Brien goto fail; 1113bfc788c2SDavid E. O'Brien } 1114bfc788c2SDavid E. O'Brien 1115aab5582fSPyun YongHyeon error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map); 1116aab5582fSPyun YongHyeon if (error != 0) { 1117aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1118aab5582fSPyun YongHyeon "could not create Rx DMA spare map\n"); 1119aab5582fSPyun YongHyeon goto fail; 1120aab5582fSPyun YongHyeon } 1121bfc788c2SDavid E. O'Brien 1122bfc788c2SDavid E. O'Brien /* 1123bfc788c2SDavid E. O'Brien * Pre-allocate Rx buffers and populate Rx ring. 1124bfc788c2SDavid E. O'Brien */ 1125bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1126bfc788c2SDavid E. O'Brien data = &sc->rxq.data[i]; 1127aab5582fSPyun YongHyeon data->rx_data_map = NULL; 1128aab5582fSPyun YongHyeon data->m = NULL; 1129aab5582fSPyun YongHyeon error = bus_dmamap_create(ring->rx_data_tag, 0, 11302c3adf61SDavid E. O'Brien &data->rx_data_map); 1131bfc788c2SDavid E. O'Brien if (error != 0) { 1132aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1133aab5582fSPyun YongHyeon "could not create Rx DMA map\n"); 1134aab5582fSPyun YongHyeon goto fail; 1135aab5582fSPyun YongHyeon } 1136aab5582fSPyun YongHyeon } 1137aab5582fSPyun YongHyeon 1138aab5582fSPyun YongHyeon fail: 1139aab5582fSPyun YongHyeon return (error); 1140aab5582fSPyun YongHyeon } 1141aab5582fSPyun YongHyeon 1142aab5582fSPyun YongHyeon 1143aab5582fSPyun YongHyeon static int 1144aab5582fSPyun YongHyeon nfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1145aab5582fSPyun YongHyeon { 1146aab5582fSPyun YongHyeon struct nfe_dmamap_arg ctx; 1147aab5582fSPyun YongHyeon struct nfe_rx_data *data; 1148aab5582fSPyun YongHyeon void *desc; 1149aab5582fSPyun YongHyeon struct nfe_jpool_entry *entry; 1150aab5582fSPyun YongHyeon uint8_t *ptr; 1151aab5582fSPyun YongHyeon int i, error, descsize; 1152aab5582fSPyun YongHyeon 1153aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1154aab5582fSPyun YongHyeon return (0); 1155aab5582fSPyun YongHyeon 1156aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 1157aab5582fSPyun YongHyeon desc = ring->jdesc64; 1158aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc64); 1159aab5582fSPyun YongHyeon } else { 1160aab5582fSPyun YongHyeon desc = ring->jdesc32; 1161aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc32); 1162aab5582fSPyun YongHyeon } 1163aab5582fSPyun YongHyeon 1164aab5582fSPyun YongHyeon ring->jcur = ring->jnext = 0; 1165aab5582fSPyun YongHyeon 1166aab5582fSPyun YongHyeon /* Create DMA tag for jumbo Rx ring. */ 1167aab5582fSPyun YongHyeon error = bus_dma_tag_create(sc->nfe_parent_tag, 1168aab5582fSPyun YongHyeon NFE_RING_ALIGN, 0, /* alignment, boundary */ 1169aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 1170aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 1171aab5582fSPyun YongHyeon NULL, NULL, /* filter, filterarg */ 1172aab5582fSPyun YongHyeon NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsize */ 1173aab5582fSPyun YongHyeon 1, /* nsegments */ 1174aab5582fSPyun YongHyeon NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsegsize */ 1175aab5582fSPyun YongHyeon 0, /* flags */ 1176aab5582fSPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 1177aab5582fSPyun YongHyeon &ring->jrx_desc_tag); 1178aab5582fSPyun YongHyeon if (error != 0) { 1179aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1180aab5582fSPyun YongHyeon "could not create jumbo ring DMA tag\n"); 1181bfc788c2SDavid E. O'Brien goto fail; 1182bfc788c2SDavid E. O'Brien } 1183bfc788c2SDavid E. O'Brien 1184aab5582fSPyun YongHyeon /* Create DMA tag for jumbo buffer blocks. */ 1185aab5582fSPyun YongHyeon error = bus_dma_tag_create(sc->nfe_parent_tag, 1186aab5582fSPyun YongHyeon PAGE_SIZE, 0, /* alignment, boundary */ 1187aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 1188aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 1189aab5582fSPyun YongHyeon NULL, NULL, /* filter, filterarg */ 1190aab5582fSPyun YongHyeon NFE_JMEM, /* maxsize */ 1191aab5582fSPyun YongHyeon 1, /* nsegments */ 1192aab5582fSPyun YongHyeon NFE_JMEM, /* maxsegsize */ 1193aab5582fSPyun YongHyeon 0, /* flags */ 1194aab5582fSPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 1195aab5582fSPyun YongHyeon &ring->jrx_jumbo_tag); 1196aab5582fSPyun YongHyeon if (error != 0) { 1197aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1198aab5582fSPyun YongHyeon "could not create jumbo Rx buffer block DMA tag\n"); 1199aab5582fSPyun YongHyeon goto fail; 1200aab5582fSPyun YongHyeon } 1201aab5582fSPyun YongHyeon 1202aab5582fSPyun YongHyeon /* Create DMA tag for jumbo Rx buffers. */ 1203aab5582fSPyun YongHyeon error = bus_dma_tag_create(sc->nfe_parent_tag, 1204aab5582fSPyun YongHyeon PAGE_SIZE, 0, /* alignment, boundary */ 1205aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 1206aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* highaddr */ 1207aab5582fSPyun YongHyeon NULL, NULL, /* filter, filterarg */ 1208aab5582fSPyun YongHyeon NFE_JLEN, /* maxsize */ 1209aab5582fSPyun YongHyeon 1, /* nsegments */ 1210aab5582fSPyun YongHyeon NFE_JLEN, /* maxsegsize */ 1211aab5582fSPyun YongHyeon 0, /* flags */ 1212aab5582fSPyun YongHyeon NULL, NULL, /* lockfunc, lockarg */ 1213aab5582fSPyun YongHyeon &ring->jrx_data_tag); 1214aab5582fSPyun YongHyeon if (error != 0) { 1215aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1216aab5582fSPyun YongHyeon "could not create jumbo Rx buffer DMA tag\n"); 1217aab5582fSPyun YongHyeon goto fail; 1218aab5582fSPyun YongHyeon } 1219aab5582fSPyun YongHyeon 1220aab5582fSPyun YongHyeon /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ 1221aab5582fSPyun YongHyeon error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK | 1222aab5582fSPyun YongHyeon BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map); 1223aab5582fSPyun YongHyeon if (error != 0) { 1224aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1225aab5582fSPyun YongHyeon "could not allocate DMA'able memory for jumbo Rx ring\n"); 1226aab5582fSPyun YongHyeon goto fail; 1227aab5582fSPyun YongHyeon } 1228aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) 1229aab5582fSPyun YongHyeon ring->jdesc64 = desc; 1230aab5582fSPyun YongHyeon else 1231aab5582fSPyun YongHyeon ring->jdesc32 = desc; 1232aab5582fSPyun YongHyeon 1233aab5582fSPyun YongHyeon ctx.nfe_busaddr = 0; 1234aab5582fSPyun YongHyeon error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc, 1235aab5582fSPyun YongHyeon NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1236aab5582fSPyun YongHyeon if (error != 0) { 1237aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1238aab5582fSPyun YongHyeon "could not load DMA'able memory for jumbo Rx ring\n"); 1239aab5582fSPyun YongHyeon goto fail; 1240aab5582fSPyun YongHyeon } 1241aab5582fSPyun YongHyeon ring->jphysaddr = ctx.nfe_busaddr; 1242aab5582fSPyun YongHyeon 1243aab5582fSPyun YongHyeon /* Create DMA maps for jumbo Rx buffers. */ 1244aab5582fSPyun YongHyeon error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map); 1245aab5582fSPyun YongHyeon if (error != 0) { 1246aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1247aab5582fSPyun YongHyeon "could not create jumbo Rx DMA spare map\n"); 1248aab5582fSPyun YongHyeon goto fail; 1249aab5582fSPyun YongHyeon } 1250aab5582fSPyun YongHyeon 1251aab5582fSPyun YongHyeon for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1252aab5582fSPyun YongHyeon data = &sc->jrxq.jdata[i]; 1253aab5582fSPyun YongHyeon data->rx_data_map = NULL; 1254aab5582fSPyun YongHyeon data->m = NULL; 1255aab5582fSPyun YongHyeon error = bus_dmamap_create(ring->jrx_data_tag, 0, 1256aab5582fSPyun YongHyeon &data->rx_data_map); 1257aab5582fSPyun YongHyeon if (error != 0) { 1258aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1259aab5582fSPyun YongHyeon "could not create jumbo Rx DMA map\n"); 1260aab5582fSPyun YongHyeon goto fail; 1261aab5582fSPyun YongHyeon } 1262aab5582fSPyun YongHyeon } 1263aab5582fSPyun YongHyeon 1264aab5582fSPyun YongHyeon /* Allocate DMA'able memory and load the DMA map for jumbo buf. */ 1265aab5582fSPyun YongHyeon error = bus_dmamem_alloc(ring->jrx_jumbo_tag, (void **)&ring->jpool, 1266aab5582fSPyun YongHyeon BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 1267aab5582fSPyun YongHyeon &ring->jrx_jumbo_map); 1268aab5582fSPyun YongHyeon if (error != 0) { 1269aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1270aab5582fSPyun YongHyeon "could not allocate DMA'able memory for jumbo pool\n"); 1271aab5582fSPyun YongHyeon goto fail; 1272aab5582fSPyun YongHyeon } 1273aab5582fSPyun YongHyeon 1274aab5582fSPyun YongHyeon ctx.nfe_busaddr = 0; 1275aab5582fSPyun YongHyeon error = bus_dmamap_load(ring->jrx_jumbo_tag, ring->jrx_jumbo_map, 1276aab5582fSPyun YongHyeon ring->jpool, NFE_JMEM, nfe_dma_map_segs, &ctx, 0); 1277aab5582fSPyun YongHyeon if (error != 0) { 1278aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1279aab5582fSPyun YongHyeon "could not load DMA'able memory for jumbo pool\n"); 1280aab5582fSPyun YongHyeon goto fail; 1281aab5582fSPyun YongHyeon } 1282aab5582fSPyun YongHyeon 1283aab5582fSPyun YongHyeon /* 1284aab5582fSPyun YongHyeon * Now divide it up into 9K pieces and save the addresses 1285aab5582fSPyun YongHyeon * in an array. 1286aab5582fSPyun YongHyeon */ 1287aab5582fSPyun YongHyeon ptr = ring->jpool; 1288aab5582fSPyun YongHyeon for (i = 0; i < NFE_JSLOTS; i++) { 1289aab5582fSPyun YongHyeon ring->jslots[i] = ptr; 1290aab5582fSPyun YongHyeon ptr += NFE_JLEN; 1291aab5582fSPyun YongHyeon entry = malloc(sizeof(struct nfe_jpool_entry), M_DEVBUF, 1292aab5582fSPyun YongHyeon M_WAITOK); 1293aab5582fSPyun YongHyeon if (entry == NULL) { 1294aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1295aab5582fSPyun YongHyeon "no memory for jumbo buffers!\n"); 1296bfc788c2SDavid E. O'Brien error = ENOMEM; 1297bfc788c2SDavid E. O'Brien goto fail; 1298bfc788c2SDavid E. O'Brien } 1299aab5582fSPyun YongHyeon entry->slot = i; 1300aab5582fSPyun YongHyeon SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry, 1301aab5582fSPyun YongHyeon jpool_entries); 1302bfc788c2SDavid E. O'Brien } 1303bfc788c2SDavid E. O'Brien 1304aab5582fSPyun YongHyeon return (0); 1305bfc788c2SDavid E. O'Brien 1306aab5582fSPyun YongHyeon fail: 1307aab5582fSPyun YongHyeon nfe_free_jrx_ring(sc, ring); 1308aab5582fSPyun YongHyeon return (error); 1309bfc788c2SDavid E. O'Brien } 1310bfc788c2SDavid E. O'Brien 13112c3adf61SDavid E. O'Brien 1312aab5582fSPyun YongHyeon static int 1313aab5582fSPyun YongHyeon nfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1314bfc788c2SDavid E. O'Brien { 1315aab5582fSPyun YongHyeon void *desc; 1316aab5582fSPyun YongHyeon size_t descsize; 1317bfc788c2SDavid E. O'Brien int i; 1318bfc788c2SDavid E. O'Brien 1319aab5582fSPyun YongHyeon ring->cur = ring->next = 0; 1320bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1321aab5582fSPyun YongHyeon desc = ring->desc64; 1322aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc64); 1323bfc788c2SDavid E. O'Brien } else { 1324aab5582fSPyun YongHyeon desc = ring->desc32; 1325aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc32); 1326bfc788c2SDavid E. O'Brien } 1327aab5582fSPyun YongHyeon bzero(desc, descsize * NFE_RX_RING_COUNT); 1328aab5582fSPyun YongHyeon for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1329aab5582fSPyun YongHyeon if (nfe_newbuf(sc, i) != 0) 1330aab5582fSPyun YongHyeon return (ENOBUFS); 1331bfc788c2SDavid E. O'Brien } 1332bfc788c2SDavid E. O'Brien 13332c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 1334aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1335bfc788c2SDavid E. O'Brien 1336aab5582fSPyun YongHyeon return (0); 1337aab5582fSPyun YongHyeon } 1338aab5582fSPyun YongHyeon 1339aab5582fSPyun YongHyeon 1340aab5582fSPyun YongHyeon static int 1341aab5582fSPyun YongHyeon nfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1342aab5582fSPyun YongHyeon { 1343aab5582fSPyun YongHyeon void *desc; 1344aab5582fSPyun YongHyeon size_t descsize; 1345aab5582fSPyun YongHyeon int i; 1346aab5582fSPyun YongHyeon 1347aab5582fSPyun YongHyeon ring->jcur = ring->jnext = 0; 1348aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 1349aab5582fSPyun YongHyeon desc = ring->jdesc64; 1350aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc64); 1351aab5582fSPyun YongHyeon } else { 1352aab5582fSPyun YongHyeon desc = ring->jdesc32; 1353aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc32); 1354aab5582fSPyun YongHyeon } 1355aab5582fSPyun YongHyeon bzero(desc, descsize * NFE_RX_RING_COUNT); 1356aab5582fSPyun YongHyeon for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1357aab5582fSPyun YongHyeon if (nfe_jnewbuf(sc, i) != 0) 1358aab5582fSPyun YongHyeon return (ENOBUFS); 1359aab5582fSPyun YongHyeon } 1360aab5582fSPyun YongHyeon 1361aab5582fSPyun YongHyeon bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map, 1362aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1363aab5582fSPyun YongHyeon 1364aab5582fSPyun YongHyeon return (0); 1365bfc788c2SDavid E. O'Brien } 1366bfc788c2SDavid E. O'Brien 1367bfc788c2SDavid E. O'Brien 1368bfc788c2SDavid E. O'Brien static void 1369bfc788c2SDavid E. O'Brien nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1370bfc788c2SDavid E. O'Brien { 1371bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 1372bfc788c2SDavid E. O'Brien void *desc; 1373bfc788c2SDavid E. O'Brien int i, descsize; 1374bfc788c2SDavid E. O'Brien 1375bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1376bfc788c2SDavid E. O'Brien desc = ring->desc64; 1377bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1378bfc788c2SDavid E. O'Brien } else { 1379bfc788c2SDavid E. O'Brien desc = ring->desc32; 1380bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1381bfc788c2SDavid E. O'Brien } 1382bfc788c2SDavid E. O'Brien 1383bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1384bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1385bfc788c2SDavid E. O'Brien if (data->rx_data_map != NULL) { 1386aab5582fSPyun YongHyeon bus_dmamap_destroy(ring->rx_data_tag, 13872c3adf61SDavid E. O'Brien data->rx_data_map); 1388aab5582fSPyun YongHyeon data->rx_data_map = NULL; 1389aab5582fSPyun YongHyeon } 1390aab5582fSPyun YongHyeon if (data->m != NULL) { 1391aab5582fSPyun YongHyeon m_freem(data->m); 1392aab5582fSPyun YongHyeon data->m = NULL; 1393aab5582fSPyun YongHyeon } 1394aab5582fSPyun YongHyeon } 1395aab5582fSPyun YongHyeon if (ring->rx_data_tag != NULL) { 1396aab5582fSPyun YongHyeon if (ring->rx_spare_map != NULL) { 1397aab5582fSPyun YongHyeon bus_dmamap_destroy(ring->rx_data_tag, 1398aab5582fSPyun YongHyeon ring->rx_spare_map); 1399aab5582fSPyun YongHyeon ring->rx_spare_map = NULL; 1400aab5582fSPyun YongHyeon } 1401aab5582fSPyun YongHyeon bus_dma_tag_destroy(ring->rx_data_tag); 1402aab5582fSPyun YongHyeon ring->rx_data_tag = NULL; 1403bfc788c2SDavid E. O'Brien } 14042c3adf61SDavid E. O'Brien 1405aab5582fSPyun YongHyeon if (desc != NULL) { 1406aab5582fSPyun YongHyeon bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 1407aab5582fSPyun YongHyeon bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 1408aab5582fSPyun YongHyeon ring->desc64 = NULL; 1409aab5582fSPyun YongHyeon ring->desc32 = NULL; 1410aab5582fSPyun YongHyeon ring->rx_desc_map = NULL; 1411aab5582fSPyun YongHyeon } 1412aab5582fSPyun YongHyeon if (ring->rx_desc_tag != NULL) { 1413aab5582fSPyun YongHyeon bus_dma_tag_destroy(ring->rx_desc_tag); 1414aab5582fSPyun YongHyeon ring->rx_desc_tag = NULL; 1415aab5582fSPyun YongHyeon } 1416aab5582fSPyun YongHyeon } 1417aab5582fSPyun YongHyeon 1418aab5582fSPyun YongHyeon 1419aab5582fSPyun YongHyeon static void 1420aab5582fSPyun YongHyeon nfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1421aab5582fSPyun YongHyeon { 1422aab5582fSPyun YongHyeon struct nfe_jpool_entry *entry; 1423aab5582fSPyun YongHyeon struct nfe_rx_data *data; 1424aab5582fSPyun YongHyeon void *desc; 1425aab5582fSPyun YongHyeon int i, descsize; 1426aab5582fSPyun YongHyeon 1427aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1428aab5582fSPyun YongHyeon return; 1429aab5582fSPyun YongHyeon 1430aab5582fSPyun YongHyeon NFE_JLIST_LOCK(sc); 1431aab5582fSPyun YongHyeon while ((entry = SLIST_FIRST(&sc->nfe_jinuse_listhead))) { 1432aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1433aab5582fSPyun YongHyeon "asked to free buffer that is in use!\n"); 1434aab5582fSPyun YongHyeon SLIST_REMOVE_HEAD(&sc->nfe_jinuse_listhead, jpool_entries); 1435aab5582fSPyun YongHyeon SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry, 1436aab5582fSPyun YongHyeon jpool_entries); 1437aab5582fSPyun YongHyeon } 1438aab5582fSPyun YongHyeon 1439aab5582fSPyun YongHyeon while (!SLIST_EMPTY(&sc->nfe_jfree_listhead)) { 1440aab5582fSPyun YongHyeon entry = SLIST_FIRST(&sc->nfe_jfree_listhead); 1441aab5582fSPyun YongHyeon SLIST_REMOVE_HEAD(&sc->nfe_jfree_listhead, jpool_entries); 1442aab5582fSPyun YongHyeon free(entry, M_DEVBUF); 1443aab5582fSPyun YongHyeon } 1444aab5582fSPyun YongHyeon NFE_JLIST_UNLOCK(sc); 1445aab5582fSPyun YongHyeon 1446aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 1447aab5582fSPyun YongHyeon desc = ring->jdesc64; 1448aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc64); 1449aab5582fSPyun YongHyeon } else { 1450aab5582fSPyun YongHyeon desc = ring->jdesc32; 1451aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc32); 1452aab5582fSPyun YongHyeon } 1453aab5582fSPyun YongHyeon 1454aab5582fSPyun YongHyeon for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1455aab5582fSPyun YongHyeon data = &ring->jdata[i]; 1456aab5582fSPyun YongHyeon if (data->rx_data_map != NULL) { 1457aab5582fSPyun YongHyeon bus_dmamap_destroy(ring->jrx_data_tag, 1458aab5582fSPyun YongHyeon data->rx_data_map); 1459aab5582fSPyun YongHyeon data->rx_data_map = NULL; 1460aab5582fSPyun YongHyeon } 1461aab5582fSPyun YongHyeon if (data->m != NULL) { 1462bfc788c2SDavid E. O'Brien m_freem(data->m); 1463aab5582fSPyun YongHyeon data->m = NULL; 1464aab5582fSPyun YongHyeon } 1465aab5582fSPyun YongHyeon } 1466aab5582fSPyun YongHyeon if (ring->jrx_data_tag != NULL) { 1467aab5582fSPyun YongHyeon if (ring->jrx_spare_map != NULL) { 1468aab5582fSPyun YongHyeon bus_dmamap_destroy(ring->jrx_data_tag, 1469aab5582fSPyun YongHyeon ring->jrx_spare_map); 1470aab5582fSPyun YongHyeon ring->jrx_spare_map = NULL; 1471aab5582fSPyun YongHyeon } 1472aab5582fSPyun YongHyeon bus_dma_tag_destroy(ring->jrx_data_tag); 1473aab5582fSPyun YongHyeon ring->jrx_data_tag = NULL; 1474aab5582fSPyun YongHyeon } 1475aab5582fSPyun YongHyeon 1476aab5582fSPyun YongHyeon if (desc != NULL) { 1477aab5582fSPyun YongHyeon bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1478aab5582fSPyun YongHyeon bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1479aab5582fSPyun YongHyeon ring->jdesc64 = NULL; 1480aab5582fSPyun YongHyeon ring->jdesc32 = NULL; 1481aab5582fSPyun YongHyeon ring->jrx_desc_map = NULL; 1482aab5582fSPyun YongHyeon } 1483aab5582fSPyun YongHyeon /* Destroy jumbo buffer block. */ 1484aab5582fSPyun YongHyeon if (ring->jrx_jumbo_map != NULL) 1485aab5582fSPyun YongHyeon bus_dmamap_unload(ring->jrx_jumbo_tag, ring->jrx_jumbo_map); 1486aab5582fSPyun YongHyeon if (ring->jrx_jumbo_map != NULL) { 1487aab5582fSPyun YongHyeon bus_dmamem_free(ring->jrx_jumbo_tag, ring->jpool, 1488aab5582fSPyun YongHyeon ring->jrx_jumbo_map); 1489aab5582fSPyun YongHyeon ring->jpool = NULL; 1490aab5582fSPyun YongHyeon ring->jrx_jumbo_map = NULL; 1491aab5582fSPyun YongHyeon } 1492aab5582fSPyun YongHyeon if (ring->jrx_desc_tag != NULL) { 1493aab5582fSPyun YongHyeon bus_dma_tag_destroy(ring->jrx_desc_tag); 1494aab5582fSPyun YongHyeon ring->jrx_desc_tag = NULL; 1495bfc788c2SDavid E. O'Brien } 1496bfc788c2SDavid E. O'Brien } 1497bfc788c2SDavid E. O'Brien 14982c3adf61SDavid E. O'Brien 1499bfc788c2SDavid E. O'Brien static int 1500bfc788c2SDavid E. O'Brien nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1501bfc788c2SDavid E. O'Brien { 1502aab5582fSPyun YongHyeon struct nfe_dmamap_arg ctx; 1503bfc788c2SDavid E. O'Brien int i, error; 1504aab5582fSPyun YongHyeon void *desc; 1505bfc788c2SDavid E. O'Brien int descsize; 1506bfc788c2SDavid E. O'Brien 1507bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1508aab5582fSPyun YongHyeon desc = ring->desc64; 1509bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1510bfc788c2SDavid E. O'Brien } else { 1511aab5582fSPyun YongHyeon desc = ring->desc32; 1512bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1513bfc788c2SDavid E. O'Brien } 1514bfc788c2SDavid E. O'Brien 1515bfc788c2SDavid E. O'Brien ring->queued = 0; 1516bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 1517bfc788c2SDavid E. O'Brien 1518bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 1519aab5582fSPyun YongHyeon NFE_RING_ALIGN, 0, /* alignment, boundary */ 1520aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, /* lowaddr */ 1521bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 1522bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 1523bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1524bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1525aab5582fSPyun YongHyeon 0, /* flags */ 1526bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 1527bfc788c2SDavid E. O'Brien &ring->tx_desc_tag); 1528bfc788c2SDavid E. O'Brien if (error != 0) { 1529aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1530bfc788c2SDavid E. O'Brien goto fail; 1531bfc788c2SDavid E. O'Brien } 1532bfc788c2SDavid E. O'Brien 1533aab5582fSPyun YongHyeon error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1534aab5582fSPyun YongHyeon BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1535bfc788c2SDavid E. O'Brien if (error != 0) { 1536aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1537bfc788c2SDavid E. O'Brien goto fail; 1538bfc788c2SDavid E. O'Brien } 1539aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) 1540aab5582fSPyun YongHyeon ring->desc64 = desc; 1541aab5582fSPyun YongHyeon else 1542aab5582fSPyun YongHyeon ring->desc32 = desc; 1543bfc788c2SDavid E. O'Brien 1544aab5582fSPyun YongHyeon ctx.nfe_busaddr = 0; 1545aab5582fSPyun YongHyeon error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1546aab5582fSPyun YongHyeon NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1547bfc788c2SDavid E. O'Brien if (error != 0) { 1548aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1549bfc788c2SDavid E. O'Brien goto fail; 1550bfc788c2SDavid E. O'Brien } 1551aab5582fSPyun YongHyeon ring->physaddr = ctx.nfe_busaddr; 1552bfc788c2SDavid E. O'Brien 1553bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 1554aab5582fSPyun YongHyeon 1, 0, 1555aab5582fSPyun YongHyeon BUS_SPACE_MAXADDR, 1556bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, 1557bfc788c2SDavid E. O'Brien NULL, NULL, 1558aab5582fSPyun YongHyeon MCLBYTES * NFE_MAX_SCATTER, 1559aab5582fSPyun YongHyeon NFE_MAX_SCATTER, 1560aab5582fSPyun YongHyeon MCLBYTES, 1561aab5582fSPyun YongHyeon 0, 1562bfc788c2SDavid E. O'Brien NULL, NULL, 1563bfc788c2SDavid E. O'Brien &ring->tx_data_tag); 1564bfc788c2SDavid E. O'Brien if (error != 0) { 1565aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1566bfc788c2SDavid E. O'Brien goto fail; 1567bfc788c2SDavid E. O'Brien } 1568bfc788c2SDavid E. O'Brien 1569bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 15702c3adf61SDavid E. O'Brien error = bus_dmamap_create(ring->tx_data_tag, 0, 15712c3adf61SDavid E. O'Brien &ring->data[i].tx_data_map); 1572bfc788c2SDavid E. O'Brien if (error != 0) { 1573aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 1574aab5582fSPyun YongHyeon "could not create Tx DMA map\n"); 1575bfc788c2SDavid E. O'Brien goto fail; 1576bfc788c2SDavid E. O'Brien } 1577bfc788c2SDavid E. O'Brien } 1578bfc788c2SDavid E. O'Brien 1579aab5582fSPyun YongHyeon fail: 1580aab5582fSPyun YongHyeon return (error); 1581bfc788c2SDavid E. O'Brien } 1582bfc788c2SDavid E. O'Brien 1583bfc788c2SDavid E. O'Brien 1584bfc788c2SDavid E. O'Brien static void 1585aab5582fSPyun YongHyeon nfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1586bfc788c2SDavid E. O'Brien { 1587aab5582fSPyun YongHyeon void *desc; 1588aab5582fSPyun YongHyeon size_t descsize; 1589bfc788c2SDavid E. O'Brien 1590aab5582fSPyun YongHyeon sc->nfe_force_tx = 0; 1591bfc788c2SDavid E. O'Brien ring->queued = 0; 1592bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 1593aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 1594aab5582fSPyun YongHyeon desc = ring->desc64; 1595aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc64); 1596aab5582fSPyun YongHyeon } else { 1597aab5582fSPyun YongHyeon desc = ring->desc32; 1598aab5582fSPyun YongHyeon descsize = sizeof (struct nfe_desc32); 1599aab5582fSPyun YongHyeon } 1600aab5582fSPyun YongHyeon bzero(desc, descsize * NFE_TX_RING_COUNT); 1601aab5582fSPyun YongHyeon 1602aab5582fSPyun YongHyeon bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1603aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1604bfc788c2SDavid E. O'Brien } 1605bfc788c2SDavid E. O'Brien 16062c3adf61SDavid E. O'Brien 1607bfc788c2SDavid E. O'Brien static void 1608bfc788c2SDavid E. O'Brien nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1609bfc788c2SDavid E. O'Brien { 1610bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 1611bfc788c2SDavid E. O'Brien void *desc; 1612bfc788c2SDavid E. O'Brien int i, descsize; 1613bfc788c2SDavid E. O'Brien 1614bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1615bfc788c2SDavid E. O'Brien desc = ring->desc64; 1616bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1617bfc788c2SDavid E. O'Brien } else { 1618bfc788c2SDavid E. O'Brien desc = ring->desc32; 1619bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1620bfc788c2SDavid E. O'Brien } 1621bfc788c2SDavid E. O'Brien 1622aab5582fSPyun YongHyeon for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1623aab5582fSPyun YongHyeon data = &ring->data[i]; 1624aab5582fSPyun YongHyeon 1625aab5582fSPyun YongHyeon if (data->m != NULL) { 1626aab5582fSPyun YongHyeon bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1627aab5582fSPyun YongHyeon BUS_DMASYNC_POSTWRITE); 1628aab5582fSPyun YongHyeon bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1629aab5582fSPyun YongHyeon m_freem(data->m); 1630aab5582fSPyun YongHyeon data->m = NULL; 1631aab5582fSPyun YongHyeon } 1632aab5582fSPyun YongHyeon if (data->tx_data_map != NULL) { 1633aab5582fSPyun YongHyeon bus_dmamap_destroy(ring->tx_data_tag, 1634aab5582fSPyun YongHyeon data->tx_data_map); 1635aab5582fSPyun YongHyeon data->tx_data_map = NULL; 1636aab5582fSPyun YongHyeon } 1637aab5582fSPyun YongHyeon } 1638aab5582fSPyun YongHyeon 1639aab5582fSPyun YongHyeon if (ring->tx_data_tag != NULL) { 1640aab5582fSPyun YongHyeon bus_dma_tag_destroy(ring->tx_data_tag); 1641aab5582fSPyun YongHyeon ring->tx_data_tag = NULL; 1642aab5582fSPyun YongHyeon } 1643aab5582fSPyun YongHyeon 1644bfc788c2SDavid E. O'Brien if (desc != NULL) { 16452c3adf61SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 16462c3adf61SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1647bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1648bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1649aab5582fSPyun YongHyeon ring->desc64 = NULL; 1650aab5582fSPyun YongHyeon ring->desc32 = NULL; 1651aab5582fSPyun YongHyeon ring->tx_desc_map = NULL; 1652bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_desc_tag); 1653aab5582fSPyun YongHyeon ring->tx_desc_tag = NULL; 1654bfc788c2SDavid E. O'Brien } 1655bfc788c2SDavid E. O'Brien } 1656bfc788c2SDavid E. O'Brien 1657bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1658bfc788c2SDavid E. O'Brien static poll_handler_t nfe_poll; 1659bfc788c2SDavid E. O'Brien 16602c3adf61SDavid E. O'Brien 1661bfc788c2SDavid E. O'Brien static void 1662bfc788c2SDavid E. O'Brien nfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1663bfc788c2SDavid E. O'Brien { 1664bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1665aab5582fSPyun YongHyeon uint32_t r; 1666bfc788c2SDavid E. O'Brien 1667bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1668bfc788c2SDavid E. O'Brien 1669bfc788c2SDavid E. O'Brien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1670aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 1671bfc788c2SDavid E. O'Brien return; 1672bfc788c2SDavid E. O'Brien } 1673bfc788c2SDavid E. O'Brien 1674aab5582fSPyun YongHyeon nfe_rxeof(sc, count); 1675bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1676bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1677aab5582fSPyun YongHyeon taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_tx_task); 1678bfc788c2SDavid E. O'Brien 1679bfc788c2SDavid E. O'Brien if (cmd == POLL_AND_CHECK_STATUS) { 1680aab5582fSPyun YongHyeon if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1681aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 1682bfc788c2SDavid E. O'Brien return; 1683bfc788c2SDavid E. O'Brien } 1684aab5582fSPyun YongHyeon NFE_WRITE(sc, sc->nfe_irq_status, r); 1685257c5577SDavid E. O'Brien 1686257c5577SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1687257c5577SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1688257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1689aab5582fSPyun YongHyeon DPRINTF(sc, "link state changed\n"); 1690257c5577SDavid E. O'Brien } 1691257c5577SDavid E. O'Brien } 1692aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 1693257c5577SDavid E. O'Brien } 1694bfc788c2SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1695257c5577SDavid E. O'Brien 1696aab5582fSPyun YongHyeon static void 1697aab5582fSPyun YongHyeon nfe_set_intr(struct nfe_softc *sc) 1698aab5582fSPyun YongHyeon { 1699aab5582fSPyun YongHyeon 1700aab5582fSPyun YongHyeon if (sc->nfe_msi != 0) 1701aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1702aab5582fSPyun YongHyeon } 1703aab5582fSPyun YongHyeon 1704aab5582fSPyun YongHyeon 1705aab5582fSPyun YongHyeon /* In MSIX, a write to mask reegisters behaves as XOR. */ 1706aab5582fSPyun YongHyeon static __inline void 1707aab5582fSPyun YongHyeon nfe_enable_intr(struct nfe_softc *sc) 1708aab5582fSPyun YongHyeon { 1709aab5582fSPyun YongHyeon 1710aab5582fSPyun YongHyeon if (sc->nfe_msix != 0) { 1711aab5582fSPyun YongHyeon /* XXX Should have a better way to enable interrupts! */ 1712aab5582fSPyun YongHyeon if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1713aab5582fSPyun YongHyeon NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1714aab5582fSPyun YongHyeon } else 1715aab5582fSPyun YongHyeon NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1716aab5582fSPyun YongHyeon } 1717aab5582fSPyun YongHyeon 1718aab5582fSPyun YongHyeon 1719aab5582fSPyun YongHyeon static __inline void 1720aab5582fSPyun YongHyeon nfe_disable_intr(struct nfe_softc *sc) 1721aab5582fSPyun YongHyeon { 1722aab5582fSPyun YongHyeon 1723aab5582fSPyun YongHyeon if (sc->nfe_msix != 0) { 1724aab5582fSPyun YongHyeon /* XXX Should have a better way to disable interrupts! */ 1725aab5582fSPyun YongHyeon if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1726aab5582fSPyun YongHyeon NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1727aab5582fSPyun YongHyeon } else 1728aab5582fSPyun YongHyeon NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1729aab5582fSPyun YongHyeon } 1730aab5582fSPyun YongHyeon 1731bfc788c2SDavid E. O'Brien 1732bfc788c2SDavid E. O'Brien static int 1733257c5577SDavid E. O'Brien nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1734257c5577SDavid E. O'Brien { 1735aab5582fSPyun YongHyeon struct nfe_softc *sc; 1736aab5582fSPyun YongHyeon struct ifreq *ifr; 1737bfc788c2SDavid E. O'Brien struct mii_data *mii; 1738aab5582fSPyun YongHyeon int error, init, mask; 1739257c5577SDavid E. O'Brien 1740aab5582fSPyun YongHyeon sc = ifp->if_softc; 1741aab5582fSPyun YongHyeon ifr = (struct ifreq *) data; 1742aab5582fSPyun YongHyeon error = 0; 1743aab5582fSPyun YongHyeon init = 0; 1744257c5577SDavid E. O'Brien switch (cmd) { 1745257c5577SDavid E. O'Brien case SIOCSIFMTU: 1746aab5582fSPyun YongHyeon if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1747257c5577SDavid E. O'Brien error = EINVAL; 1748aab5582fSPyun YongHyeon else if (ifp->if_mtu != ifr->ifr_mtu) { 1749aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0 && 1750aab5582fSPyun YongHyeon ifr->ifr_mtu > ETHERMTU) 1751aab5582fSPyun YongHyeon error = EINVAL; 1752aab5582fSPyun YongHyeon else { 17536124fe21SDavid E. O'Brien NFE_LOCK(sc); 1754aab5582fSPyun YongHyeon ifp->if_mtu = ifr->ifr_mtu; 1755aab5582fSPyun YongHyeon if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 17566124fe21SDavid E. O'Brien nfe_init_locked(sc); 17576124fe21SDavid E. O'Brien NFE_UNLOCK(sc); 1758aab5582fSPyun YongHyeon } 1759bfc788c2SDavid E. O'Brien } 1760257c5577SDavid E. O'Brien break; 1761257c5577SDavid E. O'Brien case SIOCSIFFLAGS: 1762bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1763257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 1764257c5577SDavid E. O'Brien /* 1765257c5577SDavid E. O'Brien * If only the PROMISC or ALLMULTI flag changes, then 1766257c5577SDavid E. O'Brien * don't do a full re-init of the chip, just update 1767257c5577SDavid E. O'Brien * the Rx filter. 1768257c5577SDavid E. O'Brien */ 1769bfc788c2SDavid E. O'Brien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1770bfc788c2SDavid E. O'Brien ((ifp->if_flags ^ sc->nfe_if_flags) & 1771bfc788c2SDavid E. O'Brien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1772257c5577SDavid E. O'Brien nfe_setmulti(sc); 1773bfc788c2SDavid E. O'Brien else 1774bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1775257c5577SDavid E. O'Brien } else { 1776bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1777aab5582fSPyun YongHyeon nfe_stop(ifp); 1778257c5577SDavid E. O'Brien } 1779bfc788c2SDavid E. O'Brien sc->nfe_if_flags = ifp->if_flags; 1780bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1781bfc788c2SDavid E. O'Brien error = 0; 1782257c5577SDavid E. O'Brien break; 1783257c5577SDavid E. O'Brien case SIOCADDMULTI: 1784257c5577SDavid E. O'Brien case SIOCDELMULTI: 1785aab5582fSPyun YongHyeon if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1786bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1787257c5577SDavid E. O'Brien nfe_setmulti(sc); 1788bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1789257c5577SDavid E. O'Brien error = 0; 1790257c5577SDavid E. O'Brien } 1791257c5577SDavid E. O'Brien break; 1792257c5577SDavid E. O'Brien case SIOCSIFMEDIA: 1793257c5577SDavid E. O'Brien case SIOCGIFMEDIA: 1794bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1795bfc788c2SDavid E. O'Brien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1796257c5577SDavid E. O'Brien break; 1797bfc788c2SDavid E. O'Brien case SIOCSIFCAP: 1798aab5582fSPyun YongHyeon mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1799bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1800aab5582fSPyun YongHyeon if ((mask & IFCAP_POLLING) != 0) { 1801aab5582fSPyun YongHyeon if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1802bfc788c2SDavid E. O'Brien error = ether_poll_register(nfe_poll, ifp); 1803bfc788c2SDavid E. O'Brien if (error) 1804aab5582fSPyun YongHyeon break; 1805bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1806aab5582fSPyun YongHyeon nfe_disable_intr(sc); 1807bfc788c2SDavid E. O'Brien ifp->if_capenable |= IFCAP_POLLING; 1808bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1809bfc788c2SDavid E. O'Brien } else { 1810bfc788c2SDavid E. O'Brien error = ether_poll_deregister(ifp); 1811bfc788c2SDavid E. O'Brien /* Enable interrupt even in error case */ 1812bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1813aab5582fSPyun YongHyeon nfe_enable_intr(sc); 1814bfc788c2SDavid E. O'Brien ifp->if_capenable &= ~IFCAP_POLLING; 1815bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1816257c5577SDavid E. O'Brien } 1817bfc788c2SDavid E. O'Brien } 18182c3adf61SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1819aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_HW_CSUM) != 0 && 1820aab5582fSPyun YongHyeon (mask & IFCAP_HWCSUM) != 0) { 1821bfc788c2SDavid E. O'Brien ifp->if_capenable ^= IFCAP_HWCSUM; 1822aab5582fSPyun YongHyeon if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 && 1823aab5582fSPyun YongHyeon (IFCAP_TXCSUM & ifp->if_capabilities) != 0) 1824aab5582fSPyun YongHyeon ifp->if_hwassist |= NFE_CSUM_FEATURES; 1825bfc788c2SDavid E. O'Brien else 1826aab5582fSPyun YongHyeon ifp->if_hwassist &= ~NFE_CSUM_FEATURES; 1827aab5582fSPyun YongHyeon init++; 1828bfc788c2SDavid E. O'Brien } 1829aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_HW_VLAN) != 0 && 1830aab5582fSPyun YongHyeon (mask & IFCAP_VLAN_HWTAGGING) != 0) { 1831aab5582fSPyun YongHyeon ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1832aab5582fSPyun YongHyeon init++; 1833aab5582fSPyun YongHyeon } 1834aab5582fSPyun YongHyeon /* 1835aab5582fSPyun YongHyeon * XXX 1836aab5582fSPyun YongHyeon * It seems that VLAN stripping requires Rx checksum offload. 1837aab5582fSPyun YongHyeon * Unfortunately FreeBSD has no way to disable only Rx side 1838aab5582fSPyun YongHyeon * VLAN stripping. So when we know Rx checksum offload is 1839aab5582fSPyun YongHyeon * disabled turn entire hardware VLAN assist off. 1840aab5582fSPyun YongHyeon */ 1841aab5582fSPyun YongHyeon if ((sc->nfe_flags & (NFE_HW_CSUM | NFE_HW_VLAN)) == 1842aab5582fSPyun YongHyeon (NFE_HW_CSUM | NFE_HW_VLAN)) { 1843aab5582fSPyun YongHyeon if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) 1844aab5582fSPyun YongHyeon ifp->if_capenable &= ~IFCAP_VLAN_HWTAGGING; 1845aab5582fSPyun YongHyeon } 1846aab5582fSPyun YongHyeon 1847aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_HW_CSUM) != 0 && 1848aab5582fSPyun YongHyeon (mask & IFCAP_TSO4) != 0) { 1849aab5582fSPyun YongHyeon ifp->if_capenable ^= IFCAP_TSO4; 1850aab5582fSPyun YongHyeon if ((IFCAP_TSO4 & ifp->if_capenable) != 0 && 1851aab5582fSPyun YongHyeon (IFCAP_TSO4 & ifp->if_capabilities) != 0) 1852aab5582fSPyun YongHyeon ifp->if_hwassist |= CSUM_TSO; 1853aab5582fSPyun YongHyeon else 1854aab5582fSPyun YongHyeon ifp->if_hwassist &= ~CSUM_TSO; 1855aab5582fSPyun YongHyeon } 1856aab5582fSPyun YongHyeon 1857aab5582fSPyun YongHyeon if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1858aab5582fSPyun YongHyeon ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 18597597761aSDavid E. O'Brien nfe_init(sc); 1860bfc788c2SDavid E. O'Brien } 1861aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_HW_VLAN) != 0) 1862aab5582fSPyun YongHyeon VLAN_CAPABILITIES(ifp); 1863bfc788c2SDavid E. O'Brien break; 1864bfc788c2SDavid E. O'Brien default: 1865bfc788c2SDavid E. O'Brien error = ether_ioctl(ifp, cmd, data); 1866bfc788c2SDavid E. O'Brien break; 1867bfc788c2SDavid E. O'Brien } 1868257c5577SDavid E. O'Brien 1869aab5582fSPyun YongHyeon return (error); 1870aab5582fSPyun YongHyeon } 1871aab5582fSPyun YongHyeon 1872aab5582fSPyun YongHyeon 1873aab5582fSPyun YongHyeon static int 1874aab5582fSPyun YongHyeon nfe_intr(void *arg) 1875aab5582fSPyun YongHyeon { 1876aab5582fSPyun YongHyeon struct nfe_softc *sc; 1877aab5582fSPyun YongHyeon uint32_t status; 1878aab5582fSPyun YongHyeon 1879aab5582fSPyun YongHyeon sc = (struct nfe_softc *)arg; 1880aab5582fSPyun YongHyeon 1881aab5582fSPyun YongHyeon status = NFE_READ(sc, sc->nfe_irq_status); 1882aab5582fSPyun YongHyeon if (status == 0 || status == 0xffffffff) 1883aab5582fSPyun YongHyeon return (FILTER_STRAY); 1884aab5582fSPyun YongHyeon nfe_disable_intr(sc); 1885aab5582fSPyun YongHyeon taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_int_task); 1886aab5582fSPyun YongHyeon 1887aab5582fSPyun YongHyeon return (FILTER_HANDLED); 1888257c5577SDavid E. O'Brien } 1889257c5577SDavid E. O'Brien 1890bfc788c2SDavid E. O'Brien 18912c3adf61SDavid E. O'Brien static void 1892aab5582fSPyun YongHyeon nfe_int_task(void *arg, int pending) 1893bfc788c2SDavid E. O'Brien { 1894bfc788c2SDavid E. O'Brien struct nfe_softc *sc = arg; 1895bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1896aab5582fSPyun YongHyeon uint32_t r; 1897aab5582fSPyun YongHyeon int domore; 1898bfc788c2SDavid E. O'Brien 1899bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1900bfc788c2SDavid E. O'Brien 1901aab5582fSPyun YongHyeon if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1902aab5582fSPyun YongHyeon nfe_enable_intr(sc); 1903aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 1904aab5582fSPyun YongHyeon return; /* not for us */ 1905aab5582fSPyun YongHyeon } 1906aab5582fSPyun YongHyeon NFE_WRITE(sc, sc->nfe_irq_status, r); 1907aab5582fSPyun YongHyeon 1908aab5582fSPyun YongHyeon DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1909aab5582fSPyun YongHyeon 1910bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1911bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1912bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1913bfc788c2SDavid E. O'Brien return; 1914bfc788c2SDavid E. O'Brien } 1915bfc788c2SDavid E. O'Brien #endif 1916bfc788c2SDavid E. O'Brien 1917aab5582fSPyun YongHyeon if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1918bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1919aab5582fSPyun YongHyeon nfe_enable_intr(sc); 1920aab5582fSPyun YongHyeon return; 1921bfc788c2SDavid E. O'Brien } 1922bfc788c2SDavid E. O'Brien 1923bfc788c2SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1924bfc788c2SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1925bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1926aab5582fSPyun YongHyeon DPRINTF(sc, "link state changed\n"); 1927bfc788c2SDavid E. O'Brien } 1928bfc788c2SDavid E. O'Brien 1929aab5582fSPyun YongHyeon domore = 0; 1930bfc788c2SDavid E. O'Brien /* check Rx ring */ 1931aab5582fSPyun YongHyeon if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1932aab5582fSPyun YongHyeon domore = nfe_jrxeof(sc, sc->nfe_process_limit); 1933aab5582fSPyun YongHyeon else 1934aab5582fSPyun YongHyeon domore = nfe_rxeof(sc, sc->nfe_process_limit); 1935bfc788c2SDavid E. O'Brien /* check Tx ring */ 1936bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1937bfc788c2SDavid E. O'Brien 1938aab5582fSPyun YongHyeon if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1939aab5582fSPyun YongHyeon taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_tx_task); 1940bfc788c2SDavid E. O'Brien 1941bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1942bfc788c2SDavid E. O'Brien 1943aab5582fSPyun YongHyeon if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1944aab5582fSPyun YongHyeon taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_int_task); 1945bfc788c2SDavid E. O'Brien return; 1946bfc788c2SDavid E. O'Brien } 1947bfc788c2SDavid E. O'Brien 1948aab5582fSPyun YongHyeon /* Reenable interrupts. */ 1949aab5582fSPyun YongHyeon nfe_enable_intr(sc); 1950257c5577SDavid E. O'Brien } 1951257c5577SDavid E. O'Brien 19522c3adf61SDavid E. O'Brien 1953aab5582fSPyun YongHyeon static __inline void 1954aab5582fSPyun YongHyeon nfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1955257c5577SDavid E. O'Brien { 1956aab5582fSPyun YongHyeon struct nfe_desc32 *desc32; 1957aab5582fSPyun YongHyeon struct nfe_desc64 *desc64; 1958aab5582fSPyun YongHyeon struct nfe_rx_data *data; 1959aab5582fSPyun YongHyeon struct mbuf *m; 19602c3adf61SDavid E. O'Brien 1961aab5582fSPyun YongHyeon data = &sc->rxq.data[idx]; 1962aab5582fSPyun YongHyeon m = data->m; 1963aab5582fSPyun YongHyeon 1964aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 1965aab5582fSPyun YongHyeon desc64 = &sc->rxq.desc64[idx]; 1966aab5582fSPyun YongHyeon /* VLAN packet may have overwritten it. */ 1967aab5582fSPyun YongHyeon desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1968aab5582fSPyun YongHyeon desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1969aab5582fSPyun YongHyeon desc64->length = htole16(m->m_len); 1970aab5582fSPyun YongHyeon desc64->flags = htole16(NFE_RX_READY); 1971aab5582fSPyun YongHyeon } else { 1972aab5582fSPyun YongHyeon desc32 = &sc->rxq.desc32[idx]; 1973aab5582fSPyun YongHyeon desc32->length = htole16(m->m_len); 1974aab5582fSPyun YongHyeon desc32->flags = htole16(NFE_RX_READY); 1975aab5582fSPyun YongHyeon } 1976257c5577SDavid E. O'Brien } 1977257c5577SDavid E. O'Brien 19782c3adf61SDavid E. O'Brien 1979aab5582fSPyun YongHyeon static __inline void 1980aab5582fSPyun YongHyeon nfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1981257c5577SDavid E. O'Brien { 1982aab5582fSPyun YongHyeon struct nfe_desc32 *desc32; 1983aab5582fSPyun YongHyeon struct nfe_desc64 *desc64; 1984aab5582fSPyun YongHyeon struct nfe_rx_data *data; 1985aab5582fSPyun YongHyeon struct mbuf *m; 19862c3adf61SDavid E. O'Brien 1987aab5582fSPyun YongHyeon data = &sc->jrxq.jdata[idx]; 1988aab5582fSPyun YongHyeon m = data->m; 1989aab5582fSPyun YongHyeon 1990aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 1991aab5582fSPyun YongHyeon desc64 = &sc->jrxq.jdesc64[idx]; 1992aab5582fSPyun YongHyeon /* VLAN packet may have overwritten it. */ 1993aab5582fSPyun YongHyeon desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1994aab5582fSPyun YongHyeon desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1995aab5582fSPyun YongHyeon desc64->length = htole16(m->m_len); 1996aab5582fSPyun YongHyeon desc64->flags = htole16(NFE_RX_READY); 1997aab5582fSPyun YongHyeon } else { 1998aab5582fSPyun YongHyeon desc32 = &sc->jrxq.jdesc32[idx]; 1999aab5582fSPyun YongHyeon desc32->length = htole16(m->m_len); 2000aab5582fSPyun YongHyeon desc32->flags = htole16(NFE_RX_READY); 2001aab5582fSPyun YongHyeon } 2002257c5577SDavid E. O'Brien } 2003257c5577SDavid E. O'Brien 20042c3adf61SDavid E. O'Brien 2005aab5582fSPyun YongHyeon static int 2006aab5582fSPyun YongHyeon nfe_newbuf(struct nfe_softc *sc, int idx) 2007257c5577SDavid E. O'Brien { 2008aab5582fSPyun YongHyeon struct nfe_rx_data *data; 2009aab5582fSPyun YongHyeon struct nfe_desc32 *desc32; 2010aab5582fSPyun YongHyeon struct nfe_desc64 *desc64; 2011aab5582fSPyun YongHyeon struct mbuf *m; 2012aab5582fSPyun YongHyeon bus_dma_segment_t segs[1]; 2013aab5582fSPyun YongHyeon bus_dmamap_t map; 2014aab5582fSPyun YongHyeon int nsegs; 20152c3adf61SDavid E. O'Brien 2016aab5582fSPyun YongHyeon m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2017aab5582fSPyun YongHyeon if (m == NULL) 2018aab5582fSPyun YongHyeon return (ENOBUFS); 2019aab5582fSPyun YongHyeon 2020aab5582fSPyun YongHyeon m->m_len = m->m_pkthdr.len = MCLBYTES; 2021aab5582fSPyun YongHyeon m_adj(m, ETHER_ALIGN); 2022aab5582fSPyun YongHyeon 2023aab5582fSPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 2024aab5582fSPyun YongHyeon m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2025aab5582fSPyun YongHyeon m_freem(m); 2026aab5582fSPyun YongHyeon return (ENOBUFS); 2027aab5582fSPyun YongHyeon } 2028aab5582fSPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2029aab5582fSPyun YongHyeon 2030aab5582fSPyun YongHyeon data = &sc->rxq.data[idx]; 2031aab5582fSPyun YongHyeon if (data->m != NULL) { 2032aab5582fSPyun YongHyeon bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2033aab5582fSPyun YongHyeon BUS_DMASYNC_POSTREAD); 2034aab5582fSPyun YongHyeon bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 2035aab5582fSPyun YongHyeon } 2036aab5582fSPyun YongHyeon map = data->rx_data_map; 2037aab5582fSPyun YongHyeon data->rx_data_map = sc->rxq.rx_spare_map; 2038aab5582fSPyun YongHyeon sc->rxq.rx_spare_map = map; 2039aab5582fSPyun YongHyeon bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2040aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD); 2041aab5582fSPyun YongHyeon data->paddr = segs[0].ds_addr; 2042aab5582fSPyun YongHyeon data->m = m; 2043aab5582fSPyun YongHyeon /* update mapping address in h/w descriptor */ 2044aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 2045aab5582fSPyun YongHyeon desc64 = &sc->rxq.desc64[idx]; 2046aab5582fSPyun YongHyeon desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2047aab5582fSPyun YongHyeon desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2048aab5582fSPyun YongHyeon desc64->length = htole16(segs[0].ds_len); 2049aab5582fSPyun YongHyeon desc64->flags = htole16(NFE_RX_READY); 2050aab5582fSPyun YongHyeon } else { 2051aab5582fSPyun YongHyeon desc32 = &sc->rxq.desc32[idx]; 2052aab5582fSPyun YongHyeon desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2053aab5582fSPyun YongHyeon desc32->length = htole16(segs[0].ds_len); 2054aab5582fSPyun YongHyeon desc32->flags = htole16(NFE_RX_READY); 2055aab5582fSPyun YongHyeon } 2056aab5582fSPyun YongHyeon 2057aab5582fSPyun YongHyeon return (0); 2058257c5577SDavid E. O'Brien } 2059257c5577SDavid E. O'Brien 20602c3adf61SDavid E. O'Brien 2061aab5582fSPyun YongHyeon static int 2062aab5582fSPyun YongHyeon nfe_jnewbuf(struct nfe_softc *sc, int idx) 2063257c5577SDavid E. O'Brien { 2064aab5582fSPyun YongHyeon struct nfe_rx_data *data; 2065aab5582fSPyun YongHyeon struct nfe_desc32 *desc32; 2066aab5582fSPyun YongHyeon struct nfe_desc64 *desc64; 2067aab5582fSPyun YongHyeon struct mbuf *m; 2068aab5582fSPyun YongHyeon bus_dma_segment_t segs[1]; 2069aab5582fSPyun YongHyeon bus_dmamap_t map; 2070aab5582fSPyun YongHyeon int nsegs; 2071aab5582fSPyun YongHyeon void *buf; 20722c3adf61SDavid E. O'Brien 2073aab5582fSPyun YongHyeon MGETHDR(m, M_DONTWAIT, MT_DATA); 2074aab5582fSPyun YongHyeon if (m == NULL) 2075aab5582fSPyun YongHyeon return (ENOBUFS); 2076aab5582fSPyun YongHyeon buf = nfe_jalloc(sc); 2077aab5582fSPyun YongHyeon if (buf == NULL) { 2078aab5582fSPyun YongHyeon m_freem(m); 2079aab5582fSPyun YongHyeon return (ENOBUFS); 2080aab5582fSPyun YongHyeon } 2081aab5582fSPyun YongHyeon /* Attach the buffer to the mbuf. */ 2082aab5582fSPyun YongHyeon MEXTADD(m, buf, NFE_JLEN, nfe_jfree, (struct nfe_softc *)sc, 0, 2083aab5582fSPyun YongHyeon EXT_NET_DRV); 2084aab5582fSPyun YongHyeon if ((m->m_flags & M_EXT) == 0) { 2085aab5582fSPyun YongHyeon m_freem(m); 2086aab5582fSPyun YongHyeon return (ENOBUFS); 2087aab5582fSPyun YongHyeon } 2088aab5582fSPyun YongHyeon m->m_pkthdr.len = m->m_len = NFE_JLEN; 2089aab5582fSPyun YongHyeon m_adj(m, ETHER_ALIGN); 2090aab5582fSPyun YongHyeon 2091aab5582fSPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 2092aab5582fSPyun YongHyeon sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2093aab5582fSPyun YongHyeon m_freem(m); 2094aab5582fSPyun YongHyeon return (ENOBUFS); 2095aab5582fSPyun YongHyeon } 2096aab5582fSPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2097aab5582fSPyun YongHyeon 2098aab5582fSPyun YongHyeon data = &sc->jrxq.jdata[idx]; 2099aab5582fSPyun YongHyeon if (data->m != NULL) { 2100aab5582fSPyun YongHyeon bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2101aab5582fSPyun YongHyeon BUS_DMASYNC_POSTREAD); 2102aab5582fSPyun YongHyeon bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 2103aab5582fSPyun YongHyeon } 2104aab5582fSPyun YongHyeon map = data->rx_data_map; 2105aab5582fSPyun YongHyeon data->rx_data_map = sc->jrxq.jrx_spare_map; 2106aab5582fSPyun YongHyeon sc->jrxq.jrx_spare_map = map; 2107aab5582fSPyun YongHyeon bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2108aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD); 2109aab5582fSPyun YongHyeon data->paddr = segs[0].ds_addr; 2110aab5582fSPyun YongHyeon data->m = m; 2111aab5582fSPyun YongHyeon /* update mapping address in h/w descriptor */ 2112aab5582fSPyun YongHyeon if (sc->nfe_flags & NFE_40BIT_ADDR) { 2113aab5582fSPyun YongHyeon desc64 = &sc->jrxq.jdesc64[idx]; 2114aab5582fSPyun YongHyeon desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2115aab5582fSPyun YongHyeon desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2116aab5582fSPyun YongHyeon desc64->length = htole16(segs[0].ds_len); 2117aab5582fSPyun YongHyeon desc64->flags = htole16(NFE_RX_READY); 2118aab5582fSPyun YongHyeon } else { 2119aab5582fSPyun YongHyeon desc32 = &sc->jrxq.jdesc32[idx]; 2120aab5582fSPyun YongHyeon desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2121aab5582fSPyun YongHyeon desc32->length = htole16(segs[0].ds_len); 2122aab5582fSPyun YongHyeon desc32->flags = htole16(NFE_RX_READY); 2123aab5582fSPyun YongHyeon } 2124aab5582fSPyun YongHyeon 2125aab5582fSPyun YongHyeon return (0); 2126257c5577SDavid E. O'Brien } 2127257c5577SDavid E. O'Brien 21282c3adf61SDavid E. O'Brien 2129aab5582fSPyun YongHyeon static int 2130aab5582fSPyun YongHyeon nfe_rxeof(struct nfe_softc *sc, int count) 2131257c5577SDavid E. O'Brien { 2132bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 2133aab5582fSPyun YongHyeon struct nfe_desc32 *desc32; 2134aab5582fSPyun YongHyeon struct nfe_desc64 *desc64; 2135257c5577SDavid E. O'Brien struct nfe_rx_data *data; 2136aab5582fSPyun YongHyeon struct mbuf *m; 2137aab5582fSPyun YongHyeon uint16_t flags; 2138aab5582fSPyun YongHyeon int len, prog; 2139aab5582fSPyun YongHyeon uint32_t vtag = 0; 2140bfc788c2SDavid E. O'Brien 2141bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2142257c5577SDavid E. O'Brien 2143aab5582fSPyun YongHyeon bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2144aab5582fSPyun YongHyeon BUS_DMASYNC_POSTREAD); 2145bfc788c2SDavid E. O'Brien 2146aab5582fSPyun YongHyeon for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2147aab5582fSPyun YongHyeon if (count <= 0) 2148bfc788c2SDavid E. O'Brien break; 2149aab5582fSPyun YongHyeon count--; 2150bfc788c2SDavid E. O'Brien 2151257c5577SDavid E. O'Brien data = &sc->rxq.data[sc->rxq.cur]; 2152257c5577SDavid E. O'Brien 2153bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2154257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2155aab5582fSPyun YongHyeon vtag = le32toh(desc64->physaddr[1]); 2156aab5582fSPyun YongHyeon flags = le16toh(desc64->flags); 2157aab5582fSPyun YongHyeon len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2158257c5577SDavid E. O'Brien } else { 2159257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2160aab5582fSPyun YongHyeon flags = le16toh(desc32->flags); 2161aab5582fSPyun YongHyeon len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2162257c5577SDavid E. O'Brien } 2163257c5577SDavid E. O'Brien 2164257c5577SDavid E. O'Brien if (flags & NFE_RX_READY) 2165257c5577SDavid E. O'Brien break; 2166aab5582fSPyun YongHyeon prog++; 2167bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2168aab5582fSPyun YongHyeon if (!(flags & NFE_RX_VALID_V1)) { 2169aab5582fSPyun YongHyeon ifp->if_ierrors++; 2170aab5582fSPyun YongHyeon nfe_discard_rxbuf(sc, sc->rxq.cur); 2171aab5582fSPyun YongHyeon continue; 2172aab5582fSPyun YongHyeon } 2173257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2174257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 2175257c5577SDavid E. O'Brien len--; /* fix buffer length */ 2176257c5577SDavid E. O'Brien } 2177257c5577SDavid E. O'Brien } else { 2178aab5582fSPyun YongHyeon if (!(flags & NFE_RX_VALID_V2)) { 2179aab5582fSPyun YongHyeon ifp->if_ierrors++; 2180aab5582fSPyun YongHyeon nfe_discard_rxbuf(sc, sc->rxq.cur); 2181aab5582fSPyun YongHyeon continue; 2182aab5582fSPyun YongHyeon } 2183257c5577SDavid E. O'Brien 2184257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2185257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 2186257c5577SDavid E. O'Brien len--; /* fix buffer length */ 2187257c5577SDavid E. O'Brien } 2188257c5577SDavid E. O'Brien } 2189257c5577SDavid E. O'Brien 2190257c5577SDavid E. O'Brien if (flags & NFE_RX_ERROR) { 2191257c5577SDavid E. O'Brien ifp->if_ierrors++; 2192aab5582fSPyun YongHyeon nfe_discard_rxbuf(sc, sc->rxq.cur); 2193aab5582fSPyun YongHyeon continue; 2194257c5577SDavid E. O'Brien } 2195257c5577SDavid E. O'Brien 2196257c5577SDavid E. O'Brien m = data->m; 2197aab5582fSPyun YongHyeon if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2198aab5582fSPyun YongHyeon ifp->if_iqdrops++; 2199aab5582fSPyun YongHyeon nfe_discard_rxbuf(sc, sc->rxq.cur); 2200aab5582fSPyun YongHyeon continue; 2201aab5582fSPyun YongHyeon } 2202257c5577SDavid E. O'Brien 2203aab5582fSPyun YongHyeon if ((vtag & NFE_RX_VTAG) != 0 && 2204aab5582fSPyun YongHyeon (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2205aab5582fSPyun YongHyeon m->m_pkthdr.ether_vtag = vtag & 0xffff; 2206aab5582fSPyun YongHyeon m->m_flags |= M_VLANTAG; 2207aab5582fSPyun YongHyeon } 2208aab5582fSPyun YongHyeon 2209257c5577SDavid E. O'Brien m->m_pkthdr.len = m->m_len = len; 2210257c5577SDavid E. O'Brien m->m_pkthdr.rcvif = ifp; 2211257c5577SDavid E. O'Brien 2212aab5582fSPyun YongHyeon if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2213aab5582fSPyun YongHyeon if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2214bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2215bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2216aab5582fSPyun YongHyeon if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2217aab5582fSPyun YongHyeon (flags & NFE_RX_UDP_CSUMOK) != 0) { 2218bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= 2219bfc788c2SDavid E. O'Brien CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2220bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_data = 0xffff; 2221bfc788c2SDavid E. O'Brien } 2222bfc788c2SDavid E. O'Brien } 2223bfc788c2SDavid E. O'Brien } 2224aab5582fSPyun YongHyeon 2225257c5577SDavid E. O'Brien ifp->if_ipackets++; 2226bfc788c2SDavid E. O'Brien 2227bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2228bfc788c2SDavid E. O'Brien (*ifp->if_input)(ifp, m); 2229bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2230aab5582fSPyun YongHyeon } 2231257c5577SDavid E. O'Brien 2232aab5582fSPyun YongHyeon if (prog > 0) 2233aab5582fSPyun YongHyeon bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2234aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2235aab5582fSPyun YongHyeon 2236aab5582fSPyun YongHyeon return (count > 0 ? 0 : EAGAIN); 2237aab5582fSPyun YongHyeon } 2238aab5582fSPyun YongHyeon 2239aab5582fSPyun YongHyeon 2240aab5582fSPyun YongHyeon static int 2241aab5582fSPyun YongHyeon nfe_jrxeof(struct nfe_softc *sc, int count) 2242aab5582fSPyun YongHyeon { 2243aab5582fSPyun YongHyeon struct ifnet *ifp = sc->nfe_ifp; 2244aab5582fSPyun YongHyeon struct nfe_desc32 *desc32; 2245aab5582fSPyun YongHyeon struct nfe_desc64 *desc64; 2246aab5582fSPyun YongHyeon struct nfe_rx_data *data; 2247aab5582fSPyun YongHyeon struct mbuf *m; 2248aab5582fSPyun YongHyeon uint16_t flags; 2249aab5582fSPyun YongHyeon int len, prog; 2250aab5582fSPyun YongHyeon uint32_t vtag = 0; 2251aab5582fSPyun YongHyeon 2252aab5582fSPyun YongHyeon NFE_LOCK_ASSERT(sc); 2253aab5582fSPyun YongHyeon 2254aab5582fSPyun YongHyeon bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2255aab5582fSPyun YongHyeon BUS_DMASYNC_POSTREAD); 2256aab5582fSPyun YongHyeon 2257aab5582fSPyun YongHyeon for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2258aab5582fSPyun YongHyeon vtag = 0) { 2259aab5582fSPyun YongHyeon if (count <= 0) 2260aab5582fSPyun YongHyeon break; 2261aab5582fSPyun YongHyeon count--; 2262aab5582fSPyun YongHyeon 2263aab5582fSPyun YongHyeon data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2264aab5582fSPyun YongHyeon 2265bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2266aab5582fSPyun YongHyeon desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2267aab5582fSPyun YongHyeon vtag = le32toh(desc64->physaddr[1]); 2268aab5582fSPyun YongHyeon flags = le16toh(desc64->flags); 2269aab5582fSPyun YongHyeon len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2270257c5577SDavid E. O'Brien } else { 2271aab5582fSPyun YongHyeon desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2272aab5582fSPyun YongHyeon flags = le16toh(desc32->flags); 2273aab5582fSPyun YongHyeon len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2274257c5577SDavid E. O'Brien } 2275257c5577SDavid E. O'Brien 2276aab5582fSPyun YongHyeon if (flags & NFE_RX_READY) 2277aab5582fSPyun YongHyeon break; 2278aab5582fSPyun YongHyeon prog++; 2279aab5582fSPyun YongHyeon if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2280aab5582fSPyun YongHyeon if (!(flags & NFE_RX_VALID_V1)) { 2281aab5582fSPyun YongHyeon ifp->if_ierrors++; 2282aab5582fSPyun YongHyeon nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2283aab5582fSPyun YongHyeon continue; 2284aab5582fSPyun YongHyeon } 2285aab5582fSPyun YongHyeon if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2286aab5582fSPyun YongHyeon flags &= ~NFE_RX_ERROR; 2287aab5582fSPyun YongHyeon len--; /* fix buffer length */ 2288aab5582fSPyun YongHyeon } 2289257c5577SDavid E. O'Brien } else { 2290aab5582fSPyun YongHyeon if (!(flags & NFE_RX_VALID_V2)) { 2291aab5582fSPyun YongHyeon ifp->if_ierrors++; 2292aab5582fSPyun YongHyeon nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2293aab5582fSPyun YongHyeon continue; 2294257c5577SDavid E. O'Brien } 2295257c5577SDavid E. O'Brien 2296aab5582fSPyun YongHyeon if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2297aab5582fSPyun YongHyeon flags &= ~NFE_RX_ERROR; 2298aab5582fSPyun YongHyeon len--; /* fix buffer length */ 2299aab5582fSPyun YongHyeon } 2300aab5582fSPyun YongHyeon } 2301aab5582fSPyun YongHyeon 2302aab5582fSPyun YongHyeon if (flags & NFE_RX_ERROR) { 2303aab5582fSPyun YongHyeon ifp->if_ierrors++; 2304aab5582fSPyun YongHyeon nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2305aab5582fSPyun YongHyeon continue; 2306aab5582fSPyun YongHyeon } 2307aab5582fSPyun YongHyeon 2308aab5582fSPyun YongHyeon m = data->m; 2309aab5582fSPyun YongHyeon if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2310aab5582fSPyun YongHyeon ifp->if_iqdrops++; 2311aab5582fSPyun YongHyeon nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2312aab5582fSPyun YongHyeon continue; 2313aab5582fSPyun YongHyeon } 2314aab5582fSPyun YongHyeon 2315aab5582fSPyun YongHyeon if ((vtag & NFE_RX_VTAG) != 0 && 2316aab5582fSPyun YongHyeon (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2317aab5582fSPyun YongHyeon m->m_pkthdr.ether_vtag = vtag & 0xffff; 2318aab5582fSPyun YongHyeon m->m_flags |= M_VLANTAG; 2319aab5582fSPyun YongHyeon } 2320aab5582fSPyun YongHyeon 2321aab5582fSPyun YongHyeon m->m_pkthdr.len = m->m_len = len; 2322aab5582fSPyun YongHyeon m->m_pkthdr.rcvif = ifp; 2323aab5582fSPyun YongHyeon 2324aab5582fSPyun YongHyeon if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2325aab5582fSPyun YongHyeon if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2326aab5582fSPyun YongHyeon m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2327aab5582fSPyun YongHyeon m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2328aab5582fSPyun YongHyeon if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2329aab5582fSPyun YongHyeon (flags & NFE_RX_UDP_CSUMOK) != 0) { 2330aab5582fSPyun YongHyeon m->m_pkthdr.csum_flags |= 2331aab5582fSPyun YongHyeon CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2332aab5582fSPyun YongHyeon m->m_pkthdr.csum_data = 0xffff; 2333aab5582fSPyun YongHyeon } 2334aab5582fSPyun YongHyeon } 2335aab5582fSPyun YongHyeon } 2336aab5582fSPyun YongHyeon 2337aab5582fSPyun YongHyeon ifp->if_ipackets++; 2338aab5582fSPyun YongHyeon 2339aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 2340aab5582fSPyun YongHyeon (*ifp->if_input)(ifp, m); 2341aab5582fSPyun YongHyeon NFE_LOCK(sc); 2342aab5582fSPyun YongHyeon } 2343aab5582fSPyun YongHyeon 2344aab5582fSPyun YongHyeon if (prog > 0) 2345aab5582fSPyun YongHyeon bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2346aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2347aab5582fSPyun YongHyeon 2348aab5582fSPyun YongHyeon return (count > 0 ? 0 : EAGAIN); 2349257c5577SDavid E. O'Brien } 2350257c5577SDavid E. O'Brien 23512c3adf61SDavid E. O'Brien 23522c3adf61SDavid E. O'Brien static void 23532c3adf61SDavid E. O'Brien nfe_txeof(struct nfe_softc *sc) 2354257c5577SDavid E. O'Brien { 2355bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 2356257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 2357257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 2358257c5577SDavid E. O'Brien struct nfe_tx_data *data = NULL; 2359aab5582fSPyun YongHyeon uint16_t flags; 2360aab5582fSPyun YongHyeon int cons, prog; 2361bfc788c2SDavid E. O'Brien 2362bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2363257c5577SDavid E. O'Brien 2364aab5582fSPyun YongHyeon bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2365aab5582fSPyun YongHyeon BUS_DMASYNC_POSTREAD); 2366aab5582fSPyun YongHyeon 2367aab5582fSPyun YongHyeon prog = 0; 2368aab5582fSPyun YongHyeon for (cons = sc->txq.next; cons != sc->txq.cur; 2369aab5582fSPyun YongHyeon NFE_INC(cons, NFE_TX_RING_COUNT)) { 2370bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2371aab5582fSPyun YongHyeon desc64 = &sc->txq.desc64[cons]; 2372aab5582fSPyun YongHyeon flags = le16toh(desc64->flags); 2373257c5577SDavid E. O'Brien } else { 2374aab5582fSPyun YongHyeon desc32 = &sc->txq.desc32[cons]; 2375aab5582fSPyun YongHyeon flags = le16toh(desc32->flags); 2376257c5577SDavid E. O'Brien } 2377257c5577SDavid E. O'Brien 2378257c5577SDavid E. O'Brien if (flags & NFE_TX_VALID) 2379257c5577SDavid E. O'Brien break; 2380257c5577SDavid E. O'Brien 2381aab5582fSPyun YongHyeon prog++; 2382aab5582fSPyun YongHyeon sc->txq.queued--; 2383aab5582fSPyun YongHyeon data = &sc->txq.data[cons]; 2384257c5577SDavid E. O'Brien 2385bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2386aab5582fSPyun YongHyeon if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2387aab5582fSPyun YongHyeon continue; 2388257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V1) != 0) { 2389aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 2390aab5582fSPyun YongHyeon "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2391bfc788c2SDavid E. O'Brien 2392257c5577SDavid E. O'Brien ifp->if_oerrors++; 2393257c5577SDavid E. O'Brien } else 2394257c5577SDavid E. O'Brien ifp->if_opackets++; 2395257c5577SDavid E. O'Brien } else { 2396aab5582fSPyun YongHyeon if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2397aab5582fSPyun YongHyeon continue; 2398257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V2) != 0) { 2399aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 2400aab5582fSPyun YongHyeon "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2401257c5577SDavid E. O'Brien ifp->if_oerrors++; 2402257c5577SDavid E. O'Brien } else 2403257c5577SDavid E. O'Brien ifp->if_opackets++; 2404257c5577SDavid E. O'Brien } 2405257c5577SDavid E. O'Brien 2406257c5577SDavid E. O'Brien /* last fragment of the mbuf chain transmitted */ 2407aab5582fSPyun YongHyeon KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2408aab5582fSPyun YongHyeon bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2409bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 2410aab5582fSPyun YongHyeon bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2411257c5577SDavid E. O'Brien m_freem(data->m); 2412257c5577SDavid E. O'Brien data->m = NULL; 2413257c5577SDavid E. O'Brien } 2414257c5577SDavid E. O'Brien 2415aab5582fSPyun YongHyeon if (prog > 0) { 2416aab5582fSPyun YongHyeon sc->nfe_force_tx = 0; 2417aab5582fSPyun YongHyeon sc->txq.next = cons; 2418bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2419aab5582fSPyun YongHyeon if (sc->txq.queued == 0) 2420aab5582fSPyun YongHyeon sc->nfe_watchdog_timer = 0; 2421257c5577SDavid E. O'Brien } 2422257c5577SDavid E. O'Brien } 2423257c5577SDavid E. O'Brien 2424aab5582fSPyun YongHyeon /* 2425aab5582fSPyun YongHyeon * It's copy of ath_defrag(ath(4)). 2426aab5582fSPyun YongHyeon * 2427aab5582fSPyun YongHyeon * Defragment an mbuf chain, returning at most maxfrags separate 2428aab5582fSPyun YongHyeon * mbufs+clusters. If this is not possible NULL is returned and 2429aab5582fSPyun YongHyeon * the original mbuf chain is left in it's present (potentially 2430aab5582fSPyun YongHyeon * modified) state. We use two techniques: collapsing consecutive 2431aab5582fSPyun YongHyeon * mbufs and replacing consecutive mbufs by a cluster. 2432aab5582fSPyun YongHyeon */ 2433aab5582fSPyun YongHyeon static struct mbuf * 2434aab5582fSPyun YongHyeon nfe_defrag(struct mbuf *m0, int how, int maxfrags) 2435aab5582fSPyun YongHyeon { 2436aab5582fSPyun YongHyeon struct mbuf *m, *n, *n2, **prev; 2437aab5582fSPyun YongHyeon u_int curfrags; 2438aab5582fSPyun YongHyeon 2439aab5582fSPyun YongHyeon /* 2440aab5582fSPyun YongHyeon * Calculate the current number of frags. 2441aab5582fSPyun YongHyeon */ 2442aab5582fSPyun YongHyeon curfrags = 0; 2443aab5582fSPyun YongHyeon for (m = m0; m != NULL; m = m->m_next) 2444aab5582fSPyun YongHyeon curfrags++; 2445aab5582fSPyun YongHyeon /* 2446aab5582fSPyun YongHyeon * First, try to collapse mbufs. Note that we always collapse 2447aab5582fSPyun YongHyeon * towards the front so we don't need to deal with moving the 2448aab5582fSPyun YongHyeon * pkthdr. This may be suboptimal if the first mbuf has much 2449aab5582fSPyun YongHyeon * less data than the following. 2450aab5582fSPyun YongHyeon */ 2451aab5582fSPyun YongHyeon m = m0; 2452aab5582fSPyun YongHyeon again: 2453aab5582fSPyun YongHyeon for (;;) { 2454aab5582fSPyun YongHyeon n = m->m_next; 2455aab5582fSPyun YongHyeon if (n == NULL) 2456aab5582fSPyun YongHyeon break; 2457aab5582fSPyun YongHyeon if ((m->m_flags & M_RDONLY) == 0 && 2458aab5582fSPyun YongHyeon n->m_len < M_TRAILINGSPACE(m)) { 2459aab5582fSPyun YongHyeon bcopy(mtod(n, void *), mtod(m, char *) + m->m_len, 2460aab5582fSPyun YongHyeon n->m_len); 2461aab5582fSPyun YongHyeon m->m_len += n->m_len; 2462aab5582fSPyun YongHyeon m->m_next = n->m_next; 2463aab5582fSPyun YongHyeon m_free(n); 2464aab5582fSPyun YongHyeon if (--curfrags <= maxfrags) 2465aab5582fSPyun YongHyeon return (m0); 2466aab5582fSPyun YongHyeon } else 2467aab5582fSPyun YongHyeon m = n; 2468aab5582fSPyun YongHyeon } 2469aab5582fSPyun YongHyeon KASSERT(maxfrags > 1, 2470aab5582fSPyun YongHyeon ("maxfrags %u, but normal collapse failed", maxfrags)); 2471aab5582fSPyun YongHyeon /* 2472aab5582fSPyun YongHyeon * Collapse consecutive mbufs to a cluster. 2473aab5582fSPyun YongHyeon */ 2474aab5582fSPyun YongHyeon prev = &m0->m_next; /* NB: not the first mbuf */ 2475aab5582fSPyun YongHyeon while ((n = *prev) != NULL) { 2476aab5582fSPyun YongHyeon if ((n2 = n->m_next) != NULL && 2477aab5582fSPyun YongHyeon n->m_len + n2->m_len < MCLBYTES) { 2478aab5582fSPyun YongHyeon m = m_getcl(how, MT_DATA, 0); 2479aab5582fSPyun YongHyeon if (m == NULL) 2480aab5582fSPyun YongHyeon goto bad; 2481aab5582fSPyun YongHyeon bcopy(mtod(n, void *), mtod(m, void *), n->m_len); 2482aab5582fSPyun YongHyeon bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len, 2483aab5582fSPyun YongHyeon n2->m_len); 2484aab5582fSPyun YongHyeon m->m_len = n->m_len + n2->m_len; 2485aab5582fSPyun YongHyeon m->m_next = n2->m_next; 2486aab5582fSPyun YongHyeon *prev = m; 2487aab5582fSPyun YongHyeon m_free(n); 2488aab5582fSPyun YongHyeon m_free(n2); 2489aab5582fSPyun YongHyeon if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */ 2490aab5582fSPyun YongHyeon return m0; 2491aab5582fSPyun YongHyeon /* 2492aab5582fSPyun YongHyeon * Still not there, try the normal collapse 2493aab5582fSPyun YongHyeon * again before we allocate another cluster. 2494aab5582fSPyun YongHyeon */ 2495aab5582fSPyun YongHyeon goto again; 2496aab5582fSPyun YongHyeon } 2497aab5582fSPyun YongHyeon prev = &n->m_next; 2498aab5582fSPyun YongHyeon } 2499aab5582fSPyun YongHyeon /* 2500aab5582fSPyun YongHyeon * No place where we can collapse to a cluster; punt. 2501aab5582fSPyun YongHyeon * This can occur if, for example, you request 2 frags 2502aab5582fSPyun YongHyeon * but the packet requires that both be clusters (we 2503aab5582fSPyun YongHyeon * never reallocate the first mbuf to avoid moving the 2504aab5582fSPyun YongHyeon * packet header). 2505aab5582fSPyun YongHyeon */ 2506aab5582fSPyun YongHyeon bad: 2507aab5582fSPyun YongHyeon return (NULL); 2508aab5582fSPyun YongHyeon } 2509aab5582fSPyun YongHyeon 25102c3adf61SDavid E. O'Brien 25112c3adf61SDavid E. O'Brien static int 2512aab5582fSPyun YongHyeon nfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2513257c5577SDavid E. O'Brien { 2514bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32 = NULL; 2515bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64 = NULL; 2516257c5577SDavid E. O'Brien bus_dmamap_t map; 2517bfc788c2SDavid E. O'Brien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2518aab5582fSPyun YongHyeon int error, i, nsegs, prod, si; 2519aab5582fSPyun YongHyeon uint32_t tso_segsz; 2520aab5582fSPyun YongHyeon uint16_t cflags, flags; 2521aab5582fSPyun YongHyeon struct mbuf *m; 2522257c5577SDavid E. O'Brien 2523aab5582fSPyun YongHyeon prod = si = sc->txq.cur; 2524aab5582fSPyun YongHyeon map = sc->txq.data[prod].tx_data_map; 2525257c5577SDavid E. O'Brien 2526aab5582fSPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2527bfc788c2SDavid E. O'Brien &nsegs, BUS_DMA_NOWAIT); 2528aab5582fSPyun YongHyeon if (error == EFBIG) { 2529aab5582fSPyun YongHyeon m = nfe_defrag(*m_head, M_DONTWAIT, NFE_MAX_SCATTER); 2530aab5582fSPyun YongHyeon if (m == NULL) { 2531aab5582fSPyun YongHyeon m_freem(*m_head); 2532aab5582fSPyun YongHyeon *m_head = NULL; 2533aab5582fSPyun YongHyeon return (ENOBUFS); 2534aab5582fSPyun YongHyeon } 2535aab5582fSPyun YongHyeon *m_head = m; 2536aab5582fSPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2537aab5582fSPyun YongHyeon *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2538257c5577SDavid E. O'Brien if (error != 0) { 2539aab5582fSPyun YongHyeon m_freem(*m_head); 2540aab5582fSPyun YongHyeon *m_head = NULL; 2541aab5582fSPyun YongHyeon return (ENOBUFS); 2542aab5582fSPyun YongHyeon } 2543aab5582fSPyun YongHyeon } else if (error != 0) 2544aab5582fSPyun YongHyeon return (error); 2545aab5582fSPyun YongHyeon if (nsegs == 0) { 2546aab5582fSPyun YongHyeon m_freem(*m_head); 2547aab5582fSPyun YongHyeon *m_head = NULL; 2548aab5582fSPyun YongHyeon return (EIO); 2549257c5577SDavid E. O'Brien } 2550257c5577SDavid E. O'Brien 2551aab5582fSPyun YongHyeon if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2552bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2553aab5582fSPyun YongHyeon return (ENOBUFS); 2554257c5577SDavid E. O'Brien } 2555257c5577SDavid E. O'Brien 2556aab5582fSPyun YongHyeon m = *m_head; 2557aab5582fSPyun YongHyeon cflags = flags = 0; 2558aab5582fSPyun YongHyeon tso_segsz = 0; 2559aab5582fSPyun YongHyeon if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2560aab5582fSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2561aab5582fSPyun YongHyeon cflags |= NFE_TX_IP_CSUM; 2562aab5582fSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2563aab5582fSPyun YongHyeon cflags |= NFE_TX_TCP_UDP_CSUM; 2564aab5582fSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2565aab5582fSPyun YongHyeon cflags |= NFE_TX_TCP_UDP_CSUM; 2566aab5582fSPyun YongHyeon } 2567aab5582fSPyun YongHyeon if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2568aab5582fSPyun YongHyeon tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz << 2569aab5582fSPyun YongHyeon NFE_TX_TSO_SHIFT; 2570aab5582fSPyun YongHyeon cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2571aab5582fSPyun YongHyeon cflags |= NFE_TX_TSO; 25727597761aSDavid E. O'Brien } 2573257c5577SDavid E. O'Brien 2574bfc788c2SDavid E. O'Brien for (i = 0; i < nsegs; i++) { 2575bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2576aab5582fSPyun YongHyeon desc64 = &sc->txq.desc64[prod]; 2577aab5582fSPyun YongHyeon desc64->physaddr[0] = 2578aab5582fSPyun YongHyeon htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2579aab5582fSPyun YongHyeon desc64->physaddr[1] = 2580aab5582fSPyun YongHyeon htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2581aab5582fSPyun YongHyeon desc64->vtag = 0; 2582bfc788c2SDavid E. O'Brien desc64->length = htole16(segs[i].ds_len - 1); 2583257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 2584257c5577SDavid E. O'Brien } else { 2585aab5582fSPyun YongHyeon desc32 = &sc->txq.desc32[prod]; 2586aab5582fSPyun YongHyeon desc32->physaddr = 2587aab5582fSPyun YongHyeon htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2588bfc788c2SDavid E. O'Brien desc32->length = htole16(segs[i].ds_len - 1); 2589257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 2590257c5577SDavid E. O'Brien } 2591257c5577SDavid E. O'Brien 2592aab5582fSPyun YongHyeon /* 2593aab5582fSPyun YongHyeon * Setting of the valid bit in the first descriptor is 2594aab5582fSPyun YongHyeon * deferred until the whole chain is fully setup. 2595aab5582fSPyun YongHyeon */ 2596aab5582fSPyun YongHyeon flags |= NFE_TX_VALID; 2597257c5577SDavid E. O'Brien 2598257c5577SDavid E. O'Brien sc->txq.queued++; 2599aab5582fSPyun YongHyeon NFE_INC(prod, NFE_TX_RING_COUNT); 2600257c5577SDavid E. O'Brien } 2601257c5577SDavid E. O'Brien 2602aab5582fSPyun YongHyeon /* 2603aab5582fSPyun YongHyeon * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2604aab5582fSPyun YongHyeon * csum flags, vtag and TSO belong to the first fragment only. 2605aab5582fSPyun YongHyeon */ 2606bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2607aab5582fSPyun YongHyeon desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2608aab5582fSPyun YongHyeon desc64 = &sc->txq.desc64[si]; 2609aab5582fSPyun YongHyeon if ((m->m_flags & M_VLANTAG) != 0) 2610aab5582fSPyun YongHyeon desc64->vtag = htole32(NFE_TX_VTAG | 2611aab5582fSPyun YongHyeon m->m_pkthdr.ether_vtag); 2612aab5582fSPyun YongHyeon if (tso_segsz != 0) { 2613aab5582fSPyun YongHyeon /* 2614aab5582fSPyun YongHyeon * XXX 2615aab5582fSPyun YongHyeon * The following indicates the descriptor element 2616aab5582fSPyun YongHyeon * is a 32bit quantity. 2617aab5582fSPyun YongHyeon */ 2618aab5582fSPyun YongHyeon desc64->length |= htole16((uint16_t)tso_segsz); 2619aab5582fSPyun YongHyeon desc64->flags |= htole16(tso_segsz >> 16); 2620aab5582fSPyun YongHyeon } 2621aab5582fSPyun YongHyeon /* 2622aab5582fSPyun YongHyeon * finally, set the valid/checksum/TSO bit in the first 2623aab5582fSPyun YongHyeon * descriptor. 2624aab5582fSPyun YongHyeon */ 2625aab5582fSPyun YongHyeon desc64->flags |= htole16(NFE_TX_VALID | cflags); 2626257c5577SDavid E. O'Brien } else { 2627bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 2628aab5582fSPyun YongHyeon desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2629257c5577SDavid E. O'Brien else 2630aab5582fSPyun YongHyeon desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2631aab5582fSPyun YongHyeon desc32 = &sc->txq.desc32[si]; 2632aab5582fSPyun YongHyeon if (tso_segsz != 0) { 2633aab5582fSPyun YongHyeon /* 2634aab5582fSPyun YongHyeon * XXX 2635aab5582fSPyun YongHyeon * The following indicates the descriptor element 2636aab5582fSPyun YongHyeon * is a 32bit quantity. 2637aab5582fSPyun YongHyeon */ 2638aab5582fSPyun YongHyeon desc32->length |= htole16((uint16_t)tso_segsz); 2639aab5582fSPyun YongHyeon desc32->flags |= htole16(tso_segsz >> 16); 2640aab5582fSPyun YongHyeon } 2641aab5582fSPyun YongHyeon /* 2642aab5582fSPyun YongHyeon * finally, set the valid/checksum/TSO bit in the first 2643aab5582fSPyun YongHyeon * descriptor. 2644aab5582fSPyun YongHyeon */ 2645aab5582fSPyun YongHyeon desc32->flags |= htole16(NFE_TX_VALID | cflags); 2646257c5577SDavid E. O'Brien } 2647257c5577SDavid E. O'Brien 2648aab5582fSPyun YongHyeon sc->txq.cur = prod; 2649aab5582fSPyun YongHyeon prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2650aab5582fSPyun YongHyeon sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2651aab5582fSPyun YongHyeon sc->txq.data[prod].tx_data_map = map; 2652aab5582fSPyun YongHyeon sc->txq.data[prod].m = m; 2653257c5577SDavid E. O'Brien 2654bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2655257c5577SDavid E. O'Brien 2656aab5582fSPyun YongHyeon return (0); 2657257c5577SDavid E. O'Brien } 2658257c5577SDavid E. O'Brien 2659bfc788c2SDavid E. O'Brien 26602c3adf61SDavid E. O'Brien static void 26612c3adf61SDavid E. O'Brien nfe_setmulti(struct nfe_softc *sc) 2662bfc788c2SDavid E. O'Brien { 2663bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 2664bfc788c2SDavid E. O'Brien struct ifmultiaddr *ifma; 2665bfc788c2SDavid E. O'Brien int i; 2666aab5582fSPyun YongHyeon uint32_t filter; 2667aab5582fSPyun YongHyeon uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2668aab5582fSPyun YongHyeon uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 26692c3adf61SDavid E. O'Brien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 26702c3adf61SDavid E. O'Brien }; 2671bfc788c2SDavid E. O'Brien 2672bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2673bfc788c2SDavid E. O'Brien 2674bfc788c2SDavid E. O'Brien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2675bfc788c2SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 2676bfc788c2SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 2677bfc788c2SDavid E. O'Brien goto done; 2678bfc788c2SDavid E. O'Brien } 2679bfc788c2SDavid E. O'Brien 2680bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2681bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2682bfc788c2SDavid E. O'Brien 2683bfc788c2SDavid E. O'Brien IF_ADDR_LOCK(ifp); 2684bfc788c2SDavid E. O'Brien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2685bfc788c2SDavid E. O'Brien u_char *addrp; 2686bfc788c2SDavid E. O'Brien 2687bfc788c2SDavid E. O'Brien if (ifma->ifma_addr->sa_family != AF_LINK) 2688bfc788c2SDavid E. O'Brien continue; 2689bfc788c2SDavid E. O'Brien 2690bfc788c2SDavid E. O'Brien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 2691bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2692bfc788c2SDavid E. O'Brien u_int8_t mcaddr = addrp[i]; 2693bfc788c2SDavid E. O'Brien addr[i] &= mcaddr; 2694bfc788c2SDavid E. O'Brien mask[i] &= ~mcaddr; 2695bfc788c2SDavid E. O'Brien } 2696bfc788c2SDavid E. O'Brien } 2697bfc788c2SDavid E. O'Brien IF_ADDR_UNLOCK(ifp); 2698bfc788c2SDavid E. O'Brien 2699bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2700bfc788c2SDavid E. O'Brien mask[i] |= addr[i]; 2701bfc788c2SDavid E. O'Brien } 2702bfc788c2SDavid E. O'Brien 2703bfc788c2SDavid E. O'Brien done: 2704bfc788c2SDavid E. O'Brien addr[0] |= 0x01; /* make sure multicast bit is set */ 2705bfc788c2SDavid E. O'Brien 2706bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2707bfc788c2SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2708bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2709bfc788c2SDavid E. O'Brien addr[5] << 8 | addr[4]); 2710bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2711bfc788c2SDavid E. O'Brien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2712bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2713bfc788c2SDavid E. O'Brien mask[5] << 8 | mask[4]); 2714bfc788c2SDavid E. O'Brien 2715aab5582fSPyun YongHyeon filter = NFE_READ(sc, NFE_RXFILTER); 2716aab5582fSPyun YongHyeon filter &= NFE_PFF_RX_PAUSE; 2717aab5582fSPyun YongHyeon filter |= NFE_RXFILTER_MAGIC; 2718aab5582fSPyun YongHyeon filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2719bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_RXFILTER, filter); 2720bfc788c2SDavid E. O'Brien } 2721bfc788c2SDavid E. O'Brien 27222c3adf61SDavid E. O'Brien 27232c3adf61SDavid E. O'Brien static void 2724aab5582fSPyun YongHyeon nfe_tx_task(void *arg, int pending) 2725aab5582fSPyun YongHyeon { 2726aab5582fSPyun YongHyeon struct ifnet *ifp; 2727aab5582fSPyun YongHyeon 2728aab5582fSPyun YongHyeon ifp = (struct ifnet *)arg; 2729aab5582fSPyun YongHyeon nfe_start(ifp); 2730aab5582fSPyun YongHyeon } 2731aab5582fSPyun YongHyeon 2732aab5582fSPyun YongHyeon 2733aab5582fSPyun YongHyeon static void 27342c3adf61SDavid E. O'Brien nfe_start(struct ifnet *ifp) 2735bfc788c2SDavid E. O'Brien { 2736257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2737257c5577SDavid E. O'Brien struct mbuf *m0; 2738aab5582fSPyun YongHyeon int enq; 2739257c5577SDavid E. O'Brien 2740aab5582fSPyun YongHyeon NFE_LOCK(sc); 2741aab5582fSPyun YongHyeon 2742aab5582fSPyun YongHyeon if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2743aab5582fSPyun YongHyeon IFF_DRV_RUNNING || sc->nfe_link == 0) { 2744aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 2745bfc788c2SDavid E. O'Brien return; 2746bfc788c2SDavid E. O'Brien } 2747bfc788c2SDavid E. O'Brien 2748aab5582fSPyun YongHyeon for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 2749aab5582fSPyun YongHyeon IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2750257c5577SDavid E. O'Brien if (m0 == NULL) 2751257c5577SDavid E. O'Brien break; 2752257c5577SDavid E. O'Brien 2753aab5582fSPyun YongHyeon if (nfe_encap(sc, &m0) != 0) { 2754aab5582fSPyun YongHyeon if (m0 == NULL) 2755aab5582fSPyun YongHyeon break; 2756aab5582fSPyun YongHyeon IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2757bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2758257c5577SDavid E. O'Brien break; 2759257c5577SDavid E. O'Brien } 2760aab5582fSPyun YongHyeon enq++; 276159a0d28bSChristian S.J. Peron ETHER_BPF_MTAP(ifp, m0); 2762257c5577SDavid E. O'Brien } 2763257c5577SDavid E. O'Brien 2764aab5582fSPyun YongHyeon if (enq > 0) { 2765aab5582fSPyun YongHyeon bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2766aab5582fSPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2767257c5577SDavid E. O'Brien 2768257c5577SDavid E. O'Brien /* kick Tx */ 2769257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2770257c5577SDavid E. O'Brien 2771257c5577SDavid E. O'Brien /* 2772257c5577SDavid E. O'Brien * Set a timeout in case the chip goes out to lunch. 2773257c5577SDavid E. O'Brien */ 2774aab5582fSPyun YongHyeon sc->nfe_watchdog_timer = 5; 2775aab5582fSPyun YongHyeon } 2776bfc788c2SDavid E. O'Brien 2777aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 2778257c5577SDavid E. O'Brien } 2779257c5577SDavid E. O'Brien 27802c3adf61SDavid E. O'Brien 27812c3adf61SDavid E. O'Brien static void 27822c3adf61SDavid E. O'Brien nfe_watchdog(struct ifnet *ifp) 2783257c5577SDavid E. O'Brien { 2784257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2785257c5577SDavid E. O'Brien 2786aab5582fSPyun YongHyeon if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2787aab5582fSPyun YongHyeon return; 2788aab5582fSPyun YongHyeon 2789aab5582fSPyun YongHyeon /* Check if we've lost Tx completion interrupt. */ 2790aab5582fSPyun YongHyeon nfe_txeof(sc); 2791aab5582fSPyun YongHyeon if (sc->txq.queued == 0) { 2792aab5582fSPyun YongHyeon if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2793aab5582fSPyun YongHyeon "-- recovering\n"); 2794aab5582fSPyun YongHyeon if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2795aab5582fSPyun YongHyeon taskqueue_enqueue_fast(taskqueue_fast, 2796aab5582fSPyun YongHyeon &sc->nfe_tx_task); 2797aab5582fSPyun YongHyeon return; 2798aab5582fSPyun YongHyeon } 2799aab5582fSPyun YongHyeon /* Check if we've lost start Tx command. */ 2800aab5582fSPyun YongHyeon sc->nfe_force_tx++; 2801aab5582fSPyun YongHyeon if (sc->nfe_force_tx <= 3) { 2802aab5582fSPyun YongHyeon /* 2803aab5582fSPyun YongHyeon * If this is the case for watchdog timeout, the following 2804aab5582fSPyun YongHyeon * code should go to nfe_txeof(). 2805aab5582fSPyun YongHyeon */ 2806aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2807aab5582fSPyun YongHyeon return; 2808aab5582fSPyun YongHyeon } 2809aab5582fSPyun YongHyeon sc->nfe_force_tx = 0; 2810aab5582fSPyun YongHyeon 2811aab5582fSPyun YongHyeon if_printf(ifp, "watchdog timeout\n"); 2812257c5577SDavid E. O'Brien 2813bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2814257c5577SDavid E. O'Brien ifp->if_oerrors++; 2815aab5582fSPyun YongHyeon nfe_init_locked(sc); 2816257c5577SDavid E. O'Brien } 2817257c5577SDavid E. O'Brien 28182c3adf61SDavid E. O'Brien 28192c3adf61SDavid E. O'Brien static void 28202c3adf61SDavid E. O'Brien nfe_init(void *xsc) 2821257c5577SDavid E. O'Brien { 2822bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 2823bfc788c2SDavid E. O'Brien 2824bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2825bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 2826bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2827bfc788c2SDavid E. O'Brien } 2828bfc788c2SDavid E. O'Brien 28292c3adf61SDavid E. O'Brien 28302c3adf61SDavid E. O'Brien static void 28312c3adf61SDavid E. O'Brien nfe_init_locked(void *xsc) 2832bfc788c2SDavid E. O'Brien { 2833bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 2834bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 2835bfc788c2SDavid E. O'Brien struct mii_data *mii; 2836aab5582fSPyun YongHyeon uint32_t val; 2837aab5582fSPyun YongHyeon int error; 2838bfc788c2SDavid E. O'Brien 2839bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2840bfc788c2SDavid E. O'Brien 2841bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2842bfc788c2SDavid E. O'Brien 2843aab5582fSPyun YongHyeon if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2844aab5582fSPyun YongHyeon return; 2845aab5582fSPyun YongHyeon 2846aab5582fSPyun YongHyeon nfe_stop(ifp); 2847aab5582fSPyun YongHyeon 2848aab5582fSPyun YongHyeon sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 2849aab5582fSPyun YongHyeon 2850aab5582fSPyun YongHyeon nfe_init_tx_ring(sc, &sc->txq); 2851aab5582fSPyun YongHyeon if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2852aab5582fSPyun YongHyeon error = nfe_init_jrx_ring(sc, &sc->jrxq); 2853aab5582fSPyun YongHyeon else 2854aab5582fSPyun YongHyeon error = nfe_init_rx_ring(sc, &sc->rxq); 2855aab5582fSPyun YongHyeon if (error != 0) { 2856aab5582fSPyun YongHyeon device_printf(sc->nfe_dev, 2857aab5582fSPyun YongHyeon "initialization failed: no memory for rx buffers\n"); 2858aab5582fSPyun YongHyeon nfe_stop(ifp); 2859bfc788c2SDavid E. O'Brien return; 2860bfc788c2SDavid E. O'Brien } 2861257c5577SDavid E. O'Brien 2862aab5582fSPyun YongHyeon val = 0; 2863aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2864aab5582fSPyun YongHyeon val |= NFE_MAC_ADDR_INORDER; 2865aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_UNK, val); 2866257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, 0); 2867257c5577SDavid E. O'Brien 2868aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2869aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2870aab5582fSPyun YongHyeon 2871257c5577SDavid E. O'Brien sc->rxtxctl = NFE_RXTX_BIT2; 2872bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 2873257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2874bfc788c2SDavid E. O'Brien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2875257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 28767597761aSDavid E. O'Brien 2877aab5582fSPyun YongHyeon if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 2878257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2879aab5582fSPyun YongHyeon if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2880aab5582fSPyun YongHyeon sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2881bfc788c2SDavid E. O'Brien 2882257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2883257c5577SDavid E. O'Brien DELAY(10); 2884257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2885257c5577SDavid E. O'Brien 2886aab5582fSPyun YongHyeon if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2887257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2888aab5582fSPyun YongHyeon else 2889aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2890257c5577SDavid E. O'Brien 2891257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2892257c5577SDavid E. O'Brien 2893257c5577SDavid E. O'Brien /* set MAC address */ 2894aab5582fSPyun YongHyeon nfe_set_macaddr(sc, IF_LLADDR(ifp)); 2895257c5577SDavid E. O'Brien 2896257c5577SDavid E. O'Brien /* tell MAC where rings are in memory */ 2897aab5582fSPyun YongHyeon if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2898aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2899aab5582fSPyun YongHyeon NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2900aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2901aab5582fSPyun YongHyeon NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2902aab5582fSPyun YongHyeon } else { 2903aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2904aab5582fSPyun YongHyeon NFE_ADDR_HI(sc->rxq.physaddr)); 2905aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2906aab5582fSPyun YongHyeon NFE_ADDR_LO(sc->rxq.physaddr)); 2907aab5582fSPyun YongHyeon } 2908aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2909aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2910257c5577SDavid E. O'Brien 2911257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RING_SIZE, 2912257c5577SDavid E. O'Brien (NFE_RX_RING_COUNT - 1) << 16 | 2913257c5577SDavid E. O'Brien (NFE_TX_RING_COUNT - 1)); 2914257c5577SDavid E. O'Brien 2915aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2916257c5577SDavid E. O'Brien 2917257c5577SDavid E. O'Brien /* force MAC to wakeup */ 2918aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_PWR_STATE); 2919aab5582fSPyun YongHyeon if ((val & NFE_PWR_WAKEUP) == 0) 2920aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2921257c5577SDavid E. O'Brien DELAY(10); 2922aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_PWR_STATE); 2923aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2924257c5577SDavid E. O'Brien 2925257c5577SDavid E. O'Brien #if 1 2926257c5577SDavid E. O'Brien /* configure interrupts coalescing/mitigation */ 2927257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2928257c5577SDavid E. O'Brien #else 2929257c5577SDavid E. O'Brien /* no interrupt mitigation: one interrupt per packet */ 2930257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, 970); 2931257c5577SDavid E. O'Brien #endif 2932257c5577SDavid E. O'Brien 2933aab5582fSPyun YongHyeon NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2934257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2935257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2936257c5577SDavid E. O'Brien 2937257c5577SDavid E. O'Brien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2938257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2939257c5577SDavid E. O'Brien 2940257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2941257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 2942257c5577SDavid E. O'Brien 2943257c5577SDavid E. O'Brien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2944257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2945257c5577SDavid E. O'Brien DELAY(10); 2946257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2947257c5577SDavid E. O'Brien 2948257c5577SDavid E. O'Brien /* set Rx filter */ 2949257c5577SDavid E. O'Brien nfe_setmulti(sc); 2950257c5577SDavid E. O'Brien 2951257c5577SDavid E. O'Brien /* enable Rx */ 2952257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2953257c5577SDavid E. O'Brien 2954257c5577SDavid E. O'Brien /* enable Tx */ 2955257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2956257c5577SDavid E. O'Brien 2957257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2958257c5577SDavid E. O'Brien 2959bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 2960bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 2961aab5582fSPyun YongHyeon nfe_disable_intr(sc); 2962bfc788c2SDavid E. O'Brien else 2963bfc788c2SDavid E. O'Brien #endif 2964aab5582fSPyun YongHyeon nfe_set_intr(sc); 2965aab5582fSPyun YongHyeon nfe_enable_intr(sc); /* enable interrupts */ 2966257c5577SDavid E. O'Brien 2967bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2968bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2969257c5577SDavid E. O'Brien 2970bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 2971aab5582fSPyun YongHyeon mii_mediachg(mii); 2972257c5577SDavid E. O'Brien 2973aab5582fSPyun YongHyeon callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2974257c5577SDavid E. O'Brien } 2975257c5577SDavid E. O'Brien 29762c3adf61SDavid E. O'Brien 29772c3adf61SDavid E. O'Brien static void 2978aab5582fSPyun YongHyeon nfe_stop(struct ifnet *ifp) 2979257c5577SDavid E. O'Brien { 2980257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2981aab5582fSPyun YongHyeon struct nfe_rx_ring *rx_ring; 2982aab5582fSPyun YongHyeon struct nfe_jrx_ring *jrx_ring; 2983aab5582fSPyun YongHyeon struct nfe_tx_ring *tx_ring; 2984aab5582fSPyun YongHyeon struct nfe_rx_data *rdata; 2985aab5582fSPyun YongHyeon struct nfe_tx_data *tdata; 2986aab5582fSPyun YongHyeon int i; 2987257c5577SDavid E. O'Brien 2988bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2989257c5577SDavid E. O'Brien 2990aab5582fSPyun YongHyeon sc->nfe_watchdog_timer = 0; 2991bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2992257c5577SDavid E. O'Brien 2993bfc788c2SDavid E. O'Brien callout_stop(&sc->nfe_stat_ch); 2994257c5577SDavid E. O'Brien 2995257c5577SDavid E. O'Brien /* abort Tx */ 2996257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, 0); 2997257c5577SDavid E. O'Brien 2998257c5577SDavid E. O'Brien /* disable Rx */ 2999257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, 0); 3000257c5577SDavid E. O'Brien 3001257c5577SDavid E. O'Brien /* disable interrupts */ 3002aab5582fSPyun YongHyeon nfe_disable_intr(sc); 3003257c5577SDavid E. O'Brien 3004bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 3005bfc788c2SDavid E. O'Brien 3006aab5582fSPyun YongHyeon /* free Rx and Tx mbufs still in the queues. */ 3007aab5582fSPyun YongHyeon rx_ring = &sc->rxq; 3008aab5582fSPyun YongHyeon for (i = 0; i < NFE_RX_RING_COUNT; i++) { 3009aab5582fSPyun YongHyeon rdata = &rx_ring->data[i]; 3010aab5582fSPyun YongHyeon if (rdata->m != NULL) { 3011aab5582fSPyun YongHyeon bus_dmamap_sync(rx_ring->rx_data_tag, 3012aab5582fSPyun YongHyeon rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 3013aab5582fSPyun YongHyeon bus_dmamap_unload(rx_ring->rx_data_tag, 3014aab5582fSPyun YongHyeon rdata->rx_data_map); 3015aab5582fSPyun YongHyeon m_freem(rdata->m); 3016aab5582fSPyun YongHyeon rdata->m = NULL; 3017aab5582fSPyun YongHyeon } 3018aab5582fSPyun YongHyeon } 3019257c5577SDavid E. O'Brien 3020aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 3021aab5582fSPyun YongHyeon jrx_ring = &sc->jrxq; 3022aab5582fSPyun YongHyeon for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 3023aab5582fSPyun YongHyeon rdata = &jrx_ring->jdata[i]; 3024aab5582fSPyun YongHyeon if (rdata->m != NULL) { 3025aab5582fSPyun YongHyeon bus_dmamap_sync(jrx_ring->jrx_data_tag, 3026aab5582fSPyun YongHyeon rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 3027aab5582fSPyun YongHyeon bus_dmamap_unload(jrx_ring->jrx_data_tag, 3028aab5582fSPyun YongHyeon rdata->rx_data_map); 3029aab5582fSPyun YongHyeon m_freem(rdata->m); 3030aab5582fSPyun YongHyeon rdata->m = NULL; 3031aab5582fSPyun YongHyeon } 3032aab5582fSPyun YongHyeon } 3033aab5582fSPyun YongHyeon } 3034aab5582fSPyun YongHyeon 3035aab5582fSPyun YongHyeon tx_ring = &sc->txq; 3036aab5582fSPyun YongHyeon for (i = 0; i < NFE_RX_RING_COUNT; i++) { 3037aab5582fSPyun YongHyeon tdata = &tx_ring->data[i]; 3038aab5582fSPyun YongHyeon if (tdata->m != NULL) { 3039aab5582fSPyun YongHyeon bus_dmamap_sync(tx_ring->tx_data_tag, 3040aab5582fSPyun YongHyeon tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 3041aab5582fSPyun YongHyeon bus_dmamap_unload(tx_ring->tx_data_tag, 3042aab5582fSPyun YongHyeon tdata->tx_data_map); 3043aab5582fSPyun YongHyeon m_freem(tdata->m); 3044aab5582fSPyun YongHyeon tdata->m = NULL; 3045aab5582fSPyun YongHyeon } 3046aab5582fSPyun YongHyeon } 3047257c5577SDavid E. O'Brien } 3048257c5577SDavid E. O'Brien 30492c3adf61SDavid E. O'Brien 30502c3adf61SDavid E. O'Brien static int 30512c3adf61SDavid E. O'Brien nfe_ifmedia_upd(struct ifnet *ifp) 3052257c5577SDavid E. O'Brien { 3053257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 3054bfc788c2SDavid E. O'Brien struct mii_data *mii; 3055bfc788c2SDavid E. O'Brien 3056aab5582fSPyun YongHyeon NFE_LOCK(sc); 3057bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 3058bfc788c2SDavid E. O'Brien mii_mediachg(mii); 3059aab5582fSPyun YongHyeon NFE_UNLOCK(sc); 3060bfc788c2SDavid E. O'Brien 3061bfc788c2SDavid E. O'Brien return (0); 3062257c5577SDavid E. O'Brien } 3063257c5577SDavid E. O'Brien 30642c3adf61SDavid E. O'Brien 30652c3adf61SDavid E. O'Brien static void 30662c3adf61SDavid E. O'Brien nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 3067257c5577SDavid E. O'Brien { 3068bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 3069bfc788c2SDavid E. O'Brien struct mii_data *mii; 3070257c5577SDavid E. O'Brien 3071bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 3072bfc788c2SDavid E. O'Brien 3073bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 3074bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 3075257c5577SDavid E. O'Brien mii_pollstat(mii); 3076bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 3077bfc788c2SDavid E. O'Brien 3078257c5577SDavid E. O'Brien ifmr->ifm_active = mii->mii_media_active; 3079bfc788c2SDavid E. O'Brien ifmr->ifm_status = mii->mii_media_status; 3080257c5577SDavid E. O'Brien } 3081257c5577SDavid E. O'Brien 3082257c5577SDavid E. O'Brien 30832c3adf61SDavid E. O'Brien void 3084aab5582fSPyun YongHyeon nfe_tick(void *xsc) 3085bfc788c2SDavid E. O'Brien { 3086bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 3087bfc788c2SDavid E. O'Brien struct mii_data *mii; 3088bfc788c2SDavid E. O'Brien struct ifnet *ifp; 3089bfc788c2SDavid E. O'Brien 3090aab5582fSPyun YongHyeon sc = (struct nfe_softc *)xsc; 3091bfc788c2SDavid E. O'Brien 3092bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 3093bfc788c2SDavid E. O'Brien 3094bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 3095bfc788c2SDavid E. O'Brien 3096bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 3097bfc788c2SDavid E. O'Brien mii_tick(mii); 3098aab5582fSPyun YongHyeon nfe_watchdog(ifp); 3099bfc788c2SDavid E. O'Brien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 3100257c5577SDavid E. O'Brien } 3101257c5577SDavid E. O'Brien 3102bfc788c2SDavid E. O'Brien 31032c3adf61SDavid E. O'Brien static void 31042c3adf61SDavid E. O'Brien nfe_shutdown(device_t dev) 3105bfc788c2SDavid E. O'Brien { 3106bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 3107bfc788c2SDavid E. O'Brien struct ifnet *ifp; 3108bfc788c2SDavid E. O'Brien 3109bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 3110bfc788c2SDavid E. O'Brien 3111bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 3112bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 3113aab5582fSPyun YongHyeon nfe_stop(ifp); 3114bfc788c2SDavid E. O'Brien /* nfe_reset(sc); */ 3115bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 3116bfc788c2SDavid E. O'Brien } 3117bfc788c2SDavid E. O'Brien 3118bfc788c2SDavid E. O'Brien 31192c3adf61SDavid E. O'Brien static void 3120aab5582fSPyun YongHyeon nfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 3121257c5577SDavid E. O'Brien { 3122aab5582fSPyun YongHyeon uint32_t val; 3123257c5577SDavid E. O'Brien 3124aab5582fSPyun YongHyeon if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 3125aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_MACADDR_LO); 3126aab5582fSPyun YongHyeon addr[0] = (val >> 8) & 0xff; 3127aab5582fSPyun YongHyeon addr[1] = (val & 0xff); 3128257c5577SDavid E. O'Brien 3129aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_MACADDR_HI); 3130aab5582fSPyun YongHyeon addr[2] = (val >> 24) & 0xff; 3131aab5582fSPyun YongHyeon addr[3] = (val >> 16) & 0xff; 3132aab5582fSPyun YongHyeon addr[4] = (val >> 8) & 0xff; 3133aab5582fSPyun YongHyeon addr[5] = (val & 0xff); 3134aab5582fSPyun YongHyeon } else { 3135aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_MACADDR_LO); 3136aab5582fSPyun YongHyeon addr[5] = (val >> 8) & 0xff; 3137aab5582fSPyun YongHyeon addr[4] = (val & 0xff); 3138aab5582fSPyun YongHyeon 3139aab5582fSPyun YongHyeon val = NFE_READ(sc, NFE_MACADDR_HI); 3140aab5582fSPyun YongHyeon addr[3] = (val >> 24) & 0xff; 3141aab5582fSPyun YongHyeon addr[2] = (val >> 16) & 0xff; 3142aab5582fSPyun YongHyeon addr[1] = (val >> 8) & 0xff; 3143aab5582fSPyun YongHyeon addr[0] = (val & 0xff); 3144aab5582fSPyun YongHyeon } 3145257c5577SDavid E. O'Brien } 3146257c5577SDavid E. O'Brien 31472c3adf61SDavid E. O'Brien 31482c3adf61SDavid E. O'Brien static void 3149aab5582fSPyun YongHyeon nfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 3150257c5577SDavid E. O'Brien { 3151bfc788c2SDavid E. O'Brien 3152bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 3153bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 3154bfc788c2SDavid E. O'Brien addr[1] << 8 | addr[0]); 3155257c5577SDavid E. O'Brien } 3156257c5577SDavid E. O'Brien 31572c3adf61SDavid E. O'Brien 3158bfc788c2SDavid E. O'Brien /* 3159bfc788c2SDavid E. O'Brien * Map a single buffer address. 3160bfc788c2SDavid E. O'Brien */ 3161bfc788c2SDavid E. O'Brien 3162bfc788c2SDavid E. O'Brien static void 3163aab5582fSPyun YongHyeon nfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3164257c5577SDavid E. O'Brien { 3165aab5582fSPyun YongHyeon struct nfe_dmamap_arg *ctx; 3166257c5577SDavid E. O'Brien 3167aab5582fSPyun YongHyeon if (error != 0) 3168bfc788c2SDavid E. O'Brien return; 3169257c5577SDavid E. O'Brien 3170bfc788c2SDavid E. O'Brien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 3171bfc788c2SDavid E. O'Brien 3172aab5582fSPyun YongHyeon ctx = (struct nfe_dmamap_arg *)arg; 3173aab5582fSPyun YongHyeon ctx->nfe_busaddr = segs[0].ds_addr; 3174aab5582fSPyun YongHyeon } 3175bfc788c2SDavid E. O'Brien 3176aab5582fSPyun YongHyeon 3177aab5582fSPyun YongHyeon static int 3178aab5582fSPyun YongHyeon sysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3179aab5582fSPyun YongHyeon { 3180aab5582fSPyun YongHyeon int error, value; 3181aab5582fSPyun YongHyeon 3182aab5582fSPyun YongHyeon if (!arg1) 3183aab5582fSPyun YongHyeon return (EINVAL); 3184aab5582fSPyun YongHyeon value = *(int *)arg1; 3185aab5582fSPyun YongHyeon error = sysctl_handle_int(oidp, &value, 0, req); 3186aab5582fSPyun YongHyeon if (error || !req->newptr) 3187aab5582fSPyun YongHyeon return (error); 3188aab5582fSPyun YongHyeon if (value < low || value > high) 3189aab5582fSPyun YongHyeon return (EINVAL); 3190aab5582fSPyun YongHyeon *(int *)arg1 = value; 3191aab5582fSPyun YongHyeon 3192aab5582fSPyun YongHyeon return (0); 3193aab5582fSPyun YongHyeon } 3194aab5582fSPyun YongHyeon 3195aab5582fSPyun YongHyeon 3196aab5582fSPyun YongHyeon static int 3197aab5582fSPyun YongHyeon sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 3198aab5582fSPyun YongHyeon { 3199aab5582fSPyun YongHyeon 3200aab5582fSPyun YongHyeon return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 3201aab5582fSPyun YongHyeon NFE_PROC_MAX)); 3202257c5577SDavid E. O'Brien } 3203