if_nfe.c revision 266270
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 266270 2014-05-16 21:19:17Z brueffer $"); 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 *); 91163503Sobrienstatic int nfe_ioctl(struct ifnet *, 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 *); 104159967Sobrienstatic void nfe_start(struct ifnet *); 105216925Sjhbstatic void nfe_start_locked(struct ifnet *); 106159967Sobrienstatic void nfe_watchdog(struct ifnet *); 107159967Sobrienstatic void nfe_init(void *); 108159967Sobrienstatic void nfe_init_locked(void *); 109170589Syongaristatic void nfe_stop(struct ifnet *); 110159967Sobrienstatic int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 111171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 112170589Syongaristatic int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 113170589Syongaristatic int nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 114159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 115170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 116159967Sobrienstatic int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 117170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 118159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 119159967Sobrienstatic int nfe_ifmedia_upd(struct ifnet *); 120159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 121159967Sobrienstatic void nfe_tick(void *); 122170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 123170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *); 124170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); 125159952Sobrien 126170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 127170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); 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; 348264293Syongari m = getenv("smbios.planar.maker"); 349264293Syongari p = 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; 367159952Sobrien struct ifnet *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 573164650Sobrien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 574164650Sobrien if (ifp == NULL) { 575170589Syongari device_printf(dev, "can not if_alloc()\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 593159952Sobrien ifp->if_softc = sc; 594159967Sobrien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 595159952Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 596159952Sobrien ifp->if_ioctl = nfe_ioctl; 597159952Sobrien ifp->if_start = nfe_start; 598170589Syongari ifp->if_hwassist = 0; 599170589Syongari ifp->if_capabilities = 0; 600159952Sobrien ifp->if_init = nfe_init; 601170589Syongari IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1); 602170589Syongari ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1; 603170589Syongari IFQ_SET_READY(&ifp->if_snd); 604159952Sobrien 605170589Syongari if (sc->nfe_flags & NFE_HW_CSUM) { 606170589Syongari ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4; 607170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO; 608170589Syongari } 609170589Syongari ifp->if_capenable = ifp->if_capabilities; 610164650Sobrien 611170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 612170589Syongari /* VLAN capability setup. */ 613170589Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 614170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 615159952Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 616170589Syongari if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0) 617215432Syongari ifp->if_capabilities |= IFCAP_VLAN_HWCSUM | 618215432Syongari IFCAP_VLAN_HWTSO; 619159952Sobrien } 620215132Syongari 621219902Sjhb if (pci_find_cap(dev, PCIY_PMG, ®) == 0) 622215132Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC; 623159967Sobrien ifp->if_capenable = ifp->if_capabilities; 624159952Sobrien 625170589Syongari /* 626170589Syongari * Tell the upper layer(s) we support long frames. 627170589Syongari * Must appear after the call to ether_ifattach() because 628170589Syongari * ether_ifattach() sets ifi_hdrlen to the default value. 629170589Syongari */ 630170589Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 631170589Syongari 632159967Sobrien#ifdef DEVICE_POLLING 633159967Sobrien ifp->if_capabilities |= IFCAP_POLLING; 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 } 645213894Smarius error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd, 646264293Syongari nfe_ifmedia_sts, BMSR_DEFCAPMASK, phyloc, MII_OFFSET_ANY, 647215297Smarius MIIF_DOPAUSE); 648213894Smarius if (error != 0) { 649213894Smarius device_printf(dev, "attaching PHYs failed\n"); 650159967Sobrien goto fail; 651159967Sobrien } 652159967Sobrien 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; 677159967Sobrien 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; 693163503Sobrien struct ifnet *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 702170589Syongari if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 703159967Sobrien ether_poll_deregister(ifp); 704159967Sobrien#endif 705159967Sobrien if (device_is_attached(dev)) { 706164649Sobrien NFE_LOCK(sc); 707170589Syongari nfe_stop(ifp); 708159967Sobrien ifp->if_flags &= ~IFF_UP; 709164649Sobrien NFE_UNLOCK(sc); 710159967Sobrien callout_drain(&sc->nfe_stat_ch); 711159967Sobrien 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); 723159967Sobrien 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; 808170589Syongari struct ifnet *ifp; 809170589Syongari 810170589Syongari sc = device_get_softc(dev); 811170589Syongari 812170589Syongari NFE_LOCK(sc); 813215132Syongari nfe_power(sc); 814170589Syongari ifp = sc->nfe_ifp; 815170589Syongari if (ifp->if_flags & 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 */ 842215327Syongari maker = getenv("smbios.planar.maker"); 843215327Syongari product = 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; 895170589Syongari struct ifnet *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); 920215132Syongari if (sc->nfe_link != 0 && (ifp->if_drv_flags & 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 ring->rx_desc_map = NULL; 1414170589Syongari } 1415170589Syongari if (ring->rx_desc_tag != NULL) { 1416159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 1417170589Syongari ring->rx_desc_tag = NULL; 1418159967Sobrien } 1419170589Syongari} 1420159967Sobrien 1421164650Sobrien 1422170589Syongaristatic void 1423170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1424170589Syongari{ 1425170589Syongari struct nfe_rx_data *data; 1426170589Syongari void *desc; 1427170589Syongari int i, descsize; 1428170589Syongari 1429170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1430170589Syongari return; 1431170589Syongari 1432170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1433170589Syongari desc = ring->jdesc64; 1434170589Syongari descsize = sizeof (struct nfe_desc64); 1435170589Syongari } else { 1436170589Syongari desc = ring->jdesc32; 1437170589Syongari descsize = sizeof (struct nfe_desc32); 1438170589Syongari } 1439170589Syongari 1440170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1441170589Syongari data = &ring->jdata[i]; 1442164651Sobrien if (data->rx_data_map != NULL) { 1443170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1444164651Sobrien data->rx_data_map); 1445170589Syongari data->rx_data_map = NULL; 1446164651Sobrien } 1447170589Syongari if (data->m != NULL) { 1448164651Sobrien m_freem(data->m); 1449170589Syongari data->m = NULL; 1450170589Syongari } 1451164651Sobrien } 1452170589Syongari if (ring->jrx_data_tag != NULL) { 1453170589Syongari if (ring->jrx_spare_map != NULL) { 1454170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1455170589Syongari ring->jrx_spare_map); 1456170589Syongari ring->jrx_spare_map = NULL; 1457170589Syongari } 1458170589Syongari bus_dma_tag_destroy(ring->jrx_data_tag); 1459170589Syongari ring->jrx_data_tag = NULL; 1460170589Syongari } 1461170589Syongari 1462170589Syongari if (desc != NULL) { 1463170589Syongari bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1464170589Syongari bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1465170589Syongari ring->jdesc64 = NULL; 1466170589Syongari ring->jdesc32 = NULL; 1467170589Syongari ring->jrx_desc_map = NULL; 1468170589Syongari } 1469176859Syongari 1470170589Syongari if (ring->jrx_desc_tag != NULL) { 1471170589Syongari bus_dma_tag_destroy(ring->jrx_desc_tag); 1472170589Syongari ring->jrx_desc_tag = NULL; 1473170589Syongari } 1474159952Sobrien} 1475159952Sobrien 1476163503Sobrien 1477159967Sobrienstatic int 1478159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1479159952Sobrien{ 1480170589Syongari struct nfe_dmamap_arg ctx; 1481159967Sobrien int i, error; 1482170589Syongari void *desc; 1483159967Sobrien int descsize; 1484159952Sobrien 1485159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1486170589Syongari desc = ring->desc64; 1487159967Sobrien descsize = sizeof (struct nfe_desc64); 1488159967Sobrien } else { 1489170589Syongari desc = ring->desc32; 1490159967Sobrien descsize = sizeof (struct nfe_desc32); 1491159967Sobrien } 1492159952Sobrien 1493159967Sobrien ring->queued = 0; 1494159967Sobrien ring->cur = ring->next = 0; 1495159967Sobrien 1496163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1497170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1498170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1499170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1500170589Syongari NULL, NULL, /* filter, filterarg */ 1501170589Syongari NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1502170589Syongari NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1503170589Syongari 0, /* flags */ 1504170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1505170589Syongari &ring->tx_desc_tag); 1506159967Sobrien if (error != 0) { 1507170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1508159967Sobrien goto fail; 1509159952Sobrien } 1510159952Sobrien 1511170589Syongari error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1512170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1513159967Sobrien if (error != 0) { 1514170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1515159967Sobrien goto fail; 1516159967Sobrien } 1517170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1518170589Syongari ring->desc64 = desc; 1519170589Syongari else 1520170589Syongari ring->desc32 = desc; 1521159967Sobrien 1522170589Syongari ctx.nfe_busaddr = 0; 1523170589Syongari error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1524170589Syongari NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1525159967Sobrien if (error != 0) { 1526170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1527159967Sobrien goto fail; 1528159967Sobrien } 1529170589Syongari ring->physaddr = ctx.nfe_busaddr; 1530159967Sobrien 1531163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1532170589Syongari 1, 0, 1533170589Syongari BUS_SPACE_MAXADDR, 1534170589Syongari BUS_SPACE_MAXADDR, 1535170589Syongari NULL, NULL, 1536170595Syongari NFE_TSO_MAXSIZE, 1537170589Syongari NFE_MAX_SCATTER, 1538170595Syongari NFE_TSO_MAXSGSIZE, 1539170589Syongari 0, 1540170589Syongari NULL, NULL, 1541170589Syongari &ring->tx_data_tag); 1542159967Sobrien if (error != 0) { 1543170589Syongari device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1544170589Syongari goto fail; 1545159967Sobrien } 1546159967Sobrien 1547159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1548163503Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, 1549163503Sobrien &ring->data[i].tx_data_map); 1550159967Sobrien if (error != 0) { 1551170589Syongari device_printf(sc->nfe_dev, 1552170589Syongari "could not create Tx DMA map\n"); 1553159967Sobrien goto fail; 1554159967Sobrien } 1555159967Sobrien } 1556159967Sobrien 1557170589Syongarifail: 1558170589Syongari return (error); 1559159967Sobrien} 1560159967Sobrien 1561159967Sobrien 1562159967Sobrienstatic void 1563170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1564159967Sobrien{ 1565170589Syongari void *desc; 1566170589Syongari size_t descsize; 1567159967Sobrien 1568170589Syongari sc->nfe_force_tx = 0; 1569170589Syongari ring->queued = 0; 1570170589Syongari ring->cur = ring->next = 0; 1571170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1572170589Syongari desc = ring->desc64; 1573170589Syongari descsize = sizeof (struct nfe_desc64); 1574170589Syongari } else { 1575170589Syongari desc = ring->desc32; 1576170589Syongari descsize = sizeof (struct nfe_desc32); 1577159967Sobrien } 1578170589Syongari bzero(desc, descsize * NFE_TX_RING_COUNT); 1579159967Sobrien 1580163503Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1581170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1582159967Sobrien} 1583159967Sobrien 1584163503Sobrien 1585159967Sobrienstatic void 1586159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1587159967Sobrien{ 1588159967Sobrien struct nfe_tx_data *data; 1589159967Sobrien void *desc; 1590159967Sobrien int i, descsize; 1591159967Sobrien 1592159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1593159967Sobrien desc = ring->desc64; 1594159967Sobrien descsize = sizeof (struct nfe_desc64); 1595159967Sobrien } else { 1596159967Sobrien desc = ring->desc32; 1597159967Sobrien descsize = sizeof (struct nfe_desc32); 1598159967Sobrien } 1599159967Sobrien 1600159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1601159967Sobrien data = &ring->data[i]; 1602159967Sobrien 1603159967Sobrien if (data->m != NULL) { 1604170589Syongari bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1605163503Sobrien BUS_DMASYNC_POSTWRITE); 1606170589Syongari bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1607159967Sobrien m_freem(data->m); 1608170589Syongari data->m = NULL; 1609159967Sobrien } 1610170589Syongari if (data->tx_data_map != NULL) { 1611170589Syongari bus_dmamap_destroy(ring->tx_data_tag, 1612170589Syongari data->tx_data_map); 1613170589Syongari data->tx_data_map = NULL; 1614170589Syongari } 1615159967Sobrien } 1616159967Sobrien 1617170589Syongari if (ring->tx_data_tag != NULL) { 1618170589Syongari bus_dma_tag_destroy(ring->tx_data_tag); 1619170589Syongari ring->tx_data_tag = NULL; 1620159967Sobrien } 1621159967Sobrien 1622170589Syongari if (desc != NULL) { 1623170589Syongari bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1624170589Syongari BUS_DMASYNC_POSTWRITE); 1625170589Syongari bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1626170589Syongari bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1627170589Syongari ring->desc64 = NULL; 1628170589Syongari ring->desc32 = NULL; 1629170589Syongari ring->tx_desc_map = NULL; 1630170589Syongari bus_dma_tag_destroy(ring->tx_desc_tag); 1631170589Syongari ring->tx_desc_tag = NULL; 1632170589Syongari } 1633159967Sobrien} 1634159967Sobrien 1635159967Sobrien#ifdef DEVICE_POLLING 1636159967Sobrienstatic poll_handler_t nfe_poll; 1637159967Sobrien 1638163503Sobrien 1639193096Sattiliostatic int 1640159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1641159967Sobrien{ 1642164360Sobrien struct nfe_softc *sc = ifp->if_softc; 1643170589Syongari uint32_t r; 1644193096Sattilio int rx_npkts = 0; 1645159967Sobrien 1646159967Sobrien NFE_LOCK(sc); 1647159967Sobrien 1648159967Sobrien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1649170589Syongari NFE_UNLOCK(sc); 1650193096Sattilio return (rx_npkts); 1651159967Sobrien } 1652159967Sobrien 1653171559Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1654193096Sattilio rx_npkts = nfe_jrxeof(sc, count, &rx_npkts); 1655171559Syongari else 1656193096Sattilio rx_npkts = nfe_rxeof(sc, count, &rx_npkts); 1657159967Sobrien nfe_txeof(sc); 1658159967Sobrien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1659216925Sjhb nfe_start_locked(ifp); 1660159967Sobrien 1661159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1662170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1663170589Syongari NFE_UNLOCK(sc); 1664193096Sattilio return (rx_npkts); 1665163503Sobrien } 1666170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1667159967Sobrien 1668163503Sobrien if (r & NFE_IRQ_LINK) { 1669163503Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1670163503Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1671170589Syongari DPRINTF(sc, "link state changed\n"); 1672163503Sobrien } 1673159967Sobrien } 1674170589Syongari NFE_UNLOCK(sc); 1675193096Sattilio return (rx_npkts); 1676159967Sobrien} 1677159967Sobrien#endif /* DEVICE_POLLING */ 1678159967Sobrien 1679170589Syongaristatic void 1680170589Syongarinfe_set_intr(struct nfe_softc *sc) 1681170589Syongari{ 1682159967Sobrien 1683170589Syongari if (sc->nfe_msi != 0) 1684170589Syongari NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1685170589Syongari} 1686170589Syongari 1687170589Syongari 1688170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */ 1689170589Syongaristatic __inline void 1690170589Syongarinfe_enable_intr(struct nfe_softc *sc) 1691170589Syongari{ 1692170589Syongari 1693170589Syongari if (sc->nfe_msix != 0) { 1694170589Syongari /* XXX Should have a better way to enable interrupts! */ 1695170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1696170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1697170589Syongari } else 1698170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1699170589Syongari} 1700170589Syongari 1701170589Syongari 1702170589Syongaristatic __inline void 1703170589Syongarinfe_disable_intr(struct nfe_softc *sc) 1704170589Syongari{ 1705170589Syongari 1706170589Syongari if (sc->nfe_msix != 0) { 1707170589Syongari /* XXX Should have a better way to disable interrupts! */ 1708170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1709170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1710170589Syongari } else 1711170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1712170589Syongari} 1713170589Syongari 1714170589Syongari 1715159967Sobrienstatic int 1716159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1717159967Sobrien{ 1718170589Syongari struct nfe_softc *sc; 1719170589Syongari struct ifreq *ifr; 1720163503Sobrien struct mii_data *mii; 1721170589Syongari int error, init, mask; 1722159967Sobrien 1723170589Syongari sc = ifp->if_softc; 1724170589Syongari ifr = (struct ifreq *) data; 1725170589Syongari error = 0; 1726170589Syongari init = 0; 1727159952Sobrien switch (cmd) { 1728159952Sobrien case SIOCSIFMTU: 1729170589Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1730159952Sobrien error = EINVAL; 1731170589Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 1732171559Syongari if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) || 1733171559Syongari (sc->nfe_jumbo_disable != 0)) && 1734170589Syongari ifr->ifr_mtu > ETHERMTU) 1735170589Syongari error = EINVAL; 1736170589Syongari else { 1737170589Syongari NFE_LOCK(sc); 1738170589Syongari ifp->if_mtu = ifr->ifr_mtu; 1739217794Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1740217794Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1741170589Syongari nfe_init_locked(sc); 1742217794Syongari } 1743170589Syongari NFE_UNLOCK(sc); 1744164650Sobrien } 1745164650Sobrien } 1746159952Sobrien break; 1747159952Sobrien case SIOCSIFFLAGS: 1748159967Sobrien NFE_LOCK(sc); 1749159952Sobrien if (ifp->if_flags & IFF_UP) { 1750159952Sobrien /* 1751159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1752159952Sobrien * don't do a full re-init of the chip, just update 1753159952Sobrien * the Rx filter. 1754159952Sobrien */ 1755159967Sobrien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1756159967Sobrien ((ifp->if_flags ^ sc->nfe_if_flags) & 1757159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1758159952Sobrien nfe_setmulti(sc); 1759159967Sobrien else 1760159967Sobrien nfe_init_locked(sc); 1761159952Sobrien } else { 1762159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1763170589Syongari nfe_stop(ifp); 1764159952Sobrien } 1765159967Sobrien sc->nfe_if_flags = ifp->if_flags; 1766159967Sobrien NFE_UNLOCK(sc); 1767159967Sobrien error = 0; 1768159952Sobrien break; 1769159952Sobrien case SIOCADDMULTI: 1770159952Sobrien case SIOCDELMULTI: 1771170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1772159967Sobrien NFE_LOCK(sc); 1773159967Sobrien nfe_setmulti(sc); 1774159967Sobrien NFE_UNLOCK(sc); 1775159952Sobrien error = 0; 1776159952Sobrien } 1777159952Sobrien break; 1778159952Sobrien case SIOCSIFMEDIA: 1779159952Sobrien case SIOCGIFMEDIA: 1780159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1781159967Sobrien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1782159952Sobrien break; 1783159967Sobrien case SIOCSIFCAP: 1784170589Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1785159967Sobrien#ifdef DEVICE_POLLING 1786170589Syongari if ((mask & IFCAP_POLLING) != 0) { 1787170589Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1788159967Sobrien error = ether_poll_register(nfe_poll, ifp); 1789159967Sobrien if (error) 1790170589Syongari break; 1791159967Sobrien NFE_LOCK(sc); 1792170589Syongari nfe_disable_intr(sc); 1793163503Sobrien ifp->if_capenable |= IFCAP_POLLING; 1794159967Sobrien NFE_UNLOCK(sc); 1795159967Sobrien } else { 1796159967Sobrien error = ether_poll_deregister(ifp); 1797159967Sobrien /* Enable interrupt even in error case */ 1798159967Sobrien NFE_LOCK(sc); 1799170589Syongari nfe_enable_intr(sc); 1800159967Sobrien ifp->if_capenable &= ~IFCAP_POLLING; 1801159967Sobrien NFE_UNLOCK(sc); 1802159967Sobrien } 1803159967Sobrien } 1804163503Sobrien#endif /* DEVICE_POLLING */ 1805215132Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 1806215132Syongari (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) 1807215132Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 1808215432Syongari if ((mask & IFCAP_TXCSUM) != 0 && 1809215432Syongari (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 1810215432Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 1811215432Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1812170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES; 1813159967Sobrien else 1814170589Syongari ifp->if_hwassist &= ~NFE_CSUM_FEATURES; 1815215432Syongari } 1816215432Syongari if ((mask & IFCAP_RXCSUM) != 0 && 1817215432Syongari (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 1818215432Syongari ifp->if_capenable ^= IFCAP_RXCSUM; 1819170589Syongari init++; 1820159967Sobrien } 1821215432Syongari if ((mask & IFCAP_TSO4) != 0 && 1822215432Syongari (ifp->if_capabilities & IFCAP_TSO4) != 0) { 1823215432Syongari ifp->if_capenable ^= IFCAP_TSO4; 1824215432Syongari if ((IFCAP_TSO4 & ifp->if_capenable) != 0) 1825215432Syongari ifp->if_hwassist |= CSUM_TSO; 1826215432Syongari else 1827215432Syongari ifp->if_hwassist &= ~CSUM_TSO; 1828215432Syongari } 1829215432Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 1830215432Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) 1831215432Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1832215432Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 1833215432Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 1834170589Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1835215432Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) 1836215432Syongari ifp->if_capenable &= ~IFCAP_VLAN_HWTSO; 1837170589Syongari init++; 1838170589Syongari } 1839170589Syongari /* 1840170589Syongari * XXX 1841170589Syongari * It seems that VLAN stripping requires Rx checksum offload. 1842170589Syongari * Unfortunately FreeBSD has no way to disable only Rx side 1843170589Syongari * VLAN stripping. So when we know Rx checksum offload is 1844170589Syongari * disabled turn entire hardware VLAN assist off. 1845170589Syongari */ 1846215432Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) { 1847215432Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 1848215432Syongari init++; 1849215432Syongari ifp->if_capenable &= ~(IFCAP_VLAN_HWTAGGING | 1850215432Syongari IFCAP_VLAN_HWTSO); 1851170589Syongari } 1852170589Syongari if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1853170589Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1854164656Sobrien nfe_init(sc); 1855170589Syongari } 1856215432Syongari VLAN_CAPABILITIES(ifp); 1857159967Sobrien break; 1858159952Sobrien default: 1859159967Sobrien error = ether_ioctl(ifp, cmd, data); 1860159967Sobrien break; 1861159952Sobrien } 1862159952Sobrien 1863170589Syongari return (error); 1864159952Sobrien} 1865159952Sobrien 1866159967Sobrien 1867170589Syongaristatic int 1868163503Sobriennfe_intr(void *arg) 1869159967Sobrien{ 1870170589Syongari struct nfe_softc *sc; 1871170589Syongari uint32_t status; 1872170589Syongari 1873170589Syongari sc = (struct nfe_softc *)arg; 1874170589Syongari 1875170589Syongari status = NFE_READ(sc, sc->nfe_irq_status); 1876170589Syongari if (status == 0 || status == 0xffffffff) 1877170589Syongari return (FILTER_STRAY); 1878170589Syongari nfe_disable_intr(sc); 1879173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1880170589Syongari 1881170589Syongari return (FILTER_HANDLED); 1882170589Syongari} 1883170589Syongari 1884170589Syongari 1885170589Syongaristatic void 1886170589Syongarinfe_int_task(void *arg, int pending) 1887170589Syongari{ 1888159967Sobrien struct nfe_softc *sc = arg; 1889159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1890170589Syongari uint32_t r; 1891170589Syongari int domore; 1892159967Sobrien 1893163503Sobrien NFE_LOCK(sc); 1894159967Sobrien 1895170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1896170589Syongari nfe_enable_intr(sc); 1897170589Syongari NFE_UNLOCK(sc); 1898170589Syongari return; /* not for us */ 1899170589Syongari } 1900170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1901170589Syongari 1902170589Syongari DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1903170589Syongari 1904159967Sobrien#ifdef DEVICE_POLLING 1905159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) { 1906159967Sobrien NFE_UNLOCK(sc); 1907159967Sobrien return; 1908159967Sobrien } 1909159967Sobrien#endif 1910159967Sobrien 1911172169Syongari if (r & NFE_IRQ_LINK) { 1912172169Syongari NFE_READ(sc, NFE_PHY_STATUS); 1913172169Syongari NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1914172169Syongari DPRINTF(sc, "link state changed\n"); 1915172169Syongari } 1916172169Syongari 1917170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1918163503Sobrien NFE_UNLOCK(sc); 1919222542Syongari nfe_disable_intr(sc); 1920170589Syongari return; 1921159967Sobrien } 1922159967Sobrien 1923170589Syongari domore = 0; 1924170589Syongari /* check Rx ring */ 1925170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1926193096Sattilio domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL); 1927170589Syongari else 1928193096Sattilio domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL); 1929170589Syongari /* check Tx ring */ 1930170589Syongari nfe_txeof(sc); 1931159967Sobrien 1932170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1933216925Sjhb nfe_start_locked(ifp); 1934159967Sobrien 1935159967Sobrien NFE_UNLOCK(sc); 1936159967Sobrien 1937170589Syongari if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1938173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1939170589Syongari return; 1940170589Syongari } 1941170589Syongari 1942170589Syongari /* Reenable interrupts. */ 1943170589Syongari nfe_enable_intr(sc); 1944159967Sobrien} 1945159967Sobrien 1946163503Sobrien 1947170589Syongaristatic __inline void 1948170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1949159952Sobrien{ 1950170589Syongari struct nfe_desc32 *desc32; 1951170589Syongari struct nfe_desc64 *desc64; 1952170589Syongari struct nfe_rx_data *data; 1953170589Syongari struct mbuf *m; 1954163503Sobrien 1955170589Syongari data = &sc->rxq.data[idx]; 1956170589Syongari m = data->m; 1957170589Syongari 1958170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1959170589Syongari desc64 = &sc->rxq.desc64[idx]; 1960170589Syongari /* VLAN packet may have overwritten it. */ 1961170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1962170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1963170589Syongari desc64->length = htole16(m->m_len); 1964170589Syongari desc64->flags = htole16(NFE_RX_READY); 1965170589Syongari } else { 1966170589Syongari desc32 = &sc->rxq.desc32[idx]; 1967170589Syongari desc32->length = htole16(m->m_len); 1968170589Syongari desc32->flags = htole16(NFE_RX_READY); 1969170589Syongari } 1970159952Sobrien} 1971159952Sobrien 1972163503Sobrien 1973170589Syongaristatic __inline void 1974170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1975159952Sobrien{ 1976170589Syongari struct nfe_desc32 *desc32; 1977170589Syongari struct nfe_desc64 *desc64; 1978170589Syongari struct nfe_rx_data *data; 1979170589Syongari struct mbuf *m; 1980163503Sobrien 1981170589Syongari data = &sc->jrxq.jdata[idx]; 1982170589Syongari m = data->m; 1983170589Syongari 1984170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1985170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 1986170589Syongari /* VLAN packet may have overwritten it. */ 1987170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1988170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1989170589Syongari desc64->length = htole16(m->m_len); 1990170589Syongari desc64->flags = htole16(NFE_RX_READY); 1991170589Syongari } else { 1992170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 1993170589Syongari desc32->length = htole16(m->m_len); 1994170589Syongari desc32->flags = htole16(NFE_RX_READY); 1995170589Syongari } 1996159952Sobrien} 1997159952Sobrien 1998163503Sobrien 1999170589Syongaristatic int 2000170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx) 2001159952Sobrien{ 2002170589Syongari struct nfe_rx_data *data; 2003170589Syongari struct nfe_desc32 *desc32; 2004170589Syongari struct nfe_desc64 *desc64; 2005170589Syongari struct mbuf *m; 2006170589Syongari bus_dma_segment_t segs[1]; 2007170589Syongari bus_dmamap_t map; 2008170589Syongari int nsegs; 2009163503Sobrien 2010243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2011170589Syongari if (m == NULL) 2012170589Syongari return (ENOBUFS); 2013159952Sobrien 2014170589Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 2015170589Syongari m_adj(m, ETHER_ALIGN); 2016163503Sobrien 2017170589Syongari if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 2018170589Syongari m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2019170589Syongari m_freem(m); 2020170589Syongari return (ENOBUFS); 2021170589Syongari } 2022170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2023163503Sobrien 2024170589Syongari data = &sc->rxq.data[idx]; 2025170589Syongari if (data->m != NULL) { 2026170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2027170589Syongari BUS_DMASYNC_POSTREAD); 2028170589Syongari bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 2029170589Syongari } 2030170589Syongari map = data->rx_data_map; 2031170589Syongari data->rx_data_map = sc->rxq.rx_spare_map; 2032170589Syongari sc->rxq.rx_spare_map = map; 2033170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2034170589Syongari BUS_DMASYNC_PREREAD); 2035170589Syongari data->paddr = segs[0].ds_addr; 2036170589Syongari data->m = m; 2037170589Syongari /* update mapping address in h/w descriptor */ 2038170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2039170589Syongari desc64 = &sc->rxq.desc64[idx]; 2040170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2041170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2042170589Syongari desc64->length = htole16(segs[0].ds_len); 2043170589Syongari desc64->flags = htole16(NFE_RX_READY); 2044170589Syongari } else { 2045170589Syongari desc32 = &sc->rxq.desc32[idx]; 2046170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2047170589Syongari desc32->length = htole16(segs[0].ds_len); 2048170589Syongari desc32->flags = htole16(NFE_RX_READY); 2049170589Syongari } 2050170589Syongari 2051170589Syongari return (0); 2052159952Sobrien} 2053159952Sobrien 2054163503Sobrien 2055170589Syongaristatic int 2056170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx) 2057159952Sobrien{ 2058170589Syongari struct nfe_rx_data *data; 2059170589Syongari struct nfe_desc32 *desc32; 2060170589Syongari struct nfe_desc64 *desc64; 2061170589Syongari struct mbuf *m; 2062170589Syongari bus_dma_segment_t segs[1]; 2063170589Syongari bus_dmamap_t map; 2064170589Syongari int nsegs; 2065163503Sobrien 2066243857Sglebius m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 2067170589Syongari if (m == NULL) 2068170589Syongari return (ENOBUFS); 2069170589Syongari if ((m->m_flags & M_EXT) == 0) { 2070170589Syongari m_freem(m); 2071170589Syongari return (ENOBUFS); 2072170589Syongari } 2073176859Syongari m->m_pkthdr.len = m->m_len = MJUM9BYTES; 2074170589Syongari m_adj(m, ETHER_ALIGN); 2075159952Sobrien 2076170589Syongari if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 2077170589Syongari sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2078170589Syongari m_freem(m); 2079170589Syongari return (ENOBUFS); 2080170589Syongari } 2081170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2082163503Sobrien 2083170589Syongari data = &sc->jrxq.jdata[idx]; 2084170589Syongari if (data->m != NULL) { 2085170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2086170589Syongari BUS_DMASYNC_POSTREAD); 2087170589Syongari bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 2088170589Syongari } 2089170589Syongari map = data->rx_data_map; 2090170589Syongari data->rx_data_map = sc->jrxq.jrx_spare_map; 2091170589Syongari sc->jrxq.jrx_spare_map = map; 2092170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2093170589Syongari BUS_DMASYNC_PREREAD); 2094170589Syongari data->paddr = segs[0].ds_addr; 2095170589Syongari data->m = m; 2096170589Syongari /* update mapping address in h/w descriptor */ 2097170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2098170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 2099170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2100170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2101170589Syongari desc64->length = htole16(segs[0].ds_len); 2102170589Syongari desc64->flags = htole16(NFE_RX_READY); 2103170589Syongari } else { 2104170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 2105170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2106170589Syongari desc32->length = htole16(segs[0].ds_len); 2107170589Syongari desc32->flags = htole16(NFE_RX_READY); 2108170589Syongari } 2109159967Sobrien 2110170589Syongari return (0); 2111159952Sobrien} 2112159952Sobrien 2113163503Sobrien 2114170589Syongaristatic int 2115193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2116159952Sobrien{ 2117159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2118170589Syongari struct nfe_desc32 *desc32; 2119170589Syongari struct nfe_desc64 *desc64; 2120159952Sobrien struct nfe_rx_data *data; 2121170589Syongari struct mbuf *m; 2122170589Syongari uint16_t flags; 2123193096Sattilio int len, prog, rx_npkts; 2124170589Syongari uint32_t vtag = 0; 2125159952Sobrien 2126193096Sattilio rx_npkts = 0; 2127159967Sobrien NFE_LOCK_ASSERT(sc); 2128159967Sobrien 2129170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2130170589Syongari BUS_DMASYNC_POSTREAD); 2131159967Sobrien 2132170589Syongari for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2133170589Syongari if (count <= 0) 2134170589Syongari break; 2135170589Syongari count--; 2136159967Sobrien 2137159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 2138159952Sobrien 2139159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2140159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2141170589Syongari vtag = le32toh(desc64->physaddr[1]); 2142170589Syongari flags = le16toh(desc64->flags); 2143170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2144159952Sobrien } else { 2145159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2146170589Syongari flags = le16toh(desc32->flags); 2147170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2148159952Sobrien } 2149159952Sobrien 2150159952Sobrien if (flags & NFE_RX_READY) 2151159952Sobrien break; 2152170589Syongari prog++; 2153159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2154170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2155170589Syongari ifp->if_ierrors++; 2156170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2157170589Syongari continue; 2158170589Syongari } 2159159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2160159952Sobrien flags &= ~NFE_RX_ERROR; 2161159952Sobrien len--; /* fix buffer length */ 2162159952Sobrien } 2163159952Sobrien } else { 2164170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2165170589Syongari ifp->if_ierrors++; 2166170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2167170589Syongari continue; 2168170589Syongari } 2169159952Sobrien 2170159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2171159952Sobrien flags &= ~NFE_RX_ERROR; 2172159952Sobrien len--; /* fix buffer length */ 2173159952Sobrien } 2174159952Sobrien } 2175159952Sobrien 2176159952Sobrien if (flags & NFE_RX_ERROR) { 2177159952Sobrien ifp->if_ierrors++; 2178170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2179170589Syongari continue; 2180159952Sobrien } 2181159952Sobrien 2182170589Syongari m = data->m; 2183170589Syongari if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2184170589Syongari ifp->if_iqdrops++; 2185170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2186170589Syongari continue; 2187159952Sobrien } 2188159952Sobrien 2189170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2190170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2191170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2192170589Syongari m->m_flags |= M_VLANTAG; 2193164651Sobrien } 2194159952Sobrien 2195170589Syongari m->m_pkthdr.len = m->m_len = len; 2196170589Syongari m->m_pkthdr.rcvif = ifp; 2197164651Sobrien 2198170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2199170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2200170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2201170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2202170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2203170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2204170589Syongari m->m_pkthdr.csum_flags |= 2205170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2206170589Syongari m->m_pkthdr.csum_data = 0xffff; 2207170589Syongari } 2208159952Sobrien } 2209170589Syongari } 2210170589Syongari 2211170589Syongari ifp->if_ipackets++; 2212170589Syongari 2213170589Syongari NFE_UNLOCK(sc); 2214170589Syongari (*ifp->if_input)(ifp, m); 2215170589Syongari NFE_LOCK(sc); 2216193096Sattilio rx_npkts++; 2217170589Syongari } 2218170589Syongari 2219170589Syongari if (prog > 0) 2220170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2221170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2222170589Syongari 2223193096Sattilio if (rx_npktsp != NULL) 2224193096Sattilio *rx_npktsp = rx_npkts; 2225170589Syongari return (count > 0 ? 0 : EAGAIN); 2226170589Syongari} 2227170589Syongari 2228170589Syongari 2229170589Syongaristatic int 2230193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2231170589Syongari{ 2232170589Syongari struct ifnet *ifp = sc->nfe_ifp; 2233170589Syongari struct nfe_desc32 *desc32; 2234170589Syongari struct nfe_desc64 *desc64; 2235170589Syongari struct nfe_rx_data *data; 2236170589Syongari struct mbuf *m; 2237170589Syongari uint16_t flags; 2238193096Sattilio int len, prog, rx_npkts; 2239170589Syongari uint32_t vtag = 0; 2240170589Syongari 2241193096Sattilio rx_npkts = 0; 2242170589Syongari NFE_LOCK_ASSERT(sc); 2243170589Syongari 2244170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2245170589Syongari BUS_DMASYNC_POSTREAD); 2246170589Syongari 2247170589Syongari for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2248170589Syongari vtag = 0) { 2249170589Syongari if (count <= 0) 2250170589Syongari break; 2251170589Syongari count--; 2252170589Syongari 2253170589Syongari data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2254170589Syongari 2255170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2256170589Syongari desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2257170589Syongari vtag = le32toh(desc64->physaddr[1]); 2258170589Syongari flags = le16toh(desc64->flags); 2259170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2260170589Syongari } else { 2261170589Syongari desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2262170589Syongari flags = le16toh(desc32->flags); 2263170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2264170589Syongari } 2265170589Syongari 2266170589Syongari if (flags & NFE_RX_READY) 2267170589Syongari break; 2268170589Syongari prog++; 2269170589Syongari if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2270170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2271170589Syongari ifp->if_ierrors++; 2272170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2273170589Syongari continue; 2274170589Syongari } 2275170589Syongari if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2276170589Syongari flags &= ~NFE_RX_ERROR; 2277170589Syongari len--; /* fix buffer length */ 2278170589Syongari } 2279170589Syongari } else { 2280170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2281170589Syongari ifp->if_ierrors++; 2282170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2283170589Syongari continue; 2284170589Syongari } 2285170589Syongari 2286170589Syongari if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2287170589Syongari flags &= ~NFE_RX_ERROR; 2288170589Syongari len--; /* fix buffer length */ 2289170589Syongari } 2290170589Syongari } 2291170589Syongari 2292170589Syongari if (flags & NFE_RX_ERROR) { 2293164651Sobrien ifp->if_ierrors++; 2294170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2295170589Syongari continue; 2296164651Sobrien } 2297159952Sobrien 2298159952Sobrien m = data->m; 2299170589Syongari if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2300170589Syongari ifp->if_iqdrops++; 2301170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2302170589Syongari continue; 2303170589Syongari } 2304159952Sobrien 2305170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2306170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2307170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2308170589Syongari m->m_flags |= M_VLANTAG; 2309170589Syongari } 2310170589Syongari 2311159952Sobrien m->m_pkthdr.len = m->m_len = len; 2312159952Sobrien m->m_pkthdr.rcvif = ifp; 2313159952Sobrien 2314170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2315170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2316170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2317159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2318170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2319170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2320170589Syongari m->m_pkthdr.csum_flags |= 2321170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2322170589Syongari m->m_pkthdr.csum_data = 0xffff; 2323170589Syongari } 2324159967Sobrien } 2325159952Sobrien } 2326159952Sobrien 2327159952Sobrien ifp->if_ipackets++; 2328159952Sobrien 2329159967Sobrien NFE_UNLOCK(sc); 2330159967Sobrien (*ifp->if_input)(ifp, m); 2331159967Sobrien NFE_LOCK(sc); 2332193096Sattilio rx_npkts++; 2333170589Syongari } 2334159967Sobrien 2335170589Syongari if (prog > 0) 2336170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2337170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2338159952Sobrien 2339193096Sattilio if (rx_npktsp != NULL) 2340193096Sattilio *rx_npktsp = rx_npkts; 2341170589Syongari return (count > 0 ? 0 : EAGAIN); 2342159952Sobrien} 2343159952Sobrien 2344163503Sobrien 2345163503Sobrienstatic void 2346163503Sobriennfe_txeof(struct nfe_softc *sc) 2347159952Sobrien{ 2348159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2349159952Sobrien struct nfe_desc32 *desc32; 2350159952Sobrien struct nfe_desc64 *desc64; 2351159952Sobrien struct nfe_tx_data *data = NULL; 2352170589Syongari uint16_t flags; 2353170589Syongari int cons, prog; 2354159952Sobrien 2355159967Sobrien NFE_LOCK_ASSERT(sc); 2356159967Sobrien 2357170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2358170589Syongari BUS_DMASYNC_POSTREAD); 2359170589Syongari 2360170589Syongari prog = 0; 2361170589Syongari for (cons = sc->txq.next; cons != sc->txq.cur; 2362170589Syongari NFE_INC(cons, NFE_TX_RING_COUNT)) { 2363159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2364170589Syongari desc64 = &sc->txq.desc64[cons]; 2365170589Syongari flags = le16toh(desc64->flags); 2366159952Sobrien } else { 2367170589Syongari desc32 = &sc->txq.desc32[cons]; 2368170589Syongari flags = le16toh(desc32->flags); 2369159952Sobrien } 2370159952Sobrien 2371159952Sobrien if (flags & NFE_TX_VALID) 2372159952Sobrien break; 2373159952Sobrien 2374170589Syongari prog++; 2375170589Syongari sc->txq.queued--; 2376170589Syongari data = &sc->txq.data[cons]; 2377159952Sobrien 2378159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2379170589Syongari if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2380170589Syongari continue; 2381159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 2382170589Syongari device_printf(sc->nfe_dev, 2383170589Syongari "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2384159967Sobrien 2385159952Sobrien ifp->if_oerrors++; 2386159952Sobrien } else 2387159952Sobrien ifp->if_opackets++; 2388159952Sobrien } else { 2389170589Syongari if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2390170589Syongari continue; 2391159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 2392170589Syongari device_printf(sc->nfe_dev, 2393170589Syongari "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2394159952Sobrien ifp->if_oerrors++; 2395159952Sobrien } else 2396159952Sobrien ifp->if_opackets++; 2397159952Sobrien } 2398159952Sobrien 2399159952Sobrien /* last fragment of the mbuf chain transmitted */ 2400170589Syongari KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2401170589Syongari bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2402159967Sobrien BUS_DMASYNC_POSTWRITE); 2403170589Syongari bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2404159952Sobrien m_freem(data->m); 2405159952Sobrien data->m = NULL; 2406159952Sobrien } 2407159952Sobrien 2408170589Syongari if (prog > 0) { 2409170589Syongari sc->nfe_force_tx = 0; 2410170589Syongari sc->txq.next = cons; 2411159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2412170589Syongari if (sc->txq.queued == 0) 2413170589Syongari sc->nfe_watchdog_timer = 0; 2414159952Sobrien } 2415159952Sobrien} 2416159952Sobrien 2417163503Sobrienstatic int 2418170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2419159952Sobrien{ 2420170589Syongari struct nfe_desc32 *desc32 = NULL; 2421170589Syongari struct nfe_desc64 *desc64 = NULL; 2422159952Sobrien bus_dmamap_t map; 2423163503Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2424170589Syongari int error, i, nsegs, prod, si; 2425254803Sandre uint32_t tsosegsz; 2426170589Syongari uint16_t cflags, flags; 2427170589Syongari struct mbuf *m; 2428159952Sobrien 2429170589Syongari prod = si = sc->txq.cur; 2430170589Syongari map = sc->txq.data[prod].tx_data_map; 2431159952Sobrien 2432170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2433159967Sobrien &nsegs, BUS_DMA_NOWAIT); 2434170589Syongari if (error == EFBIG) { 2435243857Sglebius m = m_collapse(*m_head, M_NOWAIT, NFE_MAX_SCATTER); 2436170589Syongari if (m == NULL) { 2437170589Syongari m_freem(*m_head); 2438170589Syongari *m_head = NULL; 2439170589Syongari return (ENOBUFS); 2440170589Syongari } 2441170589Syongari *m_head = m; 2442170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2443170589Syongari *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2444170589Syongari if (error != 0) { 2445170589Syongari m_freem(*m_head); 2446170589Syongari *m_head = NULL; 2447170589Syongari return (ENOBUFS); 2448170589Syongari } 2449170589Syongari } else if (error != 0) 2450170589Syongari return (error); 2451170589Syongari if (nsegs == 0) { 2452170589Syongari m_freem(*m_head); 2453170589Syongari *m_head = NULL; 2454170589Syongari return (EIO); 2455159952Sobrien } 2456159952Sobrien 2457170589Syongari if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2458159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2459170589Syongari return (ENOBUFS); 2460159952Sobrien } 2461159952Sobrien 2462170589Syongari m = *m_head; 2463170589Syongari cflags = flags = 0; 2464254803Sandre tsosegsz = 0; 2465206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2466254803Sandre tsosegsz = (uint32_t)m->m_pkthdr.tso_segsz << 2467206876Syongari NFE_TX_TSO_SHIFT; 2468206876Syongari cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2469206876Syongari cflags |= NFE_TX_TSO; 2470206876Syongari } else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2471170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2472170589Syongari cflags |= NFE_TX_IP_CSUM; 2473170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2474170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2475170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2476170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2477164656Sobrien } 2478159967Sobrien 2479159967Sobrien for (i = 0; i < nsegs; i++) { 2480159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2481170589Syongari desc64 = &sc->txq.desc64[prod]; 2482170589Syongari desc64->physaddr[0] = 2483170589Syongari htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2484170589Syongari desc64->physaddr[1] = 2485170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2486170589Syongari desc64->vtag = 0; 2487159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 2488159952Sobrien desc64->flags = htole16(flags); 2489159952Sobrien } else { 2490170589Syongari desc32 = &sc->txq.desc32[prod]; 2491170589Syongari desc32->physaddr = 2492170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2493159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 2494159952Sobrien desc32->flags = htole16(flags); 2495159952Sobrien } 2496159952Sobrien 2497170589Syongari /* 2498170589Syongari * Setting of the valid bit in the first descriptor is 2499170589Syongari * deferred until the whole chain is fully setup. 2500170589Syongari */ 2501170589Syongari flags |= NFE_TX_VALID; 2502163503Sobrien 2503159952Sobrien sc->txq.queued++; 2504170589Syongari NFE_INC(prod, NFE_TX_RING_COUNT); 2505159952Sobrien } 2506159952Sobrien 2507170589Syongari /* 2508170589Syongari * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2509170589Syongari * csum flags, vtag and TSO belong to the first fragment only. 2510170589Syongari */ 2511159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2512170589Syongari desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2513170589Syongari desc64 = &sc->txq.desc64[si]; 2514170589Syongari if ((m->m_flags & M_VLANTAG) != 0) 2515170589Syongari desc64->vtag = htole32(NFE_TX_VTAG | 2516170589Syongari m->m_pkthdr.ether_vtag); 2517254803Sandre if (tsosegsz != 0) { 2518170589Syongari /* 2519170589Syongari * XXX 2520170589Syongari * The following indicates the descriptor element 2521170589Syongari * is a 32bit quantity. 2522170589Syongari */ 2523254803Sandre desc64->length |= htole16((uint16_t)tsosegsz); 2524254803Sandre desc64->flags |= htole16(tsosegsz >> 16); 2525170589Syongari } 2526170589Syongari /* 2527170589Syongari * finally, set the valid/checksum/TSO bit in the first 2528170589Syongari * descriptor. 2529170589Syongari */ 2530170589Syongari desc64->flags |= htole16(NFE_TX_VALID | cflags); 2531159952Sobrien } else { 2532159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 2533170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2534159952Sobrien else 2535170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2536170589Syongari desc32 = &sc->txq.desc32[si]; 2537254803Sandre if (tsosegsz != 0) { 2538170589Syongari /* 2539170589Syongari * XXX 2540170589Syongari * The following indicates the descriptor element 2541170589Syongari * is a 32bit quantity. 2542170589Syongari */ 2543254803Sandre desc32->length |= htole16((uint16_t)tsosegsz); 2544254803Sandre desc32->flags |= htole16(tsosegsz >> 16); 2545170589Syongari } 2546170589Syongari /* 2547170589Syongari * finally, set the valid/checksum/TSO bit in the first 2548170589Syongari * descriptor. 2549170589Syongari */ 2550170589Syongari desc32->flags |= htole16(NFE_TX_VALID | cflags); 2551159952Sobrien } 2552159952Sobrien 2553170589Syongari sc->txq.cur = prod; 2554170589Syongari prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2555170589Syongari sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2556170589Syongari sc->txq.data[prod].tx_data_map = map; 2557170589Syongari sc->txq.data[prod].m = m; 2558159952Sobrien 2559159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2560159952Sobrien 2561170589Syongari return (0); 2562159952Sobrien} 2563159952Sobrien 2564159967Sobrien 2565163503Sobrienstatic void 2566163503Sobriennfe_setmulti(struct nfe_softc *sc) 2567159952Sobrien{ 2568159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2569163503Sobrien struct ifmultiaddr *ifma; 2570163503Sobrien int i; 2571170589Syongari uint32_t filter; 2572170589Syongari uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2573170589Syongari uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 2574163503Sobrien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2575163503Sobrien }; 2576159967Sobrien 2577159967Sobrien NFE_LOCK_ASSERT(sc); 2578159967Sobrien 2579159967Sobrien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2580159967Sobrien bzero(addr, ETHER_ADDR_LEN); 2581159967Sobrien bzero(mask, ETHER_ADDR_LEN); 2582159967Sobrien goto done; 2583159967Sobrien } 2584159967Sobrien 2585159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2586159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2587159967Sobrien 2588195049Srwatson if_maddr_rlock(ifp); 2589159967Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2590159967Sobrien u_char *addrp; 2591159967Sobrien 2592159967Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 2593159967Sobrien continue; 2594159967Sobrien 2595159967Sobrien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 2596159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2597159967Sobrien u_int8_t mcaddr = addrp[i]; 2598159967Sobrien addr[i] &= mcaddr; 2599159967Sobrien mask[i] &= ~mcaddr; 2600159967Sobrien } 2601159967Sobrien } 2602195049Srwatson if_maddr_runlock(ifp); 2603159967Sobrien 2604159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2605159967Sobrien mask[i] |= addr[i]; 2606159967Sobrien } 2607159967Sobrien 2608159967Sobriendone: 2609159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 2610159967Sobrien 2611159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2612159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2613159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2614159967Sobrien addr[5] << 8 | addr[4]); 2615159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2616159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2617159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2618159967Sobrien mask[5] << 8 | mask[4]); 2619159967Sobrien 2620170589Syongari filter = NFE_READ(sc, NFE_RXFILTER); 2621170589Syongari filter &= NFE_PFF_RX_PAUSE; 2622170589Syongari filter |= NFE_RXFILTER_MAGIC; 2623170589Syongari filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2624159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 2625159967Sobrien} 2626159967Sobrien 2627163503Sobrien 2628163503Sobrienstatic void 2629216925Sjhbnfe_start(struct ifnet *ifp) 2630159967Sobrien{ 2631216925Sjhb struct nfe_softc *sc = ifp->if_softc; 2632159967Sobrien 2633216925Sjhb NFE_LOCK(sc); 2634216925Sjhb nfe_start_locked(ifp); 2635216925Sjhb NFE_UNLOCK(sc); 2636159967Sobrien} 2637159967Sobrien 2638163503Sobrienstatic void 2639216925Sjhbnfe_start_locked(struct ifnet *ifp) 2640159967Sobrien{ 2641159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2642163503Sobrien struct mbuf *m0; 2643170589Syongari int enq; 2644159952Sobrien 2645216925Sjhb NFE_LOCK_ASSERT(sc); 2646170589Syongari 2647170589Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2648216925Sjhb IFF_DRV_RUNNING || sc->nfe_link == 0) 2649159967Sobrien return; 2650159967Sobrien 2651170589Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 2652170589Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2653159952Sobrien if (m0 == NULL) 2654159952Sobrien break; 2655159952Sobrien 2656170589Syongari if (nfe_encap(sc, &m0) != 0) { 2657170589Syongari if (m0 == NULL) 2658170589Syongari break; 2659170589Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2660159967Sobrien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2661159952Sobrien break; 2662159952Sobrien } 2663170589Syongari enq++; 2664167190Scsjp ETHER_BPF_MTAP(ifp, m0); 2665159952Sobrien } 2666159952Sobrien 2667170589Syongari if (enq > 0) { 2668170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2669170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2670159952Sobrien 2671170589Syongari /* kick Tx */ 2672170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2673159952Sobrien 2674170589Syongari /* 2675170589Syongari * Set a timeout in case the chip goes out to lunch. 2676170589Syongari */ 2677170589Syongari sc->nfe_watchdog_timer = 5; 2678170589Syongari } 2679159952Sobrien} 2680159952Sobrien 2681163503Sobrien 2682163503Sobrienstatic void 2683163503Sobriennfe_watchdog(struct ifnet *ifp) 2684159952Sobrien{ 2685159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2686159952Sobrien 2687170589Syongari if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2688170589Syongari return; 2689159952Sobrien 2690170589Syongari /* Check if we've lost Tx completion interrupt. */ 2691170589Syongari nfe_txeof(sc); 2692170589Syongari if (sc->txq.queued == 0) { 2693170589Syongari if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2694170589Syongari "-- recovering\n"); 2695170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2696216925Sjhb nfe_start_locked(ifp); 2697170589Syongari return; 2698170589Syongari } 2699170589Syongari /* Check if we've lost start Tx command. */ 2700170589Syongari sc->nfe_force_tx++; 2701170589Syongari if (sc->nfe_force_tx <= 3) { 2702170589Syongari /* 2703170589Syongari * If this is the case for watchdog timeout, the following 2704170589Syongari * code should go to nfe_txeof(). 2705170589Syongari */ 2706170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2707170589Syongari return; 2708170589Syongari } 2709170589Syongari sc->nfe_force_tx = 0; 2710170589Syongari 2711170589Syongari if_printf(ifp, "watchdog timeout\n"); 2712170589Syongari 2713159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2714159952Sobrien ifp->if_oerrors++; 2715170589Syongari nfe_init_locked(sc); 2716159952Sobrien} 2717159952Sobrien 2718163503Sobrien 2719163503Sobrienstatic void 2720163503Sobriennfe_init(void *xsc) 2721159952Sobrien{ 2722159967Sobrien struct nfe_softc *sc = xsc; 2723159952Sobrien 2724159967Sobrien NFE_LOCK(sc); 2725159967Sobrien nfe_init_locked(sc); 2726159967Sobrien NFE_UNLOCK(sc); 2727159967Sobrien} 2728159967Sobrien 2729163503Sobrien 2730163503Sobrienstatic void 2731163503Sobriennfe_init_locked(void *xsc) 2732159967Sobrien{ 2733159967Sobrien struct nfe_softc *sc = xsc; 2734159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2735159967Sobrien struct mii_data *mii; 2736170589Syongari uint32_t val; 2737170589Syongari int error; 2738159967Sobrien 2739159967Sobrien NFE_LOCK_ASSERT(sc); 2740159967Sobrien 2741159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2742159967Sobrien 2743170589Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2744159967Sobrien return; 2745170589Syongari 2746170589Syongari nfe_stop(ifp); 2747170589Syongari 2748170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 2749170589Syongari 2750170589Syongari nfe_init_tx_ring(sc, &sc->txq); 2751170589Syongari if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2752170589Syongari error = nfe_init_jrx_ring(sc, &sc->jrxq); 2753170589Syongari else 2754170589Syongari error = nfe_init_rx_ring(sc, &sc->rxq); 2755170589Syongari if (error != 0) { 2756170589Syongari device_printf(sc->nfe_dev, 2757170589Syongari "initialization failed: no memory for rx buffers\n"); 2758170589Syongari nfe_stop(ifp); 2759170589Syongari return; 2760159967Sobrien } 2761159967Sobrien 2762170589Syongari val = 0; 2763170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2764170589Syongari val |= NFE_MAC_ADDR_INORDER; 2765170589Syongari NFE_WRITE(sc, NFE_TX_UNK, val); 2766159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 2767159952Sobrien 2768170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2769170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2770170589Syongari 2771159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 2772159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 2773159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2774159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2775159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 2776164656Sobrien 2777170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 2778159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2779170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2780170589Syongari sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2781159967Sobrien 2782159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2783159952Sobrien DELAY(10); 2784159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2785159952Sobrien 2786170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2787159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2788170589Syongari else 2789170589Syongari NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2790159952Sobrien 2791159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2792159952Sobrien 2793159952Sobrien /* set MAC address */ 2794170589Syongari nfe_set_macaddr(sc, IF_LLADDR(ifp)); 2795159952Sobrien 2796159952Sobrien /* tell MAC where rings are in memory */ 2797170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2798170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2799170589Syongari NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2800170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2801170589Syongari NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2802170589Syongari } else { 2803170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2804170589Syongari NFE_ADDR_HI(sc->rxq.physaddr)); 2805170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2806170589Syongari NFE_ADDR_LO(sc->rxq.physaddr)); 2807170589Syongari } 2808170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2809170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2810159952Sobrien 2811159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 2812159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 2813159952Sobrien (NFE_TX_RING_COUNT - 1)); 2814159952Sobrien 2815170589Syongari NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2816159952Sobrien 2817159952Sobrien /* force MAC to wakeup */ 2818170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2819170589Syongari if ((val & NFE_PWR_WAKEUP) == 0) 2820170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2821159952Sobrien DELAY(10); 2822170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2823170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2824159952Sobrien 2825159952Sobrien#if 1 2826159952Sobrien /* configure interrupts coalescing/mitigation */ 2827159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2828159952Sobrien#else 2829159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 2830159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 2831159952Sobrien#endif 2832159952Sobrien 2833170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2834159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2835159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2836159952Sobrien 2837159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2838159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2839159952Sobrien 2840159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2841215132Syongari /* Disable WOL. */ 2842215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, 0); 2843159952Sobrien 2844159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2845159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2846159952Sobrien DELAY(10); 2847159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2848159952Sobrien 2849159952Sobrien /* set Rx filter */ 2850159952Sobrien nfe_setmulti(sc); 2851159952Sobrien 2852159952Sobrien /* enable Rx */ 2853159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2854159952Sobrien 2855159952Sobrien /* enable Tx */ 2856159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2857159952Sobrien 2858159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2859159952Sobrien 2860183561Syongari /* Clear hardware stats. */ 2861183561Syongari nfe_stats_clear(sc); 2862183561Syongari 2863159967Sobrien#ifdef DEVICE_POLLING 2864159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) 2865170589Syongari nfe_disable_intr(sc); 2866159967Sobrien else 2867159967Sobrien#endif 2868170589Syongari nfe_set_intr(sc); 2869170589Syongari nfe_enable_intr(sc); /* enable interrupts */ 2870159952Sobrien 2871159967Sobrien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2872159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2873159952Sobrien 2874159967Sobrien sc->nfe_link = 0; 2875170589Syongari mii_mediachg(mii); 2876159952Sobrien 2877170589Syongari callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2878159952Sobrien} 2879159952Sobrien 2880163503Sobrien 2881163503Sobrienstatic void 2882170589Syongarinfe_stop(struct ifnet *ifp) 2883159952Sobrien{ 2884159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2885170589Syongari struct nfe_rx_ring *rx_ring; 2886170589Syongari struct nfe_jrx_ring *jrx_ring; 2887170589Syongari struct nfe_tx_ring *tx_ring; 2888170589Syongari struct nfe_rx_data *rdata; 2889170589Syongari struct nfe_tx_data *tdata; 2890170589Syongari int i; 2891159952Sobrien 2892159967Sobrien NFE_LOCK_ASSERT(sc); 2893159952Sobrien 2894170589Syongari sc->nfe_watchdog_timer = 0; 2895159967Sobrien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2896159952Sobrien 2897159967Sobrien callout_stop(&sc->nfe_stat_ch); 2898159967Sobrien 2899159952Sobrien /* abort Tx */ 2900159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 2901159952Sobrien 2902159952Sobrien /* disable Rx */ 2903159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 2904159952Sobrien 2905159952Sobrien /* disable interrupts */ 2906170589Syongari nfe_disable_intr(sc); 2907159952Sobrien 2908159967Sobrien sc->nfe_link = 0; 2909159967Sobrien 2910170589Syongari /* free Rx and Tx mbufs still in the queues. */ 2911170589Syongari rx_ring = &sc->rxq; 2912170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2913170589Syongari rdata = &rx_ring->data[i]; 2914170589Syongari if (rdata->m != NULL) { 2915170589Syongari bus_dmamap_sync(rx_ring->rx_data_tag, 2916170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2917170589Syongari bus_dmamap_unload(rx_ring->rx_data_tag, 2918170589Syongari rdata->rx_data_map); 2919170589Syongari m_freem(rdata->m); 2920170589Syongari rdata->m = NULL; 2921170589Syongari } 2922170589Syongari } 2923159952Sobrien 2924170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 2925170589Syongari jrx_ring = &sc->jrxq; 2926170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 2927170589Syongari rdata = &jrx_ring->jdata[i]; 2928170589Syongari if (rdata->m != NULL) { 2929170589Syongari bus_dmamap_sync(jrx_ring->jrx_data_tag, 2930170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2931170589Syongari bus_dmamap_unload(jrx_ring->jrx_data_tag, 2932170589Syongari rdata->rx_data_map); 2933170589Syongari m_freem(rdata->m); 2934170589Syongari rdata->m = NULL; 2935170589Syongari } 2936170589Syongari } 2937170589Syongari } 2938170589Syongari 2939170589Syongari tx_ring = &sc->txq; 2940170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2941170589Syongari tdata = &tx_ring->data[i]; 2942170589Syongari if (tdata->m != NULL) { 2943170589Syongari bus_dmamap_sync(tx_ring->tx_data_tag, 2944170589Syongari tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 2945170589Syongari bus_dmamap_unload(tx_ring->tx_data_tag, 2946170589Syongari tdata->tx_data_map); 2947170589Syongari m_freem(tdata->m); 2948170589Syongari tdata->m = NULL; 2949170589Syongari } 2950170589Syongari } 2951183561Syongari /* Update hardware stats. */ 2952183561Syongari nfe_stats_update(sc); 2953159952Sobrien} 2954159952Sobrien 2955163503Sobrien 2956163503Sobrienstatic int 2957163503Sobriennfe_ifmedia_upd(struct ifnet *ifp) 2958159952Sobrien{ 2959159967Sobrien struct nfe_softc *sc = ifp->if_softc; 2960170589Syongari struct mii_data *mii; 2961159952Sobrien 2962159967Sobrien NFE_LOCK(sc); 2963159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2964159967Sobrien mii_mediachg(mii); 2965170589Syongari NFE_UNLOCK(sc); 2966159967Sobrien 2967159967Sobrien return (0); 2968159952Sobrien} 2969159952Sobrien 2970163503Sobrien 2971163503Sobrienstatic void 2972163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2973159952Sobrien{ 2974163503Sobrien struct nfe_softc *sc; 2975163503Sobrien struct mii_data *mii; 2976159952Sobrien 2977159967Sobrien sc = ifp->if_softc; 2978159952Sobrien 2979159967Sobrien NFE_LOCK(sc); 2980159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2981159967Sobrien mii_pollstat(mii); 2982159952Sobrien 2983159967Sobrien ifmr->ifm_active = mii->mii_media_active; 2984159967Sobrien ifmr->ifm_status = mii->mii_media_status; 2985226478Syongari NFE_UNLOCK(sc); 2986159952Sobrien} 2987159952Sobrien 2988163503Sobrien 2989170589Syongarivoid 2990159967Sobriennfe_tick(void *xsc) 2991159952Sobrien{ 2992159967Sobrien struct nfe_softc *sc; 2993163503Sobrien struct mii_data *mii; 2994163503Sobrien struct ifnet *ifp; 2995159952Sobrien 2996170589Syongari sc = (struct nfe_softc *)xsc; 2997159952Sobrien 2998163503Sobrien NFE_LOCK_ASSERT(sc); 2999159952Sobrien 3000159967Sobrien ifp = sc->nfe_ifp; 3001159952Sobrien 3002159967Sobrien mii = device_get_softc(sc->nfe_miibus); 3003159967Sobrien mii_tick(mii); 3004183561Syongari nfe_stats_update(sc); 3005170589Syongari nfe_watchdog(ifp); 3006159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 3007159952Sobrien} 3008159952Sobrien 3009159952Sobrien 3010173839Syongaristatic int 3011163503Sobriennfe_shutdown(device_t dev) 3012159952Sobrien{ 3013159952Sobrien 3014215132Syongari return (nfe_suspend(dev)); 3015159952Sobrien} 3016159952Sobrien 3017159952Sobrien 3018163503Sobrienstatic void 3019170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 3020159952Sobrien{ 3021170589Syongari uint32_t val; 3022159952Sobrien 3023170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 3024170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3025170589Syongari addr[0] = (val >> 8) & 0xff; 3026170589Syongari addr[1] = (val & 0xff); 3027159952Sobrien 3028170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3029170589Syongari addr[2] = (val >> 24) & 0xff; 3030170589Syongari addr[3] = (val >> 16) & 0xff; 3031170589Syongari addr[4] = (val >> 8) & 0xff; 3032170589Syongari addr[5] = (val & 0xff); 3033170589Syongari } else { 3034170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3035170589Syongari addr[5] = (val >> 8) & 0xff; 3036170589Syongari addr[4] = (val & 0xff); 3037170589Syongari 3038170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3039170589Syongari addr[3] = (val >> 24) & 0xff; 3040170589Syongari addr[2] = (val >> 16) & 0xff; 3041170589Syongari addr[1] = (val >> 8) & 0xff; 3042170589Syongari addr[0] = (val & 0xff); 3043170589Syongari } 3044159952Sobrien} 3045159952Sobrien 3046163503Sobrien 3047163503Sobrienstatic void 3048170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 3049159952Sobrien{ 3050159967Sobrien 3051159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 3052159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 3053159967Sobrien addr[1] << 8 | addr[0]); 3054159952Sobrien} 3055159952Sobrien 3056163503Sobrien 3057159967Sobrien/* 3058159967Sobrien * Map a single buffer address. 3059159967Sobrien */ 3060159967Sobrien 3061159967Sobrienstatic void 3062170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3063159952Sobrien{ 3064170589Syongari struct nfe_dmamap_arg *ctx; 3065159952Sobrien 3066170589Syongari if (error != 0) 3067159967Sobrien return; 3068159952Sobrien 3069159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 3070159967Sobrien 3071170589Syongari ctx = (struct nfe_dmamap_arg *)arg; 3072170589Syongari ctx->nfe_busaddr = segs[0].ds_addr; 3073170589Syongari} 3074159967Sobrien 3075170589Syongari 3076170589Syongaristatic int 3077170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3078170589Syongari{ 3079170589Syongari int error, value; 3080170589Syongari 3081170589Syongari if (!arg1) 3082170589Syongari return (EINVAL); 3083170589Syongari value = *(int *)arg1; 3084170589Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3085170589Syongari if (error || !req->newptr) 3086170589Syongari return (error); 3087170589Syongari if (value < low || value > high) 3088170589Syongari return (EINVAL); 3089170589Syongari *(int *)arg1 = value; 3090170589Syongari 3091170589Syongari return (0); 3092159952Sobrien} 3093170589Syongari 3094170589Syongari 3095170589Syongaristatic int 3096170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 3097170589Syongari{ 3098170589Syongari 3099170589Syongari return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 3100170589Syongari NFE_PROC_MAX)); 3101170589Syongari} 3102183561Syongari 3103183561Syongari 3104183561Syongari#define NFE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 3105183561Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 3106183561Syongari#define NFE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 3107217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 3108183561Syongari 3109183561Syongaristatic void 3110183561Syongarinfe_sysctl_node(struct nfe_softc *sc) 3111183561Syongari{ 3112183561Syongari struct sysctl_ctx_list *ctx; 3113183561Syongari struct sysctl_oid_list *child, *parent; 3114183561Syongari struct sysctl_oid *tree; 3115183561Syongari struct nfe_hw_stats *stats; 3116183561Syongari int error; 3117183561Syongari 3118183561Syongari stats = &sc->nfe_stats; 3119183561Syongari ctx = device_get_sysctl_ctx(sc->nfe_dev); 3120183561Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev)); 3121183561Syongari SYSCTL_ADD_PROC(ctx, child, 3122183561Syongari OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 3123183561Syongari &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 3124183561Syongari "max number of Rx events to process"); 3125183561Syongari 3126183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3127183561Syongari error = resource_int_value(device_get_name(sc->nfe_dev), 3128183561Syongari device_get_unit(sc->nfe_dev), "process_limit", 3129183561Syongari &sc->nfe_process_limit); 3130183561Syongari if (error == 0) { 3131183561Syongari if (sc->nfe_process_limit < NFE_PROC_MIN || 3132183561Syongari sc->nfe_process_limit > NFE_PROC_MAX) { 3133183561Syongari device_printf(sc->nfe_dev, 3134183561Syongari "process_limit value out of range; " 3135183561Syongari "using default: %d\n", NFE_PROC_DEFAULT); 3136183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3137183561Syongari } 3138183561Syongari } 3139183561Syongari 3140183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3141183561Syongari return; 3142183561Syongari 3143183561Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 3144183561Syongari NULL, "NFE statistics"); 3145183561Syongari parent = SYSCTL_CHILDREN(tree); 3146183561Syongari 3147183561Syongari /* Rx statistics. */ 3148183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 3149183561Syongari NULL, "Rx MAC statistics"); 3150183561Syongari child = SYSCTL_CHILDREN(tree); 3151183561Syongari 3152183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors", 3153183561Syongari &stats->rx_frame_errors, "Framing Errors"); 3154183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes", 3155183561Syongari &stats->rx_extra_bytes, "Extra Bytes"); 3156183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3157183561Syongari &stats->rx_late_cols, "Late Collisions"); 3158183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "runts", 3159183561Syongari &stats->rx_runts, "Runts"); 3160183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos", 3161183561Syongari &stats->rx_jumbos, "Jumbos"); 3162183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns", 3163183561Syongari &stats->rx_fifo_overuns, "FIFO Overruns"); 3164183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors", 3165183561Syongari &stats->rx_crc_errors, "CRC Errors"); 3166183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fae", 3167183561Syongari &stats->rx_fae, "Frame Alignment Errors"); 3168183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors", 3169183561Syongari &stats->rx_len_errors, "Length Errors"); 3170183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3171183561Syongari &stats->rx_unicast, "Unicast Frames"); 3172183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3173183561Syongari &stats->rx_multicast, "Multicast Frames"); 3174186346Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3175183561Syongari &stats->rx_broadcast, "Broadcast Frames"); 3176183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3177183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3178183561Syongari &stats->rx_octets, "Octets"); 3179183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3180183561Syongari &stats->rx_pause, "Pause frames"); 3181183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "drops", 3182183561Syongari &stats->rx_drops, "Drop frames"); 3183183561Syongari } 3184183561Syongari 3185183561Syongari /* Tx statistics. */ 3186183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 3187183561Syongari NULL, "Tx MAC statistics"); 3188183561Syongari child = SYSCTL_CHILDREN(tree); 3189183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3190183561Syongari &stats->tx_octets, "Octets"); 3191183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits", 3192183561Syongari &stats->tx_zero_rexmits, "Zero Retransmits"); 3193183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits", 3194183561Syongari &stats->tx_one_rexmits, "One Retransmits"); 3195183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits", 3196183561Syongari &stats->tx_multi_rexmits, "Multiple Retransmits"); 3197183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3198183561Syongari &stats->tx_late_cols, "Late Collisions"); 3199183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns", 3200183561Syongari &stats->tx_fifo_underuns, "FIFO Underruns"); 3201183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts", 3202183561Syongari &stats->tx_carrier_losts, "Carrier Losts"); 3203183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals", 3204183561Syongari &stats->tx_excess_deferals, "Excess Deferrals"); 3205183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors", 3206183561Syongari &stats->tx_retry_errors, "Retry Errors"); 3207183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3208183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals", 3209183561Syongari &stats->tx_deferals, "Deferrals"); 3210183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frames", 3211183561Syongari &stats->tx_frames, "Frames"); 3212183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3213183561Syongari &stats->tx_pause, "Pause Frames"); 3214183561Syongari } 3215183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3216183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3217183561Syongari &stats->tx_deferals, "Unicast Frames"); 3218183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3219183561Syongari &stats->tx_frames, "Multicast Frames"); 3220183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3221183561Syongari &stats->tx_pause, "Broadcast Frames"); 3222183561Syongari } 3223183561Syongari} 3224183561Syongari 3225183561Syongari#undef NFE_SYSCTL_STAT_ADD32 3226183561Syongari#undef NFE_SYSCTL_STAT_ADD64 3227183561Syongari 3228183561Syongaristatic void 3229183561Syongarinfe_stats_clear(struct nfe_softc *sc) 3230183561Syongari{ 3231183561Syongari int i, mib_cnt; 3232183561Syongari 3233183561Syongari if ((sc->nfe_flags & NFE_MIB_V1) != 0) 3234183561Syongari mib_cnt = NFE_NUM_MIB_STATV1; 3235183561Syongari else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0) 3236183561Syongari mib_cnt = NFE_NUM_MIB_STATV2; 3237183561Syongari else 3238183561Syongari return; 3239183561Syongari 3240256038Syongari for (i = 0; i < mib_cnt; i++) 3241256038Syongari NFE_READ(sc, NFE_TX_OCTET + i * sizeof(uint32_t)); 3242183561Syongari 3243183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3244183561Syongari NFE_READ(sc, NFE_TX_UNICAST); 3245183561Syongari NFE_READ(sc, NFE_TX_MULTICAST); 3246183561Syongari NFE_READ(sc, NFE_TX_BROADCAST); 3247183561Syongari } 3248183561Syongari} 3249183561Syongari 3250183561Syongaristatic void 3251183561Syongarinfe_stats_update(struct nfe_softc *sc) 3252183561Syongari{ 3253183561Syongari struct nfe_hw_stats *stats; 3254183561Syongari 3255183561Syongari NFE_LOCK_ASSERT(sc); 3256183561Syongari 3257183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3258183561Syongari return; 3259183561Syongari 3260183561Syongari stats = &sc->nfe_stats; 3261183561Syongari stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET); 3262183561Syongari stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT); 3263183561Syongari stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT); 3264183561Syongari stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT); 3265183561Syongari stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL); 3266183561Syongari stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN); 3267183561Syongari stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST); 3268183561Syongari stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL); 3269183561Syongari stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR); 3270183561Syongari stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR); 3271183561Syongari stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES); 3272183561Syongari stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL); 3273183561Syongari stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT); 3274183561Syongari stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO); 3275183561Syongari stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN); 3276183561Syongari stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR); 3277183561Syongari stats->rx_fae += NFE_READ(sc, NFE_RX_FAE); 3278183561Syongari stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR); 3279183561Syongari stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST); 3280183561Syongari stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST); 3281183561Syongari stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST); 3282183561Syongari 3283183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3284183561Syongari stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL); 3285183561Syongari stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME); 3286183561Syongari stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET); 3287183561Syongari stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE); 3288183561Syongari stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE); 3289183561Syongari stats->rx_drops += NFE_READ(sc, NFE_RX_DROP); 3290183561Syongari } 3291183561Syongari 3292183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3293183561Syongari stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST); 3294183561Syongari stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST); 3295255648Sdelphij stats->tx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST); 3296183561Syongari } 3297183561Syongari} 3298215132Syongari 3299215132Syongari 3300215132Syongaristatic void 3301215132Syongarinfe_set_linkspeed(struct nfe_softc *sc) 3302215132Syongari{ 3303215132Syongari struct mii_softc *miisc; 3304215132Syongari struct mii_data *mii; 3305215132Syongari int aneg, i, phyno; 3306215132Syongari 3307215132Syongari NFE_LOCK_ASSERT(sc); 3308215132Syongari 3309215132Syongari mii = device_get_softc(sc->nfe_miibus); 3310215132Syongari mii_pollstat(mii); 3311215132Syongari aneg = 0; 3312215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 3313215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 3314215132Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 3315215132Syongari case IFM_10_T: 3316215132Syongari case IFM_100_TX: 3317215132Syongari return; 3318215132Syongari case IFM_1000_T: 3319215132Syongari aneg++; 3320215132Syongari break; 3321215132Syongari default: 3322215132Syongari break; 3323215132Syongari } 3324215132Syongari } 3325221407Smarius miisc = LIST_FIRST(&mii->mii_phys); 3326221407Smarius phyno = miisc->mii_phy; 3327221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 3328221407Smarius PHY_RESET(miisc); 3329215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0); 3330215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3331215132Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 3332215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3333215132Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 3334215132Syongari DELAY(1000); 3335215132Syongari if (aneg != 0) { 3336215132Syongari /* 3337215132Syongari * Poll link state until nfe(4) get a 10/100Mbps link. 3338215132Syongari */ 3339215132Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 3340215132Syongari mii_pollstat(mii); 3341215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 3342215132Syongari == (IFM_ACTIVE | IFM_AVALID)) { 3343215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 3344215132Syongari case IFM_10_T: 3345215132Syongari case IFM_100_TX: 3346215132Syongari nfe_mac_config(sc, mii); 3347215132Syongari return; 3348215132Syongari default: 3349215132Syongari break; 3350215132Syongari } 3351215132Syongari } 3352215132Syongari NFE_UNLOCK(sc); 3353215132Syongari pause("nfelnk", hz); 3354215132Syongari NFE_LOCK(sc); 3355215132Syongari } 3356215132Syongari if (i == MII_ANEGTICKS_GIGE) 3357215132Syongari device_printf(sc->nfe_dev, 3358215132Syongari "establishing a link failed, WOL may not work!"); 3359215132Syongari } 3360215132Syongari /* 3361215132Syongari * No link, force MAC to have 100Mbps, full-duplex link. 3362215132Syongari * This is the last resort and may/may not work. 3363215132Syongari */ 3364215132Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 3365215132Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 3366215132Syongari nfe_mac_config(sc, mii); 3367215132Syongari} 3368215132Syongari 3369215132Syongari 3370215132Syongaristatic void 3371215132Syongarinfe_set_wol(struct nfe_softc *sc) 3372215132Syongari{ 3373215132Syongari struct ifnet *ifp; 3374215132Syongari uint32_t wolctl; 3375215132Syongari int pmc; 3376215132Syongari uint16_t pmstat; 3377215132Syongari 3378215132Syongari NFE_LOCK_ASSERT(sc); 3379215132Syongari 3380219902Sjhb if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0) 3381215132Syongari return; 3382215132Syongari ifp = sc->nfe_ifp; 3383215132Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 3384215132Syongari wolctl = NFE_WOL_MAGIC; 3385215132Syongari else 3386215132Syongari wolctl = 0; 3387215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, wolctl); 3388215132Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) { 3389215132Syongari nfe_set_linkspeed(sc); 3390215132Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) != 0) 3391215132Syongari NFE_WRITE(sc, NFE_PWR2_CTL, 3392215132Syongari NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS); 3393215132Syongari /* Enable RX. */ 3394215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0); 3395215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0); 3396215132Syongari NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) | 3397215132Syongari NFE_RX_START); 3398215132Syongari } 3399215132Syongari /* Request PME if WOL is requested. */ 3400215132Syongari pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2); 3401215132Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 3402215132Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 3403215132Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 3404215132Syongari pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 3405215132Syongari} 3406