1bfc788c2SDavid E. O'Brien /* $OpenBSD: if_nfe.c,v 1.54 2006/04/07 12:38:12 jsg Exp $ */ 2257c5577SDavid E. O'Brien 3257c5577SDavid E. O'Brien /*- 4bfc788c2SDavid E. O'Brien * Copyright (c) 2006 Shigeaki Tagashira <shigeaki@se.hiroshima-u.ac.jp> 5257c5577SDavid E. O'Brien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 6257c5577SDavid E. O'Brien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 7257c5577SDavid E. O'Brien * 8257c5577SDavid E. O'Brien * Permission to use, copy, modify, and distribute this software for any 9257c5577SDavid E. O'Brien * purpose with or without fee is hereby granted, provided that the above 10257c5577SDavid E. O'Brien * copyright notice and this permission notice appear in all copies. 11257c5577SDavid E. O'Brien * 12257c5577SDavid E. O'Brien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13257c5577SDavid E. O'Brien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14257c5577SDavid E. O'Brien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15257c5577SDavid E. O'Brien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16257c5577SDavid E. O'Brien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17257c5577SDavid E. O'Brien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18257c5577SDavid E. O'Brien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19257c5577SDavid E. O'Brien */ 20257c5577SDavid E. O'Brien 21257c5577SDavid E. O'Brien /* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 22257c5577SDavid E. O'Brien 23bfc788c2SDavid E. O'Brien #include <sys/cdefs.h> 24bfc788c2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 25bfc788c2SDavid E. O'Brien 26bfc788c2SDavid E. O'Brien /* Uncomment the following line to enable polling. */ 27bfc788c2SDavid E. O'Brien /* #define DEVICE_POLLING */ 28bfc788c2SDavid E. O'Brien 29bfc788c2SDavid E. O'Brien #define NFE_NO_JUMBO 30bfc788c2SDavid E. O'Brien #define NFE_CSUM 31bfc788c2SDavid E. O'Brien #define NFE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 32bfc788c2SDavid E. O'Brien #define NVLAN 0 33bfc788c2SDavid E. O'Brien 34bfc788c2SDavid E. O'Brien #ifdef HAVE_KERNEL_OPTION_HEADERS 35bfc788c2SDavid E. O'Brien #include "opt_device_polling.h" 36bfc788c2SDavid E. O'Brien #endif 37257c5577SDavid E. O'Brien 38257c5577SDavid E. O'Brien #include <sys/param.h> 39257c5577SDavid E. O'Brien #include <sys/endian.h> 40257c5577SDavid E. O'Brien #include <sys/systm.h> 41257c5577SDavid E. O'Brien #include <sys/sockio.h> 42257c5577SDavid E. O'Brien #include <sys/mbuf.h> 43257c5577SDavid E. O'Brien #include <sys/malloc.h> 44bfc788c2SDavid E. O'Brien #include <sys/module.h> 45257c5577SDavid E. O'Brien #include <sys/kernel.h> 46257c5577SDavid E. O'Brien #include <sys/socket.h> 47bfc788c2SDavid E. O'Brien #include <sys/taskqueue.h> 48257c5577SDavid E. O'Brien 49257c5577SDavid E. O'Brien #include <net/if.h> 50bfc788c2SDavid E. O'Brien #include <net/if_arp.h> 51bfc788c2SDavid E. O'Brien #include <net/ethernet.h> 52257c5577SDavid E. O'Brien #include <net/if_dl.h> 53257c5577SDavid E. O'Brien #include <net/if_media.h> 54257c5577SDavid E. O'Brien #include <net/if_types.h> 55257c5577SDavid E. O'Brien #include <net/if_vlan_var.h> 56257c5577SDavid E. O'Brien 57257c5577SDavid E. O'Brien #include <net/bpf.h> 58bfc788c2SDavid E. O'Brien 59bfc788c2SDavid E. O'Brien #include <machine/bus.h> 60bfc788c2SDavid E. O'Brien #include <machine/resource.h> 61bfc788c2SDavid E. O'Brien #include <sys/bus.h> 62bfc788c2SDavid E. O'Brien #include <sys/rman.h> 63257c5577SDavid E. O'Brien 64257c5577SDavid E. O'Brien #include <dev/mii/mii.h> 65257c5577SDavid E. O'Brien #include <dev/mii/miivar.h> 66257c5577SDavid E. O'Brien 67257c5577SDavid E. O'Brien #include <dev/pci/pcireg.h> 68257c5577SDavid E. O'Brien #include <dev/pci/pcivar.h> 69257c5577SDavid E. O'Brien 70bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfereg.h> 71bfc788c2SDavid E. O'Brien #include <dev/nfe/if_nfevar.h> 72257c5577SDavid E. O'Brien 73bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, pci, 1, 1, 1); 74bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, ether, 1, 1, 1); 75bfc788c2SDavid E. O'Brien MODULE_DEPEND(nfe, miibus, 1, 1, 1); 76bfc788c2SDavid E. O'Brien #include "miibus_if.h" 77257c5577SDavid E. O'Brien 78bfc788c2SDavid E. O'Brien static int nfe_probe (device_t); 79bfc788c2SDavid E. O'Brien static int nfe_attach (device_t); 80bfc788c2SDavid E. O'Brien static int nfe_detach (device_t); 81bfc788c2SDavid E. O'Brien static void nfe_shutdown(device_t); 82bfc788c2SDavid E. O'Brien static int nfe_miibus_readreg (device_t, int, int); 83bfc788c2SDavid E. O'Brien static int nfe_miibus_writereg (device_t, int, int, int); 84bfc788c2SDavid E. O'Brien static void nfe_miibus_statchg (device_t); 85bfc788c2SDavid E. O'Brien static int nfe_ioctl(struct ifnet *, u_long, caddr_t); 86bfc788c2SDavid E. O'Brien static void nfe_intr(void *); 87bfc788c2SDavid E. O'Brien static void nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 88bfc788c2SDavid E. O'Brien static void nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 89bfc788c2SDavid E. O'Brien static void nfe_txdesc32_rsync(struct nfe_softc *, int, int, int); 90bfc788c2SDavid E. O'Brien static void nfe_txdesc64_rsync(struct nfe_softc *, int, int, int); 91bfc788c2SDavid E. O'Brien static void nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 92bfc788c2SDavid E. O'Brien static void nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 93bfc788c2SDavid E. O'Brien static void nfe_rxeof(struct nfe_softc *); 94bfc788c2SDavid E. O'Brien static void nfe_txeof(struct nfe_softc *); 95bfc788c2SDavid E. O'Brien static int nfe_encap(struct nfe_softc *, struct mbuf *); 96bfc788c2SDavid E. O'Brien static struct nfe_jbuf *nfe_jalloc(struct nfe_softc *); 97bfc788c2SDavid E. O'Brien static void nfe_jfree(void *, void *); 98bfc788c2SDavid E. O'Brien static int nfe_jpool_alloc(struct nfe_softc *); 99bfc788c2SDavid E. O'Brien static void nfe_jpool_free(struct nfe_softc *); 100bfc788c2SDavid E. O'Brien static void nfe_setmulti(struct nfe_softc *); 101bfc788c2SDavid E. O'Brien static void nfe_start(struct ifnet *); 102bfc788c2SDavid E. O'Brien static void nfe_start_locked(struct ifnet *); 103bfc788c2SDavid E. O'Brien static void nfe_watchdog(struct ifnet *); 104bfc788c2SDavid E. O'Brien static void nfe_init(void *); 105bfc788c2SDavid E. O'Brien static void nfe_init_locked(void *); 106bfc788c2SDavid E. O'Brien static void nfe_stop(struct ifnet *, int); 107bfc788c2SDavid E. O'Brien static int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 108bfc788c2SDavid E. O'Brien static void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 109bfc788c2SDavid E. O'Brien static void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 110bfc788c2SDavid E. O'Brien static int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 111bfc788c2SDavid E. O'Brien static void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 112bfc788c2SDavid E. O'Brien static void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 113bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd(struct ifnet *); 114bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd_locked(struct ifnet *); 115bfc788c2SDavid E. O'Brien static void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 116bfc788c2SDavid E. O'Brien static void nfe_tick(void *); 117bfc788c2SDavid E. O'Brien static void nfe_tick_locked(struct nfe_softc *); 118bfc788c2SDavid E. O'Brien static void nfe_get_macaddr(struct nfe_softc *, u_char *); 119bfc788c2SDavid E. O'Brien static void nfe_set_macaddr(struct nfe_softc *, u_char *); 120bfc788c2SDavid E. O'Brien static void nfe_dma_map_segs (void *, bus_dma_segment_t *, int, int); 121bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 122bfc788c2SDavid E. O'Brien static void nfe_poll_locked(struct ifnet *, enum poll_cmd, int); 123bfc788c2SDavid E. O'Brien #endif 124257c5577SDavid E. O'Brien 125257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 126257c5577SDavid E. O'Brien int nfedebug = 0; 127257c5577SDavid E. O'Brien #define DPRINTF(x) do { if (nfedebug) printf x; } while (0) 128257c5577SDavid E. O'Brien #define DPRINTFN(n,x) do { if (nfedebug >= (n)) printf x; } while (0) 129257c5577SDavid E. O'Brien #else 130257c5577SDavid E. O'Brien #define DPRINTF(x) 131257c5577SDavid E. O'Brien #define DPRINTFN(n,x) 132257c5577SDavid E. O'Brien #endif 133257c5577SDavid E. O'Brien 134bfc788c2SDavid E. O'Brien #define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 135bfc788c2SDavid E. O'Brien #define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 136bfc788c2SDavid E. O'Brien #define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 137bfc788c2SDavid E. O'Brien 138bfc788c2SDavid E. O'Brien #define letoh16(x) le16toh(x) 139bfc788c2SDavid E. O'Brien 140bfc788c2SDavid E. O'Brien #define NV_RID 0x10 141bfc788c2SDavid E. O'Brien 142bfc788c2SDavid E. O'Brien static device_method_t nfe_methods[] = { 143bfc788c2SDavid E. O'Brien /* Device interface */ 144bfc788c2SDavid E. O'Brien DEVMETHOD(device_probe, nfe_probe), 145bfc788c2SDavid E. O'Brien DEVMETHOD(device_attach, nfe_attach), 146bfc788c2SDavid E. O'Brien DEVMETHOD(device_detach, nfe_detach), 147bfc788c2SDavid E. O'Brien DEVMETHOD(device_shutdown, nfe_shutdown), 148bfc788c2SDavid E. O'Brien 149bfc788c2SDavid E. O'Brien /* bus interface */ 150bfc788c2SDavid E. O'Brien DEVMETHOD(bus_print_child, bus_generic_print_child), 151bfc788c2SDavid E. O'Brien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 152bfc788c2SDavid E. O'Brien 153bfc788c2SDavid E. O'Brien /* MII interface */ 154bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 155bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 156bfc788c2SDavid E. O'Brien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 157bfc788c2SDavid E. O'Brien 158bfc788c2SDavid E. O'Brien { 0, 0 } 159257c5577SDavid E. O'Brien }; 160257c5577SDavid E. O'Brien 161bfc788c2SDavid E. O'Brien static driver_t nfe_driver = { 162bfc788c2SDavid E. O'Brien "nfe", 163bfc788c2SDavid E. O'Brien nfe_methods, 164bfc788c2SDavid E. O'Brien sizeof(struct nfe_softc) 165bfc788c2SDavid E. O'Brien }; 166bfc788c2SDavid E. O'Brien 167bfc788c2SDavid E. O'Brien static devclass_t nfe_devclass; 168bfc788c2SDavid E. O'Brien 169bfc788c2SDavid E. O'Brien DRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 170bfc788c2SDavid E. O'Brien DRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 171bfc788c2SDavid E. O'Brien 172bfc788c2SDavid E. O'Brien static struct nfe_type nfe_devs[] = { 173bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 174bfc788c2SDavid E. O'Brien "NVIDIA nForce Networking Adapter"}, 175bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 176bfc788c2SDavid E. O'Brien "NVIDIA nForce2 Networking Adapter"}, 177bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 178bfc788c2SDavid E. O'Brien "NVIDIA nForce3 Networking Adapter"}, 179bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 180bfc788c2SDavid E. O'Brien "NVIDIA nForce2 400 Networking Adapter"}, 181bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 182bfc788c2SDavid E. O'Brien "NVIDIA nForce2 400 Networking Adapter"}, 183bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 184bfc788c2SDavid E. O'Brien "NVIDIA nForce3 250 Networking Adapter"}, 185bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 186bfc788c2SDavid E. O'Brien "NVIDIA nForce3 Networking Adapter"}, 187bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 188bfc788c2SDavid E. O'Brien "NVIDIA nForce4 Networking Adapter"}, 189bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 190bfc788c2SDavid E. O'Brien "NVIDIA nForce4 Networking Adapter"}, 191bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 192bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, 193bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 194bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP04 Networking Adapter"}, 195bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 196bfc788c2SDavid E. O'Brien "NVIDIA nForce 430 Networking Adapter"}, 197bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 198bfc788c2SDavid E. O'Brien "NVIDIA nForce 430 Networking Adapter"}, 199bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 200bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 201bfc788c2SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 202bfc788c2SDavid E. O'Brien "NVIDIA nForce MCP55 Networking Adapter"}, 2033e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 2043e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2053e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2063e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2073e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 2083e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2093e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2103e232000SDavid E. O'Brien "NVIDIA nForce MCP61 Networking Adapter"}, 2113e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 2123e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2133e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2143e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2153e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 2163e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 2173e232000SDavid E. O'Brien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2183e232000SDavid E. O'Brien "NVIDIA nForce MCP65 Networking Adapter"}, 219bfc788c2SDavid E. O'Brien {0, 0, NULL} 220bfc788c2SDavid E. O'Brien }; 221bfc788c2SDavid E. O'Brien 222bfc788c2SDavid E. O'Brien 223bfc788c2SDavid E. O'Brien /* Probe for supported hardware ID's */ 224bfc788c2SDavid E. O'Brien static int 225bfc788c2SDavid E. O'Brien nfe_probe(device_t dev) 226257c5577SDavid E. O'Brien { 227bfc788c2SDavid E. O'Brien struct nfe_type *t; 228bfc788c2SDavid E. O'Brien 229bfc788c2SDavid E. O'Brien t = nfe_devs; 230bfc788c2SDavid E. O'Brien /* Check for matching PCI DEVICE ID's */ 231bfc788c2SDavid E. O'Brien while (t->name != NULL) { 232bfc788c2SDavid E. O'Brien if ((pci_get_vendor(dev) == t->vid_id) && 233bfc788c2SDavid E. O'Brien (pci_get_device(dev) == t->dev_id)) { 234bfc788c2SDavid E. O'Brien device_set_desc(dev, t->name); 235bfc788c2SDavid E. O'Brien return (0); 236bfc788c2SDavid E. O'Brien } 237bfc788c2SDavid E. O'Brien t++; 238257c5577SDavid E. O'Brien } 239257c5577SDavid E. O'Brien 240bfc788c2SDavid E. O'Brien return (ENXIO); 241bfc788c2SDavid E. O'Brien } 242bfc788c2SDavid E. O'Brien 243bfc788c2SDavid E. O'Brien static int 244bfc788c2SDavid E. O'Brien nfe_attach(device_t dev) 245257c5577SDavid E. O'Brien { 246bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 247257c5577SDavid E. O'Brien struct ifnet *ifp; 248bfc788c2SDavid E. O'Brien int unit, error = 0, rid; 249257c5577SDavid E. O'Brien 250bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 251bfc788c2SDavid E. O'Brien unit = device_get_unit(dev); 252bfc788c2SDavid E. O'Brien sc->nfe_dev = dev; 253bfc788c2SDavid E. O'Brien sc->nfe_unit = unit; 254bfc788c2SDavid E. O'Brien 255bfc788c2SDavid E. O'Brien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 256bfc788c2SDavid E. O'Brien MTX_DEF | MTX_RECURSE); 257bfc788c2SDavid E. O'Brien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 258bfc788c2SDavid E. O'Brien 259bfc788c2SDavid E. O'Brien 260bfc788c2SDavid E. O'Brien pci_enable_busmaster(dev); 261bfc788c2SDavid E. O'Brien 262bfc788c2SDavid E. O'Brien rid = NV_RID; 263bfc788c2SDavid E. O'Brien sc->nfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 264bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_ACTIVE); 265bfc788c2SDavid E. O'Brien 266bfc788c2SDavid E. O'Brien if (sc->nfe_res == NULL) { 267bfc788c2SDavid E. O'Brien printf ("nfe%d: couldn't map ports/memory\n", unit); 268bfc788c2SDavid E. O'Brien error = ENXIO; 269bfc788c2SDavid E. O'Brien goto fail; 270257c5577SDavid E. O'Brien } 271257c5577SDavid E. O'Brien 272bfc788c2SDavid E. O'Brien sc->nfe_memt = rman_get_bustag(sc->nfe_res); 273bfc788c2SDavid E. O'Brien sc->nfe_memh = rman_get_bushandle(sc->nfe_res); 274bfc788c2SDavid E. O'Brien 275bfc788c2SDavid E. O'Brien /* Allocate interrupt */ 276bfc788c2SDavid E. O'Brien rid = 0; 277bfc788c2SDavid E. O'Brien sc->nfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 278bfc788c2SDavid E. O'Brien 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 279bfc788c2SDavid E. O'Brien 280bfc788c2SDavid E. O'Brien if (sc->nfe_irq == NULL) { 281bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't map interrupt\n", unit); 282bfc788c2SDavid E. O'Brien error = ENXIO; 283bfc788c2SDavid E. O'Brien goto fail; 284257c5577SDavid E. O'Brien } 285257c5577SDavid E. O'Brien 286bfc788c2SDavid E. O'Brien nfe_get_macaddr(sc, sc->eaddr); 287257c5577SDavid E. O'Brien 288bfc788c2SDavid E. O'Brien sc->nfe_flags = 0; 289257c5577SDavid E. O'Brien 290bfc788c2SDavid E. O'Brien switch (pci_get_device(dev)) { 291257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 292257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 293257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 294257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 295bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 296257c5577SDavid E. O'Brien break; 297257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 298257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 299bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 300257c5577SDavid E. O'Brien break; 301257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 302257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 303257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 304257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 305bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 306257c5577SDavid E. O'Brien break; 307257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 308257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 309bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_HW_VLAN; 310257c5577SDavid E. O'Brien break; 3113e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 3123e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 3133e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 3143e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 3153e232000SDavid E. O'Brien sc->nfe_flags |= NFE_40BIT_ADDR; 3163e232000SDavid E. O'Brien break; 3173e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 3183e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 3193e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 3203e232000SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 3213e232000SDavid E. O'Brien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 3223e232000SDavid E. O'Brien break; 323257c5577SDavid E. O'Brien } 324257c5577SDavid E. O'Brien 325257c5577SDavid E. O'Brien #ifndef NFE_NO_JUMBO 326257c5577SDavid E. O'Brien /* enable jumbo frames for adapters that support it */ 327bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 328bfc788c2SDavid E. O'Brien sc->nfe_flags |= NFE_USE_JUMBO; 329257c5577SDavid E. O'Brien #endif 330257c5577SDavid E. O'Brien 331257c5577SDavid E. O'Brien /* 332bfc788c2SDavid E. O'Brien * Allocate the parent bus DMA tag appropriate for PCI. 333bfc788c2SDavid E. O'Brien */ 334bfc788c2SDavid E. O'Brien #define NFE_NSEG_NEW 32 335bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(NULL, /* parent */ 336bfc788c2SDavid E. O'Brien 1, 0, /* alignment, boundary */ 337bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 338bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 339bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 340bfc788c2SDavid E. O'Brien MAXBSIZE, NFE_NSEG_NEW, /* maxsize, nsegments */ 341bfc788c2SDavid E. O'Brien BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 342bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 343bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 344bfc788c2SDavid E. O'Brien &sc->nfe_parent_tag); 345bfc788c2SDavid E. O'Brien if (error) 346bfc788c2SDavid E. O'Brien goto fail; 347bfc788c2SDavid E. O'Brien 348bfc788c2SDavid E. O'Brien /* 349257c5577SDavid E. O'Brien * Allocate Tx and Rx rings. 350257c5577SDavid E. O'Brien */ 351257c5577SDavid E. O'Brien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 352bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Tx ring\n", unit); 353bfc788c2SDavid E. O'Brien error = ENXIO; 354bfc788c2SDavid E. O'Brien goto fail; 355257c5577SDavid E. O'Brien } 356257c5577SDavid E. O'Brien 357257c5577SDavid E. O'Brien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 358bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate Rx ring\n", unit); 359257c5577SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 360bfc788c2SDavid E. O'Brien error = ENXIO; 361bfc788c2SDavid E. O'Brien goto fail; 362257c5577SDavid E. O'Brien } 363257c5577SDavid E. O'Brien 364bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 365bfc788c2SDavid E. O'Brien if (ifp == NULL) { 366bfc788c2SDavid E. O'Brien printf("nfe%d: can not if_alloc()\n", unit); 367bfc788c2SDavid E. O'Brien error = ENOSPC; 368bfc788c2SDavid E. O'Brien goto fail; 369bfc788c2SDavid E. O'Brien } 370bfc788c2SDavid E. O'Brien 371257c5577SDavid E. O'Brien ifp->if_softc = sc; 372bfc788c2SDavid E. O'Brien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 373bfc788c2SDavid E. O'Brien ifp->if_mtu = ETHERMTU; 374257c5577SDavid E. O'Brien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 375257c5577SDavid E. O'Brien ifp->if_ioctl = nfe_ioctl; 376257c5577SDavid E. O'Brien ifp->if_start = nfe_start; 377bfc788c2SDavid E. O'Brien /* ifp->if_hwassist = NFE_CSUM_FEATURES; */ 378257c5577SDavid E. O'Brien ifp->if_watchdog = nfe_watchdog; 379257c5577SDavid E. O'Brien ifp->if_init = nfe_init; 380257c5577SDavid E. O'Brien ifp->if_baudrate = IF_Gbps(1); 381bfc788c2SDavid E. O'Brien ifp->if_snd.ifq_maxlen = NFE_IFQ_MAXLEN; 382257c5577SDavid E. O'Brien 383257c5577SDavid E. O'Brien ifp->if_capabilities = IFCAP_VLAN_MTU; 384257c5577SDavid E. O'Brien #if NVLAN > 0 385bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 386257c5577SDavid E. O'Brien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 387257c5577SDavid E. O'Brien #endif 388257c5577SDavid E. O'Brien #ifdef NFE_CSUM 389bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) { 390bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_HWCSUM; 391257c5577SDavid E. O'Brien } 392257c5577SDavid E. O'Brien #endif 393bfc788c2SDavid E. O'Brien ifp->if_capenable = ifp->if_capabilities; 394257c5577SDavid E. O'Brien 395bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 396bfc788c2SDavid E. O'Brien ifp->if_capabilities |= IFCAP_POLLING; 397bfc788c2SDavid E. O'Brien #endif 398257c5577SDavid E. O'Brien 399bfc788c2SDavid E. O'Brien /* Do MII setup */ 400bfc788c2SDavid E. O'Brien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, nfe_ifmedia_sts)) { 401bfc788c2SDavid E. O'Brien printf("nfe%d: MII without any phy!\n", unit); 402bfc788c2SDavid E. O'Brien error = ENXIO; 403bfc788c2SDavid E. O'Brien goto fail; 404257c5577SDavid E. O'Brien } 405257c5577SDavid E. O'Brien 406bfc788c2SDavid E. O'Brien ether_ifattach(ifp, sc->eaddr); 407bfc788c2SDavid E. O'Brien 408bfc788c2SDavid E. O'Brien error = bus_setup_intr(dev, sc->nfe_irq, INTR_TYPE_NET|INTR_MPSAFE, 409bfc788c2SDavid E. O'Brien nfe_intr, sc, &sc->nfe_intrhand); 410bfc788c2SDavid E. O'Brien 411bfc788c2SDavid E. O'Brien if (error) { 412bfc788c2SDavid E. O'Brien printf("nfe%d: couldn't set up irq\n", unit); 413bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 414bfc788c2SDavid E. O'Brien goto fail; 415bfc788c2SDavid E. O'Brien } 416bfc788c2SDavid E. O'Brien 417bfc788c2SDavid E. O'Brien fail: 418bfc788c2SDavid E. O'Brien if (error) 419bfc788c2SDavid E. O'Brien nfe_detach(dev); 420bfc788c2SDavid E. O'Brien 421bfc788c2SDavid E. O'Brien return (error); 422bfc788c2SDavid E. O'Brien } 423bfc788c2SDavid E. O'Brien 424bfc788c2SDavid E. O'Brien 425bfc788c2SDavid E. O'Brien static int 426bfc788c2SDavid E. O'Brien nfe_detach(device_t dev) 427257c5577SDavid E. O'Brien { 428bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 429257c5577SDavid E. O'Brien struct ifnet *ifp; 430bfc788c2SDavid E. O'Brien u_char eaddr[ETHER_ADDR_LEN]; 431bfc788c2SDavid E. O'Brien int i; 432257c5577SDavid E. O'Brien 433bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 434bfc788c2SDavid E. O'Brien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 435bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 436bfc788c2SDavid E. O'Brien 437bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 438bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 439bfc788c2SDavid E. O'Brien ether_poll_deregister(ifp); 440bfc788c2SDavid E. O'Brien #endif 441bfc788c2SDavid E. O'Brien 442bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 443bfc788c2SDavid E. O'Brien eaddr[i] = sc->eaddr[5 - i]; 444257c5577SDavid E. O'Brien } 445bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, eaddr); 446bfc788c2SDavid E. O'Brien 447bfc788c2SDavid E. O'Brien if (device_is_attached(dev)) { 448bfc788c2SDavid E. O'Brien nfe_stop(ifp, 1); 449bfc788c2SDavid E. O'Brien ifp->if_flags &= ~IFF_UP; 450bfc788c2SDavid E. O'Brien callout_drain(&sc->nfe_stat_ch); 451bfc788c2SDavid E. O'Brien ether_ifdetach(ifp); 452257c5577SDavid E. O'Brien } 453257c5577SDavid E. O'Brien 454bfc788c2SDavid E. O'Brien if (ifp) 455bfc788c2SDavid E. O'Brien if_free(ifp); 456bfc788c2SDavid E. O'Brien if (sc->nfe_miibus) 457bfc788c2SDavid E. O'Brien device_delete_child(dev, sc->nfe_miibus); 458bfc788c2SDavid E. O'Brien bus_generic_detach(dev); 459bfc788c2SDavid E. O'Brien 460bfc788c2SDavid E. O'Brien if (sc->nfe_intrhand) 461bfc788c2SDavid E. O'Brien bus_teardown_intr(dev, sc->nfe_irq, sc->nfe_intrhand); 462bfc788c2SDavid E. O'Brien if (sc->nfe_irq) 463bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nfe_irq); 464bfc788c2SDavid E. O'Brien if (sc->nfe_res) 465bfc788c2SDavid E. O'Brien bus_release_resource(dev, SYS_RES_MEMORY, NV_RID, sc->nfe_res); 466bfc788c2SDavid E. O'Brien 467bfc788c2SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 468bfc788c2SDavid E. O'Brien nfe_free_rx_ring(sc, &sc->rxq); 469bfc788c2SDavid E. O'Brien 470bfc788c2SDavid E. O'Brien if (sc->nfe_parent_tag) 471bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(sc->nfe_parent_tag); 472bfc788c2SDavid E. O'Brien 473bfc788c2SDavid E. O'Brien mtx_destroy(&sc->nfe_mtx); 474bfc788c2SDavid E. O'Brien 475bfc788c2SDavid E. O'Brien return (0); 476bfc788c2SDavid E. O'Brien } 477bfc788c2SDavid E. O'Brien 478bfc788c2SDavid E. O'Brien 479bfc788c2SDavid E. O'Brien static void 480bfc788c2SDavid E. O'Brien nfe_miibus_statchg(device_t dev) 481257c5577SDavid E. O'Brien { 482bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 483bfc788c2SDavid E. O'Brien struct mii_data *mii; 484bfc788c2SDavid E. O'Brien u_int32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 485bfc788c2SDavid E. O'Brien 486bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 487bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 488257c5577SDavid E. O'Brien 489257c5577SDavid E. O'Brien phy = NFE_READ(sc, NFE_PHY_IFACE); 490257c5577SDavid E. O'Brien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 491257c5577SDavid E. O'Brien 492257c5577SDavid E. O'Brien seed = NFE_READ(sc, NFE_RNDSEED); 493257c5577SDavid E. O'Brien seed &= ~NFE_SEED_MASK; 494257c5577SDavid E. O'Brien 495257c5577SDavid E. O'Brien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 496257c5577SDavid E. O'Brien phy |= NFE_PHY_HDX; /* half-duplex */ 497257c5577SDavid E. O'Brien misc |= NFE_MISC1_HDX; 498257c5577SDavid E. O'Brien } 499257c5577SDavid E. O'Brien 500257c5577SDavid E. O'Brien switch (IFM_SUBTYPE(mii->mii_media_active)) { 501257c5577SDavid E. O'Brien case IFM_1000_T: /* full-duplex only */ 502257c5577SDavid E. O'Brien link |= NFE_MEDIA_1000T; 503257c5577SDavid E. O'Brien seed |= NFE_SEED_1000T; 504257c5577SDavid E. O'Brien phy |= NFE_PHY_1000T; 505257c5577SDavid E. O'Brien break; 506257c5577SDavid E. O'Brien case IFM_100_TX: 507257c5577SDavid E. O'Brien link |= NFE_MEDIA_100TX; 508257c5577SDavid E. O'Brien seed |= NFE_SEED_100TX; 509257c5577SDavid E. O'Brien phy |= NFE_PHY_100TX; 510257c5577SDavid E. O'Brien break; 511257c5577SDavid E. O'Brien case IFM_10_T: 512257c5577SDavid E. O'Brien link |= NFE_MEDIA_10T; 513257c5577SDavid E. O'Brien seed |= NFE_SEED_10T; 514257c5577SDavid E. O'Brien break; 515257c5577SDavid E. O'Brien } 516257c5577SDavid E. O'Brien 517257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 518257c5577SDavid E. O'Brien 519257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 520257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MISC1, misc); 521257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_LINKSPEED, link); 522257c5577SDavid E. O'Brien } 523257c5577SDavid E. O'Brien 524bfc788c2SDavid E. O'Brien static int 525bfc788c2SDavid E. O'Brien nfe_miibus_readreg(device_t dev, int phy, int reg) 526257c5577SDavid E. O'Brien { 527bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 528bfc788c2SDavid E. O'Brien u_int32_t val; 529257c5577SDavid E. O'Brien int ntries; 530257c5577SDavid E. O'Brien 531257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 532257c5577SDavid E. O'Brien 533257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 534257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 535257c5577SDavid E. O'Brien DELAY(100); 536257c5577SDavid E. O'Brien } 537257c5577SDavid E. O'Brien 538257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 539257c5577SDavid E. O'Brien 540257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 541257c5577SDavid E. O'Brien DELAY(100); 542257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 543257c5577SDavid E. O'Brien break; 544257c5577SDavid E. O'Brien } 545257c5577SDavid E. O'Brien if (ntries == 1000) { 546bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: timeout waiting for PHY\n", sc->nfe_unit)); 547257c5577SDavid E. O'Brien return 0; 548257c5577SDavid E. O'Brien } 549257c5577SDavid E. O'Brien 550257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 551bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: could not read PHY\n", sc->nfe_unit)); 552257c5577SDavid E. O'Brien return 0; 553257c5577SDavid E. O'Brien } 554257c5577SDavid E. O'Brien 555257c5577SDavid E. O'Brien val = NFE_READ(sc, NFE_PHY_DATA); 556257c5577SDavid E. O'Brien if (val != 0xffffffff && val != 0) 557257c5577SDavid E. O'Brien sc->mii_phyaddr = phy; 558257c5577SDavid E. O'Brien 559bfc788c2SDavid E. O'Brien DPRINTFN(2, ("nfe%d: mii read phy %d reg 0x%x ret 0x%x\n", sc->nfe_unit, phy, reg, val)); 560257c5577SDavid E. O'Brien 561257c5577SDavid E. O'Brien return val; 562257c5577SDavid E. O'Brien } 563257c5577SDavid E. O'Brien 564bfc788c2SDavid E. O'Brien static int 565bfc788c2SDavid E. O'Brien nfe_miibus_writereg(device_t dev, int phy, int reg, int val) 566257c5577SDavid E. O'Brien { 567bfc788c2SDavid E. O'Brien struct nfe_softc *sc = device_get_softc(dev); 568bfc788c2SDavid E. O'Brien u_int32_t ctl; 569257c5577SDavid E. O'Brien int ntries; 570257c5577SDavid E. O'Brien 571257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 572257c5577SDavid E. O'Brien 573257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 574257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 575257c5577SDavid E. O'Brien DELAY(100); 576257c5577SDavid E. O'Brien } 577257c5577SDavid E. O'Brien 578257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_DATA, val); 579257c5577SDavid E. O'Brien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 580257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 581257c5577SDavid E. O'Brien 582257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 583257c5577SDavid E. O'Brien DELAY(100); 584257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 585257c5577SDavid E. O'Brien break; 586257c5577SDavid E. O'Brien } 587257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 588257c5577SDavid E. O'Brien if (nfedebug >= 2 && ntries == 1000) 589257c5577SDavid E. O'Brien printf("could not write to PHY\n"); 590257c5577SDavid E. O'Brien #endif 591bfc788c2SDavid E. O'Brien return 0; 592257c5577SDavid E. O'Brien } 593257c5577SDavid E. O'Brien 594bfc788c2SDavid E. O'Brien static int 595bfc788c2SDavid E. O'Brien nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 596bfc788c2SDavid E. O'Brien { 597bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32; 598bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64; 599bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 600bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 601bfc788c2SDavid E. O'Brien void **desc; 602bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 603bfc788c2SDavid E. O'Brien int i, error, descsize; 604bfc788c2SDavid E. O'Brien 605bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 606bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 607bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 608bfc788c2SDavid E. O'Brien } else { 609bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 610bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 611bfc788c2SDavid E. O'Brien } 612bfc788c2SDavid E. O'Brien 613bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 614bfc788c2SDavid E. O'Brien ring->bufsz = MCLBYTES; 615bfc788c2SDavid E. O'Brien 616bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 617bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 618bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 619bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 620bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 621bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 622bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 623bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 624bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 625bfc788c2SDavid E. O'Brien &ring->rx_desc_tag); 626bfc788c2SDavid E. O'Brien if (error != 0) { 627bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 628bfc788c2SDavid E. O'Brien goto fail; 629bfc788c2SDavid E. O'Brien } 630bfc788c2SDavid E. O'Brien 631bfc788c2SDavid E. O'Brien /* allocate memory to desc */ 632bfc788c2SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_desc_tag, (void **)desc, BUS_DMA_NOWAIT, &ring->rx_desc_map); 633bfc788c2SDavid E. O'Brien if (error != 0) { 634bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 635bfc788c2SDavid E. O'Brien goto fail; 636bfc788c2SDavid E. O'Brien } 637bfc788c2SDavid E. O'Brien 638bfc788c2SDavid E. O'Brien /* map desc to device visible address space */ 639bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, *desc, 640bfc788c2SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->rx_desc_segs, BUS_DMA_NOWAIT); 641bfc788c2SDavid E. O'Brien if (error != 0) { 642bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 643bfc788c2SDavid E. O'Brien goto fail; 644bfc788c2SDavid E. O'Brien } 645bfc788c2SDavid E. O'Brien 646bfc788c2SDavid E. O'Brien bzero(*desc, NFE_RX_RING_COUNT * descsize); 647bfc788c2SDavid E. O'Brien ring->rx_desc_addr = ring->rx_desc_segs.ds_addr; 648bfc788c2SDavid E. O'Brien ring->physaddr = ring->rx_desc_addr; 649bfc788c2SDavid E. O'Brien 650bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 651bfc788c2SDavid E. O'Brien ring->bufsz = NFE_JBYTES; 652bfc788c2SDavid E. O'Brien if ((error = nfe_jpool_alloc(sc)) != 0) { 653bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate jumbo frames\n", sc->nfe_unit); 654bfc788c2SDavid E. O'Brien goto fail; 655bfc788c2SDavid E. O'Brien } 656bfc788c2SDavid E. O'Brien } 657bfc788c2SDavid E. O'Brien 658bfc788c2SDavid E. O'Brien /* 659bfc788c2SDavid E. O'Brien * Pre-allocate Rx buffers and populate Rx ring. 660bfc788c2SDavid E. O'Brien */ 661bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 662bfc788c2SDavid E. O'Brien data = &sc->rxq.data[i]; 663bfc788c2SDavid E. O'Brien 664bfc788c2SDavid E. O'Brien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 665bfc788c2SDavid E. O'Brien if (data->m == NULL) { 666bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate rx mbuf\n", sc->nfe_unit); 667bfc788c2SDavid E. O'Brien error = ENOMEM; 668bfc788c2SDavid E. O'Brien goto fail; 669bfc788c2SDavid E. O'Brien } 670bfc788c2SDavid E. O'Brien 671bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 672bfc788c2SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 673bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate jumbo buffer\n", sc->nfe_unit); 674bfc788c2SDavid E. O'Brien goto fail; 675bfc788c2SDavid E. O'Brien } 676bfc788c2SDavid E. O'Brien data->m->m_data = (void *)jbuf->buf; 677bfc788c2SDavid E. O'Brien data->m->m_len = data->m->m_pkthdr.len = NFE_JBYTES; 678bfc788c2SDavid E. O'Brien MEXTADD(data->m, jbuf->buf, NFE_JBYTES, nfe_jfree, (struct nfe_softc *)sc, 0, EXT_NET_DRV); 679bfc788c2SDavid E. O'Brien /* m_adj(data->m, ETHER_ALIGN); */ 680bfc788c2SDavid E. O'Brien physaddr = jbuf->physaddr; 681bfc788c2SDavid E. O'Brien } else { 682bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 683d0220c83SRuslan Ermilov ETHER_ALIGN, 0, /* alignment, boundary */ 684bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 685bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 686bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 687bfc788c2SDavid E. O'Brien MCLBYTES, 1, /* maxsize, nsegments */ 688bfc788c2SDavid E. O'Brien MCLBYTES, /* maxsegsize */ 689bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 690bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 691bfc788c2SDavid E. O'Brien &data->rx_data_tag); 692bfc788c2SDavid E. O'Brien if (error != 0) { 693bfc788c2SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", sc->nfe_unit); 694bfc788c2SDavid E. O'Brien goto fail; 695bfc788c2SDavid E. O'Brien } 696bfc788c2SDavid E. O'Brien 697bfc788c2SDavid E. O'Brien error = bus_dmamap_create(data->rx_data_tag, 0, &data->rx_data_map); 698bfc788c2SDavid E. O'Brien if (error != 0) { 699bfc788c2SDavid E. O'Brien printf("nfe%d: could not allocate mbuf cluster\n", sc->nfe_unit); 700bfc788c2SDavid E. O'Brien goto fail; 701bfc788c2SDavid E. O'Brien } 702bfc788c2SDavid E. O'Brien 703bfc788c2SDavid E. O'Brien MCLGET(data->m, M_DONTWAIT); 704bfc788c2SDavid E. O'Brien if (!(data->m->m_flags & M_EXT)) { 705bfc788c2SDavid E. O'Brien error = ENOMEM; 706bfc788c2SDavid E. O'Brien goto fail; 707bfc788c2SDavid E. O'Brien } 708bfc788c2SDavid E. O'Brien 709bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, data->rx_data_map, mtod(data->m, void *), 710bfc788c2SDavid E. O'Brien MCLBYTES, nfe_dma_map_segs, &data->rx_data_segs, BUS_DMA_NOWAIT); 711bfc788c2SDavid E. O'Brien if (error != 0) { 712d0220c83SRuslan Ermilov printf("nfe%d: could not load rx buf DMA map\n", sc->nfe_unit); 713bfc788c2SDavid E. O'Brien goto fail; 714bfc788c2SDavid E. O'Brien } 715bfc788c2SDavid E. O'Brien 716bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 717bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 718bfc788c2SDavid E. O'Brien 719bfc788c2SDavid E. O'Brien } 720bfc788c2SDavid E. O'Brien 721bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 722bfc788c2SDavid E. O'Brien desc64 = &sc->rxq.desc64[i]; 723bfc788c2SDavid E. O'Brien #if defined(__LP64__) 724bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 725bfc788c2SDavid E. O'Brien #endif 726bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 727bfc788c2SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 728bfc788c2SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 729bfc788c2SDavid E. O'Brien } else { 730bfc788c2SDavid E. O'Brien desc32 = &sc->rxq.desc32[i]; 731bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 732bfc788c2SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 733bfc788c2SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 734bfc788c2SDavid E. O'Brien } 735bfc788c2SDavid E. O'Brien 736bfc788c2SDavid E. O'Brien } 737bfc788c2SDavid E. O'Brien 738bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, BUS_DMASYNC_PREWRITE); 739bfc788c2SDavid E. O'Brien 740bfc788c2SDavid E. O'Brien return 0; 741bfc788c2SDavid E. O'Brien 742bfc788c2SDavid E. O'Brien fail: nfe_free_rx_ring(sc, ring); 743bfc788c2SDavid E. O'Brien 744bfc788c2SDavid E. O'Brien return error; 745bfc788c2SDavid E. O'Brien } 746bfc788c2SDavid E. O'Brien 747bfc788c2SDavid E. O'Brien static int 748bfc788c2SDavid E. O'Brien nfe_jpool_alloc(struct nfe_softc *sc) 749bfc788c2SDavid E. O'Brien { 750bfc788c2SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 751bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 752bfc788c2SDavid E. O'Brien bus_addr_t physaddr; 753bfc788c2SDavid E. O'Brien caddr_t buf; 754bfc788c2SDavid E. O'Brien int i, error; 755bfc788c2SDavid E. O'Brien 756bfc788c2SDavid E. O'Brien /* 757bfc788c2SDavid E. O'Brien * Allocate a big chunk of DMA'able memory. 758bfc788c2SDavid E. O'Brien */ 759bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 760bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 761bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 762bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 763bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 764bfc788c2SDavid E. O'Brien NFE_JPOOL_SIZE, 1, /* maxsize, nsegments */ 765bfc788c2SDavid E. O'Brien NFE_JPOOL_SIZE, /* maxsegsize */ 766bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 767bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 768bfc788c2SDavid E. O'Brien &ring->rx_jumbo_tag); 769bfc788c2SDavid E. O'Brien if (error != 0) { 770bfc788c2SDavid E. O'Brien printf("nfe%d: could not create jumbo DMA tag\n", sc->nfe_unit); 771bfc788c2SDavid E. O'Brien goto fail; 772bfc788c2SDavid E. O'Brien } 773bfc788c2SDavid E. O'Brien error = bus_dmamem_alloc(ring->rx_jumbo_tag, (void **)&ring->jpool, BUS_DMA_NOWAIT, &ring->rx_jumbo_map); 774bfc788c2SDavid E. O'Brien if (error != 0) { 775bfc788c2SDavid E. O'Brien printf("nfe%d: could not create jumbo DMA memory\n", sc->nfe_unit); 776bfc788c2SDavid E. O'Brien goto fail; 777bfc788c2SDavid E. O'Brien } 778bfc788c2SDavid E. O'Brien 779bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->rx_jumbo_tag, ring->rx_jumbo_map, ring->jpool, 780bfc788c2SDavid E. O'Brien NFE_JPOOL_SIZE, nfe_dma_map_segs, &ring->rx_jumbo_segs, BUS_DMA_NOWAIT); 781bfc788c2SDavid E. O'Brien if (error != 0) { 782bfc788c2SDavid E. O'Brien printf("nfe%d: could not load jumbo DMA map\n", sc->nfe_unit); 783bfc788c2SDavid E. O'Brien goto fail; 784bfc788c2SDavid E. O'Brien } 785bfc788c2SDavid E. O'Brien 786bfc788c2SDavid E. O'Brien /* ..and split it into 9KB chunks */ 787bfc788c2SDavid E. O'Brien SLIST_INIT(&ring->jfreelist); 788bfc788c2SDavid E. O'Brien 789bfc788c2SDavid E. O'Brien buf = ring->jpool; 790bfc788c2SDavid E. O'Brien ring->rx_jumbo_addr = ring->rx_jumbo_segs.ds_addr; 791bfc788c2SDavid E. O'Brien physaddr = ring->rx_jumbo_addr; 792bfc788c2SDavid E. O'Brien 793bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_JPOOL_COUNT; i++) { 794bfc788c2SDavid E. O'Brien jbuf = &ring->jbuf[i]; 795bfc788c2SDavid E. O'Brien 796bfc788c2SDavid E. O'Brien jbuf->buf = buf; 797bfc788c2SDavid E. O'Brien jbuf->physaddr = physaddr; 798bfc788c2SDavid E. O'Brien 799bfc788c2SDavid E. O'Brien SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 800bfc788c2SDavid E. O'Brien 801bfc788c2SDavid E. O'Brien buf += NFE_JBYTES; 802bfc788c2SDavid E. O'Brien physaddr += NFE_JBYTES; 803bfc788c2SDavid E. O'Brien } 804bfc788c2SDavid E. O'Brien 805bfc788c2SDavid E. O'Brien return 0; 806bfc788c2SDavid E. O'Brien 807bfc788c2SDavid E. O'Brien fail: nfe_jpool_free(sc); 808bfc788c2SDavid E. O'Brien return error; 809bfc788c2SDavid E. O'Brien } 810bfc788c2SDavid E. O'Brien 811bfc788c2SDavid E. O'Brien 812bfc788c2SDavid E. O'Brien static void 813bfc788c2SDavid E. O'Brien nfe_jpool_free(struct nfe_softc *sc) 814bfc788c2SDavid E. O'Brien { 815bfc788c2SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 816bfc788c2SDavid E. O'Brien 817bfc788c2SDavid E. O'Brien if (ring->jpool != NULL) { 818bfc788c2SDavid E. O'Brien #if 0 819bfc788c2SDavid E. O'Brien bus_dmamem_unmap(ring->rx_jumbo_tag, ring->jpool, NFE_JPOOL_SIZE); 820bfc788c2SDavid E. O'Brien #endif 821bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->rx_jumbo_tag, &ring->rx_jumbo_segs, ring->rx_jumbo_map); 822bfc788c2SDavid E. O'Brien } 823bfc788c2SDavid E. O'Brien if (ring->rx_jumbo_map != NULL) { 824bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->rx_jumbo_tag, ring->rx_jumbo_map, BUS_DMASYNC_POSTWRITE); 825bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_jumbo_tag, ring->rx_jumbo_map); 826bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->rx_jumbo_tag, ring->rx_jumbo_map); 827bfc788c2SDavid E. O'Brien } 828bfc788c2SDavid E. O'Brien } 829bfc788c2SDavid E. O'Brien 830bfc788c2SDavid E. O'Brien static struct nfe_jbuf * 831bfc788c2SDavid E. O'Brien nfe_jalloc(struct nfe_softc *sc) 832bfc788c2SDavid E. O'Brien { 833bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 834bfc788c2SDavid E. O'Brien 835bfc788c2SDavid E. O'Brien jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 836bfc788c2SDavid E. O'Brien if (jbuf == NULL) 837bfc788c2SDavid E. O'Brien return NULL; 838bfc788c2SDavid E. O'Brien SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 839bfc788c2SDavid E. O'Brien return jbuf; 840bfc788c2SDavid E. O'Brien } 841bfc788c2SDavid E. O'Brien 842bfc788c2SDavid E. O'Brien /* 843bfc788c2SDavid E. O'Brien * This is called automatically by the network stack when the mbuf is freed. 844bfc788c2SDavid E. O'Brien * Caution must be taken that the NIC might be reset by the time the mbuf is 845bfc788c2SDavid E. O'Brien * freed. 846bfc788c2SDavid E. O'Brien */ 847bfc788c2SDavid E. O'Brien static void 848bfc788c2SDavid E. O'Brien nfe_jfree(void *buf, void *arg) 849257c5577SDavid E. O'Brien { 850257c5577SDavid E. O'Brien struct nfe_softc *sc = arg; 851bfc788c2SDavid E. O'Brien struct nfe_jbuf *jbuf; 852bfc788c2SDavid E. O'Brien int i; 853257c5577SDavid E. O'Brien 854bfc788c2SDavid E. O'Brien /* find the jbuf from the base pointer */ 855bfc788c2SDavid E. O'Brien i = ((vm_offset_t)buf - (vm_offset_t)sc->rxq.jpool) / NFE_JBYTES; 856bfc788c2SDavid E. O'Brien if (i < 0 || i >= NFE_JPOOL_COUNT) { 857bfc788c2SDavid E. O'Brien printf("nfe%d: request to free a buffer (%p) not managed by us\n", sc->nfe_unit, buf); 858bfc788c2SDavid E. O'Brien return; 859bfc788c2SDavid E. O'Brien } 860bfc788c2SDavid E. O'Brien jbuf = &sc->rxq.jbuf[i]; 861bfc788c2SDavid E. O'Brien 862bfc788c2SDavid E. O'Brien /* ..and put it back in the free list */ 863bfc788c2SDavid E. O'Brien SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext); 864bfc788c2SDavid E. O'Brien } 865bfc788c2SDavid E. O'Brien 866bfc788c2SDavid E. O'Brien 867bfc788c2SDavid E. O'Brien static void 868bfc788c2SDavid E. O'Brien nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 869bfc788c2SDavid E. O'Brien { 870bfc788c2SDavid E. O'Brien int i; 871bfc788c2SDavid E. O'Brien 872bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 873bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 874bfc788c2SDavid E. O'Brien ring->desc64[i].length = htole16(ring->bufsz); 875bfc788c2SDavid E. O'Brien ring->desc64[i].flags = htole16(NFE_RX_READY); 876bfc788c2SDavid E. O'Brien } else { 877bfc788c2SDavid E. O'Brien ring->desc32[i].length = htole16(ring->bufsz); 878bfc788c2SDavid E. O'Brien ring->desc32[i].flags = htole16(NFE_RX_READY); 879bfc788c2SDavid E. O'Brien } 880bfc788c2SDavid E. O'Brien } 881bfc788c2SDavid E. O'Brien 882bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, BUS_DMASYNC_PREWRITE); 883bfc788c2SDavid E. O'Brien 884bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 885bfc788c2SDavid E. O'Brien } 886bfc788c2SDavid E. O'Brien 887bfc788c2SDavid E. O'Brien 888bfc788c2SDavid E. O'Brien static void 889bfc788c2SDavid E. O'Brien nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 890bfc788c2SDavid E. O'Brien { 891bfc788c2SDavid E. O'Brien struct nfe_rx_data *data; 892bfc788c2SDavid E. O'Brien void *desc; 893bfc788c2SDavid E. O'Brien int i, descsize; 894bfc788c2SDavid E. O'Brien 895bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 896bfc788c2SDavid E. O'Brien desc = ring->desc64; 897bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 898bfc788c2SDavid E. O'Brien } else { 899bfc788c2SDavid E. O'Brien desc = ring->desc32; 900bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 901bfc788c2SDavid E. O'Brien } 902bfc788c2SDavid E. O'Brien 903bfc788c2SDavid E. O'Brien if (desc != NULL) { 904bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, BUS_DMASYNC_POSTWRITE); 905bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 906bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 907bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->rx_desc_tag); 908bfc788c2SDavid E. O'Brien } 909bfc788c2SDavid E. O'Brien 910bfc788c2SDavid E. O'Brien 911bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 912bfc788c2SDavid E. O'Brien nfe_jpool_free(sc); 913bfc788c2SDavid E. O'Brien } else { 914bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 915bfc788c2SDavid E. O'Brien data = &ring->data[i]; 916bfc788c2SDavid E. O'Brien 917bfc788c2SDavid E. O'Brien if (data->rx_data_map != NULL) { 918bfc788c2SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, BUS_DMASYNC_POSTREAD); 919bfc788c2SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 920bfc788c2SDavid E. O'Brien bus_dmamap_destroy(data->rx_data_tag, data->rx_data_map); 921bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(data->rx_data_tag); 922bfc788c2SDavid E. O'Brien } 923bfc788c2SDavid E. O'Brien if (data->m != NULL) 924bfc788c2SDavid E. O'Brien m_freem(data->m); 925bfc788c2SDavid E. O'Brien } 926bfc788c2SDavid E. O'Brien } 927bfc788c2SDavid E. O'Brien } 928bfc788c2SDavid E. O'Brien 929bfc788c2SDavid E. O'Brien static int 930bfc788c2SDavid E. O'Brien nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 931bfc788c2SDavid E. O'Brien { 932bfc788c2SDavid E. O'Brien int i, error; 933bfc788c2SDavid E. O'Brien void **desc; 934bfc788c2SDavid E. O'Brien int descsize; 935bfc788c2SDavid E. O'Brien 936bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 937bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc64; 938bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 939bfc788c2SDavid E. O'Brien } else { 940bfc788c2SDavid E. O'Brien desc = (void **)&ring->desc32; 941bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 942bfc788c2SDavid E. O'Brien } 943bfc788c2SDavid E. O'Brien 944bfc788c2SDavid E. O'Brien ring->queued = 0; 945bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 946bfc788c2SDavid E. O'Brien 947bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 948bfc788c2SDavid E. O'Brien PAGE_SIZE, 0, /* alignment, boundary */ 949bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 950bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, /* highaddr */ 951bfc788c2SDavid E. O'Brien NULL, NULL, /* filter, filterarg */ 952bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 953bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 954bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, /* flags */ 955bfc788c2SDavid E. O'Brien NULL, NULL, /* lockfunc, lockarg */ 956bfc788c2SDavid E. O'Brien &ring->tx_desc_tag); 957bfc788c2SDavid E. O'Brien if (error != 0) { 958bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 959bfc788c2SDavid E. O'Brien goto fail; 960bfc788c2SDavid E. O'Brien } 961bfc788c2SDavid E. O'Brien 962bfc788c2SDavid E. O'Brien error = bus_dmamem_alloc(ring->tx_desc_tag, (void **)desc, BUS_DMA_NOWAIT, &ring->tx_desc_map); 963bfc788c2SDavid E. O'Brien if (error != 0) { 964bfc788c2SDavid E. O'Brien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 965bfc788c2SDavid E. O'Brien goto fail; 966bfc788c2SDavid E. O'Brien } 967bfc788c2SDavid E. O'Brien 968bfc788c2SDavid E. O'Brien error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, *desc, 969bfc788c2SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->tx_desc_segs, BUS_DMA_NOWAIT); 970bfc788c2SDavid E. O'Brien if (error != 0) { 971bfc788c2SDavid E. O'Brien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 972bfc788c2SDavid E. O'Brien goto fail; 973bfc788c2SDavid E. O'Brien } 974bfc788c2SDavid E. O'Brien 975bfc788c2SDavid E. O'Brien bzero(*desc, NFE_TX_RING_COUNT * descsize); 976bfc788c2SDavid E. O'Brien 977bfc788c2SDavid E. O'Brien ring->tx_desc_addr = ring->tx_desc_segs.ds_addr; 978bfc788c2SDavid E. O'Brien ring->physaddr = ring->tx_desc_addr; 979bfc788c2SDavid E. O'Brien 980bfc788c2SDavid E. O'Brien error = bus_dma_tag_create(sc->nfe_parent_tag, 981bfc788c2SDavid E. O'Brien ETHER_ALIGN, 0, 982bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR_32BIT, 983bfc788c2SDavid E. O'Brien BUS_SPACE_MAXADDR, 984bfc788c2SDavid E. O'Brien NULL, NULL, 985bfc788c2SDavid E. O'Brien NFE_JBYTES, NFE_MAX_SCATTER, 986bfc788c2SDavid E. O'Brien NFE_JBYTES, 987bfc788c2SDavid E. O'Brien BUS_DMA_ALLOCNOW, 988bfc788c2SDavid E. O'Brien NULL, NULL, 989bfc788c2SDavid E. O'Brien &ring->tx_data_tag); 990bfc788c2SDavid E. O'Brien if (error != 0) { 991bfc788c2SDavid E. O'Brien printf("nfe%d: could not create DMA tag\n", sc->nfe_unit); 992bfc788c2SDavid E. O'Brien goto fail; 993bfc788c2SDavid E. O'Brien } 994bfc788c2SDavid E. O'Brien 995bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 996bfc788c2SDavid E. O'Brien error = bus_dmamap_create(ring->tx_data_tag, 0, &ring->data[i].tx_data_map); 997bfc788c2SDavid E. O'Brien if (error != 0) { 998bfc788c2SDavid E. O'Brien printf("nfe%d: could not create DMA map\n", sc->nfe_unit); 999bfc788c2SDavid E. O'Brien goto fail; 1000bfc788c2SDavid E. O'Brien } 1001bfc788c2SDavid E. O'Brien } 1002bfc788c2SDavid E. O'Brien 1003bfc788c2SDavid E. O'Brien return 0; 1004bfc788c2SDavid E. O'Brien 1005bfc788c2SDavid E. O'Brien fail: nfe_free_tx_ring(sc, ring); 1006bfc788c2SDavid E. O'Brien return error; 1007bfc788c2SDavid E. O'Brien } 1008bfc788c2SDavid E. O'Brien 1009bfc788c2SDavid E. O'Brien 1010bfc788c2SDavid E. O'Brien static void 1011bfc788c2SDavid E. O'Brien nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1012bfc788c2SDavid E. O'Brien { 1013bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 1014bfc788c2SDavid E. O'Brien int i; 1015bfc788c2SDavid E. O'Brien 1016bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1017bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1018bfc788c2SDavid E. O'Brien ring->desc64[i].flags = 0; 1019bfc788c2SDavid E. O'Brien else 1020bfc788c2SDavid E. O'Brien ring->desc32[i].flags = 0; 1021bfc788c2SDavid E. O'Brien 1022bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1023bfc788c2SDavid E. O'Brien 1024bfc788c2SDavid E. O'Brien if (data->m != NULL) { 1025bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, BUS_DMASYNC_POSTWRITE); 1026bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 1027bfc788c2SDavid E. O'Brien m_freem(data->m); 1028bfc788c2SDavid E. O'Brien data->m = NULL; 1029bfc788c2SDavid E. O'Brien } 1030bfc788c2SDavid E. O'Brien } 1031bfc788c2SDavid E. O'Brien 1032bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, BUS_DMASYNC_PREWRITE); 1033bfc788c2SDavid E. O'Brien 1034bfc788c2SDavid E. O'Brien ring->queued = 0; 1035bfc788c2SDavid E. O'Brien ring->cur = ring->next = 0; 1036bfc788c2SDavid E. O'Brien } 1037bfc788c2SDavid E. O'Brien 1038bfc788c2SDavid E. O'Brien static void 1039bfc788c2SDavid E. O'Brien nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1040bfc788c2SDavid E. O'Brien { 1041bfc788c2SDavid E. O'Brien struct nfe_tx_data *data; 1042bfc788c2SDavid E. O'Brien void *desc; 1043bfc788c2SDavid E. O'Brien int i, descsize; 1044bfc788c2SDavid E. O'Brien 1045bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1046bfc788c2SDavid E. O'Brien desc = ring->desc64; 1047bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1048bfc788c2SDavid E. O'Brien } else { 1049bfc788c2SDavid E. O'Brien desc = ring->desc32; 1050bfc788c2SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1051bfc788c2SDavid E. O'Brien } 1052bfc788c2SDavid E. O'Brien 1053bfc788c2SDavid E. O'Brien if (desc != NULL) { 1054bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, BUS_DMASYNC_POSTWRITE); 1055bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1056bfc788c2SDavid E. O'Brien bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1057bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_desc_tag); 1058bfc788c2SDavid E. O'Brien } 1059bfc788c2SDavid E. O'Brien 1060bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1061bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1062bfc788c2SDavid E. O'Brien 1063bfc788c2SDavid E. O'Brien if (data->m != NULL) { 1064bfc788c2SDavid E. O'Brien bus_dmamap_sync(ring->tx_data_tag, data->active, BUS_DMASYNC_POSTWRITE); 1065bfc788c2SDavid E. O'Brien bus_dmamap_unload(ring->tx_data_tag, data->active); 1066bfc788c2SDavid E. O'Brien m_freem(data->m); 1067bfc788c2SDavid E. O'Brien } 1068bfc788c2SDavid E. O'Brien } 1069bfc788c2SDavid E. O'Brien 1070bfc788c2SDavid E. O'Brien /* ..and now actually destroy the DMA mappings */ 1071bfc788c2SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1072bfc788c2SDavid E. O'Brien data = &ring->data[i]; 1073bfc788c2SDavid E. O'Brien if (data->tx_data_map == NULL) 1074bfc788c2SDavid E. O'Brien continue; 1075bfc788c2SDavid E. O'Brien bus_dmamap_destroy(ring->tx_data_tag, data->tx_data_map); 1076bfc788c2SDavid E. O'Brien } 1077bfc788c2SDavid E. O'Brien 1078bfc788c2SDavid E. O'Brien bus_dma_tag_destroy(ring->tx_data_tag); 1079bfc788c2SDavid E. O'Brien } 1080bfc788c2SDavid E. O'Brien 1081bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1082bfc788c2SDavid E. O'Brien static poll_handler_t nfe_poll; 1083bfc788c2SDavid E. O'Brien 1084bfc788c2SDavid E. O'Brien static void 1085bfc788c2SDavid E. O'Brien nfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1086bfc788c2SDavid E. O'Brien { 1087bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1088bfc788c2SDavid E. O'Brien 1089bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1090bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1091bfc788c2SDavid E. O'Brien nfe_poll_locked(ifp, cmd, count); 1092bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1093bfc788c2SDavid E. O'Brien } 1094bfc788c2SDavid E. O'Brien 1095bfc788c2SDavid E. O'Brien 1096bfc788c2SDavid E. O'Brien static void 1097bfc788c2SDavid E. O'Brien nfe_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1098bfc788c2SDavid E. O'Brien { 1099bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1100bfc788c2SDavid E. O'Brien u_int32_t r; 1101bfc788c2SDavid E. O'Brien 1102bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1103bfc788c2SDavid E. O'Brien 1104bfc788c2SDavid E. O'Brien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1105bfc788c2SDavid E. O'Brien return; 1106bfc788c2SDavid E. O'Brien } 1107bfc788c2SDavid E. O'Brien 1108bfc788c2SDavid E. O'Brien sc->rxcycles = count; 1109bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1110bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1111bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1112bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1113bfc788c2SDavid E. O'Brien 1114bfc788c2SDavid E. O'Brien if (cmd == POLL_AND_CHECK_STATUS) { 1115bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1116bfc788c2SDavid E. O'Brien return; 1117bfc788c2SDavid E. O'Brien } 1118257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1119257c5577SDavid E. O'Brien 1120257c5577SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1121257c5577SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1122257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1123bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1124257c5577SDavid E. O'Brien } 1125257c5577SDavid E. O'Brien } 1126257c5577SDavid E. O'Brien } 1127bfc788c2SDavid E. O'Brien #endif /* DEVICE_POLLING */ 1128257c5577SDavid E. O'Brien 1129bfc788c2SDavid E. O'Brien 1130bfc788c2SDavid E. O'Brien static int 1131257c5577SDavid E. O'Brien nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1132257c5577SDavid E. O'Brien { 1133bfc788c2SDavid E. O'Brien int error = 0; 1134257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1135257c5577SDavid E. O'Brien struct ifreq *ifr = (struct ifreq *) data; 1136bfc788c2SDavid E. O'Brien struct mii_data *mii; 1137257c5577SDavid E. O'Brien 1138257c5577SDavid E. O'Brien switch (cmd) { 1139257c5577SDavid E. O'Brien case SIOCSIFMTU: 1140257c5577SDavid E. O'Brien if (ifr->ifr_mtu < ETHERMIN || 1141bfc788c2SDavid E. O'Brien ((sc->nfe_flags & NFE_USE_JUMBO) && 1142257c5577SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU_JUMBO) || 1143bfc788c2SDavid E. O'Brien (!(sc->nfe_flags & NFE_USE_JUMBO) && 1144257c5577SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU)) 1145257c5577SDavid E. O'Brien error = EINVAL; 1146bfc788c2SDavid E. O'Brien else if (ifp->if_mtu != ifr->ifr_mtu) { 1147257c5577SDavid E. O'Brien ifp->if_mtu = ifr->ifr_mtu; 1148bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1149bfc788c2SDavid E. O'Brien nfe_init(sc); 1150bfc788c2SDavid E. O'Brien } 1151257c5577SDavid E. O'Brien break; 1152257c5577SDavid E. O'Brien case SIOCSIFFLAGS: 1153bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1154257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 1155257c5577SDavid E. O'Brien /* 1156257c5577SDavid E. O'Brien * If only the PROMISC or ALLMULTI flag changes, then 1157257c5577SDavid E. O'Brien * don't do a full re-init of the chip, just update 1158257c5577SDavid E. O'Brien * the Rx filter. 1159257c5577SDavid E. O'Brien */ 1160bfc788c2SDavid E. O'Brien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1161bfc788c2SDavid E. O'Brien ((ifp->if_flags ^ sc->nfe_if_flags) & 1162bfc788c2SDavid E. O'Brien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1163257c5577SDavid E. O'Brien nfe_setmulti(sc); 1164bfc788c2SDavid E. O'Brien else 1165bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1166257c5577SDavid E. O'Brien } else { 1167bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1168257c5577SDavid E. O'Brien nfe_stop(ifp, 1); 1169257c5577SDavid E. O'Brien } 1170bfc788c2SDavid E. O'Brien sc->nfe_if_flags = ifp->if_flags; 1171bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1172bfc788c2SDavid E. O'Brien error = 0; 1173257c5577SDavid E. O'Brien break; 1174257c5577SDavid E. O'Brien case SIOCADDMULTI: 1175257c5577SDavid E. O'Brien case SIOCDELMULTI: 1176bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1177bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1178257c5577SDavid E. O'Brien nfe_setmulti(sc); 1179bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1180257c5577SDavid E. O'Brien error = 0; 1181257c5577SDavid E. O'Brien } 1182257c5577SDavid E. O'Brien break; 1183257c5577SDavid E. O'Brien case SIOCSIFMEDIA: 1184257c5577SDavid E. O'Brien case SIOCGIFMEDIA: 1185bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1186bfc788c2SDavid E. O'Brien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1187257c5577SDavid E. O'Brien break; 1188bfc788c2SDavid E. O'Brien case SIOCSIFCAP: 1189bfc788c2SDavid E. O'Brien { 1190bfc788c2SDavid E. O'Brien int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1191bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1192bfc788c2SDavid E. O'Brien if (mask & IFCAP_POLLING) { 1193bfc788c2SDavid E. O'Brien if (ifr->ifr_reqcap & IFCAP_POLLING) { 1194bfc788c2SDavid E. O'Brien error = ether_poll_register(nfe_poll, ifp); 1195bfc788c2SDavid E. O'Brien if (error) 1196bfc788c2SDavid E. O'Brien return(error); 1197bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1198bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1199bfc788c2SDavid E. O'Brien ifp->if_capenable |= IFCAP_POLLING; 1200bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1201bfc788c2SDavid E. O'Brien } else { 1202bfc788c2SDavid E. O'Brien error = ether_poll_deregister(ifp); 1203bfc788c2SDavid E. O'Brien /* Enable interrupt even in error case */ 1204bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1205bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1206bfc788c2SDavid E. O'Brien ifp->if_capenable &= ~IFCAP_POLLING; 1207bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1208257c5577SDavid E. O'Brien } 1209bfc788c2SDavid E. O'Brien } 1210bfc788c2SDavid E. O'Brien #endif 1211bfc788c2SDavid E. O'Brien if (mask & IFCAP_HWCSUM) { 1212bfc788c2SDavid E. O'Brien ifp->if_capenable ^= IFCAP_HWCSUM; 1213bfc788c2SDavid E. O'Brien if (IFCAP_HWCSUM & ifp->if_capenable && 1214bfc788c2SDavid E. O'Brien IFCAP_HWCSUM & ifp->if_capabilities) 1215bfc788c2SDavid E. O'Brien ifp->if_hwassist = NFE_CSUM_FEATURES; 1216bfc788c2SDavid E. O'Brien else 1217bfc788c2SDavid E. O'Brien ifp->if_hwassist = 0; 1218bfc788c2SDavid E. O'Brien } 1219bfc788c2SDavid E. O'Brien } 1220bfc788c2SDavid E. O'Brien break; 1221257c5577SDavid E. O'Brien 1222bfc788c2SDavid E. O'Brien default: 1223bfc788c2SDavid E. O'Brien error = ether_ioctl(ifp, cmd, data); 1224bfc788c2SDavid E. O'Brien break; 1225bfc788c2SDavid E. O'Brien } 1226257c5577SDavid E. O'Brien 1227257c5577SDavid E. O'Brien return error; 1228257c5577SDavid E. O'Brien } 1229257c5577SDavid E. O'Brien 1230bfc788c2SDavid E. O'Brien 1231bfc788c2SDavid E. O'Brien static void nfe_intr(void *arg) 1232bfc788c2SDavid E. O'Brien { 1233bfc788c2SDavid E. O'Brien struct nfe_softc *sc = arg; 1234bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1235bfc788c2SDavid E. O'Brien u_int32_t r; 1236bfc788c2SDavid E. O'Brien 1237bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1238bfc788c2SDavid E. O'Brien 1239bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1240bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1241bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1242bfc788c2SDavid E. O'Brien return; 1243bfc788c2SDavid E. O'Brien } 1244bfc788c2SDavid E. O'Brien #endif 1245bfc788c2SDavid E. O'Brien 1246bfc788c2SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1247bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1248bfc788c2SDavid E. O'Brien return; /* not for us */ 1249bfc788c2SDavid E. O'Brien } 1250bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1251bfc788c2SDavid E. O'Brien 1252bfc788c2SDavid E. O'Brien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 1253bfc788c2SDavid E. O'Brien 1254bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1255bfc788c2SDavid E. O'Brien 1256bfc788c2SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 1257bfc788c2SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 1258bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1259bfc788c2SDavid E. O'Brien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1260bfc788c2SDavid E. O'Brien } 1261bfc788c2SDavid E. O'Brien 1262bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1263bfc788c2SDavid E. O'Brien /* check Rx ring */ 1264bfc788c2SDavid E. O'Brien nfe_rxeof(sc); 1265bfc788c2SDavid E. O'Brien /* check Tx ring */ 1266bfc788c2SDavid E. O'Brien nfe_txeof(sc); 1267bfc788c2SDavid E. O'Brien } 1268bfc788c2SDavid E. O'Brien 1269bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1270bfc788c2SDavid E. O'Brien 1271bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1272bfc788c2SDavid E. O'Brien !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1273bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1274bfc788c2SDavid E. O'Brien 1275bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1276bfc788c2SDavid E. O'Brien 1277bfc788c2SDavid E. O'Brien return; 1278bfc788c2SDavid E. O'Brien } 1279bfc788c2SDavid E. O'Brien 1280bfc788c2SDavid E. O'Brien static void 1281257c5577SDavid E. O'Brien nfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1282257c5577SDavid E. O'Brien { 1283bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1284257c5577SDavid E. O'Brien } 1285257c5577SDavid E. O'Brien 1286bfc788c2SDavid E. O'Brien static void 1287257c5577SDavid E. O'Brien nfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1288257c5577SDavid E. O'Brien { 1289bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1290257c5577SDavid E. O'Brien } 1291257c5577SDavid E. O'Brien 1292bfc788c2SDavid E. O'Brien static void 1293257c5577SDavid E. O'Brien nfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 1294257c5577SDavid E. O'Brien { 1295bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1296257c5577SDavid E. O'Brien } 1297257c5577SDavid E. O'Brien 1298bfc788c2SDavid E. O'Brien static void 1299257c5577SDavid E. O'Brien nfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 1300257c5577SDavid E. O'Brien { 1301bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1302257c5577SDavid E. O'Brien } 1303257c5577SDavid E. O'Brien 1304bfc788c2SDavid E. O'Brien static void 1305257c5577SDavid E. O'Brien nfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1306257c5577SDavid E. O'Brien { 1307bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1308257c5577SDavid E. O'Brien } 1309257c5577SDavid E. O'Brien 1310bfc788c2SDavid E. O'Brien static void 1311257c5577SDavid E. O'Brien nfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1312257c5577SDavid E. O'Brien { 1313bfc788c2SDavid E. O'Brien 1314bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1315257c5577SDavid E. O'Brien } 1316257c5577SDavid E. O'Brien 1317bfc788c2SDavid E. O'Brien static void nfe_rxeof(struct nfe_softc *sc) 1318257c5577SDavid E. O'Brien { 1319bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1320bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1321bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1322257c5577SDavid E. O'Brien struct nfe_rx_data *data; 1323257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 1324257c5577SDavid E. O'Brien struct mbuf *m, *mnew; 1325257c5577SDavid E. O'Brien bus_addr_t physaddr; 1326bfc788c2SDavid E. O'Brien u_int16_t flags; 1327257c5577SDavid E. O'Brien int error, len; 1328bfc788c2SDavid E. O'Brien #if NVLAN > 1 1329bfc788c2SDavid E. O'Brien u_int16_t vlan_tag = 0; 1330bfc788c2SDavid E. O'Brien int have_tag = 0; 1331bfc788c2SDavid E. O'Brien #endif 1332bfc788c2SDavid E. O'Brien 1333bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1334257c5577SDavid E. O'Brien 1335257c5577SDavid E. O'Brien for (;;) { 1336bfc788c2SDavid E. O'Brien 1337bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1338bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) { 1339bfc788c2SDavid E. O'Brien if (sc->rxcycles <= 0) 1340bfc788c2SDavid E. O'Brien break; 1341bfc788c2SDavid E. O'Brien sc->rxcycles--; 1342bfc788c2SDavid E. O'Brien } 1343bfc788c2SDavid E. O'Brien #endif 1344bfc788c2SDavid E. O'Brien 1345257c5577SDavid E. O'Brien data = &sc->rxq.data[sc->rxq.cur]; 1346257c5577SDavid E. O'Brien 1347bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1348257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 1349257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1350257c5577SDavid E. O'Brien 1351257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1352257c5577SDavid E. O'Brien len = letoh16(desc64->length) & 0x3fff; 1353bfc788c2SDavid E. O'Brien 1354bfc788c2SDavid E. O'Brien #if NVLAN > 1 1355bfc788c2SDavid E. O'Brien if (flags & NFE_TX_VLAN_TAG) { 1356bfc788c2SDavid E. O'Brien have_tag = 1; 1357bfc788c2SDavid E. O'Brien vlan_tag = desc64->vtag; 1358bfc788c2SDavid E. O'Brien } 1359bfc788c2SDavid E. O'Brien #endif 1360bfc788c2SDavid E. O'Brien 1361257c5577SDavid E. O'Brien } else { 1362257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 1363257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1364257c5577SDavid E. O'Brien 1365257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1366257c5577SDavid E. O'Brien len = letoh16(desc32->length) & 0x3fff; 1367257c5577SDavid E. O'Brien } 1368257c5577SDavid E. O'Brien 1369257c5577SDavid E. O'Brien if (flags & NFE_RX_READY) 1370257c5577SDavid E. O'Brien break; 1371257c5577SDavid E. O'Brien 1372bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1373257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V1)) 1374257c5577SDavid E. O'Brien goto skip; 1375257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 1376257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1377257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1378257c5577SDavid E. O'Brien } 1379257c5577SDavid E. O'Brien } else { 1380257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V2)) 1381257c5577SDavid E. O'Brien goto skip; 1382257c5577SDavid E. O'Brien 1383257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 1384257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 1385257c5577SDavid E. O'Brien len--; /* fix buffer length */ 1386257c5577SDavid E. O'Brien } 1387257c5577SDavid E. O'Brien } 1388257c5577SDavid E. O'Brien 1389257c5577SDavid E. O'Brien if (flags & NFE_RX_ERROR) { 1390257c5577SDavid E. O'Brien ifp->if_ierrors++; 1391257c5577SDavid E. O'Brien goto skip; 1392257c5577SDavid E. O'Brien } 1393257c5577SDavid E. O'Brien 1394257c5577SDavid E. O'Brien /* 1395257c5577SDavid E. O'Brien * Try to allocate a new mbuf for this ring element and load 1396257c5577SDavid E. O'Brien * it before processing the current mbuf. If the ring element 1397257c5577SDavid E. O'Brien * cannot be loaded, drop the received packet and reuse the 1398257c5577SDavid E. O'Brien * old mbuf. In the unlikely case that the old mbuf can't be 1399257c5577SDavid E. O'Brien * reloaded either, explicitly panic. 1400257c5577SDavid E. O'Brien */ 1401257c5577SDavid E. O'Brien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 1402257c5577SDavid E. O'Brien if (mnew == NULL) { 1403257c5577SDavid E. O'Brien ifp->if_ierrors++; 1404257c5577SDavid E. O'Brien goto skip; 1405257c5577SDavid E. O'Brien } 1406257c5577SDavid E. O'Brien 1407bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_USE_JUMBO) { 1408257c5577SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 1409257c5577SDavid E. O'Brien m_freem(mnew); 1410257c5577SDavid E. O'Brien ifp->if_ierrors++; 1411257c5577SDavid E. O'Brien goto skip; 1412257c5577SDavid E. O'Brien } 1413bfc788c2SDavid E. O'Brien mnew->m_data = (void *)jbuf->buf; 1414bfc788c2SDavid E. O'Brien mnew->m_len = mnew->m_pkthdr.len = NFE_JBYTES; 1415bfc788c2SDavid E. O'Brien MEXTADD(mnew, jbuf->buf, NFE_JBYTES, nfe_jfree, 1416bfc788c2SDavid E. O'Brien (struct nfe_softc *)sc, 0 , EXT_NET_DRV); 1417257c5577SDavid E. O'Brien 1418bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->rxq.rx_jumbo_tag, 1419bfc788c2SDavid E. O'Brien sc->rxq.rx_jumbo_map, BUS_DMASYNC_POSTREAD); 1420257c5577SDavid E. O'Brien physaddr = jbuf->physaddr; 1421257c5577SDavid E. O'Brien } else { 1422257c5577SDavid E. O'Brien MCLGET(mnew, M_DONTWAIT); 1423257c5577SDavid E. O'Brien if (!(mnew->m_flags & M_EXT)) { 1424257c5577SDavid E. O'Brien m_freem(mnew); 1425257c5577SDavid E. O'Brien ifp->if_ierrors++; 1426257c5577SDavid E. O'Brien goto skip; 1427257c5577SDavid E. O'Brien } 1428257c5577SDavid E. O'Brien 1429bfc788c2SDavid E. O'Brien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, 1430bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTREAD); 1431bfc788c2SDavid E. O'Brien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 1432bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1433bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(mnew, void *), MCLBYTES, 1434bfc788c2SDavid E. O'Brien nfe_dma_map_segs, &data->rx_data_segs, 1435bfc788c2SDavid E. O'Brien BUS_DMA_NOWAIT); 1436257c5577SDavid E. O'Brien if (error != 0) { 1437257c5577SDavid E. O'Brien m_freem(mnew); 1438257c5577SDavid E. O'Brien 1439257c5577SDavid E. O'Brien /* try to reload the old mbuf */ 1440bfc788c2SDavid E. O'Brien error = bus_dmamap_load(data->rx_data_tag, 1441bfc788c2SDavid E. O'Brien data->rx_data_map, mtod(data->m, void *), 1442bfc788c2SDavid E. O'Brien MCLBYTES, nfe_dma_map_segs, 1443bfc788c2SDavid E. O'Brien &data->rx_data_segs, BUS_DMA_NOWAIT); 1444257c5577SDavid E. O'Brien if (error != 0) { 1445257c5577SDavid E. O'Brien /* very unlikely that it will fail.. */ 1446bfc788c2SDavid E. O'Brien panic("nfe%d: could not load old rx mbuf", 1447bfc788c2SDavid E. O'Brien sc->nfe_unit); 1448257c5577SDavid E. O'Brien } 1449257c5577SDavid E. O'Brien ifp->if_ierrors++; 1450257c5577SDavid E. O'Brien goto skip; 1451257c5577SDavid E. O'Brien } 1452bfc788c2SDavid E. O'Brien data->rx_data_addr = data->rx_data_segs.ds_addr; 1453bfc788c2SDavid E. O'Brien physaddr = data->rx_data_addr; 1454257c5577SDavid E. O'Brien } 1455257c5577SDavid E. O'Brien 1456257c5577SDavid E. O'Brien /* 1457257c5577SDavid E. O'Brien * New mbuf successfully loaded, update Rx ring and continue 1458257c5577SDavid E. O'Brien * processing. 1459257c5577SDavid E. O'Brien */ 1460257c5577SDavid E. O'Brien m = data->m; 1461257c5577SDavid E. O'Brien data->m = mnew; 1462257c5577SDavid E. O'Brien 1463257c5577SDavid E. O'Brien /* finalize mbuf */ 1464257c5577SDavid E. O'Brien m->m_pkthdr.len = m->m_len = len; 1465257c5577SDavid E. O'Brien m->m_pkthdr.rcvif = ifp; 1466257c5577SDavid E. O'Brien 1467bfc788c2SDavid E. O'Brien 1468bfc788c2SDavid E. O'Brien #if defined(NFE_CSUM) 1469bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) { 1470bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1471bfc788c2SDavid E. O'Brien if (flags & NFE_RX_IP_CSUMOK_V2) { 1472bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1473257c5577SDavid E. O'Brien } 1474bfc788c2SDavid E. O'Brien if (flags & NFE_RX_UDP_CSUMOK_V2 || 1475bfc788c2SDavid E. O'Brien flags & NFE_RX_TCP_CSUMOK_V2) { 1476bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_flags |= 1477bfc788c2SDavid E. O'Brien CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 1478bfc788c2SDavid E. O'Brien m->m_pkthdr.csum_data = 0xffff; 1479bfc788c2SDavid E. O'Brien } 1480bfc788c2SDavid E. O'Brien } 1481257c5577SDavid E. O'Brien #endif 1482257c5577SDavid E. O'Brien 1483bfc788c2SDavid E. O'Brien #if NVLAN > 1 1484bfc788c2SDavid E. O'Brien if (have_tag) { 1485bfc788c2SDavid E. O'Brien VLAN_INPUT_TAG_NEW(ifp, m, vlan_tag); 1486bfc788c2SDavid E. O'Brien if (m == NULL) 1487bfc788c2SDavid E. O'Brien continue; 1488bfc788c2SDavid E. O'Brien } 1489257c5577SDavid E. O'Brien #endif 1490bfc788c2SDavid E. O'Brien 1491257c5577SDavid E. O'Brien ifp->if_ipackets++; 1492bfc788c2SDavid E. O'Brien 1493bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1494bfc788c2SDavid E. O'Brien (*ifp->if_input)(ifp, m); 1495bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1496257c5577SDavid E. O'Brien 1497257c5577SDavid E. O'Brien /* update mapping address in h/w descriptor */ 1498bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1499257c5577SDavid E. O'Brien #if defined(__LP64__) 1500257c5577SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 1501257c5577SDavid E. O'Brien #endif 1502257c5577SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1503257c5577SDavid E. O'Brien } else { 1504257c5577SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 1505257c5577SDavid E. O'Brien } 1506257c5577SDavid E. O'Brien 1507bfc788c2SDavid E. O'Brien skip: if (sc->nfe_flags & NFE_40BIT_ADDR) { 1508257c5577SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 1509257c5577SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 1510257c5577SDavid E. O'Brien 1511257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 1512257c5577SDavid E. O'Brien } else { 1513257c5577SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 1514257c5577SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 1515257c5577SDavid E. O'Brien 1516257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 1517257c5577SDavid E. O'Brien } 1518257c5577SDavid E. O'Brien 1519257c5577SDavid E. O'Brien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 1520257c5577SDavid E. O'Brien } 1521257c5577SDavid E. O'Brien } 1522257c5577SDavid E. O'Brien 1523bfc788c2SDavid E. O'Brien static void nfe_txeof(struct nfe_softc *sc) 1524257c5577SDavid E. O'Brien { 1525bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1526257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 1527257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 1528257c5577SDavid E. O'Brien struct nfe_tx_data *data = NULL; 1529bfc788c2SDavid E. O'Brien u_int16_t flags; 1530bfc788c2SDavid E. O'Brien 1531bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1532257c5577SDavid E. O'Brien 1533257c5577SDavid E. O'Brien while (sc->txq.next != sc->txq.cur) { 1534bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1535257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.next]; 1536257c5577SDavid E. O'Brien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1537257c5577SDavid E. O'Brien 1538257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 1539257c5577SDavid E. O'Brien } else { 1540257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.next]; 1541257c5577SDavid E. O'Brien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1542257c5577SDavid E. O'Brien 1543257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 1544257c5577SDavid E. O'Brien } 1545257c5577SDavid E. O'Brien 1546257c5577SDavid E. O'Brien if (flags & NFE_TX_VALID) 1547257c5577SDavid E. O'Brien break; 1548257c5577SDavid E. O'Brien 1549257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.next]; 1550257c5577SDavid E. O'Brien 1551bfc788c2SDavid E. O'Brien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1552257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 1553257c5577SDavid E. O'Brien goto skip; 1554257c5577SDavid E. O'Brien 1555257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V1) != 0) { 1556bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1557bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V1_TXERR); 1558bfc788c2SDavid E. O'Brien 1559257c5577SDavid E. O'Brien ifp->if_oerrors++; 1560257c5577SDavid E. O'Brien } else 1561257c5577SDavid E. O'Brien ifp->if_opackets++; 1562257c5577SDavid E. O'Brien } else { 1563257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 1564257c5577SDavid E. O'Brien goto skip; 1565257c5577SDavid E. O'Brien 1566257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V2) != 0) { 1567bfc788c2SDavid E. O'Brien printf("nfe%d: tx v1 error 0x%4b\n", 1568bfc788c2SDavid E. O'Brien sc->nfe_unit, flags, NFE_V2_TXERR); 1569bfc788c2SDavid E. O'Brien 1570257c5577SDavid E. O'Brien ifp->if_oerrors++; 1571257c5577SDavid E. O'Brien } else 1572257c5577SDavid E. O'Brien ifp->if_opackets++; 1573257c5577SDavid E. O'Brien } 1574257c5577SDavid E. O'Brien 1575257c5577SDavid E. O'Brien if (data->m == NULL) { /* should not get there */ 1576bfc788c2SDavid E. O'Brien printf("nfe%d: last fragment bit w/o associated mbuf!\n", 1577bfc788c2SDavid E. O'Brien sc->nfe_unit); 1578257c5577SDavid E. O'Brien goto skip; 1579257c5577SDavid E. O'Brien } 1580257c5577SDavid E. O'Brien 1581257c5577SDavid E. O'Brien /* last fragment of the mbuf chain transmitted */ 1582bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, data->active, 1583bfc788c2SDavid E. O'Brien BUS_DMASYNC_POSTWRITE); 1584bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, data->active); 1585257c5577SDavid E. O'Brien m_freem(data->m); 1586257c5577SDavid E. O'Brien data->m = NULL; 1587257c5577SDavid E. O'Brien 1588257c5577SDavid E. O'Brien ifp->if_timer = 0; 1589257c5577SDavid E. O'Brien 1590257c5577SDavid E. O'Brien skip: sc->txq.queued--; 1591257c5577SDavid E. O'Brien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 1592257c5577SDavid E. O'Brien } 1593257c5577SDavid E. O'Brien 1594257c5577SDavid E. O'Brien if (data != NULL) { /* at least one slot freed */ 1595bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1596bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1597257c5577SDavid E. O'Brien } 1598257c5577SDavid E. O'Brien } 1599257c5577SDavid E. O'Brien 1600bfc788c2SDavid E. O'Brien static int nfe_encap(struct nfe_softc *sc, struct mbuf *m0) 1601257c5577SDavid E. O'Brien { 1602bfc788c2SDavid E. O'Brien struct nfe_desc32 *desc32=NULL; 1603bfc788c2SDavid E. O'Brien struct nfe_desc64 *desc64=NULL; 1604bfc788c2SDavid E. O'Brien struct nfe_tx_data *data=NULL; 1605257c5577SDavid E. O'Brien bus_dmamap_t map; 1606bfc788c2SDavid E. O'Brien u_int16_t flags = NFE_TX_VALID; 1607257c5577SDavid E. O'Brien #if NVLAN > 0 1608bfc788c2SDavid E. O'Brien struct m_tag *vtag; 1609257c5577SDavid E. O'Brien #endif 1610bfc788c2SDavid E. O'Brien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 1611bfc788c2SDavid E. O'Brien int nsegs; 1612257c5577SDavid E. O'Brien int error, i; 1613257c5577SDavid E. O'Brien 1614bfc788c2SDavid E. O'Brien map = sc->txq.data[sc->txq.cur].tx_data_map; 1615257c5577SDavid E. O'Brien 1616bfc788c2SDavid E. O'Brien error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, m0, segs, 1617bfc788c2SDavid E. O'Brien &nsegs, BUS_DMA_NOWAIT); 1618bfc788c2SDavid E. O'Brien 1619257c5577SDavid E. O'Brien if (error != 0) { 1620bfc788c2SDavid E. O'Brien printf("nfe%d: could not map mbuf (error %d)\n", sc->nfe_unit, 1621bfc788c2SDavid E. O'Brien error); 1622257c5577SDavid E. O'Brien return error; 1623257c5577SDavid E. O'Brien } 1624257c5577SDavid E. O'Brien 1625bfc788c2SDavid E. O'Brien if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 1) { 1626bfc788c2SDavid E. O'Brien bus_dmamap_unload(sc->txq.tx_data_tag, map); 1627257c5577SDavid E. O'Brien return ENOBUFS; 1628257c5577SDavid E. O'Brien } 1629257c5577SDavid E. O'Brien 1630bfc788c2SDavid E. O'Brien 1631257c5577SDavid E. O'Brien #if NVLAN > 0 1632257c5577SDavid E. O'Brien /* setup h/w VLAN tagging */ 1633bfc788c2SDavid E. O'Brien vtag = VLAN_OUTPUT_TAG(sc->nfe_ifp, m0); 1634257c5577SDavid E. O'Brien #endif 1635bfc788c2SDavid E. O'Brien 1636257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1637bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_IP) 1638257c5577SDavid E. O'Brien flags |= NFE_TX_IP_CSUM; 1639bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_TCP) 1640bfc788c2SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1641bfc788c2SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & CSUM_UDP) 1642257c5577SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 1643257c5577SDavid E. O'Brien #endif 1644257c5577SDavid E. O'Brien 1645bfc788c2SDavid E. O'Brien for (i = 0; i < nsegs; i++) { 1646257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.cur]; 1647257c5577SDavid E. O'Brien 1648bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1649257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.cur]; 1650257c5577SDavid E. O'Brien #if defined(__LP64__) 1651bfc788c2SDavid E. O'Brien desc64->physaddr[0] = htole32(segs[i].ds_addr >> 32); 1652257c5577SDavid E. O'Brien #endif 1653bfc788c2SDavid E. O'Brien desc64->physaddr[1] = htole32(segs[i].ds_addr & 1654bfc788c2SDavid E. O'Brien 0xffffffff); 1655bfc788c2SDavid E. O'Brien desc64->length = htole16(segs[i].ds_len - 1); 1656257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1657257c5577SDavid E. O'Brien #if NVLAN > 0 1658bfc788c2SDavid E. O'Brien desc64->vtag = htole32(NFE_TX_VTAG | 1659bfc788c2SDavid E. O'Brien VLAN_TAG_VALUE(vtag)); 1660257c5577SDavid E. O'Brien #endif 1661257c5577SDavid E. O'Brien } else { 1662257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.cur]; 1663257c5577SDavid E. O'Brien 1664bfc788c2SDavid E. O'Brien desc32->physaddr = htole32(segs[i].ds_addr); 1665bfc788c2SDavid E. O'Brien desc32->length = htole16(segs[i].ds_len - 1); 1666257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1667257c5577SDavid E. O'Brien } 1668257c5577SDavid E. O'Brien 1669257c5577SDavid E. O'Brien /* csum flags and vtag belong to the first fragment only */ 1670bfc788c2SDavid E. O'Brien if (nsegs > 1) { 1671257c5577SDavid E. O'Brien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 1672257c5577SDavid E. O'Brien #if NVLAN > 0 1673257c5577SDavid E. O'Brien vtag = 0; 1674257c5577SDavid E. O'Brien #endif 1675257c5577SDavid E. O'Brien } 1676257c5577SDavid E. O'Brien 1677257c5577SDavid E. O'Brien sc->txq.queued++; 1678257c5577SDavid E. O'Brien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 1679257c5577SDavid E. O'Brien } 1680257c5577SDavid E. O'Brien 1681257c5577SDavid E. O'Brien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 1682bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1683257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1684257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 1685257c5577SDavid E. O'Brien } else { 1686bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_JUMBO_SUP) 1687257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 1688257c5577SDavid E. O'Brien else 1689257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V1; 1690257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 1691257c5577SDavid E. O'Brien } 1692257c5577SDavid E. O'Brien 1693257c5577SDavid E. O'Brien data->m = m0; 1694257c5577SDavid E. O'Brien data->active = map; 1695bfc788c2SDavid E. O'Brien data->nsegs = nsegs; 1696257c5577SDavid E. O'Brien 1697bfc788c2SDavid E. O'Brien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 1698257c5577SDavid E. O'Brien 1699257c5577SDavid E. O'Brien return 0; 1700257c5577SDavid E. O'Brien } 1701257c5577SDavid E. O'Brien 1702bfc788c2SDavid E. O'Brien 1703bfc788c2SDavid E. O'Brien static void nfe_setmulti(struct nfe_softc *sc) 1704bfc788c2SDavid E. O'Brien { 1705bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1706bfc788c2SDavid E. O'Brien struct ifmultiaddr *ifma; 1707bfc788c2SDavid E. O'Brien u_int8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 1708bfc788c2SDavid E. O'Brien u_int32_t filter = NFE_RXFILTER_MAGIC; 1709bfc788c2SDavid E. O'Brien u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = 1710bfc788c2SDavid E. O'Brien { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1711bfc788c2SDavid E. O'Brien int i; 1712bfc788c2SDavid E. O'Brien 1713bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1714bfc788c2SDavid E. O'Brien 1715bfc788c2SDavid E. O'Brien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1716bfc788c2SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 1717bfc788c2SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 1718bfc788c2SDavid E. O'Brien goto done; 1719bfc788c2SDavid E. O'Brien } 1720bfc788c2SDavid E. O'Brien 1721bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1722bfc788c2SDavid E. O'Brien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1723bfc788c2SDavid E. O'Brien 1724bfc788c2SDavid E. O'Brien IF_ADDR_LOCK(ifp); 1725bfc788c2SDavid E. O'Brien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1726bfc788c2SDavid E. O'Brien u_char *addrp; 1727bfc788c2SDavid E. O'Brien 1728bfc788c2SDavid E. O'Brien if (ifma->ifma_addr->sa_family != AF_LINK) 1729bfc788c2SDavid E. O'Brien continue; 1730bfc788c2SDavid E. O'Brien 1731bfc788c2SDavid E. O'Brien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 1732bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1733bfc788c2SDavid E. O'Brien u_int8_t mcaddr = addrp[i]; 1734bfc788c2SDavid E. O'Brien addr[i] &= mcaddr; 1735bfc788c2SDavid E. O'Brien mask[i] &= ~mcaddr; 1736bfc788c2SDavid E. O'Brien } 1737bfc788c2SDavid E. O'Brien } 1738bfc788c2SDavid E. O'Brien IF_ADDR_UNLOCK(ifp); 1739bfc788c2SDavid E. O'Brien 1740bfc788c2SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1741bfc788c2SDavid E. O'Brien mask[i] |= addr[i]; 1742bfc788c2SDavid E. O'Brien } 1743bfc788c2SDavid E. O'Brien 1744bfc788c2SDavid E. O'Brien done: 1745bfc788c2SDavid E. O'Brien addr[0] |= 0x01; /* make sure multicast bit is set */ 1746bfc788c2SDavid E. O'Brien 1747bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1748bfc788c2SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1749bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1750bfc788c2SDavid E. O'Brien addr[5] << 8 | addr[4]); 1751bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1752bfc788c2SDavid E. O'Brien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1753bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1754bfc788c2SDavid E. O'Brien mask[5] << 8 | mask[4]); 1755bfc788c2SDavid E. O'Brien 1756bfc788c2SDavid E. O'Brien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1757bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_RXFILTER, filter); 1758bfc788c2SDavid E. O'Brien } 1759bfc788c2SDavid E. O'Brien 1760bfc788c2SDavid E. O'Brien static void nfe_start(struct ifnet *ifp) 1761bfc788c2SDavid E. O'Brien { 1762bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 1763bfc788c2SDavid E. O'Brien 1764bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 1765bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1766bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 1767bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1768bfc788c2SDavid E. O'Brien } 1769bfc788c2SDavid E. O'Brien 1770bfc788c2SDavid E. O'Brien static void nfe_start_locked(struct ifnet *ifp) 1771257c5577SDavid E. O'Brien { 1772257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1773257c5577SDavid E. O'Brien int old = sc->txq.cur; 1774257c5577SDavid E. O'Brien struct mbuf *m0; 1775257c5577SDavid E. O'Brien 1776bfc788c2SDavid E. O'Brien if (!sc->nfe_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1777bfc788c2SDavid E. O'Brien return; 1778bfc788c2SDavid E. O'Brien } 1779bfc788c2SDavid E. O'Brien 1780257c5577SDavid E. O'Brien for (;;) { 1781257c5577SDavid E. O'Brien IFQ_POLL(&ifp->if_snd, m0); 1782257c5577SDavid E. O'Brien if (m0 == NULL) 1783257c5577SDavid E. O'Brien break; 1784257c5577SDavid E. O'Brien 1785257c5577SDavid E. O'Brien if (nfe_encap(sc, m0) != 0) { 1786bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1787257c5577SDavid E. O'Brien break; 1788257c5577SDavid E. O'Brien } 1789257c5577SDavid E. O'Brien 1790257c5577SDavid E. O'Brien /* packet put in h/w queue, remove from s/w queue */ 1791257c5577SDavid E. O'Brien IFQ_DEQUEUE(&ifp->if_snd, m0); 1792257c5577SDavid E. O'Brien 1793bfc788c2SDavid E. O'Brien BPF_MTAP(ifp, m0); 1794257c5577SDavid E. O'Brien } 1795bfc788c2SDavid E. O'Brien if (sc->txq.cur == old) { /* nothing sent */ 1796257c5577SDavid E. O'Brien return; 1797bfc788c2SDavid E. O'Brien } 1798257c5577SDavid E. O'Brien 1799bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1800257c5577SDavid E. O'Brien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1801257c5577SDavid E. O'Brien else 1802257c5577SDavid E. O'Brien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1803257c5577SDavid E. O'Brien 1804257c5577SDavid E. O'Brien /* kick Tx */ 1805257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1806257c5577SDavid E. O'Brien 1807257c5577SDavid E. O'Brien /* 1808257c5577SDavid E. O'Brien * Set a timeout in case the chip goes out to lunch. 1809257c5577SDavid E. O'Brien */ 1810257c5577SDavid E. O'Brien ifp->if_timer = 5; 1811bfc788c2SDavid E. O'Brien 1812bfc788c2SDavid E. O'Brien return; 1813257c5577SDavid E. O'Brien } 1814257c5577SDavid E. O'Brien 1815bfc788c2SDavid E. O'Brien static void nfe_watchdog(struct ifnet *ifp) 1816257c5577SDavid E. O'Brien { 1817257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1818257c5577SDavid E. O'Brien 1819bfc788c2SDavid E. O'Brien printf("nfe%d: watchdog timeout\n", sc->nfe_unit); 1820257c5577SDavid E. O'Brien 1821bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1822bfc788c2SDavid E. O'Brien nfe_init(sc); 1823257c5577SDavid E. O'Brien 1824257c5577SDavid E. O'Brien ifp->if_oerrors++; 1825bfc788c2SDavid E. O'Brien 1826bfc788c2SDavid E. O'Brien return; 1827257c5577SDavid E. O'Brien } 1828257c5577SDavid E. O'Brien 1829bfc788c2SDavid E. O'Brien static void nfe_init(void *xsc) 1830257c5577SDavid E. O'Brien { 1831bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1832bfc788c2SDavid E. O'Brien 1833bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 1834bfc788c2SDavid E. O'Brien nfe_init_locked(sc); 1835bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 1836bfc788c2SDavid E. O'Brien 1837bfc788c2SDavid E. O'Brien return; 1838bfc788c2SDavid E. O'Brien } 1839bfc788c2SDavid E. O'Brien 1840bfc788c2SDavid E. O'Brien static void nfe_init_locked(void *xsc) 1841bfc788c2SDavid E. O'Brien { 1842bfc788c2SDavid E. O'Brien struct nfe_softc *sc = xsc; 1843bfc788c2SDavid E. O'Brien struct ifnet *ifp = sc->nfe_ifp; 1844bfc788c2SDavid E. O'Brien struct mii_data *mii; 1845bfc788c2SDavid E. O'Brien u_int32_t tmp; 1846bfc788c2SDavid E. O'Brien 1847bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1848bfc788c2SDavid E. O'Brien 1849bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1850bfc788c2SDavid E. O'Brien 1851bfc788c2SDavid E. O'Brien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1852bfc788c2SDavid E. O'Brien return; 1853bfc788c2SDavid E. O'Brien } 1854257c5577SDavid E. O'Brien 1855257c5577SDavid E. O'Brien nfe_stop(ifp, 0); 1856257c5577SDavid E. O'Brien 1857257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_UNK, 0); 1858257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, 0); 1859257c5577SDavid E. O'Brien 1860257c5577SDavid E. O'Brien sc->rxtxctl = NFE_RXTX_BIT2; 1861bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_40BIT_ADDR) 1862257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1863bfc788c2SDavid E. O'Brien else if (sc->nfe_flags & NFE_JUMBO_SUP) 1864257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 1865257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1866bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_CSUM) 1867257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1868257c5577SDavid E. O'Brien #endif 1869bfc788c2SDavid E. O'Brien 1870257c5577SDavid E. O'Brien #if NVLAN > 0 1871257c5577SDavid E. O'Brien /* 1872257c5577SDavid E. O'Brien * Although the adapter is capable of stripping VLAN tags from received 1873257c5577SDavid E. O'Brien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1874257c5577SDavid E. O'Brien * purpose. This will be done in software by our network stack. 1875257c5577SDavid E. O'Brien */ 1876bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1877257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1878257c5577SDavid E. O'Brien #endif 1879bfc788c2SDavid E. O'Brien 1880257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1881257c5577SDavid E. O'Brien DELAY(10); 1882257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1883257c5577SDavid E. O'Brien 1884257c5577SDavid E. O'Brien #if NVLAN 1885bfc788c2SDavid E. O'Brien if (sc->nfe_flags & NFE_HW_VLAN) 1886257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1887257c5577SDavid E. O'Brien #endif 1888257c5577SDavid E. O'Brien 1889257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1890257c5577SDavid E. O'Brien 1891257c5577SDavid E. O'Brien /* set MAC address */ 1892bfc788c2SDavid E. O'Brien nfe_set_macaddr(sc, sc->eaddr); 1893257c5577SDavid E. O'Brien 1894257c5577SDavid E. O'Brien /* tell MAC where rings are in memory */ 1895257c5577SDavid E. O'Brien #ifdef __LP64__ 1896257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1897257c5577SDavid E. O'Brien #endif 1898257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1899257c5577SDavid E. O'Brien #ifdef __LP64__ 1900257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1901257c5577SDavid E. O'Brien #endif 1902257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1903257c5577SDavid E. O'Brien 1904257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RING_SIZE, 1905257c5577SDavid E. O'Brien (NFE_RX_RING_COUNT - 1) << 16 | 1906257c5577SDavid E. O'Brien (NFE_TX_RING_COUNT - 1)); 1907257c5577SDavid E. O'Brien 1908257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1909257c5577SDavid E. O'Brien 1910257c5577SDavid E. O'Brien /* force MAC to wakeup */ 1911257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1912257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1913257c5577SDavid E. O'Brien DELAY(10); 1914257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1915257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1916257c5577SDavid E. O'Brien 1917257c5577SDavid E. O'Brien #if 1 1918257c5577SDavid E. O'Brien /* configure interrupts coalescing/mitigation */ 1919257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1920257c5577SDavid E. O'Brien #else 1921257c5577SDavid E. O'Brien /* no interrupt mitigation: one interrupt per packet */ 1922257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, 970); 1923257c5577SDavid E. O'Brien #endif 1924257c5577SDavid E. O'Brien 1925257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1926257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1927257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1928257c5577SDavid E. O'Brien 1929257c5577SDavid E. O'Brien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1930257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1931257c5577SDavid E. O'Brien 1932257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1933257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1934257c5577SDavid E. O'Brien 1935257c5577SDavid E. O'Brien sc->rxtxctl &= ~NFE_RXTX_BIT2; 1936257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1937257c5577SDavid E. O'Brien DELAY(10); 1938257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1939257c5577SDavid E. O'Brien 1940257c5577SDavid E. O'Brien /* set Rx filter */ 1941257c5577SDavid E. O'Brien nfe_setmulti(sc); 1942257c5577SDavid E. O'Brien 1943257c5577SDavid E. O'Brien nfe_ifmedia_upd(ifp); 1944257c5577SDavid E. O'Brien 1945bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 1946bfc788c2SDavid E. O'Brien 1947257c5577SDavid E. O'Brien /* enable Rx */ 1948257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1949257c5577SDavid E. O'Brien 1950257c5577SDavid E. O'Brien /* enable Tx */ 1951257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1952257c5577SDavid E. O'Brien 1953257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1954257c5577SDavid E. O'Brien 1955bfc788c2SDavid E. O'Brien #ifdef DEVICE_POLLING 1956bfc788c2SDavid E. O'Brien if (ifp->if_capenable & IFCAP_POLLING) 1957bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1958bfc788c2SDavid E. O'Brien else 1959bfc788c2SDavid E. O'Brien #endif 1960bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); /* enable interrupts */ 1961257c5577SDavid E. O'Brien 1962bfc788c2SDavid E. O'Brien ifp->if_drv_flags |= IFF_DRV_RUNNING; 1963bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1964257c5577SDavid E. O'Brien 1965bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 1966257c5577SDavid E. O'Brien 1967bfc788c2SDavid E. O'Brien return; 1968257c5577SDavid E. O'Brien } 1969257c5577SDavid E. O'Brien 1970bfc788c2SDavid E. O'Brien static void nfe_stop(struct ifnet *ifp, int disable) 1971257c5577SDavid E. O'Brien { 1972257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1973bfc788c2SDavid E. O'Brien struct mii_data *mii; 1974257c5577SDavid E. O'Brien 1975bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 1976257c5577SDavid E. O'Brien 1977257c5577SDavid E. O'Brien ifp->if_timer = 0; 1978bfc788c2SDavid E. O'Brien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1979257c5577SDavid E. O'Brien 1980bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 1981bfc788c2SDavid E. O'Brien 1982bfc788c2SDavid E. O'Brien callout_stop(&sc->nfe_stat_ch); 1983257c5577SDavid E. O'Brien 1984257c5577SDavid E. O'Brien /* abort Tx */ 1985257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, 0); 1986257c5577SDavid E. O'Brien 1987257c5577SDavid E. O'Brien /* disable Rx */ 1988257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, 0); 1989257c5577SDavid E. O'Brien 1990257c5577SDavid E. O'Brien /* disable interrupts */ 1991257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1992257c5577SDavid E. O'Brien 1993bfc788c2SDavid E. O'Brien sc->nfe_link = 0; 1994bfc788c2SDavid E. O'Brien 1995257c5577SDavid E. O'Brien /* reset Tx and Rx rings */ 1996257c5577SDavid E. O'Brien nfe_reset_tx_ring(sc, &sc->txq); 1997257c5577SDavid E. O'Brien nfe_reset_rx_ring(sc, &sc->rxq); 1998257c5577SDavid E. O'Brien 1999257c5577SDavid E. O'Brien return; 2000257c5577SDavid E. O'Brien } 2001257c5577SDavid E. O'Brien 2002bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd(struct ifnet *ifp) 2003257c5577SDavid E. O'Brien { 2004257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2005257c5577SDavid E. O'Brien 2006bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2007bfc788c2SDavid E. O'Brien nfe_ifmedia_upd_locked(ifp); 2008bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2009bfc788c2SDavid E. O'Brien return (0); 2010bfc788c2SDavid E. O'Brien } 2011bfc788c2SDavid E. O'Brien 2012bfc788c2SDavid E. O'Brien static int nfe_ifmedia_upd_locked(struct ifnet *ifp) 2013bfc788c2SDavid E. O'Brien { 2014bfc788c2SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 2015bfc788c2SDavid E. O'Brien struct mii_data *mii; 2016bfc788c2SDavid E. O'Brien 2017bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2018bfc788c2SDavid E. O'Brien 2019bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2020bfc788c2SDavid E. O'Brien 2021bfc788c2SDavid E. O'Brien if (mii->mii_instance) { 2022bfc788c2SDavid E. O'Brien struct mii_softc *miisc; 2023bfc788c2SDavid E. O'Brien for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 2024bfc788c2SDavid E. O'Brien miisc = LIST_NEXT(miisc, mii_list)) { 2025257c5577SDavid E. O'Brien mii_phy_reset(miisc); 2026257c5577SDavid E. O'Brien } 2027bfc788c2SDavid E. O'Brien } 2028bfc788c2SDavid E. O'Brien mii_mediachg(mii); 2029bfc788c2SDavid E. O'Brien 2030bfc788c2SDavid E. O'Brien return (0); 2031257c5577SDavid E. O'Brien } 2032257c5577SDavid E. O'Brien 2033bfc788c2SDavid E. O'Brien static void nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2034257c5577SDavid E. O'Brien { 2035bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2036bfc788c2SDavid E. O'Brien struct mii_data *mii; 2037257c5577SDavid E. O'Brien 2038bfc788c2SDavid E. O'Brien sc = ifp->if_softc; 2039bfc788c2SDavid E. O'Brien 2040bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2041bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2042257c5577SDavid E. O'Brien mii_pollstat(mii); 2043bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2044bfc788c2SDavid E. O'Brien 2045257c5577SDavid E. O'Brien ifmr->ifm_active = mii->mii_media_active; 2046bfc788c2SDavid E. O'Brien ifmr->ifm_status = mii->mii_media_status; 2047bfc788c2SDavid E. O'Brien 2048bfc788c2SDavid E. O'Brien return; 2049257c5577SDavid E. O'Brien } 2050257c5577SDavid E. O'Brien 2051bfc788c2SDavid E. O'Brien static void 2052bfc788c2SDavid E. O'Brien nfe_tick(void *xsc) 2053257c5577SDavid E. O'Brien { 2054bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2055257c5577SDavid E. O'Brien 2056bfc788c2SDavid E. O'Brien sc = xsc; 2057bfc788c2SDavid E. O'Brien 2058bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2059bfc788c2SDavid E. O'Brien nfe_tick_locked(sc); 2060bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2061257c5577SDavid E. O'Brien } 2062257c5577SDavid E. O'Brien 2063257c5577SDavid E. O'Brien 2064bfc788c2SDavid E. O'Brien void nfe_tick_locked(struct nfe_softc *arg) 2065bfc788c2SDavid E. O'Brien { 2066bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2067bfc788c2SDavid E. O'Brien struct mii_data *mii; 2068bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2069bfc788c2SDavid E. O'Brien 2070bfc788c2SDavid E. O'Brien sc = arg; 2071bfc788c2SDavid E. O'Brien 2072bfc788c2SDavid E. O'Brien NFE_LOCK_ASSERT(sc); 2073bfc788c2SDavid E. O'Brien 2074bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2075bfc788c2SDavid E. O'Brien 2076bfc788c2SDavid E. O'Brien mii = device_get_softc(sc->nfe_miibus); 2077bfc788c2SDavid E. O'Brien mii_tick(mii); 2078bfc788c2SDavid E. O'Brien 2079bfc788c2SDavid E. O'Brien if (!sc->nfe_link) { 2080bfc788c2SDavid E. O'Brien if (mii->mii_media_status & IFM_ACTIVE && 2081bfc788c2SDavid E. O'Brien IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 2082bfc788c2SDavid E. O'Brien sc->nfe_link++; 2083bfc788c2SDavid E. O'Brien if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T 2084bfc788c2SDavid E. O'Brien && bootverbose) 2085bfc788c2SDavid E. O'Brien if_printf(sc->nfe_ifp, "gigabit link up\n"); 2086bfc788c2SDavid E. O'Brien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2087bfc788c2SDavid E. O'Brien nfe_start_locked(ifp); 2088257c5577SDavid E. O'Brien } 2089257c5577SDavid E. O'Brien } 2090bfc788c2SDavid E. O'Brien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2091257c5577SDavid E. O'Brien 2092bfc788c2SDavid E. O'Brien return; 2093257c5577SDavid E. O'Brien } 2094257c5577SDavid E. O'Brien 2095bfc788c2SDavid E. O'Brien 2096bfc788c2SDavid E. O'Brien static void nfe_shutdown(device_t dev) 2097bfc788c2SDavid E. O'Brien { 2098bfc788c2SDavid E. O'Brien struct nfe_softc *sc; 2099bfc788c2SDavid E. O'Brien struct ifnet *ifp; 2100bfc788c2SDavid E. O'Brien 2101bfc788c2SDavid E. O'Brien sc = device_get_softc(dev); 2102bfc788c2SDavid E. O'Brien 2103bfc788c2SDavid E. O'Brien NFE_LOCK(sc); 2104bfc788c2SDavid E. O'Brien ifp = sc->nfe_ifp; 2105bfc788c2SDavid E. O'Brien nfe_stop(ifp,0); 2106bfc788c2SDavid E. O'Brien /* nfe_reset(sc); */ 2107bfc788c2SDavid E. O'Brien NFE_UNLOCK(sc); 2108bfc788c2SDavid E. O'Brien 2109bfc788c2SDavid E. O'Brien return; 2110bfc788c2SDavid E. O'Brien } 2111bfc788c2SDavid E. O'Brien 2112bfc788c2SDavid E. O'Brien 2113bfc788c2SDavid E. O'Brien static void nfe_get_macaddr(struct nfe_softc *sc, u_char *addr) 2114257c5577SDavid E. O'Brien { 2115257c5577SDavid E. O'Brien uint32_t tmp; 2116257c5577SDavid E. O'Brien 2117257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_LO); 2118257c5577SDavid E. O'Brien addr[0] = (tmp >> 8) & 0xff; 2119257c5577SDavid E. O'Brien addr[1] = (tmp & 0xff); 2120257c5577SDavid E. O'Brien 2121257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_HI); 2122257c5577SDavid E. O'Brien addr[2] = (tmp >> 24) & 0xff; 2123257c5577SDavid E. O'Brien addr[3] = (tmp >> 16) & 0xff; 2124257c5577SDavid E. O'Brien addr[4] = (tmp >> 8) & 0xff; 2125257c5577SDavid E. O'Brien addr[5] = (tmp & 0xff); 2126257c5577SDavid E. O'Brien } 2127257c5577SDavid E. O'Brien 2128bfc788c2SDavid E. O'Brien static void nfe_set_macaddr(struct nfe_softc *sc, u_char *addr) 2129257c5577SDavid E. O'Brien { 2130bfc788c2SDavid E. O'Brien 2131bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 2132bfc788c2SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 2133bfc788c2SDavid E. O'Brien addr[1] << 8 | addr[0]); 2134257c5577SDavid E. O'Brien } 2135257c5577SDavid E. O'Brien 2136bfc788c2SDavid E. O'Brien /* 2137bfc788c2SDavid E. O'Brien * Map a single buffer address. 2138bfc788c2SDavid E. O'Brien */ 2139bfc788c2SDavid E. O'Brien 2140bfc788c2SDavid E. O'Brien static void 2141bfc788c2SDavid E. O'Brien nfe_dma_map_segs(arg, segs, nseg, error) 2142bfc788c2SDavid E. O'Brien void *arg; 2143bfc788c2SDavid E. O'Brien bus_dma_segment_t *segs; 2144bfc788c2SDavid E. O'Brien int error, nseg; 2145257c5577SDavid E. O'Brien { 2146257c5577SDavid E. O'Brien 2147bfc788c2SDavid E. O'Brien if (error) 2148bfc788c2SDavid E. O'Brien return; 2149257c5577SDavid E. O'Brien 2150bfc788c2SDavid E. O'Brien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2151bfc788c2SDavid E. O'Brien 2152bfc788c2SDavid E. O'Brien *(bus_dma_segment_t *)arg = *segs; 2153bfc788c2SDavid E. O'Brien 2154bfc788c2SDavid E. O'Brien return; 2155257c5577SDavid E. O'Brien } 2156