if_nfe.c revision 296272
1159967Sobrien/* $OpenBSD: if_nfe.c,v 1.54 2006/04/07 12:38:12 jsg Exp $ */ 2159952Sobrien 3159952Sobrien/*- 4159967Sobrien * Copyright (c) 2006 Shigeaki Tagashira <shigeaki@se.hiroshima-u.ac.jp> 5159952Sobrien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 6159952Sobrien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 7159952Sobrien * 8159952Sobrien * Permission to use, copy, modify, and distribute this software for any 9159952Sobrien * purpose with or without fee is hereby granted, provided that the above 10159952Sobrien * copyright notice and this permission notice appear in all copies. 11159952Sobrien * 12159952Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13159952Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14159952Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15159952Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16159952Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17159952Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18159952Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19159952Sobrien */ 20159952Sobrien 21159952Sobrien/* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 22159952Sobrien 23159967Sobrien#include <sys/cdefs.h> 24159967Sobrien__FBSDID("$FreeBSD: head/sys/dev/nfe/if_nfe.c 296272 2016-03-01 17:47:32Z jhb $"); 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"}, 268159967Sobrien {0, 0, NULL} 269159967Sobrien}; 270159967Sobrien 271159967Sobrien 272159967Sobrien/* Probe for supported hardware ID's */ 273159967Sobrienstatic int 274159967Sobriennfe_probe(device_t dev) 275159952Sobrien{ 276159967Sobrien struct nfe_type *t; 277159967Sobrien 278159967Sobrien t = nfe_devs; 279159967Sobrien /* Check for matching PCI DEVICE ID's */ 280159967Sobrien while (t->name != NULL) { 281159967Sobrien if ((pci_get_vendor(dev) == t->vid_id) && 282159967Sobrien (pci_get_device(dev) == t->dev_id)) { 283159967Sobrien device_set_desc(dev, t->name); 284170589Syongari return (BUS_PROBE_DEFAULT); 285159967Sobrien } 286159967Sobrien t++; 287159967Sobrien } 288159967Sobrien 289159967Sobrien return (ENXIO); 290159952Sobrien} 291159952Sobrien 292170589Syongaristatic void 293170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count) 294170589Syongari{ 295170589Syongari int rid; 296163503Sobrien 297170589Syongari rid = PCIR_BAR(2); 298170589Syongari sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY, 299170589Syongari &rid, RF_ACTIVE); 300170589Syongari if (sc->nfe_msix_res == NULL) { 301170589Syongari device_printf(sc->nfe_dev, 302170589Syongari "couldn't allocate MSIX table resource\n"); 303170589Syongari return; 304170589Syongari } 305170589Syongari rid = PCIR_BAR(3); 306170589Syongari sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev, 307170589Syongari SYS_RES_MEMORY, &rid, RF_ACTIVE); 308170589Syongari if (sc->nfe_msix_pba_res == NULL) { 309170589Syongari device_printf(sc->nfe_dev, 310170589Syongari "couldn't allocate MSIX PBA resource\n"); 311170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2), 312170589Syongari sc->nfe_msix_res); 313170589Syongari sc->nfe_msix_res = NULL; 314170589Syongari return; 315170589Syongari } 316170589Syongari 317170589Syongari if (pci_alloc_msix(sc->nfe_dev, &count) == 0) { 318170589Syongari if (count == NFE_MSI_MESSAGES) { 319170589Syongari if (bootverbose) 320170589Syongari device_printf(sc->nfe_dev, 321170589Syongari "Using %d MSIX messages\n", count); 322170589Syongari sc->nfe_msix = 1; 323170589Syongari } else { 324170589Syongari if (bootverbose) 325170589Syongari device_printf(sc->nfe_dev, 326170589Syongari "couldn't allocate MSIX\n"); 327170589Syongari pci_release_msi(sc->nfe_dev); 328170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 329170589Syongari PCIR_BAR(3), sc->nfe_msix_pba_res); 330170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 331170589Syongari PCIR_BAR(2), sc->nfe_msix_res); 332170589Syongari sc->nfe_msix_pba_res = NULL; 333170589Syongari sc->nfe_msix_res = NULL; 334170589Syongari } 335170589Syongari } 336170589Syongari} 337170589Syongari 338264293Syongari 339159967Sobrienstatic int 340264293Syongarinfe_detect_msik9(struct nfe_softc *sc) 341264293Syongari{ 342264293Syongari static const char *maker = "MSI"; 343264293Syongari static const char *product = "K9N6PGM2-V2 (MS-7309)"; 344264293Syongari char *m, *p; 345264293Syongari int found; 346264293Syongari 347264293Syongari found = 0; 348273174Sdavide m = kern_getenv("smbios.planar.maker"); 349273174Sdavide p = kern_getenv("smbios.planar.product"); 350264293Syongari if (m != NULL && p != NULL) { 351264293Syongari if (strcmp(m, maker) == 0 && strcmp(p, product) == 0) 352264293Syongari found = 1; 353264293Syongari } 354264293Syongari if (m != NULL) 355264293Syongari freeenv(m); 356264293Syongari if (p != NULL) 357264293Syongari freeenv(p); 358264293Syongari 359264293Syongari return (found); 360264293Syongari} 361264293Syongari 362264293Syongari 363264293Syongaristatic int 364159967Sobriennfe_attach(device_t dev) 365159952Sobrien{ 366159967Sobrien struct nfe_softc *sc; 367268131Smarcel if_t ifp; 368170589Syongari bus_addr_t dma_addr_max; 369264293Syongari int error = 0, i, msic, phyloc, reg, rid; 370159952Sobrien 371159967Sobrien sc = device_get_softc(dev); 372159967Sobrien sc->nfe_dev = dev; 373159952Sobrien 374159967Sobrien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 375170589Syongari MTX_DEF); 376159967Sobrien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 377159967Sobrien 378163503Sobrien pci_enable_busmaster(dev); 379159967Sobrien 380170589Syongari rid = PCIR_BAR(0); 381170589Syongari sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 382170589Syongari RF_ACTIVE); 383170589Syongari if (sc->nfe_res[0] == NULL) { 384170589Syongari device_printf(dev, "couldn't map memory resources\n"); 385170589Syongari mtx_destroy(&sc->nfe_mtx); 386170589Syongari return (ENXIO); 387170589Syongari } 388159967Sobrien 389219902Sjhb if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { 390170589Syongari uint16_t v, width; 391170589Syongari 392170589Syongari v = pci_read_config(dev, reg + 0x08, 2); 393170589Syongari /* Change max. read request size to 4096. */ 394170589Syongari v &= ~(7 << 12); 395170589Syongari v |= (5 << 12); 396170589Syongari pci_write_config(dev, reg + 0x08, v, 2); 397170589Syongari 398170589Syongari v = pci_read_config(dev, reg + 0x0c, 2); 399170589Syongari /* link capability */ 400170589Syongari v = (v >> 4) & 0x0f; 401170589Syongari width = pci_read_config(dev, reg + 0x12, 2); 402170589Syongari /* negotiated link width */ 403170589Syongari width = (width >> 4) & 0x3f; 404170589Syongari if (v != width) 405170589Syongari device_printf(sc->nfe_dev, 406170589Syongari "warning, negotiated width of link(x%d) != " 407170589Syongari "max. width of link(x%d)\n", width, v); 408159952Sobrien } 409159952Sobrien 410215327Syongari if (nfe_can_use_msix(sc) == 0) { 411215327Syongari device_printf(sc->nfe_dev, 412215327Syongari "MSI/MSI-X capability black-listed, will use INTx\n"); 413215327Syongari msix_disable = 1; 414215327Syongari msi_disable = 1; 415215327Syongari } 416215327Syongari 417159967Sobrien /* Allocate interrupt */ 418170589Syongari if (msix_disable == 0 || msi_disable == 0) { 419170589Syongari if (msix_disable == 0 && 420170589Syongari (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES) 421170589Syongari nfe_alloc_msix(sc, msic); 422170589Syongari if (msi_disable == 0 && sc->nfe_msix == 0 && 423170589Syongari (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES && 424170589Syongari pci_alloc_msi(dev, &msic) == 0) { 425170589Syongari if (msic == NFE_MSI_MESSAGES) { 426170589Syongari if (bootverbose) 427170589Syongari device_printf(dev, 428170589Syongari "Using %d MSI messages\n", msic); 429170589Syongari sc->nfe_msi = 1; 430170589Syongari } else 431170589Syongari pci_release_msi(dev); 432170589Syongari } 433170589Syongari } 434159967Sobrien 435170589Syongari if (sc->nfe_msix == 0 && sc->nfe_msi == 0) { 436170589Syongari rid = 0; 437170589Syongari sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 438170589Syongari RF_SHAREABLE | RF_ACTIVE); 439170589Syongari if (sc->nfe_irq[0] == NULL) { 440170589Syongari device_printf(dev, "couldn't allocate IRQ resources\n"); 441170589Syongari error = ENXIO; 442170589Syongari goto fail; 443170589Syongari } 444170589Syongari } else { 445170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 446170589Syongari sc->nfe_irq[i] = bus_alloc_resource_any(dev, 447170589Syongari SYS_RES_IRQ, &rid, RF_ACTIVE); 448170589Syongari if (sc->nfe_irq[i] == NULL) { 449170589Syongari device_printf(dev, 450170589Syongari "couldn't allocate IRQ resources for " 451170589Syongari "message %d\n", rid); 452170589Syongari error = ENXIO; 453170589Syongari goto fail; 454170589Syongari } 455170589Syongari } 456170589Syongari /* Map interrupts to vector 0. */ 457170589Syongari if (sc->nfe_msix != 0) { 458170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP0, 0); 459170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP1, 0); 460170589Syongari } else if (sc->nfe_msi != 0) { 461170589Syongari NFE_WRITE(sc, NFE_MSI_MAP0, 0); 462170589Syongari NFE_WRITE(sc, NFE_MSI_MAP1, 0); 463170589Syongari } 464159952Sobrien } 465159952Sobrien 466170589Syongari /* Set IRQ status/mask register. */ 467170589Syongari sc->nfe_irq_status = NFE_IRQ_STATUS; 468170589Syongari sc->nfe_irq_mask = NFE_IRQ_MASK; 469170589Syongari sc->nfe_intrs = NFE_IRQ_WANTED; 470170589Syongari sc->nfe_nointrs = 0; 471170589Syongari if (sc->nfe_msix != 0) { 472170589Syongari sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS; 473170589Syongari sc->nfe_nointrs = NFE_IRQ_WANTED; 474170589Syongari } else if (sc->nfe_msi != 0) { 475170589Syongari sc->nfe_irq_mask = NFE_MSI_IRQ_MASK; 476170589Syongari sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED; 477170589Syongari } 478159952Sobrien 479170589Syongari sc->nfe_devid = pci_get_device(dev); 480170589Syongari sc->nfe_revid = pci_get_revid(dev); 481159967Sobrien sc->nfe_flags = 0; 482159952Sobrien 483170589Syongari switch (sc->nfe_devid) { 484159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 485159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 486159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 487159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 488159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 489159952Sobrien break; 490159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 491159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 492183561Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1; 493159952Sobrien break; 494159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 495159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 496159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 497159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 498183561Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 499183561Syongari NFE_MIB_V1; 500159952Sobrien break; 501159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 502159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 503163503Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 504183561Syongari NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 505159952Sobrien break; 506170589Syongari 507162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 508162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 509162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 510162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 511170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 512170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 513170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 514170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 515178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN1: 516178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN2: 517178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN3: 518178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN4: 519170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | 520183561Syongari NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 521162212Sobrien break; 522183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN1: 523183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN2: 524183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN3: 525183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN4: 526183509Syongari /* XXX flow control */ 527183509Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT | 528183561Syongari NFE_CORRECT_MACADDR | NFE_MIB_V3; 529183509Syongari break; 530183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN1: 531183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN2: 532183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN3: 533183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN4: 534183509Syongari /* XXX flow control */ 535183509Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 536183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3; 537183509Syongari break; 538162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 539162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 540162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 541162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 542170589Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | 543183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | 544183561Syongari NFE_MIB_V2; 545163503Sobrien break; 546159952Sobrien } 547159952Sobrien 548170589Syongari nfe_power(sc); 549170589Syongari /* Check for reversed ethernet address */ 550170589Syongari if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0) 551170589Syongari sc->nfe_flags |= NFE_CORRECT_MACADDR; 552170589Syongari nfe_get_macaddr(sc, sc->eaddr); 553159952Sobrien /* 554159967Sobrien * Allocate the parent bus DMA tag appropriate for PCI. 555159967Sobrien */ 556170589Syongari dma_addr_max = BUS_SPACE_MAXADDR_32BIT; 557170589Syongari if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0) 558170589Syongari dma_addr_max = NFE_DMA_MAXADDR; 559170589Syongari error = bus_dma_tag_create( 560170589Syongari bus_get_dma_tag(sc->nfe_dev), /* parent */ 561163503Sobrien 1, 0, /* alignment, boundary */ 562170589Syongari dma_addr_max, /* lowaddr */ 563163503Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 564163503Sobrien NULL, NULL, /* filter, filterarg */ 565170589Syongari BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 566163503Sobrien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 567170589Syongari 0, /* flags */ 568163503Sobrien NULL, NULL, /* lockfunc, lockarg */ 569163503Sobrien &sc->nfe_parent_tag); 570159967Sobrien if (error) 571159967Sobrien goto fail; 572159967Sobrien 573268131Smarcel ifp = sc->nfe_ifp = if_gethandle(IFT_ETHER); 574164650Sobrien if (ifp == NULL) { 575268131Smarcel device_printf(dev, "can not if_gethandle()\n"); 576164650Sobrien error = ENOSPC; 577164650Sobrien goto fail; 578164650Sobrien } 579164650Sobrien 580159967Sobrien /* 581159952Sobrien * Allocate Tx and Rx rings. 582159952Sobrien */ 583170589Syongari if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0) 584159967Sobrien goto fail; 585159952Sobrien 586170589Syongari if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0) 587159967Sobrien goto fail; 588170589Syongari 589171559Syongari nfe_alloc_jrx_ring(sc, &sc->jrxq); 590183561Syongari /* Create sysctl node. */ 591183561Syongari nfe_sysctl_node(sc); 592170589Syongari 593268131Smarcel if_setsoftc(ifp, sc); 594270876Sglebius if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 595268131Smarcel if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 596268131Smarcel if_setioctlfn(ifp, nfe_ioctl); 597268131Smarcel if_setstartfn(ifp, nfe_start); 598268131Smarcel if_sethwassist(ifp, 0); 599268131Smarcel if_setcapabilities(ifp, 0); 600268131Smarcel if_setinitfn(ifp, nfe_init); 601268131Smarcel if_setsendqlen(ifp, NFE_TX_RING_COUNT - 1); 602268131Smarcel if_setsendqready(ifp); 603159952Sobrien 604268131Smarcel 605170589Syongari if (sc->nfe_flags & NFE_HW_CSUM) { 606268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_HWCSUM | IFCAP_TSO4, 0); 607268131Smarcel if_sethwassistbits(ifp, NFE_CSUM_FEATURES | CSUM_TSO, 0); 608170589Syongari } 609268131Smarcel if_setcapenable(ifp, if_getcapabilities(ifp)); 610164650Sobrien 611268131Smarcel sc->nfe_framesize = if_getmtu(ifp) + NFE_RX_HEADERS; 612170589Syongari /* VLAN capability setup. */ 613268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); 614170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 615268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0); 616268131Smarcel if ((if_getcapabilities(ifp) & IFCAP_HWCSUM) != 0) 617268131Smarcel if_setcapabilitiesbit(ifp, 618268131Smarcel (IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO), 0); 619159952Sobrien } 620215132Syongari 621219902Sjhb if (pci_find_cap(dev, PCIY_PMG, ®) == 0) 622268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_WOL_MAGIC, 0); 623268131Smarcel if_setcapenable(ifp, if_getcapabilities(ifp)); 624159952Sobrien 625170589Syongari /* 626170589Syongari * Tell the upper layer(s) we support long frames. 627270876Sglebius * Must appear after the call to ether_ifattach() because 628270876Sglebius * ether_ifattach() sets ifi_hdrlen to the default value. 629170589Syongari */ 630268131Smarcel if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); 631170589Syongari 632159967Sobrien#ifdef DEVICE_POLLING 633268131Smarcel if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0); 634159967Sobrien#endif 635159952Sobrien 636159967Sobrien /* Do MII setup */ 637264293Syongari phyloc = MII_PHY_ANY; 638264293Syongari if (sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN1 || 639264293Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN2 || 640264293Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN3 || 641264293Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN4) { 642264293Syongari if (nfe_detect_msik9(sc) != 0) 643264293Syongari phyloc = 0; 644264293Syongari } 645268131Smarcel error = mii_attach(dev, &sc->nfe_miibus, ifp, 646268131Smarcel (ifm_change_cb_t)nfe_ifmedia_upd, (ifm_stat_cb_t)nfe_ifmedia_sts, 647268131Smarcel BMSR_DEFCAPMASK, phyloc, MII_OFFSET_ANY, MIIF_DOPAUSE); 648213894Smarius if (error != 0) { 649213894Smarius device_printf(dev, "attaching PHYs failed\n"); 650159967Sobrien goto fail; 651159967Sobrien } 652270876Sglebius ether_ifattach(ifp, sc->eaddr); 653159952Sobrien 654170589Syongari TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc); 655170589Syongari sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK, 656170589Syongari taskqueue_thread_enqueue, &sc->nfe_tq); 657170589Syongari taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq", 658170589Syongari device_get_nameunit(sc->nfe_dev)); 659170589Syongari error = 0; 660170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 661170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[0], 662170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 663170589Syongari &sc->nfe_intrhand[0]); 664170589Syongari } else { 665170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 666170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[i], 667170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 668170589Syongari &sc->nfe_intrhand[i]); 669170589Syongari if (error != 0) 670170589Syongari break; 671170589Syongari } 672170589Syongari } 673159967Sobrien if (error) { 674170589Syongari device_printf(dev, "couldn't set up irq\n"); 675170589Syongari taskqueue_free(sc->nfe_tq); 676170589Syongari sc->nfe_tq = NULL; 677270876Sglebius ether_ifdetach(ifp); 678159967Sobrien goto fail; 679159967Sobrien } 680159967Sobrien 681159967Sobrienfail: 682159967Sobrien if (error) 683159967Sobrien nfe_detach(dev); 684159967Sobrien 685159967Sobrien return (error); 686159952Sobrien} 687159952Sobrien 688159967Sobrien 689159967Sobrienstatic int 690159967Sobriennfe_detach(device_t dev) 691159952Sobrien{ 692163503Sobrien struct nfe_softc *sc; 693268131Smarcel if_t ifp; 694170589Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 695170589Syongari int i, rid; 696159952Sobrien 697159967Sobrien sc = device_get_softc(dev); 698159967Sobrien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 699159967Sobrien ifp = sc->nfe_ifp; 700159967Sobrien 701159967Sobrien#ifdef DEVICE_POLLING 702268131Smarcel if (ifp != NULL && if_getcapenable(ifp) & IFCAP_POLLING) 703159967Sobrien ether_poll_deregister(ifp); 704159967Sobrien#endif 705159967Sobrien if (device_is_attached(dev)) { 706164649Sobrien NFE_LOCK(sc); 707170589Syongari nfe_stop(ifp); 708268131Smarcel if_setflagbits(ifp, 0, IFF_UP); 709164649Sobrien NFE_UNLOCK(sc); 710159967Sobrien callout_drain(&sc->nfe_stat_ch); 711270876Sglebius ether_ifdetach(ifp); 712159967Sobrien } 713159967Sobrien 714170589Syongari if (ifp) { 715170589Syongari /* restore ethernet address */ 716170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 717170589Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) { 718170589Syongari eaddr[i] = sc->eaddr[5 - i]; 719170589Syongari } 720170589Syongari } else 721170589Syongari bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN); 722170589Syongari nfe_set_macaddr(sc, eaddr); 723270876Sglebius if_free(ifp); 724170589Syongari } 725159967Sobrien if (sc->nfe_miibus) 726159967Sobrien device_delete_child(dev, sc->nfe_miibus); 727159967Sobrien bus_generic_detach(dev); 728170589Syongari if (sc->nfe_tq != NULL) { 729170589Syongari taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task); 730170589Syongari taskqueue_free(sc->nfe_tq); 731170589Syongari sc->nfe_tq = NULL; 732170589Syongari } 733159967Sobrien 734170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 735170589Syongari if (sc->nfe_intrhand[i] != NULL) { 736170589Syongari bus_teardown_intr(dev, sc->nfe_irq[i], 737170589Syongari sc->nfe_intrhand[i]); 738170589Syongari sc->nfe_intrhand[i] = NULL; 739170589Syongari } 740170589Syongari } 741159967Sobrien 742170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 743170589Syongari if (sc->nfe_irq[0] != NULL) 744170589Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, 745170589Syongari sc->nfe_irq[0]); 746170589Syongari } else { 747170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 748170589Syongari if (sc->nfe_irq[i] != NULL) { 749170589Syongari bus_release_resource(dev, SYS_RES_IRQ, rid, 750170589Syongari sc->nfe_irq[i]); 751170589Syongari sc->nfe_irq[i] = NULL; 752170589Syongari } 753170589Syongari } 754170589Syongari pci_release_msi(dev); 755170589Syongari } 756170589Syongari if (sc->nfe_msix_pba_res != NULL) { 757170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3), 758170589Syongari sc->nfe_msix_pba_res); 759170589Syongari sc->nfe_msix_pba_res = NULL; 760170589Syongari } 761170589Syongari if (sc->nfe_msix_res != NULL) { 762170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 763170589Syongari sc->nfe_msix_res); 764170589Syongari sc->nfe_msix_res = NULL; 765170589Syongari } 766170589Syongari if (sc->nfe_res[0] != NULL) { 767170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 768170589Syongari sc->nfe_res[0]); 769170589Syongari sc->nfe_res[0] = NULL; 770170589Syongari } 771170589Syongari 772159967Sobrien nfe_free_tx_ring(sc, &sc->txq); 773159967Sobrien nfe_free_rx_ring(sc, &sc->rxq); 774170589Syongari nfe_free_jrx_ring(sc, &sc->jrxq); 775159967Sobrien 776170589Syongari if (sc->nfe_parent_tag) { 777159967Sobrien bus_dma_tag_destroy(sc->nfe_parent_tag); 778170589Syongari sc->nfe_parent_tag = NULL; 779170589Syongari } 780159967Sobrien 781159967Sobrien mtx_destroy(&sc->nfe_mtx); 782159967Sobrien 783159967Sobrien return (0); 784159952Sobrien} 785159952Sobrien 786159967Sobrien 787170589Syongaristatic int 788170589Syongarinfe_suspend(device_t dev) 789170589Syongari{ 790170589Syongari struct nfe_softc *sc; 791170589Syongari 792170589Syongari sc = device_get_softc(dev); 793170589Syongari 794170589Syongari NFE_LOCK(sc); 795170589Syongari nfe_stop(sc->nfe_ifp); 796215132Syongari nfe_set_wol(sc); 797170589Syongari sc->nfe_suspended = 1; 798170589Syongari NFE_UNLOCK(sc); 799170589Syongari 800170589Syongari return (0); 801170589Syongari} 802170589Syongari 803170589Syongari 804170589Syongaristatic int 805170589Syongarinfe_resume(device_t dev) 806170589Syongari{ 807170589Syongari struct nfe_softc *sc; 808268131Smarcel if_t ifp; 809170589Syongari 810170589Syongari sc = device_get_softc(dev); 811170589Syongari 812170589Syongari NFE_LOCK(sc); 813215132Syongari nfe_power(sc); 814170589Syongari ifp = sc->nfe_ifp; 815268131Smarcel if (if_getflags(ifp) & IFF_UP) 816170589Syongari nfe_init_locked(sc); 817170589Syongari sc->nfe_suspended = 0; 818170589Syongari NFE_UNLOCK(sc); 819170589Syongari 820170589Syongari return (0); 821170589Syongari} 822170589Syongari 823170589Syongari 824215327Syongaristatic int 825215327Syongarinfe_can_use_msix(struct nfe_softc *sc) 826215327Syongari{ 827215327Syongari static struct msix_blacklist { 828215327Syongari char *maker; 829215327Syongari char *product; 830215327Syongari } msix_blacklists[] = { 831215327Syongari { "ASUSTeK Computer INC.", "P5N32-SLI PREMIUM" } 832215327Syongari }; 833215327Syongari 834215327Syongari struct msix_blacklist *mblp; 835215327Syongari char *maker, *product; 836215350Syongari int count, n, use_msix; 837215327Syongari 838215327Syongari /* 839215327Syongari * Search base board manufacturer and product name table 840215327Syongari * to see this system has a known MSI/MSI-X issue. 841215327Syongari */ 842273174Sdavide maker = kern_getenv("smbios.planar.maker"); 843273174Sdavide product = kern_getenv("smbios.planar.product"); 844215350Syongari use_msix = 1; 845215327Syongari if (maker != NULL && product != NULL) { 846215327Syongari count = sizeof(msix_blacklists) / sizeof(msix_blacklists[0]); 847215327Syongari mblp = msix_blacklists; 848215327Syongari for (n = 0; n < count; n++) { 849215327Syongari if (strcmp(maker, mblp->maker) == 0 && 850215350Syongari strcmp(product, mblp->product) == 0) { 851215350Syongari use_msix = 0; 852215350Syongari break; 853215350Syongari } 854215327Syongari mblp++; 855215327Syongari } 856215327Syongari } 857215350Syongari if (maker != NULL) 858215350Syongari freeenv(maker); 859215350Syongari if (product != NULL) 860215350Syongari freeenv(product); 861215327Syongari 862215350Syongari return (use_msix); 863215327Syongari} 864215327Syongari 865215327Syongari 866170589Syongari/* Take PHY/NIC out of powerdown, from Linux */ 867159967Sobrienstatic void 868170589Syongarinfe_power(struct nfe_softc *sc) 869170589Syongari{ 870170589Syongari uint32_t pwr; 871170589Syongari 872170589Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) == 0) 873170589Syongari return; 874170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2); 875170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC); 876170589Syongari DELAY(100); 877170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, 0); 878170589Syongari DELAY(100); 879170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2); 880170589Syongari pwr = NFE_READ(sc, NFE_PWR2_CTL); 881170589Syongari pwr &= ~NFE_PWR2_WAKEUP_MASK; 882170589Syongari if (sc->nfe_revid >= 0xa3 && 883170589Syongari (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 || 884170589Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2)) 885170589Syongari pwr |= NFE_PWR2_REVA3; 886170589Syongari NFE_WRITE(sc, NFE_PWR2_CTL, pwr); 887170589Syongari} 888170589Syongari 889170589Syongari 890170589Syongaristatic void 891159967Sobriennfe_miibus_statchg(device_t dev) 892159952Sobrien{ 893159967Sobrien struct nfe_softc *sc; 894159967Sobrien struct mii_data *mii; 895268131Smarcel if_t ifp; 896215132Syongari uint32_t rxctl, txctl; 897159952Sobrien 898215132Syongari sc = device_get_softc(dev); 899170589Syongari 900159967Sobrien mii = device_get_softc(sc->nfe_miibus); 901170589Syongari ifp = sc->nfe_ifp; 902159967Sobrien 903215132Syongari sc->nfe_link = 0; 904215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 905215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 906215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 907215132Syongari case IFM_10_T: 908215132Syongari case IFM_100_TX: 909215132Syongari case IFM_1000_T: 910170589Syongari sc->nfe_link = 1; 911215132Syongari break; 912215132Syongari default: 913215132Syongari break; 914215132Syongari } 915215132Syongari } 916170589Syongari 917215132Syongari nfe_mac_config(sc, mii); 918215132Syongari txctl = NFE_READ(sc, NFE_TX_CTL); 919215132Syongari rxctl = NFE_READ(sc, NFE_RX_CTL); 920268131Smarcel if (sc->nfe_link != 0 && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 921215132Syongari txctl |= NFE_TX_START; 922215132Syongari rxctl |= NFE_RX_START; 923215132Syongari } else { 924215132Syongari txctl &= ~NFE_TX_START; 925215132Syongari rxctl &= ~NFE_RX_START; 926215132Syongari } 927215132Syongari NFE_WRITE(sc, NFE_TX_CTL, txctl); 928215132Syongari NFE_WRITE(sc, NFE_RX_CTL, rxctl); 929215132Syongari} 930215132Syongari 931215132Syongari 932215132Syongaristatic void 933215132Syongarinfe_mac_config(struct nfe_softc *sc, struct mii_data *mii) 934215132Syongari{ 935215132Syongari uint32_t link, misc, phy, seed; 936215132Syongari uint32_t val; 937215132Syongari 938215132Syongari NFE_LOCK_ASSERT(sc); 939215132Syongari 940159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 941159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 942159952Sobrien 943159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 944159952Sobrien seed &= ~NFE_SEED_MASK; 945159952Sobrien 946215132Syongari misc = NFE_MISC1_MAGIC; 947215132Syongari link = NFE_MEDIA_SET; 948215132Syongari 949215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) == 0) { 950159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 951159952Sobrien misc |= NFE_MISC1_HDX; 952159952Sobrien } 953159952Sobrien 954159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 955159952Sobrien case IFM_1000_T: /* full-duplex only */ 956159952Sobrien link |= NFE_MEDIA_1000T; 957159952Sobrien seed |= NFE_SEED_1000T; 958159952Sobrien phy |= NFE_PHY_1000T; 959159952Sobrien break; 960159952Sobrien case IFM_100_TX: 961159952Sobrien link |= NFE_MEDIA_100TX; 962159952Sobrien seed |= NFE_SEED_100TX; 963159952Sobrien phy |= NFE_PHY_100TX; 964159952Sobrien break; 965159952Sobrien case IFM_10_T: 966159952Sobrien link |= NFE_MEDIA_10T; 967159952Sobrien seed |= NFE_SEED_10T; 968159952Sobrien break; 969159952Sobrien } 970159952Sobrien 971170589Syongari if ((phy & 0x10000000) != 0) { 972170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 973170589Syongari val = NFE_R1_MAGIC_1000; 974170589Syongari else 975170589Syongari val = NFE_R1_MAGIC_10_100; 976170589Syongari } else 977170589Syongari val = NFE_R1_MAGIC_DEFAULT; 978170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, val); 979170589Syongari 980159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 981159952Sobrien 982159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 983159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 984159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 985170589Syongari 986215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 987170589Syongari /* It seems all hardwares supports Rx pause frames. */ 988170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 989215297Smarius if ((IFM_OPTIONS(mii->mii_media_active) & 990215297Smarius IFM_ETH_RXPAUSE) != 0) 991170589Syongari val |= NFE_PFF_RX_PAUSE; 992170589Syongari else 993170589Syongari val &= ~NFE_PFF_RX_PAUSE; 994170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 995170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 996170589Syongari val = NFE_READ(sc, NFE_MISC1); 997215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & 998215297Smarius IFM_ETH_TXPAUSE) != 0) { 999170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1000170589Syongari NFE_TX_PAUSE_FRAME_ENABLE); 1001170589Syongari val |= NFE_MISC1_TX_PAUSE; 1002170589Syongari } else { 1003170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 1004170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1005170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 1006170589Syongari } 1007170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 1008170589Syongari } 1009170589Syongari } else { 1010170589Syongari /* disable rx/tx pause frames */ 1011170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 1012170589Syongari val &= ~NFE_PFF_RX_PAUSE; 1013170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 1014170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 1015170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1016170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 1017170589Syongari val = NFE_READ(sc, NFE_MISC1); 1018170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 1019170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 1020170589Syongari } 1021170589Syongari } 1022159952Sobrien} 1023159952Sobrien 1024163503Sobrien 1025159967Sobrienstatic int 1026159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg) 1027159952Sobrien{ 1028159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 1029170589Syongari uint32_t val; 1030159952Sobrien int ntries; 1031159952Sobrien 1032159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1033159952Sobrien 1034159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1035159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1036159952Sobrien DELAY(100); 1037159952Sobrien } 1038159952Sobrien 1039159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 1040159952Sobrien 1041170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1042159952Sobrien DELAY(100); 1043159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1044159952Sobrien break; 1045159952Sobrien } 1046170589Syongari if (ntries == NFE_TIMEOUT) { 1047170589Syongari DPRINTFN(sc, 2, "timeout waiting for PHY\n"); 1048159952Sobrien return 0; 1049159952Sobrien } 1050159952Sobrien 1051159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 1052170589Syongari DPRINTFN(sc, 2, "could not read PHY\n"); 1053159952Sobrien return 0; 1054159952Sobrien } 1055159952Sobrien 1056159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 1057159952Sobrien if (val != 0xffffffff && val != 0) 1058159952Sobrien sc->mii_phyaddr = phy; 1059159952Sobrien 1060170589Syongari DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 1061159952Sobrien 1062170589Syongari return (val); 1063159952Sobrien} 1064159952Sobrien 1065163503Sobrien 1066159967Sobrienstatic int 1067159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val) 1068159952Sobrien{ 1069159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 1070170589Syongari uint32_t ctl; 1071163503Sobrien int ntries; 1072159952Sobrien 1073159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1074159952Sobrien 1075159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1076159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1077159952Sobrien DELAY(100); 1078159952Sobrien } 1079159952Sobrien 1080159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 1081159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 1082159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 1083159952Sobrien 1084170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1085159952Sobrien DELAY(100); 1086159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1087159952Sobrien break; 1088159952Sobrien } 1089159952Sobrien#ifdef NFE_DEBUG 1090170589Syongari if (nfedebug >= 2 && ntries == NFE_TIMEOUT) 1091170589Syongari device_printf(sc->nfe_dev, "could not write to PHY\n"); 1092159952Sobrien#endif 1093170589Syongari return (0); 1094159952Sobrien} 1095159952Sobrien 1096170589Syongaristruct nfe_dmamap_arg { 1097170589Syongari bus_addr_t nfe_busaddr; 1098170589Syongari}; 1099170589Syongari 1100159967Sobrienstatic int 1101159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1102159952Sobrien{ 1103170589Syongari struct nfe_dmamap_arg ctx; 1104159967Sobrien struct nfe_rx_data *data; 1105170589Syongari void *desc; 1106159967Sobrien int i, error, descsize; 1107159967Sobrien 1108159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1109170589Syongari desc = ring->desc64; 1110159967Sobrien descsize = sizeof (struct nfe_desc64); 1111159967Sobrien } else { 1112170589Syongari desc = ring->desc32; 1113159967Sobrien descsize = sizeof (struct nfe_desc32); 1114159967Sobrien } 1115159967Sobrien 1116159967Sobrien ring->cur = ring->next = 0; 1117159967Sobrien 1118163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1119170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1120170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1121170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1122170589Syongari NULL, NULL, /* filter, filterarg */ 1123170589Syongari NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1124170589Syongari NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 1125170589Syongari 0, /* flags */ 1126170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1127170589Syongari &ring->rx_desc_tag); 1128159967Sobrien if (error != 0) { 1129170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1130159967Sobrien goto fail; 1131159967Sobrien } 1132159967Sobrien 1133159967Sobrien /* allocate memory to desc */ 1134170589Syongari error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK | 1135170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map); 1136159967Sobrien if (error != 0) { 1137170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1138159967Sobrien goto fail; 1139159967Sobrien } 1140170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1141170589Syongari ring->desc64 = desc; 1142170589Syongari else 1143170589Syongari ring->desc32 = desc; 1144159967Sobrien 1145159967Sobrien /* map desc to device visible address space */ 1146170589Syongari ctx.nfe_busaddr = 0; 1147170589Syongari error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc, 1148170589Syongari NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1149159967Sobrien if (error != 0) { 1150170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1151159967Sobrien goto fail; 1152159967Sobrien } 1153170589Syongari ring->physaddr = ctx.nfe_busaddr; 1154159967Sobrien 1155170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1156170589Syongari 1, 0, /* alignment, boundary */ 1157170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1158170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1159170589Syongari NULL, NULL, /* filter, filterarg */ 1160170589Syongari MCLBYTES, 1, /* maxsize, nsegments */ 1161170589Syongari MCLBYTES, /* maxsegsize */ 1162170589Syongari 0, /* flags */ 1163170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1164170589Syongari &ring->rx_data_tag); 1165170589Syongari if (error != 0) { 1166170589Syongari device_printf(sc->nfe_dev, "could not create Rx DMA tag\n"); 1167170589Syongari goto fail; 1168170589Syongari } 1169159967Sobrien 1170170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map); 1171170589Syongari if (error != 0) { 1172170589Syongari device_printf(sc->nfe_dev, 1173170589Syongari "could not create Rx DMA spare map\n"); 1174170589Syongari goto fail; 1175170589Syongari } 1176170589Syongari 1177159967Sobrien /* 1178159967Sobrien * Pre-allocate Rx buffers and populate Rx ring. 1179159967Sobrien */ 1180159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1181159967Sobrien data = &sc->rxq.data[i]; 1182170589Syongari data->rx_data_map = NULL; 1183170589Syongari data->m = NULL; 1184170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, 1185170589Syongari &data->rx_data_map); 1186164651Sobrien if (error != 0) { 1187170589Syongari device_printf(sc->nfe_dev, 1188170589Syongari "could not create Rx DMA map\n"); 1189164651Sobrien goto fail; 1190164651Sobrien } 1191170589Syongari } 1192159967Sobrien 1193170589Syongarifail: 1194170589Syongari return (error); 1195170589Syongari} 1196170589Syongari 1197170589Syongari 1198171559Syongaristatic void 1199170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1200170589Syongari{ 1201170589Syongari struct nfe_dmamap_arg ctx; 1202170589Syongari struct nfe_rx_data *data; 1203170589Syongari void *desc; 1204170589Syongari int i, error, descsize; 1205170589Syongari 1206170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1207171559Syongari return; 1208171559Syongari if (jumbo_disable != 0) { 1209171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support\n"); 1210171559Syongari sc->nfe_jumbo_disable = 1; 1211171559Syongari return; 1212171559Syongari } 1213170589Syongari 1214170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1215170589Syongari desc = ring->jdesc64; 1216170589Syongari descsize = sizeof (struct nfe_desc64); 1217170589Syongari } else { 1218170589Syongari desc = ring->jdesc32; 1219170589Syongari descsize = sizeof (struct nfe_desc32); 1220170589Syongari } 1221170589Syongari 1222170589Syongari ring->jcur = ring->jnext = 0; 1223170589Syongari 1224170589Syongari /* Create DMA tag for jumbo Rx ring. */ 1225170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1226170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1227170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1228170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1229170589Syongari NULL, NULL, /* filter, filterarg */ 1230170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsize */ 1231170589Syongari 1, /* nsegments */ 1232170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsegsize */ 1233170589Syongari 0, /* flags */ 1234170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1235170589Syongari &ring->jrx_desc_tag); 1236170589Syongari if (error != 0) { 1237170589Syongari device_printf(sc->nfe_dev, 1238170589Syongari "could not create jumbo ring DMA tag\n"); 1239170589Syongari goto fail; 1240170589Syongari } 1241170589Syongari 1242170589Syongari /* Create DMA tag for jumbo Rx buffers. */ 1243170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1244192706Syongari 1, 0, /* alignment, boundary */ 1245170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1246170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1247170589Syongari NULL, NULL, /* filter, filterarg */ 1248176859Syongari MJUM9BYTES, /* maxsize */ 1249170589Syongari 1, /* nsegments */ 1250176859Syongari MJUM9BYTES, /* maxsegsize */ 1251170589Syongari 0, /* flags */ 1252170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1253170589Syongari &ring->jrx_data_tag); 1254170589Syongari if (error != 0) { 1255170589Syongari device_printf(sc->nfe_dev, 1256170589Syongari "could not create jumbo Rx buffer DMA tag\n"); 1257170589Syongari goto fail; 1258170589Syongari } 1259170589Syongari 1260170589Syongari /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ 1261170589Syongari error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK | 1262170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map); 1263170589Syongari if (error != 0) { 1264170589Syongari device_printf(sc->nfe_dev, 1265170589Syongari "could not allocate DMA'able memory for jumbo Rx ring\n"); 1266170589Syongari goto fail; 1267170589Syongari } 1268170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1269170589Syongari ring->jdesc64 = desc; 1270170589Syongari else 1271170589Syongari ring->jdesc32 = desc; 1272170589Syongari 1273170589Syongari ctx.nfe_busaddr = 0; 1274170589Syongari error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc, 1275170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1276170589Syongari if (error != 0) { 1277170589Syongari device_printf(sc->nfe_dev, 1278170589Syongari "could not load DMA'able memory for jumbo Rx ring\n"); 1279170589Syongari goto fail; 1280170589Syongari } 1281170589Syongari ring->jphysaddr = ctx.nfe_busaddr; 1282170589Syongari 1283170589Syongari /* Create DMA maps for jumbo Rx buffers. */ 1284170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map); 1285170589Syongari if (error != 0) { 1286170589Syongari device_printf(sc->nfe_dev, 1287170589Syongari "could not create jumbo Rx DMA spare map\n"); 1288170589Syongari goto fail; 1289170589Syongari } 1290170589Syongari 1291170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1292170589Syongari data = &sc->jrxq.jdata[i]; 1293170589Syongari data->rx_data_map = NULL; 1294170589Syongari data->m = NULL; 1295170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, 1296164651Sobrien &data->rx_data_map); 1297164651Sobrien if (error != 0) { 1298170589Syongari device_printf(sc->nfe_dev, 1299170589Syongari "could not create jumbo Rx DMA map\n"); 1300164651Sobrien goto fail; 1301164651Sobrien } 1302170589Syongari } 1303159967Sobrien 1304171559Syongari return; 1305159967Sobrien 1306170589Syongarifail: 1307171559Syongari /* 1308171559Syongari * Running without jumbo frame support is ok for most cases 1309171559Syongari * so don't fail on creating dma tag/map for jumbo frame. 1310171559Syongari */ 1311170589Syongari nfe_free_jrx_ring(sc, ring); 1312171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support due to " 1313171559Syongari "resource shortage\n"); 1314171559Syongari sc->nfe_jumbo_disable = 1; 1315170589Syongari} 1316159967Sobrien 1317159967Sobrien 1318170589Syongaristatic int 1319170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1320170589Syongari{ 1321170589Syongari void *desc; 1322170589Syongari size_t descsize; 1323170589Syongari int i; 1324159967Sobrien 1325170589Syongari ring->cur = ring->next = 0; 1326170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1327170589Syongari desc = ring->desc64; 1328170589Syongari descsize = sizeof (struct nfe_desc64); 1329170589Syongari } else { 1330170589Syongari desc = ring->desc32; 1331170589Syongari descsize = sizeof (struct nfe_desc32); 1332159967Sobrien } 1333170589Syongari bzero(desc, descsize * NFE_RX_RING_COUNT); 1334170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1335170589Syongari if (nfe_newbuf(sc, i) != 0) 1336170589Syongari return (ENOBUFS); 1337170589Syongari } 1338159967Sobrien 1339163503Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 1340170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1341159967Sobrien 1342170589Syongari return (0); 1343159967Sobrien} 1344159967Sobrien 1345163503Sobrien 1346170589Syongaristatic int 1347170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1348159967Sobrien{ 1349170589Syongari void *desc; 1350170589Syongari size_t descsize; 1351159967Sobrien int i; 1352159967Sobrien 1353170589Syongari ring->jcur = ring->jnext = 0; 1354170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1355170589Syongari desc = ring->jdesc64; 1356170589Syongari descsize = sizeof (struct nfe_desc64); 1357170589Syongari } else { 1358170589Syongari desc = ring->jdesc32; 1359170589Syongari descsize = sizeof (struct nfe_desc32); 1360159952Sobrien } 1361176859Syongari bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT); 1362170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1363170589Syongari if (nfe_jnewbuf(sc, i) != 0) 1364170589Syongari return (ENOBUFS); 1365170589Syongari } 1366159952Sobrien 1367170589Syongari bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map, 1368170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1369159952Sobrien 1370170589Syongari return (0); 1371159967Sobrien} 1372159967Sobrien 1373159967Sobrien 1374159967Sobrienstatic void 1375159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1376159967Sobrien{ 1377159967Sobrien struct nfe_rx_data *data; 1378159967Sobrien void *desc; 1379266270Sbrueffer int i; 1380159967Sobrien 1381266270Sbrueffer if (sc->nfe_flags & NFE_40BIT_ADDR) 1382159967Sobrien desc = ring->desc64; 1383266270Sbrueffer else 1384159967Sobrien desc = ring->desc32; 1385159952Sobrien 1386170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1387170589Syongari data = &ring->data[i]; 1388170589Syongari if (data->rx_data_map != NULL) { 1389170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1390170589Syongari data->rx_data_map); 1391170589Syongari data->rx_data_map = NULL; 1392170589Syongari } 1393170589Syongari if (data->m != NULL) { 1394170589Syongari m_freem(data->m); 1395170589Syongari data->m = NULL; 1396170589Syongari } 1397170589Syongari } 1398170589Syongari if (ring->rx_data_tag != NULL) { 1399170589Syongari if (ring->rx_spare_map != NULL) { 1400170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1401170589Syongari ring->rx_spare_map); 1402170589Syongari ring->rx_spare_map = NULL; 1403170589Syongari } 1404170589Syongari bus_dma_tag_destroy(ring->rx_data_tag); 1405170589Syongari ring->rx_data_tag = NULL; 1406170589Syongari } 1407170589Syongari 1408159967Sobrien if (desc != NULL) { 1409159967Sobrien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 1410159967Sobrien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 1411170589Syongari ring->desc64 = NULL; 1412170589Syongari ring->desc32 = NULL; 1413170589Syongari } 1414170589Syongari if (ring->rx_desc_tag != NULL) { 1415159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 1416170589Syongari ring->rx_desc_tag = NULL; 1417159967Sobrien } 1418170589Syongari} 1419159967Sobrien 1420164650Sobrien 1421170589Syongaristatic void 1422170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1423170589Syongari{ 1424170589Syongari struct nfe_rx_data *data; 1425170589Syongari void *desc; 1426170589Syongari int i, descsize; 1427170589Syongari 1428170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1429170589Syongari return; 1430170589Syongari 1431170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1432170589Syongari desc = ring->jdesc64; 1433170589Syongari descsize = sizeof (struct nfe_desc64); 1434170589Syongari } else { 1435170589Syongari desc = ring->jdesc32; 1436170589Syongari descsize = sizeof (struct nfe_desc32); 1437170589Syongari } 1438170589Syongari 1439170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1440170589Syongari data = &ring->jdata[i]; 1441164651Sobrien if (data->rx_data_map != NULL) { 1442170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1443164651Sobrien data->rx_data_map); 1444170589Syongari data->rx_data_map = NULL; 1445164651Sobrien } 1446170589Syongari if (data->m != NULL) { 1447164651Sobrien m_freem(data->m); 1448170589Syongari data->m = NULL; 1449170589Syongari } 1450164651Sobrien } 1451170589Syongari if (ring->jrx_data_tag != NULL) { 1452170589Syongari if (ring->jrx_spare_map != NULL) { 1453170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1454170589Syongari ring->jrx_spare_map); 1455170589Syongari ring->jrx_spare_map = NULL; 1456170589Syongari } 1457170589Syongari bus_dma_tag_destroy(ring->jrx_data_tag); 1458170589Syongari ring->jrx_data_tag = NULL; 1459170589Syongari } 1460170589Syongari 1461170589Syongari if (desc != NULL) { 1462170589Syongari bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1463170589Syongari bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1464170589Syongari ring->jdesc64 = NULL; 1465170589Syongari ring->jdesc32 = NULL; 1466170589Syongari } 1467176859Syongari 1468170589Syongari if (ring->jrx_desc_tag != NULL) { 1469170589Syongari bus_dma_tag_destroy(ring->jrx_desc_tag); 1470170589Syongari ring->jrx_desc_tag = NULL; 1471170589Syongari } 1472159952Sobrien} 1473159952Sobrien 1474163503Sobrien 1475159967Sobrienstatic int 1476159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1477159952Sobrien{ 1478170589Syongari struct nfe_dmamap_arg ctx; 1479159967Sobrien int i, error; 1480170589Syongari void *desc; 1481159967Sobrien int descsize; 1482159952Sobrien 1483159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1484170589Syongari desc = ring->desc64; 1485159967Sobrien descsize = sizeof (struct nfe_desc64); 1486159967Sobrien } else { 1487170589Syongari desc = ring->desc32; 1488159967Sobrien descsize = sizeof (struct nfe_desc32); 1489159967Sobrien } 1490159952Sobrien 1491159967Sobrien ring->queued = 0; 1492159967Sobrien ring->cur = ring->next = 0; 1493159967Sobrien 1494163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1495170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1496170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1497170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1498170589Syongari NULL, NULL, /* filter, filterarg */ 1499170589Syongari NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1500170589Syongari NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1501170589Syongari 0, /* flags */ 1502170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1503170589Syongari &ring->tx_desc_tag); 1504159967Sobrien if (error != 0) { 1505170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1506159967Sobrien goto fail; 1507159952Sobrien } 1508159952Sobrien 1509170589Syongari error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1510170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1511159967Sobrien if (error != 0) { 1512170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1513159967Sobrien goto fail; 1514159967Sobrien } 1515170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1516170589Syongari ring->desc64 = desc; 1517170589Syongari else 1518170589Syongari ring->desc32 = desc; 1519159967Sobrien 1520170589Syongari ctx.nfe_busaddr = 0; 1521170589Syongari error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1522170589Syongari NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1523159967Sobrien if (error != 0) { 1524170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1525159967Sobrien goto fail; 1526159967Sobrien } 1527170589Syongari ring->physaddr = ctx.nfe_busaddr; 1528159967Sobrien 1529163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1530170589Syongari 1, 0, 1531170589Syongari BUS_SPACE_MAXADDR, 1532170589Syongari BUS_SPACE_MAXADDR, 1533170589Syongari NULL, NULL, 1534170595Syongari NFE_TSO_MAXSIZE, 1535170589Syongari NFE_MAX_SCATTER, 1536170595Syongari NFE_TSO_MAXSGSIZE, 1537170589Syongari 0, 1538170589Syongari NULL, NULL, 1539170589Syongari &ring->tx_data_tag); 1540159967Sobrien if (error != 0) { 1541170589Syongari device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1542170589Syongari goto fail; 1543159967Sobrien } 1544159967Sobrien 1545159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1546163503Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, 1547163503Sobrien &ring->data[i].tx_data_map); 1548159967Sobrien if (error != 0) { 1549170589Syongari device_printf(sc->nfe_dev, 1550170589Syongari "could not create Tx DMA map\n"); 1551159967Sobrien goto fail; 1552159967Sobrien } 1553159967Sobrien } 1554159967Sobrien 1555170589Syongarifail: 1556170589Syongari return (error); 1557159967Sobrien} 1558159967Sobrien 1559159967Sobrien 1560159967Sobrienstatic void 1561170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1562159967Sobrien{ 1563170589Syongari void *desc; 1564170589Syongari size_t descsize; 1565159967Sobrien 1566170589Syongari sc->nfe_force_tx = 0; 1567170589Syongari ring->queued = 0; 1568170589Syongari ring->cur = ring->next = 0; 1569170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1570170589Syongari desc = ring->desc64; 1571170589Syongari descsize = sizeof (struct nfe_desc64); 1572170589Syongari } else { 1573170589Syongari desc = ring->desc32; 1574170589Syongari descsize = sizeof (struct nfe_desc32); 1575159967Sobrien } 1576170589Syongari bzero(desc, descsize * NFE_TX_RING_COUNT); 1577159967Sobrien 1578163503Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1579170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1580159967Sobrien} 1581159967Sobrien 1582163503Sobrien 1583159967Sobrienstatic void 1584159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1585159967Sobrien{ 1586159967Sobrien struct nfe_tx_data *data; 1587159967Sobrien void *desc; 1588159967Sobrien int i, descsize; 1589159967Sobrien 1590159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1591159967Sobrien desc = ring->desc64; 1592159967Sobrien descsize = sizeof (struct nfe_desc64); 1593159967Sobrien } else { 1594159967Sobrien desc = ring->desc32; 1595159967Sobrien descsize = sizeof (struct nfe_desc32); 1596159967Sobrien } 1597159967Sobrien 1598159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1599159967Sobrien data = &ring->data[i]; 1600159967Sobrien 1601159967Sobrien if (data->m != NULL) { 1602170589Syongari bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1603163503Sobrien BUS_DMASYNC_POSTWRITE); 1604170589Syongari bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1605159967Sobrien m_freem(data->m); 1606170589Syongari data->m = NULL; 1607159967Sobrien } 1608170589Syongari if (data->tx_data_map != NULL) { 1609170589Syongari bus_dmamap_destroy(ring->tx_data_tag, 1610170589Syongari data->tx_data_map); 1611170589Syongari data->tx_data_map = NULL; 1612170589Syongari } 1613159967Sobrien } 1614159967Sobrien 1615170589Syongari if (ring->tx_data_tag != NULL) { 1616170589Syongari bus_dma_tag_destroy(ring->tx_data_tag); 1617170589Syongari ring->tx_data_tag = NULL; 1618159967Sobrien } 1619159967Sobrien 1620170589Syongari if (desc != NULL) { 1621170589Syongari bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1622170589Syongari BUS_DMASYNC_POSTWRITE); 1623170589Syongari bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1624170589Syongari bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1625170589Syongari ring->desc64 = NULL; 1626170589Syongari ring->desc32 = NULL; 1627170589Syongari bus_dma_tag_destroy(ring->tx_desc_tag); 1628170589Syongari ring->tx_desc_tag = NULL; 1629170589Syongari } 1630159967Sobrien} 1631159967Sobrien 1632159967Sobrien#ifdef DEVICE_POLLING 1633272257Sglebiusstatic poll_handler_t nfe_poll; 1634159967Sobrien 1635163503Sobrien 1636193096Sattiliostatic int 1637268131Smarcelnfe_poll(if_t ifp, enum poll_cmd cmd, int count) 1638159967Sobrien{ 1639268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 1640170589Syongari uint32_t r; 1641193096Sattilio int rx_npkts = 0; 1642159967Sobrien 1643159967Sobrien NFE_LOCK(sc); 1644159967Sobrien 1645268131Smarcel if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) { 1646170589Syongari NFE_UNLOCK(sc); 1647193096Sattilio return (rx_npkts); 1648159967Sobrien } 1649159967Sobrien 1650171559Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1651193096Sattilio rx_npkts = nfe_jrxeof(sc, count, &rx_npkts); 1652171559Syongari else 1653193096Sattilio rx_npkts = nfe_rxeof(sc, count, &rx_npkts); 1654159967Sobrien nfe_txeof(sc); 1655268131Smarcel if (!if_sendq_empty(ifp)) 1656216925Sjhb nfe_start_locked(ifp); 1657159967Sobrien 1658159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1659170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1660170589Syongari NFE_UNLOCK(sc); 1661193096Sattilio return (rx_npkts); 1662163503Sobrien } 1663170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1664159967Sobrien 1665163503Sobrien if (r & NFE_IRQ_LINK) { 1666163503Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1667163503Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1668170589Syongari DPRINTF(sc, "link state changed\n"); 1669163503Sobrien } 1670159967Sobrien } 1671170589Syongari NFE_UNLOCK(sc); 1672193096Sattilio return (rx_npkts); 1673159967Sobrien} 1674159967Sobrien#endif /* DEVICE_POLLING */ 1675159967Sobrien 1676170589Syongaristatic void 1677170589Syongarinfe_set_intr(struct nfe_softc *sc) 1678170589Syongari{ 1679159967Sobrien 1680170589Syongari if (sc->nfe_msi != 0) 1681170589Syongari NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1682170589Syongari} 1683170589Syongari 1684170589Syongari 1685170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */ 1686170589Syongaristatic __inline void 1687170589Syongarinfe_enable_intr(struct nfe_softc *sc) 1688170589Syongari{ 1689170589Syongari 1690170589Syongari if (sc->nfe_msix != 0) { 1691170589Syongari /* XXX Should have a better way to enable interrupts! */ 1692170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1693170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1694170589Syongari } else 1695170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1696170589Syongari} 1697170589Syongari 1698170589Syongari 1699170589Syongaristatic __inline void 1700170589Syongarinfe_disable_intr(struct nfe_softc *sc) 1701170589Syongari{ 1702170589Syongari 1703170589Syongari if (sc->nfe_msix != 0) { 1704170589Syongari /* XXX Should have a better way to disable interrupts! */ 1705170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1706170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1707170589Syongari } else 1708170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1709170589Syongari} 1710170589Syongari 1711170589Syongari 1712159967Sobrienstatic int 1713268131Smarcelnfe_ioctl(if_t ifp, u_long cmd, caddr_t data) 1714159967Sobrien{ 1715170589Syongari struct nfe_softc *sc; 1716170589Syongari struct ifreq *ifr; 1717163503Sobrien struct mii_data *mii; 1718170589Syongari int error, init, mask; 1719159967Sobrien 1720268131Smarcel sc = if_getsoftc(ifp); 1721170589Syongari ifr = (struct ifreq *) data; 1722170589Syongari error = 0; 1723170589Syongari init = 0; 1724159952Sobrien switch (cmd) { 1725159952Sobrien case SIOCSIFMTU: 1726170589Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1727159952Sobrien error = EINVAL; 1728268131Smarcel else if (if_getmtu(ifp) != ifr->ifr_mtu) { 1729171559Syongari if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) || 1730171559Syongari (sc->nfe_jumbo_disable != 0)) && 1731170589Syongari ifr->ifr_mtu > ETHERMTU) 1732170589Syongari error = EINVAL; 1733170589Syongari else { 1734170589Syongari NFE_LOCK(sc); 1735268131Smarcel if_setmtu(ifp, ifr->ifr_mtu); 1736268131Smarcel if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 1737268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1738170589Syongari nfe_init_locked(sc); 1739217794Syongari } 1740170589Syongari NFE_UNLOCK(sc); 1741164650Sobrien } 1742164650Sobrien } 1743159952Sobrien break; 1744159952Sobrien case SIOCSIFFLAGS: 1745159967Sobrien NFE_LOCK(sc); 1746268131Smarcel if (if_getflags(ifp) & IFF_UP) { 1747159952Sobrien /* 1748159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1749159952Sobrien * don't do a full re-init of the chip, just update 1750159952Sobrien * the Rx filter. 1751159952Sobrien */ 1752268131Smarcel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) && 1753268131Smarcel ((if_getflags(ifp) ^ sc->nfe_if_flags) & 1754159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1755159952Sobrien nfe_setmulti(sc); 1756159967Sobrien else 1757159967Sobrien nfe_init_locked(sc); 1758159952Sobrien } else { 1759268131Smarcel if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1760170589Syongari nfe_stop(ifp); 1761159952Sobrien } 1762268131Smarcel sc->nfe_if_flags = if_getflags(ifp); 1763159967Sobrien NFE_UNLOCK(sc); 1764159967Sobrien error = 0; 1765159952Sobrien break; 1766159952Sobrien case SIOCADDMULTI: 1767159952Sobrien case SIOCDELMULTI: 1768268131Smarcel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 1769159967Sobrien NFE_LOCK(sc); 1770159967Sobrien nfe_setmulti(sc); 1771159967Sobrien NFE_UNLOCK(sc); 1772159952Sobrien error = 0; 1773159952Sobrien } 1774159952Sobrien break; 1775159952Sobrien case SIOCSIFMEDIA: 1776159952Sobrien case SIOCGIFMEDIA: 1777159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1778270876Sglebius error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1779159952Sobrien break; 1780159967Sobrien case SIOCSIFCAP: 1781268131Smarcel mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 1782159967Sobrien#ifdef DEVICE_POLLING 1783170589Syongari if ((mask & IFCAP_POLLING) != 0) { 1784170589Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1785272257Sglebius error = ether_poll_register(nfe_poll, ifp); 1786159967Sobrien if (error) 1787170589Syongari break; 1788159967Sobrien NFE_LOCK(sc); 1789170589Syongari nfe_disable_intr(sc); 1790268131Smarcel if_setcapenablebit(ifp, IFCAP_POLLING, 0); 1791159967Sobrien NFE_UNLOCK(sc); 1792159967Sobrien } else { 1793159967Sobrien error = ether_poll_deregister(ifp); 1794159967Sobrien /* Enable interrupt even in error case */ 1795159967Sobrien NFE_LOCK(sc); 1796170589Syongari nfe_enable_intr(sc); 1797268131Smarcel if_setcapenablebit(ifp, 0, IFCAP_POLLING); 1798159967Sobrien NFE_UNLOCK(sc); 1799159967Sobrien } 1800159967Sobrien } 1801163503Sobrien#endif /* DEVICE_POLLING */ 1802215132Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 1803268131Smarcel (if_getcapabilities(ifp) & IFCAP_WOL_MAGIC) != 0) 1804268131Smarcel if_togglecapenable(ifp, IFCAP_WOL_MAGIC); 1805215432Syongari if ((mask & IFCAP_TXCSUM) != 0 && 1806268131Smarcel (if_getcapabilities(ifp) & IFCAP_TXCSUM) != 0) { 1807268131Smarcel if_togglecapenable(ifp, IFCAP_TXCSUM); 1808268131Smarcel if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0) 1809268131Smarcel if_sethwassistbits(ifp, NFE_CSUM_FEATURES, 0); 1810159967Sobrien else 1811268131Smarcel if_sethwassistbits(ifp, 0, NFE_CSUM_FEATURES); 1812215432Syongari } 1813215432Syongari if ((mask & IFCAP_RXCSUM) != 0 && 1814268131Smarcel (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) { 1815268131Smarcel if_togglecapenable(ifp, IFCAP_RXCSUM); 1816170589Syongari init++; 1817159967Sobrien } 1818215432Syongari if ((mask & IFCAP_TSO4) != 0 && 1819268131Smarcel (if_getcapabilities(ifp) & IFCAP_TSO4) != 0) { 1820268131Smarcel if_togglecapenable(ifp, IFCAP_TSO4); 1821268131Smarcel if ((IFCAP_TSO4 & if_getcapenable(ifp)) != 0) 1822268131Smarcel if_sethwassistbits(ifp, CSUM_TSO, 0); 1823215432Syongari else 1824268131Smarcel if_sethwassistbits(ifp, 0, CSUM_TSO); 1825215432Syongari } 1826215432Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 1827268131Smarcel (if_getcapabilities(ifp) & IFCAP_VLAN_HWTSO) != 0) 1828268131Smarcel if_togglecapenable(ifp, IFCAP_VLAN_HWTSO); 1829215432Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 1830268131Smarcel (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING) != 0) { 1831268131Smarcel if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING); 1832268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) == 0) 1833268131Smarcel if_setcapenablebit(ifp, 0, IFCAP_VLAN_HWTSO); 1834170589Syongari init++; 1835170589Syongari } 1836170589Syongari /* 1837170589Syongari * XXX 1838170589Syongari * It seems that VLAN stripping requires Rx checksum offload. 1839170589Syongari * Unfortunately FreeBSD has no way to disable only Rx side 1840170589Syongari * VLAN stripping. So when we know Rx checksum offload is 1841170589Syongari * disabled turn entire hardware VLAN assist off. 1842170589Syongari */ 1843268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) == 0) { 1844268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) 1845215432Syongari init++; 1846268131Smarcel if_setcapenablebit(ifp, 0, 1847268131Smarcel (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO)); 1848170589Syongari } 1849268131Smarcel if (init > 0 && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 1850268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1851164656Sobrien nfe_init(sc); 1852170589Syongari } 1853268131Smarcel if_vlancap(ifp); 1854159967Sobrien break; 1855159952Sobrien default: 1856270876Sglebius error = ether_ioctl(ifp, cmd, data); 1857159967Sobrien break; 1858159952Sobrien } 1859159952Sobrien 1860170589Syongari return (error); 1861159952Sobrien} 1862159952Sobrien 1863159967Sobrien 1864170589Syongaristatic int 1865163503Sobriennfe_intr(void *arg) 1866159967Sobrien{ 1867170589Syongari struct nfe_softc *sc; 1868170589Syongari uint32_t status; 1869170589Syongari 1870170589Syongari sc = (struct nfe_softc *)arg; 1871170589Syongari 1872170589Syongari status = NFE_READ(sc, sc->nfe_irq_status); 1873170589Syongari if (status == 0 || status == 0xffffffff) 1874170589Syongari return (FILTER_STRAY); 1875170589Syongari nfe_disable_intr(sc); 1876296272Sjhb taskqueue_enqueue(sc->nfe_tq, &sc->nfe_int_task); 1877170589Syongari 1878170589Syongari return (FILTER_HANDLED); 1879170589Syongari} 1880170589Syongari 1881170589Syongari 1882170589Syongaristatic void 1883170589Syongarinfe_int_task(void *arg, int pending) 1884170589Syongari{ 1885159967Sobrien struct nfe_softc *sc = arg; 1886268131Smarcel if_t ifp = sc->nfe_ifp; 1887170589Syongari uint32_t r; 1888170589Syongari int domore; 1889159967Sobrien 1890163503Sobrien NFE_LOCK(sc); 1891159967Sobrien 1892170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1893170589Syongari nfe_enable_intr(sc); 1894170589Syongari NFE_UNLOCK(sc); 1895170589Syongari return; /* not for us */ 1896170589Syongari } 1897170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1898170589Syongari 1899170589Syongari DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1900170589Syongari 1901159967Sobrien#ifdef DEVICE_POLLING 1902268131Smarcel if (if_getcapenable(ifp) & IFCAP_POLLING) { 1903159967Sobrien NFE_UNLOCK(sc); 1904159967Sobrien return; 1905159967Sobrien } 1906159967Sobrien#endif 1907159967Sobrien 1908172169Syongari if (r & NFE_IRQ_LINK) { 1909172169Syongari NFE_READ(sc, NFE_PHY_STATUS); 1910172169Syongari NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1911172169Syongari DPRINTF(sc, "link state changed\n"); 1912172169Syongari } 1913172169Syongari 1914268131Smarcel if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) { 1915163503Sobrien NFE_UNLOCK(sc); 1916222542Syongari nfe_disable_intr(sc); 1917170589Syongari return; 1918159967Sobrien } 1919159967Sobrien 1920170589Syongari domore = 0; 1921170589Syongari /* check Rx ring */ 1922170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1923193096Sattilio domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL); 1924170589Syongari else 1925193096Sattilio domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL); 1926170589Syongari /* check Tx ring */ 1927170589Syongari nfe_txeof(sc); 1928159967Sobrien 1929268131Smarcel if (!if_sendq_empty(ifp)) 1930216925Sjhb nfe_start_locked(ifp); 1931159967Sobrien 1932159967Sobrien NFE_UNLOCK(sc); 1933159967Sobrien 1934170589Syongari if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1935296272Sjhb taskqueue_enqueue(sc->nfe_tq, &sc->nfe_int_task); 1936170589Syongari return; 1937170589Syongari } 1938170589Syongari 1939170589Syongari /* Reenable interrupts. */ 1940170589Syongari nfe_enable_intr(sc); 1941159967Sobrien} 1942159967Sobrien 1943163503Sobrien 1944170589Syongaristatic __inline void 1945170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1946159952Sobrien{ 1947170589Syongari struct nfe_desc32 *desc32; 1948170589Syongari struct nfe_desc64 *desc64; 1949170589Syongari struct nfe_rx_data *data; 1950170589Syongari struct mbuf *m; 1951163503Sobrien 1952170589Syongari data = &sc->rxq.data[idx]; 1953170589Syongari m = data->m; 1954170589Syongari 1955170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1956170589Syongari desc64 = &sc->rxq.desc64[idx]; 1957170589Syongari /* VLAN packet may have overwritten it. */ 1958170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1959170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1960170589Syongari desc64->length = htole16(m->m_len); 1961170589Syongari desc64->flags = htole16(NFE_RX_READY); 1962170589Syongari } else { 1963170589Syongari desc32 = &sc->rxq.desc32[idx]; 1964170589Syongari desc32->length = htole16(m->m_len); 1965170589Syongari desc32->flags = htole16(NFE_RX_READY); 1966170589Syongari } 1967159952Sobrien} 1968159952Sobrien 1969163503Sobrien 1970170589Syongaristatic __inline void 1971170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1972159952Sobrien{ 1973170589Syongari struct nfe_desc32 *desc32; 1974170589Syongari struct nfe_desc64 *desc64; 1975170589Syongari struct nfe_rx_data *data; 1976170589Syongari struct mbuf *m; 1977163503Sobrien 1978170589Syongari data = &sc->jrxq.jdata[idx]; 1979170589Syongari m = data->m; 1980170589Syongari 1981170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1982170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 1983170589Syongari /* VLAN packet may have overwritten it. */ 1984170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1985170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1986170589Syongari desc64->length = htole16(m->m_len); 1987170589Syongari desc64->flags = htole16(NFE_RX_READY); 1988170589Syongari } else { 1989170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 1990170589Syongari desc32->length = htole16(m->m_len); 1991170589Syongari desc32->flags = htole16(NFE_RX_READY); 1992170589Syongari } 1993159952Sobrien} 1994159952Sobrien 1995163503Sobrien 1996170589Syongaristatic int 1997170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx) 1998159952Sobrien{ 1999170589Syongari struct nfe_rx_data *data; 2000170589Syongari struct nfe_desc32 *desc32; 2001170589Syongari struct nfe_desc64 *desc64; 2002170589Syongari struct mbuf *m; 2003170589Syongari bus_dma_segment_t segs[1]; 2004170589Syongari bus_dmamap_t map; 2005170589Syongari int nsegs; 2006163503Sobrien 2007243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2008170589Syongari if (m == NULL) 2009170589Syongari return (ENOBUFS); 2010159952Sobrien 2011170589Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 2012170589Syongari m_adj(m, ETHER_ALIGN); 2013163503Sobrien 2014170589Syongari if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 2015170589Syongari m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2016170589Syongari m_freem(m); 2017170589Syongari return (ENOBUFS); 2018170589Syongari } 2019170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2020163503Sobrien 2021170589Syongari data = &sc->rxq.data[idx]; 2022170589Syongari if (data->m != NULL) { 2023170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2024170589Syongari BUS_DMASYNC_POSTREAD); 2025170589Syongari bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 2026170589Syongari } 2027170589Syongari map = data->rx_data_map; 2028170589Syongari data->rx_data_map = sc->rxq.rx_spare_map; 2029170589Syongari sc->rxq.rx_spare_map = map; 2030170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2031170589Syongari BUS_DMASYNC_PREREAD); 2032170589Syongari data->paddr = segs[0].ds_addr; 2033170589Syongari data->m = m; 2034170589Syongari /* update mapping address in h/w descriptor */ 2035170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2036170589Syongari desc64 = &sc->rxq.desc64[idx]; 2037170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2038170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2039170589Syongari desc64->length = htole16(segs[0].ds_len); 2040170589Syongari desc64->flags = htole16(NFE_RX_READY); 2041170589Syongari } else { 2042170589Syongari desc32 = &sc->rxq.desc32[idx]; 2043170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2044170589Syongari desc32->length = htole16(segs[0].ds_len); 2045170589Syongari desc32->flags = htole16(NFE_RX_READY); 2046170589Syongari } 2047170589Syongari 2048170589Syongari return (0); 2049159952Sobrien} 2050159952Sobrien 2051163503Sobrien 2052170589Syongaristatic int 2053170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx) 2054159952Sobrien{ 2055170589Syongari struct nfe_rx_data *data; 2056170589Syongari struct nfe_desc32 *desc32; 2057170589Syongari struct nfe_desc64 *desc64; 2058170589Syongari struct mbuf *m; 2059170589Syongari bus_dma_segment_t segs[1]; 2060170589Syongari bus_dmamap_t map; 2061170589Syongari int nsegs; 2062163503Sobrien 2063243857Sglebius m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 2064170589Syongari if (m == NULL) 2065170589Syongari return (ENOBUFS); 2066176859Syongari m->m_pkthdr.len = m->m_len = MJUM9BYTES; 2067170589Syongari m_adj(m, ETHER_ALIGN); 2068159952Sobrien 2069170589Syongari if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 2070170589Syongari sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2071170589Syongari m_freem(m); 2072170589Syongari return (ENOBUFS); 2073170589Syongari } 2074170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2075163503Sobrien 2076170589Syongari data = &sc->jrxq.jdata[idx]; 2077170589Syongari if (data->m != NULL) { 2078170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2079170589Syongari BUS_DMASYNC_POSTREAD); 2080170589Syongari bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 2081170589Syongari } 2082170589Syongari map = data->rx_data_map; 2083170589Syongari data->rx_data_map = sc->jrxq.jrx_spare_map; 2084170589Syongari sc->jrxq.jrx_spare_map = map; 2085170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2086170589Syongari BUS_DMASYNC_PREREAD); 2087170589Syongari data->paddr = segs[0].ds_addr; 2088170589Syongari data->m = m; 2089170589Syongari /* update mapping address in h/w descriptor */ 2090170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2091170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 2092170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2093170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2094170589Syongari desc64->length = htole16(segs[0].ds_len); 2095170589Syongari desc64->flags = htole16(NFE_RX_READY); 2096170589Syongari } else { 2097170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 2098170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2099170589Syongari desc32->length = htole16(segs[0].ds_len); 2100170589Syongari desc32->flags = htole16(NFE_RX_READY); 2101170589Syongari } 2102159967Sobrien 2103170589Syongari return (0); 2104159952Sobrien} 2105159952Sobrien 2106163503Sobrien 2107170589Syongaristatic int 2108193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2109159952Sobrien{ 2110268131Smarcel if_t ifp = sc->nfe_ifp; 2111170589Syongari struct nfe_desc32 *desc32; 2112170589Syongari struct nfe_desc64 *desc64; 2113159952Sobrien struct nfe_rx_data *data; 2114170589Syongari struct mbuf *m; 2115170589Syongari uint16_t flags; 2116193096Sattilio int len, prog, rx_npkts; 2117170589Syongari uint32_t vtag = 0; 2118159952Sobrien 2119193096Sattilio rx_npkts = 0; 2120159967Sobrien NFE_LOCK_ASSERT(sc); 2121159967Sobrien 2122170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2123170589Syongari BUS_DMASYNC_POSTREAD); 2124159967Sobrien 2125170589Syongari for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2126170589Syongari if (count <= 0) 2127170589Syongari break; 2128170589Syongari count--; 2129159967Sobrien 2130159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 2131159952Sobrien 2132159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2133159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2134170589Syongari vtag = le32toh(desc64->physaddr[1]); 2135170589Syongari flags = le16toh(desc64->flags); 2136170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2137159952Sobrien } else { 2138159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2139170589Syongari flags = le16toh(desc32->flags); 2140170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2141159952Sobrien } 2142159952Sobrien 2143159952Sobrien if (flags & NFE_RX_READY) 2144159952Sobrien break; 2145170589Syongari prog++; 2146159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2147170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2148271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2149170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2150170589Syongari continue; 2151170589Syongari } 2152159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2153159952Sobrien flags &= ~NFE_RX_ERROR; 2154159952Sobrien len--; /* fix buffer length */ 2155159952Sobrien } 2156159952Sobrien } else { 2157170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2158271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2159170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2160170589Syongari continue; 2161170589Syongari } 2162159952Sobrien 2163159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2164159952Sobrien flags &= ~NFE_RX_ERROR; 2165159952Sobrien len--; /* fix buffer length */ 2166159952Sobrien } 2167159952Sobrien } 2168159952Sobrien 2169159952Sobrien if (flags & NFE_RX_ERROR) { 2170271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2171170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2172170589Syongari continue; 2173159952Sobrien } 2174159952Sobrien 2175170589Syongari m = data->m; 2176170589Syongari if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2177271782Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 2178170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2179170589Syongari continue; 2180159952Sobrien } 2181159952Sobrien 2182170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2183268131Smarcel (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) { 2184170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2185170589Syongari m->m_flags |= M_VLANTAG; 2186164651Sobrien } 2187159952Sobrien 2188170589Syongari m->m_pkthdr.len = m->m_len = len; 2189170589Syongari m->m_pkthdr.rcvif = ifp; 2190164651Sobrien 2191268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) { 2192170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2193170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2194170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2195170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2196170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2197170589Syongari m->m_pkthdr.csum_flags |= 2198170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2199170589Syongari m->m_pkthdr.csum_data = 0xffff; 2200170589Syongari } 2201159952Sobrien } 2202170589Syongari } 2203170589Syongari 2204271782Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 2205170589Syongari 2206170589Syongari NFE_UNLOCK(sc); 2207268131Smarcel if_input(ifp, m); 2208170589Syongari NFE_LOCK(sc); 2209193096Sattilio rx_npkts++; 2210170589Syongari } 2211170589Syongari 2212170589Syongari if (prog > 0) 2213170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2214170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2215170589Syongari 2216193096Sattilio if (rx_npktsp != NULL) 2217193096Sattilio *rx_npktsp = rx_npkts; 2218170589Syongari return (count > 0 ? 0 : EAGAIN); 2219170589Syongari} 2220170589Syongari 2221170589Syongari 2222170589Syongaristatic int 2223193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2224170589Syongari{ 2225268131Smarcel if_t ifp = sc->nfe_ifp; 2226170589Syongari struct nfe_desc32 *desc32; 2227170589Syongari struct nfe_desc64 *desc64; 2228170589Syongari struct nfe_rx_data *data; 2229170589Syongari struct mbuf *m; 2230170589Syongari uint16_t flags; 2231193096Sattilio int len, prog, rx_npkts; 2232170589Syongari uint32_t vtag = 0; 2233170589Syongari 2234193096Sattilio rx_npkts = 0; 2235170589Syongari NFE_LOCK_ASSERT(sc); 2236170589Syongari 2237170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2238170589Syongari BUS_DMASYNC_POSTREAD); 2239170589Syongari 2240170589Syongari for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2241170589Syongari vtag = 0) { 2242170589Syongari if (count <= 0) 2243170589Syongari break; 2244170589Syongari count--; 2245170589Syongari 2246170589Syongari data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2247170589Syongari 2248170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2249170589Syongari desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2250170589Syongari vtag = le32toh(desc64->physaddr[1]); 2251170589Syongari flags = le16toh(desc64->flags); 2252170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2253170589Syongari } else { 2254170589Syongari desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2255170589Syongari flags = le16toh(desc32->flags); 2256170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2257170589Syongari } 2258170589Syongari 2259170589Syongari if (flags & NFE_RX_READY) 2260170589Syongari break; 2261170589Syongari prog++; 2262170589Syongari if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2263170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2264271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2265170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2266170589Syongari continue; 2267170589Syongari } 2268170589Syongari if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2269170589Syongari flags &= ~NFE_RX_ERROR; 2270170589Syongari len--; /* fix buffer length */ 2271170589Syongari } 2272170589Syongari } else { 2273170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2274271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2275170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2276170589Syongari continue; 2277170589Syongari } 2278170589Syongari 2279170589Syongari if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2280170589Syongari flags &= ~NFE_RX_ERROR; 2281170589Syongari len--; /* fix buffer length */ 2282170589Syongari } 2283170589Syongari } 2284170589Syongari 2285170589Syongari if (flags & NFE_RX_ERROR) { 2286271782Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 2287170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2288170589Syongari continue; 2289164651Sobrien } 2290159952Sobrien 2291159952Sobrien m = data->m; 2292170589Syongari if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2293271782Sglebius if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 2294170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2295170589Syongari continue; 2296170589Syongari } 2297159952Sobrien 2298170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2299268131Smarcel (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) { 2300170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2301170589Syongari m->m_flags |= M_VLANTAG; 2302170589Syongari } 2303170589Syongari 2304159952Sobrien m->m_pkthdr.len = m->m_len = len; 2305159952Sobrien m->m_pkthdr.rcvif = ifp; 2306159952Sobrien 2307268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) { 2308170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2309170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2310159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2311170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2312170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2313170589Syongari m->m_pkthdr.csum_flags |= 2314170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2315170589Syongari m->m_pkthdr.csum_data = 0xffff; 2316170589Syongari } 2317159967Sobrien } 2318159952Sobrien } 2319159952Sobrien 2320271782Sglebius if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 2321159952Sobrien 2322159967Sobrien NFE_UNLOCK(sc); 2323268131Smarcel if_input(ifp, m); 2324159967Sobrien NFE_LOCK(sc); 2325193096Sattilio rx_npkts++; 2326170589Syongari } 2327159967Sobrien 2328170589Syongari if (prog > 0) 2329170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2330170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2331159952Sobrien 2332193096Sattilio if (rx_npktsp != NULL) 2333193096Sattilio *rx_npktsp = rx_npkts; 2334170589Syongari return (count > 0 ? 0 : EAGAIN); 2335159952Sobrien} 2336159952Sobrien 2337163503Sobrien 2338163503Sobrienstatic void 2339163503Sobriennfe_txeof(struct nfe_softc *sc) 2340159952Sobrien{ 2341268131Smarcel if_t ifp = sc->nfe_ifp; 2342159952Sobrien struct nfe_desc32 *desc32; 2343159952Sobrien struct nfe_desc64 *desc64; 2344159952Sobrien struct nfe_tx_data *data = NULL; 2345170589Syongari uint16_t flags; 2346170589Syongari int cons, prog; 2347159952Sobrien 2348159967Sobrien NFE_LOCK_ASSERT(sc); 2349159967Sobrien 2350170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2351170589Syongari BUS_DMASYNC_POSTREAD); 2352170589Syongari 2353170589Syongari prog = 0; 2354170589Syongari for (cons = sc->txq.next; cons != sc->txq.cur; 2355170589Syongari NFE_INC(cons, NFE_TX_RING_COUNT)) { 2356159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2357170589Syongari desc64 = &sc->txq.desc64[cons]; 2358170589Syongari flags = le16toh(desc64->flags); 2359159952Sobrien } else { 2360170589Syongari desc32 = &sc->txq.desc32[cons]; 2361170589Syongari flags = le16toh(desc32->flags); 2362159952Sobrien } 2363159952Sobrien 2364159952Sobrien if (flags & NFE_TX_VALID) 2365159952Sobrien break; 2366159952Sobrien 2367170589Syongari prog++; 2368170589Syongari sc->txq.queued--; 2369170589Syongari data = &sc->txq.data[cons]; 2370159952Sobrien 2371159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2372170589Syongari if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2373170589Syongari continue; 2374159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 2375170589Syongari device_printf(sc->nfe_dev, 2376170589Syongari "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2377159967Sobrien 2378271782Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2379159952Sobrien } else 2380271782Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 2381159952Sobrien } else { 2382170589Syongari if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2383170589Syongari continue; 2384159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 2385170589Syongari device_printf(sc->nfe_dev, 2386170589Syongari "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2387271782Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2388159952Sobrien } else 2389271782Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 2390159952Sobrien } 2391159952Sobrien 2392159952Sobrien /* last fragment of the mbuf chain transmitted */ 2393170589Syongari KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2394170589Syongari bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2395159967Sobrien BUS_DMASYNC_POSTWRITE); 2396170589Syongari bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2397159952Sobrien m_freem(data->m); 2398159952Sobrien data->m = NULL; 2399159952Sobrien } 2400159952Sobrien 2401170589Syongari if (prog > 0) { 2402170589Syongari sc->nfe_force_tx = 0; 2403170589Syongari sc->txq.next = cons; 2404268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 2405170589Syongari if (sc->txq.queued == 0) 2406170589Syongari sc->nfe_watchdog_timer = 0; 2407159952Sobrien } 2408159952Sobrien} 2409159952Sobrien 2410163503Sobrienstatic int 2411170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2412159952Sobrien{ 2413170589Syongari struct nfe_desc32 *desc32 = NULL; 2414170589Syongari struct nfe_desc64 *desc64 = NULL; 2415159952Sobrien bus_dmamap_t map; 2416163503Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2417170589Syongari int error, i, nsegs, prod, si; 2418254803Sandre uint32_t tsosegsz; 2419170589Syongari uint16_t cflags, flags; 2420170589Syongari struct mbuf *m; 2421159952Sobrien 2422170589Syongari prod = si = sc->txq.cur; 2423170589Syongari map = sc->txq.data[prod].tx_data_map; 2424159952Sobrien 2425170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2426159967Sobrien &nsegs, BUS_DMA_NOWAIT); 2427170589Syongari if (error == EFBIG) { 2428243857Sglebius m = m_collapse(*m_head, M_NOWAIT, NFE_MAX_SCATTER); 2429170589Syongari if (m == NULL) { 2430170589Syongari m_freem(*m_head); 2431170589Syongari *m_head = NULL; 2432170589Syongari return (ENOBUFS); 2433170589Syongari } 2434170589Syongari *m_head = m; 2435170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2436170589Syongari *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2437170589Syongari if (error != 0) { 2438170589Syongari m_freem(*m_head); 2439170589Syongari *m_head = NULL; 2440170589Syongari return (ENOBUFS); 2441170589Syongari } 2442170589Syongari } else if (error != 0) 2443170589Syongari return (error); 2444170589Syongari if (nsegs == 0) { 2445170589Syongari m_freem(*m_head); 2446170589Syongari *m_head = NULL; 2447170589Syongari return (EIO); 2448159952Sobrien } 2449159952Sobrien 2450170589Syongari if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2451159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2452170589Syongari return (ENOBUFS); 2453159952Sobrien } 2454159952Sobrien 2455170589Syongari m = *m_head; 2456170589Syongari cflags = flags = 0; 2457254803Sandre tsosegsz = 0; 2458206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2459254803Sandre tsosegsz = (uint32_t)m->m_pkthdr.tso_segsz << 2460206876Syongari NFE_TX_TSO_SHIFT; 2461206876Syongari cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2462206876Syongari cflags |= NFE_TX_TSO; 2463206876Syongari } else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2464170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2465170589Syongari cflags |= NFE_TX_IP_CSUM; 2466170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2467170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2468170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2469170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2470164656Sobrien } 2471159967Sobrien 2472159967Sobrien for (i = 0; i < nsegs; i++) { 2473159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2474170589Syongari desc64 = &sc->txq.desc64[prod]; 2475170589Syongari desc64->physaddr[0] = 2476170589Syongari htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2477170589Syongari desc64->physaddr[1] = 2478170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2479170589Syongari desc64->vtag = 0; 2480159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 2481159952Sobrien desc64->flags = htole16(flags); 2482159952Sobrien } else { 2483170589Syongari desc32 = &sc->txq.desc32[prod]; 2484170589Syongari desc32->physaddr = 2485170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2486159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 2487159952Sobrien desc32->flags = htole16(flags); 2488159952Sobrien } 2489159952Sobrien 2490170589Syongari /* 2491170589Syongari * Setting of the valid bit in the first descriptor is 2492170589Syongari * deferred until the whole chain is fully setup. 2493170589Syongari */ 2494170589Syongari flags |= NFE_TX_VALID; 2495163503Sobrien 2496159952Sobrien sc->txq.queued++; 2497170589Syongari NFE_INC(prod, NFE_TX_RING_COUNT); 2498159952Sobrien } 2499159952Sobrien 2500170589Syongari /* 2501170589Syongari * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2502170589Syongari * csum flags, vtag and TSO belong to the first fragment only. 2503170589Syongari */ 2504159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2505170589Syongari desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2506170589Syongari desc64 = &sc->txq.desc64[si]; 2507170589Syongari if ((m->m_flags & M_VLANTAG) != 0) 2508170589Syongari desc64->vtag = htole32(NFE_TX_VTAG | 2509170589Syongari m->m_pkthdr.ether_vtag); 2510254803Sandre if (tsosegsz != 0) { 2511170589Syongari /* 2512170589Syongari * XXX 2513170589Syongari * The following indicates the descriptor element 2514170589Syongari * is a 32bit quantity. 2515170589Syongari */ 2516254803Sandre desc64->length |= htole16((uint16_t)tsosegsz); 2517254803Sandre desc64->flags |= htole16(tsosegsz >> 16); 2518170589Syongari } 2519170589Syongari /* 2520170589Syongari * finally, set the valid/checksum/TSO bit in the first 2521170589Syongari * descriptor. 2522170589Syongari */ 2523170589Syongari desc64->flags |= htole16(NFE_TX_VALID | cflags); 2524159952Sobrien } else { 2525159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 2526170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2527159952Sobrien else 2528170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2529170589Syongari desc32 = &sc->txq.desc32[si]; 2530254803Sandre if (tsosegsz != 0) { 2531170589Syongari /* 2532170589Syongari * XXX 2533170589Syongari * The following indicates the descriptor element 2534170589Syongari * is a 32bit quantity. 2535170589Syongari */ 2536254803Sandre desc32->length |= htole16((uint16_t)tsosegsz); 2537254803Sandre desc32->flags |= htole16(tsosegsz >> 16); 2538170589Syongari } 2539170589Syongari /* 2540170589Syongari * finally, set the valid/checksum/TSO bit in the first 2541170589Syongari * descriptor. 2542170589Syongari */ 2543170589Syongari desc32->flags |= htole16(NFE_TX_VALID | cflags); 2544159952Sobrien } 2545159952Sobrien 2546170589Syongari sc->txq.cur = prod; 2547170589Syongari prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2548170589Syongari sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2549170589Syongari sc->txq.data[prod].tx_data_map = map; 2550170589Syongari sc->txq.data[prod].m = m; 2551159952Sobrien 2552159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2553159952Sobrien 2554170589Syongari return (0); 2555159952Sobrien} 2556159952Sobrien 2557159967Sobrien 2558163503Sobrienstatic void 2559163503Sobriennfe_setmulti(struct nfe_softc *sc) 2560159952Sobrien{ 2561268131Smarcel if_t ifp = sc->nfe_ifp; 2562268131Smarcel int i, mc_count, mcnt; 2563170589Syongari uint32_t filter; 2564170589Syongari uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2565170589Syongari uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 2566163503Sobrien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2567163503Sobrien }; 2568268131Smarcel uint8_t *mta; 2569159967Sobrien 2570159967Sobrien NFE_LOCK_ASSERT(sc); 2571159967Sobrien 2572268131Smarcel if ((if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2573159967Sobrien bzero(addr, ETHER_ADDR_LEN); 2574159967Sobrien bzero(mask, ETHER_ADDR_LEN); 2575159967Sobrien goto done; 2576159967Sobrien } 2577159967Sobrien 2578159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2579159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2580159967Sobrien 2581268131Smarcel mc_count = if_multiaddr_count(ifp, -1); 2582268131Smarcel mta = malloc(sizeof(uint8_t) * ETHER_ADDR_LEN * mc_count, M_DEVBUF, 2583268131Smarcel M_NOWAIT); 2584159967Sobrien 2585268131Smarcel /* Unable to get memory - process without filtering */ 2586268131Smarcel if (mta == NULL) { 2587268131Smarcel device_printf(sc->nfe_dev, "nfe_setmulti: failed to allocate" 2588268131Smarcel "temp multicast buffer!\n"); 2589159967Sobrien 2590268131Smarcel bzero(addr, ETHER_ADDR_LEN); 2591268131Smarcel bzero(mask, ETHER_ADDR_LEN); 2592268131Smarcel goto done; 2593268131Smarcel }; 2594268131Smarcel 2595269479Smarcel if_multiaddr_array(ifp, mta, &mcnt, mc_count); 2596268131Smarcel 2597268131Smarcel for (i = 0; i < mcnt; i++) { 2598268131Smarcel uint8_t *addrp; 2599269479Smarcel int j; 2600268131Smarcel 2601268131Smarcel addrp = mta + (i * ETHER_ADDR_LEN); 2602269479Smarcel for (j = 0; j < ETHER_ADDR_LEN; j++) { 2603269479Smarcel u_int8_t mcaddr = addrp[j]; 2604269479Smarcel addr[j] &= mcaddr; 2605269479Smarcel mask[j] &= ~mcaddr; 2606159967Sobrien } 2607159967Sobrien } 2608159967Sobrien 2609269479Smarcel free(mta, M_DEVBUF); 2610269479Smarcel 2611159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2612159967Sobrien mask[i] |= addr[i]; 2613159967Sobrien } 2614159967Sobrien 2615159967Sobriendone: 2616159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 2617159967Sobrien 2618159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2619159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2620159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2621159967Sobrien addr[5] << 8 | addr[4]); 2622159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2623159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2624159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2625159967Sobrien mask[5] << 8 | mask[4]); 2626159967Sobrien 2627170589Syongari filter = NFE_READ(sc, NFE_RXFILTER); 2628170589Syongari filter &= NFE_PFF_RX_PAUSE; 2629170589Syongari filter |= NFE_RXFILTER_MAGIC; 2630268131Smarcel filter |= (if_getflags(ifp) & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2631159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 2632159967Sobrien} 2633159967Sobrien 2634163503Sobrien 2635163503Sobrienstatic void 2636268131Smarcelnfe_start(if_t ifp) 2637159967Sobrien{ 2638268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2639159967Sobrien 2640216925Sjhb NFE_LOCK(sc); 2641216925Sjhb nfe_start_locked(ifp); 2642216925Sjhb NFE_UNLOCK(sc); 2643159967Sobrien} 2644159967Sobrien 2645163503Sobrienstatic void 2646268131Smarcelnfe_start_locked(if_t ifp) 2647159967Sobrien{ 2648268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2649163503Sobrien struct mbuf *m0; 2650268131Smarcel int enq = 0; 2651159952Sobrien 2652216925Sjhb NFE_LOCK_ASSERT(sc); 2653170589Syongari 2654268131Smarcel if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2655216925Sjhb IFF_DRV_RUNNING || sc->nfe_link == 0) 2656159967Sobrien return; 2657159967Sobrien 2658268131Smarcel while (!if_sendq_empty(ifp)) { 2659268131Smarcel m0 = if_dequeue(ifp); 2660268131Smarcel 2661159952Sobrien if (m0 == NULL) 2662159952Sobrien break; 2663159952Sobrien 2664170589Syongari if (nfe_encap(sc, &m0) != 0) { 2665170589Syongari if (m0 == NULL) 2666170589Syongari break; 2667268131Smarcel if_sendq_prepend(ifp, m0); 2668268131Smarcel if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 2669159952Sobrien break; 2670159952Sobrien } 2671170589Syongari enq++; 2672268131Smarcel if_etherbpfmtap(ifp, m0); 2673159952Sobrien } 2674159952Sobrien 2675170589Syongari if (enq > 0) { 2676170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2677170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2678159952Sobrien 2679170589Syongari /* kick Tx */ 2680170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2681159952Sobrien 2682170589Syongari /* 2683170589Syongari * Set a timeout in case the chip goes out to lunch. 2684170589Syongari */ 2685170589Syongari sc->nfe_watchdog_timer = 5; 2686170589Syongari } 2687159952Sobrien} 2688159952Sobrien 2689163503Sobrien 2690163503Sobrienstatic void 2691268131Smarcelnfe_watchdog(if_t ifp) 2692159952Sobrien{ 2693268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2694159952Sobrien 2695170589Syongari if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2696170589Syongari return; 2697159952Sobrien 2698170589Syongari /* Check if we've lost Tx completion interrupt. */ 2699170589Syongari nfe_txeof(sc); 2700170589Syongari if (sc->txq.queued == 0) { 2701170589Syongari if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2702170589Syongari "-- recovering\n"); 2703268131Smarcel if (!if_sendq_empty(ifp)) 2704216925Sjhb nfe_start_locked(ifp); 2705170589Syongari return; 2706170589Syongari } 2707170589Syongari /* Check if we've lost start Tx command. */ 2708170589Syongari sc->nfe_force_tx++; 2709170589Syongari if (sc->nfe_force_tx <= 3) { 2710170589Syongari /* 2711170589Syongari * If this is the case for watchdog timeout, the following 2712170589Syongari * code should go to nfe_txeof(). 2713170589Syongari */ 2714170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2715170589Syongari return; 2716170589Syongari } 2717170589Syongari sc->nfe_force_tx = 0; 2718170589Syongari 2719170589Syongari if_printf(ifp, "watchdog timeout\n"); 2720170589Syongari 2721268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 2722271782Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2723170589Syongari nfe_init_locked(sc); 2724159952Sobrien} 2725159952Sobrien 2726163503Sobrien 2727163503Sobrienstatic void 2728163503Sobriennfe_init(void *xsc) 2729159952Sobrien{ 2730159967Sobrien struct nfe_softc *sc = xsc; 2731159952Sobrien 2732159967Sobrien NFE_LOCK(sc); 2733159967Sobrien nfe_init_locked(sc); 2734159967Sobrien NFE_UNLOCK(sc); 2735159967Sobrien} 2736159967Sobrien 2737163503Sobrien 2738163503Sobrienstatic void 2739163503Sobriennfe_init_locked(void *xsc) 2740159967Sobrien{ 2741159967Sobrien struct nfe_softc *sc = xsc; 2742268131Smarcel if_t ifp = sc->nfe_ifp; 2743159967Sobrien struct mii_data *mii; 2744170589Syongari uint32_t val; 2745170589Syongari int error; 2746159967Sobrien 2747159967Sobrien NFE_LOCK_ASSERT(sc); 2748159967Sobrien 2749159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2750159967Sobrien 2751268131Smarcel if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 2752159967Sobrien return; 2753170589Syongari 2754170589Syongari nfe_stop(ifp); 2755170589Syongari 2756268131Smarcel sc->nfe_framesize = if_getmtu(ifp) + NFE_RX_HEADERS; 2757170589Syongari 2758170589Syongari nfe_init_tx_ring(sc, &sc->txq); 2759170589Syongari if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2760170589Syongari error = nfe_init_jrx_ring(sc, &sc->jrxq); 2761170589Syongari else 2762170589Syongari error = nfe_init_rx_ring(sc, &sc->rxq); 2763170589Syongari if (error != 0) { 2764170589Syongari device_printf(sc->nfe_dev, 2765170589Syongari "initialization failed: no memory for rx buffers\n"); 2766170589Syongari nfe_stop(ifp); 2767170589Syongari return; 2768159967Sobrien } 2769159967Sobrien 2770170589Syongari val = 0; 2771170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2772170589Syongari val |= NFE_MAC_ADDR_INORDER; 2773170589Syongari NFE_WRITE(sc, NFE_TX_UNK, val); 2774159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 2775159952Sobrien 2776170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2777170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2778170589Syongari 2779159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 2780159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 2781159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2782159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2783159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 2784164656Sobrien 2785268131Smarcel if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) 2786159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2787268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) 2788170589Syongari sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2789159967Sobrien 2790159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2791159952Sobrien DELAY(10); 2792159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2793159952Sobrien 2794268131Smarcel if ((if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0) 2795159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2796170589Syongari else 2797170589Syongari NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2798159952Sobrien 2799159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2800159952Sobrien 2801159952Sobrien /* set MAC address */ 2802268131Smarcel nfe_set_macaddr(sc, if_getlladdr(ifp)); 2803159952Sobrien 2804159952Sobrien /* tell MAC where rings are in memory */ 2805170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2806170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2807170589Syongari NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2808170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2809170589Syongari NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2810170589Syongari } else { 2811170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2812170589Syongari NFE_ADDR_HI(sc->rxq.physaddr)); 2813170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2814170589Syongari NFE_ADDR_LO(sc->rxq.physaddr)); 2815170589Syongari } 2816170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2817170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2818159952Sobrien 2819159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 2820159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 2821159952Sobrien (NFE_TX_RING_COUNT - 1)); 2822159952Sobrien 2823170589Syongari NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2824159952Sobrien 2825159952Sobrien /* force MAC to wakeup */ 2826170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2827170589Syongari if ((val & NFE_PWR_WAKEUP) == 0) 2828170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2829159952Sobrien DELAY(10); 2830170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2831170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2832159952Sobrien 2833159952Sobrien#if 1 2834159952Sobrien /* configure interrupts coalescing/mitigation */ 2835159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2836159952Sobrien#else 2837159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 2838159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 2839159952Sobrien#endif 2840159952Sobrien 2841170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2842159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2843159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2844159952Sobrien 2845159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2846159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2847159952Sobrien 2848159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2849215132Syongari /* Disable WOL. */ 2850215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, 0); 2851159952Sobrien 2852159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2853159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2854159952Sobrien DELAY(10); 2855159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2856159952Sobrien 2857159952Sobrien /* set Rx filter */ 2858159952Sobrien nfe_setmulti(sc); 2859159952Sobrien 2860159952Sobrien /* enable Rx */ 2861159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2862159952Sobrien 2863159952Sobrien /* enable Tx */ 2864159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2865159952Sobrien 2866159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2867159952Sobrien 2868183561Syongari /* Clear hardware stats. */ 2869183561Syongari nfe_stats_clear(sc); 2870183561Syongari 2871159967Sobrien#ifdef DEVICE_POLLING 2872268131Smarcel if (if_getcapenable(ifp) & IFCAP_POLLING) 2873170589Syongari nfe_disable_intr(sc); 2874159967Sobrien else 2875159967Sobrien#endif 2876170589Syongari nfe_set_intr(sc); 2877170589Syongari nfe_enable_intr(sc); /* enable interrupts */ 2878159952Sobrien 2879268131Smarcel if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 2880268131Smarcel if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 2881159952Sobrien 2882159967Sobrien sc->nfe_link = 0; 2883170589Syongari mii_mediachg(mii); 2884159952Sobrien 2885170589Syongari callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2886159952Sobrien} 2887159952Sobrien 2888163503Sobrien 2889163503Sobrienstatic void 2890268131Smarcelnfe_stop(if_t ifp) 2891159952Sobrien{ 2892268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2893170589Syongari struct nfe_rx_ring *rx_ring; 2894170589Syongari struct nfe_jrx_ring *jrx_ring; 2895170589Syongari struct nfe_tx_ring *tx_ring; 2896170589Syongari struct nfe_rx_data *rdata; 2897170589Syongari struct nfe_tx_data *tdata; 2898170589Syongari int i; 2899159952Sobrien 2900159967Sobrien NFE_LOCK_ASSERT(sc); 2901159952Sobrien 2902170589Syongari sc->nfe_watchdog_timer = 0; 2903268131Smarcel if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 2904159952Sobrien 2905159967Sobrien callout_stop(&sc->nfe_stat_ch); 2906159967Sobrien 2907159952Sobrien /* abort Tx */ 2908159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 2909159952Sobrien 2910159952Sobrien /* disable Rx */ 2911159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 2912159952Sobrien 2913159952Sobrien /* disable interrupts */ 2914170589Syongari nfe_disable_intr(sc); 2915159952Sobrien 2916159967Sobrien sc->nfe_link = 0; 2917159967Sobrien 2918170589Syongari /* free Rx and Tx mbufs still in the queues. */ 2919170589Syongari rx_ring = &sc->rxq; 2920170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2921170589Syongari rdata = &rx_ring->data[i]; 2922170589Syongari if (rdata->m != NULL) { 2923170589Syongari bus_dmamap_sync(rx_ring->rx_data_tag, 2924170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2925170589Syongari bus_dmamap_unload(rx_ring->rx_data_tag, 2926170589Syongari rdata->rx_data_map); 2927170589Syongari m_freem(rdata->m); 2928170589Syongari rdata->m = NULL; 2929170589Syongari } 2930170589Syongari } 2931159952Sobrien 2932170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 2933170589Syongari jrx_ring = &sc->jrxq; 2934170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 2935170589Syongari rdata = &jrx_ring->jdata[i]; 2936170589Syongari if (rdata->m != NULL) { 2937170589Syongari bus_dmamap_sync(jrx_ring->jrx_data_tag, 2938170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2939170589Syongari bus_dmamap_unload(jrx_ring->jrx_data_tag, 2940170589Syongari rdata->rx_data_map); 2941170589Syongari m_freem(rdata->m); 2942170589Syongari rdata->m = NULL; 2943170589Syongari } 2944170589Syongari } 2945170589Syongari } 2946170589Syongari 2947170589Syongari tx_ring = &sc->txq; 2948170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2949170589Syongari tdata = &tx_ring->data[i]; 2950170589Syongari if (tdata->m != NULL) { 2951170589Syongari bus_dmamap_sync(tx_ring->tx_data_tag, 2952170589Syongari tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 2953170589Syongari bus_dmamap_unload(tx_ring->tx_data_tag, 2954170589Syongari tdata->tx_data_map); 2955170589Syongari m_freem(tdata->m); 2956170589Syongari tdata->m = NULL; 2957170589Syongari } 2958170589Syongari } 2959183561Syongari /* Update hardware stats. */ 2960183561Syongari nfe_stats_update(sc); 2961159952Sobrien} 2962159952Sobrien 2963163503Sobrien 2964163503Sobrienstatic int 2965268131Smarcelnfe_ifmedia_upd(if_t ifp) 2966159952Sobrien{ 2967268131Smarcel struct nfe_softc *sc = if_getsoftc(ifp); 2968170589Syongari struct mii_data *mii; 2969159952Sobrien 2970159967Sobrien NFE_LOCK(sc); 2971159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2972159967Sobrien mii_mediachg(mii); 2973170589Syongari NFE_UNLOCK(sc); 2974159967Sobrien 2975159967Sobrien return (0); 2976159952Sobrien} 2977159952Sobrien 2978163503Sobrien 2979163503Sobrienstatic void 2980268131Smarcelnfe_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 2981159952Sobrien{ 2982163503Sobrien struct nfe_softc *sc; 2983163503Sobrien struct mii_data *mii; 2984159952Sobrien 2985268131Smarcel sc = if_getsoftc(ifp); 2986159952Sobrien 2987159967Sobrien NFE_LOCK(sc); 2988159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2989159967Sobrien mii_pollstat(mii); 2990159952Sobrien 2991159967Sobrien ifmr->ifm_active = mii->mii_media_active; 2992159967Sobrien ifmr->ifm_status = mii->mii_media_status; 2993226478Syongari NFE_UNLOCK(sc); 2994159952Sobrien} 2995159952Sobrien 2996163503Sobrien 2997170589Syongarivoid 2998159967Sobriennfe_tick(void *xsc) 2999159952Sobrien{ 3000159967Sobrien struct nfe_softc *sc; 3001163503Sobrien struct mii_data *mii; 3002268131Smarcel if_t ifp; 3003159952Sobrien 3004170589Syongari sc = (struct nfe_softc *)xsc; 3005159952Sobrien 3006163503Sobrien NFE_LOCK_ASSERT(sc); 3007159952Sobrien 3008159967Sobrien ifp = sc->nfe_ifp; 3009159952Sobrien 3010159967Sobrien mii = device_get_softc(sc->nfe_miibus); 3011159967Sobrien mii_tick(mii); 3012183561Syongari nfe_stats_update(sc); 3013170589Syongari nfe_watchdog(ifp); 3014159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 3015159952Sobrien} 3016159952Sobrien 3017159952Sobrien 3018173839Syongaristatic int 3019163503Sobriennfe_shutdown(device_t dev) 3020159952Sobrien{ 3021159952Sobrien 3022215132Syongari return (nfe_suspend(dev)); 3023159952Sobrien} 3024159952Sobrien 3025159952Sobrien 3026163503Sobrienstatic void 3027170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 3028159952Sobrien{ 3029170589Syongari uint32_t val; 3030159952Sobrien 3031170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 3032170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3033170589Syongari addr[0] = (val >> 8) & 0xff; 3034170589Syongari addr[1] = (val & 0xff); 3035159952Sobrien 3036170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3037170589Syongari addr[2] = (val >> 24) & 0xff; 3038170589Syongari addr[3] = (val >> 16) & 0xff; 3039170589Syongari addr[4] = (val >> 8) & 0xff; 3040170589Syongari addr[5] = (val & 0xff); 3041170589Syongari } else { 3042170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3043170589Syongari addr[5] = (val >> 8) & 0xff; 3044170589Syongari addr[4] = (val & 0xff); 3045170589Syongari 3046170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3047170589Syongari addr[3] = (val >> 24) & 0xff; 3048170589Syongari addr[2] = (val >> 16) & 0xff; 3049170589Syongari addr[1] = (val >> 8) & 0xff; 3050170589Syongari addr[0] = (val & 0xff); 3051170589Syongari } 3052159952Sobrien} 3053159952Sobrien 3054163503Sobrien 3055163503Sobrienstatic void 3056170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 3057159952Sobrien{ 3058159967Sobrien 3059159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 3060159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 3061159967Sobrien addr[1] << 8 | addr[0]); 3062159952Sobrien} 3063159952Sobrien 3064163503Sobrien 3065159967Sobrien/* 3066159967Sobrien * Map a single buffer address. 3067159967Sobrien */ 3068159967Sobrien 3069159967Sobrienstatic void 3070170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3071159952Sobrien{ 3072170589Syongari struct nfe_dmamap_arg *ctx; 3073159952Sobrien 3074170589Syongari if (error != 0) 3075159967Sobrien return; 3076159952Sobrien 3077159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 3078159967Sobrien 3079170589Syongari ctx = (struct nfe_dmamap_arg *)arg; 3080170589Syongari ctx->nfe_busaddr = segs[0].ds_addr; 3081170589Syongari} 3082159967Sobrien 3083170589Syongari 3084170589Syongaristatic int 3085170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3086170589Syongari{ 3087170589Syongari int error, value; 3088170589Syongari 3089170589Syongari if (!arg1) 3090170589Syongari return (EINVAL); 3091170589Syongari value = *(int *)arg1; 3092170589Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3093170589Syongari if (error || !req->newptr) 3094170589Syongari return (error); 3095170589Syongari if (value < low || value > high) 3096170589Syongari return (EINVAL); 3097170589Syongari *(int *)arg1 = value; 3098170589Syongari 3099170589Syongari return (0); 3100159952Sobrien} 3101170589Syongari 3102170589Syongari 3103170589Syongaristatic int 3104170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 3105170589Syongari{ 3106170589Syongari 3107170589Syongari return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 3108170589Syongari NFE_PROC_MAX)); 3109170589Syongari} 3110183561Syongari 3111183561Syongari 3112183561Syongari#define NFE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 3113183561Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 3114183561Syongari#define NFE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 3115217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 3116183561Syongari 3117183561Syongaristatic void 3118183561Syongarinfe_sysctl_node(struct nfe_softc *sc) 3119183561Syongari{ 3120183561Syongari struct sysctl_ctx_list *ctx; 3121183561Syongari struct sysctl_oid_list *child, *parent; 3122183561Syongari struct sysctl_oid *tree; 3123183561Syongari struct nfe_hw_stats *stats; 3124183561Syongari int error; 3125183561Syongari 3126183561Syongari stats = &sc->nfe_stats; 3127183561Syongari ctx = device_get_sysctl_ctx(sc->nfe_dev); 3128183561Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev)); 3129183561Syongari SYSCTL_ADD_PROC(ctx, child, 3130183561Syongari OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 3131183561Syongari &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 3132183561Syongari "max number of Rx events to process"); 3133183561Syongari 3134183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3135183561Syongari error = resource_int_value(device_get_name(sc->nfe_dev), 3136183561Syongari device_get_unit(sc->nfe_dev), "process_limit", 3137183561Syongari &sc->nfe_process_limit); 3138183561Syongari if (error == 0) { 3139183561Syongari if (sc->nfe_process_limit < NFE_PROC_MIN || 3140183561Syongari sc->nfe_process_limit > NFE_PROC_MAX) { 3141183561Syongari device_printf(sc->nfe_dev, 3142183561Syongari "process_limit value out of range; " 3143183561Syongari "using default: %d\n", NFE_PROC_DEFAULT); 3144183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3145183561Syongari } 3146183561Syongari } 3147183561Syongari 3148183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3149183561Syongari return; 3150183561Syongari 3151183561Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 3152183561Syongari NULL, "NFE statistics"); 3153183561Syongari parent = SYSCTL_CHILDREN(tree); 3154183561Syongari 3155183561Syongari /* Rx statistics. */ 3156183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 3157183561Syongari NULL, "Rx MAC statistics"); 3158183561Syongari child = SYSCTL_CHILDREN(tree); 3159183561Syongari 3160183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors", 3161183561Syongari &stats->rx_frame_errors, "Framing Errors"); 3162183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes", 3163183561Syongari &stats->rx_extra_bytes, "Extra Bytes"); 3164183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3165183561Syongari &stats->rx_late_cols, "Late Collisions"); 3166183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "runts", 3167183561Syongari &stats->rx_runts, "Runts"); 3168183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos", 3169183561Syongari &stats->rx_jumbos, "Jumbos"); 3170183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns", 3171183561Syongari &stats->rx_fifo_overuns, "FIFO Overruns"); 3172183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors", 3173183561Syongari &stats->rx_crc_errors, "CRC Errors"); 3174183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fae", 3175183561Syongari &stats->rx_fae, "Frame Alignment Errors"); 3176183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors", 3177183561Syongari &stats->rx_len_errors, "Length Errors"); 3178183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3179183561Syongari &stats->rx_unicast, "Unicast Frames"); 3180183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3181183561Syongari &stats->rx_multicast, "Multicast Frames"); 3182186346Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3183183561Syongari &stats->rx_broadcast, "Broadcast Frames"); 3184183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3185183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3186183561Syongari &stats->rx_octets, "Octets"); 3187183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3188183561Syongari &stats->rx_pause, "Pause frames"); 3189183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "drops", 3190183561Syongari &stats->rx_drops, "Drop frames"); 3191183561Syongari } 3192183561Syongari 3193183561Syongari /* Tx statistics. */ 3194183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 3195183561Syongari NULL, "Tx MAC statistics"); 3196183561Syongari child = SYSCTL_CHILDREN(tree); 3197183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3198183561Syongari &stats->tx_octets, "Octets"); 3199183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits", 3200183561Syongari &stats->tx_zero_rexmits, "Zero Retransmits"); 3201183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits", 3202183561Syongari &stats->tx_one_rexmits, "One Retransmits"); 3203183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits", 3204183561Syongari &stats->tx_multi_rexmits, "Multiple Retransmits"); 3205183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3206183561Syongari &stats->tx_late_cols, "Late Collisions"); 3207183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns", 3208183561Syongari &stats->tx_fifo_underuns, "FIFO Underruns"); 3209183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts", 3210183561Syongari &stats->tx_carrier_losts, "Carrier Losts"); 3211183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals", 3212183561Syongari &stats->tx_excess_deferals, "Excess Deferrals"); 3213183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors", 3214183561Syongari &stats->tx_retry_errors, "Retry Errors"); 3215183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3216183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals", 3217183561Syongari &stats->tx_deferals, "Deferrals"); 3218183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frames", 3219183561Syongari &stats->tx_frames, "Frames"); 3220183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3221183561Syongari &stats->tx_pause, "Pause Frames"); 3222183561Syongari } 3223183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3224183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3225183561Syongari &stats->tx_deferals, "Unicast Frames"); 3226183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3227183561Syongari &stats->tx_frames, "Multicast Frames"); 3228183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3229183561Syongari &stats->tx_pause, "Broadcast Frames"); 3230183561Syongari } 3231183561Syongari} 3232183561Syongari 3233183561Syongari#undef NFE_SYSCTL_STAT_ADD32 3234183561Syongari#undef NFE_SYSCTL_STAT_ADD64 3235183561Syongari 3236183561Syongaristatic void 3237183561Syongarinfe_stats_clear(struct nfe_softc *sc) 3238183561Syongari{ 3239183561Syongari int i, mib_cnt; 3240183561Syongari 3241183561Syongari if ((sc->nfe_flags & NFE_MIB_V1) != 0) 3242183561Syongari mib_cnt = NFE_NUM_MIB_STATV1; 3243183561Syongari else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0) 3244183561Syongari mib_cnt = NFE_NUM_MIB_STATV2; 3245183561Syongari else 3246183561Syongari return; 3247183561Syongari 3248256038Syongari for (i = 0; i < mib_cnt; i++) 3249256038Syongari NFE_READ(sc, NFE_TX_OCTET + i * sizeof(uint32_t)); 3250183561Syongari 3251183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3252183561Syongari NFE_READ(sc, NFE_TX_UNICAST); 3253183561Syongari NFE_READ(sc, NFE_TX_MULTICAST); 3254183561Syongari NFE_READ(sc, NFE_TX_BROADCAST); 3255183561Syongari } 3256183561Syongari} 3257183561Syongari 3258183561Syongaristatic void 3259183561Syongarinfe_stats_update(struct nfe_softc *sc) 3260183561Syongari{ 3261183561Syongari struct nfe_hw_stats *stats; 3262183561Syongari 3263183561Syongari NFE_LOCK_ASSERT(sc); 3264183561Syongari 3265183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3266183561Syongari return; 3267183561Syongari 3268183561Syongari stats = &sc->nfe_stats; 3269183561Syongari stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET); 3270183561Syongari stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT); 3271183561Syongari stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT); 3272183561Syongari stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT); 3273183561Syongari stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL); 3274183561Syongari stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN); 3275183561Syongari stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST); 3276183561Syongari stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL); 3277183561Syongari stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR); 3278183561Syongari stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR); 3279183561Syongari stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES); 3280183561Syongari stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL); 3281183561Syongari stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT); 3282183561Syongari stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO); 3283183561Syongari stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN); 3284183561Syongari stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR); 3285183561Syongari stats->rx_fae += NFE_READ(sc, NFE_RX_FAE); 3286183561Syongari stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR); 3287183561Syongari stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST); 3288183561Syongari stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST); 3289183561Syongari stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST); 3290183561Syongari 3291183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3292183561Syongari stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL); 3293183561Syongari stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME); 3294183561Syongari stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET); 3295183561Syongari stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE); 3296183561Syongari stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE); 3297183561Syongari stats->rx_drops += NFE_READ(sc, NFE_RX_DROP); 3298183561Syongari } 3299183561Syongari 3300183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3301183561Syongari stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST); 3302183561Syongari stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST); 3303255648Sdelphij stats->tx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST); 3304183561Syongari } 3305183561Syongari} 3306215132Syongari 3307215132Syongari 3308215132Syongaristatic void 3309215132Syongarinfe_set_linkspeed(struct nfe_softc *sc) 3310215132Syongari{ 3311215132Syongari struct mii_softc *miisc; 3312215132Syongari struct mii_data *mii; 3313215132Syongari int aneg, i, phyno; 3314215132Syongari 3315215132Syongari NFE_LOCK_ASSERT(sc); 3316215132Syongari 3317215132Syongari mii = device_get_softc(sc->nfe_miibus); 3318215132Syongari mii_pollstat(mii); 3319215132Syongari aneg = 0; 3320215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 3321215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 3322215132Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 3323215132Syongari case IFM_10_T: 3324215132Syongari case IFM_100_TX: 3325215132Syongari return; 3326215132Syongari case IFM_1000_T: 3327215132Syongari aneg++; 3328215132Syongari break; 3329215132Syongari default: 3330215132Syongari break; 3331215132Syongari } 3332215132Syongari } 3333221407Smarius miisc = LIST_FIRST(&mii->mii_phys); 3334221407Smarius phyno = miisc->mii_phy; 3335221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 3336221407Smarius PHY_RESET(miisc); 3337215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0); 3338215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3339215132Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 3340215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3341215132Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 3342215132Syongari DELAY(1000); 3343215132Syongari if (aneg != 0) { 3344215132Syongari /* 3345215132Syongari * Poll link state until nfe(4) get a 10/100Mbps link. 3346215132Syongari */ 3347215132Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 3348215132Syongari mii_pollstat(mii); 3349215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 3350215132Syongari == (IFM_ACTIVE | IFM_AVALID)) { 3351215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 3352215132Syongari case IFM_10_T: 3353215132Syongari case IFM_100_TX: 3354215132Syongari nfe_mac_config(sc, mii); 3355215132Syongari return; 3356215132Syongari default: 3357215132Syongari break; 3358215132Syongari } 3359215132Syongari } 3360215132Syongari NFE_UNLOCK(sc); 3361215132Syongari pause("nfelnk", hz); 3362215132Syongari NFE_LOCK(sc); 3363215132Syongari } 3364215132Syongari if (i == MII_ANEGTICKS_GIGE) 3365215132Syongari device_printf(sc->nfe_dev, 3366215132Syongari "establishing a link failed, WOL may not work!"); 3367215132Syongari } 3368215132Syongari /* 3369215132Syongari * No link, force MAC to have 100Mbps, full-duplex link. 3370215132Syongari * This is the last resort and may/may not work. 3371215132Syongari */ 3372215132Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 3373215132Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 3374215132Syongari nfe_mac_config(sc, mii); 3375215132Syongari} 3376215132Syongari 3377215132Syongari 3378215132Syongaristatic void 3379215132Syongarinfe_set_wol(struct nfe_softc *sc) 3380215132Syongari{ 3381268131Smarcel if_t ifp; 3382215132Syongari uint32_t wolctl; 3383215132Syongari int pmc; 3384215132Syongari uint16_t pmstat; 3385215132Syongari 3386215132Syongari NFE_LOCK_ASSERT(sc); 3387215132Syongari 3388219902Sjhb if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0) 3389215132Syongari return; 3390215132Syongari ifp = sc->nfe_ifp; 3391268131Smarcel if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) 3392215132Syongari wolctl = NFE_WOL_MAGIC; 3393215132Syongari else 3394215132Syongari wolctl = 0; 3395215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, wolctl); 3396268131Smarcel if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) { 3397215132Syongari nfe_set_linkspeed(sc); 3398215132Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) != 0) 3399215132Syongari NFE_WRITE(sc, NFE_PWR2_CTL, 3400215132Syongari NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS); 3401215132Syongari /* Enable RX. */ 3402215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0); 3403215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0); 3404215132Syongari NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) | 3405215132Syongari NFE_RX_START); 3406215132Syongari } 3407215132Syongari /* Request PME if WOL is requested. */ 3408215132Syongari pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2); 3409215132Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 3410268131Smarcel if ((if_getcapenable(ifp) & IFCAP_WOL) != 0) 3411215132Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 3412215132Syongari pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 3413215132Syongari} 3414