if_nfe.c revision 172164
1159967Sobrien/* $OpenBSD: if_nfe.c,v 1.54 2006/04/07 12:38:12 jsg Exp $ */ 2159952Sobrien 3159952Sobrien/*- 4159967Sobrien * Copyright (c) 2006 Shigeaki Tagashira <shigeaki@se.hiroshima-u.ac.jp> 5159952Sobrien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 6159952Sobrien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 7159952Sobrien * 8159952Sobrien * Permission to use, copy, modify, and distribute this software for any 9159952Sobrien * purpose with or without fee is hereby granted, provided that the above 10159952Sobrien * copyright notice and this permission notice appear in all copies. 11159952Sobrien * 12159952Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13159952Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14159952Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15159952Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16159952Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17159952Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18159952Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19159952Sobrien */ 20159952Sobrien 21159952Sobrien/* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 22159952Sobrien 23159967Sobrien#include <sys/cdefs.h> 24159967Sobrien__FBSDID("$FreeBSD: head/sys/dev/nfe/if_nfe.c 172164 2007-09-14 01:28:18Z yongari $"); 25159952Sobrien 26159967Sobrien#ifdef HAVE_KERNEL_OPTION_HEADERS 27159967Sobrien#include "opt_device_polling.h" 28159967Sobrien#endif 29159967Sobrien 30159952Sobrien#include <sys/param.h> 31159952Sobrien#include <sys/endian.h> 32159952Sobrien#include <sys/systm.h> 33159952Sobrien#include <sys/sockio.h> 34159952Sobrien#include <sys/mbuf.h> 35159952Sobrien#include <sys/malloc.h> 36159967Sobrien#include <sys/module.h> 37159952Sobrien#include <sys/kernel.h> 38170589Syongari#include <sys/queue.h> 39159952Sobrien#include <sys/socket.h> 40170589Syongari#include <sys/sysctl.h> 41159967Sobrien#include <sys/taskqueue.h> 42159952Sobrien 43159952Sobrien#include <net/if.h> 44159967Sobrien#include <net/if_arp.h> 45159967Sobrien#include <net/ethernet.h> 46159952Sobrien#include <net/if_dl.h> 47159952Sobrien#include <net/if_media.h> 48159952Sobrien#include <net/if_types.h> 49159952Sobrien#include <net/if_vlan_var.h> 50159952Sobrien 51159952Sobrien#include <net/bpf.h> 52159952Sobrien 53159967Sobrien#include <machine/bus.h> 54159967Sobrien#include <machine/resource.h> 55159967Sobrien#include <sys/bus.h> 56159967Sobrien#include <sys/rman.h> 57159967Sobrien 58159952Sobrien#include <dev/mii/mii.h> 59159952Sobrien#include <dev/mii/miivar.h> 60159952Sobrien 61159952Sobrien#include <dev/pci/pcireg.h> 62159952Sobrien#include <dev/pci/pcivar.h> 63159952Sobrien 64159967Sobrien#include <dev/nfe/if_nfereg.h> 65159967Sobrien#include <dev/nfe/if_nfevar.h> 66159952Sobrien 67159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1); 68159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1); 69159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1); 70170589Syongari 71170589Syongari/* "device miibus" required. See GENERIC if you get errors here. */ 72159967Sobrien#include "miibus_if.h" 73159952Sobrien 74163503Sobrienstatic int nfe_probe(device_t); 75163503Sobrienstatic int nfe_attach(device_t); 76163503Sobrienstatic int nfe_detach(device_t); 77170589Syongaristatic int nfe_suspend(device_t); 78170589Syongaristatic int nfe_resume(device_t); 79163503Sobrienstatic void nfe_shutdown(device_t); 80170589Syongaristatic void nfe_power(struct nfe_softc *); 81163503Sobrienstatic int nfe_miibus_readreg(device_t, int, int); 82163503Sobrienstatic int nfe_miibus_writereg(device_t, int, int, int); 83163503Sobrienstatic void nfe_miibus_statchg(device_t); 84170589Syongaristatic void nfe_link_task(void *, int); 85170589Syongaristatic void nfe_set_intr(struct nfe_softc *); 86170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *); 87170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *); 88163503Sobrienstatic int nfe_ioctl(struct ifnet *, u_long, caddr_t); 89170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int); 90170589Syongaristatic int nfe_intr(void *); 91170589Syongaristatic void nfe_int_task(void *, int); 92170589Syongaristatic void *nfe_jalloc(struct nfe_softc *); 93170589Syongaristatic void nfe_jfree(void *, void *); 94170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int); 95170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int); 96170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int); 97170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int); 98170589Syongaristatic int nfe_rxeof(struct nfe_softc *, int); 99170589Syongaristatic int nfe_jrxeof(struct nfe_softc *, int); 100159967Sobrienstatic void nfe_txeof(struct nfe_softc *); 101170589Syongaristatic struct mbuf *nfe_defrag(struct mbuf *, int, int); 102170589Syongaristatic int nfe_encap(struct nfe_softc *, struct mbuf **); 103159967Sobrienstatic void nfe_setmulti(struct nfe_softc *); 104170589Syongaristatic void nfe_tx_task(void *, int); 105159967Sobrienstatic void nfe_start(struct ifnet *); 106159967Sobrienstatic void nfe_watchdog(struct ifnet *); 107159967Sobrienstatic void nfe_init(void *); 108159967Sobrienstatic void nfe_init_locked(void *); 109170589Syongaristatic void nfe_stop(struct ifnet *); 110159967Sobrienstatic int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 111171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 112170589Syongaristatic int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 113170589Syongaristatic int nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 114159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 115170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 116159967Sobrienstatic int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 117170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 118159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 119159967Sobrienstatic int nfe_ifmedia_upd(struct ifnet *); 120159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 121159967Sobrienstatic void nfe_tick(void *); 122170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 123170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *); 124170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); 125159952Sobrien 126170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 127170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); 128170589Syongari 129159952Sobrien#ifdef NFE_DEBUG 130170589Syongaristatic int nfedebug = 0; 131170589Syongari#define DPRINTF(sc, ...) do { \ 132170589Syongari if (nfedebug) \ 133170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 134170589Syongari} while (0) 135170589Syongari#define DPRINTFN(sc, n, ...) do { \ 136170589Syongari if (nfedebug >= (n)) \ 137170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 138170589Syongari} while (0) 139159952Sobrien#else 140170589Syongari#define DPRINTF(sc, ...) 141170589Syongari#define DPRINTFN(sc, n, ...) 142159952Sobrien#endif 143159952Sobrien 144159967Sobrien#define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 145159967Sobrien#define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 146159967Sobrien#define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 147159967Sobrien 148170589Syongari#define NFE_JLIST_LOCK(_sc) mtx_lock(&(_sc)->nfe_jlist_mtx) 149170589Syongari#define NFE_JLIST_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_jlist_mtx) 150159967Sobrien 151170589Syongari/* Tunables. */ 152170589Syongaristatic int msi_disable = 0; 153170589Syongaristatic int msix_disable = 0; 154171559Syongaristatic int jumbo_disable = 0; 155170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable); 156170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable); 157171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable); 158159967Sobrien 159159967Sobrienstatic device_method_t nfe_methods[] = { 160159967Sobrien /* Device interface */ 161159967Sobrien DEVMETHOD(device_probe, nfe_probe), 162159967Sobrien DEVMETHOD(device_attach, nfe_attach), 163159967Sobrien DEVMETHOD(device_detach, nfe_detach), 164170589Syongari DEVMETHOD(device_suspend, nfe_suspend), 165170589Syongari DEVMETHOD(device_resume, nfe_resume), 166159967Sobrien DEVMETHOD(device_shutdown, nfe_shutdown), 167159967Sobrien 168159967Sobrien /* bus interface */ 169159967Sobrien DEVMETHOD(bus_print_child, bus_generic_print_child), 170159967Sobrien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 171159967Sobrien 172159967Sobrien /* MII interface */ 173159967Sobrien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 174159967Sobrien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 175163503Sobrien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 176159967Sobrien 177170589Syongari { NULL, NULL } 178159952Sobrien}; 179159952Sobrien 180159967Sobrienstatic driver_t nfe_driver = { 181159967Sobrien "nfe", 182159967Sobrien nfe_methods, 183159967Sobrien sizeof(struct nfe_softc) 184159967Sobrien}; 185159967Sobrien 186159967Sobrienstatic devclass_t nfe_devclass; 187159967Sobrien 188159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 189159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 190159967Sobrien 191159967Sobrienstatic struct nfe_type nfe_devs[] = { 192159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 193163503Sobrien "NVIDIA nForce MCP Networking Adapter"}, 194159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 195163503Sobrien "NVIDIA nForce2 MCP2 Networking Adapter"}, 196159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 197163503Sobrien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 198159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 199163503Sobrien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 200163437Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 201163503Sobrien "NVIDIA nForce3 MCP3 Networking Adapter"}, 202159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 203163503Sobrien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 204159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 205163503Sobrien "NVIDIA nForce3 MCP7 Networking Adapter"}, 206159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 207163503Sobrien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 208159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 209163503Sobrien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 210159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 211170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP10 */ 212159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 213170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP11 */ 214159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 215163503Sobrien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 216159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 217163503Sobrien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 218159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 219163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 220159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 221163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 222162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 223163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 224162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 225163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 226162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 227163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 228170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4, 229163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 230162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 231163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 232162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 233163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 234162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 235163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 236170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4, 237163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 238170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1, 239170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 240170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2, 241170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 242170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3, 243170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 244170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4, 245170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 246159967Sobrien {0, 0, NULL} 247159967Sobrien}; 248159967Sobrien 249159967Sobrien 250159967Sobrien/* Probe for supported hardware ID's */ 251159967Sobrienstatic int 252159967Sobriennfe_probe(device_t dev) 253159952Sobrien{ 254159967Sobrien struct nfe_type *t; 255159967Sobrien 256159967Sobrien t = nfe_devs; 257159967Sobrien /* Check for matching PCI DEVICE ID's */ 258159967Sobrien while (t->name != NULL) { 259159967Sobrien if ((pci_get_vendor(dev) == t->vid_id) && 260159967Sobrien (pci_get_device(dev) == t->dev_id)) { 261159967Sobrien device_set_desc(dev, t->name); 262170589Syongari return (BUS_PROBE_DEFAULT); 263159967Sobrien } 264159967Sobrien t++; 265159967Sobrien } 266159967Sobrien 267159967Sobrien return (ENXIO); 268159952Sobrien} 269159952Sobrien 270170589Syongaristatic void 271170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count) 272170589Syongari{ 273170589Syongari int rid; 274163503Sobrien 275170589Syongari rid = PCIR_BAR(2); 276170589Syongari sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY, 277170589Syongari &rid, RF_ACTIVE); 278170589Syongari if (sc->nfe_msix_res == NULL) { 279170589Syongari device_printf(sc->nfe_dev, 280170589Syongari "couldn't allocate MSIX table resource\n"); 281170589Syongari return; 282170589Syongari } 283170589Syongari rid = PCIR_BAR(3); 284170589Syongari sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev, 285170589Syongari SYS_RES_MEMORY, &rid, RF_ACTIVE); 286170589Syongari if (sc->nfe_msix_pba_res == NULL) { 287170589Syongari device_printf(sc->nfe_dev, 288170589Syongari "couldn't allocate MSIX PBA resource\n"); 289170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2), 290170589Syongari sc->nfe_msix_res); 291170589Syongari sc->nfe_msix_res = NULL; 292170589Syongari return; 293170589Syongari } 294170589Syongari 295170589Syongari if (pci_alloc_msix(sc->nfe_dev, &count) == 0) { 296170589Syongari if (count == NFE_MSI_MESSAGES) { 297170589Syongari if (bootverbose) 298170589Syongari device_printf(sc->nfe_dev, 299170589Syongari "Using %d MSIX messages\n", count); 300170589Syongari sc->nfe_msix = 1; 301170589Syongari } else { 302170589Syongari if (bootverbose) 303170589Syongari device_printf(sc->nfe_dev, 304170589Syongari "couldn't allocate MSIX\n"); 305170589Syongari pci_release_msi(sc->nfe_dev); 306170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 307170589Syongari PCIR_BAR(3), sc->nfe_msix_pba_res); 308170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 309170589Syongari PCIR_BAR(2), sc->nfe_msix_res); 310170589Syongari sc->nfe_msix_pba_res = NULL; 311170589Syongari sc->nfe_msix_res = NULL; 312170589Syongari } 313170589Syongari } 314170589Syongari} 315170589Syongari 316159967Sobrienstatic int 317159967Sobriennfe_attach(device_t dev) 318159952Sobrien{ 319159967Sobrien struct nfe_softc *sc; 320159952Sobrien struct ifnet *ifp; 321170589Syongari bus_addr_t dma_addr_max; 322170589Syongari int error = 0, i, msic, reg, rid; 323159952Sobrien 324159967Sobrien sc = device_get_softc(dev); 325159967Sobrien sc->nfe_dev = dev; 326159952Sobrien 327159967Sobrien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 328170589Syongari MTX_DEF); 329170589Syongari mtx_init(&sc->nfe_jlist_mtx, "nfe_jlist_mtx", NULL, MTX_DEF); 330159967Sobrien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 331170589Syongari TASK_INIT(&sc->nfe_link_task, 0, nfe_link_task, sc); 332170589Syongari SLIST_INIT(&sc->nfe_jfree_listhead); 333170589Syongari SLIST_INIT(&sc->nfe_jinuse_listhead); 334159967Sobrien 335163503Sobrien pci_enable_busmaster(dev); 336159967Sobrien 337170589Syongari rid = PCIR_BAR(0); 338170589Syongari sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 339170589Syongari RF_ACTIVE); 340170589Syongari if (sc->nfe_res[0] == NULL) { 341170589Syongari device_printf(dev, "couldn't map memory resources\n"); 342170589Syongari mtx_destroy(&sc->nfe_mtx); 343170589Syongari return (ENXIO); 344170589Syongari } 345159967Sobrien 346170589Syongari if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 347170589Syongari uint16_t v, width; 348170589Syongari 349170589Syongari v = pci_read_config(dev, reg + 0x08, 2); 350170589Syongari /* Change max. read request size to 4096. */ 351170589Syongari v &= ~(7 << 12); 352170589Syongari v |= (5 << 12); 353170589Syongari pci_write_config(dev, reg + 0x08, v, 2); 354170589Syongari 355170589Syongari v = pci_read_config(dev, reg + 0x0c, 2); 356170589Syongari /* link capability */ 357170589Syongari v = (v >> 4) & 0x0f; 358170589Syongari width = pci_read_config(dev, reg + 0x12, 2); 359170589Syongari /* negotiated link width */ 360170589Syongari width = (width >> 4) & 0x3f; 361170589Syongari if (v != width) 362170589Syongari device_printf(sc->nfe_dev, 363170589Syongari "warning, negotiated width of link(x%d) != " 364170589Syongari "max. width of link(x%d)\n", width, v); 365159952Sobrien } 366159952Sobrien 367159967Sobrien /* Allocate interrupt */ 368170589Syongari if (msix_disable == 0 || msi_disable == 0) { 369170589Syongari if (msix_disable == 0 && 370170589Syongari (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES) 371170589Syongari nfe_alloc_msix(sc, msic); 372170589Syongari if (msi_disable == 0 && sc->nfe_msix == 0 && 373170589Syongari (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES && 374170589Syongari pci_alloc_msi(dev, &msic) == 0) { 375170589Syongari if (msic == NFE_MSI_MESSAGES) { 376170589Syongari if (bootverbose) 377170589Syongari device_printf(dev, 378170589Syongari "Using %d MSI messages\n", msic); 379170589Syongari sc->nfe_msi = 1; 380170589Syongari } else 381170589Syongari pci_release_msi(dev); 382170589Syongari } 383170589Syongari } 384159967Sobrien 385170589Syongari if (sc->nfe_msix == 0 && sc->nfe_msi == 0) { 386170589Syongari rid = 0; 387170589Syongari sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 388170589Syongari RF_SHAREABLE | RF_ACTIVE); 389170589Syongari if (sc->nfe_irq[0] == NULL) { 390170589Syongari device_printf(dev, "couldn't allocate IRQ resources\n"); 391170589Syongari error = ENXIO; 392170589Syongari goto fail; 393170589Syongari } 394170589Syongari } else { 395170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 396170589Syongari sc->nfe_irq[i] = bus_alloc_resource_any(dev, 397170589Syongari SYS_RES_IRQ, &rid, RF_ACTIVE); 398170589Syongari if (sc->nfe_irq[i] == NULL) { 399170589Syongari device_printf(dev, 400170589Syongari "couldn't allocate IRQ resources for " 401170589Syongari "message %d\n", rid); 402170589Syongari error = ENXIO; 403170589Syongari goto fail; 404170589Syongari } 405170589Syongari } 406170589Syongari /* Map interrupts to vector 0. */ 407170589Syongari if (sc->nfe_msix != 0) { 408170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP0, 0); 409170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP1, 0); 410170589Syongari } else if (sc->nfe_msi != 0) { 411170589Syongari NFE_WRITE(sc, NFE_MSI_MAP0, 0); 412170589Syongari NFE_WRITE(sc, NFE_MSI_MAP1, 0); 413170589Syongari } 414159952Sobrien } 415159952Sobrien 416170589Syongari /* Set IRQ status/mask register. */ 417170589Syongari sc->nfe_irq_status = NFE_IRQ_STATUS; 418170589Syongari sc->nfe_irq_mask = NFE_IRQ_MASK; 419170589Syongari sc->nfe_intrs = NFE_IRQ_WANTED; 420170589Syongari sc->nfe_nointrs = 0; 421170589Syongari if (sc->nfe_msix != 0) { 422170589Syongari sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS; 423170589Syongari sc->nfe_nointrs = NFE_IRQ_WANTED; 424170589Syongari } else if (sc->nfe_msi != 0) { 425170589Syongari sc->nfe_irq_mask = NFE_MSI_IRQ_MASK; 426170589Syongari sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED; 427170589Syongari } 428159952Sobrien 429170589Syongari sc->nfe_devid = pci_get_device(dev); 430170589Syongari sc->nfe_revid = pci_get_revid(dev); 431159967Sobrien sc->nfe_flags = 0; 432159952Sobrien 433170589Syongari switch (sc->nfe_devid) { 434159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 435159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 436159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 437159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 438159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 439159952Sobrien break; 440159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 441159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 442170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT; 443159952Sobrien break; 444159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 445159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 446159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 447159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 448159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 449159952Sobrien break; 450159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 451159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 452163503Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 453170589Syongari NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL; 454159952Sobrien break; 455170589Syongari 456162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 457162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 458162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 459162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 460170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 461170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 462170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 463170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 464170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | 465170589Syongari NFE_TX_FLOW_CTRL; 466162212Sobrien break; 467162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 468162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 469162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 470162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 471170589Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | 472170589Syongari NFE_PWR_MGMT | NFE_TX_FLOW_CTRL; 473163503Sobrien break; 474159952Sobrien } 475159952Sobrien 476170589Syongari nfe_power(sc); 477170589Syongari /* Check for reversed ethernet address */ 478170589Syongari if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0) 479170589Syongari sc->nfe_flags |= NFE_CORRECT_MACADDR; 480170589Syongari nfe_get_macaddr(sc, sc->eaddr); 481159952Sobrien /* 482159967Sobrien * Allocate the parent bus DMA tag appropriate for PCI. 483159967Sobrien */ 484170589Syongari dma_addr_max = BUS_SPACE_MAXADDR_32BIT; 485170589Syongari if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0) 486170589Syongari dma_addr_max = NFE_DMA_MAXADDR; 487170589Syongari error = bus_dma_tag_create( 488170589Syongari bus_get_dma_tag(sc->nfe_dev), /* parent */ 489163503Sobrien 1, 0, /* alignment, boundary */ 490170589Syongari dma_addr_max, /* lowaddr */ 491163503Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 492163503Sobrien NULL, NULL, /* filter, filterarg */ 493170589Syongari BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 494163503Sobrien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 495170589Syongari 0, /* flags */ 496163503Sobrien NULL, NULL, /* lockfunc, lockarg */ 497163503Sobrien &sc->nfe_parent_tag); 498159967Sobrien if (error) 499159967Sobrien goto fail; 500159967Sobrien 501164650Sobrien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 502164650Sobrien if (ifp == NULL) { 503170589Syongari device_printf(dev, "can not if_alloc()\n"); 504164650Sobrien error = ENOSPC; 505164650Sobrien goto fail; 506164650Sobrien } 507170589Syongari TASK_INIT(&sc->nfe_tx_task, 1, nfe_tx_task, ifp); 508164650Sobrien 509159967Sobrien /* 510159952Sobrien * Allocate Tx and Rx rings. 511159952Sobrien */ 512170589Syongari if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0) 513159967Sobrien goto fail; 514159952Sobrien 515170589Syongari if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0) 516159967Sobrien goto fail; 517170589Syongari 518171559Syongari nfe_alloc_jrx_ring(sc, &sc->jrxq); 519170589Syongari 520170589Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 521170589Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 522170589Syongari OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 523170589Syongari &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 524170589Syongari "max number of Rx events to process"); 525170589Syongari 526170589Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 527170589Syongari error = resource_int_value(device_get_name(dev), device_get_unit(dev), 528170589Syongari "process_limit", &sc->nfe_process_limit); 529170589Syongari if (error == 0) { 530170589Syongari if (sc->nfe_process_limit < NFE_PROC_MIN || 531170589Syongari sc->nfe_process_limit > NFE_PROC_MAX) { 532170589Syongari device_printf(dev, "process_limit value out of range; " 533170589Syongari "using default: %d\n", NFE_PROC_DEFAULT); 534170589Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 535170589Syongari } 536159952Sobrien } 537159952Sobrien 538159952Sobrien ifp->if_softc = sc; 539159967Sobrien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 540170589Syongari ifp->if_mtu = ETHERMTU; 541159952Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 542159952Sobrien ifp->if_ioctl = nfe_ioctl; 543159952Sobrien ifp->if_start = nfe_start; 544170589Syongari ifp->if_hwassist = 0; 545170589Syongari ifp->if_capabilities = 0; 546170589Syongari ifp->if_watchdog = NULL; 547159952Sobrien ifp->if_init = nfe_init; 548170589Syongari IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1); 549170589Syongari ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1; 550170589Syongari IFQ_SET_READY(&ifp->if_snd); 551159952Sobrien 552170589Syongari if (sc->nfe_flags & NFE_HW_CSUM) { 553170589Syongari ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4; 554170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO; 555170589Syongari } 556170589Syongari ifp->if_capenable = ifp->if_capabilities; 557164650Sobrien 558170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 559170589Syongari /* VLAN capability setup. */ 560170589Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 561170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 562159952Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 563170589Syongari if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0) 564170589Syongari ifp->if_capabilities |= IFCAP_VLAN_HWCSUM; 565159952Sobrien } 566159967Sobrien ifp->if_capenable = ifp->if_capabilities; 567159952Sobrien 568170589Syongari /* 569170589Syongari * Tell the upper layer(s) we support long frames. 570170589Syongari * Must appear after the call to ether_ifattach() because 571170589Syongari * ether_ifattach() sets ifi_hdrlen to the default value. 572170589Syongari */ 573170589Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 574170589Syongari 575159967Sobrien#ifdef DEVICE_POLLING 576159967Sobrien ifp->if_capabilities |= IFCAP_POLLING; 577159967Sobrien#endif 578159952Sobrien 579159967Sobrien /* Do MII setup */ 580163503Sobrien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, 581163503Sobrien nfe_ifmedia_sts)) { 582170589Syongari device_printf(dev, "MII without any phy!\n"); 583159967Sobrien error = ENXIO; 584159967Sobrien goto fail; 585159967Sobrien } 586159967Sobrien ether_ifattach(ifp, sc->eaddr); 587159952Sobrien 588170589Syongari TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc); 589170589Syongari sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK, 590170589Syongari taskqueue_thread_enqueue, &sc->nfe_tq); 591170589Syongari taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq", 592170589Syongari device_get_nameunit(sc->nfe_dev)); 593170589Syongari error = 0; 594170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 595170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[0], 596170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 597170589Syongari &sc->nfe_intrhand[0]); 598170589Syongari } else { 599170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 600170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[i], 601170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 602170589Syongari &sc->nfe_intrhand[i]); 603170589Syongari if (error != 0) 604170589Syongari break; 605170589Syongari } 606170589Syongari } 607159967Sobrien if (error) { 608170589Syongari device_printf(dev, "couldn't set up irq\n"); 609170589Syongari taskqueue_free(sc->nfe_tq); 610170589Syongari sc->nfe_tq = NULL; 611159967Sobrien ether_ifdetach(ifp); 612159967Sobrien goto fail; 613159967Sobrien } 614159967Sobrien 615159967Sobrienfail: 616159967Sobrien if (error) 617159967Sobrien nfe_detach(dev); 618159967Sobrien 619159967Sobrien return (error); 620159952Sobrien} 621159952Sobrien 622159967Sobrien 623159967Sobrienstatic int 624159967Sobriennfe_detach(device_t dev) 625159952Sobrien{ 626163503Sobrien struct nfe_softc *sc; 627163503Sobrien struct ifnet *ifp; 628170589Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 629170589Syongari int i, rid; 630159952Sobrien 631159967Sobrien sc = device_get_softc(dev); 632159967Sobrien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 633159967Sobrien ifp = sc->nfe_ifp; 634159967Sobrien 635159967Sobrien#ifdef DEVICE_POLLING 636170589Syongari if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 637159967Sobrien ether_poll_deregister(ifp); 638159967Sobrien#endif 639159967Sobrien if (device_is_attached(dev)) { 640164649Sobrien NFE_LOCK(sc); 641170589Syongari nfe_stop(ifp); 642159967Sobrien ifp->if_flags &= ~IFF_UP; 643164649Sobrien NFE_UNLOCK(sc); 644159967Sobrien callout_drain(&sc->nfe_stat_ch); 645170589Syongari taskqueue_drain(taskqueue_fast, &sc->nfe_tx_task); 646170589Syongari taskqueue_drain(taskqueue_swi, &sc->nfe_link_task); 647159967Sobrien ether_ifdetach(ifp); 648159967Sobrien } 649159967Sobrien 650170589Syongari if (ifp) { 651170589Syongari /* restore ethernet address */ 652170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 653170589Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) { 654170589Syongari eaddr[i] = sc->eaddr[5 - i]; 655170589Syongari } 656170589Syongari } else 657170589Syongari bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN); 658170589Syongari nfe_set_macaddr(sc, eaddr); 659159967Sobrien if_free(ifp); 660170589Syongari } 661159967Sobrien if (sc->nfe_miibus) 662159967Sobrien device_delete_child(dev, sc->nfe_miibus); 663159967Sobrien bus_generic_detach(dev); 664170589Syongari if (sc->nfe_tq != NULL) { 665170589Syongari taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task); 666170589Syongari taskqueue_free(sc->nfe_tq); 667170589Syongari sc->nfe_tq = NULL; 668170589Syongari } 669159967Sobrien 670170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 671170589Syongari if (sc->nfe_intrhand[i] != NULL) { 672170589Syongari bus_teardown_intr(dev, sc->nfe_irq[i], 673170589Syongari sc->nfe_intrhand[i]); 674170589Syongari sc->nfe_intrhand[i] = NULL; 675170589Syongari } 676170589Syongari } 677159967Sobrien 678170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 679170589Syongari if (sc->nfe_irq[0] != NULL) 680170589Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, 681170589Syongari sc->nfe_irq[0]); 682170589Syongari } else { 683170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 684170589Syongari if (sc->nfe_irq[i] != NULL) { 685170589Syongari bus_release_resource(dev, SYS_RES_IRQ, rid, 686170589Syongari sc->nfe_irq[i]); 687170589Syongari sc->nfe_irq[i] = NULL; 688170589Syongari } 689170589Syongari } 690170589Syongari pci_release_msi(dev); 691170589Syongari } 692170589Syongari if (sc->nfe_msix_pba_res != NULL) { 693170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3), 694170589Syongari sc->nfe_msix_pba_res); 695170589Syongari sc->nfe_msix_pba_res = NULL; 696170589Syongari } 697170589Syongari if (sc->nfe_msix_res != NULL) { 698170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 699170589Syongari sc->nfe_msix_res); 700170589Syongari sc->nfe_msix_res = NULL; 701170589Syongari } 702170589Syongari if (sc->nfe_res[0] != NULL) { 703170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 704170589Syongari sc->nfe_res[0]); 705170589Syongari sc->nfe_res[0] = NULL; 706170589Syongari } 707170589Syongari 708159967Sobrien nfe_free_tx_ring(sc, &sc->txq); 709159967Sobrien nfe_free_rx_ring(sc, &sc->rxq); 710170589Syongari nfe_free_jrx_ring(sc, &sc->jrxq); 711159967Sobrien 712170589Syongari if (sc->nfe_parent_tag) { 713159967Sobrien bus_dma_tag_destroy(sc->nfe_parent_tag); 714170589Syongari sc->nfe_parent_tag = NULL; 715170589Syongari } 716159967Sobrien 717170589Syongari mtx_destroy(&sc->nfe_jlist_mtx); 718159967Sobrien mtx_destroy(&sc->nfe_mtx); 719159967Sobrien 720159967Sobrien return (0); 721159952Sobrien} 722159952Sobrien 723159967Sobrien 724170589Syongaristatic int 725170589Syongarinfe_suspend(device_t dev) 726170589Syongari{ 727170589Syongari struct nfe_softc *sc; 728170589Syongari 729170589Syongari sc = device_get_softc(dev); 730170589Syongari 731170589Syongari NFE_LOCK(sc); 732170589Syongari nfe_stop(sc->nfe_ifp); 733170589Syongari sc->nfe_suspended = 1; 734170589Syongari NFE_UNLOCK(sc); 735170589Syongari 736170589Syongari return (0); 737170589Syongari} 738170589Syongari 739170589Syongari 740170589Syongaristatic int 741170589Syongarinfe_resume(device_t dev) 742170589Syongari{ 743170589Syongari struct nfe_softc *sc; 744170589Syongari struct ifnet *ifp; 745170589Syongari 746170589Syongari sc = device_get_softc(dev); 747170589Syongari 748170589Syongari NFE_LOCK(sc); 749170589Syongari ifp = sc->nfe_ifp; 750170589Syongari if (ifp->if_flags & IFF_UP) 751170589Syongari nfe_init_locked(sc); 752170589Syongari sc->nfe_suspended = 0; 753170589Syongari NFE_UNLOCK(sc); 754170589Syongari 755170589Syongari return (0); 756170589Syongari} 757170589Syongari 758170589Syongari 759170589Syongari/* Take PHY/NIC out of powerdown, from Linux */ 760159967Sobrienstatic void 761170589Syongarinfe_power(struct nfe_softc *sc) 762170589Syongari{ 763170589Syongari uint32_t pwr; 764170589Syongari 765170589Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) == 0) 766170589Syongari return; 767170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2); 768170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC); 769170589Syongari DELAY(100); 770170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, 0); 771170589Syongari DELAY(100); 772170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2); 773170589Syongari pwr = NFE_READ(sc, NFE_PWR2_CTL); 774170589Syongari pwr &= ~NFE_PWR2_WAKEUP_MASK; 775170589Syongari if (sc->nfe_revid >= 0xa3 && 776170589Syongari (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 || 777170589Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2)) 778170589Syongari pwr |= NFE_PWR2_REVA3; 779170589Syongari NFE_WRITE(sc, NFE_PWR2_CTL, pwr); 780170589Syongari} 781170589Syongari 782170589Syongari 783170589Syongaristatic void 784159967Sobriennfe_miibus_statchg(device_t dev) 785159952Sobrien{ 786159967Sobrien struct nfe_softc *sc; 787170589Syongari 788170589Syongari sc = device_get_softc(dev); 789170589Syongari taskqueue_enqueue(taskqueue_swi, &sc->nfe_link_task); 790170589Syongari} 791170589Syongari 792170589Syongari 793170589Syongaristatic void 794170589Syongarinfe_link_task(void *arg, int pending) 795170589Syongari{ 796170589Syongari struct nfe_softc *sc; 797159967Sobrien struct mii_data *mii; 798170589Syongari struct ifnet *ifp; 799170589Syongari uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 800170589Syongari uint32_t gmask, rxctl, txctl, val; 801159952Sobrien 802170589Syongari sc = (struct nfe_softc *)arg; 803170589Syongari 804170589Syongari NFE_LOCK(sc); 805170589Syongari 806159967Sobrien mii = device_get_softc(sc->nfe_miibus); 807170589Syongari ifp = sc->nfe_ifp; 808170589Syongari if (mii == NULL || ifp == NULL) { 809170589Syongari NFE_UNLOCK(sc); 810170589Syongari return; 811170589Syongari } 812159967Sobrien 813170589Syongari if (mii->mii_media_status & IFM_ACTIVE) { 814170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) 815170589Syongari sc->nfe_link = 1; 816170589Syongari } else 817170589Syongari sc->nfe_link = 0; 818170589Syongari 819159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 820159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 821159952Sobrien 822159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 823159952Sobrien seed &= ~NFE_SEED_MASK; 824159952Sobrien 825170589Syongari if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) == 0) { 826159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 827159952Sobrien misc |= NFE_MISC1_HDX; 828159952Sobrien } 829159952Sobrien 830159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 831159952Sobrien case IFM_1000_T: /* full-duplex only */ 832159952Sobrien link |= NFE_MEDIA_1000T; 833159952Sobrien seed |= NFE_SEED_1000T; 834159952Sobrien phy |= NFE_PHY_1000T; 835159952Sobrien break; 836159952Sobrien case IFM_100_TX: 837159952Sobrien link |= NFE_MEDIA_100TX; 838159952Sobrien seed |= NFE_SEED_100TX; 839159952Sobrien phy |= NFE_PHY_100TX; 840159952Sobrien break; 841159952Sobrien case IFM_10_T: 842159952Sobrien link |= NFE_MEDIA_10T; 843159952Sobrien seed |= NFE_SEED_10T; 844159952Sobrien break; 845159952Sobrien } 846159952Sobrien 847170589Syongari if ((phy & 0x10000000) != 0) { 848170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 849170589Syongari val = NFE_R1_MAGIC_1000; 850170589Syongari else 851170589Syongari val = NFE_R1_MAGIC_10_100; 852170589Syongari } else 853170589Syongari val = NFE_R1_MAGIC_DEFAULT; 854170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, val); 855170589Syongari 856159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 857159952Sobrien 858159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 859159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 860159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 861170589Syongari 862170589Syongari gmask = mii->mii_media_active & IFM_GMASK; 863170589Syongari if ((gmask & IFM_FDX) != 0) { 864170589Syongari /* It seems all hardwares supports Rx pause frames. */ 865170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 866170589Syongari if ((gmask & IFM_FLAG0) != 0) 867170589Syongari val |= NFE_PFF_RX_PAUSE; 868170589Syongari else 869170589Syongari val &= ~NFE_PFF_RX_PAUSE; 870170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 871170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 872170589Syongari val = NFE_READ(sc, NFE_MISC1); 873170589Syongari if ((gmask & IFM_FLAG1) != 0) { 874170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 875170589Syongari NFE_TX_PAUSE_FRAME_ENABLE); 876170589Syongari val |= NFE_MISC1_TX_PAUSE; 877170589Syongari } else { 878170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 879170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 880170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 881170589Syongari } 882170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 883170589Syongari } 884170589Syongari } else { 885170589Syongari /* disable rx/tx pause frames */ 886170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 887170589Syongari val &= ~NFE_PFF_RX_PAUSE; 888170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 889170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 890170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 891170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 892170589Syongari val = NFE_READ(sc, NFE_MISC1); 893170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 894170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 895170589Syongari } 896170589Syongari } 897170589Syongari 898170589Syongari txctl = NFE_READ(sc, NFE_TX_CTL); 899170589Syongari rxctl = NFE_READ(sc, NFE_RX_CTL); 900170589Syongari if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 901170589Syongari txctl |= NFE_TX_START; 902170589Syongari rxctl |= NFE_RX_START; 903170589Syongari } else { 904170589Syongari txctl &= ~NFE_TX_START; 905170589Syongari rxctl &= ~NFE_RX_START; 906170589Syongari } 907172164Syongari NFE_WRITE(sc, NFE_TX_CTL, txctl); 908172164Syongari NFE_WRITE(sc, NFE_RX_CTL, rxctl); 909170589Syongari 910170589Syongari NFE_UNLOCK(sc); 911159952Sobrien} 912159952Sobrien 913163503Sobrien 914159967Sobrienstatic int 915159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg) 916159952Sobrien{ 917159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 918170589Syongari uint32_t val; 919159952Sobrien int ntries; 920159952Sobrien 921159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 922159952Sobrien 923159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 924159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 925159952Sobrien DELAY(100); 926159952Sobrien } 927159952Sobrien 928159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 929159952Sobrien 930170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 931159952Sobrien DELAY(100); 932159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 933159952Sobrien break; 934159952Sobrien } 935170589Syongari if (ntries == NFE_TIMEOUT) { 936170589Syongari DPRINTFN(sc, 2, "timeout waiting for PHY\n"); 937159952Sobrien return 0; 938159952Sobrien } 939159952Sobrien 940159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 941170589Syongari DPRINTFN(sc, 2, "could not read PHY\n"); 942159952Sobrien return 0; 943159952Sobrien } 944159952Sobrien 945159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 946159952Sobrien if (val != 0xffffffff && val != 0) 947159952Sobrien sc->mii_phyaddr = phy; 948159952Sobrien 949170589Syongari DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 950159952Sobrien 951170589Syongari return (val); 952159952Sobrien} 953159952Sobrien 954163503Sobrien 955159967Sobrienstatic int 956159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val) 957159952Sobrien{ 958159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 959170589Syongari uint32_t ctl; 960163503Sobrien int ntries; 961159952Sobrien 962159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 963159952Sobrien 964159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 965159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 966159952Sobrien DELAY(100); 967159952Sobrien } 968159952Sobrien 969159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 970159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 971159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 972159952Sobrien 973170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 974159952Sobrien DELAY(100); 975159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 976159952Sobrien break; 977159952Sobrien } 978159952Sobrien#ifdef NFE_DEBUG 979170589Syongari if (nfedebug >= 2 && ntries == NFE_TIMEOUT) 980170589Syongari device_printf(sc->nfe_dev, "could not write to PHY\n"); 981159952Sobrien#endif 982170589Syongari return (0); 983159952Sobrien} 984159952Sobrien 985170589Syongari/* 986170589Syongari * Allocate a jumbo buffer. 987170589Syongari */ 988170589Syongaristatic void * 989170589Syongarinfe_jalloc(struct nfe_softc *sc) 990170589Syongari{ 991170589Syongari struct nfe_jpool_entry *entry; 992163503Sobrien 993170589Syongari NFE_JLIST_LOCK(sc); 994170589Syongari 995170589Syongari entry = SLIST_FIRST(&sc->nfe_jfree_listhead); 996170589Syongari 997170589Syongari if (entry == NULL) { 998170589Syongari NFE_JLIST_UNLOCK(sc); 999170589Syongari return (NULL); 1000170589Syongari } 1001170589Syongari 1002170589Syongari SLIST_REMOVE_HEAD(&sc->nfe_jfree_listhead, jpool_entries); 1003170589Syongari SLIST_INSERT_HEAD(&sc->nfe_jinuse_listhead, entry, jpool_entries); 1004170589Syongari 1005170589Syongari NFE_JLIST_UNLOCK(sc); 1006170589Syongari 1007170589Syongari return (sc->jrxq.jslots[entry->slot]); 1008170589Syongari} 1009170589Syongari 1010170589Syongari/* 1011170589Syongari * Release a jumbo buffer. 1012170589Syongari */ 1013170589Syongaristatic void 1014170589Syongarinfe_jfree(void *buf, void *args) 1015170589Syongari{ 1016170589Syongari struct nfe_softc *sc; 1017170589Syongari struct nfe_jpool_entry *entry; 1018170589Syongari int i; 1019170589Syongari 1020170589Syongari /* Extract the softc struct pointer. */ 1021170589Syongari sc = (struct nfe_softc *)args; 1022170589Syongari KASSERT(sc != NULL, ("%s: can't find softc pointer!", __func__)); 1023170589Syongari 1024170589Syongari NFE_JLIST_LOCK(sc); 1025170589Syongari /* Calculate the slot this buffer belongs to. */ 1026170589Syongari i = ((vm_offset_t)buf 1027170589Syongari - (vm_offset_t)sc->jrxq.jpool) / NFE_JLEN; 1028170589Syongari KASSERT(i >= 0 && i < NFE_JSLOTS, 1029170589Syongari ("%s: asked to free buffer that we don't manage!", __func__)); 1030170589Syongari 1031170589Syongari entry = SLIST_FIRST(&sc->nfe_jinuse_listhead); 1032170589Syongari KASSERT(entry != NULL, ("%s: buffer not in use!", __func__)); 1033170589Syongari entry->slot = i; 1034170589Syongari SLIST_REMOVE_HEAD(&sc->nfe_jinuse_listhead, jpool_entries); 1035170589Syongari SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry, jpool_entries); 1036170589Syongari if (SLIST_EMPTY(&sc->nfe_jinuse_listhead)) 1037170589Syongari wakeup(sc); 1038170589Syongari 1039170589Syongari NFE_JLIST_UNLOCK(sc); 1040170589Syongari} 1041170589Syongari 1042170589Syongaristruct nfe_dmamap_arg { 1043170589Syongari bus_addr_t nfe_busaddr; 1044170589Syongari}; 1045170589Syongari 1046159967Sobrienstatic int 1047159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1048159952Sobrien{ 1049170589Syongari struct nfe_dmamap_arg ctx; 1050159967Sobrien struct nfe_rx_data *data; 1051170589Syongari void *desc; 1052159967Sobrien int i, error, descsize; 1053159967Sobrien 1054159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1055170589Syongari desc = ring->desc64; 1056159967Sobrien descsize = sizeof (struct nfe_desc64); 1057159967Sobrien } else { 1058170589Syongari desc = ring->desc32; 1059159967Sobrien descsize = sizeof (struct nfe_desc32); 1060159967Sobrien } 1061159967Sobrien 1062159967Sobrien ring->cur = ring->next = 0; 1063159967Sobrien 1064163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1065170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1066170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1067170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1068170589Syongari NULL, NULL, /* filter, filterarg */ 1069170589Syongari NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1070170589Syongari NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 1071170589Syongari 0, /* flags */ 1072170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1073170589Syongari &ring->rx_desc_tag); 1074159967Sobrien if (error != 0) { 1075170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1076159967Sobrien goto fail; 1077159967Sobrien } 1078159967Sobrien 1079159967Sobrien /* allocate memory to desc */ 1080170589Syongari error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK | 1081170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map); 1082159967Sobrien if (error != 0) { 1083170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1084159967Sobrien goto fail; 1085159967Sobrien } 1086170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1087170589Syongari ring->desc64 = desc; 1088170589Syongari else 1089170589Syongari ring->desc32 = desc; 1090159967Sobrien 1091159967Sobrien /* map desc to device visible address space */ 1092170589Syongari ctx.nfe_busaddr = 0; 1093170589Syongari error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc, 1094170589Syongari NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1095159967Sobrien if (error != 0) { 1096170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1097159967Sobrien goto fail; 1098159967Sobrien } 1099170589Syongari ring->physaddr = ctx.nfe_busaddr; 1100159967Sobrien 1101170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1102170589Syongari 1, 0, /* alignment, boundary */ 1103170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1104170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1105170589Syongari NULL, NULL, /* filter, filterarg */ 1106170589Syongari MCLBYTES, 1, /* maxsize, nsegments */ 1107170589Syongari MCLBYTES, /* maxsegsize */ 1108170589Syongari 0, /* flags */ 1109170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1110170589Syongari &ring->rx_data_tag); 1111170589Syongari if (error != 0) { 1112170589Syongari device_printf(sc->nfe_dev, "could not create Rx DMA tag\n"); 1113170589Syongari goto fail; 1114170589Syongari } 1115159967Sobrien 1116170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map); 1117170589Syongari if (error != 0) { 1118170589Syongari device_printf(sc->nfe_dev, 1119170589Syongari "could not create Rx DMA spare map\n"); 1120170589Syongari goto fail; 1121170589Syongari } 1122170589Syongari 1123159967Sobrien /* 1124159967Sobrien * Pre-allocate Rx buffers and populate Rx ring. 1125159967Sobrien */ 1126159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1127159967Sobrien data = &sc->rxq.data[i]; 1128170589Syongari data->rx_data_map = NULL; 1129170589Syongari data->m = NULL; 1130170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, 1131170589Syongari &data->rx_data_map); 1132164651Sobrien if (error != 0) { 1133170589Syongari device_printf(sc->nfe_dev, 1134170589Syongari "could not create Rx DMA map\n"); 1135164651Sobrien goto fail; 1136164651Sobrien } 1137170589Syongari } 1138159967Sobrien 1139170589Syongarifail: 1140170589Syongari return (error); 1141170589Syongari} 1142170589Syongari 1143170589Syongari 1144171559Syongaristatic void 1145170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1146170589Syongari{ 1147170589Syongari struct nfe_dmamap_arg ctx; 1148170589Syongari struct nfe_rx_data *data; 1149170589Syongari void *desc; 1150170589Syongari struct nfe_jpool_entry *entry; 1151170589Syongari uint8_t *ptr; 1152170589Syongari int i, error, descsize; 1153170589Syongari 1154170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1155171559Syongari return; 1156171559Syongari if (jumbo_disable != 0) { 1157171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support\n"); 1158171559Syongari sc->nfe_jumbo_disable = 1; 1159171559Syongari return; 1160171559Syongari } 1161170589Syongari 1162170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1163170589Syongari desc = ring->jdesc64; 1164170589Syongari descsize = sizeof (struct nfe_desc64); 1165170589Syongari } else { 1166170589Syongari desc = ring->jdesc32; 1167170589Syongari descsize = sizeof (struct nfe_desc32); 1168170589Syongari } 1169170589Syongari 1170170589Syongari ring->jcur = ring->jnext = 0; 1171170589Syongari 1172170589Syongari /* Create DMA tag for jumbo Rx ring. */ 1173170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1174170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1175170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1176170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1177170589Syongari NULL, NULL, /* filter, filterarg */ 1178170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsize */ 1179170589Syongari 1, /* nsegments */ 1180170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsegsize */ 1181170589Syongari 0, /* flags */ 1182170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1183170589Syongari &ring->jrx_desc_tag); 1184170589Syongari if (error != 0) { 1185170589Syongari device_printf(sc->nfe_dev, 1186170589Syongari "could not create jumbo ring DMA tag\n"); 1187170589Syongari goto fail; 1188170589Syongari } 1189170589Syongari 1190170589Syongari /* Create DMA tag for jumbo buffer blocks. */ 1191170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1192170589Syongari PAGE_SIZE, 0, /* alignment, boundary */ 1193170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1194170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1195170589Syongari NULL, NULL, /* filter, filterarg */ 1196170589Syongari NFE_JMEM, /* maxsize */ 1197170589Syongari 1, /* nsegments */ 1198170589Syongari NFE_JMEM, /* maxsegsize */ 1199170589Syongari 0, /* flags */ 1200170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1201170589Syongari &ring->jrx_jumbo_tag); 1202170589Syongari if (error != 0) { 1203170589Syongari device_printf(sc->nfe_dev, 1204170589Syongari "could not create jumbo Rx buffer block DMA tag\n"); 1205170589Syongari goto fail; 1206170589Syongari } 1207170589Syongari 1208170589Syongari /* Create DMA tag for jumbo Rx buffers. */ 1209170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1210170589Syongari PAGE_SIZE, 0, /* alignment, boundary */ 1211170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1212170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1213170589Syongari NULL, NULL, /* filter, filterarg */ 1214170589Syongari NFE_JLEN, /* maxsize */ 1215170589Syongari 1, /* nsegments */ 1216170589Syongari NFE_JLEN, /* maxsegsize */ 1217170589Syongari 0, /* flags */ 1218170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1219170589Syongari &ring->jrx_data_tag); 1220170589Syongari if (error != 0) { 1221170589Syongari device_printf(sc->nfe_dev, 1222170589Syongari "could not create jumbo Rx buffer DMA tag\n"); 1223170589Syongari goto fail; 1224170589Syongari } 1225170589Syongari 1226170589Syongari /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ 1227170589Syongari error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK | 1228170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map); 1229170589Syongari if (error != 0) { 1230170589Syongari device_printf(sc->nfe_dev, 1231170589Syongari "could not allocate DMA'able memory for jumbo Rx ring\n"); 1232170589Syongari goto fail; 1233170589Syongari } 1234170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1235170589Syongari ring->jdesc64 = desc; 1236170589Syongari else 1237170589Syongari ring->jdesc32 = desc; 1238170589Syongari 1239170589Syongari ctx.nfe_busaddr = 0; 1240170589Syongari error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc, 1241170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1242170589Syongari if (error != 0) { 1243170589Syongari device_printf(sc->nfe_dev, 1244170589Syongari "could not load DMA'able memory for jumbo Rx ring\n"); 1245170589Syongari goto fail; 1246170589Syongari } 1247170589Syongari ring->jphysaddr = ctx.nfe_busaddr; 1248170589Syongari 1249170589Syongari /* Create DMA maps for jumbo Rx buffers. */ 1250170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map); 1251170589Syongari if (error != 0) { 1252170589Syongari device_printf(sc->nfe_dev, 1253170589Syongari "could not create jumbo Rx DMA spare map\n"); 1254170589Syongari goto fail; 1255170589Syongari } 1256170589Syongari 1257170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1258170589Syongari data = &sc->jrxq.jdata[i]; 1259170589Syongari data->rx_data_map = NULL; 1260170589Syongari data->m = NULL; 1261170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, 1262164651Sobrien &data->rx_data_map); 1263164651Sobrien if (error != 0) { 1264170589Syongari device_printf(sc->nfe_dev, 1265170589Syongari "could not create jumbo Rx DMA map\n"); 1266164651Sobrien goto fail; 1267164651Sobrien } 1268170589Syongari } 1269159967Sobrien 1270170589Syongari /* Allocate DMA'able memory and load the DMA map for jumbo buf. */ 1271170589Syongari error = bus_dmamem_alloc(ring->jrx_jumbo_tag, (void **)&ring->jpool, 1272170589Syongari BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, 1273170589Syongari &ring->jrx_jumbo_map); 1274170589Syongari if (error != 0) { 1275170589Syongari device_printf(sc->nfe_dev, 1276170589Syongari "could not allocate DMA'able memory for jumbo pool\n"); 1277170589Syongari goto fail; 1278170589Syongari } 1279170589Syongari 1280170589Syongari ctx.nfe_busaddr = 0; 1281170589Syongari error = bus_dmamap_load(ring->jrx_jumbo_tag, ring->jrx_jumbo_map, 1282170589Syongari ring->jpool, NFE_JMEM, nfe_dma_map_segs, &ctx, 0); 1283170589Syongari if (error != 0) { 1284170589Syongari device_printf(sc->nfe_dev, 1285170589Syongari "could not load DMA'able memory for jumbo pool\n"); 1286170589Syongari goto fail; 1287170589Syongari } 1288170589Syongari 1289170589Syongari /* 1290170589Syongari * Now divide it up into 9K pieces and save the addresses 1291170589Syongari * in an array. 1292170589Syongari */ 1293170589Syongari ptr = ring->jpool; 1294170589Syongari for (i = 0; i < NFE_JSLOTS; i++) { 1295170589Syongari ring->jslots[i] = ptr; 1296170589Syongari ptr += NFE_JLEN; 1297170589Syongari entry = malloc(sizeof(struct nfe_jpool_entry), M_DEVBUF, 1298170589Syongari M_WAITOK); 1299170589Syongari if (entry == NULL) { 1300170589Syongari device_printf(sc->nfe_dev, 1301170589Syongari "no memory for jumbo buffers!\n"); 1302164651Sobrien error = ENOMEM; 1303164651Sobrien goto fail; 1304164651Sobrien } 1305170589Syongari entry->slot = i; 1306170589Syongari SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry, 1307170589Syongari jpool_entries); 1308170589Syongari } 1309159967Sobrien 1310171559Syongari return; 1311159967Sobrien 1312170589Syongarifail: 1313171559Syongari /* 1314171559Syongari * Running without jumbo frame support is ok for most cases 1315171559Syongari * so don't fail on creating dma tag/map for jumbo frame. 1316171559Syongari */ 1317170589Syongari nfe_free_jrx_ring(sc, ring); 1318171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support due to " 1319171559Syongari "resource shortage\n"); 1320171559Syongari sc->nfe_jumbo_disable = 1; 1321170589Syongari} 1322159967Sobrien 1323159967Sobrien 1324170589Syongaristatic int 1325170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1326170589Syongari{ 1327170589Syongari void *desc; 1328170589Syongari size_t descsize; 1329170589Syongari int i; 1330159967Sobrien 1331170589Syongari ring->cur = ring->next = 0; 1332170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1333170589Syongari desc = ring->desc64; 1334170589Syongari descsize = sizeof (struct nfe_desc64); 1335170589Syongari } else { 1336170589Syongari desc = ring->desc32; 1337170589Syongari descsize = sizeof (struct nfe_desc32); 1338159967Sobrien } 1339170589Syongari bzero(desc, descsize * NFE_RX_RING_COUNT); 1340170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1341170589Syongari if (nfe_newbuf(sc, i) != 0) 1342170589Syongari return (ENOBUFS); 1343170589Syongari } 1344159967Sobrien 1345163503Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 1346170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1347159967Sobrien 1348170589Syongari return (0); 1349159967Sobrien} 1350159967Sobrien 1351163503Sobrien 1352170589Syongaristatic int 1353170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1354159967Sobrien{ 1355170589Syongari void *desc; 1356170589Syongari size_t descsize; 1357159967Sobrien int i; 1358159967Sobrien 1359170589Syongari ring->jcur = ring->jnext = 0; 1360170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1361170589Syongari desc = ring->jdesc64; 1362170589Syongari descsize = sizeof (struct nfe_desc64); 1363170589Syongari } else { 1364170589Syongari desc = ring->jdesc32; 1365170589Syongari descsize = sizeof (struct nfe_desc32); 1366159952Sobrien } 1367170589Syongari bzero(desc, descsize * NFE_RX_RING_COUNT); 1368170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1369170589Syongari if (nfe_jnewbuf(sc, i) != 0) 1370170589Syongari return (ENOBUFS); 1371170589Syongari } 1372159952Sobrien 1373170589Syongari bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map, 1374170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1375159952Sobrien 1376170589Syongari return (0); 1377159967Sobrien} 1378159967Sobrien 1379159967Sobrien 1380159967Sobrienstatic void 1381159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1382159967Sobrien{ 1383159967Sobrien struct nfe_rx_data *data; 1384159967Sobrien void *desc; 1385159967Sobrien int i, descsize; 1386159967Sobrien 1387159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1388159967Sobrien desc = ring->desc64; 1389159967Sobrien descsize = sizeof (struct nfe_desc64); 1390159967Sobrien } else { 1391159967Sobrien desc = ring->desc32; 1392159967Sobrien descsize = sizeof (struct nfe_desc32); 1393159952Sobrien } 1394159952Sobrien 1395170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1396170589Syongari data = &ring->data[i]; 1397170589Syongari if (data->rx_data_map != NULL) { 1398170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1399170589Syongari data->rx_data_map); 1400170589Syongari data->rx_data_map = NULL; 1401170589Syongari } 1402170589Syongari if (data->m != NULL) { 1403170589Syongari m_freem(data->m); 1404170589Syongari data->m = NULL; 1405170589Syongari } 1406170589Syongari } 1407170589Syongari if (ring->rx_data_tag != NULL) { 1408170589Syongari if (ring->rx_spare_map != NULL) { 1409170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1410170589Syongari ring->rx_spare_map); 1411170589Syongari ring->rx_spare_map = NULL; 1412170589Syongari } 1413170589Syongari bus_dma_tag_destroy(ring->rx_data_tag); 1414170589Syongari ring->rx_data_tag = NULL; 1415170589Syongari } 1416170589Syongari 1417159967Sobrien if (desc != NULL) { 1418159967Sobrien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 1419159967Sobrien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 1420170589Syongari ring->desc64 = NULL; 1421170589Syongari ring->desc32 = NULL; 1422170589Syongari ring->rx_desc_map = NULL; 1423170589Syongari } 1424170589Syongari if (ring->rx_desc_tag != NULL) { 1425159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 1426170589Syongari ring->rx_desc_tag = NULL; 1427159967Sobrien } 1428170589Syongari} 1429159967Sobrien 1430164650Sobrien 1431170589Syongaristatic void 1432170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1433170589Syongari{ 1434170589Syongari struct nfe_jpool_entry *entry; 1435170589Syongari struct nfe_rx_data *data; 1436170589Syongari void *desc; 1437170589Syongari int i, descsize; 1438170589Syongari 1439170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1440170589Syongari return; 1441170589Syongari 1442170589Syongari NFE_JLIST_LOCK(sc); 1443170589Syongari while ((entry = SLIST_FIRST(&sc->nfe_jinuse_listhead))) { 1444170589Syongari device_printf(sc->nfe_dev, 1445170589Syongari "asked to free buffer that is in use!\n"); 1446170589Syongari SLIST_REMOVE_HEAD(&sc->nfe_jinuse_listhead, jpool_entries); 1447170589Syongari SLIST_INSERT_HEAD(&sc->nfe_jfree_listhead, entry, 1448170589Syongari jpool_entries); 1449170589Syongari } 1450170589Syongari 1451170589Syongari while (!SLIST_EMPTY(&sc->nfe_jfree_listhead)) { 1452170589Syongari entry = SLIST_FIRST(&sc->nfe_jfree_listhead); 1453170589Syongari SLIST_REMOVE_HEAD(&sc->nfe_jfree_listhead, jpool_entries); 1454170589Syongari free(entry, M_DEVBUF); 1455170589Syongari } 1456170589Syongari NFE_JLIST_UNLOCK(sc); 1457170589Syongari 1458170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1459170589Syongari desc = ring->jdesc64; 1460170589Syongari descsize = sizeof (struct nfe_desc64); 1461170589Syongari } else { 1462170589Syongari desc = ring->jdesc32; 1463170589Syongari descsize = sizeof (struct nfe_desc32); 1464170589Syongari } 1465170589Syongari 1466170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1467170589Syongari data = &ring->jdata[i]; 1468164651Sobrien if (data->rx_data_map != NULL) { 1469170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1470164651Sobrien data->rx_data_map); 1471170589Syongari data->rx_data_map = NULL; 1472164651Sobrien } 1473170589Syongari if (data->m != NULL) { 1474164651Sobrien m_freem(data->m); 1475170589Syongari data->m = NULL; 1476170589Syongari } 1477164651Sobrien } 1478170589Syongari if (ring->jrx_data_tag != NULL) { 1479170589Syongari if (ring->jrx_spare_map != NULL) { 1480170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1481170589Syongari ring->jrx_spare_map); 1482170589Syongari ring->jrx_spare_map = NULL; 1483170589Syongari } 1484170589Syongari bus_dma_tag_destroy(ring->jrx_data_tag); 1485170589Syongari ring->jrx_data_tag = NULL; 1486170589Syongari } 1487170589Syongari 1488170589Syongari if (desc != NULL) { 1489170589Syongari bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1490170589Syongari bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1491170589Syongari ring->jdesc64 = NULL; 1492170589Syongari ring->jdesc32 = NULL; 1493170589Syongari ring->jrx_desc_map = NULL; 1494170589Syongari } 1495170589Syongari /* Destroy jumbo buffer block. */ 1496170589Syongari if (ring->jrx_jumbo_map != NULL) 1497170589Syongari bus_dmamap_unload(ring->jrx_jumbo_tag, ring->jrx_jumbo_map); 1498170589Syongari if (ring->jrx_jumbo_map != NULL) { 1499170589Syongari bus_dmamem_free(ring->jrx_jumbo_tag, ring->jpool, 1500170589Syongari ring->jrx_jumbo_map); 1501170589Syongari ring->jpool = NULL; 1502170589Syongari ring->jrx_jumbo_map = NULL; 1503170589Syongari } 1504170589Syongari if (ring->jrx_desc_tag != NULL) { 1505170589Syongari bus_dma_tag_destroy(ring->jrx_desc_tag); 1506170589Syongari ring->jrx_desc_tag = NULL; 1507170589Syongari } 1508159952Sobrien} 1509159952Sobrien 1510163503Sobrien 1511159967Sobrienstatic int 1512159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1513159952Sobrien{ 1514170589Syongari struct nfe_dmamap_arg ctx; 1515159967Sobrien int i, error; 1516170589Syongari void *desc; 1517159967Sobrien int descsize; 1518159952Sobrien 1519159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1520170589Syongari desc = ring->desc64; 1521159967Sobrien descsize = sizeof (struct nfe_desc64); 1522159967Sobrien } else { 1523170589Syongari desc = ring->desc32; 1524159967Sobrien descsize = sizeof (struct nfe_desc32); 1525159967Sobrien } 1526159952Sobrien 1527159967Sobrien ring->queued = 0; 1528159967Sobrien ring->cur = ring->next = 0; 1529159967Sobrien 1530163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1531170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1532170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1533170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1534170589Syongari NULL, NULL, /* filter, filterarg */ 1535170589Syongari NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1536170589Syongari NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1537170589Syongari 0, /* flags */ 1538170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1539170589Syongari &ring->tx_desc_tag); 1540159967Sobrien if (error != 0) { 1541170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1542159967Sobrien goto fail; 1543159952Sobrien } 1544159952Sobrien 1545170589Syongari error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1546170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1547159967Sobrien if (error != 0) { 1548170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1549159967Sobrien goto fail; 1550159967Sobrien } 1551170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1552170589Syongari ring->desc64 = desc; 1553170589Syongari else 1554170589Syongari ring->desc32 = desc; 1555159967Sobrien 1556170589Syongari ctx.nfe_busaddr = 0; 1557170589Syongari error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1558170589Syongari NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1559159967Sobrien if (error != 0) { 1560170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1561159967Sobrien goto fail; 1562159967Sobrien } 1563170589Syongari ring->physaddr = ctx.nfe_busaddr; 1564159967Sobrien 1565163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1566170589Syongari 1, 0, 1567170589Syongari BUS_SPACE_MAXADDR, 1568170589Syongari BUS_SPACE_MAXADDR, 1569170589Syongari NULL, NULL, 1570170595Syongari NFE_TSO_MAXSIZE, 1571170589Syongari NFE_MAX_SCATTER, 1572170595Syongari NFE_TSO_MAXSGSIZE, 1573170589Syongari 0, 1574170589Syongari NULL, NULL, 1575170589Syongari &ring->tx_data_tag); 1576159967Sobrien if (error != 0) { 1577170589Syongari device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1578170589Syongari goto fail; 1579159967Sobrien } 1580159967Sobrien 1581159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1582163503Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, 1583163503Sobrien &ring->data[i].tx_data_map); 1584159967Sobrien if (error != 0) { 1585170589Syongari device_printf(sc->nfe_dev, 1586170589Syongari "could not create Tx DMA map\n"); 1587159967Sobrien goto fail; 1588159967Sobrien } 1589159967Sobrien } 1590159967Sobrien 1591170589Syongarifail: 1592170589Syongari return (error); 1593159967Sobrien} 1594159967Sobrien 1595159967Sobrien 1596159967Sobrienstatic void 1597170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1598159967Sobrien{ 1599170589Syongari void *desc; 1600170589Syongari size_t descsize; 1601159967Sobrien 1602170589Syongari sc->nfe_force_tx = 0; 1603170589Syongari ring->queued = 0; 1604170589Syongari ring->cur = ring->next = 0; 1605170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1606170589Syongari desc = ring->desc64; 1607170589Syongari descsize = sizeof (struct nfe_desc64); 1608170589Syongari } else { 1609170589Syongari desc = ring->desc32; 1610170589Syongari descsize = sizeof (struct nfe_desc32); 1611159967Sobrien } 1612170589Syongari bzero(desc, descsize * NFE_TX_RING_COUNT); 1613159967Sobrien 1614163503Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1615170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1616159967Sobrien} 1617159967Sobrien 1618163503Sobrien 1619159967Sobrienstatic void 1620159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1621159967Sobrien{ 1622159967Sobrien struct nfe_tx_data *data; 1623159967Sobrien void *desc; 1624159967Sobrien int i, descsize; 1625159967Sobrien 1626159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1627159967Sobrien desc = ring->desc64; 1628159967Sobrien descsize = sizeof (struct nfe_desc64); 1629159967Sobrien } else { 1630159967Sobrien desc = ring->desc32; 1631159967Sobrien descsize = sizeof (struct nfe_desc32); 1632159967Sobrien } 1633159967Sobrien 1634159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1635159967Sobrien data = &ring->data[i]; 1636159967Sobrien 1637159967Sobrien if (data->m != NULL) { 1638170589Syongari bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1639163503Sobrien BUS_DMASYNC_POSTWRITE); 1640170589Syongari bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1641159967Sobrien m_freem(data->m); 1642170589Syongari data->m = NULL; 1643159967Sobrien } 1644170589Syongari if (data->tx_data_map != NULL) { 1645170589Syongari bus_dmamap_destroy(ring->tx_data_tag, 1646170589Syongari data->tx_data_map); 1647170589Syongari data->tx_data_map = NULL; 1648170589Syongari } 1649159967Sobrien } 1650159967Sobrien 1651170589Syongari if (ring->tx_data_tag != NULL) { 1652170589Syongari bus_dma_tag_destroy(ring->tx_data_tag); 1653170589Syongari ring->tx_data_tag = NULL; 1654159967Sobrien } 1655159967Sobrien 1656170589Syongari if (desc != NULL) { 1657170589Syongari bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1658170589Syongari BUS_DMASYNC_POSTWRITE); 1659170589Syongari bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1660170589Syongari bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1661170589Syongari ring->desc64 = NULL; 1662170589Syongari ring->desc32 = NULL; 1663170589Syongari ring->tx_desc_map = NULL; 1664170589Syongari bus_dma_tag_destroy(ring->tx_desc_tag); 1665170589Syongari ring->tx_desc_tag = NULL; 1666170589Syongari } 1667159967Sobrien} 1668159967Sobrien 1669159967Sobrien#ifdef DEVICE_POLLING 1670159967Sobrienstatic poll_handler_t nfe_poll; 1671159967Sobrien 1672163503Sobrien 1673159967Sobrienstatic void 1674159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1675159967Sobrien{ 1676164360Sobrien struct nfe_softc *sc = ifp->if_softc; 1677170589Syongari uint32_t r; 1678159967Sobrien 1679159967Sobrien NFE_LOCK(sc); 1680159967Sobrien 1681159967Sobrien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1682170589Syongari NFE_UNLOCK(sc); 1683159967Sobrien return; 1684159967Sobrien } 1685159967Sobrien 1686171559Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1687171559Syongari nfe_jrxeof(sc, count); 1688171559Syongari else 1689171559Syongari nfe_rxeof(sc, count); 1690159967Sobrien nfe_txeof(sc); 1691159967Sobrien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1692170589Syongari taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_tx_task); 1693159967Sobrien 1694159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1695170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1696170589Syongari NFE_UNLOCK(sc); 1697163503Sobrien return; 1698163503Sobrien } 1699170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1700159967Sobrien 1701163503Sobrien if (r & NFE_IRQ_LINK) { 1702163503Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1703163503Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1704170589Syongari DPRINTF(sc, "link state changed\n"); 1705163503Sobrien } 1706159967Sobrien } 1707170589Syongari NFE_UNLOCK(sc); 1708159967Sobrien} 1709159967Sobrien#endif /* DEVICE_POLLING */ 1710159967Sobrien 1711170589Syongaristatic void 1712170589Syongarinfe_set_intr(struct nfe_softc *sc) 1713170589Syongari{ 1714159967Sobrien 1715170589Syongari if (sc->nfe_msi != 0) 1716170589Syongari NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1717170589Syongari} 1718170589Syongari 1719170589Syongari 1720170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */ 1721170589Syongaristatic __inline void 1722170589Syongarinfe_enable_intr(struct nfe_softc *sc) 1723170589Syongari{ 1724170589Syongari 1725170589Syongari if (sc->nfe_msix != 0) { 1726170589Syongari /* XXX Should have a better way to enable interrupts! */ 1727170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1728170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1729170589Syongari } else 1730170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1731170589Syongari} 1732170589Syongari 1733170589Syongari 1734170589Syongaristatic __inline void 1735170589Syongarinfe_disable_intr(struct nfe_softc *sc) 1736170589Syongari{ 1737170589Syongari 1738170589Syongari if (sc->nfe_msix != 0) { 1739170589Syongari /* XXX Should have a better way to disable interrupts! */ 1740170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1741170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1742170589Syongari } else 1743170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1744170589Syongari} 1745170589Syongari 1746170589Syongari 1747159967Sobrienstatic int 1748159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1749159967Sobrien{ 1750170589Syongari struct nfe_softc *sc; 1751170589Syongari struct ifreq *ifr; 1752163503Sobrien struct mii_data *mii; 1753170589Syongari int error, init, mask; 1754159967Sobrien 1755170589Syongari sc = ifp->if_softc; 1756170589Syongari ifr = (struct ifreq *) data; 1757170589Syongari error = 0; 1758170589Syongari init = 0; 1759159952Sobrien switch (cmd) { 1760159952Sobrien case SIOCSIFMTU: 1761170589Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1762159952Sobrien error = EINVAL; 1763170589Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 1764171559Syongari if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) || 1765171559Syongari (sc->nfe_jumbo_disable != 0)) && 1766170589Syongari ifr->ifr_mtu > ETHERMTU) 1767170589Syongari error = EINVAL; 1768170589Syongari else { 1769170589Syongari NFE_LOCK(sc); 1770170589Syongari ifp->if_mtu = ifr->ifr_mtu; 1771170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1772170589Syongari nfe_init_locked(sc); 1773170589Syongari NFE_UNLOCK(sc); 1774164650Sobrien } 1775164650Sobrien } 1776159952Sobrien break; 1777159952Sobrien case SIOCSIFFLAGS: 1778159967Sobrien NFE_LOCK(sc); 1779159952Sobrien if (ifp->if_flags & IFF_UP) { 1780159952Sobrien /* 1781159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1782159952Sobrien * don't do a full re-init of the chip, just update 1783159952Sobrien * the Rx filter. 1784159952Sobrien */ 1785159967Sobrien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1786159967Sobrien ((ifp->if_flags ^ sc->nfe_if_flags) & 1787159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1788159952Sobrien nfe_setmulti(sc); 1789159967Sobrien else 1790159967Sobrien nfe_init_locked(sc); 1791159952Sobrien } else { 1792159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1793170589Syongari nfe_stop(ifp); 1794159952Sobrien } 1795159967Sobrien sc->nfe_if_flags = ifp->if_flags; 1796159967Sobrien NFE_UNLOCK(sc); 1797159967Sobrien error = 0; 1798159952Sobrien break; 1799159952Sobrien case SIOCADDMULTI: 1800159952Sobrien case SIOCDELMULTI: 1801170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1802159967Sobrien NFE_LOCK(sc); 1803159967Sobrien nfe_setmulti(sc); 1804159967Sobrien NFE_UNLOCK(sc); 1805159952Sobrien error = 0; 1806159952Sobrien } 1807159952Sobrien break; 1808159952Sobrien case SIOCSIFMEDIA: 1809159952Sobrien case SIOCGIFMEDIA: 1810159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1811159967Sobrien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1812159952Sobrien break; 1813159967Sobrien case SIOCSIFCAP: 1814170589Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1815159967Sobrien#ifdef DEVICE_POLLING 1816170589Syongari if ((mask & IFCAP_POLLING) != 0) { 1817170589Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1818159967Sobrien error = ether_poll_register(nfe_poll, ifp); 1819159967Sobrien if (error) 1820170589Syongari break; 1821159967Sobrien NFE_LOCK(sc); 1822170589Syongari nfe_disable_intr(sc); 1823163503Sobrien ifp->if_capenable |= IFCAP_POLLING; 1824159967Sobrien NFE_UNLOCK(sc); 1825159967Sobrien } else { 1826159967Sobrien error = ether_poll_deregister(ifp); 1827159967Sobrien /* Enable interrupt even in error case */ 1828159967Sobrien NFE_LOCK(sc); 1829170589Syongari nfe_enable_intr(sc); 1830159967Sobrien ifp->if_capenable &= ~IFCAP_POLLING; 1831159967Sobrien NFE_UNLOCK(sc); 1832159967Sobrien } 1833159967Sobrien } 1834163503Sobrien#endif /* DEVICE_POLLING */ 1835170589Syongari if ((sc->nfe_flags & NFE_HW_CSUM) != 0 && 1836170589Syongari (mask & IFCAP_HWCSUM) != 0) { 1837159967Sobrien ifp->if_capenable ^= IFCAP_HWCSUM; 1838170589Syongari if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 && 1839170589Syongari (IFCAP_TXCSUM & ifp->if_capabilities) != 0) 1840170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES; 1841159967Sobrien else 1842170589Syongari ifp->if_hwassist &= ~NFE_CSUM_FEATURES; 1843170589Syongari init++; 1844159967Sobrien } 1845170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0 && 1846170589Syongari (mask & IFCAP_VLAN_HWTAGGING) != 0) { 1847170589Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1848170589Syongari init++; 1849170589Syongari } 1850170589Syongari /* 1851170589Syongari * XXX 1852170589Syongari * It seems that VLAN stripping requires Rx checksum offload. 1853170589Syongari * Unfortunately FreeBSD has no way to disable only Rx side 1854170589Syongari * VLAN stripping. So when we know Rx checksum offload is 1855170589Syongari * disabled turn entire hardware VLAN assist off. 1856170589Syongari */ 1857170589Syongari if ((sc->nfe_flags & (NFE_HW_CSUM | NFE_HW_VLAN)) == 1858170589Syongari (NFE_HW_CSUM | NFE_HW_VLAN)) { 1859170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) 1860170589Syongari ifp->if_capenable &= ~IFCAP_VLAN_HWTAGGING; 1861170589Syongari } 1862170589Syongari 1863170589Syongari if ((sc->nfe_flags & NFE_HW_CSUM) != 0 && 1864170589Syongari (mask & IFCAP_TSO4) != 0) { 1865170589Syongari ifp->if_capenable ^= IFCAP_TSO4; 1866170589Syongari if ((IFCAP_TSO4 & ifp->if_capenable) != 0 && 1867170589Syongari (IFCAP_TSO4 & ifp->if_capabilities) != 0) 1868170589Syongari ifp->if_hwassist |= CSUM_TSO; 1869170589Syongari else 1870170589Syongari ifp->if_hwassist &= ~CSUM_TSO; 1871170589Syongari } 1872170589Syongari 1873170589Syongari if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1874170589Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1875164656Sobrien nfe_init(sc); 1876170589Syongari } 1877170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) 1878170589Syongari VLAN_CAPABILITIES(ifp); 1879159967Sobrien break; 1880159952Sobrien default: 1881159967Sobrien error = ether_ioctl(ifp, cmd, data); 1882159967Sobrien break; 1883159952Sobrien } 1884159952Sobrien 1885170589Syongari return (error); 1886159952Sobrien} 1887159952Sobrien 1888159967Sobrien 1889170589Syongaristatic int 1890163503Sobriennfe_intr(void *arg) 1891159967Sobrien{ 1892170589Syongari struct nfe_softc *sc; 1893170589Syongari uint32_t status; 1894170589Syongari 1895170589Syongari sc = (struct nfe_softc *)arg; 1896170589Syongari 1897170589Syongari status = NFE_READ(sc, sc->nfe_irq_status); 1898170589Syongari if (status == 0 || status == 0xffffffff) 1899170589Syongari return (FILTER_STRAY); 1900170589Syongari nfe_disable_intr(sc); 1901170589Syongari taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_int_task); 1902170589Syongari 1903170589Syongari return (FILTER_HANDLED); 1904170589Syongari} 1905170589Syongari 1906170589Syongari 1907170589Syongaristatic void 1908170589Syongarinfe_int_task(void *arg, int pending) 1909170589Syongari{ 1910159967Sobrien struct nfe_softc *sc = arg; 1911159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1912170589Syongari uint32_t r; 1913170589Syongari int domore; 1914159967Sobrien 1915163503Sobrien NFE_LOCK(sc); 1916159967Sobrien 1917170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1918170589Syongari nfe_enable_intr(sc); 1919170589Syongari NFE_UNLOCK(sc); 1920170589Syongari return; /* not for us */ 1921170589Syongari } 1922170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1923170589Syongari 1924170589Syongari DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1925170589Syongari 1926159967Sobrien#ifdef DEVICE_POLLING 1927159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) { 1928159967Sobrien NFE_UNLOCK(sc); 1929159967Sobrien return; 1930159967Sobrien } 1931159967Sobrien#endif 1932159967Sobrien 1933170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1934163503Sobrien NFE_UNLOCK(sc); 1935170589Syongari nfe_enable_intr(sc); 1936170589Syongari return; 1937159967Sobrien } 1938159967Sobrien 1939159967Sobrien if (r & NFE_IRQ_LINK) { 1940159967Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1941159967Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1942170589Syongari DPRINTF(sc, "link state changed\n"); 1943159967Sobrien } 1944159967Sobrien 1945170589Syongari domore = 0; 1946170589Syongari /* check Rx ring */ 1947170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1948170589Syongari domore = nfe_jrxeof(sc, sc->nfe_process_limit); 1949170589Syongari else 1950170589Syongari domore = nfe_rxeof(sc, sc->nfe_process_limit); 1951170589Syongari /* check Tx ring */ 1952170589Syongari nfe_txeof(sc); 1953159967Sobrien 1954170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1955170589Syongari taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_tx_task); 1956159967Sobrien 1957159967Sobrien NFE_UNLOCK(sc); 1958159967Sobrien 1959170589Syongari if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1960170589Syongari taskqueue_enqueue_fast(taskqueue_fast, &sc->nfe_int_task); 1961170589Syongari return; 1962170589Syongari } 1963170589Syongari 1964170589Syongari /* Reenable interrupts. */ 1965170589Syongari nfe_enable_intr(sc); 1966159967Sobrien} 1967159967Sobrien 1968163503Sobrien 1969170589Syongaristatic __inline void 1970170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1971159952Sobrien{ 1972170589Syongari struct nfe_desc32 *desc32; 1973170589Syongari struct nfe_desc64 *desc64; 1974170589Syongari struct nfe_rx_data *data; 1975170589Syongari struct mbuf *m; 1976163503Sobrien 1977170589Syongari data = &sc->rxq.data[idx]; 1978170589Syongari m = data->m; 1979170589Syongari 1980170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1981170589Syongari desc64 = &sc->rxq.desc64[idx]; 1982170589Syongari /* VLAN packet may have overwritten it. */ 1983170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1984170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1985170589Syongari desc64->length = htole16(m->m_len); 1986170589Syongari desc64->flags = htole16(NFE_RX_READY); 1987170589Syongari } else { 1988170589Syongari desc32 = &sc->rxq.desc32[idx]; 1989170589Syongari desc32->length = htole16(m->m_len); 1990170589Syongari desc32->flags = htole16(NFE_RX_READY); 1991170589Syongari } 1992159952Sobrien} 1993159952Sobrien 1994163503Sobrien 1995170589Syongaristatic __inline void 1996170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1997159952Sobrien{ 1998170589Syongari struct nfe_desc32 *desc32; 1999170589Syongari struct nfe_desc64 *desc64; 2000170589Syongari struct nfe_rx_data *data; 2001170589Syongari struct mbuf *m; 2002163503Sobrien 2003170589Syongari data = &sc->jrxq.jdata[idx]; 2004170589Syongari m = data->m; 2005170589Syongari 2006170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2007170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 2008170589Syongari /* VLAN packet may have overwritten it. */ 2009170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 2010170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 2011170589Syongari desc64->length = htole16(m->m_len); 2012170589Syongari desc64->flags = htole16(NFE_RX_READY); 2013170589Syongari } else { 2014170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 2015170589Syongari desc32->length = htole16(m->m_len); 2016170589Syongari desc32->flags = htole16(NFE_RX_READY); 2017170589Syongari } 2018159952Sobrien} 2019159952Sobrien 2020163503Sobrien 2021170589Syongaristatic int 2022170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx) 2023159952Sobrien{ 2024170589Syongari struct nfe_rx_data *data; 2025170589Syongari struct nfe_desc32 *desc32; 2026170589Syongari struct nfe_desc64 *desc64; 2027170589Syongari struct mbuf *m; 2028170589Syongari bus_dma_segment_t segs[1]; 2029170589Syongari bus_dmamap_t map; 2030170589Syongari int nsegs; 2031163503Sobrien 2032170589Syongari m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 2033170589Syongari if (m == NULL) 2034170589Syongari return (ENOBUFS); 2035159952Sobrien 2036170589Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 2037170589Syongari m_adj(m, ETHER_ALIGN); 2038163503Sobrien 2039170589Syongari if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 2040170589Syongari m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2041170589Syongari m_freem(m); 2042170589Syongari return (ENOBUFS); 2043170589Syongari } 2044170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2045163503Sobrien 2046170589Syongari data = &sc->rxq.data[idx]; 2047170589Syongari if (data->m != NULL) { 2048170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2049170589Syongari BUS_DMASYNC_POSTREAD); 2050170589Syongari bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 2051170589Syongari } 2052170589Syongari map = data->rx_data_map; 2053170589Syongari data->rx_data_map = sc->rxq.rx_spare_map; 2054170589Syongari sc->rxq.rx_spare_map = map; 2055170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2056170589Syongari BUS_DMASYNC_PREREAD); 2057170589Syongari data->paddr = segs[0].ds_addr; 2058170589Syongari data->m = m; 2059170589Syongari /* update mapping address in h/w descriptor */ 2060170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2061170589Syongari desc64 = &sc->rxq.desc64[idx]; 2062170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2063170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2064170589Syongari desc64->length = htole16(segs[0].ds_len); 2065170589Syongari desc64->flags = htole16(NFE_RX_READY); 2066170589Syongari } else { 2067170589Syongari desc32 = &sc->rxq.desc32[idx]; 2068170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2069170589Syongari desc32->length = htole16(segs[0].ds_len); 2070170589Syongari desc32->flags = htole16(NFE_RX_READY); 2071170589Syongari } 2072170589Syongari 2073170589Syongari return (0); 2074159952Sobrien} 2075159952Sobrien 2076163503Sobrien 2077170589Syongaristatic int 2078170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx) 2079159952Sobrien{ 2080170589Syongari struct nfe_rx_data *data; 2081170589Syongari struct nfe_desc32 *desc32; 2082170589Syongari struct nfe_desc64 *desc64; 2083170589Syongari struct mbuf *m; 2084170589Syongari bus_dma_segment_t segs[1]; 2085170589Syongari bus_dmamap_t map; 2086170589Syongari int nsegs; 2087170589Syongari void *buf; 2088163503Sobrien 2089170589Syongari MGETHDR(m, M_DONTWAIT, MT_DATA); 2090170589Syongari if (m == NULL) 2091170589Syongari return (ENOBUFS); 2092170589Syongari buf = nfe_jalloc(sc); 2093170589Syongari if (buf == NULL) { 2094170589Syongari m_freem(m); 2095170589Syongari return (ENOBUFS); 2096170589Syongari } 2097170589Syongari /* Attach the buffer to the mbuf. */ 2098170589Syongari MEXTADD(m, buf, NFE_JLEN, nfe_jfree, (struct nfe_softc *)sc, 0, 2099170589Syongari EXT_NET_DRV); 2100170589Syongari if ((m->m_flags & M_EXT) == 0) { 2101170589Syongari m_freem(m); 2102170589Syongari return (ENOBUFS); 2103170589Syongari } 2104170589Syongari m->m_pkthdr.len = m->m_len = NFE_JLEN; 2105170589Syongari m_adj(m, ETHER_ALIGN); 2106159952Sobrien 2107170589Syongari if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 2108170589Syongari sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2109170589Syongari m_freem(m); 2110170589Syongari return (ENOBUFS); 2111170589Syongari } 2112170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2113163503Sobrien 2114170589Syongari data = &sc->jrxq.jdata[idx]; 2115170589Syongari if (data->m != NULL) { 2116170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2117170589Syongari BUS_DMASYNC_POSTREAD); 2118170589Syongari bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 2119170589Syongari } 2120170589Syongari map = data->rx_data_map; 2121170589Syongari data->rx_data_map = sc->jrxq.jrx_spare_map; 2122170589Syongari sc->jrxq.jrx_spare_map = map; 2123170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2124170589Syongari BUS_DMASYNC_PREREAD); 2125170589Syongari data->paddr = segs[0].ds_addr; 2126170589Syongari data->m = m; 2127170589Syongari /* update mapping address in h/w descriptor */ 2128170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2129170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 2130170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2131170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2132170589Syongari desc64->length = htole16(segs[0].ds_len); 2133170589Syongari desc64->flags = htole16(NFE_RX_READY); 2134170589Syongari } else { 2135170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 2136170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2137170589Syongari desc32->length = htole16(segs[0].ds_len); 2138170589Syongari desc32->flags = htole16(NFE_RX_READY); 2139170589Syongari } 2140159967Sobrien 2141170589Syongari return (0); 2142159952Sobrien} 2143159952Sobrien 2144163503Sobrien 2145170589Syongaristatic int 2146170589Syongarinfe_rxeof(struct nfe_softc *sc, int count) 2147159952Sobrien{ 2148159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2149170589Syongari struct nfe_desc32 *desc32; 2150170589Syongari struct nfe_desc64 *desc64; 2151159952Sobrien struct nfe_rx_data *data; 2152170589Syongari struct mbuf *m; 2153170589Syongari uint16_t flags; 2154170589Syongari int len, prog; 2155170589Syongari uint32_t vtag = 0; 2156159952Sobrien 2157159967Sobrien NFE_LOCK_ASSERT(sc); 2158159967Sobrien 2159170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2160170589Syongari BUS_DMASYNC_POSTREAD); 2161159967Sobrien 2162170589Syongari for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2163170589Syongari if (count <= 0) 2164170589Syongari break; 2165170589Syongari count--; 2166159967Sobrien 2167159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 2168159952Sobrien 2169159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2170159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2171170589Syongari vtag = le32toh(desc64->physaddr[1]); 2172170589Syongari flags = le16toh(desc64->flags); 2173170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2174159952Sobrien } else { 2175159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2176170589Syongari flags = le16toh(desc32->flags); 2177170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2178159952Sobrien } 2179159952Sobrien 2180159952Sobrien if (flags & NFE_RX_READY) 2181159952Sobrien break; 2182170589Syongari prog++; 2183159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2184170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2185170589Syongari ifp->if_ierrors++; 2186170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2187170589Syongari continue; 2188170589Syongari } 2189159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2190159952Sobrien flags &= ~NFE_RX_ERROR; 2191159952Sobrien len--; /* fix buffer length */ 2192159952Sobrien } 2193159952Sobrien } else { 2194170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2195170589Syongari ifp->if_ierrors++; 2196170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2197170589Syongari continue; 2198170589Syongari } 2199159952Sobrien 2200159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2201159952Sobrien flags &= ~NFE_RX_ERROR; 2202159952Sobrien len--; /* fix buffer length */ 2203159952Sobrien } 2204159952Sobrien } 2205159952Sobrien 2206159952Sobrien if (flags & NFE_RX_ERROR) { 2207159952Sobrien ifp->if_ierrors++; 2208170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2209170589Syongari continue; 2210159952Sobrien } 2211159952Sobrien 2212170589Syongari m = data->m; 2213170589Syongari if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2214170589Syongari ifp->if_iqdrops++; 2215170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2216170589Syongari continue; 2217159952Sobrien } 2218159952Sobrien 2219170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2220170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2221170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2222170589Syongari m->m_flags |= M_VLANTAG; 2223164651Sobrien } 2224159952Sobrien 2225170589Syongari m->m_pkthdr.len = m->m_len = len; 2226170589Syongari m->m_pkthdr.rcvif = ifp; 2227164651Sobrien 2228170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2229170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2230170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2231170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2232170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2233170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2234170589Syongari m->m_pkthdr.csum_flags |= 2235170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2236170589Syongari m->m_pkthdr.csum_data = 0xffff; 2237170589Syongari } 2238159952Sobrien } 2239170589Syongari } 2240170589Syongari 2241170589Syongari ifp->if_ipackets++; 2242170589Syongari 2243170589Syongari NFE_UNLOCK(sc); 2244170589Syongari (*ifp->if_input)(ifp, m); 2245170589Syongari NFE_LOCK(sc); 2246170589Syongari } 2247170589Syongari 2248170589Syongari if (prog > 0) 2249170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2250170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2251170589Syongari 2252170589Syongari return (count > 0 ? 0 : EAGAIN); 2253170589Syongari} 2254170589Syongari 2255170589Syongari 2256170589Syongaristatic int 2257170589Syongarinfe_jrxeof(struct nfe_softc *sc, int count) 2258170589Syongari{ 2259170589Syongari struct ifnet *ifp = sc->nfe_ifp; 2260170589Syongari struct nfe_desc32 *desc32; 2261170589Syongari struct nfe_desc64 *desc64; 2262170589Syongari struct nfe_rx_data *data; 2263170589Syongari struct mbuf *m; 2264170589Syongari uint16_t flags; 2265170589Syongari int len, prog; 2266170589Syongari uint32_t vtag = 0; 2267170589Syongari 2268170589Syongari NFE_LOCK_ASSERT(sc); 2269170589Syongari 2270170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2271170589Syongari BUS_DMASYNC_POSTREAD); 2272170589Syongari 2273170589Syongari for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2274170589Syongari vtag = 0) { 2275170589Syongari if (count <= 0) 2276170589Syongari break; 2277170589Syongari count--; 2278170589Syongari 2279170589Syongari data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2280170589Syongari 2281170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2282170589Syongari desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2283170589Syongari vtag = le32toh(desc64->physaddr[1]); 2284170589Syongari flags = le16toh(desc64->flags); 2285170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2286170589Syongari } else { 2287170589Syongari desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2288170589Syongari flags = le16toh(desc32->flags); 2289170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2290170589Syongari } 2291170589Syongari 2292170589Syongari if (flags & NFE_RX_READY) 2293170589Syongari break; 2294170589Syongari prog++; 2295170589Syongari if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2296170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2297170589Syongari ifp->if_ierrors++; 2298170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2299170589Syongari continue; 2300170589Syongari } 2301170589Syongari if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2302170589Syongari flags &= ~NFE_RX_ERROR; 2303170589Syongari len--; /* fix buffer length */ 2304170589Syongari } 2305170589Syongari } else { 2306170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2307170589Syongari ifp->if_ierrors++; 2308170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2309170589Syongari continue; 2310170589Syongari } 2311170589Syongari 2312170589Syongari if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2313170589Syongari flags &= ~NFE_RX_ERROR; 2314170589Syongari len--; /* fix buffer length */ 2315170589Syongari } 2316170589Syongari } 2317170589Syongari 2318170589Syongari if (flags & NFE_RX_ERROR) { 2319164651Sobrien ifp->if_ierrors++; 2320170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2321170589Syongari continue; 2322164651Sobrien } 2323159952Sobrien 2324159952Sobrien m = data->m; 2325170589Syongari if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2326170589Syongari ifp->if_iqdrops++; 2327170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2328170589Syongari continue; 2329170589Syongari } 2330159952Sobrien 2331170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2332170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2333170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2334170589Syongari m->m_flags |= M_VLANTAG; 2335170589Syongari } 2336170589Syongari 2337159952Sobrien m->m_pkthdr.len = m->m_len = len; 2338159952Sobrien m->m_pkthdr.rcvif = ifp; 2339159952Sobrien 2340170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2341170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2342170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2343159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2344170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2345170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2346170589Syongari m->m_pkthdr.csum_flags |= 2347170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2348170589Syongari m->m_pkthdr.csum_data = 0xffff; 2349170589Syongari } 2350159967Sobrien } 2351159952Sobrien } 2352159952Sobrien 2353159952Sobrien ifp->if_ipackets++; 2354159952Sobrien 2355159967Sobrien NFE_UNLOCK(sc); 2356159967Sobrien (*ifp->if_input)(ifp, m); 2357159967Sobrien NFE_LOCK(sc); 2358170589Syongari } 2359159967Sobrien 2360170589Syongari if (prog > 0) 2361170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2362170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2363159952Sobrien 2364170589Syongari return (count > 0 ? 0 : EAGAIN); 2365159952Sobrien} 2366159952Sobrien 2367163503Sobrien 2368163503Sobrienstatic void 2369163503Sobriennfe_txeof(struct nfe_softc *sc) 2370159952Sobrien{ 2371159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2372159952Sobrien struct nfe_desc32 *desc32; 2373159952Sobrien struct nfe_desc64 *desc64; 2374159952Sobrien struct nfe_tx_data *data = NULL; 2375170589Syongari uint16_t flags; 2376170589Syongari int cons, prog; 2377159952Sobrien 2378159967Sobrien NFE_LOCK_ASSERT(sc); 2379159967Sobrien 2380170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2381170589Syongari BUS_DMASYNC_POSTREAD); 2382170589Syongari 2383170589Syongari prog = 0; 2384170589Syongari for (cons = sc->txq.next; cons != sc->txq.cur; 2385170589Syongari NFE_INC(cons, NFE_TX_RING_COUNT)) { 2386159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2387170589Syongari desc64 = &sc->txq.desc64[cons]; 2388170589Syongari flags = le16toh(desc64->flags); 2389159952Sobrien } else { 2390170589Syongari desc32 = &sc->txq.desc32[cons]; 2391170589Syongari flags = le16toh(desc32->flags); 2392159952Sobrien } 2393159952Sobrien 2394159952Sobrien if (flags & NFE_TX_VALID) 2395159952Sobrien break; 2396159952Sobrien 2397170589Syongari prog++; 2398170589Syongari sc->txq.queued--; 2399170589Syongari data = &sc->txq.data[cons]; 2400159952Sobrien 2401159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2402170589Syongari if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2403170589Syongari continue; 2404159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 2405170589Syongari device_printf(sc->nfe_dev, 2406170589Syongari "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2407159967Sobrien 2408159952Sobrien ifp->if_oerrors++; 2409159952Sobrien } else 2410159952Sobrien ifp->if_opackets++; 2411159952Sobrien } else { 2412170589Syongari if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2413170589Syongari continue; 2414159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 2415170589Syongari device_printf(sc->nfe_dev, 2416170589Syongari "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2417159952Sobrien ifp->if_oerrors++; 2418159952Sobrien } else 2419159952Sobrien ifp->if_opackets++; 2420159952Sobrien } 2421159952Sobrien 2422159952Sobrien /* last fragment of the mbuf chain transmitted */ 2423170589Syongari KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2424170589Syongari bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2425159967Sobrien BUS_DMASYNC_POSTWRITE); 2426170589Syongari bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2427159952Sobrien m_freem(data->m); 2428159952Sobrien data->m = NULL; 2429159952Sobrien } 2430159952Sobrien 2431170589Syongari if (prog > 0) { 2432170589Syongari sc->nfe_force_tx = 0; 2433170589Syongari sc->txq.next = cons; 2434159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2435170589Syongari if (sc->txq.queued == 0) 2436170589Syongari sc->nfe_watchdog_timer = 0; 2437159952Sobrien } 2438159952Sobrien} 2439159952Sobrien 2440170589Syongari/* 2441170589Syongari * It's copy of ath_defrag(ath(4)). 2442170589Syongari * 2443170589Syongari * Defragment an mbuf chain, returning at most maxfrags separate 2444170589Syongari * mbufs+clusters. If this is not possible NULL is returned and 2445170589Syongari * the original mbuf chain is left in it's present (potentially 2446170589Syongari * modified) state. We use two techniques: collapsing consecutive 2447170589Syongari * mbufs and replacing consecutive mbufs by a cluster. 2448170589Syongari */ 2449170589Syongaristatic struct mbuf * 2450170589Syongarinfe_defrag(struct mbuf *m0, int how, int maxfrags) 2451170589Syongari{ 2452170589Syongari struct mbuf *m, *n, *n2, **prev; 2453170589Syongari u_int curfrags; 2454163503Sobrien 2455170589Syongari /* 2456170589Syongari * Calculate the current number of frags. 2457170589Syongari */ 2458170589Syongari curfrags = 0; 2459170589Syongari for (m = m0; m != NULL; m = m->m_next) 2460170589Syongari curfrags++; 2461170589Syongari /* 2462170589Syongari * First, try to collapse mbufs. Note that we always collapse 2463170589Syongari * towards the front so we don't need to deal with moving the 2464170589Syongari * pkthdr. This may be suboptimal if the first mbuf has much 2465170589Syongari * less data than the following. 2466170589Syongari */ 2467170589Syongari m = m0; 2468170589Syongariagain: 2469170589Syongari for (;;) { 2470170589Syongari n = m->m_next; 2471170589Syongari if (n == NULL) 2472170589Syongari break; 2473170589Syongari if ((m->m_flags & M_RDONLY) == 0 && 2474170589Syongari n->m_len < M_TRAILINGSPACE(m)) { 2475170589Syongari bcopy(mtod(n, void *), mtod(m, char *) + m->m_len, 2476170589Syongari n->m_len); 2477170589Syongari m->m_len += n->m_len; 2478170589Syongari m->m_next = n->m_next; 2479170589Syongari m_free(n); 2480170589Syongari if (--curfrags <= maxfrags) 2481170589Syongari return (m0); 2482170589Syongari } else 2483170589Syongari m = n; 2484170589Syongari } 2485170589Syongari KASSERT(maxfrags > 1, 2486170589Syongari ("maxfrags %u, but normal collapse failed", maxfrags)); 2487170589Syongari /* 2488170589Syongari * Collapse consecutive mbufs to a cluster. 2489170589Syongari */ 2490170589Syongari prev = &m0->m_next; /* NB: not the first mbuf */ 2491170589Syongari while ((n = *prev) != NULL) { 2492170589Syongari if ((n2 = n->m_next) != NULL && 2493170589Syongari n->m_len + n2->m_len < MCLBYTES) { 2494170589Syongari m = m_getcl(how, MT_DATA, 0); 2495170589Syongari if (m == NULL) 2496170589Syongari goto bad; 2497170589Syongari bcopy(mtod(n, void *), mtod(m, void *), n->m_len); 2498170589Syongari bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len, 2499170589Syongari n2->m_len); 2500170589Syongari m->m_len = n->m_len + n2->m_len; 2501170589Syongari m->m_next = n2->m_next; 2502170589Syongari *prev = m; 2503170589Syongari m_free(n); 2504170589Syongari m_free(n2); 2505170589Syongari if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */ 2506170589Syongari return m0; 2507170589Syongari /* 2508170589Syongari * Still not there, try the normal collapse 2509170589Syongari * again before we allocate another cluster. 2510170589Syongari */ 2511170589Syongari goto again; 2512170589Syongari } 2513170589Syongari prev = &n->m_next; 2514170589Syongari } 2515170589Syongari /* 2516170589Syongari * No place where we can collapse to a cluster; punt. 2517170589Syongari * This can occur if, for example, you request 2 frags 2518170589Syongari * but the packet requires that both be clusters (we 2519170589Syongari * never reallocate the first mbuf to avoid moving the 2520170589Syongari * packet header). 2521170589Syongari */ 2522170589Syongaribad: 2523170589Syongari return (NULL); 2524170589Syongari} 2525170589Syongari 2526170589Syongari 2527163503Sobrienstatic int 2528170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2529159952Sobrien{ 2530170589Syongari struct nfe_desc32 *desc32 = NULL; 2531170589Syongari struct nfe_desc64 *desc64 = NULL; 2532159952Sobrien bus_dmamap_t map; 2533163503Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2534170589Syongari int error, i, nsegs, prod, si; 2535170589Syongari uint32_t tso_segsz; 2536170589Syongari uint16_t cflags, flags; 2537170589Syongari struct mbuf *m; 2538159952Sobrien 2539170589Syongari prod = si = sc->txq.cur; 2540170589Syongari map = sc->txq.data[prod].tx_data_map; 2541159952Sobrien 2542170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2543159967Sobrien &nsegs, BUS_DMA_NOWAIT); 2544170589Syongari if (error == EFBIG) { 2545170589Syongari m = nfe_defrag(*m_head, M_DONTWAIT, NFE_MAX_SCATTER); 2546170589Syongari if (m == NULL) { 2547170589Syongari m_freem(*m_head); 2548170589Syongari *m_head = NULL; 2549170589Syongari return (ENOBUFS); 2550170589Syongari } 2551170589Syongari *m_head = m; 2552170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2553170589Syongari *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2554170589Syongari if (error != 0) { 2555170589Syongari m_freem(*m_head); 2556170589Syongari *m_head = NULL; 2557170589Syongari return (ENOBUFS); 2558170589Syongari } 2559170589Syongari } else if (error != 0) 2560170589Syongari return (error); 2561170589Syongari if (nsegs == 0) { 2562170589Syongari m_freem(*m_head); 2563170589Syongari *m_head = NULL; 2564170589Syongari return (EIO); 2565159952Sobrien } 2566159952Sobrien 2567170589Syongari if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2568159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2569170589Syongari return (ENOBUFS); 2570159952Sobrien } 2571159952Sobrien 2572170589Syongari m = *m_head; 2573170589Syongari cflags = flags = 0; 2574170589Syongari tso_segsz = 0; 2575170589Syongari if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2576170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2577170589Syongari cflags |= NFE_TX_IP_CSUM; 2578170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2579170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2580170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2581170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2582164656Sobrien } 2583170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2584170589Syongari tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz << 2585170589Syongari NFE_TX_TSO_SHIFT; 2586170589Syongari cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2587170589Syongari cflags |= NFE_TX_TSO; 2588170589Syongari } 2589159967Sobrien 2590159967Sobrien for (i = 0; i < nsegs; i++) { 2591159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2592170589Syongari desc64 = &sc->txq.desc64[prod]; 2593170589Syongari desc64->physaddr[0] = 2594170589Syongari htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2595170589Syongari desc64->physaddr[1] = 2596170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2597170589Syongari desc64->vtag = 0; 2598159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 2599159952Sobrien desc64->flags = htole16(flags); 2600159952Sobrien } else { 2601170589Syongari desc32 = &sc->txq.desc32[prod]; 2602170589Syongari desc32->physaddr = 2603170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2604159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 2605159952Sobrien desc32->flags = htole16(flags); 2606159952Sobrien } 2607159952Sobrien 2608170589Syongari /* 2609170589Syongari * Setting of the valid bit in the first descriptor is 2610170589Syongari * deferred until the whole chain is fully setup. 2611170589Syongari */ 2612170589Syongari flags |= NFE_TX_VALID; 2613163503Sobrien 2614159952Sobrien sc->txq.queued++; 2615170589Syongari NFE_INC(prod, NFE_TX_RING_COUNT); 2616159952Sobrien } 2617159952Sobrien 2618170589Syongari /* 2619170589Syongari * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2620170589Syongari * csum flags, vtag and TSO belong to the first fragment only. 2621170589Syongari */ 2622159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2623170589Syongari desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2624170589Syongari desc64 = &sc->txq.desc64[si]; 2625170589Syongari if ((m->m_flags & M_VLANTAG) != 0) 2626170589Syongari desc64->vtag = htole32(NFE_TX_VTAG | 2627170589Syongari m->m_pkthdr.ether_vtag); 2628170589Syongari if (tso_segsz != 0) { 2629170589Syongari /* 2630170589Syongari * XXX 2631170589Syongari * The following indicates the descriptor element 2632170589Syongari * is a 32bit quantity. 2633170589Syongari */ 2634170589Syongari desc64->length |= htole16((uint16_t)tso_segsz); 2635170589Syongari desc64->flags |= htole16(tso_segsz >> 16); 2636170589Syongari } 2637170589Syongari /* 2638170589Syongari * finally, set the valid/checksum/TSO bit in the first 2639170589Syongari * descriptor. 2640170589Syongari */ 2641170589Syongari desc64->flags |= htole16(NFE_TX_VALID | cflags); 2642159952Sobrien } else { 2643159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 2644170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2645159952Sobrien else 2646170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2647170589Syongari desc32 = &sc->txq.desc32[si]; 2648170589Syongari if (tso_segsz != 0) { 2649170589Syongari /* 2650170589Syongari * XXX 2651170589Syongari * The following indicates the descriptor element 2652170589Syongari * is a 32bit quantity. 2653170589Syongari */ 2654170589Syongari desc32->length |= htole16((uint16_t)tso_segsz); 2655170589Syongari desc32->flags |= htole16(tso_segsz >> 16); 2656170589Syongari } 2657170589Syongari /* 2658170589Syongari * finally, set the valid/checksum/TSO bit in the first 2659170589Syongari * descriptor. 2660170589Syongari */ 2661170589Syongari desc32->flags |= htole16(NFE_TX_VALID | cflags); 2662159952Sobrien } 2663159952Sobrien 2664170589Syongari sc->txq.cur = prod; 2665170589Syongari prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2666170589Syongari sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2667170589Syongari sc->txq.data[prod].tx_data_map = map; 2668170589Syongari sc->txq.data[prod].m = m; 2669159952Sobrien 2670159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2671159952Sobrien 2672170589Syongari return (0); 2673159952Sobrien} 2674159952Sobrien 2675159967Sobrien 2676163503Sobrienstatic void 2677163503Sobriennfe_setmulti(struct nfe_softc *sc) 2678159952Sobrien{ 2679159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2680163503Sobrien struct ifmultiaddr *ifma; 2681163503Sobrien int i; 2682170589Syongari uint32_t filter; 2683170589Syongari uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2684170589Syongari uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 2685163503Sobrien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2686163503Sobrien }; 2687159967Sobrien 2688159967Sobrien NFE_LOCK_ASSERT(sc); 2689159967Sobrien 2690159967Sobrien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2691159967Sobrien bzero(addr, ETHER_ADDR_LEN); 2692159967Sobrien bzero(mask, ETHER_ADDR_LEN); 2693159967Sobrien goto done; 2694159967Sobrien } 2695159967Sobrien 2696159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2697159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2698159967Sobrien 2699159967Sobrien IF_ADDR_LOCK(ifp); 2700159967Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2701159967Sobrien u_char *addrp; 2702159967Sobrien 2703159967Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 2704159967Sobrien continue; 2705159967Sobrien 2706159967Sobrien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 2707159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2708159967Sobrien u_int8_t mcaddr = addrp[i]; 2709159967Sobrien addr[i] &= mcaddr; 2710159967Sobrien mask[i] &= ~mcaddr; 2711159967Sobrien } 2712159967Sobrien } 2713159967Sobrien IF_ADDR_UNLOCK(ifp); 2714159967Sobrien 2715159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2716159967Sobrien mask[i] |= addr[i]; 2717159967Sobrien } 2718159967Sobrien 2719159967Sobriendone: 2720159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 2721159967Sobrien 2722159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2723159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2724159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2725159967Sobrien addr[5] << 8 | addr[4]); 2726159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2727159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2728159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2729159967Sobrien mask[5] << 8 | mask[4]); 2730159967Sobrien 2731170589Syongari filter = NFE_READ(sc, NFE_RXFILTER); 2732170589Syongari filter &= NFE_PFF_RX_PAUSE; 2733170589Syongari filter |= NFE_RXFILTER_MAGIC; 2734170589Syongari filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2735159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 2736159967Sobrien} 2737159967Sobrien 2738163503Sobrien 2739163503Sobrienstatic void 2740170589Syongarinfe_tx_task(void *arg, int pending) 2741159967Sobrien{ 2742170589Syongari struct ifnet *ifp; 2743159967Sobrien 2744170589Syongari ifp = (struct ifnet *)arg; 2745170589Syongari nfe_start(ifp); 2746159967Sobrien} 2747159967Sobrien 2748163503Sobrien 2749163503Sobrienstatic void 2750170589Syongarinfe_start(struct ifnet *ifp) 2751159967Sobrien{ 2752159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2753163503Sobrien struct mbuf *m0; 2754170589Syongari int enq; 2755159952Sobrien 2756170589Syongari NFE_LOCK(sc); 2757170589Syongari 2758170589Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2759170589Syongari IFF_DRV_RUNNING || sc->nfe_link == 0) { 2760170589Syongari NFE_UNLOCK(sc); 2761159967Sobrien return; 2762159967Sobrien } 2763159967Sobrien 2764170589Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 2765170589Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2766159952Sobrien if (m0 == NULL) 2767159952Sobrien break; 2768159952Sobrien 2769170589Syongari if (nfe_encap(sc, &m0) != 0) { 2770170589Syongari if (m0 == NULL) 2771170589Syongari break; 2772170589Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2773159967Sobrien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2774159952Sobrien break; 2775159952Sobrien } 2776170589Syongari enq++; 2777167190Scsjp ETHER_BPF_MTAP(ifp, m0); 2778159952Sobrien } 2779159952Sobrien 2780170589Syongari if (enq > 0) { 2781170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2782170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2783159952Sobrien 2784170589Syongari /* kick Tx */ 2785170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2786159952Sobrien 2787170589Syongari /* 2788170589Syongari * Set a timeout in case the chip goes out to lunch. 2789170589Syongari */ 2790170589Syongari sc->nfe_watchdog_timer = 5; 2791170589Syongari } 2792159967Sobrien 2793170589Syongari NFE_UNLOCK(sc); 2794159952Sobrien} 2795159952Sobrien 2796163503Sobrien 2797163503Sobrienstatic void 2798163503Sobriennfe_watchdog(struct ifnet *ifp) 2799159952Sobrien{ 2800159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2801159952Sobrien 2802170589Syongari if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2803170589Syongari return; 2804159952Sobrien 2805170589Syongari /* Check if we've lost Tx completion interrupt. */ 2806170589Syongari nfe_txeof(sc); 2807170589Syongari if (sc->txq.queued == 0) { 2808170589Syongari if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2809170589Syongari "-- recovering\n"); 2810170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2811170589Syongari taskqueue_enqueue_fast(taskqueue_fast, 2812170589Syongari &sc->nfe_tx_task); 2813170589Syongari return; 2814170589Syongari } 2815170589Syongari /* Check if we've lost start Tx command. */ 2816170589Syongari sc->nfe_force_tx++; 2817170589Syongari if (sc->nfe_force_tx <= 3) { 2818170589Syongari /* 2819170589Syongari * If this is the case for watchdog timeout, the following 2820170589Syongari * code should go to nfe_txeof(). 2821170589Syongari */ 2822170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2823170589Syongari return; 2824170589Syongari } 2825170589Syongari sc->nfe_force_tx = 0; 2826170589Syongari 2827170589Syongari if_printf(ifp, "watchdog timeout\n"); 2828170589Syongari 2829159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2830159952Sobrien ifp->if_oerrors++; 2831170589Syongari nfe_init_locked(sc); 2832159952Sobrien} 2833159952Sobrien 2834163503Sobrien 2835163503Sobrienstatic void 2836163503Sobriennfe_init(void *xsc) 2837159952Sobrien{ 2838159967Sobrien struct nfe_softc *sc = xsc; 2839159952Sobrien 2840159967Sobrien NFE_LOCK(sc); 2841159967Sobrien nfe_init_locked(sc); 2842159967Sobrien NFE_UNLOCK(sc); 2843159967Sobrien} 2844159967Sobrien 2845163503Sobrien 2846163503Sobrienstatic void 2847163503Sobriennfe_init_locked(void *xsc) 2848159967Sobrien{ 2849159967Sobrien struct nfe_softc *sc = xsc; 2850159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2851159967Sobrien struct mii_data *mii; 2852170589Syongari uint32_t val; 2853170589Syongari int error; 2854159967Sobrien 2855159967Sobrien NFE_LOCK_ASSERT(sc); 2856159967Sobrien 2857159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2858159967Sobrien 2859170589Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2860159967Sobrien return; 2861170589Syongari 2862170589Syongari nfe_stop(ifp); 2863170589Syongari 2864170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 2865170589Syongari 2866170589Syongari nfe_init_tx_ring(sc, &sc->txq); 2867170589Syongari if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2868170589Syongari error = nfe_init_jrx_ring(sc, &sc->jrxq); 2869170589Syongari else 2870170589Syongari error = nfe_init_rx_ring(sc, &sc->rxq); 2871170589Syongari if (error != 0) { 2872170589Syongari device_printf(sc->nfe_dev, 2873170589Syongari "initialization failed: no memory for rx buffers\n"); 2874170589Syongari nfe_stop(ifp); 2875170589Syongari return; 2876159967Sobrien } 2877159967Sobrien 2878170589Syongari val = 0; 2879170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2880170589Syongari val |= NFE_MAC_ADDR_INORDER; 2881170589Syongari NFE_WRITE(sc, NFE_TX_UNK, val); 2882159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 2883159952Sobrien 2884170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2885170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2886170589Syongari 2887159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 2888159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 2889159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2890159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2891159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 2892164656Sobrien 2893170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 2894159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2895170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2896170589Syongari sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2897159967Sobrien 2898159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2899159952Sobrien DELAY(10); 2900159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2901159952Sobrien 2902170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2903159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2904170589Syongari else 2905170589Syongari NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2906159952Sobrien 2907159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2908159952Sobrien 2909159952Sobrien /* set MAC address */ 2910170589Syongari nfe_set_macaddr(sc, IF_LLADDR(ifp)); 2911159952Sobrien 2912159952Sobrien /* tell MAC where rings are in memory */ 2913170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2914170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2915170589Syongari NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2916170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2917170589Syongari NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2918170589Syongari } else { 2919170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2920170589Syongari NFE_ADDR_HI(sc->rxq.physaddr)); 2921170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2922170589Syongari NFE_ADDR_LO(sc->rxq.physaddr)); 2923170589Syongari } 2924170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2925170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2926159952Sobrien 2927159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 2928159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 2929159952Sobrien (NFE_TX_RING_COUNT - 1)); 2930159952Sobrien 2931170589Syongari NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2932159952Sobrien 2933159952Sobrien /* force MAC to wakeup */ 2934170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2935170589Syongari if ((val & NFE_PWR_WAKEUP) == 0) 2936170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2937159952Sobrien DELAY(10); 2938170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2939170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2940159952Sobrien 2941159952Sobrien#if 1 2942159952Sobrien /* configure interrupts coalescing/mitigation */ 2943159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2944159952Sobrien#else 2945159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 2946159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 2947159952Sobrien#endif 2948159952Sobrien 2949170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2950159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2951159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2952159952Sobrien 2953159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2954159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2955159952Sobrien 2956159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2957159952Sobrien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 2958159952Sobrien 2959159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2960159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2961159952Sobrien DELAY(10); 2962159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2963159952Sobrien 2964159952Sobrien /* set Rx filter */ 2965159952Sobrien nfe_setmulti(sc); 2966159952Sobrien 2967159952Sobrien /* enable Rx */ 2968159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2969159952Sobrien 2970159952Sobrien /* enable Tx */ 2971159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2972159952Sobrien 2973159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2974159952Sobrien 2975159967Sobrien#ifdef DEVICE_POLLING 2976159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) 2977170589Syongari nfe_disable_intr(sc); 2978159967Sobrien else 2979159967Sobrien#endif 2980170589Syongari nfe_set_intr(sc); 2981170589Syongari nfe_enable_intr(sc); /* enable interrupts */ 2982159952Sobrien 2983159967Sobrien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2984159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2985159952Sobrien 2986159967Sobrien sc->nfe_link = 0; 2987170589Syongari mii_mediachg(mii); 2988159952Sobrien 2989170589Syongari callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2990159952Sobrien} 2991159952Sobrien 2992163503Sobrien 2993163503Sobrienstatic void 2994170589Syongarinfe_stop(struct ifnet *ifp) 2995159952Sobrien{ 2996159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2997170589Syongari struct nfe_rx_ring *rx_ring; 2998170589Syongari struct nfe_jrx_ring *jrx_ring; 2999170589Syongari struct nfe_tx_ring *tx_ring; 3000170589Syongari struct nfe_rx_data *rdata; 3001170589Syongari struct nfe_tx_data *tdata; 3002170589Syongari int i; 3003159952Sobrien 3004159967Sobrien NFE_LOCK_ASSERT(sc); 3005159952Sobrien 3006170589Syongari sc->nfe_watchdog_timer = 0; 3007159967Sobrien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 3008159952Sobrien 3009159967Sobrien callout_stop(&sc->nfe_stat_ch); 3010159967Sobrien 3011159952Sobrien /* abort Tx */ 3012159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 3013159952Sobrien 3014159952Sobrien /* disable Rx */ 3015159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 3016159952Sobrien 3017159952Sobrien /* disable interrupts */ 3018170589Syongari nfe_disable_intr(sc); 3019159952Sobrien 3020159967Sobrien sc->nfe_link = 0; 3021159967Sobrien 3022170589Syongari /* free Rx and Tx mbufs still in the queues. */ 3023170589Syongari rx_ring = &sc->rxq; 3024170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 3025170589Syongari rdata = &rx_ring->data[i]; 3026170589Syongari if (rdata->m != NULL) { 3027170589Syongari bus_dmamap_sync(rx_ring->rx_data_tag, 3028170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 3029170589Syongari bus_dmamap_unload(rx_ring->rx_data_tag, 3030170589Syongari rdata->rx_data_map); 3031170589Syongari m_freem(rdata->m); 3032170589Syongari rdata->m = NULL; 3033170589Syongari } 3034170589Syongari } 3035159952Sobrien 3036170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 3037170589Syongari jrx_ring = &sc->jrxq; 3038170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 3039170589Syongari rdata = &jrx_ring->jdata[i]; 3040170589Syongari if (rdata->m != NULL) { 3041170589Syongari bus_dmamap_sync(jrx_ring->jrx_data_tag, 3042170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 3043170589Syongari bus_dmamap_unload(jrx_ring->jrx_data_tag, 3044170589Syongari rdata->rx_data_map); 3045170589Syongari m_freem(rdata->m); 3046170589Syongari rdata->m = NULL; 3047170589Syongari } 3048170589Syongari } 3049170589Syongari } 3050170589Syongari 3051170589Syongari tx_ring = &sc->txq; 3052170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 3053170589Syongari tdata = &tx_ring->data[i]; 3054170589Syongari if (tdata->m != NULL) { 3055170589Syongari bus_dmamap_sync(tx_ring->tx_data_tag, 3056170589Syongari tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 3057170589Syongari bus_dmamap_unload(tx_ring->tx_data_tag, 3058170589Syongari tdata->tx_data_map); 3059170589Syongari m_freem(tdata->m); 3060170589Syongari tdata->m = NULL; 3061170589Syongari } 3062170589Syongari } 3063159952Sobrien} 3064159952Sobrien 3065163503Sobrien 3066163503Sobrienstatic int 3067163503Sobriennfe_ifmedia_upd(struct ifnet *ifp) 3068159952Sobrien{ 3069159967Sobrien struct nfe_softc *sc = ifp->if_softc; 3070170589Syongari struct mii_data *mii; 3071159952Sobrien 3072159967Sobrien NFE_LOCK(sc); 3073159967Sobrien mii = device_get_softc(sc->nfe_miibus); 3074159967Sobrien mii_mediachg(mii); 3075170589Syongari NFE_UNLOCK(sc); 3076159967Sobrien 3077159967Sobrien return (0); 3078159952Sobrien} 3079159952Sobrien 3080163503Sobrien 3081163503Sobrienstatic void 3082163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 3083159952Sobrien{ 3084163503Sobrien struct nfe_softc *sc; 3085163503Sobrien struct mii_data *mii; 3086159952Sobrien 3087159967Sobrien sc = ifp->if_softc; 3088159952Sobrien 3089159967Sobrien NFE_LOCK(sc); 3090159967Sobrien mii = device_get_softc(sc->nfe_miibus); 3091159967Sobrien mii_pollstat(mii); 3092159967Sobrien NFE_UNLOCK(sc); 3093159952Sobrien 3094159967Sobrien ifmr->ifm_active = mii->mii_media_active; 3095159967Sobrien ifmr->ifm_status = mii->mii_media_status; 3096159952Sobrien} 3097159952Sobrien 3098163503Sobrien 3099170589Syongarivoid 3100159967Sobriennfe_tick(void *xsc) 3101159952Sobrien{ 3102159967Sobrien struct nfe_softc *sc; 3103163503Sobrien struct mii_data *mii; 3104163503Sobrien struct ifnet *ifp; 3105159952Sobrien 3106170589Syongari sc = (struct nfe_softc *)xsc; 3107159952Sobrien 3108163503Sobrien NFE_LOCK_ASSERT(sc); 3109159952Sobrien 3110159967Sobrien ifp = sc->nfe_ifp; 3111159952Sobrien 3112159967Sobrien mii = device_get_softc(sc->nfe_miibus); 3113159967Sobrien mii_tick(mii); 3114170589Syongari nfe_watchdog(ifp); 3115159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 3116159952Sobrien} 3117159952Sobrien 3118159952Sobrien 3119163503Sobrienstatic void 3120163503Sobriennfe_shutdown(device_t dev) 3121159952Sobrien{ 3122159967Sobrien struct nfe_softc *sc; 3123159967Sobrien struct ifnet *ifp; 3124159952Sobrien 3125159967Sobrien sc = device_get_softc(dev); 3126159952Sobrien 3127159967Sobrien NFE_LOCK(sc); 3128159967Sobrien ifp = sc->nfe_ifp; 3129170589Syongari nfe_stop(ifp); 3130159967Sobrien /* nfe_reset(sc); */ 3131159967Sobrien NFE_UNLOCK(sc); 3132159952Sobrien} 3133159952Sobrien 3134159952Sobrien 3135163503Sobrienstatic void 3136170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 3137159952Sobrien{ 3138170589Syongari uint32_t val; 3139159952Sobrien 3140170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 3141170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3142170589Syongari addr[0] = (val >> 8) & 0xff; 3143170589Syongari addr[1] = (val & 0xff); 3144159952Sobrien 3145170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3146170589Syongari addr[2] = (val >> 24) & 0xff; 3147170589Syongari addr[3] = (val >> 16) & 0xff; 3148170589Syongari addr[4] = (val >> 8) & 0xff; 3149170589Syongari addr[5] = (val & 0xff); 3150170589Syongari } else { 3151170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3152170589Syongari addr[5] = (val >> 8) & 0xff; 3153170589Syongari addr[4] = (val & 0xff); 3154170589Syongari 3155170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3156170589Syongari addr[3] = (val >> 24) & 0xff; 3157170589Syongari addr[2] = (val >> 16) & 0xff; 3158170589Syongari addr[1] = (val >> 8) & 0xff; 3159170589Syongari addr[0] = (val & 0xff); 3160170589Syongari } 3161159952Sobrien} 3162159952Sobrien 3163163503Sobrien 3164163503Sobrienstatic void 3165170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 3166159952Sobrien{ 3167159967Sobrien 3168159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 3169159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 3170159967Sobrien addr[1] << 8 | addr[0]); 3171159952Sobrien} 3172159952Sobrien 3173163503Sobrien 3174159967Sobrien/* 3175159967Sobrien * Map a single buffer address. 3176159967Sobrien */ 3177159967Sobrien 3178159967Sobrienstatic void 3179170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3180159952Sobrien{ 3181170589Syongari struct nfe_dmamap_arg *ctx; 3182159952Sobrien 3183170589Syongari if (error != 0) 3184159967Sobrien return; 3185159952Sobrien 3186159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 3187159967Sobrien 3188170589Syongari ctx = (struct nfe_dmamap_arg *)arg; 3189170589Syongari ctx->nfe_busaddr = segs[0].ds_addr; 3190170589Syongari} 3191159967Sobrien 3192170589Syongari 3193170589Syongaristatic int 3194170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3195170589Syongari{ 3196170589Syongari int error, value; 3197170589Syongari 3198170589Syongari if (!arg1) 3199170589Syongari return (EINVAL); 3200170589Syongari value = *(int *)arg1; 3201170589Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3202170589Syongari if (error || !req->newptr) 3203170589Syongari return (error); 3204170589Syongari if (value < low || value > high) 3205170589Syongari return (EINVAL); 3206170589Syongari *(int *)arg1 = value; 3207170589Syongari 3208170589Syongari return (0); 3209159952Sobrien} 3210170589Syongari 3211170589Syongari 3212170589Syongaristatic int 3213170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 3214170589Syongari{ 3215170589Syongari 3216170589Syongari return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 3217170589Syongari NFE_PROC_MAX)); 3218170589Syongari} 3219