if_nfe.c revision 221407
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 221407 2011-05-03 19:51:29Z marius $"); 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); 79173839Syongaristatic int nfe_shutdown(device_t); 80215327Syongaristatic int nfe_can_use_msix(struct nfe_softc *); 81170589Syongaristatic void nfe_power(struct nfe_softc *); 82163503Sobrienstatic int nfe_miibus_readreg(device_t, int, int); 83163503Sobrienstatic int nfe_miibus_writereg(device_t, int, int, int); 84163503Sobrienstatic void nfe_miibus_statchg(device_t); 85215132Syongaristatic void nfe_mac_config(struct nfe_softc *, struct mii_data *); 86170589Syongaristatic void nfe_set_intr(struct nfe_softc *); 87170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *); 88170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *); 89163503Sobrienstatic int nfe_ioctl(struct ifnet *, u_long, caddr_t); 90170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int); 91170589Syongaristatic int nfe_intr(void *); 92170589Syongaristatic void nfe_int_task(void *, int); 93170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int); 94170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int); 95170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int); 96170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int); 97193096Sattiliostatic int nfe_rxeof(struct nfe_softc *, int, int *); 98193096Sattiliostatic int nfe_jrxeof(struct nfe_softc *, int, int *); 99159967Sobrienstatic void nfe_txeof(struct nfe_softc *); 100170589Syongaristatic int nfe_encap(struct nfe_softc *, struct mbuf **); 101159967Sobrienstatic void nfe_setmulti(struct nfe_softc *); 102159967Sobrienstatic void nfe_start(struct ifnet *); 103216925Sjhbstatic void nfe_start_locked(struct ifnet *); 104159967Sobrienstatic void nfe_watchdog(struct ifnet *); 105159967Sobrienstatic void nfe_init(void *); 106159967Sobrienstatic void nfe_init_locked(void *); 107170589Syongaristatic void nfe_stop(struct ifnet *); 108159967Sobrienstatic int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 109171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 110170589Syongaristatic int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 111170589Syongaristatic int nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 112159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 113170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 114159967Sobrienstatic int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 115170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 116159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 117159967Sobrienstatic int nfe_ifmedia_upd(struct ifnet *); 118159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 119159967Sobrienstatic void nfe_tick(void *); 120170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 121170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *); 122170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); 123159952Sobrien 124170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 125170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); 126183561Syongaristatic void nfe_sysctl_node(struct nfe_softc *); 127183561Syongaristatic void nfe_stats_clear(struct nfe_softc *); 128183561Syongaristatic void nfe_stats_update(struct nfe_softc *); 129215132Syongaristatic void nfe_set_linkspeed(struct nfe_softc *); 130215132Syongaristatic void nfe_set_wol(struct nfe_softc *); 131170589Syongari 132159952Sobrien#ifdef NFE_DEBUG 133170589Syongaristatic int nfedebug = 0; 134170589Syongari#define DPRINTF(sc, ...) do { \ 135170589Syongari if (nfedebug) \ 136170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 137170589Syongari} while (0) 138170589Syongari#define DPRINTFN(sc, n, ...) do { \ 139170589Syongari if (nfedebug >= (n)) \ 140170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 141170589Syongari} while (0) 142159952Sobrien#else 143170589Syongari#define DPRINTF(sc, ...) 144170589Syongari#define DPRINTFN(sc, n, ...) 145159952Sobrien#endif 146159952Sobrien 147159967Sobrien#define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 148159967Sobrien#define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 149159967Sobrien#define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 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"}, 246178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1, 247178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 248178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2, 249178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 250178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3, 251178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 252178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4, 253178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 254183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1, 255183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 256183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2, 257183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 258183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3, 259183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 260183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4, 261183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 262183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1, 263183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 264183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2, 265183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 266183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3, 267183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 268183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4, 269183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 270159967Sobrien {0, 0, NULL} 271159967Sobrien}; 272159967Sobrien 273159967Sobrien 274159967Sobrien/* Probe for supported hardware ID's */ 275159967Sobrienstatic int 276159967Sobriennfe_probe(device_t dev) 277159952Sobrien{ 278159967Sobrien struct nfe_type *t; 279159967Sobrien 280159967Sobrien t = nfe_devs; 281159967Sobrien /* Check for matching PCI DEVICE ID's */ 282159967Sobrien while (t->name != NULL) { 283159967Sobrien if ((pci_get_vendor(dev) == t->vid_id) && 284159967Sobrien (pci_get_device(dev) == t->dev_id)) { 285159967Sobrien device_set_desc(dev, t->name); 286170589Syongari return (BUS_PROBE_DEFAULT); 287159967Sobrien } 288159967Sobrien t++; 289159967Sobrien } 290159967Sobrien 291159967Sobrien return (ENXIO); 292159952Sobrien} 293159952Sobrien 294170589Syongaristatic void 295170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count) 296170589Syongari{ 297170589Syongari int rid; 298163503Sobrien 299170589Syongari rid = PCIR_BAR(2); 300170589Syongari sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY, 301170589Syongari &rid, RF_ACTIVE); 302170589Syongari if (sc->nfe_msix_res == NULL) { 303170589Syongari device_printf(sc->nfe_dev, 304170589Syongari "couldn't allocate MSIX table resource\n"); 305170589Syongari return; 306170589Syongari } 307170589Syongari rid = PCIR_BAR(3); 308170589Syongari sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev, 309170589Syongari SYS_RES_MEMORY, &rid, RF_ACTIVE); 310170589Syongari if (sc->nfe_msix_pba_res == NULL) { 311170589Syongari device_printf(sc->nfe_dev, 312170589Syongari "couldn't allocate MSIX PBA resource\n"); 313170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2), 314170589Syongari sc->nfe_msix_res); 315170589Syongari sc->nfe_msix_res = NULL; 316170589Syongari return; 317170589Syongari } 318170589Syongari 319170589Syongari if (pci_alloc_msix(sc->nfe_dev, &count) == 0) { 320170589Syongari if (count == NFE_MSI_MESSAGES) { 321170589Syongari if (bootverbose) 322170589Syongari device_printf(sc->nfe_dev, 323170589Syongari "Using %d MSIX messages\n", count); 324170589Syongari sc->nfe_msix = 1; 325170589Syongari } else { 326170589Syongari if (bootverbose) 327170589Syongari device_printf(sc->nfe_dev, 328170589Syongari "couldn't allocate MSIX\n"); 329170589Syongari pci_release_msi(sc->nfe_dev); 330170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 331170589Syongari PCIR_BAR(3), sc->nfe_msix_pba_res); 332170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 333170589Syongari PCIR_BAR(2), sc->nfe_msix_res); 334170589Syongari sc->nfe_msix_pba_res = NULL; 335170589Syongari sc->nfe_msix_res = NULL; 336170589Syongari } 337170589Syongari } 338170589Syongari} 339170589Syongari 340159967Sobrienstatic int 341159967Sobriennfe_attach(device_t dev) 342159952Sobrien{ 343159967Sobrien struct nfe_softc *sc; 344159952Sobrien struct ifnet *ifp; 345170589Syongari bus_addr_t dma_addr_max; 346170589Syongari int error = 0, i, msic, reg, rid; 347159952Sobrien 348159967Sobrien sc = device_get_softc(dev); 349159967Sobrien sc->nfe_dev = dev; 350159952Sobrien 351159967Sobrien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 352170589Syongari MTX_DEF); 353159967Sobrien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 354159967Sobrien 355163503Sobrien pci_enable_busmaster(dev); 356159967Sobrien 357170589Syongari rid = PCIR_BAR(0); 358170589Syongari sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 359170589Syongari RF_ACTIVE); 360170589Syongari if (sc->nfe_res[0] == NULL) { 361170589Syongari device_printf(dev, "couldn't map memory resources\n"); 362170589Syongari mtx_destroy(&sc->nfe_mtx); 363170589Syongari return (ENXIO); 364170589Syongari } 365159967Sobrien 366219902Sjhb if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { 367170589Syongari uint16_t v, width; 368170589Syongari 369170589Syongari v = pci_read_config(dev, reg + 0x08, 2); 370170589Syongari /* Change max. read request size to 4096. */ 371170589Syongari v &= ~(7 << 12); 372170589Syongari v |= (5 << 12); 373170589Syongari pci_write_config(dev, reg + 0x08, v, 2); 374170589Syongari 375170589Syongari v = pci_read_config(dev, reg + 0x0c, 2); 376170589Syongari /* link capability */ 377170589Syongari v = (v >> 4) & 0x0f; 378170589Syongari width = pci_read_config(dev, reg + 0x12, 2); 379170589Syongari /* negotiated link width */ 380170589Syongari width = (width >> 4) & 0x3f; 381170589Syongari if (v != width) 382170589Syongari device_printf(sc->nfe_dev, 383170589Syongari "warning, negotiated width of link(x%d) != " 384170589Syongari "max. width of link(x%d)\n", width, v); 385159952Sobrien } 386159952Sobrien 387215327Syongari if (nfe_can_use_msix(sc) == 0) { 388215327Syongari device_printf(sc->nfe_dev, 389215327Syongari "MSI/MSI-X capability black-listed, will use INTx\n"); 390215327Syongari msix_disable = 1; 391215327Syongari msi_disable = 1; 392215327Syongari } 393215327Syongari 394159967Sobrien /* Allocate interrupt */ 395170589Syongari if (msix_disable == 0 || msi_disable == 0) { 396170589Syongari if (msix_disable == 0 && 397170589Syongari (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES) 398170589Syongari nfe_alloc_msix(sc, msic); 399170589Syongari if (msi_disable == 0 && sc->nfe_msix == 0 && 400170589Syongari (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES && 401170589Syongari pci_alloc_msi(dev, &msic) == 0) { 402170589Syongari if (msic == NFE_MSI_MESSAGES) { 403170589Syongari if (bootverbose) 404170589Syongari device_printf(dev, 405170589Syongari "Using %d MSI messages\n", msic); 406170589Syongari sc->nfe_msi = 1; 407170589Syongari } else 408170589Syongari pci_release_msi(dev); 409170589Syongari } 410170589Syongari } 411159967Sobrien 412170589Syongari if (sc->nfe_msix == 0 && sc->nfe_msi == 0) { 413170589Syongari rid = 0; 414170589Syongari sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 415170589Syongari RF_SHAREABLE | RF_ACTIVE); 416170589Syongari if (sc->nfe_irq[0] == NULL) { 417170589Syongari device_printf(dev, "couldn't allocate IRQ resources\n"); 418170589Syongari error = ENXIO; 419170589Syongari goto fail; 420170589Syongari } 421170589Syongari } else { 422170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 423170589Syongari sc->nfe_irq[i] = bus_alloc_resource_any(dev, 424170589Syongari SYS_RES_IRQ, &rid, RF_ACTIVE); 425170589Syongari if (sc->nfe_irq[i] == NULL) { 426170589Syongari device_printf(dev, 427170589Syongari "couldn't allocate IRQ resources for " 428170589Syongari "message %d\n", rid); 429170589Syongari error = ENXIO; 430170589Syongari goto fail; 431170589Syongari } 432170589Syongari } 433170589Syongari /* Map interrupts to vector 0. */ 434170589Syongari if (sc->nfe_msix != 0) { 435170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP0, 0); 436170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP1, 0); 437170589Syongari } else if (sc->nfe_msi != 0) { 438170589Syongari NFE_WRITE(sc, NFE_MSI_MAP0, 0); 439170589Syongari NFE_WRITE(sc, NFE_MSI_MAP1, 0); 440170589Syongari } 441159952Sobrien } 442159952Sobrien 443170589Syongari /* Set IRQ status/mask register. */ 444170589Syongari sc->nfe_irq_status = NFE_IRQ_STATUS; 445170589Syongari sc->nfe_irq_mask = NFE_IRQ_MASK; 446170589Syongari sc->nfe_intrs = NFE_IRQ_WANTED; 447170589Syongari sc->nfe_nointrs = 0; 448170589Syongari if (sc->nfe_msix != 0) { 449170589Syongari sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS; 450170589Syongari sc->nfe_nointrs = NFE_IRQ_WANTED; 451170589Syongari } else if (sc->nfe_msi != 0) { 452170589Syongari sc->nfe_irq_mask = NFE_MSI_IRQ_MASK; 453170589Syongari sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED; 454170589Syongari } 455159952Sobrien 456170589Syongari sc->nfe_devid = pci_get_device(dev); 457170589Syongari sc->nfe_revid = pci_get_revid(dev); 458159967Sobrien sc->nfe_flags = 0; 459159952Sobrien 460170589Syongari switch (sc->nfe_devid) { 461159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 462159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 463159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 464159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 465159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 466159952Sobrien break; 467159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 468159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 469183561Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1; 470159952Sobrien break; 471159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 472159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 473159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 474159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 475183561Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 476183561Syongari NFE_MIB_V1; 477159952Sobrien break; 478159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 479159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 480163503Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 481183561Syongari NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 482159952Sobrien break; 483170589Syongari 484162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 485162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 486162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 487162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 488170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 489170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 490170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 491170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 492178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN1: 493178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN2: 494178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN3: 495178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN4: 496170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | 497183561Syongari NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 498162212Sobrien break; 499183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN1: 500183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN2: 501183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN3: 502183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN4: 503183509Syongari /* XXX flow control */ 504183509Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT | 505183561Syongari NFE_CORRECT_MACADDR | NFE_MIB_V3; 506183509Syongari break; 507183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN1: 508183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN2: 509183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN3: 510183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN4: 511183509Syongari /* XXX flow control */ 512183509Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 513183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3; 514183509Syongari break; 515162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 516162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 517162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 518162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 519170589Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | 520183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | 521183561Syongari NFE_MIB_V2; 522163503Sobrien break; 523159952Sobrien } 524159952Sobrien 525170589Syongari nfe_power(sc); 526170589Syongari /* Check for reversed ethernet address */ 527170589Syongari if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0) 528170589Syongari sc->nfe_flags |= NFE_CORRECT_MACADDR; 529170589Syongari nfe_get_macaddr(sc, sc->eaddr); 530159952Sobrien /* 531159967Sobrien * Allocate the parent bus DMA tag appropriate for PCI. 532159967Sobrien */ 533170589Syongari dma_addr_max = BUS_SPACE_MAXADDR_32BIT; 534170589Syongari if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0) 535170589Syongari dma_addr_max = NFE_DMA_MAXADDR; 536170589Syongari error = bus_dma_tag_create( 537170589Syongari bus_get_dma_tag(sc->nfe_dev), /* parent */ 538163503Sobrien 1, 0, /* alignment, boundary */ 539170589Syongari dma_addr_max, /* lowaddr */ 540163503Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 541163503Sobrien NULL, NULL, /* filter, filterarg */ 542170589Syongari BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 543163503Sobrien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 544170589Syongari 0, /* flags */ 545163503Sobrien NULL, NULL, /* lockfunc, lockarg */ 546163503Sobrien &sc->nfe_parent_tag); 547159967Sobrien if (error) 548159967Sobrien goto fail; 549159967Sobrien 550164650Sobrien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 551164650Sobrien if (ifp == NULL) { 552170589Syongari device_printf(dev, "can not if_alloc()\n"); 553164650Sobrien error = ENOSPC; 554164650Sobrien goto fail; 555164650Sobrien } 556164650Sobrien 557159967Sobrien /* 558159952Sobrien * Allocate Tx and Rx rings. 559159952Sobrien */ 560170589Syongari if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0) 561159967Sobrien goto fail; 562159952Sobrien 563170589Syongari if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0) 564159967Sobrien goto fail; 565170589Syongari 566171559Syongari nfe_alloc_jrx_ring(sc, &sc->jrxq); 567183561Syongari /* Create sysctl node. */ 568183561Syongari nfe_sysctl_node(sc); 569170589Syongari 570159952Sobrien ifp->if_softc = sc; 571159967Sobrien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 572170589Syongari ifp->if_mtu = ETHERMTU; 573159952Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 574159952Sobrien ifp->if_ioctl = nfe_ioctl; 575159952Sobrien ifp->if_start = nfe_start; 576170589Syongari ifp->if_hwassist = 0; 577170589Syongari ifp->if_capabilities = 0; 578159952Sobrien ifp->if_init = nfe_init; 579170589Syongari IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1); 580170589Syongari ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1; 581170589Syongari IFQ_SET_READY(&ifp->if_snd); 582159952Sobrien 583170589Syongari if (sc->nfe_flags & NFE_HW_CSUM) { 584170589Syongari ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4; 585170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO; 586170589Syongari } 587170589Syongari ifp->if_capenable = ifp->if_capabilities; 588164650Sobrien 589170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 590170589Syongari /* VLAN capability setup. */ 591170589Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 592170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 593159952Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 594170589Syongari if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0) 595215432Syongari ifp->if_capabilities |= IFCAP_VLAN_HWCSUM | 596215432Syongari IFCAP_VLAN_HWTSO; 597159952Sobrien } 598215132Syongari 599219902Sjhb if (pci_find_cap(dev, PCIY_PMG, ®) == 0) 600215132Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC; 601159967Sobrien ifp->if_capenable = ifp->if_capabilities; 602159952Sobrien 603170589Syongari /* 604170589Syongari * Tell the upper layer(s) we support long frames. 605170589Syongari * Must appear after the call to ether_ifattach() because 606170589Syongari * ether_ifattach() sets ifi_hdrlen to the default value. 607170589Syongari */ 608170589Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 609170589Syongari 610159967Sobrien#ifdef DEVICE_POLLING 611159967Sobrien ifp->if_capabilities |= IFCAP_POLLING; 612159967Sobrien#endif 613159952Sobrien 614159967Sobrien /* Do MII setup */ 615213894Smarius error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd, 616215297Smarius nfe_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 617215297Smarius MIIF_DOPAUSE); 618213894Smarius if (error != 0) { 619213894Smarius device_printf(dev, "attaching PHYs failed\n"); 620159967Sobrien goto fail; 621159967Sobrien } 622159967Sobrien ether_ifattach(ifp, sc->eaddr); 623159952Sobrien 624170589Syongari TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc); 625170589Syongari sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK, 626170589Syongari taskqueue_thread_enqueue, &sc->nfe_tq); 627170589Syongari taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq", 628170589Syongari device_get_nameunit(sc->nfe_dev)); 629170589Syongari error = 0; 630170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 631170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[0], 632170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 633170589Syongari &sc->nfe_intrhand[0]); 634170589Syongari } else { 635170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 636170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[i], 637170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 638170589Syongari &sc->nfe_intrhand[i]); 639170589Syongari if (error != 0) 640170589Syongari break; 641170589Syongari } 642170589Syongari } 643159967Sobrien if (error) { 644170589Syongari device_printf(dev, "couldn't set up irq\n"); 645170589Syongari taskqueue_free(sc->nfe_tq); 646170589Syongari sc->nfe_tq = NULL; 647159967Sobrien ether_ifdetach(ifp); 648159967Sobrien goto fail; 649159967Sobrien } 650159967Sobrien 651159967Sobrienfail: 652159967Sobrien if (error) 653159967Sobrien nfe_detach(dev); 654159967Sobrien 655159967Sobrien return (error); 656159952Sobrien} 657159952Sobrien 658159967Sobrien 659159967Sobrienstatic int 660159967Sobriennfe_detach(device_t dev) 661159952Sobrien{ 662163503Sobrien struct nfe_softc *sc; 663163503Sobrien struct ifnet *ifp; 664170589Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 665170589Syongari int i, rid; 666159952Sobrien 667159967Sobrien sc = device_get_softc(dev); 668159967Sobrien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 669159967Sobrien ifp = sc->nfe_ifp; 670159967Sobrien 671159967Sobrien#ifdef DEVICE_POLLING 672170589Syongari if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 673159967Sobrien ether_poll_deregister(ifp); 674159967Sobrien#endif 675159967Sobrien if (device_is_attached(dev)) { 676164649Sobrien NFE_LOCK(sc); 677170589Syongari nfe_stop(ifp); 678159967Sobrien ifp->if_flags &= ~IFF_UP; 679164649Sobrien NFE_UNLOCK(sc); 680159967Sobrien callout_drain(&sc->nfe_stat_ch); 681159967Sobrien ether_ifdetach(ifp); 682159967Sobrien } 683159967Sobrien 684170589Syongari if (ifp) { 685170589Syongari /* restore ethernet address */ 686170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 687170589Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) { 688170589Syongari eaddr[i] = sc->eaddr[5 - i]; 689170589Syongari } 690170589Syongari } else 691170589Syongari bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN); 692170589Syongari nfe_set_macaddr(sc, eaddr); 693159967Sobrien if_free(ifp); 694170589Syongari } 695159967Sobrien if (sc->nfe_miibus) 696159967Sobrien device_delete_child(dev, sc->nfe_miibus); 697159967Sobrien bus_generic_detach(dev); 698170589Syongari if (sc->nfe_tq != NULL) { 699170589Syongari taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task); 700170589Syongari taskqueue_free(sc->nfe_tq); 701170589Syongari sc->nfe_tq = NULL; 702170589Syongari } 703159967Sobrien 704170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 705170589Syongari if (sc->nfe_intrhand[i] != NULL) { 706170589Syongari bus_teardown_intr(dev, sc->nfe_irq[i], 707170589Syongari sc->nfe_intrhand[i]); 708170589Syongari sc->nfe_intrhand[i] = NULL; 709170589Syongari } 710170589Syongari } 711159967Sobrien 712170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 713170589Syongari if (sc->nfe_irq[0] != NULL) 714170589Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, 715170589Syongari sc->nfe_irq[0]); 716170589Syongari } else { 717170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 718170589Syongari if (sc->nfe_irq[i] != NULL) { 719170589Syongari bus_release_resource(dev, SYS_RES_IRQ, rid, 720170589Syongari sc->nfe_irq[i]); 721170589Syongari sc->nfe_irq[i] = NULL; 722170589Syongari } 723170589Syongari } 724170589Syongari pci_release_msi(dev); 725170589Syongari } 726170589Syongari if (sc->nfe_msix_pba_res != NULL) { 727170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3), 728170589Syongari sc->nfe_msix_pba_res); 729170589Syongari sc->nfe_msix_pba_res = NULL; 730170589Syongari } 731170589Syongari if (sc->nfe_msix_res != NULL) { 732170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 733170589Syongari sc->nfe_msix_res); 734170589Syongari sc->nfe_msix_res = NULL; 735170589Syongari } 736170589Syongari if (sc->nfe_res[0] != NULL) { 737170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 738170589Syongari sc->nfe_res[0]); 739170589Syongari sc->nfe_res[0] = NULL; 740170589Syongari } 741170589Syongari 742159967Sobrien nfe_free_tx_ring(sc, &sc->txq); 743159967Sobrien nfe_free_rx_ring(sc, &sc->rxq); 744170589Syongari nfe_free_jrx_ring(sc, &sc->jrxq); 745159967Sobrien 746170589Syongari if (sc->nfe_parent_tag) { 747159967Sobrien bus_dma_tag_destroy(sc->nfe_parent_tag); 748170589Syongari sc->nfe_parent_tag = NULL; 749170589Syongari } 750159967Sobrien 751159967Sobrien mtx_destroy(&sc->nfe_mtx); 752159967Sobrien 753159967Sobrien return (0); 754159952Sobrien} 755159952Sobrien 756159967Sobrien 757170589Syongaristatic int 758170589Syongarinfe_suspend(device_t dev) 759170589Syongari{ 760170589Syongari struct nfe_softc *sc; 761170589Syongari 762170589Syongari sc = device_get_softc(dev); 763170589Syongari 764170589Syongari NFE_LOCK(sc); 765170589Syongari nfe_stop(sc->nfe_ifp); 766215132Syongari nfe_set_wol(sc); 767170589Syongari sc->nfe_suspended = 1; 768170589Syongari NFE_UNLOCK(sc); 769170589Syongari 770170589Syongari return (0); 771170589Syongari} 772170589Syongari 773170589Syongari 774170589Syongaristatic int 775170589Syongarinfe_resume(device_t dev) 776170589Syongari{ 777170589Syongari struct nfe_softc *sc; 778170589Syongari struct ifnet *ifp; 779170589Syongari 780170589Syongari sc = device_get_softc(dev); 781170589Syongari 782170589Syongari NFE_LOCK(sc); 783215132Syongari nfe_power(sc); 784170589Syongari ifp = sc->nfe_ifp; 785170589Syongari if (ifp->if_flags & IFF_UP) 786170589Syongari nfe_init_locked(sc); 787170589Syongari sc->nfe_suspended = 0; 788170589Syongari NFE_UNLOCK(sc); 789170589Syongari 790170589Syongari return (0); 791170589Syongari} 792170589Syongari 793170589Syongari 794215327Syongaristatic int 795215327Syongarinfe_can_use_msix(struct nfe_softc *sc) 796215327Syongari{ 797215327Syongari static struct msix_blacklist { 798215327Syongari char *maker; 799215327Syongari char *product; 800215327Syongari } msix_blacklists[] = { 801215327Syongari { "ASUSTeK Computer INC.", "P5N32-SLI PREMIUM" } 802215327Syongari }; 803215327Syongari 804215327Syongari struct msix_blacklist *mblp; 805215327Syongari char *maker, *product; 806215350Syongari int count, n, use_msix; 807215327Syongari 808215327Syongari /* 809215327Syongari * Search base board manufacturer and product name table 810215327Syongari * to see this system has a known MSI/MSI-X issue. 811215327Syongari */ 812215327Syongari maker = getenv("smbios.planar.maker"); 813215327Syongari product = getenv("smbios.planar.product"); 814215350Syongari use_msix = 1; 815215327Syongari if (maker != NULL && product != NULL) { 816215327Syongari count = sizeof(msix_blacklists) / sizeof(msix_blacklists[0]); 817215327Syongari mblp = msix_blacklists; 818215327Syongari for (n = 0; n < count; n++) { 819215327Syongari if (strcmp(maker, mblp->maker) == 0 && 820215350Syongari strcmp(product, mblp->product) == 0) { 821215350Syongari use_msix = 0; 822215350Syongari break; 823215350Syongari } 824215327Syongari mblp++; 825215327Syongari } 826215327Syongari } 827215350Syongari if (maker != NULL) 828215350Syongari freeenv(maker); 829215350Syongari if (product != NULL) 830215350Syongari freeenv(product); 831215327Syongari 832215350Syongari return (use_msix); 833215327Syongari} 834215327Syongari 835215327Syongari 836170589Syongari/* Take PHY/NIC out of powerdown, from Linux */ 837159967Sobrienstatic void 838170589Syongarinfe_power(struct nfe_softc *sc) 839170589Syongari{ 840170589Syongari uint32_t pwr; 841170589Syongari 842170589Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) == 0) 843170589Syongari return; 844170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2); 845170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC); 846170589Syongari DELAY(100); 847170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, 0); 848170589Syongari DELAY(100); 849170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2); 850170589Syongari pwr = NFE_READ(sc, NFE_PWR2_CTL); 851170589Syongari pwr &= ~NFE_PWR2_WAKEUP_MASK; 852170589Syongari if (sc->nfe_revid >= 0xa3 && 853170589Syongari (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 || 854170589Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2)) 855170589Syongari pwr |= NFE_PWR2_REVA3; 856170589Syongari NFE_WRITE(sc, NFE_PWR2_CTL, pwr); 857170589Syongari} 858170589Syongari 859170589Syongari 860170589Syongaristatic void 861159967Sobriennfe_miibus_statchg(device_t dev) 862159952Sobrien{ 863159967Sobrien struct nfe_softc *sc; 864159967Sobrien struct mii_data *mii; 865170589Syongari struct ifnet *ifp; 866215132Syongari uint32_t rxctl, txctl; 867159952Sobrien 868215132Syongari sc = device_get_softc(dev); 869170589Syongari 870159967Sobrien mii = device_get_softc(sc->nfe_miibus); 871170589Syongari ifp = sc->nfe_ifp; 872159967Sobrien 873215132Syongari sc->nfe_link = 0; 874215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 875215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 876215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 877215132Syongari case IFM_10_T: 878215132Syongari case IFM_100_TX: 879215132Syongari case IFM_1000_T: 880170589Syongari sc->nfe_link = 1; 881215132Syongari break; 882215132Syongari default: 883215132Syongari break; 884215132Syongari } 885215132Syongari } 886170589Syongari 887215132Syongari nfe_mac_config(sc, mii); 888215132Syongari txctl = NFE_READ(sc, NFE_TX_CTL); 889215132Syongari rxctl = NFE_READ(sc, NFE_RX_CTL); 890215132Syongari if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 891215132Syongari txctl |= NFE_TX_START; 892215132Syongari rxctl |= NFE_RX_START; 893215132Syongari } else { 894215132Syongari txctl &= ~NFE_TX_START; 895215132Syongari rxctl &= ~NFE_RX_START; 896215132Syongari } 897215132Syongari NFE_WRITE(sc, NFE_TX_CTL, txctl); 898215132Syongari NFE_WRITE(sc, NFE_RX_CTL, rxctl); 899215132Syongari} 900215132Syongari 901215132Syongari 902215132Syongaristatic void 903215132Syongarinfe_mac_config(struct nfe_softc *sc, struct mii_data *mii) 904215132Syongari{ 905215132Syongari uint32_t link, misc, phy, seed; 906215132Syongari uint32_t val; 907215132Syongari 908215132Syongari NFE_LOCK_ASSERT(sc); 909215132Syongari 910159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 911159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 912159952Sobrien 913159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 914159952Sobrien seed &= ~NFE_SEED_MASK; 915159952Sobrien 916215132Syongari misc = NFE_MISC1_MAGIC; 917215132Syongari link = NFE_MEDIA_SET; 918215132Syongari 919215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) == 0) { 920159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 921159952Sobrien misc |= NFE_MISC1_HDX; 922159952Sobrien } 923159952Sobrien 924159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 925159952Sobrien case IFM_1000_T: /* full-duplex only */ 926159952Sobrien link |= NFE_MEDIA_1000T; 927159952Sobrien seed |= NFE_SEED_1000T; 928159952Sobrien phy |= NFE_PHY_1000T; 929159952Sobrien break; 930159952Sobrien case IFM_100_TX: 931159952Sobrien link |= NFE_MEDIA_100TX; 932159952Sobrien seed |= NFE_SEED_100TX; 933159952Sobrien phy |= NFE_PHY_100TX; 934159952Sobrien break; 935159952Sobrien case IFM_10_T: 936159952Sobrien link |= NFE_MEDIA_10T; 937159952Sobrien seed |= NFE_SEED_10T; 938159952Sobrien break; 939159952Sobrien } 940159952Sobrien 941170589Syongari if ((phy & 0x10000000) != 0) { 942170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 943170589Syongari val = NFE_R1_MAGIC_1000; 944170589Syongari else 945170589Syongari val = NFE_R1_MAGIC_10_100; 946170589Syongari } else 947170589Syongari val = NFE_R1_MAGIC_DEFAULT; 948170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, val); 949170589Syongari 950159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 951159952Sobrien 952159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 953159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 954159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 955170589Syongari 956215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 957170589Syongari /* It seems all hardwares supports Rx pause frames. */ 958170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 959215297Smarius if ((IFM_OPTIONS(mii->mii_media_active) & 960215297Smarius IFM_ETH_RXPAUSE) != 0) 961170589Syongari val |= NFE_PFF_RX_PAUSE; 962170589Syongari else 963170589Syongari val &= ~NFE_PFF_RX_PAUSE; 964170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 965170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 966170589Syongari val = NFE_READ(sc, NFE_MISC1); 967215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & 968215297Smarius IFM_ETH_TXPAUSE) != 0) { 969170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 970170589Syongari NFE_TX_PAUSE_FRAME_ENABLE); 971170589Syongari val |= NFE_MISC1_TX_PAUSE; 972170589Syongari } else { 973170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 974170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 975170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 976170589Syongari } 977170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 978170589Syongari } 979170589Syongari } else { 980170589Syongari /* disable rx/tx pause frames */ 981170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 982170589Syongari val &= ~NFE_PFF_RX_PAUSE; 983170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 984170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 985170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 986170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 987170589Syongari val = NFE_READ(sc, NFE_MISC1); 988170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 989170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 990170589Syongari } 991170589Syongari } 992159952Sobrien} 993159952Sobrien 994163503Sobrien 995159967Sobrienstatic int 996159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg) 997159952Sobrien{ 998159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 999170589Syongari uint32_t val; 1000159952Sobrien int ntries; 1001159952Sobrien 1002159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1003159952Sobrien 1004159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1005159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1006159952Sobrien DELAY(100); 1007159952Sobrien } 1008159952Sobrien 1009159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 1010159952Sobrien 1011170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1012159952Sobrien DELAY(100); 1013159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1014159952Sobrien break; 1015159952Sobrien } 1016170589Syongari if (ntries == NFE_TIMEOUT) { 1017170589Syongari DPRINTFN(sc, 2, "timeout waiting for PHY\n"); 1018159952Sobrien return 0; 1019159952Sobrien } 1020159952Sobrien 1021159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 1022170589Syongari DPRINTFN(sc, 2, "could not read PHY\n"); 1023159952Sobrien return 0; 1024159952Sobrien } 1025159952Sobrien 1026159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 1027159952Sobrien if (val != 0xffffffff && val != 0) 1028159952Sobrien sc->mii_phyaddr = phy; 1029159952Sobrien 1030170589Syongari DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 1031159952Sobrien 1032170589Syongari return (val); 1033159952Sobrien} 1034159952Sobrien 1035163503Sobrien 1036159967Sobrienstatic int 1037159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val) 1038159952Sobrien{ 1039159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 1040170589Syongari uint32_t ctl; 1041163503Sobrien int ntries; 1042159952Sobrien 1043159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1044159952Sobrien 1045159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1046159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1047159952Sobrien DELAY(100); 1048159952Sobrien } 1049159952Sobrien 1050159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 1051159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 1052159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 1053159952Sobrien 1054170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1055159952Sobrien DELAY(100); 1056159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1057159952Sobrien break; 1058159952Sobrien } 1059159952Sobrien#ifdef NFE_DEBUG 1060170589Syongari if (nfedebug >= 2 && ntries == NFE_TIMEOUT) 1061170589Syongari device_printf(sc->nfe_dev, "could not write to PHY\n"); 1062159952Sobrien#endif 1063170589Syongari return (0); 1064159952Sobrien} 1065159952Sobrien 1066170589Syongaristruct nfe_dmamap_arg { 1067170589Syongari bus_addr_t nfe_busaddr; 1068170589Syongari}; 1069170589Syongari 1070159967Sobrienstatic int 1071159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1072159952Sobrien{ 1073170589Syongari struct nfe_dmamap_arg ctx; 1074159967Sobrien struct nfe_rx_data *data; 1075170589Syongari void *desc; 1076159967Sobrien int i, error, descsize; 1077159967Sobrien 1078159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1079170589Syongari desc = ring->desc64; 1080159967Sobrien descsize = sizeof (struct nfe_desc64); 1081159967Sobrien } else { 1082170589Syongari desc = ring->desc32; 1083159967Sobrien descsize = sizeof (struct nfe_desc32); 1084159967Sobrien } 1085159967Sobrien 1086159967Sobrien ring->cur = ring->next = 0; 1087159967Sobrien 1088163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1089170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1090170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1091170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1092170589Syongari NULL, NULL, /* filter, filterarg */ 1093170589Syongari NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1094170589Syongari NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 1095170589Syongari 0, /* flags */ 1096170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1097170589Syongari &ring->rx_desc_tag); 1098159967Sobrien if (error != 0) { 1099170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1100159967Sobrien goto fail; 1101159967Sobrien } 1102159967Sobrien 1103159967Sobrien /* allocate memory to desc */ 1104170589Syongari error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK | 1105170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map); 1106159967Sobrien if (error != 0) { 1107170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1108159967Sobrien goto fail; 1109159967Sobrien } 1110170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1111170589Syongari ring->desc64 = desc; 1112170589Syongari else 1113170589Syongari ring->desc32 = desc; 1114159967Sobrien 1115159967Sobrien /* map desc to device visible address space */ 1116170589Syongari ctx.nfe_busaddr = 0; 1117170589Syongari error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc, 1118170589Syongari NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1119159967Sobrien if (error != 0) { 1120170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1121159967Sobrien goto fail; 1122159967Sobrien } 1123170589Syongari ring->physaddr = ctx.nfe_busaddr; 1124159967Sobrien 1125170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1126170589Syongari 1, 0, /* alignment, boundary */ 1127170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1128170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1129170589Syongari NULL, NULL, /* filter, filterarg */ 1130170589Syongari MCLBYTES, 1, /* maxsize, nsegments */ 1131170589Syongari MCLBYTES, /* maxsegsize */ 1132170589Syongari 0, /* flags */ 1133170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1134170589Syongari &ring->rx_data_tag); 1135170589Syongari if (error != 0) { 1136170589Syongari device_printf(sc->nfe_dev, "could not create Rx DMA tag\n"); 1137170589Syongari goto fail; 1138170589Syongari } 1139159967Sobrien 1140170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map); 1141170589Syongari if (error != 0) { 1142170589Syongari device_printf(sc->nfe_dev, 1143170589Syongari "could not create Rx DMA spare map\n"); 1144170589Syongari goto fail; 1145170589Syongari } 1146170589Syongari 1147159967Sobrien /* 1148159967Sobrien * Pre-allocate Rx buffers and populate Rx ring. 1149159967Sobrien */ 1150159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1151159967Sobrien data = &sc->rxq.data[i]; 1152170589Syongari data->rx_data_map = NULL; 1153170589Syongari data->m = NULL; 1154170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, 1155170589Syongari &data->rx_data_map); 1156164651Sobrien if (error != 0) { 1157170589Syongari device_printf(sc->nfe_dev, 1158170589Syongari "could not create Rx DMA map\n"); 1159164651Sobrien goto fail; 1160164651Sobrien } 1161170589Syongari } 1162159967Sobrien 1163170589Syongarifail: 1164170589Syongari return (error); 1165170589Syongari} 1166170589Syongari 1167170589Syongari 1168171559Syongaristatic void 1169170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1170170589Syongari{ 1171170589Syongari struct nfe_dmamap_arg ctx; 1172170589Syongari struct nfe_rx_data *data; 1173170589Syongari void *desc; 1174170589Syongari int i, error, descsize; 1175170589Syongari 1176170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1177171559Syongari return; 1178171559Syongari if (jumbo_disable != 0) { 1179171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support\n"); 1180171559Syongari sc->nfe_jumbo_disable = 1; 1181171559Syongari return; 1182171559Syongari } 1183170589Syongari 1184170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1185170589Syongari desc = ring->jdesc64; 1186170589Syongari descsize = sizeof (struct nfe_desc64); 1187170589Syongari } else { 1188170589Syongari desc = ring->jdesc32; 1189170589Syongari descsize = sizeof (struct nfe_desc32); 1190170589Syongari } 1191170589Syongari 1192170589Syongari ring->jcur = ring->jnext = 0; 1193170589Syongari 1194170589Syongari /* Create DMA tag for jumbo Rx ring. */ 1195170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1196170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1197170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1198170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1199170589Syongari NULL, NULL, /* filter, filterarg */ 1200170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsize */ 1201170589Syongari 1, /* nsegments */ 1202170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsegsize */ 1203170589Syongari 0, /* flags */ 1204170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1205170589Syongari &ring->jrx_desc_tag); 1206170589Syongari if (error != 0) { 1207170589Syongari device_printf(sc->nfe_dev, 1208170589Syongari "could not create jumbo ring DMA tag\n"); 1209170589Syongari goto fail; 1210170589Syongari } 1211170589Syongari 1212170589Syongari /* Create DMA tag for jumbo Rx buffers. */ 1213170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1214192706Syongari 1, 0, /* alignment, boundary */ 1215170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1216170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1217170589Syongari NULL, NULL, /* filter, filterarg */ 1218176859Syongari MJUM9BYTES, /* maxsize */ 1219170589Syongari 1, /* nsegments */ 1220176859Syongari MJUM9BYTES, /* maxsegsize */ 1221170589Syongari 0, /* flags */ 1222170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1223170589Syongari &ring->jrx_data_tag); 1224170589Syongari if (error != 0) { 1225170589Syongari device_printf(sc->nfe_dev, 1226170589Syongari "could not create jumbo Rx buffer DMA tag\n"); 1227170589Syongari goto fail; 1228170589Syongari } 1229170589Syongari 1230170589Syongari /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ 1231170589Syongari error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK | 1232170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map); 1233170589Syongari if (error != 0) { 1234170589Syongari device_printf(sc->nfe_dev, 1235170589Syongari "could not allocate DMA'able memory for jumbo Rx ring\n"); 1236170589Syongari goto fail; 1237170589Syongari } 1238170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1239170589Syongari ring->jdesc64 = desc; 1240170589Syongari else 1241170589Syongari ring->jdesc32 = desc; 1242170589Syongari 1243170589Syongari ctx.nfe_busaddr = 0; 1244170589Syongari error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc, 1245170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1246170589Syongari if (error != 0) { 1247170589Syongari device_printf(sc->nfe_dev, 1248170589Syongari "could not load DMA'able memory for jumbo Rx ring\n"); 1249170589Syongari goto fail; 1250170589Syongari } 1251170589Syongari ring->jphysaddr = ctx.nfe_busaddr; 1252170589Syongari 1253170589Syongari /* Create DMA maps for jumbo Rx buffers. */ 1254170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map); 1255170589Syongari if (error != 0) { 1256170589Syongari device_printf(sc->nfe_dev, 1257170589Syongari "could not create jumbo Rx DMA spare map\n"); 1258170589Syongari goto fail; 1259170589Syongari } 1260170589Syongari 1261170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1262170589Syongari data = &sc->jrxq.jdata[i]; 1263170589Syongari data->rx_data_map = NULL; 1264170589Syongari data->m = NULL; 1265170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, 1266164651Sobrien &data->rx_data_map); 1267164651Sobrien if (error != 0) { 1268170589Syongari device_printf(sc->nfe_dev, 1269170589Syongari "could not create jumbo Rx DMA map\n"); 1270164651Sobrien goto fail; 1271164651Sobrien } 1272170589Syongari } 1273159967Sobrien 1274171559Syongari return; 1275159967Sobrien 1276170589Syongarifail: 1277171559Syongari /* 1278171559Syongari * Running without jumbo frame support is ok for most cases 1279171559Syongari * so don't fail on creating dma tag/map for jumbo frame. 1280171559Syongari */ 1281170589Syongari nfe_free_jrx_ring(sc, ring); 1282171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support due to " 1283171559Syongari "resource shortage\n"); 1284171559Syongari sc->nfe_jumbo_disable = 1; 1285170589Syongari} 1286159967Sobrien 1287159967Sobrien 1288170589Syongaristatic int 1289170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1290170589Syongari{ 1291170589Syongari void *desc; 1292170589Syongari size_t descsize; 1293170589Syongari int i; 1294159967Sobrien 1295170589Syongari ring->cur = ring->next = 0; 1296170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1297170589Syongari desc = ring->desc64; 1298170589Syongari descsize = sizeof (struct nfe_desc64); 1299170589Syongari } else { 1300170589Syongari desc = ring->desc32; 1301170589Syongari descsize = sizeof (struct nfe_desc32); 1302159967Sobrien } 1303170589Syongari bzero(desc, descsize * NFE_RX_RING_COUNT); 1304170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1305170589Syongari if (nfe_newbuf(sc, i) != 0) 1306170589Syongari return (ENOBUFS); 1307170589Syongari } 1308159967Sobrien 1309163503Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 1310170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1311159967Sobrien 1312170589Syongari return (0); 1313159967Sobrien} 1314159967Sobrien 1315163503Sobrien 1316170589Syongaristatic int 1317170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1318159967Sobrien{ 1319170589Syongari void *desc; 1320170589Syongari size_t descsize; 1321159967Sobrien int i; 1322159967Sobrien 1323170589Syongari ring->jcur = ring->jnext = 0; 1324170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1325170589Syongari desc = ring->jdesc64; 1326170589Syongari descsize = sizeof (struct nfe_desc64); 1327170589Syongari } else { 1328170589Syongari desc = ring->jdesc32; 1329170589Syongari descsize = sizeof (struct nfe_desc32); 1330159952Sobrien } 1331176859Syongari bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT); 1332170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1333170589Syongari if (nfe_jnewbuf(sc, i) != 0) 1334170589Syongari return (ENOBUFS); 1335170589Syongari } 1336159952Sobrien 1337170589Syongari bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map, 1338170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1339159952Sobrien 1340170589Syongari return (0); 1341159967Sobrien} 1342159967Sobrien 1343159967Sobrien 1344159967Sobrienstatic void 1345159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1346159967Sobrien{ 1347159967Sobrien struct nfe_rx_data *data; 1348159967Sobrien void *desc; 1349159967Sobrien int i, descsize; 1350159967Sobrien 1351159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1352159967Sobrien desc = ring->desc64; 1353159967Sobrien descsize = sizeof (struct nfe_desc64); 1354159967Sobrien } else { 1355159967Sobrien desc = ring->desc32; 1356159967Sobrien descsize = sizeof (struct nfe_desc32); 1357159952Sobrien } 1358159952Sobrien 1359170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1360170589Syongari data = &ring->data[i]; 1361170589Syongari if (data->rx_data_map != NULL) { 1362170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1363170589Syongari data->rx_data_map); 1364170589Syongari data->rx_data_map = NULL; 1365170589Syongari } 1366170589Syongari if (data->m != NULL) { 1367170589Syongari m_freem(data->m); 1368170589Syongari data->m = NULL; 1369170589Syongari } 1370170589Syongari } 1371170589Syongari if (ring->rx_data_tag != NULL) { 1372170589Syongari if (ring->rx_spare_map != NULL) { 1373170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1374170589Syongari ring->rx_spare_map); 1375170589Syongari ring->rx_spare_map = NULL; 1376170589Syongari } 1377170589Syongari bus_dma_tag_destroy(ring->rx_data_tag); 1378170589Syongari ring->rx_data_tag = NULL; 1379170589Syongari } 1380170589Syongari 1381159967Sobrien if (desc != NULL) { 1382159967Sobrien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 1383159967Sobrien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 1384170589Syongari ring->desc64 = NULL; 1385170589Syongari ring->desc32 = NULL; 1386170589Syongari ring->rx_desc_map = NULL; 1387170589Syongari } 1388170589Syongari if (ring->rx_desc_tag != NULL) { 1389159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 1390170589Syongari ring->rx_desc_tag = NULL; 1391159967Sobrien } 1392170589Syongari} 1393159967Sobrien 1394164650Sobrien 1395170589Syongaristatic void 1396170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1397170589Syongari{ 1398170589Syongari struct nfe_rx_data *data; 1399170589Syongari void *desc; 1400170589Syongari int i, descsize; 1401170589Syongari 1402170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1403170589Syongari return; 1404170589Syongari 1405170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1406170589Syongari desc = ring->jdesc64; 1407170589Syongari descsize = sizeof (struct nfe_desc64); 1408170589Syongari } else { 1409170589Syongari desc = ring->jdesc32; 1410170589Syongari descsize = sizeof (struct nfe_desc32); 1411170589Syongari } 1412170589Syongari 1413170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1414170589Syongari data = &ring->jdata[i]; 1415164651Sobrien if (data->rx_data_map != NULL) { 1416170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1417164651Sobrien data->rx_data_map); 1418170589Syongari data->rx_data_map = NULL; 1419164651Sobrien } 1420170589Syongari if (data->m != NULL) { 1421164651Sobrien m_freem(data->m); 1422170589Syongari data->m = NULL; 1423170589Syongari } 1424164651Sobrien } 1425170589Syongari if (ring->jrx_data_tag != NULL) { 1426170589Syongari if (ring->jrx_spare_map != NULL) { 1427170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1428170589Syongari ring->jrx_spare_map); 1429170589Syongari ring->jrx_spare_map = NULL; 1430170589Syongari } 1431170589Syongari bus_dma_tag_destroy(ring->jrx_data_tag); 1432170589Syongari ring->jrx_data_tag = NULL; 1433170589Syongari } 1434170589Syongari 1435170589Syongari if (desc != NULL) { 1436170589Syongari bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1437170589Syongari bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1438170589Syongari ring->jdesc64 = NULL; 1439170589Syongari ring->jdesc32 = NULL; 1440170589Syongari ring->jrx_desc_map = NULL; 1441170589Syongari } 1442176859Syongari 1443170589Syongari if (ring->jrx_desc_tag != NULL) { 1444170589Syongari bus_dma_tag_destroy(ring->jrx_desc_tag); 1445170589Syongari ring->jrx_desc_tag = NULL; 1446170589Syongari } 1447159952Sobrien} 1448159952Sobrien 1449163503Sobrien 1450159967Sobrienstatic int 1451159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1452159952Sobrien{ 1453170589Syongari struct nfe_dmamap_arg ctx; 1454159967Sobrien int i, error; 1455170589Syongari void *desc; 1456159967Sobrien int descsize; 1457159952Sobrien 1458159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1459170589Syongari desc = ring->desc64; 1460159967Sobrien descsize = sizeof (struct nfe_desc64); 1461159967Sobrien } else { 1462170589Syongari desc = ring->desc32; 1463159967Sobrien descsize = sizeof (struct nfe_desc32); 1464159967Sobrien } 1465159952Sobrien 1466159967Sobrien ring->queued = 0; 1467159967Sobrien ring->cur = ring->next = 0; 1468159967Sobrien 1469163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1470170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1471170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1472170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1473170589Syongari NULL, NULL, /* filter, filterarg */ 1474170589Syongari NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1475170589Syongari NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1476170589Syongari 0, /* flags */ 1477170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1478170589Syongari &ring->tx_desc_tag); 1479159967Sobrien if (error != 0) { 1480170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1481159967Sobrien goto fail; 1482159952Sobrien } 1483159952Sobrien 1484170589Syongari error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1485170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1486159967Sobrien if (error != 0) { 1487170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1488159967Sobrien goto fail; 1489159967Sobrien } 1490170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1491170589Syongari ring->desc64 = desc; 1492170589Syongari else 1493170589Syongari ring->desc32 = desc; 1494159967Sobrien 1495170589Syongari ctx.nfe_busaddr = 0; 1496170589Syongari error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1497170589Syongari NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1498159967Sobrien if (error != 0) { 1499170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1500159967Sobrien goto fail; 1501159967Sobrien } 1502170589Syongari ring->physaddr = ctx.nfe_busaddr; 1503159967Sobrien 1504163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1505170589Syongari 1, 0, 1506170589Syongari BUS_SPACE_MAXADDR, 1507170589Syongari BUS_SPACE_MAXADDR, 1508170589Syongari NULL, NULL, 1509170595Syongari NFE_TSO_MAXSIZE, 1510170589Syongari NFE_MAX_SCATTER, 1511170595Syongari NFE_TSO_MAXSGSIZE, 1512170589Syongari 0, 1513170589Syongari NULL, NULL, 1514170589Syongari &ring->tx_data_tag); 1515159967Sobrien if (error != 0) { 1516170589Syongari device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1517170589Syongari goto fail; 1518159967Sobrien } 1519159967Sobrien 1520159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1521163503Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, 1522163503Sobrien &ring->data[i].tx_data_map); 1523159967Sobrien if (error != 0) { 1524170589Syongari device_printf(sc->nfe_dev, 1525170589Syongari "could not create Tx DMA map\n"); 1526159967Sobrien goto fail; 1527159967Sobrien } 1528159967Sobrien } 1529159967Sobrien 1530170589Syongarifail: 1531170589Syongari return (error); 1532159967Sobrien} 1533159967Sobrien 1534159967Sobrien 1535159967Sobrienstatic void 1536170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1537159967Sobrien{ 1538170589Syongari void *desc; 1539170589Syongari size_t descsize; 1540159967Sobrien 1541170589Syongari sc->nfe_force_tx = 0; 1542170589Syongari ring->queued = 0; 1543170589Syongari ring->cur = ring->next = 0; 1544170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1545170589Syongari desc = ring->desc64; 1546170589Syongari descsize = sizeof (struct nfe_desc64); 1547170589Syongari } else { 1548170589Syongari desc = ring->desc32; 1549170589Syongari descsize = sizeof (struct nfe_desc32); 1550159967Sobrien } 1551170589Syongari bzero(desc, descsize * NFE_TX_RING_COUNT); 1552159967Sobrien 1553163503Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1554170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1555159967Sobrien} 1556159967Sobrien 1557163503Sobrien 1558159967Sobrienstatic void 1559159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1560159967Sobrien{ 1561159967Sobrien struct nfe_tx_data *data; 1562159967Sobrien void *desc; 1563159967Sobrien int i, descsize; 1564159967Sobrien 1565159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1566159967Sobrien desc = ring->desc64; 1567159967Sobrien descsize = sizeof (struct nfe_desc64); 1568159967Sobrien } else { 1569159967Sobrien desc = ring->desc32; 1570159967Sobrien descsize = sizeof (struct nfe_desc32); 1571159967Sobrien } 1572159967Sobrien 1573159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1574159967Sobrien data = &ring->data[i]; 1575159967Sobrien 1576159967Sobrien if (data->m != NULL) { 1577170589Syongari bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1578163503Sobrien BUS_DMASYNC_POSTWRITE); 1579170589Syongari bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1580159967Sobrien m_freem(data->m); 1581170589Syongari data->m = NULL; 1582159967Sobrien } 1583170589Syongari if (data->tx_data_map != NULL) { 1584170589Syongari bus_dmamap_destroy(ring->tx_data_tag, 1585170589Syongari data->tx_data_map); 1586170589Syongari data->tx_data_map = NULL; 1587170589Syongari } 1588159967Sobrien } 1589159967Sobrien 1590170589Syongari if (ring->tx_data_tag != NULL) { 1591170589Syongari bus_dma_tag_destroy(ring->tx_data_tag); 1592170589Syongari ring->tx_data_tag = NULL; 1593159967Sobrien } 1594159967Sobrien 1595170589Syongari if (desc != NULL) { 1596170589Syongari bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1597170589Syongari BUS_DMASYNC_POSTWRITE); 1598170589Syongari bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1599170589Syongari bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1600170589Syongari ring->desc64 = NULL; 1601170589Syongari ring->desc32 = NULL; 1602170589Syongari ring->tx_desc_map = NULL; 1603170589Syongari bus_dma_tag_destroy(ring->tx_desc_tag); 1604170589Syongari ring->tx_desc_tag = NULL; 1605170589Syongari } 1606159967Sobrien} 1607159967Sobrien 1608159967Sobrien#ifdef DEVICE_POLLING 1609159967Sobrienstatic poll_handler_t nfe_poll; 1610159967Sobrien 1611163503Sobrien 1612193096Sattiliostatic int 1613159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1614159967Sobrien{ 1615164360Sobrien struct nfe_softc *sc = ifp->if_softc; 1616170589Syongari uint32_t r; 1617193096Sattilio int rx_npkts = 0; 1618159967Sobrien 1619159967Sobrien NFE_LOCK(sc); 1620159967Sobrien 1621159967Sobrien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1622170589Syongari NFE_UNLOCK(sc); 1623193096Sattilio return (rx_npkts); 1624159967Sobrien } 1625159967Sobrien 1626171559Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1627193096Sattilio rx_npkts = nfe_jrxeof(sc, count, &rx_npkts); 1628171559Syongari else 1629193096Sattilio rx_npkts = nfe_rxeof(sc, count, &rx_npkts); 1630159967Sobrien nfe_txeof(sc); 1631159967Sobrien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1632216925Sjhb nfe_start_locked(ifp); 1633159967Sobrien 1634159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1635170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1636170589Syongari NFE_UNLOCK(sc); 1637193096Sattilio return (rx_npkts); 1638163503Sobrien } 1639170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1640159967Sobrien 1641163503Sobrien if (r & NFE_IRQ_LINK) { 1642163503Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1643163503Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1644170589Syongari DPRINTF(sc, "link state changed\n"); 1645163503Sobrien } 1646159967Sobrien } 1647170589Syongari NFE_UNLOCK(sc); 1648193096Sattilio return (rx_npkts); 1649159967Sobrien} 1650159967Sobrien#endif /* DEVICE_POLLING */ 1651159967Sobrien 1652170589Syongaristatic void 1653170589Syongarinfe_set_intr(struct nfe_softc *sc) 1654170589Syongari{ 1655159967Sobrien 1656170589Syongari if (sc->nfe_msi != 0) 1657170589Syongari NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1658170589Syongari} 1659170589Syongari 1660170589Syongari 1661170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */ 1662170589Syongaristatic __inline void 1663170589Syongarinfe_enable_intr(struct nfe_softc *sc) 1664170589Syongari{ 1665170589Syongari 1666170589Syongari if (sc->nfe_msix != 0) { 1667170589Syongari /* XXX Should have a better way to enable interrupts! */ 1668170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1669170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1670170589Syongari } else 1671170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1672170589Syongari} 1673170589Syongari 1674170589Syongari 1675170589Syongaristatic __inline void 1676170589Syongarinfe_disable_intr(struct nfe_softc *sc) 1677170589Syongari{ 1678170589Syongari 1679170589Syongari if (sc->nfe_msix != 0) { 1680170589Syongari /* XXX Should have a better way to disable interrupts! */ 1681170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1682170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1683170589Syongari } else 1684170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1685170589Syongari} 1686170589Syongari 1687170589Syongari 1688159967Sobrienstatic int 1689159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1690159967Sobrien{ 1691170589Syongari struct nfe_softc *sc; 1692170589Syongari struct ifreq *ifr; 1693163503Sobrien struct mii_data *mii; 1694170589Syongari int error, init, mask; 1695159967Sobrien 1696170589Syongari sc = ifp->if_softc; 1697170589Syongari ifr = (struct ifreq *) data; 1698170589Syongari error = 0; 1699170589Syongari init = 0; 1700159952Sobrien switch (cmd) { 1701159952Sobrien case SIOCSIFMTU: 1702170589Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1703159952Sobrien error = EINVAL; 1704170589Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 1705171559Syongari if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) || 1706171559Syongari (sc->nfe_jumbo_disable != 0)) && 1707170589Syongari ifr->ifr_mtu > ETHERMTU) 1708170589Syongari error = EINVAL; 1709170589Syongari else { 1710170589Syongari NFE_LOCK(sc); 1711170589Syongari ifp->if_mtu = ifr->ifr_mtu; 1712217794Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1713217794Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1714170589Syongari nfe_init_locked(sc); 1715217794Syongari } 1716170589Syongari NFE_UNLOCK(sc); 1717164650Sobrien } 1718164650Sobrien } 1719159952Sobrien break; 1720159952Sobrien case SIOCSIFFLAGS: 1721159967Sobrien NFE_LOCK(sc); 1722159952Sobrien if (ifp->if_flags & IFF_UP) { 1723159952Sobrien /* 1724159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1725159952Sobrien * don't do a full re-init of the chip, just update 1726159952Sobrien * the Rx filter. 1727159952Sobrien */ 1728159967Sobrien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1729159967Sobrien ((ifp->if_flags ^ sc->nfe_if_flags) & 1730159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1731159952Sobrien nfe_setmulti(sc); 1732159967Sobrien else 1733159967Sobrien nfe_init_locked(sc); 1734159952Sobrien } else { 1735159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1736170589Syongari nfe_stop(ifp); 1737159952Sobrien } 1738159967Sobrien sc->nfe_if_flags = ifp->if_flags; 1739159967Sobrien NFE_UNLOCK(sc); 1740159967Sobrien error = 0; 1741159952Sobrien break; 1742159952Sobrien case SIOCADDMULTI: 1743159952Sobrien case SIOCDELMULTI: 1744170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1745159967Sobrien NFE_LOCK(sc); 1746159967Sobrien nfe_setmulti(sc); 1747159967Sobrien NFE_UNLOCK(sc); 1748159952Sobrien error = 0; 1749159952Sobrien } 1750159952Sobrien break; 1751159952Sobrien case SIOCSIFMEDIA: 1752159952Sobrien case SIOCGIFMEDIA: 1753159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1754159967Sobrien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1755159952Sobrien break; 1756159967Sobrien case SIOCSIFCAP: 1757170589Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1758159967Sobrien#ifdef DEVICE_POLLING 1759170589Syongari if ((mask & IFCAP_POLLING) != 0) { 1760170589Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1761159967Sobrien error = ether_poll_register(nfe_poll, ifp); 1762159967Sobrien if (error) 1763170589Syongari break; 1764159967Sobrien NFE_LOCK(sc); 1765170589Syongari nfe_disable_intr(sc); 1766163503Sobrien ifp->if_capenable |= IFCAP_POLLING; 1767159967Sobrien NFE_UNLOCK(sc); 1768159967Sobrien } else { 1769159967Sobrien error = ether_poll_deregister(ifp); 1770159967Sobrien /* Enable interrupt even in error case */ 1771159967Sobrien NFE_LOCK(sc); 1772170589Syongari nfe_enable_intr(sc); 1773159967Sobrien ifp->if_capenable &= ~IFCAP_POLLING; 1774159967Sobrien NFE_UNLOCK(sc); 1775159967Sobrien } 1776159967Sobrien } 1777163503Sobrien#endif /* DEVICE_POLLING */ 1778215132Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 1779215132Syongari (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) 1780215132Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 1781215432Syongari if ((mask & IFCAP_TXCSUM) != 0 && 1782215432Syongari (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 1783215432Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 1784215432Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1785170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES; 1786159967Sobrien else 1787170589Syongari ifp->if_hwassist &= ~NFE_CSUM_FEATURES; 1788215432Syongari } 1789215432Syongari if ((mask & IFCAP_RXCSUM) != 0 && 1790215432Syongari (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 1791215432Syongari ifp->if_capenable ^= IFCAP_RXCSUM; 1792170589Syongari init++; 1793159967Sobrien } 1794215432Syongari if ((mask & IFCAP_TSO4) != 0 && 1795215432Syongari (ifp->if_capabilities & IFCAP_TSO4) != 0) { 1796215432Syongari ifp->if_capenable ^= IFCAP_TSO4; 1797215432Syongari if ((IFCAP_TSO4 & ifp->if_capenable) != 0) 1798215432Syongari ifp->if_hwassist |= CSUM_TSO; 1799215432Syongari else 1800215432Syongari ifp->if_hwassist &= ~CSUM_TSO; 1801215432Syongari } 1802215432Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 1803215432Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) 1804215432Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1805215432Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 1806215432Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 1807170589Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1808215432Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) 1809215432Syongari ifp->if_capenable &= ~IFCAP_VLAN_HWTSO; 1810170589Syongari init++; 1811170589Syongari } 1812170589Syongari /* 1813170589Syongari * XXX 1814170589Syongari * It seems that VLAN stripping requires Rx checksum offload. 1815170589Syongari * Unfortunately FreeBSD has no way to disable only Rx side 1816170589Syongari * VLAN stripping. So when we know Rx checksum offload is 1817170589Syongari * disabled turn entire hardware VLAN assist off. 1818170589Syongari */ 1819215432Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) { 1820215432Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 1821215432Syongari init++; 1822215432Syongari ifp->if_capenable &= ~(IFCAP_VLAN_HWTAGGING | 1823215432Syongari IFCAP_VLAN_HWTSO); 1824170589Syongari } 1825170589Syongari if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1826170589Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1827164656Sobrien nfe_init(sc); 1828170589Syongari } 1829215432Syongari VLAN_CAPABILITIES(ifp); 1830159967Sobrien break; 1831159952Sobrien default: 1832159967Sobrien error = ether_ioctl(ifp, cmd, data); 1833159967Sobrien break; 1834159952Sobrien } 1835159952Sobrien 1836170589Syongari return (error); 1837159952Sobrien} 1838159952Sobrien 1839159967Sobrien 1840170589Syongaristatic int 1841163503Sobriennfe_intr(void *arg) 1842159967Sobrien{ 1843170589Syongari struct nfe_softc *sc; 1844170589Syongari uint32_t status; 1845170589Syongari 1846170589Syongari sc = (struct nfe_softc *)arg; 1847170589Syongari 1848170589Syongari status = NFE_READ(sc, sc->nfe_irq_status); 1849170589Syongari if (status == 0 || status == 0xffffffff) 1850170589Syongari return (FILTER_STRAY); 1851170589Syongari nfe_disable_intr(sc); 1852173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1853170589Syongari 1854170589Syongari return (FILTER_HANDLED); 1855170589Syongari} 1856170589Syongari 1857170589Syongari 1858170589Syongaristatic void 1859170589Syongarinfe_int_task(void *arg, int pending) 1860170589Syongari{ 1861159967Sobrien struct nfe_softc *sc = arg; 1862159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1863170589Syongari uint32_t r; 1864170589Syongari int domore; 1865159967Sobrien 1866163503Sobrien NFE_LOCK(sc); 1867159967Sobrien 1868170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1869170589Syongari nfe_enable_intr(sc); 1870170589Syongari NFE_UNLOCK(sc); 1871170589Syongari return; /* not for us */ 1872170589Syongari } 1873170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1874170589Syongari 1875170589Syongari DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1876170589Syongari 1877159967Sobrien#ifdef DEVICE_POLLING 1878159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) { 1879159967Sobrien NFE_UNLOCK(sc); 1880159967Sobrien return; 1881159967Sobrien } 1882159967Sobrien#endif 1883159967Sobrien 1884172169Syongari if (r & NFE_IRQ_LINK) { 1885172169Syongari NFE_READ(sc, NFE_PHY_STATUS); 1886172169Syongari NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1887172169Syongari DPRINTF(sc, "link state changed\n"); 1888172169Syongari } 1889172169Syongari 1890170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1891163503Sobrien NFE_UNLOCK(sc); 1892170589Syongari nfe_enable_intr(sc); 1893170589Syongari return; 1894159967Sobrien } 1895159967Sobrien 1896170589Syongari domore = 0; 1897170589Syongari /* check Rx ring */ 1898170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1899193096Sattilio domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL); 1900170589Syongari else 1901193096Sattilio domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL); 1902170589Syongari /* check Tx ring */ 1903170589Syongari nfe_txeof(sc); 1904159967Sobrien 1905170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1906216925Sjhb nfe_start_locked(ifp); 1907159967Sobrien 1908159967Sobrien NFE_UNLOCK(sc); 1909159967Sobrien 1910170589Syongari if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1911173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1912170589Syongari return; 1913170589Syongari } 1914170589Syongari 1915170589Syongari /* Reenable interrupts. */ 1916170589Syongari nfe_enable_intr(sc); 1917159967Sobrien} 1918159967Sobrien 1919163503Sobrien 1920170589Syongaristatic __inline void 1921170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1922159952Sobrien{ 1923170589Syongari struct nfe_desc32 *desc32; 1924170589Syongari struct nfe_desc64 *desc64; 1925170589Syongari struct nfe_rx_data *data; 1926170589Syongari struct mbuf *m; 1927163503Sobrien 1928170589Syongari data = &sc->rxq.data[idx]; 1929170589Syongari m = data->m; 1930170589Syongari 1931170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1932170589Syongari desc64 = &sc->rxq.desc64[idx]; 1933170589Syongari /* VLAN packet may have overwritten it. */ 1934170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1935170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1936170589Syongari desc64->length = htole16(m->m_len); 1937170589Syongari desc64->flags = htole16(NFE_RX_READY); 1938170589Syongari } else { 1939170589Syongari desc32 = &sc->rxq.desc32[idx]; 1940170589Syongari desc32->length = htole16(m->m_len); 1941170589Syongari desc32->flags = htole16(NFE_RX_READY); 1942170589Syongari } 1943159952Sobrien} 1944159952Sobrien 1945163503Sobrien 1946170589Syongaristatic __inline void 1947170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1948159952Sobrien{ 1949170589Syongari struct nfe_desc32 *desc32; 1950170589Syongari struct nfe_desc64 *desc64; 1951170589Syongari struct nfe_rx_data *data; 1952170589Syongari struct mbuf *m; 1953163503Sobrien 1954170589Syongari data = &sc->jrxq.jdata[idx]; 1955170589Syongari m = data->m; 1956170589Syongari 1957170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1958170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 1959170589Syongari /* VLAN packet may have overwritten it. */ 1960170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1961170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1962170589Syongari desc64->length = htole16(m->m_len); 1963170589Syongari desc64->flags = htole16(NFE_RX_READY); 1964170589Syongari } else { 1965170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 1966170589Syongari desc32->length = htole16(m->m_len); 1967170589Syongari desc32->flags = htole16(NFE_RX_READY); 1968170589Syongari } 1969159952Sobrien} 1970159952Sobrien 1971163503Sobrien 1972170589Syongaristatic int 1973170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx) 1974159952Sobrien{ 1975170589Syongari struct nfe_rx_data *data; 1976170589Syongari struct nfe_desc32 *desc32; 1977170589Syongari struct nfe_desc64 *desc64; 1978170589Syongari struct mbuf *m; 1979170589Syongari bus_dma_segment_t segs[1]; 1980170589Syongari bus_dmamap_t map; 1981170589Syongari int nsegs; 1982163503Sobrien 1983170589Syongari m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1984170589Syongari if (m == NULL) 1985170589Syongari return (ENOBUFS); 1986159952Sobrien 1987170589Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 1988170589Syongari m_adj(m, ETHER_ALIGN); 1989163503Sobrien 1990170589Syongari if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 1991170589Syongari m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 1992170589Syongari m_freem(m); 1993170589Syongari return (ENOBUFS); 1994170589Syongari } 1995170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1996163503Sobrien 1997170589Syongari data = &sc->rxq.data[idx]; 1998170589Syongari if (data->m != NULL) { 1999170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2000170589Syongari BUS_DMASYNC_POSTREAD); 2001170589Syongari bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 2002170589Syongari } 2003170589Syongari map = data->rx_data_map; 2004170589Syongari data->rx_data_map = sc->rxq.rx_spare_map; 2005170589Syongari sc->rxq.rx_spare_map = map; 2006170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2007170589Syongari BUS_DMASYNC_PREREAD); 2008170589Syongari data->paddr = segs[0].ds_addr; 2009170589Syongari data->m = m; 2010170589Syongari /* update mapping address in h/w descriptor */ 2011170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2012170589Syongari desc64 = &sc->rxq.desc64[idx]; 2013170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2014170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2015170589Syongari desc64->length = htole16(segs[0].ds_len); 2016170589Syongari desc64->flags = htole16(NFE_RX_READY); 2017170589Syongari } else { 2018170589Syongari desc32 = &sc->rxq.desc32[idx]; 2019170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2020170589Syongari desc32->length = htole16(segs[0].ds_len); 2021170589Syongari desc32->flags = htole16(NFE_RX_READY); 2022170589Syongari } 2023170589Syongari 2024170589Syongari return (0); 2025159952Sobrien} 2026159952Sobrien 2027163503Sobrien 2028170589Syongaristatic int 2029170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx) 2030159952Sobrien{ 2031170589Syongari struct nfe_rx_data *data; 2032170589Syongari struct nfe_desc32 *desc32; 2033170589Syongari struct nfe_desc64 *desc64; 2034170589Syongari struct mbuf *m; 2035170589Syongari bus_dma_segment_t segs[1]; 2036170589Syongari bus_dmamap_t map; 2037170589Syongari int nsegs; 2038163503Sobrien 2039176859Syongari m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 2040170589Syongari if (m == NULL) 2041170589Syongari return (ENOBUFS); 2042170589Syongari if ((m->m_flags & M_EXT) == 0) { 2043170589Syongari m_freem(m); 2044170589Syongari return (ENOBUFS); 2045170589Syongari } 2046176859Syongari m->m_pkthdr.len = m->m_len = MJUM9BYTES; 2047170589Syongari m_adj(m, ETHER_ALIGN); 2048159952Sobrien 2049170589Syongari if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 2050170589Syongari sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2051170589Syongari m_freem(m); 2052170589Syongari return (ENOBUFS); 2053170589Syongari } 2054170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2055163503Sobrien 2056170589Syongari data = &sc->jrxq.jdata[idx]; 2057170589Syongari if (data->m != NULL) { 2058170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2059170589Syongari BUS_DMASYNC_POSTREAD); 2060170589Syongari bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 2061170589Syongari } 2062170589Syongari map = data->rx_data_map; 2063170589Syongari data->rx_data_map = sc->jrxq.jrx_spare_map; 2064170589Syongari sc->jrxq.jrx_spare_map = map; 2065170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2066170589Syongari BUS_DMASYNC_PREREAD); 2067170589Syongari data->paddr = segs[0].ds_addr; 2068170589Syongari data->m = m; 2069170589Syongari /* update mapping address in h/w descriptor */ 2070170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2071170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 2072170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2073170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2074170589Syongari desc64->length = htole16(segs[0].ds_len); 2075170589Syongari desc64->flags = htole16(NFE_RX_READY); 2076170589Syongari } else { 2077170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 2078170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2079170589Syongari desc32->length = htole16(segs[0].ds_len); 2080170589Syongari desc32->flags = htole16(NFE_RX_READY); 2081170589Syongari } 2082159967Sobrien 2083170589Syongari return (0); 2084159952Sobrien} 2085159952Sobrien 2086163503Sobrien 2087170589Syongaristatic int 2088193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2089159952Sobrien{ 2090159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2091170589Syongari struct nfe_desc32 *desc32; 2092170589Syongari struct nfe_desc64 *desc64; 2093159952Sobrien struct nfe_rx_data *data; 2094170589Syongari struct mbuf *m; 2095170589Syongari uint16_t flags; 2096193096Sattilio int len, prog, rx_npkts; 2097170589Syongari uint32_t vtag = 0; 2098159952Sobrien 2099193096Sattilio rx_npkts = 0; 2100159967Sobrien NFE_LOCK_ASSERT(sc); 2101159967Sobrien 2102170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2103170589Syongari BUS_DMASYNC_POSTREAD); 2104159967Sobrien 2105170589Syongari for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2106170589Syongari if (count <= 0) 2107170589Syongari break; 2108170589Syongari count--; 2109159967Sobrien 2110159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 2111159952Sobrien 2112159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2113159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2114170589Syongari vtag = le32toh(desc64->physaddr[1]); 2115170589Syongari flags = le16toh(desc64->flags); 2116170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2117159952Sobrien } else { 2118159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2119170589Syongari flags = le16toh(desc32->flags); 2120170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2121159952Sobrien } 2122159952Sobrien 2123159952Sobrien if (flags & NFE_RX_READY) 2124159952Sobrien break; 2125170589Syongari prog++; 2126159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2127170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2128170589Syongari ifp->if_ierrors++; 2129170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2130170589Syongari continue; 2131170589Syongari } 2132159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2133159952Sobrien flags &= ~NFE_RX_ERROR; 2134159952Sobrien len--; /* fix buffer length */ 2135159952Sobrien } 2136159952Sobrien } else { 2137170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2138170589Syongari ifp->if_ierrors++; 2139170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2140170589Syongari continue; 2141170589Syongari } 2142159952Sobrien 2143159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2144159952Sobrien flags &= ~NFE_RX_ERROR; 2145159952Sobrien len--; /* fix buffer length */ 2146159952Sobrien } 2147159952Sobrien } 2148159952Sobrien 2149159952Sobrien if (flags & NFE_RX_ERROR) { 2150159952Sobrien ifp->if_ierrors++; 2151170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2152170589Syongari continue; 2153159952Sobrien } 2154159952Sobrien 2155170589Syongari m = data->m; 2156170589Syongari if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2157170589Syongari ifp->if_iqdrops++; 2158170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2159170589Syongari continue; 2160159952Sobrien } 2161159952Sobrien 2162170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2163170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2164170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2165170589Syongari m->m_flags |= M_VLANTAG; 2166164651Sobrien } 2167159952Sobrien 2168170589Syongari m->m_pkthdr.len = m->m_len = len; 2169170589Syongari m->m_pkthdr.rcvif = ifp; 2170164651Sobrien 2171170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2172170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2173170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2174170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2175170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2176170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2177170589Syongari m->m_pkthdr.csum_flags |= 2178170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2179170589Syongari m->m_pkthdr.csum_data = 0xffff; 2180170589Syongari } 2181159952Sobrien } 2182170589Syongari } 2183170589Syongari 2184170589Syongari ifp->if_ipackets++; 2185170589Syongari 2186170589Syongari NFE_UNLOCK(sc); 2187170589Syongari (*ifp->if_input)(ifp, m); 2188170589Syongari NFE_LOCK(sc); 2189193096Sattilio rx_npkts++; 2190170589Syongari } 2191170589Syongari 2192170589Syongari if (prog > 0) 2193170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2194170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2195170589Syongari 2196193096Sattilio if (rx_npktsp != NULL) 2197193096Sattilio *rx_npktsp = rx_npkts; 2198170589Syongari return (count > 0 ? 0 : EAGAIN); 2199170589Syongari} 2200170589Syongari 2201170589Syongari 2202170589Syongaristatic int 2203193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2204170589Syongari{ 2205170589Syongari struct ifnet *ifp = sc->nfe_ifp; 2206170589Syongari struct nfe_desc32 *desc32; 2207170589Syongari struct nfe_desc64 *desc64; 2208170589Syongari struct nfe_rx_data *data; 2209170589Syongari struct mbuf *m; 2210170589Syongari uint16_t flags; 2211193096Sattilio int len, prog, rx_npkts; 2212170589Syongari uint32_t vtag = 0; 2213170589Syongari 2214193096Sattilio rx_npkts = 0; 2215170589Syongari NFE_LOCK_ASSERT(sc); 2216170589Syongari 2217170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2218170589Syongari BUS_DMASYNC_POSTREAD); 2219170589Syongari 2220170589Syongari for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2221170589Syongari vtag = 0) { 2222170589Syongari if (count <= 0) 2223170589Syongari break; 2224170589Syongari count--; 2225170589Syongari 2226170589Syongari data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2227170589Syongari 2228170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2229170589Syongari desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2230170589Syongari vtag = le32toh(desc64->physaddr[1]); 2231170589Syongari flags = le16toh(desc64->flags); 2232170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2233170589Syongari } else { 2234170589Syongari desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2235170589Syongari flags = le16toh(desc32->flags); 2236170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2237170589Syongari } 2238170589Syongari 2239170589Syongari if (flags & NFE_RX_READY) 2240170589Syongari break; 2241170589Syongari prog++; 2242170589Syongari if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2243170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2244170589Syongari ifp->if_ierrors++; 2245170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2246170589Syongari continue; 2247170589Syongari } 2248170589Syongari if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2249170589Syongari flags &= ~NFE_RX_ERROR; 2250170589Syongari len--; /* fix buffer length */ 2251170589Syongari } 2252170589Syongari } else { 2253170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2254170589Syongari ifp->if_ierrors++; 2255170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2256170589Syongari continue; 2257170589Syongari } 2258170589Syongari 2259170589Syongari if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2260170589Syongari flags &= ~NFE_RX_ERROR; 2261170589Syongari len--; /* fix buffer length */ 2262170589Syongari } 2263170589Syongari } 2264170589Syongari 2265170589Syongari if (flags & NFE_RX_ERROR) { 2266164651Sobrien ifp->if_ierrors++; 2267170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2268170589Syongari continue; 2269164651Sobrien } 2270159952Sobrien 2271159952Sobrien m = data->m; 2272170589Syongari if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2273170589Syongari ifp->if_iqdrops++; 2274170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2275170589Syongari continue; 2276170589Syongari } 2277159952Sobrien 2278170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2279170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2280170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2281170589Syongari m->m_flags |= M_VLANTAG; 2282170589Syongari } 2283170589Syongari 2284159952Sobrien m->m_pkthdr.len = m->m_len = len; 2285159952Sobrien m->m_pkthdr.rcvif = ifp; 2286159952Sobrien 2287170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2288170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2289170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2290159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2291170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2292170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2293170589Syongari m->m_pkthdr.csum_flags |= 2294170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2295170589Syongari m->m_pkthdr.csum_data = 0xffff; 2296170589Syongari } 2297159967Sobrien } 2298159952Sobrien } 2299159952Sobrien 2300159952Sobrien ifp->if_ipackets++; 2301159952Sobrien 2302159967Sobrien NFE_UNLOCK(sc); 2303159967Sobrien (*ifp->if_input)(ifp, m); 2304159967Sobrien NFE_LOCK(sc); 2305193096Sattilio rx_npkts++; 2306170589Syongari } 2307159967Sobrien 2308170589Syongari if (prog > 0) 2309170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2310170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2311159952Sobrien 2312193096Sattilio if (rx_npktsp != NULL) 2313193096Sattilio *rx_npktsp = rx_npkts; 2314170589Syongari return (count > 0 ? 0 : EAGAIN); 2315159952Sobrien} 2316159952Sobrien 2317163503Sobrien 2318163503Sobrienstatic void 2319163503Sobriennfe_txeof(struct nfe_softc *sc) 2320159952Sobrien{ 2321159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2322159952Sobrien struct nfe_desc32 *desc32; 2323159952Sobrien struct nfe_desc64 *desc64; 2324159952Sobrien struct nfe_tx_data *data = NULL; 2325170589Syongari uint16_t flags; 2326170589Syongari int cons, prog; 2327159952Sobrien 2328159967Sobrien NFE_LOCK_ASSERT(sc); 2329159967Sobrien 2330170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2331170589Syongari BUS_DMASYNC_POSTREAD); 2332170589Syongari 2333170589Syongari prog = 0; 2334170589Syongari for (cons = sc->txq.next; cons != sc->txq.cur; 2335170589Syongari NFE_INC(cons, NFE_TX_RING_COUNT)) { 2336159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2337170589Syongari desc64 = &sc->txq.desc64[cons]; 2338170589Syongari flags = le16toh(desc64->flags); 2339159952Sobrien } else { 2340170589Syongari desc32 = &sc->txq.desc32[cons]; 2341170589Syongari flags = le16toh(desc32->flags); 2342159952Sobrien } 2343159952Sobrien 2344159952Sobrien if (flags & NFE_TX_VALID) 2345159952Sobrien break; 2346159952Sobrien 2347170589Syongari prog++; 2348170589Syongari sc->txq.queued--; 2349170589Syongari data = &sc->txq.data[cons]; 2350159952Sobrien 2351159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2352170589Syongari if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2353170589Syongari continue; 2354159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 2355170589Syongari device_printf(sc->nfe_dev, 2356170589Syongari "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2357159967Sobrien 2358159952Sobrien ifp->if_oerrors++; 2359159952Sobrien } else 2360159952Sobrien ifp->if_opackets++; 2361159952Sobrien } else { 2362170589Syongari if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2363170589Syongari continue; 2364159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 2365170589Syongari device_printf(sc->nfe_dev, 2366170589Syongari "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2367159952Sobrien ifp->if_oerrors++; 2368159952Sobrien } else 2369159952Sobrien ifp->if_opackets++; 2370159952Sobrien } 2371159952Sobrien 2372159952Sobrien /* last fragment of the mbuf chain transmitted */ 2373170589Syongari KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2374170589Syongari bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2375159967Sobrien BUS_DMASYNC_POSTWRITE); 2376170589Syongari bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2377159952Sobrien m_freem(data->m); 2378159952Sobrien data->m = NULL; 2379159952Sobrien } 2380159952Sobrien 2381170589Syongari if (prog > 0) { 2382170589Syongari sc->nfe_force_tx = 0; 2383170589Syongari sc->txq.next = cons; 2384159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2385170589Syongari if (sc->txq.queued == 0) 2386170589Syongari sc->nfe_watchdog_timer = 0; 2387159952Sobrien } 2388159952Sobrien} 2389159952Sobrien 2390163503Sobrienstatic int 2391170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2392159952Sobrien{ 2393170589Syongari struct nfe_desc32 *desc32 = NULL; 2394170589Syongari struct nfe_desc64 *desc64 = NULL; 2395159952Sobrien bus_dmamap_t map; 2396163503Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2397170589Syongari int error, i, nsegs, prod, si; 2398170589Syongari uint32_t tso_segsz; 2399170589Syongari uint16_t cflags, flags; 2400170589Syongari struct mbuf *m; 2401159952Sobrien 2402170589Syongari prod = si = sc->txq.cur; 2403170589Syongari map = sc->txq.data[prod].tx_data_map; 2404159952Sobrien 2405170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2406159967Sobrien &nsegs, BUS_DMA_NOWAIT); 2407170589Syongari if (error == EFBIG) { 2408175418Sjhb m = m_collapse(*m_head, M_DONTWAIT, NFE_MAX_SCATTER); 2409170589Syongari if (m == NULL) { 2410170589Syongari m_freem(*m_head); 2411170589Syongari *m_head = NULL; 2412170589Syongari return (ENOBUFS); 2413170589Syongari } 2414170589Syongari *m_head = m; 2415170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2416170589Syongari *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2417170589Syongari if (error != 0) { 2418170589Syongari m_freem(*m_head); 2419170589Syongari *m_head = NULL; 2420170589Syongari return (ENOBUFS); 2421170589Syongari } 2422170589Syongari } else if (error != 0) 2423170589Syongari return (error); 2424170589Syongari if (nsegs == 0) { 2425170589Syongari m_freem(*m_head); 2426170589Syongari *m_head = NULL; 2427170589Syongari return (EIO); 2428159952Sobrien } 2429159952Sobrien 2430170589Syongari if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2431159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2432170589Syongari return (ENOBUFS); 2433159952Sobrien } 2434159952Sobrien 2435170589Syongari m = *m_head; 2436170589Syongari cflags = flags = 0; 2437170589Syongari tso_segsz = 0; 2438206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2439206876Syongari tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz << 2440206876Syongari NFE_TX_TSO_SHIFT; 2441206876Syongari cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2442206876Syongari cflags |= NFE_TX_TSO; 2443206876Syongari } else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2444170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2445170589Syongari cflags |= NFE_TX_IP_CSUM; 2446170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2447170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2448170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2449170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2450164656Sobrien } 2451159967Sobrien 2452159967Sobrien for (i = 0; i < nsegs; i++) { 2453159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2454170589Syongari desc64 = &sc->txq.desc64[prod]; 2455170589Syongari desc64->physaddr[0] = 2456170589Syongari htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2457170589Syongari desc64->physaddr[1] = 2458170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2459170589Syongari desc64->vtag = 0; 2460159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 2461159952Sobrien desc64->flags = htole16(flags); 2462159952Sobrien } else { 2463170589Syongari desc32 = &sc->txq.desc32[prod]; 2464170589Syongari desc32->physaddr = 2465170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2466159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 2467159952Sobrien desc32->flags = htole16(flags); 2468159952Sobrien } 2469159952Sobrien 2470170589Syongari /* 2471170589Syongari * Setting of the valid bit in the first descriptor is 2472170589Syongari * deferred until the whole chain is fully setup. 2473170589Syongari */ 2474170589Syongari flags |= NFE_TX_VALID; 2475163503Sobrien 2476159952Sobrien sc->txq.queued++; 2477170589Syongari NFE_INC(prod, NFE_TX_RING_COUNT); 2478159952Sobrien } 2479159952Sobrien 2480170589Syongari /* 2481170589Syongari * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2482170589Syongari * csum flags, vtag and TSO belong to the first fragment only. 2483170589Syongari */ 2484159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2485170589Syongari desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2486170589Syongari desc64 = &sc->txq.desc64[si]; 2487170589Syongari if ((m->m_flags & M_VLANTAG) != 0) 2488170589Syongari desc64->vtag = htole32(NFE_TX_VTAG | 2489170589Syongari m->m_pkthdr.ether_vtag); 2490170589Syongari if (tso_segsz != 0) { 2491170589Syongari /* 2492170589Syongari * XXX 2493170589Syongari * The following indicates the descriptor element 2494170589Syongari * is a 32bit quantity. 2495170589Syongari */ 2496170589Syongari desc64->length |= htole16((uint16_t)tso_segsz); 2497170589Syongari desc64->flags |= htole16(tso_segsz >> 16); 2498170589Syongari } 2499170589Syongari /* 2500170589Syongari * finally, set the valid/checksum/TSO bit in the first 2501170589Syongari * descriptor. 2502170589Syongari */ 2503170589Syongari desc64->flags |= htole16(NFE_TX_VALID | cflags); 2504159952Sobrien } else { 2505159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 2506170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2507159952Sobrien else 2508170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2509170589Syongari desc32 = &sc->txq.desc32[si]; 2510170589Syongari if (tso_segsz != 0) { 2511170589Syongari /* 2512170589Syongari * XXX 2513170589Syongari * The following indicates the descriptor element 2514170589Syongari * is a 32bit quantity. 2515170589Syongari */ 2516170589Syongari desc32->length |= htole16((uint16_t)tso_segsz); 2517170589Syongari desc32->flags |= htole16(tso_segsz >> 16); 2518170589Syongari } 2519170589Syongari /* 2520170589Syongari * finally, set the valid/checksum/TSO bit in the first 2521170589Syongari * descriptor. 2522170589Syongari */ 2523170589Syongari desc32->flags |= htole16(NFE_TX_VALID | cflags); 2524159952Sobrien } 2525159952Sobrien 2526170589Syongari sc->txq.cur = prod; 2527170589Syongari prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2528170589Syongari sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2529170589Syongari sc->txq.data[prod].tx_data_map = map; 2530170589Syongari sc->txq.data[prod].m = m; 2531159952Sobrien 2532159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2533159952Sobrien 2534170589Syongari return (0); 2535159952Sobrien} 2536159952Sobrien 2537159967Sobrien 2538163503Sobrienstatic void 2539163503Sobriennfe_setmulti(struct nfe_softc *sc) 2540159952Sobrien{ 2541159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2542163503Sobrien struct ifmultiaddr *ifma; 2543163503Sobrien int i; 2544170589Syongari uint32_t filter; 2545170589Syongari uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2546170589Syongari uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 2547163503Sobrien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2548163503Sobrien }; 2549159967Sobrien 2550159967Sobrien NFE_LOCK_ASSERT(sc); 2551159967Sobrien 2552159967Sobrien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2553159967Sobrien bzero(addr, ETHER_ADDR_LEN); 2554159967Sobrien bzero(mask, ETHER_ADDR_LEN); 2555159967Sobrien goto done; 2556159967Sobrien } 2557159967Sobrien 2558159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2559159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2560159967Sobrien 2561195049Srwatson if_maddr_rlock(ifp); 2562159967Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2563159967Sobrien u_char *addrp; 2564159967Sobrien 2565159967Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 2566159967Sobrien continue; 2567159967Sobrien 2568159967Sobrien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 2569159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2570159967Sobrien u_int8_t mcaddr = addrp[i]; 2571159967Sobrien addr[i] &= mcaddr; 2572159967Sobrien mask[i] &= ~mcaddr; 2573159967Sobrien } 2574159967Sobrien } 2575195049Srwatson if_maddr_runlock(ifp); 2576159967Sobrien 2577159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2578159967Sobrien mask[i] |= addr[i]; 2579159967Sobrien } 2580159967Sobrien 2581159967Sobriendone: 2582159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 2583159967Sobrien 2584159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2585159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2586159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2587159967Sobrien addr[5] << 8 | addr[4]); 2588159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2589159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2590159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2591159967Sobrien mask[5] << 8 | mask[4]); 2592159967Sobrien 2593170589Syongari filter = NFE_READ(sc, NFE_RXFILTER); 2594170589Syongari filter &= NFE_PFF_RX_PAUSE; 2595170589Syongari filter |= NFE_RXFILTER_MAGIC; 2596170589Syongari filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2597159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 2598159967Sobrien} 2599159967Sobrien 2600163503Sobrien 2601163503Sobrienstatic void 2602216925Sjhbnfe_start(struct ifnet *ifp) 2603159967Sobrien{ 2604216925Sjhb struct nfe_softc *sc = ifp->if_softc; 2605159967Sobrien 2606216925Sjhb NFE_LOCK(sc); 2607216925Sjhb nfe_start_locked(ifp); 2608216925Sjhb NFE_UNLOCK(sc); 2609159967Sobrien} 2610159967Sobrien 2611163503Sobrienstatic void 2612216925Sjhbnfe_start_locked(struct ifnet *ifp) 2613159967Sobrien{ 2614159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2615163503Sobrien struct mbuf *m0; 2616170589Syongari int enq; 2617159952Sobrien 2618216925Sjhb NFE_LOCK_ASSERT(sc); 2619170589Syongari 2620170589Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2621216925Sjhb IFF_DRV_RUNNING || sc->nfe_link == 0) 2622159967Sobrien return; 2623159967Sobrien 2624170589Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 2625170589Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2626159952Sobrien if (m0 == NULL) 2627159952Sobrien break; 2628159952Sobrien 2629170589Syongari if (nfe_encap(sc, &m0) != 0) { 2630170589Syongari if (m0 == NULL) 2631170589Syongari break; 2632170589Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2633159967Sobrien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2634159952Sobrien break; 2635159952Sobrien } 2636170589Syongari enq++; 2637167190Scsjp ETHER_BPF_MTAP(ifp, m0); 2638159952Sobrien } 2639159952Sobrien 2640170589Syongari if (enq > 0) { 2641170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2642170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2643159952Sobrien 2644170589Syongari /* kick Tx */ 2645170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2646159952Sobrien 2647170589Syongari /* 2648170589Syongari * Set a timeout in case the chip goes out to lunch. 2649170589Syongari */ 2650170589Syongari sc->nfe_watchdog_timer = 5; 2651170589Syongari } 2652159952Sobrien} 2653159952Sobrien 2654163503Sobrien 2655163503Sobrienstatic void 2656163503Sobriennfe_watchdog(struct ifnet *ifp) 2657159952Sobrien{ 2658159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2659159952Sobrien 2660170589Syongari if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2661170589Syongari return; 2662159952Sobrien 2663170589Syongari /* Check if we've lost Tx completion interrupt. */ 2664170589Syongari nfe_txeof(sc); 2665170589Syongari if (sc->txq.queued == 0) { 2666170589Syongari if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2667170589Syongari "-- recovering\n"); 2668170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2669216925Sjhb nfe_start_locked(ifp); 2670170589Syongari return; 2671170589Syongari } 2672170589Syongari /* Check if we've lost start Tx command. */ 2673170589Syongari sc->nfe_force_tx++; 2674170589Syongari if (sc->nfe_force_tx <= 3) { 2675170589Syongari /* 2676170589Syongari * If this is the case for watchdog timeout, the following 2677170589Syongari * code should go to nfe_txeof(). 2678170589Syongari */ 2679170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2680170589Syongari return; 2681170589Syongari } 2682170589Syongari sc->nfe_force_tx = 0; 2683170589Syongari 2684170589Syongari if_printf(ifp, "watchdog timeout\n"); 2685170589Syongari 2686159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2687159952Sobrien ifp->if_oerrors++; 2688170589Syongari nfe_init_locked(sc); 2689159952Sobrien} 2690159952Sobrien 2691163503Sobrien 2692163503Sobrienstatic void 2693163503Sobriennfe_init(void *xsc) 2694159952Sobrien{ 2695159967Sobrien struct nfe_softc *sc = xsc; 2696159952Sobrien 2697159967Sobrien NFE_LOCK(sc); 2698159967Sobrien nfe_init_locked(sc); 2699159967Sobrien NFE_UNLOCK(sc); 2700159967Sobrien} 2701159967Sobrien 2702163503Sobrien 2703163503Sobrienstatic void 2704163503Sobriennfe_init_locked(void *xsc) 2705159967Sobrien{ 2706159967Sobrien struct nfe_softc *sc = xsc; 2707159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2708159967Sobrien struct mii_data *mii; 2709170589Syongari uint32_t val; 2710170589Syongari int error; 2711159967Sobrien 2712159967Sobrien NFE_LOCK_ASSERT(sc); 2713159967Sobrien 2714159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2715159967Sobrien 2716170589Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2717159967Sobrien return; 2718170589Syongari 2719170589Syongari nfe_stop(ifp); 2720170589Syongari 2721170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 2722170589Syongari 2723170589Syongari nfe_init_tx_ring(sc, &sc->txq); 2724170589Syongari if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2725170589Syongari error = nfe_init_jrx_ring(sc, &sc->jrxq); 2726170589Syongari else 2727170589Syongari error = nfe_init_rx_ring(sc, &sc->rxq); 2728170589Syongari if (error != 0) { 2729170589Syongari device_printf(sc->nfe_dev, 2730170589Syongari "initialization failed: no memory for rx buffers\n"); 2731170589Syongari nfe_stop(ifp); 2732170589Syongari return; 2733159967Sobrien } 2734159967Sobrien 2735170589Syongari val = 0; 2736170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2737170589Syongari val |= NFE_MAC_ADDR_INORDER; 2738170589Syongari NFE_WRITE(sc, NFE_TX_UNK, val); 2739159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 2740159952Sobrien 2741170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2742170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2743170589Syongari 2744159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 2745159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 2746159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2747159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2748159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 2749164656Sobrien 2750170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 2751159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2752170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2753170589Syongari sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2754159967Sobrien 2755159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2756159952Sobrien DELAY(10); 2757159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2758159952Sobrien 2759170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2760159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2761170589Syongari else 2762170589Syongari NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2763159952Sobrien 2764159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2765159952Sobrien 2766159952Sobrien /* set MAC address */ 2767170589Syongari nfe_set_macaddr(sc, IF_LLADDR(ifp)); 2768159952Sobrien 2769159952Sobrien /* tell MAC where rings are in memory */ 2770170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2771170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2772170589Syongari NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2773170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2774170589Syongari NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2775170589Syongari } else { 2776170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2777170589Syongari NFE_ADDR_HI(sc->rxq.physaddr)); 2778170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2779170589Syongari NFE_ADDR_LO(sc->rxq.physaddr)); 2780170589Syongari } 2781170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2782170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2783159952Sobrien 2784159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 2785159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 2786159952Sobrien (NFE_TX_RING_COUNT - 1)); 2787159952Sobrien 2788170589Syongari NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2789159952Sobrien 2790159952Sobrien /* force MAC to wakeup */ 2791170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2792170589Syongari if ((val & NFE_PWR_WAKEUP) == 0) 2793170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2794159952Sobrien DELAY(10); 2795170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2796170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2797159952Sobrien 2798159952Sobrien#if 1 2799159952Sobrien /* configure interrupts coalescing/mitigation */ 2800159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2801159952Sobrien#else 2802159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 2803159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 2804159952Sobrien#endif 2805159952Sobrien 2806170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2807159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2808159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2809159952Sobrien 2810159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2811159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2812159952Sobrien 2813159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2814215132Syongari /* Disable WOL. */ 2815215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, 0); 2816159952Sobrien 2817159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2818159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2819159952Sobrien DELAY(10); 2820159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2821159952Sobrien 2822159952Sobrien /* set Rx filter */ 2823159952Sobrien nfe_setmulti(sc); 2824159952Sobrien 2825159952Sobrien /* enable Rx */ 2826159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2827159952Sobrien 2828159952Sobrien /* enable Tx */ 2829159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2830159952Sobrien 2831159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2832159952Sobrien 2833183561Syongari /* Clear hardware stats. */ 2834183561Syongari nfe_stats_clear(sc); 2835183561Syongari 2836159967Sobrien#ifdef DEVICE_POLLING 2837159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) 2838170589Syongari nfe_disable_intr(sc); 2839159967Sobrien else 2840159967Sobrien#endif 2841170589Syongari nfe_set_intr(sc); 2842170589Syongari nfe_enable_intr(sc); /* enable interrupts */ 2843159952Sobrien 2844159967Sobrien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2845159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2846159952Sobrien 2847159967Sobrien sc->nfe_link = 0; 2848170589Syongari mii_mediachg(mii); 2849159952Sobrien 2850170589Syongari callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2851159952Sobrien} 2852159952Sobrien 2853163503Sobrien 2854163503Sobrienstatic void 2855170589Syongarinfe_stop(struct ifnet *ifp) 2856159952Sobrien{ 2857159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2858170589Syongari struct nfe_rx_ring *rx_ring; 2859170589Syongari struct nfe_jrx_ring *jrx_ring; 2860170589Syongari struct nfe_tx_ring *tx_ring; 2861170589Syongari struct nfe_rx_data *rdata; 2862170589Syongari struct nfe_tx_data *tdata; 2863170589Syongari int i; 2864159952Sobrien 2865159967Sobrien NFE_LOCK_ASSERT(sc); 2866159952Sobrien 2867170589Syongari sc->nfe_watchdog_timer = 0; 2868159967Sobrien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2869159952Sobrien 2870159967Sobrien callout_stop(&sc->nfe_stat_ch); 2871159967Sobrien 2872159952Sobrien /* abort Tx */ 2873159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 2874159952Sobrien 2875159952Sobrien /* disable Rx */ 2876159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 2877159952Sobrien 2878159952Sobrien /* disable interrupts */ 2879170589Syongari nfe_disable_intr(sc); 2880159952Sobrien 2881159967Sobrien sc->nfe_link = 0; 2882159967Sobrien 2883170589Syongari /* free Rx and Tx mbufs still in the queues. */ 2884170589Syongari rx_ring = &sc->rxq; 2885170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2886170589Syongari rdata = &rx_ring->data[i]; 2887170589Syongari if (rdata->m != NULL) { 2888170589Syongari bus_dmamap_sync(rx_ring->rx_data_tag, 2889170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2890170589Syongari bus_dmamap_unload(rx_ring->rx_data_tag, 2891170589Syongari rdata->rx_data_map); 2892170589Syongari m_freem(rdata->m); 2893170589Syongari rdata->m = NULL; 2894170589Syongari } 2895170589Syongari } 2896159952Sobrien 2897170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 2898170589Syongari jrx_ring = &sc->jrxq; 2899170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 2900170589Syongari rdata = &jrx_ring->jdata[i]; 2901170589Syongari if (rdata->m != NULL) { 2902170589Syongari bus_dmamap_sync(jrx_ring->jrx_data_tag, 2903170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2904170589Syongari bus_dmamap_unload(jrx_ring->jrx_data_tag, 2905170589Syongari rdata->rx_data_map); 2906170589Syongari m_freem(rdata->m); 2907170589Syongari rdata->m = NULL; 2908170589Syongari } 2909170589Syongari } 2910170589Syongari } 2911170589Syongari 2912170589Syongari tx_ring = &sc->txq; 2913170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2914170589Syongari tdata = &tx_ring->data[i]; 2915170589Syongari if (tdata->m != NULL) { 2916170589Syongari bus_dmamap_sync(tx_ring->tx_data_tag, 2917170589Syongari tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 2918170589Syongari bus_dmamap_unload(tx_ring->tx_data_tag, 2919170589Syongari tdata->tx_data_map); 2920170589Syongari m_freem(tdata->m); 2921170589Syongari tdata->m = NULL; 2922170589Syongari } 2923170589Syongari } 2924183561Syongari /* Update hardware stats. */ 2925183561Syongari nfe_stats_update(sc); 2926159952Sobrien} 2927159952Sobrien 2928163503Sobrien 2929163503Sobrienstatic int 2930163503Sobriennfe_ifmedia_upd(struct ifnet *ifp) 2931159952Sobrien{ 2932159967Sobrien struct nfe_softc *sc = ifp->if_softc; 2933170589Syongari struct mii_data *mii; 2934159952Sobrien 2935159967Sobrien NFE_LOCK(sc); 2936159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2937159967Sobrien mii_mediachg(mii); 2938170589Syongari NFE_UNLOCK(sc); 2939159967Sobrien 2940159967Sobrien return (0); 2941159952Sobrien} 2942159952Sobrien 2943163503Sobrien 2944163503Sobrienstatic void 2945163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2946159952Sobrien{ 2947163503Sobrien struct nfe_softc *sc; 2948163503Sobrien struct mii_data *mii; 2949159952Sobrien 2950159967Sobrien sc = ifp->if_softc; 2951159952Sobrien 2952159967Sobrien NFE_LOCK(sc); 2953159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2954159967Sobrien mii_pollstat(mii); 2955159967Sobrien NFE_UNLOCK(sc); 2956159952Sobrien 2957159967Sobrien ifmr->ifm_active = mii->mii_media_active; 2958159967Sobrien ifmr->ifm_status = mii->mii_media_status; 2959159952Sobrien} 2960159952Sobrien 2961163503Sobrien 2962170589Syongarivoid 2963159967Sobriennfe_tick(void *xsc) 2964159952Sobrien{ 2965159967Sobrien struct nfe_softc *sc; 2966163503Sobrien struct mii_data *mii; 2967163503Sobrien struct ifnet *ifp; 2968159952Sobrien 2969170589Syongari sc = (struct nfe_softc *)xsc; 2970159952Sobrien 2971163503Sobrien NFE_LOCK_ASSERT(sc); 2972159952Sobrien 2973159967Sobrien ifp = sc->nfe_ifp; 2974159952Sobrien 2975159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2976159967Sobrien mii_tick(mii); 2977183561Syongari nfe_stats_update(sc); 2978170589Syongari nfe_watchdog(ifp); 2979159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2980159952Sobrien} 2981159952Sobrien 2982159952Sobrien 2983173839Syongaristatic int 2984163503Sobriennfe_shutdown(device_t dev) 2985159952Sobrien{ 2986159952Sobrien 2987215132Syongari return (nfe_suspend(dev)); 2988159952Sobrien} 2989159952Sobrien 2990159952Sobrien 2991163503Sobrienstatic void 2992170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 2993159952Sobrien{ 2994170589Syongari uint32_t val; 2995159952Sobrien 2996170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 2997170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 2998170589Syongari addr[0] = (val >> 8) & 0xff; 2999170589Syongari addr[1] = (val & 0xff); 3000159952Sobrien 3001170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3002170589Syongari addr[2] = (val >> 24) & 0xff; 3003170589Syongari addr[3] = (val >> 16) & 0xff; 3004170589Syongari addr[4] = (val >> 8) & 0xff; 3005170589Syongari addr[5] = (val & 0xff); 3006170589Syongari } else { 3007170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3008170589Syongari addr[5] = (val >> 8) & 0xff; 3009170589Syongari addr[4] = (val & 0xff); 3010170589Syongari 3011170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3012170589Syongari addr[3] = (val >> 24) & 0xff; 3013170589Syongari addr[2] = (val >> 16) & 0xff; 3014170589Syongari addr[1] = (val >> 8) & 0xff; 3015170589Syongari addr[0] = (val & 0xff); 3016170589Syongari } 3017159952Sobrien} 3018159952Sobrien 3019163503Sobrien 3020163503Sobrienstatic void 3021170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 3022159952Sobrien{ 3023159967Sobrien 3024159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 3025159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 3026159967Sobrien addr[1] << 8 | addr[0]); 3027159952Sobrien} 3028159952Sobrien 3029163503Sobrien 3030159967Sobrien/* 3031159967Sobrien * Map a single buffer address. 3032159967Sobrien */ 3033159967Sobrien 3034159967Sobrienstatic void 3035170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3036159952Sobrien{ 3037170589Syongari struct nfe_dmamap_arg *ctx; 3038159952Sobrien 3039170589Syongari if (error != 0) 3040159967Sobrien return; 3041159952Sobrien 3042159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 3043159967Sobrien 3044170589Syongari ctx = (struct nfe_dmamap_arg *)arg; 3045170589Syongari ctx->nfe_busaddr = segs[0].ds_addr; 3046170589Syongari} 3047159967Sobrien 3048170589Syongari 3049170589Syongaristatic int 3050170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3051170589Syongari{ 3052170589Syongari int error, value; 3053170589Syongari 3054170589Syongari if (!arg1) 3055170589Syongari return (EINVAL); 3056170589Syongari value = *(int *)arg1; 3057170589Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3058170589Syongari if (error || !req->newptr) 3059170589Syongari return (error); 3060170589Syongari if (value < low || value > high) 3061170589Syongari return (EINVAL); 3062170589Syongari *(int *)arg1 = value; 3063170589Syongari 3064170589Syongari return (0); 3065159952Sobrien} 3066170589Syongari 3067170589Syongari 3068170589Syongaristatic int 3069170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 3070170589Syongari{ 3071170589Syongari 3072170589Syongari return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 3073170589Syongari NFE_PROC_MAX)); 3074170589Syongari} 3075183561Syongari 3076183561Syongari 3077183561Syongari#define NFE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 3078183561Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 3079183561Syongari#define NFE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 3080217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 3081183561Syongari 3082183561Syongaristatic void 3083183561Syongarinfe_sysctl_node(struct nfe_softc *sc) 3084183561Syongari{ 3085183561Syongari struct sysctl_ctx_list *ctx; 3086183561Syongari struct sysctl_oid_list *child, *parent; 3087183561Syongari struct sysctl_oid *tree; 3088183561Syongari struct nfe_hw_stats *stats; 3089183561Syongari int error; 3090183561Syongari 3091183561Syongari stats = &sc->nfe_stats; 3092183561Syongari ctx = device_get_sysctl_ctx(sc->nfe_dev); 3093183561Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev)); 3094183561Syongari SYSCTL_ADD_PROC(ctx, child, 3095183561Syongari OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 3096183561Syongari &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 3097183561Syongari "max number of Rx events to process"); 3098183561Syongari 3099183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3100183561Syongari error = resource_int_value(device_get_name(sc->nfe_dev), 3101183561Syongari device_get_unit(sc->nfe_dev), "process_limit", 3102183561Syongari &sc->nfe_process_limit); 3103183561Syongari if (error == 0) { 3104183561Syongari if (sc->nfe_process_limit < NFE_PROC_MIN || 3105183561Syongari sc->nfe_process_limit > NFE_PROC_MAX) { 3106183561Syongari device_printf(sc->nfe_dev, 3107183561Syongari "process_limit value out of range; " 3108183561Syongari "using default: %d\n", NFE_PROC_DEFAULT); 3109183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3110183561Syongari } 3111183561Syongari } 3112183561Syongari 3113183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3114183561Syongari return; 3115183561Syongari 3116183561Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 3117183561Syongari NULL, "NFE statistics"); 3118183561Syongari parent = SYSCTL_CHILDREN(tree); 3119183561Syongari 3120183561Syongari /* Rx statistics. */ 3121183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 3122183561Syongari NULL, "Rx MAC statistics"); 3123183561Syongari child = SYSCTL_CHILDREN(tree); 3124183561Syongari 3125183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors", 3126183561Syongari &stats->rx_frame_errors, "Framing Errors"); 3127183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes", 3128183561Syongari &stats->rx_extra_bytes, "Extra Bytes"); 3129183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3130183561Syongari &stats->rx_late_cols, "Late Collisions"); 3131183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "runts", 3132183561Syongari &stats->rx_runts, "Runts"); 3133183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos", 3134183561Syongari &stats->rx_jumbos, "Jumbos"); 3135183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns", 3136183561Syongari &stats->rx_fifo_overuns, "FIFO Overruns"); 3137183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors", 3138183561Syongari &stats->rx_crc_errors, "CRC Errors"); 3139183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fae", 3140183561Syongari &stats->rx_fae, "Frame Alignment Errors"); 3141183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors", 3142183561Syongari &stats->rx_len_errors, "Length Errors"); 3143183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3144183561Syongari &stats->rx_unicast, "Unicast Frames"); 3145183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3146183561Syongari &stats->rx_multicast, "Multicast Frames"); 3147186346Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3148183561Syongari &stats->rx_broadcast, "Broadcast Frames"); 3149183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3150183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3151183561Syongari &stats->rx_octets, "Octets"); 3152183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3153183561Syongari &stats->rx_pause, "Pause frames"); 3154183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "drops", 3155183561Syongari &stats->rx_drops, "Drop frames"); 3156183561Syongari } 3157183561Syongari 3158183561Syongari /* Tx statistics. */ 3159183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 3160183561Syongari NULL, "Tx MAC statistics"); 3161183561Syongari child = SYSCTL_CHILDREN(tree); 3162183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3163183561Syongari &stats->tx_octets, "Octets"); 3164183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits", 3165183561Syongari &stats->tx_zero_rexmits, "Zero Retransmits"); 3166183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits", 3167183561Syongari &stats->tx_one_rexmits, "One Retransmits"); 3168183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits", 3169183561Syongari &stats->tx_multi_rexmits, "Multiple Retransmits"); 3170183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3171183561Syongari &stats->tx_late_cols, "Late Collisions"); 3172183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns", 3173183561Syongari &stats->tx_fifo_underuns, "FIFO Underruns"); 3174183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts", 3175183561Syongari &stats->tx_carrier_losts, "Carrier Losts"); 3176183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals", 3177183561Syongari &stats->tx_excess_deferals, "Excess Deferrals"); 3178183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors", 3179183561Syongari &stats->tx_retry_errors, "Retry Errors"); 3180183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3181183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals", 3182183561Syongari &stats->tx_deferals, "Deferrals"); 3183183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frames", 3184183561Syongari &stats->tx_frames, "Frames"); 3185183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3186183561Syongari &stats->tx_pause, "Pause Frames"); 3187183561Syongari } 3188183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3189183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3190183561Syongari &stats->tx_deferals, "Unicast Frames"); 3191183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3192183561Syongari &stats->tx_frames, "Multicast Frames"); 3193183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3194183561Syongari &stats->tx_pause, "Broadcast Frames"); 3195183561Syongari } 3196183561Syongari} 3197183561Syongari 3198183561Syongari#undef NFE_SYSCTL_STAT_ADD32 3199183561Syongari#undef NFE_SYSCTL_STAT_ADD64 3200183561Syongari 3201183561Syongaristatic void 3202183561Syongarinfe_stats_clear(struct nfe_softc *sc) 3203183561Syongari{ 3204183561Syongari int i, mib_cnt; 3205183561Syongari 3206183561Syongari if ((sc->nfe_flags & NFE_MIB_V1) != 0) 3207183561Syongari mib_cnt = NFE_NUM_MIB_STATV1; 3208183561Syongari else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0) 3209183561Syongari mib_cnt = NFE_NUM_MIB_STATV2; 3210183561Syongari else 3211183561Syongari return; 3212183561Syongari 3213183561Syongari for (i = 0; i < mib_cnt; i += sizeof(uint32_t)) 3214183561Syongari NFE_READ(sc, NFE_TX_OCTET + i); 3215183561Syongari 3216183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3217183561Syongari NFE_READ(sc, NFE_TX_UNICAST); 3218183561Syongari NFE_READ(sc, NFE_TX_MULTICAST); 3219183561Syongari NFE_READ(sc, NFE_TX_BROADCAST); 3220183561Syongari } 3221183561Syongari} 3222183561Syongari 3223183561Syongaristatic void 3224183561Syongarinfe_stats_update(struct nfe_softc *sc) 3225183561Syongari{ 3226183561Syongari struct nfe_hw_stats *stats; 3227183561Syongari 3228183561Syongari NFE_LOCK_ASSERT(sc); 3229183561Syongari 3230183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3231183561Syongari return; 3232183561Syongari 3233183561Syongari stats = &sc->nfe_stats; 3234183561Syongari stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET); 3235183561Syongari stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT); 3236183561Syongari stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT); 3237183561Syongari stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT); 3238183561Syongari stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL); 3239183561Syongari stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN); 3240183561Syongari stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST); 3241183561Syongari stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL); 3242183561Syongari stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR); 3243183561Syongari stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR); 3244183561Syongari stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES); 3245183561Syongari stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL); 3246183561Syongari stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT); 3247183561Syongari stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO); 3248183561Syongari stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN); 3249183561Syongari stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR); 3250183561Syongari stats->rx_fae += NFE_READ(sc, NFE_RX_FAE); 3251183561Syongari stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR); 3252183561Syongari stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST); 3253183561Syongari stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST); 3254183561Syongari stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST); 3255183561Syongari 3256183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3257183561Syongari stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL); 3258183561Syongari stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME); 3259183561Syongari stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET); 3260183561Syongari stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE); 3261183561Syongari stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE); 3262183561Syongari stats->rx_drops += NFE_READ(sc, NFE_RX_DROP); 3263183561Syongari } 3264183561Syongari 3265183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3266183561Syongari stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST); 3267183561Syongari stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST); 3268183561Syongari stats->rx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST); 3269183561Syongari } 3270183561Syongari} 3271215132Syongari 3272215132Syongari 3273215132Syongaristatic void 3274215132Syongarinfe_set_linkspeed(struct nfe_softc *sc) 3275215132Syongari{ 3276215132Syongari struct mii_softc *miisc; 3277215132Syongari struct mii_data *mii; 3278215132Syongari int aneg, i, phyno; 3279215132Syongari 3280215132Syongari NFE_LOCK_ASSERT(sc); 3281215132Syongari 3282215132Syongari mii = device_get_softc(sc->nfe_miibus); 3283215132Syongari mii_pollstat(mii); 3284215132Syongari aneg = 0; 3285215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 3286215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 3287215132Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 3288215132Syongari case IFM_10_T: 3289215132Syongari case IFM_100_TX: 3290215132Syongari return; 3291215132Syongari case IFM_1000_T: 3292215132Syongari aneg++; 3293215132Syongari break; 3294215132Syongari default: 3295215132Syongari break; 3296215132Syongari } 3297215132Syongari } 3298221407Smarius miisc = LIST_FIRST(&mii->mii_phys); 3299221407Smarius phyno = miisc->mii_phy; 3300221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 3301221407Smarius PHY_RESET(miisc); 3302215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0); 3303215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3304215132Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 3305215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3306215132Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 3307215132Syongari DELAY(1000); 3308215132Syongari if (aneg != 0) { 3309215132Syongari /* 3310215132Syongari * Poll link state until nfe(4) get a 10/100Mbps link. 3311215132Syongari */ 3312215132Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 3313215132Syongari mii_pollstat(mii); 3314215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 3315215132Syongari == (IFM_ACTIVE | IFM_AVALID)) { 3316215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 3317215132Syongari case IFM_10_T: 3318215132Syongari case IFM_100_TX: 3319215132Syongari nfe_mac_config(sc, mii); 3320215132Syongari return; 3321215132Syongari default: 3322215132Syongari break; 3323215132Syongari } 3324215132Syongari } 3325215132Syongari NFE_UNLOCK(sc); 3326215132Syongari pause("nfelnk", hz); 3327215132Syongari NFE_LOCK(sc); 3328215132Syongari } 3329215132Syongari if (i == MII_ANEGTICKS_GIGE) 3330215132Syongari device_printf(sc->nfe_dev, 3331215132Syongari "establishing a link failed, WOL may not work!"); 3332215132Syongari } 3333215132Syongari /* 3334215132Syongari * No link, force MAC to have 100Mbps, full-duplex link. 3335215132Syongari * This is the last resort and may/may not work. 3336215132Syongari */ 3337215132Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 3338215132Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 3339215132Syongari nfe_mac_config(sc, mii); 3340215132Syongari} 3341215132Syongari 3342215132Syongari 3343215132Syongaristatic void 3344215132Syongarinfe_set_wol(struct nfe_softc *sc) 3345215132Syongari{ 3346215132Syongari struct ifnet *ifp; 3347215132Syongari uint32_t wolctl; 3348215132Syongari int pmc; 3349215132Syongari uint16_t pmstat; 3350215132Syongari 3351215132Syongari NFE_LOCK_ASSERT(sc); 3352215132Syongari 3353219902Sjhb if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0) 3354215132Syongari return; 3355215132Syongari ifp = sc->nfe_ifp; 3356215132Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 3357215132Syongari wolctl = NFE_WOL_MAGIC; 3358215132Syongari else 3359215132Syongari wolctl = 0; 3360215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, wolctl); 3361215132Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) { 3362215132Syongari nfe_set_linkspeed(sc); 3363215132Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) != 0) 3364215132Syongari NFE_WRITE(sc, NFE_PWR2_CTL, 3365215132Syongari NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS); 3366215132Syongari /* Enable RX. */ 3367215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0); 3368215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0); 3369215132Syongari NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) | 3370215132Syongari NFE_RX_START); 3371215132Syongari } 3372215132Syongari /* Request PME if WOL is requested. */ 3373215132Syongari pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2); 3374215132Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 3375215132Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 3376215132Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 3377215132Syongari pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 3378215132Syongari} 3379