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: stable/11/sys/dev/nfe/if_nfe.c 342294 2018-12-21 02:26:08Z markj $"); 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> 44257176Sglebius#include <net/if_var.h> 45159967Sobrien#include <net/if_arp.h> 46159967Sobrien#include <net/ethernet.h> 47159952Sobrien#include <net/if_dl.h> 48159952Sobrien#include <net/if_media.h> 49159952Sobrien#include <net/if_types.h> 50159952Sobrien#include <net/if_vlan_var.h> 51159952Sobrien 52159952Sobrien#include <net/bpf.h> 53159952Sobrien 54159967Sobrien#include <machine/bus.h> 55159967Sobrien#include <machine/resource.h> 56159967Sobrien#include <sys/bus.h> 57159967Sobrien#include <sys/rman.h> 58159967Sobrien 59159952Sobrien#include <dev/mii/mii.h> 60159952Sobrien#include <dev/mii/miivar.h> 61159952Sobrien 62159952Sobrien#include <dev/pci/pcireg.h> 63159952Sobrien#include <dev/pci/pcivar.h> 64159952Sobrien 65159967Sobrien#include <dev/nfe/if_nfereg.h> 66159967Sobrien#include <dev/nfe/if_nfevar.h> 67159952Sobrien 68159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1); 69159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1); 70159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1); 71170589Syongari 72170589Syongari/* "device miibus" required. See GENERIC if you get errors here. */ 73159967Sobrien#include "miibus_if.h" 74159952Sobrien 75163503Sobrienstatic int nfe_probe(device_t); 76163503Sobrienstatic int nfe_attach(device_t); 77163503Sobrienstatic int nfe_detach(device_t); 78170589Syongaristatic int nfe_suspend(device_t); 79170589Syongaristatic int nfe_resume(device_t); 80173839Syongaristatic int nfe_shutdown(device_t); 81215327Syongaristatic int nfe_can_use_msix(struct nfe_softc *); 82264293Syongaristatic int nfe_detect_msik9(struct nfe_softc *); 83170589Syongaristatic void nfe_power(struct nfe_softc *); 84163503Sobrienstatic int nfe_miibus_readreg(device_t, int, int); 85163503Sobrienstatic int nfe_miibus_writereg(device_t, int, int, int); 86163503Sobrienstatic void nfe_miibus_statchg(device_t); 87215132Syongaristatic void nfe_mac_config(struct nfe_softc *, struct mii_data *); 88170589Syongaristatic void nfe_set_intr(struct nfe_softc *); 89170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *); 90170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *); 91268131Smarcelstatic int nfe_ioctl(if_t, u_long, caddr_t); 92170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int); 93170589Syongaristatic int nfe_intr(void *); 94170589Syongaristatic void nfe_int_task(void *, int); 95170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int); 96170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int); 97170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int); 98170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int); 99193096Sattiliostatic int nfe_rxeof(struct nfe_softc *, int, int *); 100193096Sattiliostatic int nfe_jrxeof(struct nfe_softc *, int, int *); 101159967Sobrienstatic void nfe_txeof(struct nfe_softc *); 102170589Syongaristatic int nfe_encap(struct nfe_softc *, struct mbuf **); 103159967Sobrienstatic void nfe_setmulti(struct nfe_softc *); 104268131Smarcelstatic void nfe_start(if_t); 105268131Smarcelstatic void nfe_start_locked(if_t); 106268131Smarcelstatic void nfe_watchdog(if_t); 107159967Sobrienstatic void nfe_init(void *); 108159967Sobrienstatic void nfe_init_locked(void *); 109268131Smarcelstatic void nfe_stop(if_t); 110159967Sobrienstatic int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 111171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 112170589Syongaristatic int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 113170589Syongaristatic int nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 114159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 115170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 116159967Sobrienstatic int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 117170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 118159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 119268131Smarcelstatic int nfe_ifmedia_upd(if_t); 120268131Smarcelstatic void nfe_ifmedia_sts(if_t, struct ifmediareq *); 121159967Sobrienstatic void nfe_tick(void *); 122170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 123170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *); 124170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); 125159952Sobrien 126170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 127170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); 128183561Syongaristatic void nfe_sysctl_node(struct nfe_softc *); 129183561Syongaristatic void nfe_stats_clear(struct nfe_softc *); 130183561Syongaristatic void nfe_stats_update(struct nfe_softc *); 131215132Syongaristatic void nfe_set_linkspeed(struct nfe_softc *); 132215132Syongaristatic void nfe_set_wol(struct nfe_softc *); 133170589Syongari 134159952Sobrien#ifdef NFE_DEBUG 135170589Syongaristatic int nfedebug = 0; 136170589Syongari#define DPRINTF(sc, ...) do { \ 137170589Syongari if (nfedebug) \ 138170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 139170589Syongari} while (0) 140170589Syongari#define DPRINTFN(sc, n, ...) do { \ 141170589Syongari if (nfedebug >= (n)) \ 142170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 143170589Syongari} while (0) 144159952Sobrien#else 145170589Syongari#define DPRINTF(sc, ...) 146170589Syongari#define DPRINTFN(sc, n, ...) 147159952Sobrien#endif 148159952Sobrien 149159967Sobrien#define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 150159967Sobrien#define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 151159967Sobrien#define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 152159967Sobrien 153170589Syongari/* Tunables. */ 154170589Syongaristatic int msi_disable = 0; 155170589Syongaristatic int msix_disable = 0; 156171559Syongaristatic int jumbo_disable = 0; 157170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable); 158170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable); 159171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable); 160159967Sobrien 161159967Sobrienstatic device_method_t nfe_methods[] = { 162159967Sobrien /* Device interface */ 163159967Sobrien DEVMETHOD(device_probe, nfe_probe), 164159967Sobrien DEVMETHOD(device_attach, nfe_attach), 165159967Sobrien DEVMETHOD(device_detach, nfe_detach), 166170589Syongari DEVMETHOD(device_suspend, nfe_suspend), 167170589Syongari DEVMETHOD(device_resume, nfe_resume), 168159967Sobrien DEVMETHOD(device_shutdown, nfe_shutdown), 169159967Sobrien 170159967Sobrien /* MII interface */ 171159967Sobrien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 172159967Sobrien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 173163503Sobrien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 174159967Sobrien 175227843Smarius DEVMETHOD_END 176159952Sobrien}; 177159952Sobrien 178159967Sobrienstatic driver_t nfe_driver = { 179159967Sobrien "nfe", 180159967Sobrien nfe_methods, 181159967Sobrien sizeof(struct nfe_softc) 182159967Sobrien}; 183159967Sobrien 184159967Sobrienstatic devclass_t nfe_devclass; 185159967Sobrien 186159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 187159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 188159967Sobrien 189159967Sobrienstatic struct nfe_type nfe_devs[] = { 190159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 191163503Sobrien "NVIDIA nForce MCP Networking Adapter"}, 192159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 193163503Sobrien "NVIDIA nForce2 MCP2 Networking Adapter"}, 194159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 195163503Sobrien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 196159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 197163503Sobrien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 198163437Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 199163503Sobrien "NVIDIA nForce3 MCP3 Networking Adapter"}, 200159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 201163503Sobrien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 202159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 203163503Sobrien "NVIDIA nForce3 MCP7 Networking Adapter"}, 204159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 205163503Sobrien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 206159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 207163503Sobrien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 208159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 209170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP10 */ 210159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 211170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP11 */ 212159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 213163503Sobrien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 214159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 215163503Sobrien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 216159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 217163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 218159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 219163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 220162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 221163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 222162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 223163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 224162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 225163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 226170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4, 227163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 228162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 229163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 230162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 231163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 232162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 233163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 234170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4, 235163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 236170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1, 237170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 238170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2, 239170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 240170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3, 241170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 242170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4, 243170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 244178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1, 245178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 246178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2, 247178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 248178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3, 249178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 250178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4, 251178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 252183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1, 253183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 254183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2, 255183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 256183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3, 257183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 258183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4, 259183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 260183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1, 261183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 262183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2, 263183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 264183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3, 265183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 266183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4, 267183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 268342294Smarkj {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP89_LAN, 269342294Smarkj "NVIDIA nForce MCP89 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 340264293Syongari 341159967Sobrienstatic int 342264293Syongarinfe_detect_msik9(struct nfe_softc *sc) 343264293Syongari{ 344264293Syongari static const char *maker = "MSI"; 345264293Syongari static const char *product = "K9N6PGM2-V2 (MS-7309)"; 346264293Syongari char *m, *p; 347264293Syongari int found; 348264293Syongari 349264293Syongari found = 0; 350273174Sdavide m = kern_getenv("smbios.planar.maker"); 351273174Sdavide p = kern_getenv("smbios.planar.product"); 352264293Syongari if (m != NULL && p != NULL) { 353264293Syongari if (strcmp(m, maker) == 0 && strcmp(p, product) == 0) 354264293Syongari found = 1; 355264293Syongari } 356264293Syongari if (m != NULL) 357264293Syongari freeenv(m); 358264293Syongari if (p != NULL) 359264293Syongari freeenv(p); 360264293Syongari 361264293Syongari return (found); 362264293Syongari} 363264293Syongari 364264293Syongari 365264293Syongaristatic int 366159967Sobriennfe_attach(device_t dev) 367159952Sobrien{ 368159967Sobrien struct nfe_softc *sc; 369268131Smarcel if_t ifp; 370170589Syongari bus_addr_t dma_addr_max; 371264293Syongari int error = 0, i, msic, phyloc, reg, rid; 372159952Sobrien 373159967Sobrien sc = device_get_softc(dev); 374159967Sobrien sc->nfe_dev = dev; 375159952Sobrien 376159967Sobrien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 377170589Syongari MTX_DEF); 378159967Sobrien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 379159967Sobrien 380163503Sobrien pci_enable_busmaster(dev); 381159967Sobrien 382170589Syongari rid = PCIR_BAR(0); 383170589Syongari sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 384170589Syongari RF_ACTIVE); 385170589Syongari if (sc->nfe_res[0] == NULL) { 386170589Syongari device_printf(dev, "couldn't map memory resources\n"); 387170589Syongari mtx_destroy(&sc->nfe_mtx); 388170589Syongari return (ENXIO); 389170589Syongari } 390159967Sobrien 391219902Sjhb if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { 392170589Syongari uint16_t v, width; 393170589Syongari 394170589Syongari v = pci_read_config(dev, reg + 0x08, 2); 395170589Syongari /* Change max. read request size to 4096. */ 396170589Syongari v &= ~(7 << 12); 397170589Syongari v |= (5 << 12); 398170589Syongari pci_write_config(dev, reg + 0x08, v, 2); 399170589Syongari 400170589Syongari v = pci_read_config(dev, reg + 0x0c, 2); 401170589Syongari /* link capability */ 402170589Syongari v = (v >> 4) & 0x0f; 403170589Syongari width = pci_read_config(dev, reg + 0x12, 2); 404170589Syongari /* negotiated link width */ 405170589Syongari width = (width >> 4) & 0x3f; 406170589Syongari if (v != width) 407170589Syongari device_printf(sc->nfe_dev, 408170589Syongari "warning, negotiated width of link(x%d) != " 409170589Syongari "max. width of link(x%d)\n", width, v); 410159952Sobrien } 411159952Sobrien 412215327Syongari if (nfe_can_use_msix(sc) == 0) { 413215327Syongari device_printf(sc->nfe_dev, 414215327Syongari "MSI/MSI-X capability black-listed, will use INTx\n"); 415215327Syongari msix_disable = 1; 416215327Syongari msi_disable = 1; 417215327Syongari } 418215327Syongari 419159967Sobrien /* Allocate interrupt */ 420170589Syongari if (msix_disable == 0 || msi_disable == 0) { 421170589Syongari if (msix_disable == 0 && 422170589Syongari (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES) 423170589Syongari nfe_alloc_msix(sc, msic); 424170589Syongari if (msi_disable == 0 && sc->nfe_msix == 0 && 425170589Syongari (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES && 426170589Syongari pci_alloc_msi(dev, &msic) == 0) { 427170589Syongari if (msic == NFE_MSI_MESSAGES) { 428170589Syongari if (bootverbose) 429170589Syongari device_printf(dev, 430170589Syongari "Using %d MSI messages\n", msic); 431170589Syongari sc->nfe_msi = 1; 432170589Syongari } else 433170589Syongari pci_release_msi(dev); 434170589Syongari } 435170589Syongari } 436159967Sobrien 437170589Syongari if (sc->nfe_msix == 0 && sc->nfe_msi == 0) { 438170589Syongari rid = 0; 439170589Syongari sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 440170589Syongari RF_SHAREABLE | RF_ACTIVE); 441170589Syongari if (sc->nfe_irq[0] == NULL) { 442170589Syongari device_printf(dev, "couldn't allocate IRQ resources\n"); 443170589Syongari error = ENXIO; 444170589Syongari goto fail; 445170589Syongari } 446170589Syongari } else { 447170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 448170589Syongari sc->nfe_irq[i] = bus_alloc_resource_any(dev, 449170589Syongari SYS_RES_IRQ, &rid, RF_ACTIVE); 450170589Syongari if (sc->nfe_irq[i] == NULL) { 451170589Syongari device_printf(dev, 452170589Syongari "couldn't allocate IRQ resources for " 453170589Syongari "message %d\n", rid); 454170589Syongari error = ENXIO; 455170589Syongari goto fail; 456170589Syongari } 457170589Syongari } 458170589Syongari /* Map interrupts to vector 0. */ 459170589Syongari if (sc->nfe_msix != 0) { 460170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP0, 0); 461170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP1, 0); 462170589Syongari } else if (sc->nfe_msi != 0) { 463170589Syongari NFE_WRITE(sc, NFE_MSI_MAP0, 0); 464170589Syongari NFE_WRITE(sc, NFE_MSI_MAP1, 0); 465170589Syongari } 466159952Sobrien } 467159952Sobrien 468170589Syongari /* Set IRQ status/mask register. */ 469170589Syongari sc->nfe_irq_status = NFE_IRQ_STATUS; 470170589Syongari sc->nfe_irq_mask = NFE_IRQ_MASK; 471170589Syongari sc->nfe_intrs = NFE_IRQ_WANTED; 472170589Syongari sc->nfe_nointrs = 0; 473170589Syongari if (sc->nfe_msix != 0) { 474170589Syongari sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS; 475170589Syongari sc->nfe_nointrs = NFE_IRQ_WANTED; 476170589Syongari } else if (sc->nfe_msi != 0) { 477170589Syongari sc->nfe_irq_mask = NFE_MSI_IRQ_MASK; 478170589Syongari sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED; 479170589Syongari } 480159952Sobrien 481170589Syongari sc->nfe_devid = pci_get_device(dev); 482170589Syongari sc->nfe_revid = pci_get_revid(dev); 483159967Sobrien sc->nfe_flags = 0; 484159952Sobrien 485170589Syongari switch (sc->nfe_devid) { 486159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 487159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 488159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 489159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 490159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 491159952Sobrien break; 492159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 493159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 494183561Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1; 495159952Sobrien break; 496159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 497159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 498159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 499159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 500183561Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 501183561Syongari NFE_MIB_V1; 502159952Sobrien break; 503159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 504159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 505163503Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 506183561Syongari NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 507159952Sobrien break; 508170589Syongari 509162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 510162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 511162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 512162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 513170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 514170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 515170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 516170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 517178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN1: 518178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN2: 519178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN3: 520178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN4: 521170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | 522183561Syongari NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 523162212Sobrien break; 524183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN1: 525183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN2: 526183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN3: 527183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN4: 528183509Syongari /* XXX flow control */ 529183509Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT | 530183561Syongari NFE_CORRECT_MACADDR | NFE_MIB_V3; 531183509Syongari break; 532183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN1: 533183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN2: 534183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN3: 535183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN4: 536342294Smarkj case PCI_PRODUCT_NVIDIA_MCP89_LAN: 537183509Syongari /* XXX flow control */ 538183509Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 539183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3; 540183509Syongari break; 541162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 542162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 543162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 544162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 545170589Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | 546183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | 547183561Syongari NFE_MIB_V2; 548163503Sobrien break; 549159952Sobrien } 550159952Sobrien 551170589Syongari nfe_power(sc); 552170589Syongari /* Check for reversed ethernet address */ 553170589Syongari if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0) 554170589Syongari sc->nfe_flags |= NFE_CORRECT_MACADDR; 555170589Syongari nfe_get_macaddr(sc, sc->eaddr); 556159952Sobrien /* 557159967Sobrien * Allocate the parent bus DMA tag appropriate for PCI. 558159967Sobrien */ 559170589Syongari dma_addr_max = BUS_SPACE_MAXADDR_32BIT; 560170589Syongari if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0) 561170589Syongari dma_addr_max = NFE_DMA_MAXADDR; 562170589Syongari error = bus_dma_tag_create( 563170589Syongari bus_get_dma_tag(sc->nfe_dev), /* parent */ 564163503Sobrien 1, 0, /* alignment, boundary */ 565170589Syongari dma_addr_max, /* lowaddr */ 566163503Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 567163503Sobrien NULL, NULL, /* filter, filterarg */ 568170589Syongari BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 569163503Sobrien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 570170589Syongari 0, /* flags */ 571163503Sobrien NULL, NULL, /* lockfunc, lockarg */ 572163503Sobrien &sc->nfe_parent_tag); 573159967Sobrien if (error) 574159967Sobrien goto fail; 575159967Sobrien 576268131Smarcel ifp = sc->nfe_ifp = if_gethandle(IFT_ETHER); 577164650Sobrien if (ifp == NULL) { 578268131Smarcel device_printf(dev, "can not if_gethandle()\n"); 579164650Sobrien error = ENOSPC; 580164650Sobrien goto fail; 581164650Sobrien } 582164650Sobrien 583159967Sobrien /* 584159952Sobrien * Allocate Tx and Rx rings. 585159952Sobrien */ 586170589Syongari if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0) 587159967Sobrien goto fail; 588159952Sobrien 589170589Syongari if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0) 590159967Sobrien goto fail; 591170589Syongari 592171559Syongari nfe_alloc_jrx_ring(sc, &sc->jrxq); 593183561Syongari /* Create sysctl node. */ 594183561Syongari nfe_sysctl_node(sc); 595170589Syongari 596268131Smarcel if_setsoftc(ifp, sc); 597270876Sglebius if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 598268131Smarcel if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 599268131Smarcel if_setioctlfn(ifp, nfe_ioctl); 600268131Smarcel if_setstartfn(ifp, nfe_start); 601268131Smarcel if_sethwassist(ifp, 0); 602268131Smarcel if_setcapabilities(ifp, 0); 603268131Smarcel if_setinitfn(ifp, nfe_init); 604268131Smarcel if_setsendqlen(ifp, NFE_TX_RING_COUNT - 1); 605268131Smarcel if_setsendqready(ifp); 606159952Sobrien 607268131Smarcel 608170589Syongari if (sc->nfe_flags & NFE_HW_CSUM) { 609268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_HWCSUM | IFCAP_TSO4, 0); 610268131Smarcel if_sethwassistbits(ifp, NFE_CSUM_FEATURES | CSUM_TSO, 0); 611170589Syongari } 612268131Smarcel if_setcapenable(ifp, if_getcapabilities(ifp)); 613164650Sobrien 614268131Smarcel sc->nfe_framesize = if_getmtu(ifp) + NFE_RX_HEADERS; 615170589Syongari /* VLAN capability setup. */ 616268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); 617170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 618268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0); 619268131Smarcel if ((if_getcapabilities(ifp) & IFCAP_HWCSUM) != 0) 620268131Smarcel if_setcapabilitiesbit(ifp, 621268131Smarcel (IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO), 0); 622159952Sobrien } 623215132Syongari 624219902Sjhb if (pci_find_cap(dev, PCIY_PMG, ®) == 0) 625268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_WOL_MAGIC, 0); 626268131Smarcel if_setcapenable(ifp, if_getcapabilities(ifp)); 627159952Sobrien 628170589Syongari /* 629170589Syongari * Tell the upper layer(s) we support long frames. 630270876Sglebius * Must appear after the call to ether_ifattach() because 631270876Sglebius * ether_ifattach() sets ifi_hdrlen to the default value. 632170589Syongari */ 633268131Smarcel if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); 634170589Syongari 635159967Sobrien#ifdef DEVICE_POLLING 636268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0); 637159967Sobrien#endif 638159952Sobrien 639159967Sobrien /* Do MII setup */ 640264293Syongari phyloc = MII_PHY_ANY; 641264293Syongari if (sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN1 || 642264293Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN2 || 643264293Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN3 || 644264293Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN4) { 645264293Syongari if (nfe_detect_msik9(sc) != 0) 646264293Syongari phyloc = 0; 647264293Syongari } 648268131Smarcel error = mii_attach(dev, &sc->nfe_miibus, ifp, 649268131Smarcel (ifm_change_cb_t)nfe_ifmedia_upd, (ifm_stat_cb_t)nfe_ifmedia_sts, 650268131Smarcel BMSR_DEFCAPMASK, phyloc, MII_OFFSET_ANY, MIIF_DOPAUSE); 651213894Smarius if (error != 0) { 652213894Smarius device_printf(dev, "attaching PHYs failed\n"); 653159967Sobrien goto fail; 654159967Sobrien } 655270876Sglebius ether_ifattach(ifp, sc->eaddr); 656159952Sobrien 657170589Syongari TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc); 658170589Syongari sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK, 659170589Syongari taskqueue_thread_enqueue, &sc->nfe_tq); 660170589Syongari taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq", 661170589Syongari device_get_nameunit(sc->nfe_dev)); 662170589Syongari error = 0; 663170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 664170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[0], 665170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 666170589Syongari &sc->nfe_intrhand[0]); 667170589Syongari } else { 668170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 669170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[i], 670170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 671170589Syongari &sc->nfe_intrhand[i]); 672170589Syongari if (error != 0) 673170589Syongari break; 674170589Syongari } 675170589Syongari } 676159967Sobrien if (error) { 677170589Syongari device_printf(dev, "couldn't set up irq\n"); 678170589Syongari taskqueue_free(sc->nfe_tq); 679170589Syongari sc->nfe_tq = NULL; 680270876Sglebius ether_ifdetach(ifp); 681159967Sobrien goto fail; 682159967Sobrien } 683159967Sobrien 684159967Sobrienfail: 685159967Sobrien if (error) 686159967Sobrien nfe_detach(dev); 687159967Sobrien 688159967Sobrien return (error); 689159952Sobrien} 690159952Sobrien 691159967Sobrien 692159967Sobrienstatic int 693159967Sobriennfe_detach(device_t dev) 694159952Sobrien{ 695163503Sobrien struct nfe_softc *sc; 696268131Smarcel if_t ifp; 697170589Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 698170589Syongari int i, rid; 699159952Sobrien 700159967Sobrien sc = device_get_softc(dev); 701159967Sobrien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 702159967Sobrien ifp = sc->nfe_ifp; 703159967Sobrien 704159967Sobrien#ifdef DEVICE_POLLING 705268131Smarcel if (ifp != NULL && if_getcapenable(ifp) & IFCAP_POLLING) 706159967Sobrien ether_poll_deregister(ifp); 707159967Sobrien#endif 708159967Sobrien if (device_is_attached(dev)) { 709164649Sobrien NFE_LOCK(sc); 710170589Syongari nfe_stop(ifp); 711268131Smarcel if_setflagbits(ifp, 0, IFF_UP); 712164649Sobrien NFE_UNLOCK(sc); 713159967Sobrien callout_drain(&sc->nfe_stat_ch); 714270876Sglebius ether_ifdetach(ifp); 715159967Sobrien } 716159967Sobrien 717170589Syongari if (ifp) { 718170589Syongari /* restore ethernet address */ 719170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 720170589Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) { 721170589Syongari eaddr[i] = sc->eaddr[5 - i]; 722170589Syongari } 723170589Syongari } else 724170589Syongari bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN); 725170589Syongari nfe_set_macaddr(sc, eaddr); 726270876Sglebius if_free(ifp); 727170589Syongari } 728159967Sobrien if (sc->nfe_miibus) 729159967Sobrien device_delete_child(dev, sc->nfe_miibus); 730159967Sobrien bus_generic_detach(dev); 731170589Syongari if (sc->nfe_tq != NULL) { 732170589Syongari taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task); 733170589Syongari taskqueue_free(sc->nfe_tq); 734170589Syongari sc->nfe_tq = NULL; 735170589Syongari } 736159967Sobrien 737170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 738170589Syongari if (sc->nfe_intrhand[i] != NULL) { 739170589Syongari bus_teardown_intr(dev, sc->nfe_irq[i], 740170589Syongari sc->nfe_intrhand[i]); 741170589Syongari sc->nfe_intrhand[i] = NULL; 742170589Syongari } 743170589Syongari } 744159967Sobrien 745170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 746170589Syongari if (sc->nfe_irq[0] != NULL) 747170589Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, 748170589Syongari sc->nfe_irq[0]); 749170589Syongari } else { 750170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 751170589Syongari if (sc->nfe_irq[i] != NULL) { 752170589Syongari bus_release_resource(dev, SYS_RES_IRQ, rid, 753170589Syongari sc->nfe_irq[i]); 754170589Syongari sc->nfe_irq[i] = NULL; 755170589Syongari } 756170589Syongari } 757170589Syongari pci_release_msi(dev); 758170589Syongari } 759170589Syongari if (sc->nfe_msix_pba_res != NULL) { 760170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3), 761170589Syongari sc->nfe_msix_pba_res); 762170589Syongari sc->nfe_msix_pba_res = NULL; 763170589Syongari } 764170589Syongari if (sc->nfe_msix_res != NULL) { 765170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 766170589Syongari sc->nfe_msix_res); 767170589Syongari sc->nfe_msix_res = NULL; 768170589Syongari } 769170589Syongari if (sc->nfe_res[0] != NULL) { 770170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 771170589Syongari sc->nfe_res[0]); 772170589Syongari sc->nfe_res[0] = NULL; 773170589Syongari } 774170589Syongari 775159967Sobrien nfe_free_tx_ring(sc, &sc->txq); 776159967Sobrien nfe_free_rx_ring(sc, &sc->rxq); 777170589Syongari nfe_free_jrx_ring(sc, &sc->jrxq); 778159967Sobrien 779170589Syongari if (sc->nfe_parent_tag) { 780159967Sobrien bus_dma_tag_destroy(sc->nfe_parent_tag); 781170589Syongari sc->nfe_parent_tag = NULL; 782170589Syongari } 783159967Sobrien 784159967Sobrien mtx_destroy(&sc->nfe_mtx); 785159967Sobrien 786159967Sobrien return (0); 787159952Sobrien} 788159952Sobrien 789159967Sobrien 790170589Syongaristatic int 791170589Syongarinfe_suspend(device_t dev) 792170589Syongari{ 793170589Syongari struct nfe_softc *sc; 794170589Syongari 795170589Syongari sc = device_get_softc(dev); 796170589Syongari 797170589Syongari NFE_LOCK(sc); 798170589Syongari nfe_stop(sc->nfe_ifp); 799215132Syongari nfe_set_wol(sc); 800170589Syongari sc->nfe_suspended = 1; 801170589Syongari NFE_UNLOCK(sc); 802170589Syongari 803170589Syongari return (0); 804170589Syongari} 805170589Syongari 806170589Syongari 807170589Syongaristatic int 808170589Syongarinfe_resume(device_t dev) 809170589Syongari{ 810170589Syongari struct nfe_softc *sc; 811268131Smarcel if_t ifp; 812170589Syongari 813170589Syongari sc = device_get_softc(dev); 814170589Syongari 815170589Syongari NFE_LOCK(sc); 816215132Syongari nfe_power(sc); 817170589Syongari ifp = sc->nfe_ifp; 818268131Smarcel if (if_getflags(ifp) & IFF_UP) 819170589Syongari nfe_init_locked(sc); 820170589Syongari sc->nfe_suspended = 0; 821170589Syongari NFE_UNLOCK(sc); 822170589Syongari 823170589Syongari return (0); 824170589Syongari} 825170589Syongari 826170589Syongari 827215327Syongaristatic int 828215327Syongarinfe_can_use_msix(struct nfe_softc *sc) 829215327Syongari{ 830215327Syongari static struct msix_blacklist { 831215327Syongari char *maker; 832215327Syongari char *product; 833215327Syongari } msix_blacklists[] = { 834215327Syongari { "ASUSTeK Computer INC.", "P5N32-SLI PREMIUM" } 835215327Syongari }; 836215327Syongari 837215327Syongari struct msix_blacklist *mblp; 838215327Syongari char *maker, *product; 839215350Syongari int count, n, use_msix; 840215327Syongari 841215327Syongari /* 842215327Syongari * Search base board manufacturer and product name table 843215327Syongari * to see this system has a known MSI/MSI-X issue. 844215327Syongari */ 845273174Sdavide maker = kern_getenv("smbios.planar.maker"); 846273174Sdavide product = kern_getenv("smbios.planar.product"); 847215350Syongari use_msix = 1; 848215327Syongari if (maker != NULL && product != NULL) { 849298307Spfg count = nitems(msix_blacklists); 850215327Syongari mblp = msix_blacklists; 851215327Syongari for (n = 0; n < count; n++) { 852215327Syongari if (strcmp(maker, mblp->maker) == 0 && 853215350Syongari strcmp(product, mblp->product) == 0) { 854215350Syongari use_msix = 0; 855215350Syongari break; 856215350Syongari } 857215327Syongari mblp++; 858215327Syongari } 859215327Syongari } 860215350Syongari if (maker != NULL) 861215350Syongari freeenv(maker); 862215350Syongari if (product != NULL) 863215350Syongari freeenv(product); 864215327Syongari 865215350Syongari return (use_msix); 866215327Syongari} 867215327Syongari 868215327Syongari 869170589Syongari/* Take PHY/NIC out of powerdown, from Linux */ 870159967Sobrienstatic void 871170589Syongarinfe_power(struct nfe_softc *sc) 872170589Syongari{ 873170589Syongari uint32_t pwr; 874170589Syongari 875170589Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) == 0) 876170589Syongari return; 877170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2); 878170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC); 879170589Syongari DELAY(100); 880170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, 0); 881170589Syongari DELAY(100); 882170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2); 883170589Syongari pwr = NFE_READ(sc, NFE_PWR2_CTL); 884170589Syongari pwr &= ~NFE_PWR2_WAKEUP_MASK; 885170589Syongari if (sc->nfe_revid >= 0xa3 && 886170589Syongari (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 || 887170589Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2)) 888170589Syongari pwr |= NFE_PWR2_REVA3; 889170589Syongari NFE_WRITE(sc, NFE_PWR2_CTL, pwr); 890170589Syongari} 891170589Syongari 892170589Syongari 893170589Syongaristatic void 894159967Sobriennfe_miibus_statchg(device_t dev) 895159952Sobrien{ 896159967Sobrien struct nfe_softc *sc; 897159967Sobrien struct mii_data *mii; 898268131Smarcel if_t ifp; 899215132Syongari uint32_t rxctl, txctl; 900159952Sobrien 901215132Syongari sc = device_get_softc(dev); 902170589Syongari 903159967Sobrien mii = device_get_softc(sc->nfe_miibus); 904170589Syongari ifp = sc->nfe_ifp; 905159967Sobrien 906215132Syongari sc->nfe_link = 0; 907215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 908215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 909215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 910215132Syongari case IFM_10_T: 911215132Syongari case IFM_100_TX: 912215132Syongari case IFM_1000_T: 913170589Syongari sc->nfe_link = 1; 914215132Syongari break; 915215132Syongari default: 916215132Syongari break; 917215132Syongari } 918215132Syongari } 919170589Syongari 920215132Syongari nfe_mac_config(sc, mii); 921215132Syongari txctl = NFE_READ(sc, NFE_TX_CTL); 922215132Syongari rxctl = NFE_READ(sc, NFE_RX_CTL); 923268131Smarcel if (sc->nfe_link != 0 && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 924215132Syongari txctl |= NFE_TX_START; 925215132Syongari rxctl |= NFE_RX_START; 926215132Syongari } else { 927215132Syongari txctl &= ~NFE_TX_START; 928215132Syongari rxctl &= ~NFE_RX_START; 929215132Syongari } 930215132Syongari NFE_WRITE(sc, NFE_TX_CTL, txctl); 931215132Syongari NFE_WRITE(sc, NFE_RX_CTL, rxctl); 932215132Syongari} 933215132Syongari 934215132Syongari 935215132Syongaristatic void 936215132Syongarinfe_mac_config(struct nfe_softc *sc, struct mii_data *mii) 937215132Syongari{ 938215132Syongari uint32_t link, misc, phy, seed; 939215132Syongari uint32_t val; 940215132Syongari 941215132Syongari NFE_LOCK_ASSERT(sc); 942215132Syongari 943159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 944159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 945159952Sobrien 946159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 947159952Sobrien seed &= ~NFE_SEED_MASK; 948159952Sobrien 949215132Syongari misc = NFE_MISC1_MAGIC; 950215132Syongari link = NFE_MEDIA_SET; 951215132Syongari 952215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) == 0) { 953159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 954159952Sobrien misc |= NFE_MISC1_HDX; 955159952Sobrien } 956159952Sobrien 957159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 958159952Sobrien case IFM_1000_T: /* full-duplex only */ 959159952Sobrien link |= NFE_MEDIA_1000T; 960159952Sobrien seed |= NFE_SEED_1000T; 961159952Sobrien phy |= NFE_PHY_1000T; 962159952Sobrien break; 963159952Sobrien case IFM_100_TX: 964159952Sobrien link |= NFE_MEDIA_100TX; 965159952Sobrien seed |= NFE_SEED_100TX; 966159952Sobrien phy |= NFE_PHY_100TX; 967159952Sobrien break; 968159952Sobrien case IFM_10_T: 969159952Sobrien link |= NFE_MEDIA_10T; 970159952Sobrien seed |= NFE_SEED_10T; 971159952Sobrien break; 972159952Sobrien } 973159952Sobrien 974170589Syongari if ((phy & 0x10000000) != 0) { 975170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 976170589Syongari val = NFE_R1_MAGIC_1000; 977170589Syongari else 978170589Syongari val = NFE_R1_MAGIC_10_100; 979170589Syongari } else 980170589Syongari val = NFE_R1_MAGIC_DEFAULT; 981170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, val); 982170589Syongari 983159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 984159952Sobrien 985159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 986159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 987159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 988170589Syongari 989215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 990170589Syongari /* It seems all hardwares supports Rx pause frames. */ 991170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 992215297Smarius if ((IFM_OPTIONS(mii->mii_media_active) & 993215297Smarius IFM_ETH_RXPAUSE) != 0) 994170589Syongari val |= NFE_PFF_RX_PAUSE; 995170589Syongari else 996170589Syongari val &= ~NFE_PFF_RX_PAUSE; 997170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 998170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 999170589Syongari val = NFE_READ(sc, NFE_MISC1); 1000215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & 1001215297Smarius IFM_ETH_TXPAUSE) != 0) { 1002170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1003170589Syongari NFE_TX_PAUSE_FRAME_ENABLE); 1004170589Syongari val |= NFE_MISC1_TX_PAUSE; 1005170589Syongari } else { 1006170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 1007170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1008170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 1009170589Syongari } 1010170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 1011170589Syongari } 1012170589Syongari } else { 1013170589Syongari /* disable rx/tx pause frames */ 1014170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 1015170589Syongari val &= ~NFE_PFF_RX_PAUSE; 1016170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 1017170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 1018170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1019170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 1020170589Syongari val = NFE_READ(sc, NFE_MISC1); 1021170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 1022170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 1023170589Syongari } 1024170589Syongari } 1025159952Sobrien} 1026159952Sobrien 1027163503Sobrien 1028159967Sobrienstatic int 1029159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg) 1030159952Sobrien{ 1031159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 1032170589Syongari uint32_t val; 1033159952Sobrien int ntries; 1034159952Sobrien 1035159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1036159952Sobrien 1037159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1038159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1039159952Sobrien DELAY(100); 1040159952Sobrien } 1041159952Sobrien 1042159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 1043159952Sobrien 1044170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1045159952Sobrien DELAY(100); 1046159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1047159952Sobrien break; 1048159952Sobrien } 1049170589Syongari if (ntries == NFE_TIMEOUT) { 1050170589Syongari DPRINTFN(sc, 2, "timeout waiting for PHY\n"); 1051159952Sobrien return 0; 1052159952Sobrien } 1053159952Sobrien 1054159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 1055170589Syongari DPRINTFN(sc, 2, "could not read PHY\n"); 1056159952Sobrien return 0; 1057159952Sobrien } 1058159952Sobrien 1059159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 1060159952Sobrien if (val != 0xffffffff && val != 0) 1061159952Sobrien sc->mii_phyaddr = phy; 1062159952Sobrien 1063170589Syongari DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 1064159952Sobrien 1065170589Syongari return (val); 1066159952Sobrien} 1067159952Sobrien 1068163503Sobrien 1069159967Sobrienstatic int 1070159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val) 1071159952Sobrien{ 1072159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 1073170589Syongari uint32_t ctl; 1074163503Sobrien int ntries; 1075159952Sobrien 1076159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1077159952Sobrien 1078159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1079159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1080159952Sobrien DELAY(100); 1081159952Sobrien } 1082159952Sobrien 1083159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 1084159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 1085159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 1086159952Sobrien 1087170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1088159952Sobrien DELAY(100); 1089159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1090159952Sobrien break; 1091159952Sobrien } 1092159952Sobrien#ifdef NFE_DEBUG 1093170589Syongari if (nfedebug >= 2 && ntries == NFE_TIMEOUT) 1094170589Syongari device_printf(sc->nfe_dev, "could not write to PHY\n"); 1095159952Sobrien#endif 1096170589Syongari return (0); 1097159952Sobrien} 1098159952Sobrien 1099170589Syongaristruct nfe_dmamap_arg { 1100170589Syongari bus_addr_t nfe_busaddr; 1101170589Syongari}; 1102170589Syongari 1103159967Sobrienstatic int 1104159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1105159952Sobrien{ 1106170589Syongari struct nfe_dmamap_arg ctx; 1107159967Sobrien struct nfe_rx_data *data; 1108170589Syongari void *desc; 1109159967Sobrien int i, error, descsize; 1110159967Sobrien 1111159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1112170589Syongari desc = ring->desc64; 1113159967Sobrien descsize = sizeof (struct nfe_desc64); 1114159967Sobrien } else { 1115170589Syongari desc = ring->desc32; 1116159967Sobrien descsize = sizeof (struct nfe_desc32); 1117159967Sobrien } 1118159967Sobrien 1119159967Sobrien ring->cur = ring->next = 0; 1120159967Sobrien 1121163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1122170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1123170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1124170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1125170589Syongari NULL, NULL, /* filter, filterarg */ 1126170589Syongari NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1127170589Syongari NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 1128170589Syongari 0, /* flags */ 1129170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1130170589Syongari &ring->rx_desc_tag); 1131159967Sobrien if (error != 0) { 1132170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1133159967Sobrien goto fail; 1134159967Sobrien } 1135159967Sobrien 1136159967Sobrien /* allocate memory to desc */ 1137170589Syongari error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK | 1138170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map); 1139159967Sobrien if (error != 0) { 1140170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1141159967Sobrien goto fail; 1142159967Sobrien } 1143170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1144170589Syongari ring->desc64 = desc; 1145170589Syongari else 1146170589Syongari ring->desc32 = desc; 1147159967Sobrien 1148159967Sobrien /* map desc to device visible address space */ 1149170589Syongari ctx.nfe_busaddr = 0; 1150170589Syongari error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc, 1151170589Syongari NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1152159967Sobrien if (error != 0) { 1153170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1154159967Sobrien goto fail; 1155159967Sobrien } 1156170589Syongari ring->physaddr = ctx.nfe_busaddr; 1157159967Sobrien 1158170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1159170589Syongari 1, 0, /* alignment, boundary */ 1160170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1161170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1162170589Syongari NULL, NULL, /* filter, filterarg */ 1163170589Syongari MCLBYTES, 1, /* maxsize, nsegments */ 1164170589Syongari MCLBYTES, /* maxsegsize */ 1165170589Syongari 0, /* flags */ 1166170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1167170589Syongari &ring->rx_data_tag); 1168170589Syongari if (error != 0) { 1169170589Syongari device_printf(sc->nfe_dev, "could not create Rx DMA tag\n"); 1170170589Syongari goto fail; 1171170589Syongari } 1172159967Sobrien 1173170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map); 1174170589Syongari if (error != 0) { 1175170589Syongari device_printf(sc->nfe_dev, 1176170589Syongari "could not create Rx DMA spare map\n"); 1177170589Syongari goto fail; 1178170589Syongari } 1179170589Syongari 1180159967Sobrien /* 1181159967Sobrien * Pre-allocate Rx buffers and populate Rx ring. 1182159967Sobrien */ 1183159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1184159967Sobrien data = &sc->rxq.data[i]; 1185170589Syongari data->rx_data_map = NULL; 1186170589Syongari data->m = NULL; 1187170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, 1188170589Syongari &data->rx_data_map); 1189164651Sobrien if (error != 0) { 1190170589Syongari device_printf(sc->nfe_dev, 1191170589Syongari "could not create Rx DMA map\n"); 1192164651Sobrien goto fail; 1193164651Sobrien } 1194170589Syongari } 1195159967Sobrien 1196170589Syongarifail: 1197170589Syongari return (error); 1198170589Syongari} 1199170589Syongari 1200170589Syongari 1201171559Syongaristatic void 1202170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1203170589Syongari{ 1204170589Syongari struct nfe_dmamap_arg ctx; 1205170589Syongari struct nfe_rx_data *data; 1206170589Syongari void *desc; 1207170589Syongari int i, error, descsize; 1208170589Syongari 1209170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1210171559Syongari return; 1211171559Syongari if (jumbo_disable != 0) { 1212171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support\n"); 1213171559Syongari sc->nfe_jumbo_disable = 1; 1214171559Syongari return; 1215171559Syongari } 1216170589Syongari 1217170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1218170589Syongari desc = ring->jdesc64; 1219170589Syongari descsize = sizeof (struct nfe_desc64); 1220170589Syongari } else { 1221170589Syongari desc = ring->jdesc32; 1222170589Syongari descsize = sizeof (struct nfe_desc32); 1223170589Syongari } 1224170589Syongari 1225170589Syongari ring->jcur = ring->jnext = 0; 1226170589Syongari 1227170589Syongari /* Create DMA tag for jumbo Rx ring. */ 1228170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1229170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1230170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1231170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1232170589Syongari NULL, NULL, /* filter, filterarg */ 1233170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsize */ 1234170589Syongari 1, /* nsegments */ 1235170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsegsize */ 1236170589Syongari 0, /* flags */ 1237170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1238170589Syongari &ring->jrx_desc_tag); 1239170589Syongari if (error != 0) { 1240170589Syongari device_printf(sc->nfe_dev, 1241170589Syongari "could not create jumbo ring DMA tag\n"); 1242170589Syongari goto fail; 1243170589Syongari } 1244170589Syongari 1245170589Syongari /* Create DMA tag for jumbo Rx buffers. */ 1246170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1247192706Syongari 1, 0, /* alignment, boundary */ 1248170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1249170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1250170589Syongari NULL, NULL, /* filter, filterarg */ 1251176859Syongari MJUM9BYTES, /* maxsize */ 1252170589Syongari 1, /* nsegments */ 1253176859Syongari MJUM9BYTES, /* maxsegsize */ 1254170589Syongari 0, /* flags */ 1255170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1256170589Syongari &ring->jrx_data_tag); 1257170589Syongari if (error != 0) { 1258170589Syongari device_printf(sc->nfe_dev, 1259170589Syongari "could not create jumbo Rx buffer DMA tag\n"); 1260170589Syongari goto fail; 1261170589Syongari } 1262170589Syongari 1263170589Syongari /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ 1264170589Syongari error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK | 1265170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map); 1266170589Syongari if (error != 0) { 1267170589Syongari device_printf(sc->nfe_dev, 1268170589Syongari "could not allocate DMA'able memory for jumbo Rx ring\n"); 1269170589Syongari goto fail; 1270170589Syongari } 1271170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1272170589Syongari ring->jdesc64 = desc; 1273170589Syongari else 1274170589Syongari ring->jdesc32 = desc; 1275170589Syongari 1276170589Syongari ctx.nfe_busaddr = 0; 1277170589Syongari error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc, 1278170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1279170589Syongari if (error != 0) { 1280170589Syongari device_printf(sc->nfe_dev, 1281170589Syongari "could not load DMA'able memory for jumbo Rx ring\n"); 1282170589Syongari goto fail; 1283170589Syongari } 1284170589Syongari ring->jphysaddr = ctx.nfe_busaddr; 1285170589Syongari 1286170589Syongari /* Create DMA maps for jumbo Rx buffers. */ 1287170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map); 1288170589Syongari if (error != 0) { 1289170589Syongari device_printf(sc->nfe_dev, 1290170589Syongari "could not create jumbo Rx DMA spare map\n"); 1291170589Syongari goto fail; 1292170589Syongari } 1293170589Syongari 1294170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1295170589Syongari data = &sc->jrxq.jdata[i]; 1296170589Syongari data->rx_data_map = NULL; 1297170589Syongari data->m = NULL; 1298170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, 1299164651Sobrien &data->rx_data_map); 1300164651Sobrien if (error != 0) { 1301170589Syongari device_printf(sc->nfe_dev, 1302170589Syongari "could not create jumbo Rx DMA map\n"); 1303164651Sobrien goto fail; 1304164651Sobrien } 1305170589Syongari } 1306159967Sobrien 1307171559Syongari return; 1308159967Sobrien 1309170589Syongarifail: 1310171559Syongari /* 1311171559Syongari * Running without jumbo frame support is ok for most cases 1312171559Syongari * so don't fail on creating dma tag/map for jumbo frame. 1313171559Syongari */ 1314170589Syongari nfe_free_jrx_ring(sc, ring); 1315171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support due to " 1316171559Syongari "resource shortage\n"); 1317171559Syongari sc->nfe_jumbo_disable = 1; 1318170589Syongari} 1319159967Sobrien 1320159967Sobrien 1321170589Syongaristatic int 1322170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1323170589Syongari{ 1324170589Syongari void *desc; 1325170589Syongari size_t descsize; 1326170589Syongari int i; 1327159967Sobrien 1328170589Syongari ring->cur = ring->next = 0; 1329170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1330170589Syongari desc = ring->desc64; 1331170589Syongari descsize = sizeof (struct nfe_desc64); 1332170589Syongari } else { 1333170589Syongari desc = ring->desc32; 1334170589Syongari descsize = sizeof (struct nfe_desc32); 1335159967Sobrien } 1336170589Syongari bzero(desc, descsize * NFE_RX_RING_COUNT); 1337170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1338170589Syongari if (nfe_newbuf(sc, i) != 0) 1339170589Syongari return (ENOBUFS); 1340170589Syongari } 1341159967Sobrien 1342163503Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 1343170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1344159967Sobrien 1345170589Syongari return (0); 1346159967Sobrien} 1347159967Sobrien 1348163503Sobrien 1349170589Syongaristatic int 1350170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1351159967Sobrien{ 1352170589Syongari void *desc; 1353170589Syongari size_t descsize; 1354159967Sobrien int i; 1355159967Sobrien 1356170589Syongari ring->jcur = ring->jnext = 0; 1357170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1358170589Syongari desc = ring->jdesc64; 1359170589Syongari descsize = sizeof (struct nfe_desc64); 1360170589Syongari } else { 1361170589Syongari desc = ring->jdesc32; 1362170589Syongari descsize = sizeof (struct nfe_desc32); 1363159952Sobrien } 1364176859Syongari bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT); 1365170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1366170589Syongari if (nfe_jnewbuf(sc, i) != 0) 1367170589Syongari return (ENOBUFS); 1368170589Syongari } 1369159952Sobrien 1370170589Syongari bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map, 1371170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1372159952Sobrien 1373170589Syongari return (0); 1374159967Sobrien} 1375159967Sobrien 1376159967Sobrien 1377159967Sobrienstatic void 1378159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1379159967Sobrien{ 1380159967Sobrien struct nfe_rx_data *data; 1381159967Sobrien void *desc; 1382266270Sbrueffer int i; 1383159967Sobrien 1384266270Sbrueffer if (sc->nfe_flags & NFE_40BIT_ADDR) 1385159967Sobrien desc = ring->desc64; 1386266270Sbrueffer else 1387159967Sobrien desc = ring->desc32; 1388159952Sobrien 1389170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1390170589Syongari data = &ring->data[i]; 1391170589Syongari if (data->rx_data_map != NULL) { 1392170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1393170589Syongari data->rx_data_map); 1394170589Syongari data->rx_data_map = NULL; 1395170589Syongari } 1396170589Syongari if (data->m != NULL) { 1397170589Syongari m_freem(data->m); 1398170589Syongari data->m = NULL; 1399170589Syongari } 1400170589Syongari } 1401170589Syongari if (ring->rx_data_tag != NULL) { 1402170589Syongari if (ring->rx_spare_map != NULL) { 1403170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1404170589Syongari ring->rx_spare_map); 1405170589Syongari ring->rx_spare_map = NULL; 1406170589Syongari } 1407170589Syongari bus_dma_tag_destroy(ring->rx_data_tag); 1408170589Syongari ring->rx_data_tag = NULL; 1409170589Syongari } 1410170589Syongari 1411159967Sobrien if (desc != NULL) { 1412159967Sobrien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 1413159967Sobrien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 1414170589Syongari ring->desc64 = NULL; 1415170589Syongari ring->desc32 = NULL; 1416170589Syongari } 1417170589Syongari if (ring->rx_desc_tag != NULL) { 1418159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 1419170589Syongari ring->rx_desc_tag = NULL; 1420159967Sobrien } 1421170589Syongari} 1422159967Sobrien 1423164650Sobrien 1424170589Syongaristatic void 1425170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1426170589Syongari{ 1427170589Syongari struct nfe_rx_data *data; 1428170589Syongari void *desc; 1429170589Syongari int i, descsize; 1430170589Syongari 1431170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1432170589Syongari return; 1433170589Syongari 1434170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1435170589Syongari desc = ring->jdesc64; 1436170589Syongari descsize = sizeof (struct nfe_desc64); 1437170589Syongari } else { 1438170589Syongari desc = ring->jdesc32; 1439170589Syongari descsize = sizeof (struct nfe_desc32); 1440170589Syongari } 1441170589Syongari 1442170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1443170589Syongari data = &ring->jdata[i]; 1444164651Sobrien if (data->rx_data_map != NULL) { 1445170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1446164651Sobrien data->rx_data_map); 1447170589Syongari data->rx_data_map = NULL; 1448164651Sobrien } 1449170589Syongari if (data->m != NULL) { 1450164651Sobrien m_freem(data->m); 1451170589Syongari data->m = NULL; 1452170589Syongari } 1453164651Sobrien } 1454170589Syongari if (ring->jrx_data_tag != NULL) { 1455170589Syongari if (ring->jrx_spare_map != NULL) { 1456170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1457170589Syongari ring->jrx_spare_map); 1458170589Syongari ring->jrx_spare_map = NULL; 1459170589Syongari } 1460170589Syongari bus_dma_tag_destroy(ring->jrx_data_tag); 1461170589Syongari ring->jrx_data_tag = NULL; 1462170589Syongari } 1463170589Syongari 1464170589Syongari if (desc != NULL) { 1465170589Syongari bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1466170589Syongari bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1467170589Syongari ring->jdesc64 = NULL; 1468170589Syongari ring->jdesc32 = NULL; 1469170589Syongari } 1470176859Syongari 1471170589Syongari if (ring->jrx_desc_tag != NULL) { 1472170589Syongari bus_dma_tag_destroy(ring->jrx_desc_tag); 1473170589Syongari ring->jrx_desc_tag = NULL; 1474170589Syongari } 1475159952Sobrien} 1476159952Sobrien 1477163503Sobrien 1478159967Sobrienstatic int 1479159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1480159952Sobrien{ 1481170589Syongari struct nfe_dmamap_arg ctx; 1482159967Sobrien int i, error; 1483170589Syongari void *desc; 1484159967Sobrien int descsize; 1485159952Sobrien 1486159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1487170589Syongari desc = ring->desc64; 1488159967Sobrien descsize = sizeof (struct nfe_desc64); 1489159967Sobrien } else { 1490170589Syongari desc = ring->desc32; 1491159967Sobrien descsize = sizeof (struct nfe_desc32); 1492159967Sobrien } 1493159952Sobrien 1494159967Sobrien ring->queued = 0; 1495159967Sobrien ring->cur = ring->next = 0; 1496159967Sobrien 1497163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1498170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1499170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1500170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1501170589Syongari NULL, NULL, /* filter, filterarg */ 1502170589Syongari NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1503170589Syongari NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1504170589Syongari 0, /* flags */ 1505170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1506170589Syongari &ring->tx_desc_tag); 1507159967Sobrien if (error != 0) { 1508170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1509159967Sobrien goto fail; 1510159952Sobrien } 1511159952Sobrien 1512170589Syongari error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1513170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1514159967Sobrien if (error != 0) { 1515170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1516159967Sobrien goto fail; 1517159967Sobrien } 1518170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1519170589Syongari ring->desc64 = desc; 1520170589Syongari else 1521170589Syongari ring->desc32 = desc; 1522159967Sobrien 1523170589Syongari ctx.nfe_busaddr = 0; 1524170589Syongari error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1525170589Syongari NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1526159967Sobrien if (error != 0) { 1527170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1528159967Sobrien goto fail; 1529159967Sobrien } 1530170589Syongari ring->physaddr = ctx.nfe_busaddr; 1531159967Sobrien 1532163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1533170589Syongari 1, 0, 1534170589Syongari BUS_SPACE_MAXADDR, 1535170589Syongari BUS_SPACE_MAXADDR, 1536170589Syongari NULL, NULL, 1537170595Syongari NFE_TSO_MAXSIZE, 1538170589Syongari NFE_MAX_SCATTER, 1539170595Syongari NFE_TSO_MAXSGSIZE, 1540170589Syongari 0, 1541170589Syongari NULL, NULL, 1542170589Syongari &ring->tx_data_tag); 1543159967Sobrien if (error != 0) { 1544170589Syongari device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1545170589Syongari goto fail; 1546159967Sobrien } 1547159967Sobrien 1548159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1549163503Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, 1550163503Sobrien &ring->data[i].tx_data_map); 1551159967Sobrien if (error != 0) { 1552170589Syongari device_printf(sc->nfe_dev, 1553170589Syongari "could not create Tx DMA map\n"); 1554159967Sobrien goto fail; 1555159967Sobrien } 1556159967Sobrien } 1557159967Sobrien 1558170589Syongarifail: 1559170589Syongari return (error); 1560159967Sobrien} 1561159967Sobrien 1562159967Sobrien 1563159967Sobrienstatic void 1564170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1565159967Sobrien{ 1566170589Syongari void *desc; 1567170589Syongari size_t descsize; 1568159967Sobrien 1569170589Syongari sc->nfe_force_tx = 0; 1570170589Syongari ring->queued = 0; 1571170589Syongari ring->cur = ring->next = 0; 1572170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1573170589Syongari desc = ring->desc64; 1574170589Syongari descsize = sizeof (struct nfe_desc64); 1575170589Syongari } else { 1576170589Syongari desc = ring->desc32; 1577170589Syongari descsize = sizeof (struct nfe_desc32); 1578159967Sobrien } 1579170589Syongari bzero(desc, descsize * NFE_TX_RING_COUNT); 1580159967Sobrien 1581163503Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1582170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1583159967Sobrien} 1584159967Sobrien 1585163503Sobrien 1586159967Sobrienstatic void 1587159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1588159967Sobrien{ 1589159967Sobrien struct nfe_tx_data *data; 1590159967Sobrien void *desc; 1591159967Sobrien int i, descsize; 1592159967Sobrien 1593159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1594159967Sobrien desc = ring->desc64; 1595159967Sobrien descsize = sizeof (struct nfe_desc64); 1596159967Sobrien } else { 1597159967Sobrien desc = ring->desc32; 1598159967Sobrien descsize = sizeof (struct nfe_desc32); 1599159967Sobrien } 1600159967Sobrien 1601159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1602159967Sobrien data = &ring->data[i]; 1603159967Sobrien 1604159967Sobrien if (data->m != NULL) { 1605170589Syongari bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1606163503Sobrien BUS_DMASYNC_POSTWRITE); 1607170589Syongari bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1608159967Sobrien m_freem(data->m); 1609170589Syongari data->m = NULL; 1610159967Sobrien } 1611170589Syongari if (data->tx_data_map != NULL) { 1612170589Syongari bus_dmamap_destroy(ring->tx_data_tag, 1613170589Syongari data->tx_data_map); 1614170589Syongari data->tx_data_map = NULL; 1615170589Syongari } 1616159967Sobrien } 1617159967Sobrien 1618170589Syongari if (ring->tx_data_tag != NULL) { 1619170589Syongari bus_dma_tag_destroy(ring->tx_data_tag); 1620170589Syongari ring->tx_data_tag = NULL; 1621159967Sobrien } 1622159967Sobrien 1623170589Syongari if (desc != NULL) { 1624170589Syongari bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1625170589Syongari BUS_DMASYNC_POSTWRITE); 1626170589Syongari bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1627170589Syongari bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1628170589Syongari ring->desc64 = NULL; 1629170589Syongari ring->desc32 = NULL; 1630170589Syongari bus_dma_tag_destroy(ring->tx_desc_tag); 1631170589Syongari ring->tx_desc_tag = NULL; 1632170589Syongari } 1633159967Sobrien} 1634159967Sobrien 1635159967Sobrien#ifdef DEVICE_POLLING 1636272257Sglebiusstatic poll_handler_t nfe_poll; 1637159967Sobrien 1638163503Sobrien 1639193096Sattiliostatic int 1640268131Smarcelnfe_poll(if_t ifp, enum poll_cmd cmd, int count) 1641159967Sobrien{ 1642268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 1643170589Syongari uint32_t r; 1644193096Sattilio int rx_npkts = 0; 1645159967Sobrien 1646159967Sobrien NFE_LOCK(sc); 1647159967Sobrien 1648268131Smarcel if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) { 1649170589Syongari NFE_UNLOCK(sc); 1650193096Sattilio return (rx_npkts); 1651159967Sobrien } 1652159967Sobrien 1653171559Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1654193096Sattilio rx_npkts = nfe_jrxeof(sc, count, &rx_npkts); 1655171559Syongari else 1656193096Sattilio rx_npkts = nfe_rxeof(sc, count, &rx_npkts); 1657159967Sobrien nfe_txeof(sc); 1658268131Smarcel if (!if_sendq_empty(ifp)) 1659216925Sjhb nfe_start_locked(ifp); 1660159967Sobrien 1661159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1662170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1663170589Syongari NFE_UNLOCK(sc); 1664193096Sattilio return (rx_npkts); 1665163503Sobrien } 1666170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1667159967Sobrien 1668163503Sobrien if (r & NFE_IRQ_LINK) { 1669163503Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1670163503Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1671170589Syongari DPRINTF(sc, "link state changed\n"); 1672163503Sobrien } 1673159967Sobrien } 1674170589Syongari NFE_UNLOCK(sc); 1675193096Sattilio return (rx_npkts); 1676159967Sobrien} 1677159967Sobrien#endif /* DEVICE_POLLING */ 1678159967Sobrien 1679170589Syongaristatic void 1680170589Syongarinfe_set_intr(struct nfe_softc *sc) 1681170589Syongari{ 1682159967Sobrien 1683170589Syongari if (sc->nfe_msi != 0) 1684170589Syongari NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1685170589Syongari} 1686170589Syongari 1687170589Syongari 1688170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */ 1689170589Syongaristatic __inline void 1690170589Syongarinfe_enable_intr(struct nfe_softc *sc) 1691170589Syongari{ 1692170589Syongari 1693170589Syongari if (sc->nfe_msix != 0) { 1694170589Syongari /* XXX Should have a better way to enable interrupts! */ 1695170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1696170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1697170589Syongari } else 1698170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1699170589Syongari} 1700170589Syongari 1701170589Syongari 1702170589Syongaristatic __inline void 1703170589Syongarinfe_disable_intr(struct nfe_softc *sc) 1704170589Syongari{ 1705170589Syongari 1706170589Syongari if (sc->nfe_msix != 0) { 1707170589Syongari /* XXX Should have a better way to disable interrupts! */ 1708170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1709170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1710170589Syongari } else 1711170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1712170589Syongari} 1713170589Syongari 1714170589Syongari 1715159967Sobrienstatic int 1716268131Smarcelnfe_ioctl(if_t ifp, u_long cmd, caddr_t data) 1717159967Sobrien{ 1718170589Syongari struct nfe_softc *sc; 1719170589Syongari struct ifreq *ifr; 1720163503Sobrien struct mii_data *mii; 1721170589Syongari int error, init, mask; 1722159967Sobrien 1723268131Smarcel sc = if_getsoftc(ifp); 1724170589Syongari ifr = (struct ifreq *) data; 1725170589Syongari error = 0; 1726170589Syongari init = 0; 1727159952Sobrien switch (cmd) { 1728159952Sobrien case SIOCSIFMTU: 1729170589Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1730159952Sobrien error = EINVAL; 1731268131Smarcel else if (if_getmtu(ifp) != ifr->ifr_mtu) { 1732171559Syongari if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) || 1733171559Syongari (sc->nfe_jumbo_disable != 0)) && 1734170589Syongari ifr->ifr_mtu > ETHERMTU) 1735170589Syongari error = EINVAL; 1736170589Syongari else { 1737170589Syongari NFE_LOCK(sc); 1738268131Smarcel if_setmtu(ifp, ifr->ifr_mtu); 1739268131Smarcel if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 1740268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1741170589Syongari nfe_init_locked(sc); 1742217794Syongari } 1743170589Syongari NFE_UNLOCK(sc); 1744164650Sobrien } 1745164650Sobrien } 1746159952Sobrien break; 1747159952Sobrien case SIOCSIFFLAGS: 1748159967Sobrien NFE_LOCK(sc); 1749268131Smarcel if (if_getflags(ifp) & IFF_UP) { 1750159952Sobrien /* 1751159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1752159952Sobrien * don't do a full re-init of the chip, just update 1753159952Sobrien * the Rx filter. 1754159952Sobrien */ 1755268131Smarcel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) && 1756268131Smarcel ((if_getflags(ifp) ^ sc->nfe_if_flags) & 1757159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1758159952Sobrien nfe_setmulti(sc); 1759159967Sobrien else 1760159967Sobrien nfe_init_locked(sc); 1761159952Sobrien } else { 1762268131Smarcel if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1763170589Syongari nfe_stop(ifp); 1764159952Sobrien } 1765268131Smarcel sc->nfe_if_flags = if_getflags(ifp); 1766159967Sobrien NFE_UNLOCK(sc); 1767159967Sobrien error = 0; 1768159952Sobrien break; 1769159952Sobrien case SIOCADDMULTI: 1770159952Sobrien case SIOCDELMULTI: 1771268131Smarcel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 1772159967Sobrien NFE_LOCK(sc); 1773159967Sobrien nfe_setmulti(sc); 1774159967Sobrien NFE_UNLOCK(sc); 1775159952Sobrien error = 0; 1776159952Sobrien } 1777159952Sobrien break; 1778159952Sobrien case SIOCSIFMEDIA: 1779159952Sobrien case SIOCGIFMEDIA: 1780159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1781270876Sglebius error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1782159952Sobrien break; 1783159967Sobrien case SIOCSIFCAP: 1784268131Smarcel mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 1785159967Sobrien#ifdef DEVICE_POLLING 1786170589Syongari if ((mask & IFCAP_POLLING) != 0) { 1787170589Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1788272257Sglebius error = ether_poll_register(nfe_poll, ifp); 1789159967Sobrien if (error) 1790170589Syongari break; 1791159967Sobrien NFE_LOCK(sc); 1792170589Syongari nfe_disable_intr(sc); 1793268131Smarcel if_setcapenablebit(ifp, IFCAP_POLLING, 0); 1794159967Sobrien NFE_UNLOCK(sc); 1795159967Sobrien } else { 1796159967Sobrien error = ether_poll_deregister(ifp); 1797159967Sobrien /* Enable interrupt even in error case */ 1798159967Sobrien NFE_LOCK(sc); 1799170589Syongari nfe_enable_intr(sc); 1800268131Smarcel if_setcapenablebit(ifp, 0, IFCAP_POLLING); 1801159967Sobrien NFE_UNLOCK(sc); 1802159967Sobrien } 1803159967Sobrien } 1804163503Sobrien#endif /* DEVICE_POLLING */ 1805215132Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 1806268131Smarcel (if_getcapabilities(ifp) & IFCAP_WOL_MAGIC) != 0) 1807268131Smarcel if_togglecapenable(ifp, IFCAP_WOL_MAGIC); 1808215432Syongari if ((mask & IFCAP_TXCSUM) != 0 && 1809268131Smarcel (if_getcapabilities(ifp) & IFCAP_TXCSUM) != 0) { 1810268131Smarcel if_togglecapenable(ifp, IFCAP_TXCSUM); 1811268131Smarcel if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0) 1812268131Smarcel if_sethwassistbits(ifp, NFE_CSUM_FEATURES, 0); 1813159967Sobrien else 1814268131Smarcel if_sethwassistbits(ifp, 0, NFE_CSUM_FEATURES); 1815215432Syongari } 1816215432Syongari if ((mask & IFCAP_RXCSUM) != 0 && 1817268131Smarcel (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) { 1818268131Smarcel if_togglecapenable(ifp, IFCAP_RXCSUM); 1819170589Syongari init++; 1820159967Sobrien } 1821215432Syongari if ((mask & IFCAP_TSO4) != 0 && 1822268131Smarcel (if_getcapabilities(ifp) & IFCAP_TSO4) != 0) { 1823268131Smarcel if_togglecapenable(ifp, IFCAP_TSO4); 1824268131Smarcel if ((IFCAP_TSO4 & if_getcapenable(ifp)) != 0) 1825268131Smarcel if_sethwassistbits(ifp, CSUM_TSO, 0); 1826215432Syongari else 1827268131Smarcel if_sethwassistbits(ifp, 0, CSUM_TSO); 1828215432Syongari } 1829215432Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 1830268131Smarcel (if_getcapabilities(ifp) & IFCAP_VLAN_HWTSO) != 0) 1831268131Smarcel if_togglecapenable(ifp, IFCAP_VLAN_HWTSO); 1832215432Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 1833268131Smarcel (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING) != 0) { 1834268131Smarcel if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING); 1835268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) == 0) 1836268131Smarcel if_setcapenablebit(ifp, 0, IFCAP_VLAN_HWTSO); 1837170589Syongari init++; 1838170589Syongari } 1839170589Syongari /* 1840170589Syongari * XXX 1841170589Syongari * It seems that VLAN stripping requires Rx checksum offload. 1842170589Syongari * Unfortunately FreeBSD has no way to disable only Rx side 1843170589Syongari * VLAN stripping. So when we know Rx checksum offload is 1844170589Syongari * disabled turn entire hardware VLAN assist off. 1845170589Syongari */ 1846268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) == 0) { 1847268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) 1848215432Syongari init++; 1849268131Smarcel if_setcapenablebit(ifp, 0, 1850268131Smarcel (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO)); 1851170589Syongari } 1852268131Smarcel if (init > 0 && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 1853268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1854164656Sobrien nfe_init(sc); 1855170589Syongari } 1856268131Smarcel if_vlancap(ifp); 1857159967Sobrien break; 1858159952Sobrien default: 1859270876Sglebius error = ether_ioctl(ifp, cmd, data); 1860159967Sobrien break; 1861159952Sobrien } 1862159952Sobrien 1863170589Syongari return (error); 1864159952Sobrien} 1865159952Sobrien 1866159967Sobrien 1867170589Syongaristatic int 1868163503Sobriennfe_intr(void *arg) 1869159967Sobrien{ 1870170589Syongari struct nfe_softc *sc; 1871170589Syongari uint32_t status; 1872170589Syongari 1873170589Syongari sc = (struct nfe_softc *)arg; 1874170589Syongari 1875170589Syongari status = NFE_READ(sc, sc->nfe_irq_status); 1876170589Syongari if (status == 0 || status == 0xffffffff) 1877170589Syongari return (FILTER_STRAY); 1878170589Syongari nfe_disable_intr(sc); 1879296272Sjhb taskqueue_enqueue(sc->nfe_tq, &sc->nfe_int_task); 1880170589Syongari 1881170589Syongari return (FILTER_HANDLED); 1882170589Syongari} 1883170589Syongari 1884170589Syongari 1885170589Syongaristatic void 1886170589Syongarinfe_int_task(void *arg, int pending) 1887170589Syongari{ 1888159967Sobrien struct nfe_softc *sc = arg; 1889268131Smarcel if_t ifp = sc->nfe_ifp; 1890170589Syongari uint32_t r; 1891170589Syongari int domore; 1892159967Sobrien 1893163503Sobrien NFE_LOCK(sc); 1894159967Sobrien 1895170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1896170589Syongari nfe_enable_intr(sc); 1897170589Syongari NFE_UNLOCK(sc); 1898170589Syongari return; /* not for us */ 1899170589Syongari } 1900170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1901170589Syongari 1902170589Syongari DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1903170589Syongari 1904159967Sobrien#ifdef DEVICE_POLLING 1905268131Smarcel if (if_getcapenable(ifp) & IFCAP_POLLING) { 1906159967Sobrien NFE_UNLOCK(sc); 1907159967Sobrien return; 1908159967Sobrien } 1909159967Sobrien#endif 1910159967Sobrien 1911172169Syongari if (r & NFE_IRQ_LINK) { 1912172169Syongari NFE_READ(sc, NFE_PHY_STATUS); 1913172169Syongari NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1914172169Syongari DPRINTF(sc, "link state changed\n"); 1915172169Syongari } 1916172169Syongari 1917268131Smarcel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { 1918163503Sobrien NFE_UNLOCK(sc); 1919222542Syongari nfe_disable_intr(sc); 1920170589Syongari return; 1921159967Sobrien } 1922159967Sobrien 1923170589Syongari domore = 0; 1924170589Syongari /* check Rx ring */ 1925170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1926193096Sattilio domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL); 1927170589Syongari else 1928193096Sattilio domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL); 1929170589Syongari /* check Tx ring */ 1930170589Syongari nfe_txeof(sc); 1931159967Sobrien 1932268131Smarcel if (!if_sendq_empty(ifp)) 1933216925Sjhb nfe_start_locked(ifp); 1934159967Sobrien 1935159967Sobrien NFE_UNLOCK(sc); 1936159967Sobrien 1937170589Syongari if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1938296272Sjhb taskqueue_enqueue(sc->nfe_tq, &sc->nfe_int_task); 1939170589Syongari return; 1940170589Syongari } 1941170589Syongari 1942170589Syongari /* Reenable interrupts. */ 1943170589Syongari nfe_enable_intr(sc); 1944159967Sobrien} 1945159967Sobrien 1946163503Sobrien 1947170589Syongaristatic __inline void 1948170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1949159952Sobrien{ 1950170589Syongari struct nfe_desc32 *desc32; 1951170589Syongari struct nfe_desc64 *desc64; 1952170589Syongari struct nfe_rx_data *data; 1953170589Syongari struct mbuf *m; 1954163503Sobrien 1955170589Syongari data = &sc->rxq.data[idx]; 1956170589Syongari m = data->m; 1957170589Syongari 1958170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1959170589Syongari desc64 = &sc->rxq.desc64[idx]; 1960170589Syongari /* VLAN packet may have overwritten it. */ 1961170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1962170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1963170589Syongari desc64->length = htole16(m->m_len); 1964170589Syongari desc64->flags = htole16(NFE_RX_READY); 1965170589Syongari } else { 1966170589Syongari desc32 = &sc->rxq.desc32[idx]; 1967170589Syongari desc32->length = htole16(m->m_len); 1968170589Syongari desc32->flags = htole16(NFE_RX_READY); 1969170589Syongari } 1970159952Sobrien} 1971159952Sobrien 1972163503Sobrien 1973170589Syongaristatic __inline void 1974170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1975159952Sobrien{ 1976170589Syongari struct nfe_desc32 *desc32; 1977170589Syongari struct nfe_desc64 *desc64; 1978170589Syongari struct nfe_rx_data *data; 1979170589Syongari struct mbuf *m; 1980163503Sobrien 1981170589Syongari data = &sc->jrxq.jdata[idx]; 1982170589Syongari m = data->m; 1983170589Syongari 1984170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1985170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 1986170589Syongari /* VLAN packet may have overwritten it. */ 1987170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1988170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1989170589Syongari desc64->length = htole16(m->m_len); 1990170589Syongari desc64->flags = htole16(NFE_RX_READY); 1991170589Syongari } else { 1992170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 1993170589Syongari desc32->length = htole16(m->m_len); 1994170589Syongari desc32->flags = htole16(NFE_RX_READY); 1995170589Syongari } 1996159952Sobrien} 1997159952Sobrien 1998163503Sobrien 1999170589Syongaristatic int 2000170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx) 2001159952Sobrien{ 2002170589Syongari struct nfe_rx_data *data; 2003170589Syongari struct nfe_desc32 *desc32; 2004170589Syongari struct nfe_desc64 *desc64; 2005170589Syongari struct mbuf *m; 2006170589Syongari bus_dma_segment_t segs[1]; 2007170589Syongari bus_dmamap_t map; 2008170589Syongari int nsegs; 2009163503Sobrien 2010243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2011170589Syongari if (m == NULL) 2012170589Syongari return (ENOBUFS); 2013159952Sobrien 2014170589Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 2015170589Syongari m_adj(m, ETHER_ALIGN); 2016163503Sobrien 2017170589Syongari if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 2018170589Syongari m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2019170589Syongari m_freem(m); 2020170589Syongari return (ENOBUFS); 2021170589Syongari } 2022170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2023163503Sobrien 2024170589Syongari data = &sc->rxq.data[idx]; 2025170589Syongari if (data->m != NULL) { 2026170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2027170589Syongari BUS_DMASYNC_POSTREAD); 2028170589Syongari bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 2029170589Syongari } 2030170589Syongari map = data->rx_data_map; 2031170589Syongari data->rx_data_map = sc->rxq.rx_spare_map; 2032170589Syongari sc->rxq.rx_spare_map = map; 2033170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2034170589Syongari BUS_DMASYNC_PREREAD); 2035170589Syongari data->paddr = segs[0].ds_addr; 2036170589Syongari data->m = m; 2037170589Syongari /* update mapping address in h/w descriptor */ 2038170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2039170589Syongari desc64 = &sc->rxq.desc64[idx]; 2040170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2041170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2042170589Syongari desc64->length = htole16(segs[0].ds_len); 2043170589Syongari desc64->flags = htole16(NFE_RX_READY); 2044170589Syongari } else { 2045170589Syongari desc32 = &sc->rxq.desc32[idx]; 2046170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2047170589Syongari desc32->length = htole16(segs[0].ds_len); 2048170589Syongari desc32->flags = htole16(NFE_RX_READY); 2049170589Syongari } 2050170589Syongari 2051170589Syongari return (0); 2052159952Sobrien} 2053159952Sobrien 2054163503Sobrien 2055170589Syongaristatic int 2056170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx) 2057159952Sobrien{ 2058170589Syongari struct nfe_rx_data *data; 2059170589Syongari struct nfe_desc32 *desc32; 2060170589Syongari struct nfe_desc64 *desc64; 2061170589Syongari struct mbuf *m; 2062170589Syongari bus_dma_segment_t segs[1]; 2063170589Syongari bus_dmamap_t map; 2064170589Syongari int nsegs; 2065163503Sobrien 2066243857Sglebius m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 2067170589Syongari if (m == NULL) 2068170589Syongari return (ENOBUFS); 2069176859Syongari m->m_pkthdr.len = m->m_len = MJUM9BYTES; 2070170589Syongari m_adj(m, ETHER_ALIGN); 2071159952Sobrien 2072170589Syongari if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 2073170589Syongari sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2074170589Syongari m_freem(m); 2075170589Syongari return (ENOBUFS); 2076170589Syongari } 2077170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2078163503Sobrien 2079170589Syongari data = &sc->jrxq.jdata[idx]; 2080170589Syongari if (data->m != NULL) { 2081170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2082170589Syongari BUS_DMASYNC_POSTREAD); 2083170589Syongari bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 2084170589Syongari } 2085170589Syongari map = data->rx_data_map; 2086170589Syongari data->rx_data_map = sc->jrxq.jrx_spare_map; 2087170589Syongari sc->jrxq.jrx_spare_map = map; 2088170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2089170589Syongari BUS_DMASYNC_PREREAD); 2090170589Syongari data->paddr = segs[0].ds_addr; 2091170589Syongari data->m = m; 2092170589Syongari /* update mapping address in h/w descriptor */ 2093170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2094170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 2095170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2096170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2097170589Syongari desc64->length = htole16(segs[0].ds_len); 2098170589Syongari desc64->flags = htole16(NFE_RX_READY); 2099170589Syongari } else { 2100170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 2101170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2102170589Syongari desc32->length = htole16(segs[0].ds_len); 2103170589Syongari desc32->flags = htole16(NFE_RX_READY); 2104170589Syongari } 2105159967Sobrien 2106170589Syongari return (0); 2107159952Sobrien} 2108159952Sobrien 2109163503Sobrien 2110170589Syongaristatic int 2111193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2112159952Sobrien{ 2113268131Smarcel if_t ifp = sc->nfe_ifp; 2114170589Syongari struct nfe_desc32 *desc32; 2115170589Syongari struct nfe_desc64 *desc64; 2116159952Sobrien struct nfe_rx_data *data; 2117170589Syongari struct mbuf *m; 2118170589Syongari uint16_t flags; 2119193096Sattilio int len, prog, rx_npkts; 2120170589Syongari uint32_t vtag = 0; 2121159952Sobrien 2122193096Sattilio rx_npkts = 0; 2123159967Sobrien NFE_LOCK_ASSERT(sc); 2124159967Sobrien 2125170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2126170589Syongari BUS_DMASYNC_POSTREAD); 2127159967Sobrien 2128170589Syongari for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2129170589Syongari if (count <= 0) 2130170589Syongari break; 2131170589Syongari count--; 2132159967Sobrien 2133159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 2134159952Sobrien 2135159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2136159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2137170589Syongari vtag = le32toh(desc64->physaddr[1]); 2138170589Syongari flags = le16toh(desc64->flags); 2139170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2140159952Sobrien } else { 2141159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2142170589Syongari flags = le16toh(desc32->flags); 2143170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2144159952Sobrien } 2145159952Sobrien 2146159952Sobrien if (flags & NFE_RX_READY) 2147159952Sobrien break; 2148170589Syongari prog++; 2149159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2150170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2151271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2152170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2153170589Syongari continue; 2154170589Syongari } 2155159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2156159952Sobrien flags &= ~NFE_RX_ERROR; 2157159952Sobrien len--; /* fix buffer length */ 2158159952Sobrien } 2159159952Sobrien } else { 2160170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2161271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2162170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2163170589Syongari continue; 2164170589Syongari } 2165159952Sobrien 2166159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2167159952Sobrien flags &= ~NFE_RX_ERROR; 2168159952Sobrien len--; /* fix buffer length */ 2169159952Sobrien } 2170159952Sobrien } 2171159952Sobrien 2172159952Sobrien if (flags & NFE_RX_ERROR) { 2173271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2174170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2175170589Syongari continue; 2176159952Sobrien } 2177159952Sobrien 2178170589Syongari m = data->m; 2179170589Syongari if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2180271782Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 2181170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2182170589Syongari continue; 2183159952Sobrien } 2184159952Sobrien 2185170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2186268131Smarcel (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) { 2187170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2188170589Syongari m->m_flags |= M_VLANTAG; 2189164651Sobrien } 2190159952Sobrien 2191170589Syongari m->m_pkthdr.len = m->m_len = len; 2192170589Syongari m->m_pkthdr.rcvif = ifp; 2193164651Sobrien 2194268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) { 2195170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2196170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2197170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2198170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2199170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2200170589Syongari m->m_pkthdr.csum_flags |= 2201170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2202170589Syongari m->m_pkthdr.csum_data = 0xffff; 2203170589Syongari } 2204159952Sobrien } 2205170589Syongari } 2206170589Syongari 2207271782Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 2208170589Syongari 2209170589Syongari NFE_UNLOCK(sc); 2210268131Smarcel if_input(ifp, m); 2211170589Syongari NFE_LOCK(sc); 2212193096Sattilio rx_npkts++; 2213170589Syongari } 2214170589Syongari 2215170589Syongari if (prog > 0) 2216170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2217170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2218170589Syongari 2219193096Sattilio if (rx_npktsp != NULL) 2220193096Sattilio *rx_npktsp = rx_npkts; 2221170589Syongari return (count > 0 ? 0 : EAGAIN); 2222170589Syongari} 2223170589Syongari 2224170589Syongari 2225170589Syongaristatic int 2226193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2227170589Syongari{ 2228268131Smarcel if_t ifp = sc->nfe_ifp; 2229170589Syongari struct nfe_desc32 *desc32; 2230170589Syongari struct nfe_desc64 *desc64; 2231170589Syongari struct nfe_rx_data *data; 2232170589Syongari struct mbuf *m; 2233170589Syongari uint16_t flags; 2234193096Sattilio int len, prog, rx_npkts; 2235170589Syongari uint32_t vtag = 0; 2236170589Syongari 2237193096Sattilio rx_npkts = 0; 2238170589Syongari NFE_LOCK_ASSERT(sc); 2239170589Syongari 2240170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2241170589Syongari BUS_DMASYNC_POSTREAD); 2242170589Syongari 2243170589Syongari for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2244170589Syongari vtag = 0) { 2245170589Syongari if (count <= 0) 2246170589Syongari break; 2247170589Syongari count--; 2248170589Syongari 2249170589Syongari data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2250170589Syongari 2251170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2252170589Syongari desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2253170589Syongari vtag = le32toh(desc64->physaddr[1]); 2254170589Syongari flags = le16toh(desc64->flags); 2255170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2256170589Syongari } else { 2257170589Syongari desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2258170589Syongari flags = le16toh(desc32->flags); 2259170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2260170589Syongari } 2261170589Syongari 2262170589Syongari if (flags & NFE_RX_READY) 2263170589Syongari break; 2264170589Syongari prog++; 2265170589Syongari if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2266170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2267271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2268170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2269170589Syongari continue; 2270170589Syongari } 2271170589Syongari if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2272170589Syongari flags &= ~NFE_RX_ERROR; 2273170589Syongari len--; /* fix buffer length */ 2274170589Syongari } 2275170589Syongari } else { 2276170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2277271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2278170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2279170589Syongari continue; 2280170589Syongari } 2281170589Syongari 2282170589Syongari if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2283170589Syongari flags &= ~NFE_RX_ERROR; 2284170589Syongari len--; /* fix buffer length */ 2285170589Syongari } 2286170589Syongari } 2287170589Syongari 2288170589Syongari if (flags & NFE_RX_ERROR) { 2289271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2290170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2291170589Syongari continue; 2292164651Sobrien } 2293159952Sobrien 2294159952Sobrien m = data->m; 2295170589Syongari if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2296271782Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 2297170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2298170589Syongari continue; 2299170589Syongari } 2300159952Sobrien 2301170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2302268131Smarcel (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) { 2303170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2304170589Syongari m->m_flags |= M_VLANTAG; 2305170589Syongari } 2306170589Syongari 2307159952Sobrien m->m_pkthdr.len = m->m_len = len; 2308159952Sobrien m->m_pkthdr.rcvif = ifp; 2309159952Sobrien 2310268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) { 2311170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2312170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2313159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2314170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2315170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2316170589Syongari m->m_pkthdr.csum_flags |= 2317170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2318170589Syongari m->m_pkthdr.csum_data = 0xffff; 2319170589Syongari } 2320159967Sobrien } 2321159952Sobrien } 2322159952Sobrien 2323271782Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 2324159952Sobrien 2325159967Sobrien NFE_UNLOCK(sc); 2326268131Smarcel if_input(ifp, m); 2327159967Sobrien NFE_LOCK(sc); 2328193096Sattilio rx_npkts++; 2329170589Syongari } 2330159967Sobrien 2331170589Syongari if (prog > 0) 2332170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2333170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2334159952Sobrien 2335193096Sattilio if (rx_npktsp != NULL) 2336193096Sattilio *rx_npktsp = rx_npkts; 2337170589Syongari return (count > 0 ? 0 : EAGAIN); 2338159952Sobrien} 2339159952Sobrien 2340163503Sobrien 2341163503Sobrienstatic void 2342163503Sobriennfe_txeof(struct nfe_softc *sc) 2343159952Sobrien{ 2344268131Smarcel if_t ifp = sc->nfe_ifp; 2345159952Sobrien struct nfe_desc32 *desc32; 2346159952Sobrien struct nfe_desc64 *desc64; 2347159952Sobrien struct nfe_tx_data *data = NULL; 2348170589Syongari uint16_t flags; 2349170589Syongari int cons, prog; 2350159952Sobrien 2351159967Sobrien NFE_LOCK_ASSERT(sc); 2352159967Sobrien 2353170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2354170589Syongari BUS_DMASYNC_POSTREAD); 2355170589Syongari 2356170589Syongari prog = 0; 2357170589Syongari for (cons = sc->txq.next; cons != sc->txq.cur; 2358170589Syongari NFE_INC(cons, NFE_TX_RING_COUNT)) { 2359159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2360170589Syongari desc64 = &sc->txq.desc64[cons]; 2361170589Syongari flags = le16toh(desc64->flags); 2362159952Sobrien } else { 2363170589Syongari desc32 = &sc->txq.desc32[cons]; 2364170589Syongari flags = le16toh(desc32->flags); 2365159952Sobrien } 2366159952Sobrien 2367159952Sobrien if (flags & NFE_TX_VALID) 2368159952Sobrien break; 2369159952Sobrien 2370170589Syongari prog++; 2371170589Syongari sc->txq.queued--; 2372170589Syongari data = &sc->txq.data[cons]; 2373159952Sobrien 2374159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2375170589Syongari if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2376170589Syongari continue; 2377159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 2378170589Syongari device_printf(sc->nfe_dev, 2379170589Syongari "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2380159967Sobrien 2381271782Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2382159952Sobrien } else 2383271782Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 2384159952Sobrien } else { 2385170589Syongari if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2386170589Syongari continue; 2387159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 2388170589Syongari device_printf(sc->nfe_dev, 2389170589Syongari "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2390271782Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2391159952Sobrien } else 2392271782Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 2393159952Sobrien } 2394159952Sobrien 2395159952Sobrien /* last fragment of the mbuf chain transmitted */ 2396170589Syongari KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2397170589Syongari bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2398159967Sobrien BUS_DMASYNC_POSTWRITE); 2399170589Syongari bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2400159952Sobrien m_freem(data->m); 2401159952Sobrien data->m = NULL; 2402159952Sobrien } 2403159952Sobrien 2404170589Syongari if (prog > 0) { 2405170589Syongari sc->nfe_force_tx = 0; 2406170589Syongari sc->txq.next = cons; 2407268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 2408170589Syongari if (sc->txq.queued == 0) 2409170589Syongari sc->nfe_watchdog_timer = 0; 2410159952Sobrien } 2411159952Sobrien} 2412159952Sobrien 2413163503Sobrienstatic int 2414170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2415159952Sobrien{ 2416170589Syongari struct nfe_desc32 *desc32 = NULL; 2417170589Syongari struct nfe_desc64 *desc64 = NULL; 2418159952Sobrien bus_dmamap_t map; 2419163503Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2420170589Syongari int error, i, nsegs, prod, si; 2421254803Sandre uint32_t tsosegsz; 2422170589Syongari uint16_t cflags, flags; 2423170589Syongari struct mbuf *m; 2424159952Sobrien 2425170589Syongari prod = si = sc->txq.cur; 2426170589Syongari map = sc->txq.data[prod].tx_data_map; 2427159952Sobrien 2428170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2429159967Sobrien &nsegs, BUS_DMA_NOWAIT); 2430170589Syongari if (error == EFBIG) { 2431243857Sglebius m = m_collapse(*m_head, M_NOWAIT, NFE_MAX_SCATTER); 2432170589Syongari if (m == NULL) { 2433170589Syongari m_freem(*m_head); 2434170589Syongari *m_head = NULL; 2435170589Syongari return (ENOBUFS); 2436170589Syongari } 2437170589Syongari *m_head = m; 2438170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2439170589Syongari *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2440170589Syongari if (error != 0) { 2441170589Syongari m_freem(*m_head); 2442170589Syongari *m_head = NULL; 2443170589Syongari return (ENOBUFS); 2444170589Syongari } 2445170589Syongari } else if (error != 0) 2446170589Syongari return (error); 2447170589Syongari if (nsegs == 0) { 2448170589Syongari m_freem(*m_head); 2449170589Syongari *m_head = NULL; 2450170589Syongari return (EIO); 2451159952Sobrien } 2452159952Sobrien 2453170589Syongari if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2454159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2455170589Syongari return (ENOBUFS); 2456159952Sobrien } 2457159952Sobrien 2458170589Syongari m = *m_head; 2459170589Syongari cflags = flags = 0; 2460254803Sandre tsosegsz = 0; 2461206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2462254803Sandre tsosegsz = (uint32_t)m->m_pkthdr.tso_segsz << 2463206876Syongari NFE_TX_TSO_SHIFT; 2464206876Syongari cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2465206876Syongari cflags |= NFE_TX_TSO; 2466206876Syongari } else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2467170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2468170589Syongari cflags |= NFE_TX_IP_CSUM; 2469170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2470170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2471170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2472170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2473164656Sobrien } 2474159967Sobrien 2475159967Sobrien for (i = 0; i < nsegs; i++) { 2476159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2477170589Syongari desc64 = &sc->txq.desc64[prod]; 2478170589Syongari desc64->physaddr[0] = 2479170589Syongari htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2480170589Syongari desc64->physaddr[1] = 2481170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2482170589Syongari desc64->vtag = 0; 2483159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 2484159952Sobrien desc64->flags = htole16(flags); 2485159952Sobrien } else { 2486170589Syongari desc32 = &sc->txq.desc32[prod]; 2487170589Syongari desc32->physaddr = 2488170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2489159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 2490159952Sobrien desc32->flags = htole16(flags); 2491159952Sobrien } 2492159952Sobrien 2493170589Syongari /* 2494170589Syongari * Setting of the valid bit in the first descriptor is 2495170589Syongari * deferred until the whole chain is fully setup. 2496170589Syongari */ 2497170589Syongari flags |= NFE_TX_VALID; 2498163503Sobrien 2499159952Sobrien sc->txq.queued++; 2500170589Syongari NFE_INC(prod, NFE_TX_RING_COUNT); 2501159952Sobrien } 2502159952Sobrien 2503170589Syongari /* 2504170589Syongari * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2505170589Syongari * csum flags, vtag and TSO belong to the first fragment only. 2506170589Syongari */ 2507159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2508170589Syongari desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2509170589Syongari desc64 = &sc->txq.desc64[si]; 2510170589Syongari if ((m->m_flags & M_VLANTAG) != 0) 2511170589Syongari desc64->vtag = htole32(NFE_TX_VTAG | 2512170589Syongari m->m_pkthdr.ether_vtag); 2513254803Sandre if (tsosegsz != 0) { 2514170589Syongari /* 2515170589Syongari * XXX 2516170589Syongari * The following indicates the descriptor element 2517170589Syongari * is a 32bit quantity. 2518170589Syongari */ 2519254803Sandre desc64->length |= htole16((uint16_t)tsosegsz); 2520254803Sandre desc64->flags |= htole16(tsosegsz >> 16); 2521170589Syongari } 2522170589Syongari /* 2523170589Syongari * finally, set the valid/checksum/TSO bit in the first 2524170589Syongari * descriptor. 2525170589Syongari */ 2526170589Syongari desc64->flags |= htole16(NFE_TX_VALID | cflags); 2527159952Sobrien } else { 2528159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 2529170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2530159952Sobrien else 2531170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2532170589Syongari desc32 = &sc->txq.desc32[si]; 2533254803Sandre if (tsosegsz != 0) { 2534170589Syongari /* 2535170589Syongari * XXX 2536170589Syongari * The following indicates the descriptor element 2537170589Syongari * is a 32bit quantity. 2538170589Syongari */ 2539254803Sandre desc32->length |= htole16((uint16_t)tsosegsz); 2540254803Sandre desc32->flags |= htole16(tsosegsz >> 16); 2541170589Syongari } 2542170589Syongari /* 2543170589Syongari * finally, set the valid/checksum/TSO bit in the first 2544170589Syongari * descriptor. 2545170589Syongari */ 2546170589Syongari desc32->flags |= htole16(NFE_TX_VALID | cflags); 2547159952Sobrien } 2548159952Sobrien 2549170589Syongari sc->txq.cur = prod; 2550170589Syongari prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2551170589Syongari sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2552170589Syongari sc->txq.data[prod].tx_data_map = map; 2553170589Syongari sc->txq.data[prod].m = m; 2554159952Sobrien 2555159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2556159952Sobrien 2557170589Syongari return (0); 2558159952Sobrien} 2559159952Sobrien 2560159967Sobrien 2561163503Sobrienstatic void 2562163503Sobriennfe_setmulti(struct nfe_softc *sc) 2563159952Sobrien{ 2564268131Smarcel if_t ifp = sc->nfe_ifp; 2565268131Smarcel int i, mc_count, mcnt; 2566170589Syongari uint32_t filter; 2567170589Syongari uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2568170589Syongari uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 2569163503Sobrien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2570163503Sobrien }; 2571268131Smarcel uint8_t *mta; 2572159967Sobrien 2573159967Sobrien NFE_LOCK_ASSERT(sc); 2574159967Sobrien 2575268131Smarcel if ((if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2576159967Sobrien bzero(addr, ETHER_ADDR_LEN); 2577159967Sobrien bzero(mask, ETHER_ADDR_LEN); 2578159967Sobrien goto done; 2579159967Sobrien } 2580159967Sobrien 2581159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2582159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2583159967Sobrien 2584268131Smarcel mc_count = if_multiaddr_count(ifp, -1); 2585268131Smarcel mta = malloc(sizeof(uint8_t) * ETHER_ADDR_LEN * mc_count, M_DEVBUF, 2586268131Smarcel M_NOWAIT); 2587159967Sobrien 2588268131Smarcel /* Unable to get memory - process without filtering */ 2589268131Smarcel if (mta == NULL) { 2590268131Smarcel device_printf(sc->nfe_dev, "nfe_setmulti: failed to allocate" 2591268131Smarcel "temp multicast buffer!\n"); 2592159967Sobrien 2593268131Smarcel bzero(addr, ETHER_ADDR_LEN); 2594268131Smarcel bzero(mask, ETHER_ADDR_LEN); 2595268131Smarcel goto done; 2596297793Spfg } 2597268131Smarcel 2598269479Smarcel if_multiaddr_array(ifp, mta, &mcnt, mc_count); 2599268131Smarcel 2600268131Smarcel for (i = 0; i < mcnt; i++) { 2601268131Smarcel uint8_t *addrp; 2602269479Smarcel int j; 2603268131Smarcel 2604268131Smarcel addrp = mta + (i * ETHER_ADDR_LEN); 2605269479Smarcel for (j = 0; j < ETHER_ADDR_LEN; j++) { 2606269479Smarcel u_int8_t mcaddr = addrp[j]; 2607269479Smarcel addr[j] &= mcaddr; 2608269479Smarcel mask[j] &= ~mcaddr; 2609159967Sobrien } 2610159967Sobrien } 2611159967Sobrien 2612269479Smarcel free(mta, M_DEVBUF); 2613269479Smarcel 2614159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2615159967Sobrien mask[i] |= addr[i]; 2616159967Sobrien } 2617159967Sobrien 2618159967Sobriendone: 2619159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 2620159967Sobrien 2621159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2622159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2623159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2624159967Sobrien addr[5] << 8 | addr[4]); 2625159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2626159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2627159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2628159967Sobrien mask[5] << 8 | mask[4]); 2629159967Sobrien 2630170589Syongari filter = NFE_READ(sc, NFE_RXFILTER); 2631170589Syongari filter &= NFE_PFF_RX_PAUSE; 2632170589Syongari filter |= NFE_RXFILTER_MAGIC; 2633268131Smarcel filter |= (if_getflags(ifp) & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2634159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 2635159967Sobrien} 2636159967Sobrien 2637163503Sobrien 2638163503Sobrienstatic void 2639268131Smarcelnfe_start(if_t ifp) 2640159967Sobrien{ 2641268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2642159967Sobrien 2643216925Sjhb NFE_LOCK(sc); 2644216925Sjhb nfe_start_locked(ifp); 2645216925Sjhb NFE_UNLOCK(sc); 2646159967Sobrien} 2647159967Sobrien 2648163503Sobrienstatic void 2649268131Smarcelnfe_start_locked(if_t ifp) 2650159967Sobrien{ 2651268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2652163503Sobrien struct mbuf *m0; 2653268131Smarcel int enq = 0; 2654159952Sobrien 2655216925Sjhb NFE_LOCK_ASSERT(sc); 2656170589Syongari 2657268131Smarcel if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2658216925Sjhb IFF_DRV_RUNNING || sc->nfe_link == 0) 2659159967Sobrien return; 2660159967Sobrien 2661268131Smarcel while (!if_sendq_empty(ifp)) { 2662268131Smarcel m0 = if_dequeue(ifp); 2663268131Smarcel 2664159952Sobrien if (m0 == NULL) 2665159952Sobrien break; 2666159952Sobrien 2667170589Syongari if (nfe_encap(sc, &m0) != 0) { 2668170589Syongari if (m0 == NULL) 2669170589Syongari break; 2670268131Smarcel if_sendq_prepend(ifp, m0); 2671268131Smarcel if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 2672159952Sobrien break; 2673159952Sobrien } 2674170589Syongari enq++; 2675268131Smarcel if_etherbpfmtap(ifp, m0); 2676159952Sobrien } 2677159952Sobrien 2678170589Syongari if (enq > 0) { 2679170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2680170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2681159952Sobrien 2682170589Syongari /* kick Tx */ 2683170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2684159952Sobrien 2685170589Syongari /* 2686170589Syongari * Set a timeout in case the chip goes out to lunch. 2687170589Syongari */ 2688170589Syongari sc->nfe_watchdog_timer = 5; 2689170589Syongari } 2690159952Sobrien} 2691159952Sobrien 2692163503Sobrien 2693163503Sobrienstatic void 2694268131Smarcelnfe_watchdog(if_t ifp) 2695159952Sobrien{ 2696268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2697159952Sobrien 2698170589Syongari if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2699170589Syongari return; 2700159952Sobrien 2701170589Syongari /* Check if we've lost Tx completion interrupt. */ 2702170589Syongari nfe_txeof(sc); 2703170589Syongari if (sc->txq.queued == 0) { 2704170589Syongari if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2705170589Syongari "-- recovering\n"); 2706268131Smarcel if (!if_sendq_empty(ifp)) 2707216925Sjhb nfe_start_locked(ifp); 2708170589Syongari return; 2709170589Syongari } 2710170589Syongari /* Check if we've lost start Tx command. */ 2711170589Syongari sc->nfe_force_tx++; 2712170589Syongari if (sc->nfe_force_tx <= 3) { 2713170589Syongari /* 2714170589Syongari * If this is the case for watchdog timeout, the following 2715170589Syongari * code should go to nfe_txeof(). 2716170589Syongari */ 2717170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2718170589Syongari return; 2719170589Syongari } 2720170589Syongari sc->nfe_force_tx = 0; 2721170589Syongari 2722170589Syongari if_printf(ifp, "watchdog timeout\n"); 2723170589Syongari 2724268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 2725271782Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2726170589Syongari nfe_init_locked(sc); 2727159952Sobrien} 2728159952Sobrien 2729163503Sobrien 2730163503Sobrienstatic void 2731163503Sobriennfe_init(void *xsc) 2732159952Sobrien{ 2733159967Sobrien struct nfe_softc *sc = xsc; 2734159952Sobrien 2735159967Sobrien NFE_LOCK(sc); 2736159967Sobrien nfe_init_locked(sc); 2737159967Sobrien NFE_UNLOCK(sc); 2738159967Sobrien} 2739159967Sobrien 2740163503Sobrien 2741163503Sobrienstatic void 2742163503Sobriennfe_init_locked(void *xsc) 2743159967Sobrien{ 2744159967Sobrien struct nfe_softc *sc = xsc; 2745268131Smarcel if_t ifp = sc->nfe_ifp; 2746159967Sobrien struct mii_data *mii; 2747170589Syongari uint32_t val; 2748170589Syongari int error; 2749159967Sobrien 2750159967Sobrien NFE_LOCK_ASSERT(sc); 2751159967Sobrien 2752159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2753159967Sobrien 2754268131Smarcel if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 2755159967Sobrien return; 2756170589Syongari 2757170589Syongari nfe_stop(ifp); 2758170589Syongari 2759268131Smarcel sc->nfe_framesize = if_getmtu(ifp) + NFE_RX_HEADERS; 2760170589Syongari 2761170589Syongari nfe_init_tx_ring(sc, &sc->txq); 2762170589Syongari if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2763170589Syongari error = nfe_init_jrx_ring(sc, &sc->jrxq); 2764170589Syongari else 2765170589Syongari error = nfe_init_rx_ring(sc, &sc->rxq); 2766170589Syongari if (error != 0) { 2767170589Syongari device_printf(sc->nfe_dev, 2768170589Syongari "initialization failed: no memory for rx buffers\n"); 2769170589Syongari nfe_stop(ifp); 2770170589Syongari return; 2771159967Sobrien } 2772159967Sobrien 2773170589Syongari val = 0; 2774170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2775170589Syongari val |= NFE_MAC_ADDR_INORDER; 2776170589Syongari NFE_WRITE(sc, NFE_TX_UNK, val); 2777159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 2778159952Sobrien 2779170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2780170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2781170589Syongari 2782159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 2783159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 2784159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2785159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2786159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 2787164656Sobrien 2788268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) 2789159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2790268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) 2791170589Syongari sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2792159967Sobrien 2793159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2794159952Sobrien DELAY(10); 2795159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2796159952Sobrien 2797268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) 2798159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2799170589Syongari else 2800170589Syongari NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2801159952Sobrien 2802159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2803159952Sobrien 2804159952Sobrien /* set MAC address */ 2805268131Smarcel nfe_set_macaddr(sc, if_getlladdr(ifp)); 2806159952Sobrien 2807159952Sobrien /* tell MAC where rings are in memory */ 2808170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2809170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2810170589Syongari NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2811170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2812170589Syongari NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2813170589Syongari } else { 2814170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2815170589Syongari NFE_ADDR_HI(sc->rxq.physaddr)); 2816170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2817170589Syongari NFE_ADDR_LO(sc->rxq.physaddr)); 2818170589Syongari } 2819170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2820170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2821159952Sobrien 2822159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 2823159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 2824159952Sobrien (NFE_TX_RING_COUNT - 1)); 2825159952Sobrien 2826170589Syongari NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2827159952Sobrien 2828159952Sobrien /* force MAC to wakeup */ 2829170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2830170589Syongari if ((val & NFE_PWR_WAKEUP) == 0) 2831170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2832159952Sobrien DELAY(10); 2833170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2834170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2835159952Sobrien 2836159952Sobrien#if 1 2837159952Sobrien /* configure interrupts coalescing/mitigation */ 2838159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2839159952Sobrien#else 2840159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 2841159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 2842159952Sobrien#endif 2843159952Sobrien 2844170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2845159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2846159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2847159952Sobrien 2848159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2849159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2850159952Sobrien 2851159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2852215132Syongari /* Disable WOL. */ 2853215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, 0); 2854159952Sobrien 2855159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2856159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2857159952Sobrien DELAY(10); 2858159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2859159952Sobrien 2860159952Sobrien /* set Rx filter */ 2861159952Sobrien nfe_setmulti(sc); 2862159952Sobrien 2863159952Sobrien /* enable Rx */ 2864159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2865159952Sobrien 2866159952Sobrien /* enable Tx */ 2867159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2868159952Sobrien 2869159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2870159952Sobrien 2871183561Syongari /* Clear hardware stats. */ 2872183561Syongari nfe_stats_clear(sc); 2873183561Syongari 2874159967Sobrien#ifdef DEVICE_POLLING 2875268131Smarcel if (if_getcapenable(ifp) & IFCAP_POLLING) 2876170589Syongari nfe_disable_intr(sc); 2877159967Sobrien else 2878159967Sobrien#endif 2879170589Syongari nfe_set_intr(sc); 2880170589Syongari nfe_enable_intr(sc); /* enable interrupts */ 2881159952Sobrien 2882268131Smarcel if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 2883268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 2884159952Sobrien 2885159967Sobrien sc->nfe_link = 0; 2886170589Syongari mii_mediachg(mii); 2887159952Sobrien 2888170589Syongari callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2889159952Sobrien} 2890159952Sobrien 2891163503Sobrien 2892163503Sobrienstatic void 2893268131Smarcelnfe_stop(if_t ifp) 2894159952Sobrien{ 2895268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2896170589Syongari struct nfe_rx_ring *rx_ring; 2897170589Syongari struct nfe_jrx_ring *jrx_ring; 2898170589Syongari struct nfe_tx_ring *tx_ring; 2899170589Syongari struct nfe_rx_data *rdata; 2900170589Syongari struct nfe_tx_data *tdata; 2901170589Syongari int i; 2902159952Sobrien 2903159967Sobrien NFE_LOCK_ASSERT(sc); 2904159952Sobrien 2905170589Syongari sc->nfe_watchdog_timer = 0; 2906268131Smarcel if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 2907159952Sobrien 2908159967Sobrien callout_stop(&sc->nfe_stat_ch); 2909159967Sobrien 2910159952Sobrien /* abort Tx */ 2911159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 2912159952Sobrien 2913159952Sobrien /* disable Rx */ 2914159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 2915159952Sobrien 2916159952Sobrien /* disable interrupts */ 2917170589Syongari nfe_disable_intr(sc); 2918159952Sobrien 2919159967Sobrien sc->nfe_link = 0; 2920159967Sobrien 2921170589Syongari /* free Rx and Tx mbufs still in the queues. */ 2922170589Syongari rx_ring = &sc->rxq; 2923170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2924170589Syongari rdata = &rx_ring->data[i]; 2925170589Syongari if (rdata->m != NULL) { 2926170589Syongari bus_dmamap_sync(rx_ring->rx_data_tag, 2927170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2928170589Syongari bus_dmamap_unload(rx_ring->rx_data_tag, 2929170589Syongari rdata->rx_data_map); 2930170589Syongari m_freem(rdata->m); 2931170589Syongari rdata->m = NULL; 2932170589Syongari } 2933170589Syongari } 2934159952Sobrien 2935170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 2936170589Syongari jrx_ring = &sc->jrxq; 2937170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 2938170589Syongari rdata = &jrx_ring->jdata[i]; 2939170589Syongari if (rdata->m != NULL) { 2940170589Syongari bus_dmamap_sync(jrx_ring->jrx_data_tag, 2941170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2942170589Syongari bus_dmamap_unload(jrx_ring->jrx_data_tag, 2943170589Syongari rdata->rx_data_map); 2944170589Syongari m_freem(rdata->m); 2945170589Syongari rdata->m = NULL; 2946170589Syongari } 2947170589Syongari } 2948170589Syongari } 2949170589Syongari 2950170589Syongari tx_ring = &sc->txq; 2951170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2952170589Syongari tdata = &tx_ring->data[i]; 2953170589Syongari if (tdata->m != NULL) { 2954170589Syongari bus_dmamap_sync(tx_ring->tx_data_tag, 2955170589Syongari tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 2956170589Syongari bus_dmamap_unload(tx_ring->tx_data_tag, 2957170589Syongari tdata->tx_data_map); 2958170589Syongari m_freem(tdata->m); 2959170589Syongari tdata->m = NULL; 2960170589Syongari } 2961170589Syongari } 2962183561Syongari /* Update hardware stats. */ 2963183561Syongari nfe_stats_update(sc); 2964159952Sobrien} 2965159952Sobrien 2966163503Sobrien 2967163503Sobrienstatic int 2968268131Smarcelnfe_ifmedia_upd(if_t ifp) 2969159952Sobrien{ 2970268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2971170589Syongari struct mii_data *mii; 2972159952Sobrien 2973159967Sobrien NFE_LOCK(sc); 2974159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2975159967Sobrien mii_mediachg(mii); 2976170589Syongari NFE_UNLOCK(sc); 2977159967Sobrien 2978159967Sobrien return (0); 2979159952Sobrien} 2980159952Sobrien 2981163503Sobrien 2982163503Sobrienstatic void 2983268131Smarcelnfe_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 2984159952Sobrien{ 2985163503Sobrien struct nfe_softc *sc; 2986163503Sobrien struct mii_data *mii; 2987159952Sobrien 2988268131Smarcel sc = if_getsoftc(ifp); 2989159952Sobrien 2990159967Sobrien NFE_LOCK(sc); 2991159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2992159967Sobrien mii_pollstat(mii); 2993159952Sobrien 2994159967Sobrien ifmr->ifm_active = mii->mii_media_active; 2995159967Sobrien ifmr->ifm_status = mii->mii_media_status; 2996226478Syongari NFE_UNLOCK(sc); 2997159952Sobrien} 2998159952Sobrien 2999163503Sobrien 3000170589Syongarivoid 3001159967Sobriennfe_tick(void *xsc) 3002159952Sobrien{ 3003159967Sobrien struct nfe_softc *sc; 3004163503Sobrien struct mii_data *mii; 3005268131Smarcel if_t ifp; 3006159952Sobrien 3007170589Syongari sc = (struct nfe_softc *)xsc; 3008159952Sobrien 3009163503Sobrien NFE_LOCK_ASSERT(sc); 3010159952Sobrien 3011159967Sobrien ifp = sc->nfe_ifp; 3012159952Sobrien 3013159967Sobrien mii = device_get_softc(sc->nfe_miibus); 3014159967Sobrien mii_tick(mii); 3015183561Syongari nfe_stats_update(sc); 3016170589Syongari nfe_watchdog(ifp); 3017159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 3018159952Sobrien} 3019159952Sobrien 3020159952Sobrien 3021173839Syongaristatic int 3022163503Sobriennfe_shutdown(device_t dev) 3023159952Sobrien{ 3024159952Sobrien 3025215132Syongari return (nfe_suspend(dev)); 3026159952Sobrien} 3027159952Sobrien 3028159952Sobrien 3029163503Sobrienstatic void 3030170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 3031159952Sobrien{ 3032170589Syongari uint32_t val; 3033159952Sobrien 3034170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 3035170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3036170589Syongari addr[0] = (val >> 8) & 0xff; 3037170589Syongari addr[1] = (val & 0xff); 3038159952Sobrien 3039170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3040170589Syongari addr[2] = (val >> 24) & 0xff; 3041170589Syongari addr[3] = (val >> 16) & 0xff; 3042170589Syongari addr[4] = (val >> 8) & 0xff; 3043170589Syongari addr[5] = (val & 0xff); 3044170589Syongari } else { 3045170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3046170589Syongari addr[5] = (val >> 8) & 0xff; 3047170589Syongari addr[4] = (val & 0xff); 3048170589Syongari 3049170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3050170589Syongari addr[3] = (val >> 24) & 0xff; 3051170589Syongari addr[2] = (val >> 16) & 0xff; 3052170589Syongari addr[1] = (val >> 8) & 0xff; 3053170589Syongari addr[0] = (val & 0xff); 3054170589Syongari } 3055159952Sobrien} 3056159952Sobrien 3057163503Sobrien 3058163503Sobrienstatic void 3059170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 3060159952Sobrien{ 3061159967Sobrien 3062159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 3063159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 3064159967Sobrien addr[1] << 8 | addr[0]); 3065159952Sobrien} 3066159952Sobrien 3067163503Sobrien 3068159967Sobrien/* 3069159967Sobrien * Map a single buffer address. 3070159967Sobrien */ 3071159967Sobrien 3072159967Sobrienstatic void 3073170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3074159952Sobrien{ 3075170589Syongari struct nfe_dmamap_arg *ctx; 3076159952Sobrien 3077170589Syongari if (error != 0) 3078159967Sobrien return; 3079159952Sobrien 3080159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 3081159967Sobrien 3082170589Syongari ctx = (struct nfe_dmamap_arg *)arg; 3083170589Syongari ctx->nfe_busaddr = segs[0].ds_addr; 3084170589Syongari} 3085159967Sobrien 3086170589Syongari 3087170589Syongaristatic int 3088170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3089170589Syongari{ 3090170589Syongari int error, value; 3091170589Syongari 3092170589Syongari if (!arg1) 3093170589Syongari return (EINVAL); 3094170589Syongari value = *(int *)arg1; 3095170589Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3096170589Syongari if (error || !req->newptr) 3097170589Syongari return (error); 3098170589Syongari if (value < low || value > high) 3099170589Syongari return (EINVAL); 3100170589Syongari *(int *)arg1 = value; 3101170589Syongari 3102170589Syongari return (0); 3103159952Sobrien} 3104170589Syongari 3105170589Syongari 3106170589Syongaristatic int 3107170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 3108170589Syongari{ 3109170589Syongari 3110170589Syongari return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 3111170589Syongari NFE_PROC_MAX)); 3112170589Syongari} 3113183561Syongari 3114183561Syongari 3115183561Syongari#define NFE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 3116183561Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 3117183561Syongari#define NFE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 3118217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 3119183561Syongari 3120183561Syongaristatic void 3121183561Syongarinfe_sysctl_node(struct nfe_softc *sc) 3122183561Syongari{ 3123183561Syongari struct sysctl_ctx_list *ctx; 3124183561Syongari struct sysctl_oid_list *child, *parent; 3125183561Syongari struct sysctl_oid *tree; 3126183561Syongari struct nfe_hw_stats *stats; 3127183561Syongari int error; 3128183561Syongari 3129183561Syongari stats = &sc->nfe_stats; 3130183561Syongari ctx = device_get_sysctl_ctx(sc->nfe_dev); 3131183561Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev)); 3132183561Syongari SYSCTL_ADD_PROC(ctx, child, 3133183561Syongari OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 3134183561Syongari &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 3135183561Syongari "max number of Rx events to process"); 3136183561Syongari 3137183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3138183561Syongari error = resource_int_value(device_get_name(sc->nfe_dev), 3139183561Syongari device_get_unit(sc->nfe_dev), "process_limit", 3140183561Syongari &sc->nfe_process_limit); 3141183561Syongari if (error == 0) { 3142183561Syongari if (sc->nfe_process_limit < NFE_PROC_MIN || 3143183561Syongari sc->nfe_process_limit > NFE_PROC_MAX) { 3144183561Syongari device_printf(sc->nfe_dev, 3145183561Syongari "process_limit value out of range; " 3146183561Syongari "using default: %d\n", NFE_PROC_DEFAULT); 3147183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3148183561Syongari } 3149183561Syongari } 3150183561Syongari 3151183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3152183561Syongari return; 3153183561Syongari 3154183561Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 3155183561Syongari NULL, "NFE statistics"); 3156183561Syongari parent = SYSCTL_CHILDREN(tree); 3157183561Syongari 3158183561Syongari /* Rx statistics. */ 3159183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 3160183561Syongari NULL, "Rx MAC statistics"); 3161183561Syongari child = SYSCTL_CHILDREN(tree); 3162183561Syongari 3163183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors", 3164183561Syongari &stats->rx_frame_errors, "Framing Errors"); 3165183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes", 3166183561Syongari &stats->rx_extra_bytes, "Extra Bytes"); 3167183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3168183561Syongari &stats->rx_late_cols, "Late Collisions"); 3169183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "runts", 3170183561Syongari &stats->rx_runts, "Runts"); 3171183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos", 3172183561Syongari &stats->rx_jumbos, "Jumbos"); 3173183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns", 3174183561Syongari &stats->rx_fifo_overuns, "FIFO Overruns"); 3175183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors", 3176183561Syongari &stats->rx_crc_errors, "CRC Errors"); 3177183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fae", 3178183561Syongari &stats->rx_fae, "Frame Alignment Errors"); 3179183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors", 3180183561Syongari &stats->rx_len_errors, "Length Errors"); 3181183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3182183561Syongari &stats->rx_unicast, "Unicast Frames"); 3183183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3184183561Syongari &stats->rx_multicast, "Multicast Frames"); 3185186346Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3186183561Syongari &stats->rx_broadcast, "Broadcast Frames"); 3187183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3188183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3189183561Syongari &stats->rx_octets, "Octets"); 3190183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3191183561Syongari &stats->rx_pause, "Pause frames"); 3192183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "drops", 3193183561Syongari &stats->rx_drops, "Drop frames"); 3194183561Syongari } 3195183561Syongari 3196183561Syongari /* Tx statistics. */ 3197183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 3198183561Syongari NULL, "Tx MAC statistics"); 3199183561Syongari child = SYSCTL_CHILDREN(tree); 3200183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3201183561Syongari &stats->tx_octets, "Octets"); 3202183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits", 3203183561Syongari &stats->tx_zero_rexmits, "Zero Retransmits"); 3204183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits", 3205183561Syongari &stats->tx_one_rexmits, "One Retransmits"); 3206183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits", 3207183561Syongari &stats->tx_multi_rexmits, "Multiple Retransmits"); 3208183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3209183561Syongari &stats->tx_late_cols, "Late Collisions"); 3210183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns", 3211183561Syongari &stats->tx_fifo_underuns, "FIFO Underruns"); 3212183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts", 3213183561Syongari &stats->tx_carrier_losts, "Carrier Losts"); 3214183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals", 3215183561Syongari &stats->tx_excess_deferals, "Excess Deferrals"); 3216183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors", 3217183561Syongari &stats->tx_retry_errors, "Retry Errors"); 3218183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3219183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals", 3220183561Syongari &stats->tx_deferals, "Deferrals"); 3221183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frames", 3222183561Syongari &stats->tx_frames, "Frames"); 3223183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3224183561Syongari &stats->tx_pause, "Pause Frames"); 3225183561Syongari } 3226183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3227183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3228183561Syongari &stats->tx_deferals, "Unicast Frames"); 3229183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3230183561Syongari &stats->tx_frames, "Multicast Frames"); 3231183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3232183561Syongari &stats->tx_pause, "Broadcast Frames"); 3233183561Syongari } 3234183561Syongari} 3235183561Syongari 3236183561Syongari#undef NFE_SYSCTL_STAT_ADD32 3237183561Syongari#undef NFE_SYSCTL_STAT_ADD64 3238183561Syongari 3239183561Syongaristatic void 3240183561Syongarinfe_stats_clear(struct nfe_softc *sc) 3241183561Syongari{ 3242183561Syongari int i, mib_cnt; 3243183561Syongari 3244183561Syongari if ((sc->nfe_flags & NFE_MIB_V1) != 0) 3245183561Syongari mib_cnt = NFE_NUM_MIB_STATV1; 3246183561Syongari else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0) 3247183561Syongari mib_cnt = NFE_NUM_MIB_STATV2; 3248183561Syongari else 3249183561Syongari return; 3250183561Syongari 3251256038Syongari for (i = 0; i < mib_cnt; i++) 3252256038Syongari NFE_READ(sc, NFE_TX_OCTET + i * sizeof(uint32_t)); 3253183561Syongari 3254183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3255183561Syongari NFE_READ(sc, NFE_TX_UNICAST); 3256183561Syongari NFE_READ(sc, NFE_TX_MULTICAST); 3257183561Syongari NFE_READ(sc, NFE_TX_BROADCAST); 3258183561Syongari } 3259183561Syongari} 3260183561Syongari 3261183561Syongaristatic void 3262183561Syongarinfe_stats_update(struct nfe_softc *sc) 3263183561Syongari{ 3264183561Syongari struct nfe_hw_stats *stats; 3265183561Syongari 3266183561Syongari NFE_LOCK_ASSERT(sc); 3267183561Syongari 3268183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3269183561Syongari return; 3270183561Syongari 3271183561Syongari stats = &sc->nfe_stats; 3272183561Syongari stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET); 3273183561Syongari stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT); 3274183561Syongari stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT); 3275183561Syongari stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT); 3276183561Syongari stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL); 3277183561Syongari stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN); 3278183561Syongari stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST); 3279183561Syongari stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL); 3280183561Syongari stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR); 3281183561Syongari stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR); 3282183561Syongari stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES); 3283183561Syongari stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL); 3284183561Syongari stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT); 3285183561Syongari stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO); 3286183561Syongari stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN); 3287183561Syongari stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR); 3288183561Syongari stats->rx_fae += NFE_READ(sc, NFE_RX_FAE); 3289183561Syongari stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR); 3290183561Syongari stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST); 3291183561Syongari stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST); 3292183561Syongari stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST); 3293183561Syongari 3294183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3295183561Syongari stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL); 3296183561Syongari stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME); 3297183561Syongari stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET); 3298183561Syongari stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE); 3299183561Syongari stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE); 3300183561Syongari stats->rx_drops += NFE_READ(sc, NFE_RX_DROP); 3301183561Syongari } 3302183561Syongari 3303183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3304183561Syongari stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST); 3305183561Syongari stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST); 3306255648Sdelphij stats->tx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST); 3307183561Syongari } 3308183561Syongari} 3309215132Syongari 3310215132Syongari 3311215132Syongaristatic void 3312215132Syongarinfe_set_linkspeed(struct nfe_softc *sc) 3313215132Syongari{ 3314215132Syongari struct mii_softc *miisc; 3315215132Syongari struct mii_data *mii; 3316215132Syongari int aneg, i, phyno; 3317215132Syongari 3318215132Syongari NFE_LOCK_ASSERT(sc); 3319215132Syongari 3320215132Syongari mii = device_get_softc(sc->nfe_miibus); 3321215132Syongari mii_pollstat(mii); 3322215132Syongari aneg = 0; 3323215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 3324215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 3325215132Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 3326215132Syongari case IFM_10_T: 3327215132Syongari case IFM_100_TX: 3328215132Syongari return; 3329215132Syongari case IFM_1000_T: 3330215132Syongari aneg++; 3331215132Syongari break; 3332215132Syongari default: 3333215132Syongari break; 3334215132Syongari } 3335215132Syongari } 3336221407Smarius miisc = LIST_FIRST(&mii->mii_phys); 3337221407Smarius phyno = miisc->mii_phy; 3338221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 3339221407Smarius PHY_RESET(miisc); 3340215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0); 3341215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3342215132Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 3343215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3344215132Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 3345215132Syongari DELAY(1000); 3346215132Syongari if (aneg != 0) { 3347215132Syongari /* 3348215132Syongari * Poll link state until nfe(4) get a 10/100Mbps link. 3349215132Syongari */ 3350215132Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 3351215132Syongari mii_pollstat(mii); 3352215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 3353215132Syongari == (IFM_ACTIVE | IFM_AVALID)) { 3354215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 3355215132Syongari case IFM_10_T: 3356215132Syongari case IFM_100_TX: 3357215132Syongari nfe_mac_config(sc, mii); 3358215132Syongari return; 3359215132Syongari default: 3360215132Syongari break; 3361215132Syongari } 3362215132Syongari } 3363215132Syongari NFE_UNLOCK(sc); 3364215132Syongari pause("nfelnk", hz); 3365215132Syongari NFE_LOCK(sc); 3366215132Syongari } 3367215132Syongari if (i == MII_ANEGTICKS_GIGE) 3368215132Syongari device_printf(sc->nfe_dev, 3369215132Syongari "establishing a link failed, WOL may not work!"); 3370215132Syongari } 3371215132Syongari /* 3372215132Syongari * No link, force MAC to have 100Mbps, full-duplex link. 3373215132Syongari * This is the last resort and may/may not work. 3374215132Syongari */ 3375215132Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 3376215132Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 3377215132Syongari nfe_mac_config(sc, mii); 3378215132Syongari} 3379215132Syongari 3380215132Syongari 3381215132Syongaristatic void 3382215132Syongarinfe_set_wol(struct nfe_softc *sc) 3383215132Syongari{ 3384268131Smarcel if_t ifp; 3385215132Syongari uint32_t wolctl; 3386215132Syongari int pmc; 3387215132Syongari uint16_t pmstat; 3388215132Syongari 3389215132Syongari NFE_LOCK_ASSERT(sc); 3390215132Syongari 3391219902Sjhb if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0) 3392215132Syongari return; 3393215132Syongari ifp = sc->nfe_ifp; 3394268131Smarcel if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) 3395215132Syongari wolctl = NFE_WOL_MAGIC; 3396215132Syongari else 3397215132Syongari wolctl = 0; 3398215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, wolctl); 3399268131Smarcel if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) { 3400215132Syongari nfe_set_linkspeed(sc); 3401215132Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) != 0) 3402215132Syongari NFE_WRITE(sc, NFE_PWR2_CTL, 3403215132Syongari NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS); 3404215132Syongari /* Enable RX. */ 3405215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0); 3406215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0); 3407215132Syongari NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) | 3408215132Syongari NFE_RX_START); 3409215132Syongari } 3410215132Syongari /* Request PME if WOL is requested. */ 3411215132Syongari pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2); 3412215132Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 3413268131Smarcel if ((if_getcapenable(ifp) & IFCAP_WOL) != 0) 3414215132Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 3415215132Syongari pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 3416215132Syongari} 3417