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$"); 25159952Sobrien 26159967Sobrien#ifdef HAVE_KERNEL_OPTION_HEADERS 27159967Sobrien#include "opt_device_polling.h" 28159967Sobrien#endif 29159967Sobrien 30159952Sobrien#include <sys/param.h> 31159952Sobrien#include <sys/endian.h> 32159952Sobrien#include <sys/systm.h> 33159952Sobrien#include <sys/sockio.h> 34159952Sobrien#include <sys/mbuf.h> 35159952Sobrien#include <sys/malloc.h> 36159967Sobrien#include <sys/module.h> 37159952Sobrien#include <sys/kernel.h> 38170589Syongari#include <sys/queue.h> 39159952Sobrien#include <sys/socket.h> 40170589Syongari#include <sys/sysctl.h> 41159967Sobrien#include <sys/taskqueue.h> 42159952Sobrien 43159952Sobrien#include <net/if.h> 44159967Sobrien#include <net/if_arp.h> 45159967Sobrien#include <net/ethernet.h> 46159952Sobrien#include <net/if_dl.h> 47159952Sobrien#include <net/if_media.h> 48159952Sobrien#include <net/if_types.h> 49159952Sobrien#include <net/if_vlan_var.h> 50159952Sobrien 51159952Sobrien#include <net/bpf.h> 52159952Sobrien 53159967Sobrien#include <machine/bus.h> 54159967Sobrien#include <machine/resource.h> 55159967Sobrien#include <sys/bus.h> 56159967Sobrien#include <sys/rman.h> 57159967Sobrien 58159952Sobrien#include <dev/mii/mii.h> 59159952Sobrien#include <dev/mii/miivar.h> 60159952Sobrien 61159952Sobrien#include <dev/pci/pcireg.h> 62159952Sobrien#include <dev/pci/pcivar.h> 63159952Sobrien 64159967Sobrien#include <dev/nfe/if_nfereg.h> 65159967Sobrien#include <dev/nfe/if_nfevar.h> 66159952Sobrien 67159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1); 68159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1); 69159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1); 70170589Syongari 71170589Syongari/* "device miibus" required. See GENERIC if you get errors here. */ 72159967Sobrien#include "miibus_if.h" 73159952Sobrien 74163503Sobrienstatic int nfe_probe(device_t); 75163503Sobrienstatic int nfe_attach(device_t); 76163503Sobrienstatic int nfe_detach(device_t); 77170589Syongaristatic int nfe_suspend(device_t); 78170589Syongaristatic int nfe_resume(device_t); 79173839Syongaristatic int nfe_shutdown(device_t); 80215327Syongaristatic int nfe_can_use_msix(struct nfe_softc *); 81264747Syongaristatic int nfe_detect_msik9(struct nfe_softc *); 82170589Syongaristatic void nfe_power(struct nfe_softc *); 83163503Sobrienstatic int nfe_miibus_readreg(device_t, int, int); 84163503Sobrienstatic int nfe_miibus_writereg(device_t, int, int, int); 85163503Sobrienstatic void nfe_miibus_statchg(device_t); 86215132Syongaristatic void nfe_mac_config(struct nfe_softc *, struct mii_data *); 87170589Syongaristatic void nfe_set_intr(struct nfe_softc *); 88170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *); 89170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *); 90163503Sobrienstatic int nfe_ioctl(struct ifnet *, u_long, caddr_t); 91170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int); 92170589Syongaristatic int nfe_intr(void *); 93170589Syongaristatic void nfe_int_task(void *, int); 94170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int); 95170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int); 96170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int); 97170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int); 98193096Sattiliostatic int nfe_rxeof(struct nfe_softc *, int, int *); 99193096Sattiliostatic int nfe_jrxeof(struct nfe_softc *, int, int *); 100159967Sobrienstatic void nfe_txeof(struct nfe_softc *); 101170589Syongaristatic int nfe_encap(struct nfe_softc *, struct mbuf **); 102159967Sobrienstatic void nfe_setmulti(struct nfe_softc *); 103159967Sobrienstatic void nfe_start(struct ifnet *); 104216925Sjhbstatic void nfe_start_locked(struct ifnet *); 105159967Sobrienstatic void nfe_watchdog(struct ifnet *); 106159967Sobrienstatic void nfe_init(void *); 107159967Sobrienstatic void nfe_init_locked(void *); 108170589Syongaristatic void nfe_stop(struct ifnet *); 109159967Sobrienstatic int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 110171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 111170589Syongaristatic int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 112170589Syongaristatic int nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 113159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 114170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 115159967Sobrienstatic int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 116170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 117159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 118159967Sobrienstatic int nfe_ifmedia_upd(struct ifnet *); 119159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 120159967Sobrienstatic void nfe_tick(void *); 121170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 122170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *); 123170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); 124159952Sobrien 125170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 126170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); 127183561Syongaristatic void nfe_sysctl_node(struct nfe_softc *); 128183561Syongaristatic void nfe_stats_clear(struct nfe_softc *); 129183561Syongaristatic void nfe_stats_update(struct nfe_softc *); 130215132Syongaristatic void nfe_set_linkspeed(struct nfe_softc *); 131215132Syongaristatic void nfe_set_wol(struct nfe_softc *); 132170589Syongari 133159952Sobrien#ifdef NFE_DEBUG 134170589Syongaristatic int nfedebug = 0; 135170589Syongari#define DPRINTF(sc, ...) do { \ 136170589Syongari if (nfedebug) \ 137170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 138170589Syongari} while (0) 139170589Syongari#define DPRINTFN(sc, n, ...) do { \ 140170589Syongari if (nfedebug >= (n)) \ 141170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 142170589Syongari} while (0) 143159952Sobrien#else 144170589Syongari#define DPRINTF(sc, ...) 145170589Syongari#define DPRINTFN(sc, n, ...) 146159952Sobrien#endif 147159952Sobrien 148159967Sobrien#define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 149159967Sobrien#define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 150159967Sobrien#define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 151159967Sobrien 152170589Syongari/* Tunables. */ 153170589Syongaristatic int msi_disable = 0; 154170589Syongaristatic int msix_disable = 0; 155171559Syongaristatic int jumbo_disable = 0; 156170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable); 157170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable); 158171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable); 159159967Sobrien 160159967Sobrienstatic device_method_t nfe_methods[] = { 161159967Sobrien /* Device interface */ 162159967Sobrien DEVMETHOD(device_probe, nfe_probe), 163159967Sobrien DEVMETHOD(device_attach, nfe_attach), 164159967Sobrien DEVMETHOD(device_detach, nfe_detach), 165170589Syongari DEVMETHOD(device_suspend, nfe_suspend), 166170589Syongari DEVMETHOD(device_resume, nfe_resume), 167159967Sobrien DEVMETHOD(device_shutdown, nfe_shutdown), 168159967Sobrien 169159967Sobrien /* MII interface */ 170159967Sobrien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 171159967Sobrien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 172163503Sobrien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 173159967Sobrien 174227843Smarius DEVMETHOD_END 175159952Sobrien}; 176159952Sobrien 177159967Sobrienstatic driver_t nfe_driver = { 178159967Sobrien "nfe", 179159967Sobrien nfe_methods, 180159967Sobrien sizeof(struct nfe_softc) 181159967Sobrien}; 182159967Sobrien 183159967Sobrienstatic devclass_t nfe_devclass; 184159967Sobrien 185159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 186159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 187159967Sobrien 188159967Sobrienstatic struct nfe_type nfe_devs[] = { 189159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 190163503Sobrien "NVIDIA nForce MCP Networking Adapter"}, 191159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 192163503Sobrien "NVIDIA nForce2 MCP2 Networking Adapter"}, 193159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 194163503Sobrien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 195159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 196163503Sobrien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 197163437Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 198163503Sobrien "NVIDIA nForce3 MCP3 Networking Adapter"}, 199159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 200163503Sobrien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 201159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 202163503Sobrien "NVIDIA nForce3 MCP7 Networking Adapter"}, 203159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 204163503Sobrien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 205159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 206163503Sobrien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 207159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 208170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP10 */ 209159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 210170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP11 */ 211159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 212163503Sobrien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 213159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 214163503Sobrien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 215159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 216163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 217159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 218163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 219162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 220163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 221162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 222163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 223162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 224163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 225170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4, 226163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 227162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 228163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 229162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 230163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 231162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 232163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 233170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4, 234163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 235170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1, 236170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 237170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2, 238170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 239170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3, 240170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 241170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4, 242170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 243178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1, 244178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 245178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2, 246178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 247178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3, 248178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 249178055Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4, 250178055Syongari "NVIDIA nForce MCP73 Networking Adapter"}, 251183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1, 252183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 253183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2, 254183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 255183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3, 256183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 257183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4, 258183509Syongari "NVIDIA nForce MCP77 Networking Adapter"}, 259183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1, 260183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 261183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2, 262183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 263183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3, 264183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 265183509Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4, 266183509Syongari "NVIDIA nForce MCP79 Networking Adapter"}, 267159967Sobrien {0, 0, NULL} 268159967Sobrien}; 269159967Sobrien 270159967Sobrien 271159967Sobrien/* Probe for supported hardware ID's */ 272159967Sobrienstatic int 273159967Sobriennfe_probe(device_t dev) 274159952Sobrien{ 275159967Sobrien struct nfe_type *t; 276159967Sobrien 277159967Sobrien t = nfe_devs; 278159967Sobrien /* Check for matching PCI DEVICE ID's */ 279159967Sobrien while (t->name != NULL) { 280159967Sobrien if ((pci_get_vendor(dev) == t->vid_id) && 281159967Sobrien (pci_get_device(dev) == t->dev_id)) { 282159967Sobrien device_set_desc(dev, t->name); 283170589Syongari return (BUS_PROBE_DEFAULT); 284159967Sobrien } 285159967Sobrien t++; 286159967Sobrien } 287159967Sobrien 288159967Sobrien return (ENXIO); 289159952Sobrien} 290159952Sobrien 291170589Syongaristatic void 292170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count) 293170589Syongari{ 294170589Syongari int rid; 295163503Sobrien 296170589Syongari rid = PCIR_BAR(2); 297170589Syongari sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY, 298170589Syongari &rid, RF_ACTIVE); 299170589Syongari if (sc->nfe_msix_res == NULL) { 300170589Syongari device_printf(sc->nfe_dev, 301170589Syongari "couldn't allocate MSIX table resource\n"); 302170589Syongari return; 303170589Syongari } 304170589Syongari rid = PCIR_BAR(3); 305170589Syongari sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev, 306170589Syongari SYS_RES_MEMORY, &rid, RF_ACTIVE); 307170589Syongari if (sc->nfe_msix_pba_res == NULL) { 308170589Syongari device_printf(sc->nfe_dev, 309170589Syongari "couldn't allocate MSIX PBA resource\n"); 310170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2), 311170589Syongari sc->nfe_msix_res); 312170589Syongari sc->nfe_msix_res = NULL; 313170589Syongari return; 314170589Syongari } 315170589Syongari 316170589Syongari if (pci_alloc_msix(sc->nfe_dev, &count) == 0) { 317170589Syongari if (count == NFE_MSI_MESSAGES) { 318170589Syongari if (bootverbose) 319170589Syongari device_printf(sc->nfe_dev, 320170589Syongari "Using %d MSIX messages\n", count); 321170589Syongari sc->nfe_msix = 1; 322170589Syongari } else { 323170589Syongari if (bootverbose) 324170589Syongari device_printf(sc->nfe_dev, 325170589Syongari "couldn't allocate MSIX\n"); 326170589Syongari pci_release_msi(sc->nfe_dev); 327170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 328170589Syongari PCIR_BAR(3), sc->nfe_msix_pba_res); 329170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 330170589Syongari PCIR_BAR(2), sc->nfe_msix_res); 331170589Syongari sc->nfe_msix_pba_res = NULL; 332170589Syongari sc->nfe_msix_res = NULL; 333170589Syongari } 334170589Syongari } 335170589Syongari} 336170589Syongari 337264747Syongari 338159967Sobrienstatic int 339264747Syongarinfe_detect_msik9(struct nfe_softc *sc) 340264747Syongari{ 341264747Syongari static const char *maker = "MSI"; 342264747Syongari static const char *product = "K9N6PGM2-V2 (MS-7309)"; 343264747Syongari char *m, *p; 344264747Syongari int found; 345264747Syongari 346264747Syongari found = 0; 347264747Syongari m = getenv("smbios.planar.maker"); 348264747Syongari p = getenv("smbios.planar.product"); 349264747Syongari if (m != NULL && p != NULL) { 350264747Syongari if (strcmp(m, maker) == 0 && strcmp(p, product) == 0) 351264747Syongari found = 1; 352264747Syongari } 353264747Syongari if (m != NULL) 354264747Syongari freeenv(m); 355264747Syongari if (p != NULL) 356264747Syongari freeenv(p); 357264747Syongari 358264747Syongari return (found); 359264747Syongari} 360264747Syongari 361264747Syongari 362264747Syongaristatic int 363159967Sobriennfe_attach(device_t dev) 364159952Sobrien{ 365159967Sobrien struct nfe_softc *sc; 366159952Sobrien struct ifnet *ifp; 367170589Syongari bus_addr_t dma_addr_max; 368264747Syongari int error = 0, i, msic, phyloc, reg, rid; 369159952Sobrien 370159967Sobrien sc = device_get_softc(dev); 371159967Sobrien sc->nfe_dev = dev; 372159952Sobrien 373159967Sobrien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 374170589Syongari MTX_DEF); 375159967Sobrien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 376159967Sobrien 377163503Sobrien pci_enable_busmaster(dev); 378159967Sobrien 379170589Syongari rid = PCIR_BAR(0); 380170589Syongari sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 381170589Syongari RF_ACTIVE); 382170589Syongari if (sc->nfe_res[0] == NULL) { 383170589Syongari device_printf(dev, "couldn't map memory resources\n"); 384170589Syongari mtx_destroy(&sc->nfe_mtx); 385170589Syongari return (ENXIO); 386170589Syongari } 387159967Sobrien 388219902Sjhb if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { 389170589Syongari uint16_t v, width; 390170589Syongari 391170589Syongari v = pci_read_config(dev, reg + 0x08, 2); 392170589Syongari /* Change max. read request size to 4096. */ 393170589Syongari v &= ~(7 << 12); 394170589Syongari v |= (5 << 12); 395170589Syongari pci_write_config(dev, reg + 0x08, v, 2); 396170589Syongari 397170589Syongari v = pci_read_config(dev, reg + 0x0c, 2); 398170589Syongari /* link capability */ 399170589Syongari v = (v >> 4) & 0x0f; 400170589Syongari width = pci_read_config(dev, reg + 0x12, 2); 401170589Syongari /* negotiated link width */ 402170589Syongari width = (width >> 4) & 0x3f; 403170589Syongari if (v != width) 404170589Syongari device_printf(sc->nfe_dev, 405170589Syongari "warning, negotiated width of link(x%d) != " 406170589Syongari "max. width of link(x%d)\n", width, v); 407159952Sobrien } 408159952Sobrien 409215327Syongari if (nfe_can_use_msix(sc) == 0) { 410215327Syongari device_printf(sc->nfe_dev, 411215327Syongari "MSI/MSI-X capability black-listed, will use INTx\n"); 412215327Syongari msix_disable = 1; 413215327Syongari msi_disable = 1; 414215327Syongari } 415215327Syongari 416159967Sobrien /* Allocate interrupt */ 417170589Syongari if (msix_disable == 0 || msi_disable == 0) { 418170589Syongari if (msix_disable == 0 && 419170589Syongari (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES) 420170589Syongari nfe_alloc_msix(sc, msic); 421170589Syongari if (msi_disable == 0 && sc->nfe_msix == 0 && 422170589Syongari (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES && 423170589Syongari pci_alloc_msi(dev, &msic) == 0) { 424170589Syongari if (msic == NFE_MSI_MESSAGES) { 425170589Syongari if (bootverbose) 426170589Syongari device_printf(dev, 427170589Syongari "Using %d MSI messages\n", msic); 428170589Syongari sc->nfe_msi = 1; 429170589Syongari } else 430170589Syongari pci_release_msi(dev); 431170589Syongari } 432170589Syongari } 433159967Sobrien 434170589Syongari if (sc->nfe_msix == 0 && sc->nfe_msi == 0) { 435170589Syongari rid = 0; 436170589Syongari sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 437170589Syongari RF_SHAREABLE | RF_ACTIVE); 438170589Syongari if (sc->nfe_irq[0] == NULL) { 439170589Syongari device_printf(dev, "couldn't allocate IRQ resources\n"); 440170589Syongari error = ENXIO; 441170589Syongari goto fail; 442170589Syongari } 443170589Syongari } else { 444170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 445170589Syongari sc->nfe_irq[i] = bus_alloc_resource_any(dev, 446170589Syongari SYS_RES_IRQ, &rid, RF_ACTIVE); 447170589Syongari if (sc->nfe_irq[i] == NULL) { 448170589Syongari device_printf(dev, 449170589Syongari "couldn't allocate IRQ resources for " 450170589Syongari "message %d\n", rid); 451170589Syongari error = ENXIO; 452170589Syongari goto fail; 453170589Syongari } 454170589Syongari } 455170589Syongari /* Map interrupts to vector 0. */ 456170589Syongari if (sc->nfe_msix != 0) { 457170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP0, 0); 458170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP1, 0); 459170589Syongari } else if (sc->nfe_msi != 0) { 460170589Syongari NFE_WRITE(sc, NFE_MSI_MAP0, 0); 461170589Syongari NFE_WRITE(sc, NFE_MSI_MAP1, 0); 462170589Syongari } 463159952Sobrien } 464159952Sobrien 465170589Syongari /* Set IRQ status/mask register. */ 466170589Syongari sc->nfe_irq_status = NFE_IRQ_STATUS; 467170589Syongari sc->nfe_irq_mask = NFE_IRQ_MASK; 468170589Syongari sc->nfe_intrs = NFE_IRQ_WANTED; 469170589Syongari sc->nfe_nointrs = 0; 470170589Syongari if (sc->nfe_msix != 0) { 471170589Syongari sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS; 472170589Syongari sc->nfe_nointrs = NFE_IRQ_WANTED; 473170589Syongari } else if (sc->nfe_msi != 0) { 474170589Syongari sc->nfe_irq_mask = NFE_MSI_IRQ_MASK; 475170589Syongari sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED; 476170589Syongari } 477159952Sobrien 478170589Syongari sc->nfe_devid = pci_get_device(dev); 479170589Syongari sc->nfe_revid = pci_get_revid(dev); 480159967Sobrien sc->nfe_flags = 0; 481159952Sobrien 482170589Syongari switch (sc->nfe_devid) { 483159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 484159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 485159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 486159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 487159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 488159952Sobrien break; 489159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 490159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 491183561Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | NFE_MIB_V1; 492159952Sobrien break; 493159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 494159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 495159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 496159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 497183561Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 498183561Syongari NFE_MIB_V1; 499159952Sobrien break; 500159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 501159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 502163503Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 503183561Syongari NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 504159952Sobrien break; 505170589Syongari 506162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 507162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 508162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 509162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 510170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 511170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 512170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 513170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 514178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN1: 515178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN2: 516178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN3: 517178055Syongari case PCI_PRODUCT_NVIDIA_MCP73_LAN4: 518170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | 519183561Syongari NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | NFE_MIB_V2; 520162212Sobrien break; 521183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN1: 522183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN2: 523183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN3: 524183509Syongari case PCI_PRODUCT_NVIDIA_MCP77_LAN4: 525183509Syongari /* XXX flow control */ 526183509Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_PWR_MGMT | 527183561Syongari NFE_CORRECT_MACADDR | NFE_MIB_V3; 528183509Syongari break; 529183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN1: 530183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN2: 531183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN3: 532183509Syongari case PCI_PRODUCT_NVIDIA_MCP79_LAN4: 533183509Syongari /* XXX flow control */ 534183509Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 535183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_MIB_V3; 536183509Syongari break; 537162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 538162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 539162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 540162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 541170589Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | 542183561Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL | 543183561Syongari NFE_MIB_V2; 544163503Sobrien break; 545159952Sobrien } 546159952Sobrien 547170589Syongari nfe_power(sc); 548170589Syongari /* Check for reversed ethernet address */ 549170589Syongari if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0) 550170589Syongari sc->nfe_flags |= NFE_CORRECT_MACADDR; 551170589Syongari nfe_get_macaddr(sc, sc->eaddr); 552159952Sobrien /* 553159967Sobrien * Allocate the parent bus DMA tag appropriate for PCI. 554159967Sobrien */ 555170589Syongari dma_addr_max = BUS_SPACE_MAXADDR_32BIT; 556170589Syongari if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0) 557170589Syongari dma_addr_max = NFE_DMA_MAXADDR; 558170589Syongari error = bus_dma_tag_create( 559170589Syongari bus_get_dma_tag(sc->nfe_dev), /* parent */ 560163503Sobrien 1, 0, /* alignment, boundary */ 561170589Syongari dma_addr_max, /* lowaddr */ 562163503Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 563163503Sobrien NULL, NULL, /* filter, filterarg */ 564170589Syongari BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 565163503Sobrien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 566170589Syongari 0, /* flags */ 567163503Sobrien NULL, NULL, /* lockfunc, lockarg */ 568163503Sobrien &sc->nfe_parent_tag); 569159967Sobrien if (error) 570159967Sobrien goto fail; 571159967Sobrien 572164650Sobrien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 573164650Sobrien if (ifp == NULL) { 574170589Syongari device_printf(dev, "can not if_alloc()\n"); 575164650Sobrien error = ENOSPC; 576164650Sobrien goto fail; 577164650Sobrien } 578164650Sobrien 579159967Sobrien /* 580159952Sobrien * Allocate Tx and Rx rings. 581159952Sobrien */ 582170589Syongari if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0) 583159967Sobrien goto fail; 584159952Sobrien 585170589Syongari if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0) 586159967Sobrien goto fail; 587170589Syongari 588171559Syongari nfe_alloc_jrx_ring(sc, &sc->jrxq); 589183561Syongari /* Create sysctl node. */ 590183561Syongari nfe_sysctl_node(sc); 591170589Syongari 592159952Sobrien ifp->if_softc = sc; 593159967Sobrien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 594159952Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 595159952Sobrien ifp->if_ioctl = nfe_ioctl; 596159952Sobrien ifp->if_start = nfe_start; 597170589Syongari ifp->if_hwassist = 0; 598170589Syongari ifp->if_capabilities = 0; 599159952Sobrien ifp->if_init = nfe_init; 600170589Syongari IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1); 601170589Syongari ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1; 602170589Syongari IFQ_SET_READY(&ifp->if_snd); 603159952Sobrien 604170589Syongari if (sc->nfe_flags & NFE_HW_CSUM) { 605170589Syongari ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4; 606170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO; 607170589Syongari } 608170589Syongari ifp->if_capenable = ifp->if_capabilities; 609164650Sobrien 610170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 611170589Syongari /* VLAN capability setup. */ 612170589Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 613170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 614159952Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 615170589Syongari if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0) 616215432Syongari ifp->if_capabilities |= IFCAP_VLAN_HWCSUM | 617215432Syongari IFCAP_VLAN_HWTSO; 618159952Sobrien } 619215132Syongari 620219902Sjhb if (pci_find_cap(dev, PCIY_PMG, ®) == 0) 621215132Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC; 622159967Sobrien ifp->if_capenable = ifp->if_capabilities; 623159952Sobrien 624170589Syongari /* 625170589Syongari * Tell the upper layer(s) we support long frames. 626170589Syongari * Must appear after the call to ether_ifattach() because 627170589Syongari * ether_ifattach() sets ifi_hdrlen to the default value. 628170589Syongari */ 629170589Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 630170589Syongari 631159967Sobrien#ifdef DEVICE_POLLING 632159967Sobrien ifp->if_capabilities |= IFCAP_POLLING; 633159967Sobrien#endif 634159952Sobrien 635159967Sobrien /* Do MII setup */ 636264747Syongari phyloc = MII_PHY_ANY; 637264747Syongari if (sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN1 || 638264747Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN2 || 639264747Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN3 || 640264747Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_MCP61_LAN4) { 641264747Syongari if (nfe_detect_msik9(sc) != 0) 642264747Syongari phyloc = 0; 643264747Syongari } 644213894Smarius error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd, 645264747Syongari nfe_ifmedia_sts, BMSR_DEFCAPMASK, phyloc, MII_OFFSET_ANY, 646215297Smarius MIIF_DOPAUSE); 647213894Smarius if (error != 0) { 648213894Smarius device_printf(dev, "attaching PHYs failed\n"); 649159967Sobrien goto fail; 650159967Sobrien } 651159967Sobrien ether_ifattach(ifp, sc->eaddr); 652159952Sobrien 653170589Syongari TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc); 654170589Syongari sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK, 655170589Syongari taskqueue_thread_enqueue, &sc->nfe_tq); 656170589Syongari taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq", 657170589Syongari device_get_nameunit(sc->nfe_dev)); 658170589Syongari error = 0; 659170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 660170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[0], 661170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 662170589Syongari &sc->nfe_intrhand[0]); 663170589Syongari } else { 664170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 665170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[i], 666170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 667170589Syongari &sc->nfe_intrhand[i]); 668170589Syongari if (error != 0) 669170589Syongari break; 670170589Syongari } 671170589Syongari } 672159967Sobrien if (error) { 673170589Syongari device_printf(dev, "couldn't set up irq\n"); 674170589Syongari taskqueue_free(sc->nfe_tq); 675170589Syongari sc->nfe_tq = NULL; 676159967Sobrien ether_ifdetach(ifp); 677159967Sobrien goto fail; 678159967Sobrien } 679159967Sobrien 680159967Sobrienfail: 681159967Sobrien if (error) 682159967Sobrien nfe_detach(dev); 683159967Sobrien 684159967Sobrien return (error); 685159952Sobrien} 686159952Sobrien 687159967Sobrien 688159967Sobrienstatic int 689159967Sobriennfe_detach(device_t dev) 690159952Sobrien{ 691163503Sobrien struct nfe_softc *sc; 692163503Sobrien struct ifnet *ifp; 693170589Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 694170589Syongari int i, rid; 695159952Sobrien 696159967Sobrien sc = device_get_softc(dev); 697159967Sobrien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 698159967Sobrien ifp = sc->nfe_ifp; 699159967Sobrien 700159967Sobrien#ifdef DEVICE_POLLING 701170589Syongari if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 702159967Sobrien ether_poll_deregister(ifp); 703159967Sobrien#endif 704159967Sobrien if (device_is_attached(dev)) { 705164649Sobrien NFE_LOCK(sc); 706170589Syongari nfe_stop(ifp); 707159967Sobrien ifp->if_flags &= ~IFF_UP; 708164649Sobrien NFE_UNLOCK(sc); 709159967Sobrien callout_drain(&sc->nfe_stat_ch); 710159967Sobrien ether_ifdetach(ifp); 711159967Sobrien } 712159967Sobrien 713170589Syongari if (ifp) { 714170589Syongari /* restore ethernet address */ 715170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 716170589Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) { 717170589Syongari eaddr[i] = sc->eaddr[5 - i]; 718170589Syongari } 719170589Syongari } else 720170589Syongari bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN); 721170589Syongari nfe_set_macaddr(sc, eaddr); 722159967Sobrien if_free(ifp); 723170589Syongari } 724159967Sobrien if (sc->nfe_miibus) 725159967Sobrien device_delete_child(dev, sc->nfe_miibus); 726159967Sobrien bus_generic_detach(dev); 727170589Syongari if (sc->nfe_tq != NULL) { 728170589Syongari taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task); 729170589Syongari taskqueue_free(sc->nfe_tq); 730170589Syongari sc->nfe_tq = NULL; 731170589Syongari } 732159967Sobrien 733170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 734170589Syongari if (sc->nfe_intrhand[i] != NULL) { 735170589Syongari bus_teardown_intr(dev, sc->nfe_irq[i], 736170589Syongari sc->nfe_intrhand[i]); 737170589Syongari sc->nfe_intrhand[i] = NULL; 738170589Syongari } 739170589Syongari } 740159967Sobrien 741170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 742170589Syongari if (sc->nfe_irq[0] != NULL) 743170589Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, 744170589Syongari sc->nfe_irq[0]); 745170589Syongari } else { 746170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 747170589Syongari if (sc->nfe_irq[i] != NULL) { 748170589Syongari bus_release_resource(dev, SYS_RES_IRQ, rid, 749170589Syongari sc->nfe_irq[i]); 750170589Syongari sc->nfe_irq[i] = NULL; 751170589Syongari } 752170589Syongari } 753170589Syongari pci_release_msi(dev); 754170589Syongari } 755170589Syongari if (sc->nfe_msix_pba_res != NULL) { 756170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3), 757170589Syongari sc->nfe_msix_pba_res); 758170589Syongari sc->nfe_msix_pba_res = NULL; 759170589Syongari } 760170589Syongari if (sc->nfe_msix_res != NULL) { 761170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 762170589Syongari sc->nfe_msix_res); 763170589Syongari sc->nfe_msix_res = NULL; 764170589Syongari } 765170589Syongari if (sc->nfe_res[0] != NULL) { 766170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 767170589Syongari sc->nfe_res[0]); 768170589Syongari sc->nfe_res[0] = NULL; 769170589Syongari } 770170589Syongari 771159967Sobrien nfe_free_tx_ring(sc, &sc->txq); 772159967Sobrien nfe_free_rx_ring(sc, &sc->rxq); 773170589Syongari nfe_free_jrx_ring(sc, &sc->jrxq); 774159967Sobrien 775170589Syongari if (sc->nfe_parent_tag) { 776159967Sobrien bus_dma_tag_destroy(sc->nfe_parent_tag); 777170589Syongari sc->nfe_parent_tag = NULL; 778170589Syongari } 779159967Sobrien 780159967Sobrien mtx_destroy(&sc->nfe_mtx); 781159967Sobrien 782159967Sobrien return (0); 783159952Sobrien} 784159952Sobrien 785159967Sobrien 786170589Syongaristatic int 787170589Syongarinfe_suspend(device_t dev) 788170589Syongari{ 789170589Syongari struct nfe_softc *sc; 790170589Syongari 791170589Syongari sc = device_get_softc(dev); 792170589Syongari 793170589Syongari NFE_LOCK(sc); 794170589Syongari nfe_stop(sc->nfe_ifp); 795215132Syongari nfe_set_wol(sc); 796170589Syongari sc->nfe_suspended = 1; 797170589Syongari NFE_UNLOCK(sc); 798170589Syongari 799170589Syongari return (0); 800170589Syongari} 801170589Syongari 802170589Syongari 803170589Syongaristatic int 804170589Syongarinfe_resume(device_t dev) 805170589Syongari{ 806170589Syongari struct nfe_softc *sc; 807170589Syongari struct ifnet *ifp; 808170589Syongari 809170589Syongari sc = device_get_softc(dev); 810170589Syongari 811170589Syongari NFE_LOCK(sc); 812215132Syongari nfe_power(sc); 813170589Syongari ifp = sc->nfe_ifp; 814170589Syongari if (ifp->if_flags & IFF_UP) 815170589Syongari nfe_init_locked(sc); 816170589Syongari sc->nfe_suspended = 0; 817170589Syongari NFE_UNLOCK(sc); 818170589Syongari 819170589Syongari return (0); 820170589Syongari} 821170589Syongari 822170589Syongari 823215327Syongaristatic int 824215327Syongarinfe_can_use_msix(struct nfe_softc *sc) 825215327Syongari{ 826215327Syongari static struct msix_blacklist { 827215327Syongari char *maker; 828215327Syongari char *product; 829215327Syongari } msix_blacklists[] = { 830215327Syongari { "ASUSTeK Computer INC.", "P5N32-SLI PREMIUM" } 831215327Syongari }; 832215327Syongari 833215327Syongari struct msix_blacklist *mblp; 834215327Syongari char *maker, *product; 835215350Syongari int count, n, use_msix; 836215327Syongari 837215327Syongari /* 838215327Syongari * Search base board manufacturer and product name table 839215327Syongari * to see this system has a known MSI/MSI-X issue. 840215327Syongari */ 841215327Syongari maker = getenv("smbios.planar.maker"); 842215327Syongari product = getenv("smbios.planar.product"); 843215350Syongari use_msix = 1; 844215327Syongari if (maker != NULL && product != NULL) { 845215327Syongari count = sizeof(msix_blacklists) / sizeof(msix_blacklists[0]); 846215327Syongari mblp = msix_blacklists; 847215327Syongari for (n = 0; n < count; n++) { 848215327Syongari if (strcmp(maker, mblp->maker) == 0 && 849215350Syongari strcmp(product, mblp->product) == 0) { 850215350Syongari use_msix = 0; 851215350Syongari break; 852215350Syongari } 853215327Syongari mblp++; 854215327Syongari } 855215327Syongari } 856215350Syongari if (maker != NULL) 857215350Syongari freeenv(maker); 858215350Syongari if (product != NULL) 859215350Syongari freeenv(product); 860215327Syongari 861215350Syongari return (use_msix); 862215327Syongari} 863215327Syongari 864215327Syongari 865170589Syongari/* Take PHY/NIC out of powerdown, from Linux */ 866159967Sobrienstatic void 867170589Syongarinfe_power(struct nfe_softc *sc) 868170589Syongari{ 869170589Syongari uint32_t pwr; 870170589Syongari 871170589Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) == 0) 872170589Syongari return; 873170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2); 874170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC); 875170589Syongari DELAY(100); 876170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, 0); 877170589Syongari DELAY(100); 878170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2); 879170589Syongari pwr = NFE_READ(sc, NFE_PWR2_CTL); 880170589Syongari pwr &= ~NFE_PWR2_WAKEUP_MASK; 881170589Syongari if (sc->nfe_revid >= 0xa3 && 882170589Syongari (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 || 883170589Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2)) 884170589Syongari pwr |= NFE_PWR2_REVA3; 885170589Syongari NFE_WRITE(sc, NFE_PWR2_CTL, pwr); 886170589Syongari} 887170589Syongari 888170589Syongari 889170589Syongaristatic void 890159967Sobriennfe_miibus_statchg(device_t dev) 891159952Sobrien{ 892159967Sobrien struct nfe_softc *sc; 893159967Sobrien struct mii_data *mii; 894170589Syongari struct ifnet *ifp; 895215132Syongari uint32_t rxctl, txctl; 896159952Sobrien 897215132Syongari sc = device_get_softc(dev); 898170589Syongari 899159967Sobrien mii = device_get_softc(sc->nfe_miibus); 900170589Syongari ifp = sc->nfe_ifp; 901159967Sobrien 902215132Syongari sc->nfe_link = 0; 903215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 904215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 905215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 906215132Syongari case IFM_10_T: 907215132Syongari case IFM_100_TX: 908215132Syongari case IFM_1000_T: 909170589Syongari sc->nfe_link = 1; 910215132Syongari break; 911215132Syongari default: 912215132Syongari break; 913215132Syongari } 914215132Syongari } 915170589Syongari 916215132Syongari nfe_mac_config(sc, mii); 917215132Syongari txctl = NFE_READ(sc, NFE_TX_CTL); 918215132Syongari rxctl = NFE_READ(sc, NFE_RX_CTL); 919215132Syongari if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 920215132Syongari txctl |= NFE_TX_START; 921215132Syongari rxctl |= NFE_RX_START; 922215132Syongari } else { 923215132Syongari txctl &= ~NFE_TX_START; 924215132Syongari rxctl &= ~NFE_RX_START; 925215132Syongari } 926215132Syongari NFE_WRITE(sc, NFE_TX_CTL, txctl); 927215132Syongari NFE_WRITE(sc, NFE_RX_CTL, rxctl); 928215132Syongari} 929215132Syongari 930215132Syongari 931215132Syongaristatic void 932215132Syongarinfe_mac_config(struct nfe_softc *sc, struct mii_data *mii) 933215132Syongari{ 934215132Syongari uint32_t link, misc, phy, seed; 935215132Syongari uint32_t val; 936215132Syongari 937215132Syongari NFE_LOCK_ASSERT(sc); 938215132Syongari 939159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 940159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 941159952Sobrien 942159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 943159952Sobrien seed &= ~NFE_SEED_MASK; 944159952Sobrien 945215132Syongari misc = NFE_MISC1_MAGIC; 946215132Syongari link = NFE_MEDIA_SET; 947215132Syongari 948215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) == 0) { 949159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 950159952Sobrien misc |= NFE_MISC1_HDX; 951159952Sobrien } 952159952Sobrien 953159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 954159952Sobrien case IFM_1000_T: /* full-duplex only */ 955159952Sobrien link |= NFE_MEDIA_1000T; 956159952Sobrien seed |= NFE_SEED_1000T; 957159952Sobrien phy |= NFE_PHY_1000T; 958159952Sobrien break; 959159952Sobrien case IFM_100_TX: 960159952Sobrien link |= NFE_MEDIA_100TX; 961159952Sobrien seed |= NFE_SEED_100TX; 962159952Sobrien phy |= NFE_PHY_100TX; 963159952Sobrien break; 964159952Sobrien case IFM_10_T: 965159952Sobrien link |= NFE_MEDIA_10T; 966159952Sobrien seed |= NFE_SEED_10T; 967159952Sobrien break; 968159952Sobrien } 969159952Sobrien 970170589Syongari if ((phy & 0x10000000) != 0) { 971170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 972170589Syongari val = NFE_R1_MAGIC_1000; 973170589Syongari else 974170589Syongari val = NFE_R1_MAGIC_10_100; 975170589Syongari } else 976170589Syongari val = NFE_R1_MAGIC_DEFAULT; 977170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, val); 978170589Syongari 979159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 980159952Sobrien 981159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 982159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 983159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 984170589Syongari 985215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 986170589Syongari /* It seems all hardwares supports Rx pause frames. */ 987170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 988215297Smarius if ((IFM_OPTIONS(mii->mii_media_active) & 989215297Smarius IFM_ETH_RXPAUSE) != 0) 990170589Syongari val |= NFE_PFF_RX_PAUSE; 991170589Syongari else 992170589Syongari val &= ~NFE_PFF_RX_PAUSE; 993170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 994170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 995170589Syongari val = NFE_READ(sc, NFE_MISC1); 996215132Syongari if ((IFM_OPTIONS(mii->mii_media_active) & 997215297Smarius IFM_ETH_TXPAUSE) != 0) { 998170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 999170589Syongari NFE_TX_PAUSE_FRAME_ENABLE); 1000170589Syongari val |= NFE_MISC1_TX_PAUSE; 1001170589Syongari } else { 1002170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 1003170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1004170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 1005170589Syongari } 1006170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 1007170589Syongari } 1008170589Syongari } else { 1009170589Syongari /* disable rx/tx pause frames */ 1010170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 1011170589Syongari val &= ~NFE_PFF_RX_PAUSE; 1012170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 1013170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 1014170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 1015170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 1016170589Syongari val = NFE_READ(sc, NFE_MISC1); 1017170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 1018170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 1019170589Syongari } 1020170589Syongari } 1021159952Sobrien} 1022159952Sobrien 1023163503Sobrien 1024159967Sobrienstatic int 1025159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg) 1026159952Sobrien{ 1027159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 1028170589Syongari uint32_t val; 1029159952Sobrien int ntries; 1030159952Sobrien 1031159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1032159952Sobrien 1033159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1034159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1035159952Sobrien DELAY(100); 1036159952Sobrien } 1037159952Sobrien 1038159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 1039159952Sobrien 1040170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1041159952Sobrien DELAY(100); 1042159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1043159952Sobrien break; 1044159952Sobrien } 1045170589Syongari if (ntries == NFE_TIMEOUT) { 1046170589Syongari DPRINTFN(sc, 2, "timeout waiting for PHY\n"); 1047159952Sobrien return 0; 1048159952Sobrien } 1049159952Sobrien 1050159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 1051170589Syongari DPRINTFN(sc, 2, "could not read PHY\n"); 1052159952Sobrien return 0; 1053159952Sobrien } 1054159952Sobrien 1055159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 1056159952Sobrien if (val != 0xffffffff && val != 0) 1057159952Sobrien sc->mii_phyaddr = phy; 1058159952Sobrien 1059170589Syongari DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 1060159952Sobrien 1061170589Syongari return (val); 1062159952Sobrien} 1063159952Sobrien 1064163503Sobrien 1065159967Sobrienstatic int 1066159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val) 1067159952Sobrien{ 1068159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 1069170589Syongari uint32_t ctl; 1070163503Sobrien int ntries; 1071159952Sobrien 1072159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1073159952Sobrien 1074159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 1075159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 1076159952Sobrien DELAY(100); 1077159952Sobrien } 1078159952Sobrien 1079159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 1080159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 1081159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 1082159952Sobrien 1083170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 1084159952Sobrien DELAY(100); 1085159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 1086159952Sobrien break; 1087159952Sobrien } 1088159952Sobrien#ifdef NFE_DEBUG 1089170589Syongari if (nfedebug >= 2 && ntries == NFE_TIMEOUT) 1090170589Syongari device_printf(sc->nfe_dev, "could not write to PHY\n"); 1091159952Sobrien#endif 1092170589Syongari return (0); 1093159952Sobrien} 1094159952Sobrien 1095170589Syongaristruct nfe_dmamap_arg { 1096170589Syongari bus_addr_t nfe_busaddr; 1097170589Syongari}; 1098170589Syongari 1099159967Sobrienstatic int 1100159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1101159952Sobrien{ 1102170589Syongari struct nfe_dmamap_arg ctx; 1103159967Sobrien struct nfe_rx_data *data; 1104170589Syongari void *desc; 1105159967Sobrien int i, error, descsize; 1106159967Sobrien 1107159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1108170589Syongari desc = ring->desc64; 1109159967Sobrien descsize = sizeof (struct nfe_desc64); 1110159967Sobrien } else { 1111170589Syongari desc = ring->desc32; 1112159967Sobrien descsize = sizeof (struct nfe_desc32); 1113159967Sobrien } 1114159967Sobrien 1115159967Sobrien ring->cur = ring->next = 0; 1116159967Sobrien 1117163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1118170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1119170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1120170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1121170589Syongari NULL, NULL, /* filter, filterarg */ 1122170589Syongari NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1123170589Syongari NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 1124170589Syongari 0, /* flags */ 1125170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1126170589Syongari &ring->rx_desc_tag); 1127159967Sobrien if (error != 0) { 1128170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1129159967Sobrien goto fail; 1130159967Sobrien } 1131159967Sobrien 1132159967Sobrien /* allocate memory to desc */ 1133170589Syongari error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK | 1134170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map); 1135159967Sobrien if (error != 0) { 1136170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1137159967Sobrien goto fail; 1138159967Sobrien } 1139170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1140170589Syongari ring->desc64 = desc; 1141170589Syongari else 1142170589Syongari ring->desc32 = desc; 1143159967Sobrien 1144159967Sobrien /* map desc to device visible address space */ 1145170589Syongari ctx.nfe_busaddr = 0; 1146170589Syongari error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc, 1147170589Syongari NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1148159967Sobrien if (error != 0) { 1149170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1150159967Sobrien goto fail; 1151159967Sobrien } 1152170589Syongari ring->physaddr = ctx.nfe_busaddr; 1153159967Sobrien 1154170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1155170589Syongari 1, 0, /* alignment, boundary */ 1156170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1157170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1158170589Syongari NULL, NULL, /* filter, filterarg */ 1159170589Syongari MCLBYTES, 1, /* maxsize, nsegments */ 1160170589Syongari MCLBYTES, /* maxsegsize */ 1161170589Syongari 0, /* flags */ 1162170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1163170589Syongari &ring->rx_data_tag); 1164170589Syongari if (error != 0) { 1165170589Syongari device_printf(sc->nfe_dev, "could not create Rx DMA tag\n"); 1166170589Syongari goto fail; 1167170589Syongari } 1168159967Sobrien 1169170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map); 1170170589Syongari if (error != 0) { 1171170589Syongari device_printf(sc->nfe_dev, 1172170589Syongari "could not create Rx DMA spare map\n"); 1173170589Syongari goto fail; 1174170589Syongari } 1175170589Syongari 1176159967Sobrien /* 1177159967Sobrien * Pre-allocate Rx buffers and populate Rx ring. 1178159967Sobrien */ 1179159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1180159967Sobrien data = &sc->rxq.data[i]; 1181170589Syongari data->rx_data_map = NULL; 1182170589Syongari data->m = NULL; 1183170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, 1184170589Syongari &data->rx_data_map); 1185164651Sobrien if (error != 0) { 1186170589Syongari device_printf(sc->nfe_dev, 1187170589Syongari "could not create Rx DMA map\n"); 1188164651Sobrien goto fail; 1189164651Sobrien } 1190170589Syongari } 1191159967Sobrien 1192170589Syongarifail: 1193170589Syongari return (error); 1194170589Syongari} 1195170589Syongari 1196170589Syongari 1197171559Syongaristatic void 1198170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1199170589Syongari{ 1200170589Syongari struct nfe_dmamap_arg ctx; 1201170589Syongari struct nfe_rx_data *data; 1202170589Syongari void *desc; 1203170589Syongari int i, error, descsize; 1204170589Syongari 1205170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1206171559Syongari return; 1207171559Syongari if (jumbo_disable != 0) { 1208171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support\n"); 1209171559Syongari sc->nfe_jumbo_disable = 1; 1210171559Syongari return; 1211171559Syongari } 1212170589Syongari 1213170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1214170589Syongari desc = ring->jdesc64; 1215170589Syongari descsize = sizeof (struct nfe_desc64); 1216170589Syongari } else { 1217170589Syongari desc = ring->jdesc32; 1218170589Syongari descsize = sizeof (struct nfe_desc32); 1219170589Syongari } 1220170589Syongari 1221170589Syongari ring->jcur = ring->jnext = 0; 1222170589Syongari 1223170589Syongari /* Create DMA tag for jumbo Rx ring. */ 1224170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1225170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1226170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1227170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1228170589Syongari NULL, NULL, /* filter, filterarg */ 1229170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsize */ 1230170589Syongari 1, /* nsegments */ 1231170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsegsize */ 1232170589Syongari 0, /* flags */ 1233170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1234170589Syongari &ring->jrx_desc_tag); 1235170589Syongari if (error != 0) { 1236170589Syongari device_printf(sc->nfe_dev, 1237170589Syongari "could not create jumbo ring DMA tag\n"); 1238170589Syongari goto fail; 1239170589Syongari } 1240170589Syongari 1241170589Syongari /* Create DMA tag for jumbo Rx buffers. */ 1242170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1243192706Syongari 1, 0, /* alignment, boundary */ 1244170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1245170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1246170589Syongari NULL, NULL, /* filter, filterarg */ 1247176859Syongari MJUM9BYTES, /* maxsize */ 1248170589Syongari 1, /* nsegments */ 1249176859Syongari MJUM9BYTES, /* maxsegsize */ 1250170589Syongari 0, /* flags */ 1251170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1252170589Syongari &ring->jrx_data_tag); 1253170589Syongari if (error != 0) { 1254170589Syongari device_printf(sc->nfe_dev, 1255170589Syongari "could not create jumbo Rx buffer DMA tag\n"); 1256170589Syongari goto fail; 1257170589Syongari } 1258170589Syongari 1259170589Syongari /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ 1260170589Syongari error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK | 1261170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map); 1262170589Syongari if (error != 0) { 1263170589Syongari device_printf(sc->nfe_dev, 1264170589Syongari "could not allocate DMA'able memory for jumbo Rx ring\n"); 1265170589Syongari goto fail; 1266170589Syongari } 1267170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1268170589Syongari ring->jdesc64 = desc; 1269170589Syongari else 1270170589Syongari ring->jdesc32 = desc; 1271170589Syongari 1272170589Syongari ctx.nfe_busaddr = 0; 1273170589Syongari error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc, 1274170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1275170589Syongari if (error != 0) { 1276170589Syongari device_printf(sc->nfe_dev, 1277170589Syongari "could not load DMA'able memory for jumbo Rx ring\n"); 1278170589Syongari goto fail; 1279170589Syongari } 1280170589Syongari ring->jphysaddr = ctx.nfe_busaddr; 1281170589Syongari 1282170589Syongari /* Create DMA maps for jumbo Rx buffers. */ 1283170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map); 1284170589Syongari if (error != 0) { 1285170589Syongari device_printf(sc->nfe_dev, 1286170589Syongari "could not create jumbo Rx DMA spare map\n"); 1287170589Syongari goto fail; 1288170589Syongari } 1289170589Syongari 1290170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1291170589Syongari data = &sc->jrxq.jdata[i]; 1292170589Syongari data->rx_data_map = NULL; 1293170589Syongari data->m = NULL; 1294170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, 1295164651Sobrien &data->rx_data_map); 1296164651Sobrien if (error != 0) { 1297170589Syongari device_printf(sc->nfe_dev, 1298170589Syongari "could not create jumbo Rx DMA map\n"); 1299164651Sobrien goto fail; 1300164651Sobrien } 1301170589Syongari } 1302159967Sobrien 1303171559Syongari return; 1304159967Sobrien 1305170589Syongarifail: 1306171559Syongari /* 1307171559Syongari * Running without jumbo frame support is ok for most cases 1308171559Syongari * so don't fail on creating dma tag/map for jumbo frame. 1309171559Syongari */ 1310170589Syongari nfe_free_jrx_ring(sc, ring); 1311171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support due to " 1312171559Syongari "resource shortage\n"); 1313171559Syongari sc->nfe_jumbo_disable = 1; 1314170589Syongari} 1315159967Sobrien 1316159967Sobrien 1317170589Syongaristatic int 1318170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1319170589Syongari{ 1320170589Syongari void *desc; 1321170589Syongari size_t descsize; 1322170589Syongari int i; 1323159967Sobrien 1324170589Syongari ring->cur = ring->next = 0; 1325170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1326170589Syongari desc = ring->desc64; 1327170589Syongari descsize = sizeof (struct nfe_desc64); 1328170589Syongari } else { 1329170589Syongari desc = ring->desc32; 1330170589Syongari descsize = sizeof (struct nfe_desc32); 1331159967Sobrien } 1332170589Syongari bzero(desc, descsize * NFE_RX_RING_COUNT); 1333170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1334170589Syongari if (nfe_newbuf(sc, i) != 0) 1335170589Syongari return (ENOBUFS); 1336170589Syongari } 1337159967Sobrien 1338163503Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 1339170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1340159967Sobrien 1341170589Syongari return (0); 1342159967Sobrien} 1343159967Sobrien 1344163503Sobrien 1345170589Syongaristatic int 1346170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1347159967Sobrien{ 1348170589Syongari void *desc; 1349170589Syongari size_t descsize; 1350159967Sobrien int i; 1351159967Sobrien 1352170589Syongari ring->jcur = ring->jnext = 0; 1353170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1354170589Syongari desc = ring->jdesc64; 1355170589Syongari descsize = sizeof (struct nfe_desc64); 1356170589Syongari } else { 1357170589Syongari desc = ring->jdesc32; 1358170589Syongari descsize = sizeof (struct nfe_desc32); 1359159952Sobrien } 1360176859Syongari bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT); 1361170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1362170589Syongari if (nfe_jnewbuf(sc, i) != 0) 1363170589Syongari return (ENOBUFS); 1364170589Syongari } 1365159952Sobrien 1366170589Syongari bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map, 1367170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1368159952Sobrien 1369170589Syongari return (0); 1370159967Sobrien} 1371159967Sobrien 1372159967Sobrien 1373159967Sobrienstatic void 1374159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1375159967Sobrien{ 1376159967Sobrien struct nfe_rx_data *data; 1377159967Sobrien void *desc; 1378266921Sbrueffer int i; 1379159967Sobrien 1380266921Sbrueffer if (sc->nfe_flags & NFE_40BIT_ADDR) 1381159967Sobrien desc = ring->desc64; 1382266921Sbrueffer else 1383159967Sobrien desc = ring->desc32; 1384159952Sobrien 1385170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1386170589Syongari data = &ring->data[i]; 1387170589Syongari if (data->rx_data_map != NULL) { 1388170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1389170589Syongari data->rx_data_map); 1390170589Syongari data->rx_data_map = NULL; 1391170589Syongari } 1392170589Syongari if (data->m != NULL) { 1393170589Syongari m_freem(data->m); 1394170589Syongari data->m = NULL; 1395170589Syongari } 1396170589Syongari } 1397170589Syongari if (ring->rx_data_tag != NULL) { 1398170589Syongari if (ring->rx_spare_map != NULL) { 1399170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1400170589Syongari ring->rx_spare_map); 1401170589Syongari ring->rx_spare_map = NULL; 1402170589Syongari } 1403170589Syongari bus_dma_tag_destroy(ring->rx_data_tag); 1404170589Syongari ring->rx_data_tag = NULL; 1405170589Syongari } 1406170589Syongari 1407159967Sobrien if (desc != NULL) { 1408159967Sobrien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 1409159967Sobrien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 1410170589Syongari ring->desc64 = NULL; 1411170589Syongari ring->desc32 = NULL; 1412170589Syongari ring->rx_desc_map = NULL; 1413170589Syongari } 1414170589Syongari if (ring->rx_desc_tag != NULL) { 1415159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 1416170589Syongari ring->rx_desc_tag = NULL; 1417159967Sobrien } 1418170589Syongari} 1419159967Sobrien 1420164650Sobrien 1421170589Syongaristatic void 1422170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1423170589Syongari{ 1424170589Syongari struct nfe_rx_data *data; 1425170589Syongari void *desc; 1426170589Syongari int i, descsize; 1427170589Syongari 1428170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1429170589Syongari return; 1430170589Syongari 1431170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1432170589Syongari desc = ring->jdesc64; 1433170589Syongari descsize = sizeof (struct nfe_desc64); 1434170589Syongari } else { 1435170589Syongari desc = ring->jdesc32; 1436170589Syongari descsize = sizeof (struct nfe_desc32); 1437170589Syongari } 1438170589Syongari 1439170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1440170589Syongari data = &ring->jdata[i]; 1441164651Sobrien if (data->rx_data_map != NULL) { 1442170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1443164651Sobrien data->rx_data_map); 1444170589Syongari data->rx_data_map = NULL; 1445164651Sobrien } 1446170589Syongari if (data->m != NULL) { 1447164651Sobrien m_freem(data->m); 1448170589Syongari data->m = NULL; 1449170589Syongari } 1450164651Sobrien } 1451170589Syongari if (ring->jrx_data_tag != NULL) { 1452170589Syongari if (ring->jrx_spare_map != NULL) { 1453170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1454170589Syongari ring->jrx_spare_map); 1455170589Syongari ring->jrx_spare_map = NULL; 1456170589Syongari } 1457170589Syongari bus_dma_tag_destroy(ring->jrx_data_tag); 1458170589Syongari ring->jrx_data_tag = NULL; 1459170589Syongari } 1460170589Syongari 1461170589Syongari if (desc != NULL) { 1462170589Syongari bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1463170589Syongari bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1464170589Syongari ring->jdesc64 = NULL; 1465170589Syongari ring->jdesc32 = NULL; 1466170589Syongari ring->jrx_desc_map = NULL; 1467170589Syongari } 1468176859Syongari 1469170589Syongari if (ring->jrx_desc_tag != NULL) { 1470170589Syongari bus_dma_tag_destroy(ring->jrx_desc_tag); 1471170589Syongari ring->jrx_desc_tag = NULL; 1472170589Syongari } 1473159952Sobrien} 1474159952Sobrien 1475163503Sobrien 1476159967Sobrienstatic int 1477159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1478159952Sobrien{ 1479170589Syongari struct nfe_dmamap_arg ctx; 1480159967Sobrien int i, error; 1481170589Syongari void *desc; 1482159967Sobrien int descsize; 1483159952Sobrien 1484159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1485170589Syongari desc = ring->desc64; 1486159967Sobrien descsize = sizeof (struct nfe_desc64); 1487159967Sobrien } else { 1488170589Syongari desc = ring->desc32; 1489159967Sobrien descsize = sizeof (struct nfe_desc32); 1490159967Sobrien } 1491159952Sobrien 1492159967Sobrien ring->queued = 0; 1493159967Sobrien ring->cur = ring->next = 0; 1494159967Sobrien 1495163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1496170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1497170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1498170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1499170589Syongari NULL, NULL, /* filter, filterarg */ 1500170589Syongari NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1501170589Syongari NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1502170589Syongari 0, /* flags */ 1503170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1504170589Syongari &ring->tx_desc_tag); 1505159967Sobrien if (error != 0) { 1506170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1507159967Sobrien goto fail; 1508159952Sobrien } 1509159952Sobrien 1510170589Syongari error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1511170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1512159967Sobrien if (error != 0) { 1513170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1514159967Sobrien goto fail; 1515159967Sobrien } 1516170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1517170589Syongari ring->desc64 = desc; 1518170589Syongari else 1519170589Syongari ring->desc32 = desc; 1520159967Sobrien 1521170589Syongari ctx.nfe_busaddr = 0; 1522170589Syongari error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1523170589Syongari NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1524159967Sobrien if (error != 0) { 1525170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1526159967Sobrien goto fail; 1527159967Sobrien } 1528170589Syongari ring->physaddr = ctx.nfe_busaddr; 1529159967Sobrien 1530163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1531170589Syongari 1, 0, 1532170589Syongari BUS_SPACE_MAXADDR, 1533170589Syongari BUS_SPACE_MAXADDR, 1534170589Syongari NULL, NULL, 1535170595Syongari NFE_TSO_MAXSIZE, 1536170589Syongari NFE_MAX_SCATTER, 1537170595Syongari NFE_TSO_MAXSGSIZE, 1538170589Syongari 0, 1539170589Syongari NULL, NULL, 1540170589Syongari &ring->tx_data_tag); 1541159967Sobrien if (error != 0) { 1542170589Syongari device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1543170589Syongari goto fail; 1544159967Sobrien } 1545159967Sobrien 1546159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1547163503Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, 1548163503Sobrien &ring->data[i].tx_data_map); 1549159967Sobrien if (error != 0) { 1550170589Syongari device_printf(sc->nfe_dev, 1551170589Syongari "could not create Tx DMA map\n"); 1552159967Sobrien goto fail; 1553159967Sobrien } 1554159967Sobrien } 1555159967Sobrien 1556170589Syongarifail: 1557170589Syongari return (error); 1558159967Sobrien} 1559159967Sobrien 1560159967Sobrien 1561159967Sobrienstatic void 1562170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1563159967Sobrien{ 1564170589Syongari void *desc; 1565170589Syongari size_t descsize; 1566159967Sobrien 1567170589Syongari sc->nfe_force_tx = 0; 1568170589Syongari ring->queued = 0; 1569170589Syongari ring->cur = ring->next = 0; 1570170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1571170589Syongari desc = ring->desc64; 1572170589Syongari descsize = sizeof (struct nfe_desc64); 1573170589Syongari } else { 1574170589Syongari desc = ring->desc32; 1575170589Syongari descsize = sizeof (struct nfe_desc32); 1576159967Sobrien } 1577170589Syongari bzero(desc, descsize * NFE_TX_RING_COUNT); 1578159967Sobrien 1579163503Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1580170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1581159967Sobrien} 1582159967Sobrien 1583163503Sobrien 1584159967Sobrienstatic void 1585159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1586159967Sobrien{ 1587159967Sobrien struct nfe_tx_data *data; 1588159967Sobrien void *desc; 1589159967Sobrien int i, descsize; 1590159967Sobrien 1591159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1592159967Sobrien desc = ring->desc64; 1593159967Sobrien descsize = sizeof (struct nfe_desc64); 1594159967Sobrien } else { 1595159967Sobrien desc = ring->desc32; 1596159967Sobrien descsize = sizeof (struct nfe_desc32); 1597159967Sobrien } 1598159967Sobrien 1599159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1600159967Sobrien data = &ring->data[i]; 1601159967Sobrien 1602159967Sobrien if (data->m != NULL) { 1603170589Syongari bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1604163503Sobrien BUS_DMASYNC_POSTWRITE); 1605170589Syongari bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1606159967Sobrien m_freem(data->m); 1607170589Syongari data->m = NULL; 1608159967Sobrien } 1609170589Syongari if (data->tx_data_map != NULL) { 1610170589Syongari bus_dmamap_destroy(ring->tx_data_tag, 1611170589Syongari data->tx_data_map); 1612170589Syongari data->tx_data_map = NULL; 1613170589Syongari } 1614159967Sobrien } 1615159967Sobrien 1616170589Syongari if (ring->tx_data_tag != NULL) { 1617170589Syongari bus_dma_tag_destroy(ring->tx_data_tag); 1618170589Syongari ring->tx_data_tag = NULL; 1619159967Sobrien } 1620159967Sobrien 1621170589Syongari if (desc != NULL) { 1622170589Syongari bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1623170589Syongari BUS_DMASYNC_POSTWRITE); 1624170589Syongari bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1625170589Syongari bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1626170589Syongari ring->desc64 = NULL; 1627170589Syongari ring->desc32 = NULL; 1628170589Syongari ring->tx_desc_map = NULL; 1629170589Syongari bus_dma_tag_destroy(ring->tx_desc_tag); 1630170589Syongari ring->tx_desc_tag = NULL; 1631170589Syongari } 1632159967Sobrien} 1633159967Sobrien 1634159967Sobrien#ifdef DEVICE_POLLING 1635159967Sobrienstatic poll_handler_t nfe_poll; 1636159967Sobrien 1637163503Sobrien 1638193096Sattiliostatic int 1639159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1640159967Sobrien{ 1641164360Sobrien struct nfe_softc *sc = ifp->if_softc; 1642170589Syongari uint32_t r; 1643193096Sattilio int rx_npkts = 0; 1644159967Sobrien 1645159967Sobrien NFE_LOCK(sc); 1646159967Sobrien 1647159967Sobrien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1648170589Syongari NFE_UNLOCK(sc); 1649193096Sattilio return (rx_npkts); 1650159967Sobrien } 1651159967Sobrien 1652171559Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1653193096Sattilio rx_npkts = nfe_jrxeof(sc, count, &rx_npkts); 1654171559Syongari else 1655193096Sattilio rx_npkts = nfe_rxeof(sc, count, &rx_npkts); 1656159967Sobrien nfe_txeof(sc); 1657159967Sobrien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1658216925Sjhb nfe_start_locked(ifp); 1659159967Sobrien 1660159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1661170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1662170589Syongari NFE_UNLOCK(sc); 1663193096Sattilio return (rx_npkts); 1664163503Sobrien } 1665170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1666159967Sobrien 1667163503Sobrien if (r & NFE_IRQ_LINK) { 1668163503Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1669163503Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1670170589Syongari DPRINTF(sc, "link state changed\n"); 1671163503Sobrien } 1672159967Sobrien } 1673170589Syongari NFE_UNLOCK(sc); 1674193096Sattilio return (rx_npkts); 1675159967Sobrien} 1676159967Sobrien#endif /* DEVICE_POLLING */ 1677159967Sobrien 1678170589Syongaristatic void 1679170589Syongarinfe_set_intr(struct nfe_softc *sc) 1680170589Syongari{ 1681159967Sobrien 1682170589Syongari if (sc->nfe_msi != 0) 1683170589Syongari NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1684170589Syongari} 1685170589Syongari 1686170589Syongari 1687170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */ 1688170589Syongaristatic __inline void 1689170589Syongarinfe_enable_intr(struct nfe_softc *sc) 1690170589Syongari{ 1691170589Syongari 1692170589Syongari if (sc->nfe_msix != 0) { 1693170589Syongari /* XXX Should have a better way to enable interrupts! */ 1694170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1695170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1696170589Syongari } else 1697170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1698170589Syongari} 1699170589Syongari 1700170589Syongari 1701170589Syongaristatic __inline void 1702170589Syongarinfe_disable_intr(struct nfe_softc *sc) 1703170589Syongari{ 1704170589Syongari 1705170589Syongari if (sc->nfe_msix != 0) { 1706170589Syongari /* XXX Should have a better way to disable interrupts! */ 1707170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1708170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1709170589Syongari } else 1710170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1711170589Syongari} 1712170589Syongari 1713170589Syongari 1714159967Sobrienstatic int 1715159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1716159967Sobrien{ 1717170589Syongari struct nfe_softc *sc; 1718170589Syongari struct ifreq *ifr; 1719163503Sobrien struct mii_data *mii; 1720170589Syongari int error, init, mask; 1721159967Sobrien 1722170589Syongari sc = ifp->if_softc; 1723170589Syongari ifr = (struct ifreq *) data; 1724170589Syongari error = 0; 1725170589Syongari init = 0; 1726159952Sobrien switch (cmd) { 1727159952Sobrien case SIOCSIFMTU: 1728170589Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1729159952Sobrien error = EINVAL; 1730170589Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 1731171559Syongari if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) || 1732171559Syongari (sc->nfe_jumbo_disable != 0)) && 1733170589Syongari ifr->ifr_mtu > ETHERMTU) 1734170589Syongari error = EINVAL; 1735170589Syongari else { 1736170589Syongari NFE_LOCK(sc); 1737170589Syongari ifp->if_mtu = ifr->ifr_mtu; 1738217794Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1739217794Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1740170589Syongari nfe_init_locked(sc); 1741217794Syongari } 1742170589Syongari NFE_UNLOCK(sc); 1743164650Sobrien } 1744164650Sobrien } 1745159952Sobrien break; 1746159952Sobrien case SIOCSIFFLAGS: 1747159967Sobrien NFE_LOCK(sc); 1748159952Sobrien if (ifp->if_flags & IFF_UP) { 1749159952Sobrien /* 1750159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1751159952Sobrien * don't do a full re-init of the chip, just update 1752159952Sobrien * the Rx filter. 1753159952Sobrien */ 1754159967Sobrien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1755159967Sobrien ((ifp->if_flags ^ sc->nfe_if_flags) & 1756159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1757159952Sobrien nfe_setmulti(sc); 1758159967Sobrien else 1759159967Sobrien nfe_init_locked(sc); 1760159952Sobrien } else { 1761159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1762170589Syongari nfe_stop(ifp); 1763159952Sobrien } 1764159967Sobrien sc->nfe_if_flags = ifp->if_flags; 1765159967Sobrien NFE_UNLOCK(sc); 1766159967Sobrien error = 0; 1767159952Sobrien break; 1768159952Sobrien case SIOCADDMULTI: 1769159952Sobrien case SIOCDELMULTI: 1770170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1771159967Sobrien NFE_LOCK(sc); 1772159967Sobrien nfe_setmulti(sc); 1773159967Sobrien NFE_UNLOCK(sc); 1774159952Sobrien error = 0; 1775159952Sobrien } 1776159952Sobrien break; 1777159952Sobrien case SIOCSIFMEDIA: 1778159952Sobrien case SIOCGIFMEDIA: 1779159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1780159967Sobrien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1781159952Sobrien break; 1782159967Sobrien case SIOCSIFCAP: 1783170589Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1784159967Sobrien#ifdef DEVICE_POLLING 1785170589Syongari if ((mask & IFCAP_POLLING) != 0) { 1786170589Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1787159967Sobrien error = ether_poll_register(nfe_poll, ifp); 1788159967Sobrien if (error) 1789170589Syongari break; 1790159967Sobrien NFE_LOCK(sc); 1791170589Syongari nfe_disable_intr(sc); 1792163503Sobrien ifp->if_capenable |= IFCAP_POLLING; 1793159967Sobrien NFE_UNLOCK(sc); 1794159967Sobrien } else { 1795159967Sobrien error = ether_poll_deregister(ifp); 1796159967Sobrien /* Enable interrupt even in error case */ 1797159967Sobrien NFE_LOCK(sc); 1798170589Syongari nfe_enable_intr(sc); 1799159967Sobrien ifp->if_capenable &= ~IFCAP_POLLING; 1800159967Sobrien NFE_UNLOCK(sc); 1801159967Sobrien } 1802159967Sobrien } 1803163503Sobrien#endif /* DEVICE_POLLING */ 1804215132Syongari if ((mask & IFCAP_WOL_MAGIC) != 0 && 1805215132Syongari (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) 1806215132Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 1807215432Syongari if ((mask & IFCAP_TXCSUM) != 0 && 1808215432Syongari (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 1809215432Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 1810215432Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1811170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES; 1812159967Sobrien else 1813170589Syongari ifp->if_hwassist &= ~NFE_CSUM_FEATURES; 1814215432Syongari } 1815215432Syongari if ((mask & IFCAP_RXCSUM) != 0 && 1816215432Syongari (ifp->if_capabilities & IFCAP_RXCSUM) != 0) { 1817215432Syongari ifp->if_capenable ^= IFCAP_RXCSUM; 1818170589Syongari init++; 1819159967Sobrien } 1820215432Syongari if ((mask & IFCAP_TSO4) != 0 && 1821215432Syongari (ifp->if_capabilities & IFCAP_TSO4) != 0) { 1822215432Syongari ifp->if_capenable ^= IFCAP_TSO4; 1823215432Syongari if ((IFCAP_TSO4 & ifp->if_capenable) != 0) 1824215432Syongari ifp->if_hwassist |= CSUM_TSO; 1825215432Syongari else 1826215432Syongari ifp->if_hwassist &= ~CSUM_TSO; 1827215432Syongari } 1828215432Syongari if ((mask & IFCAP_VLAN_HWTSO) != 0 && 1829215432Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) 1830215432Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1831215432Syongari if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && 1832215432Syongari (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { 1833170589Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1834215432Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) 1835215432Syongari ifp->if_capenable &= ~IFCAP_VLAN_HWTSO; 1836170589Syongari init++; 1837170589Syongari } 1838170589Syongari /* 1839170589Syongari * XXX 1840170589Syongari * It seems that VLAN stripping requires Rx checksum offload. 1841170589Syongari * Unfortunately FreeBSD has no way to disable only Rx side 1842170589Syongari * VLAN stripping. So when we know Rx checksum offload is 1843170589Syongari * disabled turn entire hardware VLAN assist off. 1844170589Syongari */ 1845215432Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) { 1846215432Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 1847215432Syongari init++; 1848215432Syongari ifp->if_capenable &= ~(IFCAP_VLAN_HWTAGGING | 1849215432Syongari IFCAP_VLAN_HWTSO); 1850170589Syongari } 1851170589Syongari if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1852170589Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1853164656Sobrien nfe_init(sc); 1854170589Syongari } 1855215432Syongari VLAN_CAPABILITIES(ifp); 1856159967Sobrien break; 1857159952Sobrien default: 1858159967Sobrien error = ether_ioctl(ifp, cmd, data); 1859159967Sobrien break; 1860159952Sobrien } 1861159952Sobrien 1862170589Syongari return (error); 1863159952Sobrien} 1864159952Sobrien 1865159967Sobrien 1866170589Syongaristatic int 1867163503Sobriennfe_intr(void *arg) 1868159967Sobrien{ 1869170589Syongari struct nfe_softc *sc; 1870170589Syongari uint32_t status; 1871170589Syongari 1872170589Syongari sc = (struct nfe_softc *)arg; 1873170589Syongari 1874170589Syongari status = NFE_READ(sc, sc->nfe_irq_status); 1875170589Syongari if (status == 0 || status == 0xffffffff) 1876170589Syongari return (FILTER_STRAY); 1877170589Syongari nfe_disable_intr(sc); 1878173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1879170589Syongari 1880170589Syongari return (FILTER_HANDLED); 1881170589Syongari} 1882170589Syongari 1883170589Syongari 1884170589Syongaristatic void 1885170589Syongarinfe_int_task(void *arg, int pending) 1886170589Syongari{ 1887159967Sobrien struct nfe_softc *sc = arg; 1888159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1889170589Syongari uint32_t r; 1890170589Syongari int domore; 1891159967Sobrien 1892163503Sobrien NFE_LOCK(sc); 1893159967Sobrien 1894170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1895170589Syongari nfe_enable_intr(sc); 1896170589Syongari NFE_UNLOCK(sc); 1897170589Syongari return; /* not for us */ 1898170589Syongari } 1899170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1900170589Syongari 1901170589Syongari DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1902170589Syongari 1903159967Sobrien#ifdef DEVICE_POLLING 1904159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) { 1905159967Sobrien NFE_UNLOCK(sc); 1906159967Sobrien return; 1907159967Sobrien } 1908159967Sobrien#endif 1909159967Sobrien 1910172169Syongari if (r & NFE_IRQ_LINK) { 1911172169Syongari NFE_READ(sc, NFE_PHY_STATUS); 1912172169Syongari NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1913172169Syongari DPRINTF(sc, "link state changed\n"); 1914172169Syongari } 1915172169Syongari 1916170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1917163503Sobrien NFE_UNLOCK(sc); 1918222542Syongari nfe_disable_intr(sc); 1919170589Syongari return; 1920159967Sobrien } 1921159967Sobrien 1922170589Syongari domore = 0; 1923170589Syongari /* check Rx ring */ 1924170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1925193096Sattilio domore = nfe_jrxeof(sc, sc->nfe_process_limit, NULL); 1926170589Syongari else 1927193096Sattilio domore = nfe_rxeof(sc, sc->nfe_process_limit, NULL); 1928170589Syongari /* check Tx ring */ 1929170589Syongari nfe_txeof(sc); 1930159967Sobrien 1931170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1932216925Sjhb nfe_start_locked(ifp); 1933159967Sobrien 1934159967Sobrien NFE_UNLOCK(sc); 1935159967Sobrien 1936170589Syongari if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1937173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1938170589Syongari return; 1939170589Syongari } 1940170589Syongari 1941170589Syongari /* Reenable interrupts. */ 1942170589Syongari nfe_enable_intr(sc); 1943159967Sobrien} 1944159967Sobrien 1945163503Sobrien 1946170589Syongaristatic __inline void 1947170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1948159952Sobrien{ 1949170589Syongari struct nfe_desc32 *desc32; 1950170589Syongari struct nfe_desc64 *desc64; 1951170589Syongari struct nfe_rx_data *data; 1952170589Syongari struct mbuf *m; 1953163503Sobrien 1954170589Syongari data = &sc->rxq.data[idx]; 1955170589Syongari m = data->m; 1956170589Syongari 1957170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1958170589Syongari desc64 = &sc->rxq.desc64[idx]; 1959170589Syongari /* VLAN packet may have overwritten it. */ 1960170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1961170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1962170589Syongari desc64->length = htole16(m->m_len); 1963170589Syongari desc64->flags = htole16(NFE_RX_READY); 1964170589Syongari } else { 1965170589Syongari desc32 = &sc->rxq.desc32[idx]; 1966170589Syongari desc32->length = htole16(m->m_len); 1967170589Syongari desc32->flags = htole16(NFE_RX_READY); 1968170589Syongari } 1969159952Sobrien} 1970159952Sobrien 1971163503Sobrien 1972170589Syongaristatic __inline void 1973170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1974159952Sobrien{ 1975170589Syongari struct nfe_desc32 *desc32; 1976170589Syongari struct nfe_desc64 *desc64; 1977170589Syongari struct nfe_rx_data *data; 1978170589Syongari struct mbuf *m; 1979163503Sobrien 1980170589Syongari data = &sc->jrxq.jdata[idx]; 1981170589Syongari m = data->m; 1982170589Syongari 1983170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1984170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 1985170589Syongari /* VLAN packet may have overwritten it. */ 1986170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1987170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1988170589Syongari desc64->length = htole16(m->m_len); 1989170589Syongari desc64->flags = htole16(NFE_RX_READY); 1990170589Syongari } else { 1991170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 1992170589Syongari desc32->length = htole16(m->m_len); 1993170589Syongari desc32->flags = htole16(NFE_RX_READY); 1994170589Syongari } 1995159952Sobrien} 1996159952Sobrien 1997163503Sobrien 1998170589Syongaristatic int 1999170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx) 2000159952Sobrien{ 2001170589Syongari struct nfe_rx_data *data; 2002170589Syongari struct nfe_desc32 *desc32; 2003170589Syongari struct nfe_desc64 *desc64; 2004170589Syongari struct mbuf *m; 2005170589Syongari bus_dma_segment_t segs[1]; 2006170589Syongari bus_dmamap_t map; 2007170589Syongari int nsegs; 2008163503Sobrien 2009243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 2010170589Syongari if (m == NULL) 2011170589Syongari return (ENOBUFS); 2012159952Sobrien 2013170589Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 2014170589Syongari m_adj(m, ETHER_ALIGN); 2015163503Sobrien 2016170589Syongari if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 2017170589Syongari m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2018170589Syongari m_freem(m); 2019170589Syongari return (ENOBUFS); 2020170589Syongari } 2021170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2022163503Sobrien 2023170589Syongari data = &sc->rxq.data[idx]; 2024170589Syongari if (data->m != NULL) { 2025170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2026170589Syongari BUS_DMASYNC_POSTREAD); 2027170589Syongari bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 2028170589Syongari } 2029170589Syongari map = data->rx_data_map; 2030170589Syongari data->rx_data_map = sc->rxq.rx_spare_map; 2031170589Syongari sc->rxq.rx_spare_map = map; 2032170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 2033170589Syongari BUS_DMASYNC_PREREAD); 2034170589Syongari data->paddr = segs[0].ds_addr; 2035170589Syongari data->m = m; 2036170589Syongari /* update mapping address in h/w descriptor */ 2037170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2038170589Syongari desc64 = &sc->rxq.desc64[idx]; 2039170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2040170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2041170589Syongari desc64->length = htole16(segs[0].ds_len); 2042170589Syongari desc64->flags = htole16(NFE_RX_READY); 2043170589Syongari } else { 2044170589Syongari desc32 = &sc->rxq.desc32[idx]; 2045170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2046170589Syongari desc32->length = htole16(segs[0].ds_len); 2047170589Syongari desc32->flags = htole16(NFE_RX_READY); 2048170589Syongari } 2049170589Syongari 2050170589Syongari return (0); 2051159952Sobrien} 2052159952Sobrien 2053163503Sobrien 2054170589Syongaristatic int 2055170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx) 2056159952Sobrien{ 2057170589Syongari struct nfe_rx_data *data; 2058170589Syongari struct nfe_desc32 *desc32; 2059170589Syongari struct nfe_desc64 *desc64; 2060170589Syongari struct mbuf *m; 2061170589Syongari bus_dma_segment_t segs[1]; 2062170589Syongari bus_dmamap_t map; 2063170589Syongari int nsegs; 2064163503Sobrien 2065243857Sglebius m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 2066170589Syongari if (m == NULL) 2067170589Syongari return (ENOBUFS); 2068170589Syongari if ((m->m_flags & M_EXT) == 0) { 2069170589Syongari m_freem(m); 2070170589Syongari return (ENOBUFS); 2071170589Syongari } 2072176859Syongari m->m_pkthdr.len = m->m_len = MJUM9BYTES; 2073170589Syongari m_adj(m, ETHER_ALIGN); 2074159952Sobrien 2075170589Syongari if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 2076170589Syongari sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 2077170589Syongari m_freem(m); 2078170589Syongari return (ENOBUFS); 2079170589Syongari } 2080170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 2081163503Sobrien 2082170589Syongari data = &sc->jrxq.jdata[idx]; 2083170589Syongari if (data->m != NULL) { 2084170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2085170589Syongari BUS_DMASYNC_POSTREAD); 2086170589Syongari bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 2087170589Syongari } 2088170589Syongari map = data->rx_data_map; 2089170589Syongari data->rx_data_map = sc->jrxq.jrx_spare_map; 2090170589Syongari sc->jrxq.jrx_spare_map = map; 2091170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 2092170589Syongari BUS_DMASYNC_PREREAD); 2093170589Syongari data->paddr = segs[0].ds_addr; 2094170589Syongari data->m = m; 2095170589Syongari /* update mapping address in h/w descriptor */ 2096170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2097170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 2098170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 2099170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2100170589Syongari desc64->length = htole16(segs[0].ds_len); 2101170589Syongari desc64->flags = htole16(NFE_RX_READY); 2102170589Syongari } else { 2103170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 2104170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 2105170589Syongari desc32->length = htole16(segs[0].ds_len); 2106170589Syongari desc32->flags = htole16(NFE_RX_READY); 2107170589Syongari } 2108159967Sobrien 2109170589Syongari return (0); 2110159952Sobrien} 2111159952Sobrien 2112163503Sobrien 2113170589Syongaristatic int 2114193096Sattilionfe_rxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2115159952Sobrien{ 2116159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2117170589Syongari struct nfe_desc32 *desc32; 2118170589Syongari struct nfe_desc64 *desc64; 2119159952Sobrien struct nfe_rx_data *data; 2120170589Syongari struct mbuf *m; 2121170589Syongari uint16_t flags; 2122193096Sattilio int len, prog, rx_npkts; 2123170589Syongari uint32_t vtag = 0; 2124159952Sobrien 2125193096Sattilio rx_npkts = 0; 2126159967Sobrien NFE_LOCK_ASSERT(sc); 2127159967Sobrien 2128170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2129170589Syongari BUS_DMASYNC_POSTREAD); 2130159967Sobrien 2131170589Syongari for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2132170589Syongari if (count <= 0) 2133170589Syongari break; 2134170589Syongari count--; 2135159967Sobrien 2136159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 2137159952Sobrien 2138159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2139159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2140170589Syongari vtag = le32toh(desc64->physaddr[1]); 2141170589Syongari flags = le16toh(desc64->flags); 2142170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2143159952Sobrien } else { 2144159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2145170589Syongari flags = le16toh(desc32->flags); 2146170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2147159952Sobrien } 2148159952Sobrien 2149159952Sobrien if (flags & NFE_RX_READY) 2150159952Sobrien break; 2151170589Syongari prog++; 2152159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2153170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2154170589Syongari ifp->if_ierrors++; 2155170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2156170589Syongari continue; 2157170589Syongari } 2158159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2159159952Sobrien flags &= ~NFE_RX_ERROR; 2160159952Sobrien len--; /* fix buffer length */ 2161159952Sobrien } 2162159952Sobrien } else { 2163170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2164170589Syongari ifp->if_ierrors++; 2165170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2166170589Syongari continue; 2167170589Syongari } 2168159952Sobrien 2169159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2170159952Sobrien flags &= ~NFE_RX_ERROR; 2171159952Sobrien len--; /* fix buffer length */ 2172159952Sobrien } 2173159952Sobrien } 2174159952Sobrien 2175159952Sobrien if (flags & NFE_RX_ERROR) { 2176159952Sobrien ifp->if_ierrors++; 2177170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2178170589Syongari continue; 2179159952Sobrien } 2180159952Sobrien 2181170589Syongari m = data->m; 2182170589Syongari if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2183170589Syongari ifp->if_iqdrops++; 2184170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2185170589Syongari continue; 2186159952Sobrien } 2187159952Sobrien 2188170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2189170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2190170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2191170589Syongari m->m_flags |= M_VLANTAG; 2192164651Sobrien } 2193159952Sobrien 2194170589Syongari m->m_pkthdr.len = m->m_len = len; 2195170589Syongari m->m_pkthdr.rcvif = ifp; 2196164651Sobrien 2197170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2198170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2199170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2200170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2201170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2202170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2203170589Syongari m->m_pkthdr.csum_flags |= 2204170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2205170589Syongari m->m_pkthdr.csum_data = 0xffff; 2206170589Syongari } 2207159952Sobrien } 2208170589Syongari } 2209170589Syongari 2210170589Syongari ifp->if_ipackets++; 2211170589Syongari 2212170589Syongari NFE_UNLOCK(sc); 2213170589Syongari (*ifp->if_input)(ifp, m); 2214170589Syongari NFE_LOCK(sc); 2215193096Sattilio rx_npkts++; 2216170589Syongari } 2217170589Syongari 2218170589Syongari if (prog > 0) 2219170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2220170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2221170589Syongari 2222193096Sattilio if (rx_npktsp != NULL) 2223193096Sattilio *rx_npktsp = rx_npkts; 2224170589Syongari return (count > 0 ? 0 : EAGAIN); 2225170589Syongari} 2226170589Syongari 2227170589Syongari 2228170589Syongaristatic int 2229193096Sattilionfe_jrxeof(struct nfe_softc *sc, int count, int *rx_npktsp) 2230170589Syongari{ 2231170589Syongari struct ifnet *ifp = sc->nfe_ifp; 2232170589Syongari struct nfe_desc32 *desc32; 2233170589Syongari struct nfe_desc64 *desc64; 2234170589Syongari struct nfe_rx_data *data; 2235170589Syongari struct mbuf *m; 2236170589Syongari uint16_t flags; 2237193096Sattilio int len, prog, rx_npkts; 2238170589Syongari uint32_t vtag = 0; 2239170589Syongari 2240193096Sattilio rx_npkts = 0; 2241170589Syongari NFE_LOCK_ASSERT(sc); 2242170589Syongari 2243170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2244170589Syongari BUS_DMASYNC_POSTREAD); 2245170589Syongari 2246170589Syongari for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2247170589Syongari vtag = 0) { 2248170589Syongari if (count <= 0) 2249170589Syongari break; 2250170589Syongari count--; 2251170589Syongari 2252170589Syongari data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2253170589Syongari 2254170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2255170589Syongari desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2256170589Syongari vtag = le32toh(desc64->physaddr[1]); 2257170589Syongari flags = le16toh(desc64->flags); 2258170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2259170589Syongari } else { 2260170589Syongari desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2261170589Syongari flags = le16toh(desc32->flags); 2262170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2263170589Syongari } 2264170589Syongari 2265170589Syongari if (flags & NFE_RX_READY) 2266170589Syongari break; 2267170589Syongari prog++; 2268170589Syongari if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2269170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2270170589Syongari ifp->if_ierrors++; 2271170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2272170589Syongari continue; 2273170589Syongari } 2274170589Syongari if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2275170589Syongari flags &= ~NFE_RX_ERROR; 2276170589Syongari len--; /* fix buffer length */ 2277170589Syongari } 2278170589Syongari } else { 2279170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2280170589Syongari ifp->if_ierrors++; 2281170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2282170589Syongari continue; 2283170589Syongari } 2284170589Syongari 2285170589Syongari if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2286170589Syongari flags &= ~NFE_RX_ERROR; 2287170589Syongari len--; /* fix buffer length */ 2288170589Syongari } 2289170589Syongari } 2290170589Syongari 2291170589Syongari if (flags & NFE_RX_ERROR) { 2292164651Sobrien ifp->if_ierrors++; 2293170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2294170589Syongari continue; 2295164651Sobrien } 2296159952Sobrien 2297159952Sobrien m = data->m; 2298170589Syongari if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2299170589Syongari ifp->if_iqdrops++; 2300170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2301170589Syongari continue; 2302170589Syongari } 2303159952Sobrien 2304170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2305170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2306170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2307170589Syongari m->m_flags |= M_VLANTAG; 2308170589Syongari } 2309170589Syongari 2310159952Sobrien m->m_pkthdr.len = m->m_len = len; 2311159952Sobrien m->m_pkthdr.rcvif = ifp; 2312159952Sobrien 2313170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2314170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2315170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2316159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2317170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2318170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2319170589Syongari m->m_pkthdr.csum_flags |= 2320170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2321170589Syongari m->m_pkthdr.csum_data = 0xffff; 2322170589Syongari } 2323159967Sobrien } 2324159952Sobrien } 2325159952Sobrien 2326159952Sobrien ifp->if_ipackets++; 2327159952Sobrien 2328159967Sobrien NFE_UNLOCK(sc); 2329159967Sobrien (*ifp->if_input)(ifp, m); 2330159967Sobrien NFE_LOCK(sc); 2331193096Sattilio rx_npkts++; 2332170589Syongari } 2333159967Sobrien 2334170589Syongari if (prog > 0) 2335170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2336170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2337159952Sobrien 2338193096Sattilio if (rx_npktsp != NULL) 2339193096Sattilio *rx_npktsp = rx_npkts; 2340170589Syongari return (count > 0 ? 0 : EAGAIN); 2341159952Sobrien} 2342159952Sobrien 2343163503Sobrien 2344163503Sobrienstatic void 2345163503Sobriennfe_txeof(struct nfe_softc *sc) 2346159952Sobrien{ 2347159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2348159952Sobrien struct nfe_desc32 *desc32; 2349159952Sobrien struct nfe_desc64 *desc64; 2350159952Sobrien struct nfe_tx_data *data = NULL; 2351170589Syongari uint16_t flags; 2352170589Syongari int cons, prog; 2353159952Sobrien 2354159967Sobrien NFE_LOCK_ASSERT(sc); 2355159967Sobrien 2356170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2357170589Syongari BUS_DMASYNC_POSTREAD); 2358170589Syongari 2359170589Syongari prog = 0; 2360170589Syongari for (cons = sc->txq.next; cons != sc->txq.cur; 2361170589Syongari NFE_INC(cons, NFE_TX_RING_COUNT)) { 2362159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2363170589Syongari desc64 = &sc->txq.desc64[cons]; 2364170589Syongari flags = le16toh(desc64->flags); 2365159952Sobrien } else { 2366170589Syongari desc32 = &sc->txq.desc32[cons]; 2367170589Syongari flags = le16toh(desc32->flags); 2368159952Sobrien } 2369159952Sobrien 2370159952Sobrien if (flags & NFE_TX_VALID) 2371159952Sobrien break; 2372159952Sobrien 2373170589Syongari prog++; 2374170589Syongari sc->txq.queued--; 2375170589Syongari data = &sc->txq.data[cons]; 2376159952Sobrien 2377159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2378170589Syongari if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2379170589Syongari continue; 2380159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 2381170589Syongari device_printf(sc->nfe_dev, 2382170589Syongari "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2383159967Sobrien 2384159952Sobrien ifp->if_oerrors++; 2385159952Sobrien } else 2386159952Sobrien ifp->if_opackets++; 2387159952Sobrien } else { 2388170589Syongari if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2389170589Syongari continue; 2390159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 2391170589Syongari device_printf(sc->nfe_dev, 2392170589Syongari "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2393159952Sobrien ifp->if_oerrors++; 2394159952Sobrien } else 2395159952Sobrien ifp->if_opackets++; 2396159952Sobrien } 2397159952Sobrien 2398159952Sobrien /* last fragment of the mbuf chain transmitted */ 2399170589Syongari KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2400170589Syongari bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2401159967Sobrien BUS_DMASYNC_POSTWRITE); 2402170589Syongari bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2403159952Sobrien m_freem(data->m); 2404159952Sobrien data->m = NULL; 2405159952Sobrien } 2406159952Sobrien 2407170589Syongari if (prog > 0) { 2408170589Syongari sc->nfe_force_tx = 0; 2409170589Syongari sc->txq.next = cons; 2410159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2411170589Syongari if (sc->txq.queued == 0) 2412170589Syongari sc->nfe_watchdog_timer = 0; 2413159952Sobrien } 2414159952Sobrien} 2415159952Sobrien 2416163503Sobrienstatic int 2417170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2418159952Sobrien{ 2419170589Syongari struct nfe_desc32 *desc32 = NULL; 2420170589Syongari struct nfe_desc64 *desc64 = NULL; 2421159952Sobrien bus_dmamap_t map; 2422163503Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2423170589Syongari int error, i, nsegs, prod, si; 2424254803Sandre uint32_t tsosegsz; 2425170589Syongari uint16_t cflags, flags; 2426170589Syongari struct mbuf *m; 2427159952Sobrien 2428170589Syongari prod = si = sc->txq.cur; 2429170589Syongari map = sc->txq.data[prod].tx_data_map; 2430159952Sobrien 2431170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2432159967Sobrien &nsegs, BUS_DMA_NOWAIT); 2433170589Syongari if (error == EFBIG) { 2434243857Sglebius m = m_collapse(*m_head, M_NOWAIT, NFE_MAX_SCATTER); 2435170589Syongari if (m == NULL) { 2436170589Syongari m_freem(*m_head); 2437170589Syongari *m_head = NULL; 2438170589Syongari return (ENOBUFS); 2439170589Syongari } 2440170589Syongari *m_head = m; 2441170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2442170589Syongari *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2443170589Syongari if (error != 0) { 2444170589Syongari m_freem(*m_head); 2445170589Syongari *m_head = NULL; 2446170589Syongari return (ENOBUFS); 2447170589Syongari } 2448170589Syongari } else if (error != 0) 2449170589Syongari return (error); 2450170589Syongari if (nsegs == 0) { 2451170589Syongari m_freem(*m_head); 2452170589Syongari *m_head = NULL; 2453170589Syongari return (EIO); 2454159952Sobrien } 2455159952Sobrien 2456170589Syongari if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2457159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2458170589Syongari return (ENOBUFS); 2459159952Sobrien } 2460159952Sobrien 2461170589Syongari m = *m_head; 2462170589Syongari cflags = flags = 0; 2463254803Sandre tsosegsz = 0; 2464206876Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2465254803Sandre tsosegsz = (uint32_t)m->m_pkthdr.tso_segsz << 2466206876Syongari NFE_TX_TSO_SHIFT; 2467206876Syongari cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2468206876Syongari cflags |= NFE_TX_TSO; 2469206876Syongari } else if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2470170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2471170589Syongari cflags |= NFE_TX_IP_CSUM; 2472170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2473170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2474170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2475170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2476164656Sobrien } 2477159967Sobrien 2478159967Sobrien for (i = 0; i < nsegs; i++) { 2479159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2480170589Syongari desc64 = &sc->txq.desc64[prod]; 2481170589Syongari desc64->physaddr[0] = 2482170589Syongari htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2483170589Syongari desc64->physaddr[1] = 2484170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2485170589Syongari desc64->vtag = 0; 2486159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 2487159952Sobrien desc64->flags = htole16(flags); 2488159952Sobrien } else { 2489170589Syongari desc32 = &sc->txq.desc32[prod]; 2490170589Syongari desc32->physaddr = 2491170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2492159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 2493159952Sobrien desc32->flags = htole16(flags); 2494159952Sobrien } 2495159952Sobrien 2496170589Syongari /* 2497170589Syongari * Setting of the valid bit in the first descriptor is 2498170589Syongari * deferred until the whole chain is fully setup. 2499170589Syongari */ 2500170589Syongari flags |= NFE_TX_VALID; 2501163503Sobrien 2502159952Sobrien sc->txq.queued++; 2503170589Syongari NFE_INC(prod, NFE_TX_RING_COUNT); 2504159952Sobrien } 2505159952Sobrien 2506170589Syongari /* 2507170589Syongari * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2508170589Syongari * csum flags, vtag and TSO belong to the first fragment only. 2509170589Syongari */ 2510159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2511170589Syongari desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2512170589Syongari desc64 = &sc->txq.desc64[si]; 2513170589Syongari if ((m->m_flags & M_VLANTAG) != 0) 2514170589Syongari desc64->vtag = htole32(NFE_TX_VTAG | 2515170589Syongari m->m_pkthdr.ether_vtag); 2516254803Sandre if (tsosegsz != 0) { 2517170589Syongari /* 2518170589Syongari * XXX 2519170589Syongari * The following indicates the descriptor element 2520170589Syongari * is a 32bit quantity. 2521170589Syongari */ 2522254803Sandre desc64->length |= htole16((uint16_t)tsosegsz); 2523254803Sandre desc64->flags |= htole16(tsosegsz >> 16); 2524170589Syongari } 2525170589Syongari /* 2526170589Syongari * finally, set the valid/checksum/TSO bit in the first 2527170589Syongari * descriptor. 2528170589Syongari */ 2529170589Syongari desc64->flags |= htole16(NFE_TX_VALID | cflags); 2530159952Sobrien } else { 2531159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 2532170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2533159952Sobrien else 2534170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2535170589Syongari desc32 = &sc->txq.desc32[si]; 2536254803Sandre if (tsosegsz != 0) { 2537170589Syongari /* 2538170589Syongari * XXX 2539170589Syongari * The following indicates the descriptor element 2540170589Syongari * is a 32bit quantity. 2541170589Syongari */ 2542254803Sandre desc32->length |= htole16((uint16_t)tsosegsz); 2543254803Sandre desc32->flags |= htole16(tsosegsz >> 16); 2544170589Syongari } 2545170589Syongari /* 2546170589Syongari * finally, set the valid/checksum/TSO bit in the first 2547170589Syongari * descriptor. 2548170589Syongari */ 2549170589Syongari desc32->flags |= htole16(NFE_TX_VALID | cflags); 2550159952Sobrien } 2551159952Sobrien 2552170589Syongari sc->txq.cur = prod; 2553170589Syongari prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2554170589Syongari sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2555170589Syongari sc->txq.data[prod].tx_data_map = map; 2556170589Syongari sc->txq.data[prod].m = m; 2557159952Sobrien 2558159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2559159952Sobrien 2560170589Syongari return (0); 2561159952Sobrien} 2562159952Sobrien 2563159967Sobrien 2564163503Sobrienstatic void 2565163503Sobriennfe_setmulti(struct nfe_softc *sc) 2566159952Sobrien{ 2567159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2568163503Sobrien struct ifmultiaddr *ifma; 2569163503Sobrien int i; 2570170589Syongari uint32_t filter; 2571170589Syongari uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2572170589Syongari uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 2573163503Sobrien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2574163503Sobrien }; 2575159967Sobrien 2576159967Sobrien NFE_LOCK_ASSERT(sc); 2577159967Sobrien 2578159967Sobrien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2579159967Sobrien bzero(addr, ETHER_ADDR_LEN); 2580159967Sobrien bzero(mask, ETHER_ADDR_LEN); 2581159967Sobrien goto done; 2582159967Sobrien } 2583159967Sobrien 2584159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2585159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2586159967Sobrien 2587195049Srwatson if_maddr_rlock(ifp); 2588159967Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2589159967Sobrien u_char *addrp; 2590159967Sobrien 2591159967Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 2592159967Sobrien continue; 2593159967Sobrien 2594159967Sobrien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 2595159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2596159967Sobrien u_int8_t mcaddr = addrp[i]; 2597159967Sobrien addr[i] &= mcaddr; 2598159967Sobrien mask[i] &= ~mcaddr; 2599159967Sobrien } 2600159967Sobrien } 2601195049Srwatson if_maddr_runlock(ifp); 2602159967Sobrien 2603159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2604159967Sobrien mask[i] |= addr[i]; 2605159967Sobrien } 2606159967Sobrien 2607159967Sobriendone: 2608159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 2609159967Sobrien 2610159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2611159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2612159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2613159967Sobrien addr[5] << 8 | addr[4]); 2614159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2615159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2616159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2617159967Sobrien mask[5] << 8 | mask[4]); 2618159967Sobrien 2619170589Syongari filter = NFE_READ(sc, NFE_RXFILTER); 2620170589Syongari filter &= NFE_PFF_RX_PAUSE; 2621170589Syongari filter |= NFE_RXFILTER_MAGIC; 2622170589Syongari filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2623159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 2624159967Sobrien} 2625159967Sobrien 2626163503Sobrien 2627163503Sobrienstatic void 2628216925Sjhbnfe_start(struct ifnet *ifp) 2629159967Sobrien{ 2630216925Sjhb struct nfe_softc *sc = ifp->if_softc; 2631159967Sobrien 2632216925Sjhb NFE_LOCK(sc); 2633216925Sjhb nfe_start_locked(ifp); 2634216925Sjhb NFE_UNLOCK(sc); 2635159967Sobrien} 2636159967Sobrien 2637163503Sobrienstatic void 2638216925Sjhbnfe_start_locked(struct ifnet *ifp) 2639159967Sobrien{ 2640159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2641163503Sobrien struct mbuf *m0; 2642170589Syongari int enq; 2643159952Sobrien 2644216925Sjhb NFE_LOCK_ASSERT(sc); 2645170589Syongari 2646170589Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2647216925Sjhb IFF_DRV_RUNNING || sc->nfe_link == 0) 2648159967Sobrien return; 2649159967Sobrien 2650170589Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 2651170589Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2652159952Sobrien if (m0 == NULL) 2653159952Sobrien break; 2654159952Sobrien 2655170589Syongari if (nfe_encap(sc, &m0) != 0) { 2656170589Syongari if (m0 == NULL) 2657170589Syongari break; 2658170589Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2659159967Sobrien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2660159952Sobrien break; 2661159952Sobrien } 2662170589Syongari enq++; 2663167190Scsjp ETHER_BPF_MTAP(ifp, m0); 2664159952Sobrien } 2665159952Sobrien 2666170589Syongari if (enq > 0) { 2667170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2668170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2669159952Sobrien 2670170589Syongari /* kick Tx */ 2671170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2672159952Sobrien 2673170589Syongari /* 2674170589Syongari * Set a timeout in case the chip goes out to lunch. 2675170589Syongari */ 2676170589Syongari sc->nfe_watchdog_timer = 5; 2677170589Syongari } 2678159952Sobrien} 2679159952Sobrien 2680163503Sobrien 2681163503Sobrienstatic void 2682163503Sobriennfe_watchdog(struct ifnet *ifp) 2683159952Sobrien{ 2684159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2685159952Sobrien 2686170589Syongari if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2687170589Syongari return; 2688159952Sobrien 2689170589Syongari /* Check if we've lost Tx completion interrupt. */ 2690170589Syongari nfe_txeof(sc); 2691170589Syongari if (sc->txq.queued == 0) { 2692170589Syongari if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2693170589Syongari "-- recovering\n"); 2694170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2695216925Sjhb nfe_start_locked(ifp); 2696170589Syongari return; 2697170589Syongari } 2698170589Syongari /* Check if we've lost start Tx command. */ 2699170589Syongari sc->nfe_force_tx++; 2700170589Syongari if (sc->nfe_force_tx <= 3) { 2701170589Syongari /* 2702170589Syongari * If this is the case for watchdog timeout, the following 2703170589Syongari * code should go to nfe_txeof(). 2704170589Syongari */ 2705170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2706170589Syongari return; 2707170589Syongari } 2708170589Syongari sc->nfe_force_tx = 0; 2709170589Syongari 2710170589Syongari if_printf(ifp, "watchdog timeout\n"); 2711170589Syongari 2712159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2713159952Sobrien ifp->if_oerrors++; 2714170589Syongari nfe_init_locked(sc); 2715159952Sobrien} 2716159952Sobrien 2717163503Sobrien 2718163503Sobrienstatic void 2719163503Sobriennfe_init(void *xsc) 2720159952Sobrien{ 2721159967Sobrien struct nfe_softc *sc = xsc; 2722159952Sobrien 2723159967Sobrien NFE_LOCK(sc); 2724159967Sobrien nfe_init_locked(sc); 2725159967Sobrien NFE_UNLOCK(sc); 2726159967Sobrien} 2727159967Sobrien 2728163503Sobrien 2729163503Sobrienstatic void 2730163503Sobriennfe_init_locked(void *xsc) 2731159967Sobrien{ 2732159967Sobrien struct nfe_softc *sc = xsc; 2733159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2734159967Sobrien struct mii_data *mii; 2735170589Syongari uint32_t val; 2736170589Syongari int error; 2737159967Sobrien 2738159967Sobrien NFE_LOCK_ASSERT(sc); 2739159967Sobrien 2740159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2741159967Sobrien 2742170589Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2743159967Sobrien return; 2744170589Syongari 2745170589Syongari nfe_stop(ifp); 2746170589Syongari 2747170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 2748170589Syongari 2749170589Syongari nfe_init_tx_ring(sc, &sc->txq); 2750170589Syongari if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2751170589Syongari error = nfe_init_jrx_ring(sc, &sc->jrxq); 2752170589Syongari else 2753170589Syongari error = nfe_init_rx_ring(sc, &sc->rxq); 2754170589Syongari if (error != 0) { 2755170589Syongari device_printf(sc->nfe_dev, 2756170589Syongari "initialization failed: no memory for rx buffers\n"); 2757170589Syongari nfe_stop(ifp); 2758170589Syongari return; 2759159967Sobrien } 2760159967Sobrien 2761170589Syongari val = 0; 2762170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2763170589Syongari val |= NFE_MAC_ADDR_INORDER; 2764170589Syongari NFE_WRITE(sc, NFE_TX_UNK, val); 2765159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 2766159952Sobrien 2767170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2768170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2769170589Syongari 2770159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 2771159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 2772159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2773159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2774159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 2775164656Sobrien 2776170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 2777159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2778170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2779170589Syongari sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2780159967Sobrien 2781159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2782159952Sobrien DELAY(10); 2783159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2784159952Sobrien 2785170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2786159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2787170589Syongari else 2788170589Syongari NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2789159952Sobrien 2790159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2791159952Sobrien 2792159952Sobrien /* set MAC address */ 2793170589Syongari nfe_set_macaddr(sc, IF_LLADDR(ifp)); 2794159952Sobrien 2795159952Sobrien /* tell MAC where rings are in memory */ 2796170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2797170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2798170589Syongari NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2799170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2800170589Syongari NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2801170589Syongari } else { 2802170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2803170589Syongari NFE_ADDR_HI(sc->rxq.physaddr)); 2804170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2805170589Syongari NFE_ADDR_LO(sc->rxq.physaddr)); 2806170589Syongari } 2807170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2808170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2809159952Sobrien 2810159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 2811159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 2812159952Sobrien (NFE_TX_RING_COUNT - 1)); 2813159952Sobrien 2814170589Syongari NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2815159952Sobrien 2816159952Sobrien /* force MAC to wakeup */ 2817170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2818170589Syongari if ((val & NFE_PWR_WAKEUP) == 0) 2819170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2820159952Sobrien DELAY(10); 2821170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2822170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2823159952Sobrien 2824159952Sobrien#if 1 2825159952Sobrien /* configure interrupts coalescing/mitigation */ 2826159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2827159952Sobrien#else 2828159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 2829159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 2830159952Sobrien#endif 2831159952Sobrien 2832170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2833159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2834159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2835159952Sobrien 2836159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2837159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2838159952Sobrien 2839159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2840215132Syongari /* Disable WOL. */ 2841215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, 0); 2842159952Sobrien 2843159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2844159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2845159952Sobrien DELAY(10); 2846159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2847159952Sobrien 2848159952Sobrien /* set Rx filter */ 2849159952Sobrien nfe_setmulti(sc); 2850159952Sobrien 2851159952Sobrien /* enable Rx */ 2852159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2853159952Sobrien 2854159952Sobrien /* enable Tx */ 2855159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2856159952Sobrien 2857159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2858159952Sobrien 2859183561Syongari /* Clear hardware stats. */ 2860183561Syongari nfe_stats_clear(sc); 2861183561Syongari 2862159967Sobrien#ifdef DEVICE_POLLING 2863159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) 2864170589Syongari nfe_disable_intr(sc); 2865159967Sobrien else 2866159967Sobrien#endif 2867170589Syongari nfe_set_intr(sc); 2868170589Syongari nfe_enable_intr(sc); /* enable interrupts */ 2869159952Sobrien 2870159967Sobrien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2871159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2872159952Sobrien 2873159967Sobrien sc->nfe_link = 0; 2874170589Syongari mii_mediachg(mii); 2875159952Sobrien 2876170589Syongari callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2877159952Sobrien} 2878159952Sobrien 2879163503Sobrien 2880163503Sobrienstatic void 2881170589Syongarinfe_stop(struct ifnet *ifp) 2882159952Sobrien{ 2883159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2884170589Syongari struct nfe_rx_ring *rx_ring; 2885170589Syongari struct nfe_jrx_ring *jrx_ring; 2886170589Syongari struct nfe_tx_ring *tx_ring; 2887170589Syongari struct nfe_rx_data *rdata; 2888170589Syongari struct nfe_tx_data *tdata; 2889170589Syongari int i; 2890159952Sobrien 2891159967Sobrien NFE_LOCK_ASSERT(sc); 2892159952Sobrien 2893170589Syongari sc->nfe_watchdog_timer = 0; 2894159967Sobrien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2895159952Sobrien 2896159967Sobrien callout_stop(&sc->nfe_stat_ch); 2897159967Sobrien 2898159952Sobrien /* abort Tx */ 2899159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 2900159952Sobrien 2901159952Sobrien /* disable Rx */ 2902159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 2903159952Sobrien 2904159952Sobrien /* disable interrupts */ 2905170589Syongari nfe_disable_intr(sc); 2906159952Sobrien 2907159967Sobrien sc->nfe_link = 0; 2908159967Sobrien 2909170589Syongari /* free Rx and Tx mbufs still in the queues. */ 2910170589Syongari rx_ring = &sc->rxq; 2911170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2912170589Syongari rdata = &rx_ring->data[i]; 2913170589Syongari if (rdata->m != NULL) { 2914170589Syongari bus_dmamap_sync(rx_ring->rx_data_tag, 2915170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2916170589Syongari bus_dmamap_unload(rx_ring->rx_data_tag, 2917170589Syongari rdata->rx_data_map); 2918170589Syongari m_freem(rdata->m); 2919170589Syongari rdata->m = NULL; 2920170589Syongari } 2921170589Syongari } 2922159952Sobrien 2923170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 2924170589Syongari jrx_ring = &sc->jrxq; 2925170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 2926170589Syongari rdata = &jrx_ring->jdata[i]; 2927170589Syongari if (rdata->m != NULL) { 2928170589Syongari bus_dmamap_sync(jrx_ring->jrx_data_tag, 2929170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2930170589Syongari bus_dmamap_unload(jrx_ring->jrx_data_tag, 2931170589Syongari rdata->rx_data_map); 2932170589Syongari m_freem(rdata->m); 2933170589Syongari rdata->m = NULL; 2934170589Syongari } 2935170589Syongari } 2936170589Syongari } 2937170589Syongari 2938170589Syongari tx_ring = &sc->txq; 2939170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2940170589Syongari tdata = &tx_ring->data[i]; 2941170589Syongari if (tdata->m != NULL) { 2942170589Syongari bus_dmamap_sync(tx_ring->tx_data_tag, 2943170589Syongari tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 2944170589Syongari bus_dmamap_unload(tx_ring->tx_data_tag, 2945170589Syongari tdata->tx_data_map); 2946170589Syongari m_freem(tdata->m); 2947170589Syongari tdata->m = NULL; 2948170589Syongari } 2949170589Syongari } 2950183561Syongari /* Update hardware stats. */ 2951183561Syongari nfe_stats_update(sc); 2952159952Sobrien} 2953159952Sobrien 2954163503Sobrien 2955163503Sobrienstatic int 2956163503Sobriennfe_ifmedia_upd(struct ifnet *ifp) 2957159952Sobrien{ 2958159967Sobrien struct nfe_softc *sc = ifp->if_softc; 2959170589Syongari struct mii_data *mii; 2960159952Sobrien 2961159967Sobrien NFE_LOCK(sc); 2962159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2963159967Sobrien mii_mediachg(mii); 2964170589Syongari NFE_UNLOCK(sc); 2965159967Sobrien 2966159967Sobrien return (0); 2967159952Sobrien} 2968159952Sobrien 2969163503Sobrien 2970163503Sobrienstatic void 2971163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2972159952Sobrien{ 2973163503Sobrien struct nfe_softc *sc; 2974163503Sobrien struct mii_data *mii; 2975159952Sobrien 2976159967Sobrien sc = ifp->if_softc; 2977159952Sobrien 2978159967Sobrien NFE_LOCK(sc); 2979159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2980159967Sobrien mii_pollstat(mii); 2981159952Sobrien 2982159967Sobrien ifmr->ifm_active = mii->mii_media_active; 2983159967Sobrien ifmr->ifm_status = mii->mii_media_status; 2984226478Syongari NFE_UNLOCK(sc); 2985159952Sobrien} 2986159952Sobrien 2987163503Sobrien 2988170589Syongarivoid 2989159967Sobriennfe_tick(void *xsc) 2990159952Sobrien{ 2991159967Sobrien struct nfe_softc *sc; 2992163503Sobrien struct mii_data *mii; 2993163503Sobrien struct ifnet *ifp; 2994159952Sobrien 2995170589Syongari sc = (struct nfe_softc *)xsc; 2996159952Sobrien 2997163503Sobrien NFE_LOCK_ASSERT(sc); 2998159952Sobrien 2999159967Sobrien ifp = sc->nfe_ifp; 3000159952Sobrien 3001159967Sobrien mii = device_get_softc(sc->nfe_miibus); 3002159967Sobrien mii_tick(mii); 3003183561Syongari nfe_stats_update(sc); 3004170589Syongari nfe_watchdog(ifp); 3005159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 3006159952Sobrien} 3007159952Sobrien 3008159952Sobrien 3009173839Syongaristatic int 3010163503Sobriennfe_shutdown(device_t dev) 3011159952Sobrien{ 3012159952Sobrien 3013215132Syongari return (nfe_suspend(dev)); 3014159952Sobrien} 3015159952Sobrien 3016159952Sobrien 3017163503Sobrienstatic void 3018170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 3019159952Sobrien{ 3020170589Syongari uint32_t val; 3021159952Sobrien 3022170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 3023170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3024170589Syongari addr[0] = (val >> 8) & 0xff; 3025170589Syongari addr[1] = (val & 0xff); 3026159952Sobrien 3027170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3028170589Syongari addr[2] = (val >> 24) & 0xff; 3029170589Syongari addr[3] = (val >> 16) & 0xff; 3030170589Syongari addr[4] = (val >> 8) & 0xff; 3031170589Syongari addr[5] = (val & 0xff); 3032170589Syongari } else { 3033170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 3034170589Syongari addr[5] = (val >> 8) & 0xff; 3035170589Syongari addr[4] = (val & 0xff); 3036170589Syongari 3037170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 3038170589Syongari addr[3] = (val >> 24) & 0xff; 3039170589Syongari addr[2] = (val >> 16) & 0xff; 3040170589Syongari addr[1] = (val >> 8) & 0xff; 3041170589Syongari addr[0] = (val & 0xff); 3042170589Syongari } 3043159952Sobrien} 3044159952Sobrien 3045163503Sobrien 3046163503Sobrienstatic void 3047170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 3048159952Sobrien{ 3049159967Sobrien 3050159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 3051159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 3052159967Sobrien addr[1] << 8 | addr[0]); 3053159952Sobrien} 3054159952Sobrien 3055163503Sobrien 3056159967Sobrien/* 3057159967Sobrien * Map a single buffer address. 3058159967Sobrien */ 3059159967Sobrien 3060159967Sobrienstatic void 3061170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 3062159952Sobrien{ 3063170589Syongari struct nfe_dmamap_arg *ctx; 3064159952Sobrien 3065170589Syongari if (error != 0) 3066159967Sobrien return; 3067159952Sobrien 3068159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 3069159967Sobrien 3070170589Syongari ctx = (struct nfe_dmamap_arg *)arg; 3071170589Syongari ctx->nfe_busaddr = segs[0].ds_addr; 3072170589Syongari} 3073159967Sobrien 3074170589Syongari 3075170589Syongaristatic int 3076170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 3077170589Syongari{ 3078170589Syongari int error, value; 3079170589Syongari 3080170589Syongari if (!arg1) 3081170589Syongari return (EINVAL); 3082170589Syongari value = *(int *)arg1; 3083170589Syongari error = sysctl_handle_int(oidp, &value, 0, req); 3084170589Syongari if (error || !req->newptr) 3085170589Syongari return (error); 3086170589Syongari if (value < low || value > high) 3087170589Syongari return (EINVAL); 3088170589Syongari *(int *)arg1 = value; 3089170589Syongari 3090170589Syongari return (0); 3091159952Sobrien} 3092170589Syongari 3093170589Syongari 3094170589Syongaristatic int 3095170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 3096170589Syongari{ 3097170589Syongari 3098170589Syongari return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 3099170589Syongari NFE_PROC_MAX)); 3100170589Syongari} 3101183561Syongari 3102183561Syongari 3103183561Syongari#define NFE_SYSCTL_STAT_ADD32(c, h, n, p, d) \ 3104183561Syongari SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) 3105183561Syongari#define NFE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ 3106217323Smdf SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) 3107183561Syongari 3108183561Syongaristatic void 3109183561Syongarinfe_sysctl_node(struct nfe_softc *sc) 3110183561Syongari{ 3111183561Syongari struct sysctl_ctx_list *ctx; 3112183561Syongari struct sysctl_oid_list *child, *parent; 3113183561Syongari struct sysctl_oid *tree; 3114183561Syongari struct nfe_hw_stats *stats; 3115183561Syongari int error; 3116183561Syongari 3117183561Syongari stats = &sc->nfe_stats; 3118183561Syongari ctx = device_get_sysctl_ctx(sc->nfe_dev); 3119183561Syongari child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->nfe_dev)); 3120183561Syongari SYSCTL_ADD_PROC(ctx, child, 3121183561Syongari OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 3122183561Syongari &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 3123183561Syongari "max number of Rx events to process"); 3124183561Syongari 3125183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3126183561Syongari error = resource_int_value(device_get_name(sc->nfe_dev), 3127183561Syongari device_get_unit(sc->nfe_dev), "process_limit", 3128183561Syongari &sc->nfe_process_limit); 3129183561Syongari if (error == 0) { 3130183561Syongari if (sc->nfe_process_limit < NFE_PROC_MIN || 3131183561Syongari sc->nfe_process_limit > NFE_PROC_MAX) { 3132183561Syongari device_printf(sc->nfe_dev, 3133183561Syongari "process_limit value out of range; " 3134183561Syongari "using default: %d\n", NFE_PROC_DEFAULT); 3135183561Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 3136183561Syongari } 3137183561Syongari } 3138183561Syongari 3139183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3140183561Syongari return; 3141183561Syongari 3142183561Syongari tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, 3143183561Syongari NULL, "NFE statistics"); 3144183561Syongari parent = SYSCTL_CHILDREN(tree); 3145183561Syongari 3146183561Syongari /* Rx statistics. */ 3147183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD, 3148183561Syongari NULL, "Rx MAC statistics"); 3149183561Syongari child = SYSCTL_CHILDREN(tree); 3150183561Syongari 3151183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frame_errors", 3152183561Syongari &stats->rx_frame_errors, "Framing Errors"); 3153183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "extra_bytes", 3154183561Syongari &stats->rx_extra_bytes, "Extra Bytes"); 3155183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3156183561Syongari &stats->rx_late_cols, "Late Collisions"); 3157183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "runts", 3158183561Syongari &stats->rx_runts, "Runts"); 3159183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "jumbos", 3160183561Syongari &stats->rx_jumbos, "Jumbos"); 3161183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_overuns", 3162183561Syongari &stats->rx_fifo_overuns, "FIFO Overruns"); 3163183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "crc_errors", 3164183561Syongari &stats->rx_crc_errors, "CRC Errors"); 3165183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fae", 3166183561Syongari &stats->rx_fae, "Frame Alignment Errors"); 3167183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "len_errors", 3168183561Syongari &stats->rx_len_errors, "Length Errors"); 3169183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3170183561Syongari &stats->rx_unicast, "Unicast Frames"); 3171183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3172183561Syongari &stats->rx_multicast, "Multicast Frames"); 3173186346Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3174183561Syongari &stats->rx_broadcast, "Broadcast Frames"); 3175183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3176183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3177183561Syongari &stats->rx_octets, "Octets"); 3178183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3179183561Syongari &stats->rx_pause, "Pause frames"); 3180183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "drops", 3181183561Syongari &stats->rx_drops, "Drop frames"); 3182183561Syongari } 3183183561Syongari 3184183561Syongari /* Tx statistics. */ 3185183561Syongari tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD, 3186183561Syongari NULL, "Tx MAC statistics"); 3187183561Syongari child = SYSCTL_CHILDREN(tree); 3188183561Syongari NFE_SYSCTL_STAT_ADD64(ctx, child, "octets", 3189183561Syongari &stats->tx_octets, "Octets"); 3190183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "zero_rexmits", 3191183561Syongari &stats->tx_zero_rexmits, "Zero Retransmits"); 3192183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "one_rexmits", 3193183561Syongari &stats->tx_one_rexmits, "One Retransmits"); 3194183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multi_rexmits", 3195183561Syongari &stats->tx_multi_rexmits, "Multiple Retransmits"); 3196183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "late_cols", 3197183561Syongari &stats->tx_late_cols, "Late Collisions"); 3198183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "fifo_underuns", 3199183561Syongari &stats->tx_fifo_underuns, "FIFO Underruns"); 3200183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "carrier_losts", 3201183561Syongari &stats->tx_carrier_losts, "Carrier Losts"); 3202183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "excess_deferrals", 3203183561Syongari &stats->tx_excess_deferals, "Excess Deferrals"); 3204183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "retry_errors", 3205183561Syongari &stats->tx_retry_errors, "Retry Errors"); 3206183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3207183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "deferrals", 3208183561Syongari &stats->tx_deferals, "Deferrals"); 3209183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "frames", 3210183561Syongari &stats->tx_frames, "Frames"); 3211183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "pause", 3212183561Syongari &stats->tx_pause, "Pause Frames"); 3213183561Syongari } 3214183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3215183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "unicast", 3216183561Syongari &stats->tx_deferals, "Unicast Frames"); 3217183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "multicast", 3218183561Syongari &stats->tx_frames, "Multicast Frames"); 3219183561Syongari NFE_SYSCTL_STAT_ADD32(ctx, child, "broadcast", 3220183561Syongari &stats->tx_pause, "Broadcast Frames"); 3221183561Syongari } 3222183561Syongari} 3223183561Syongari 3224183561Syongari#undef NFE_SYSCTL_STAT_ADD32 3225183561Syongari#undef NFE_SYSCTL_STAT_ADD64 3226183561Syongari 3227183561Syongaristatic void 3228183561Syongarinfe_stats_clear(struct nfe_softc *sc) 3229183561Syongari{ 3230183561Syongari int i, mib_cnt; 3231183561Syongari 3232183561Syongari if ((sc->nfe_flags & NFE_MIB_V1) != 0) 3233183561Syongari mib_cnt = NFE_NUM_MIB_STATV1; 3234183561Syongari else if ((sc->nfe_flags & (NFE_MIB_V2 | NFE_MIB_V3)) != 0) 3235183561Syongari mib_cnt = NFE_NUM_MIB_STATV2; 3236183561Syongari else 3237183561Syongari return; 3238183561Syongari 3239256038Syongari for (i = 0; i < mib_cnt; i++) 3240256038Syongari NFE_READ(sc, NFE_TX_OCTET + i * sizeof(uint32_t)); 3241183561Syongari 3242183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3243183561Syongari NFE_READ(sc, NFE_TX_UNICAST); 3244183561Syongari NFE_READ(sc, NFE_TX_MULTICAST); 3245183561Syongari NFE_READ(sc, NFE_TX_BROADCAST); 3246183561Syongari } 3247183561Syongari} 3248183561Syongari 3249183561Syongaristatic void 3250183561Syongarinfe_stats_update(struct nfe_softc *sc) 3251183561Syongari{ 3252183561Syongari struct nfe_hw_stats *stats; 3253183561Syongari 3254183561Syongari NFE_LOCK_ASSERT(sc); 3255183561Syongari 3256183561Syongari if ((sc->nfe_flags & (NFE_MIB_V1 | NFE_MIB_V2 | NFE_MIB_V3)) == 0) 3257183561Syongari return; 3258183561Syongari 3259183561Syongari stats = &sc->nfe_stats; 3260183561Syongari stats->tx_octets += NFE_READ(sc, NFE_TX_OCTET); 3261183561Syongari stats->tx_zero_rexmits += NFE_READ(sc, NFE_TX_ZERO_REXMIT); 3262183561Syongari stats->tx_one_rexmits += NFE_READ(sc, NFE_TX_ONE_REXMIT); 3263183561Syongari stats->tx_multi_rexmits += NFE_READ(sc, NFE_TX_MULTI_REXMIT); 3264183561Syongari stats->tx_late_cols += NFE_READ(sc, NFE_TX_LATE_COL); 3265183561Syongari stats->tx_fifo_underuns += NFE_READ(sc, NFE_TX_FIFO_UNDERUN); 3266183561Syongari stats->tx_carrier_losts += NFE_READ(sc, NFE_TX_CARRIER_LOST); 3267183561Syongari stats->tx_excess_deferals += NFE_READ(sc, NFE_TX_EXCESS_DEFERRAL); 3268183561Syongari stats->tx_retry_errors += NFE_READ(sc, NFE_TX_RETRY_ERROR); 3269183561Syongari stats->rx_frame_errors += NFE_READ(sc, NFE_RX_FRAME_ERROR); 3270183561Syongari stats->rx_extra_bytes += NFE_READ(sc, NFE_RX_EXTRA_BYTES); 3271183561Syongari stats->rx_late_cols += NFE_READ(sc, NFE_RX_LATE_COL); 3272183561Syongari stats->rx_runts += NFE_READ(sc, NFE_RX_RUNT); 3273183561Syongari stats->rx_jumbos += NFE_READ(sc, NFE_RX_JUMBO); 3274183561Syongari stats->rx_fifo_overuns += NFE_READ(sc, NFE_RX_FIFO_OVERUN); 3275183561Syongari stats->rx_crc_errors += NFE_READ(sc, NFE_RX_CRC_ERROR); 3276183561Syongari stats->rx_fae += NFE_READ(sc, NFE_RX_FAE); 3277183561Syongari stats->rx_len_errors += NFE_READ(sc, NFE_RX_LEN_ERROR); 3278183561Syongari stats->rx_unicast += NFE_READ(sc, NFE_RX_UNICAST); 3279183561Syongari stats->rx_multicast += NFE_READ(sc, NFE_RX_MULTICAST); 3280183561Syongari stats->rx_broadcast += NFE_READ(sc, NFE_RX_BROADCAST); 3281183561Syongari 3282183561Syongari if ((sc->nfe_flags & NFE_MIB_V2) != 0) { 3283183561Syongari stats->tx_deferals += NFE_READ(sc, NFE_TX_DEFERAL); 3284183561Syongari stats->tx_frames += NFE_READ(sc, NFE_TX_FRAME); 3285183561Syongari stats->rx_octets += NFE_READ(sc, NFE_RX_OCTET); 3286183561Syongari stats->tx_pause += NFE_READ(sc, NFE_TX_PAUSE); 3287183561Syongari stats->rx_pause += NFE_READ(sc, NFE_RX_PAUSE); 3288183561Syongari stats->rx_drops += NFE_READ(sc, NFE_RX_DROP); 3289183561Syongari } 3290183561Syongari 3291183561Syongari if ((sc->nfe_flags & NFE_MIB_V3) != 0) { 3292183561Syongari stats->tx_unicast += NFE_READ(sc, NFE_TX_UNICAST); 3293183561Syongari stats->tx_multicast += NFE_READ(sc, NFE_TX_MULTICAST); 3294255648Sdelphij stats->tx_broadcast += NFE_READ(sc, NFE_TX_BROADCAST); 3295183561Syongari } 3296183561Syongari} 3297215132Syongari 3298215132Syongari 3299215132Syongaristatic void 3300215132Syongarinfe_set_linkspeed(struct nfe_softc *sc) 3301215132Syongari{ 3302215132Syongari struct mii_softc *miisc; 3303215132Syongari struct mii_data *mii; 3304215132Syongari int aneg, i, phyno; 3305215132Syongari 3306215132Syongari NFE_LOCK_ASSERT(sc); 3307215132Syongari 3308215132Syongari mii = device_get_softc(sc->nfe_miibus); 3309215132Syongari mii_pollstat(mii); 3310215132Syongari aneg = 0; 3311215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 3312215132Syongari (IFM_ACTIVE | IFM_AVALID)) { 3313215132Syongari switch IFM_SUBTYPE(mii->mii_media_active) { 3314215132Syongari case IFM_10_T: 3315215132Syongari case IFM_100_TX: 3316215132Syongari return; 3317215132Syongari case IFM_1000_T: 3318215132Syongari aneg++; 3319215132Syongari break; 3320215132Syongari default: 3321215132Syongari break; 3322215132Syongari } 3323215132Syongari } 3324221407Smarius miisc = LIST_FIRST(&mii->mii_phys); 3325221407Smarius phyno = miisc->mii_phy; 3326221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 3327221407Smarius PHY_RESET(miisc); 3328215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, MII_100T2CR, 0); 3329215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3330215132Syongari MII_ANAR, ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA); 3331215132Syongari nfe_miibus_writereg(sc->nfe_dev, phyno, 3332215132Syongari MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); 3333215132Syongari DELAY(1000); 3334215132Syongari if (aneg != 0) { 3335215132Syongari /* 3336215132Syongari * Poll link state until nfe(4) get a 10/100Mbps link. 3337215132Syongari */ 3338215132Syongari for (i = 0; i < MII_ANEGTICKS_GIGE; i++) { 3339215132Syongari mii_pollstat(mii); 3340215132Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) 3341215132Syongari == (IFM_ACTIVE | IFM_AVALID)) { 3342215132Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 3343215132Syongari case IFM_10_T: 3344215132Syongari case IFM_100_TX: 3345215132Syongari nfe_mac_config(sc, mii); 3346215132Syongari return; 3347215132Syongari default: 3348215132Syongari break; 3349215132Syongari } 3350215132Syongari } 3351215132Syongari NFE_UNLOCK(sc); 3352215132Syongari pause("nfelnk", hz); 3353215132Syongari NFE_LOCK(sc); 3354215132Syongari } 3355215132Syongari if (i == MII_ANEGTICKS_GIGE) 3356215132Syongari device_printf(sc->nfe_dev, 3357215132Syongari "establishing a link failed, WOL may not work!"); 3358215132Syongari } 3359215132Syongari /* 3360215132Syongari * No link, force MAC to have 100Mbps, full-duplex link. 3361215132Syongari * This is the last resort and may/may not work. 3362215132Syongari */ 3363215132Syongari mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; 3364215132Syongari mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; 3365215132Syongari nfe_mac_config(sc, mii); 3366215132Syongari} 3367215132Syongari 3368215132Syongari 3369215132Syongaristatic void 3370215132Syongarinfe_set_wol(struct nfe_softc *sc) 3371215132Syongari{ 3372215132Syongari struct ifnet *ifp; 3373215132Syongari uint32_t wolctl; 3374215132Syongari int pmc; 3375215132Syongari uint16_t pmstat; 3376215132Syongari 3377215132Syongari NFE_LOCK_ASSERT(sc); 3378215132Syongari 3379219902Sjhb if (pci_find_cap(sc->nfe_dev, PCIY_PMG, &pmc) != 0) 3380215132Syongari return; 3381215132Syongari ifp = sc->nfe_ifp; 3382215132Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 3383215132Syongari wolctl = NFE_WOL_MAGIC; 3384215132Syongari else 3385215132Syongari wolctl = 0; 3386215132Syongari NFE_WRITE(sc, NFE_WOL_CTL, wolctl); 3387215132Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) { 3388215132Syongari nfe_set_linkspeed(sc); 3389215132Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) != 0) 3390215132Syongari NFE_WRITE(sc, NFE_PWR2_CTL, 3391215132Syongari NFE_READ(sc, NFE_PWR2_CTL) & ~NFE_PWR2_GATE_CLOCKS); 3392215132Syongari /* Enable RX. */ 3393215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 0); 3394215132Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 0); 3395215132Syongari NFE_WRITE(sc, NFE_RX_CTL, NFE_READ(sc, NFE_RX_CTL) | 3396215132Syongari NFE_RX_START); 3397215132Syongari } 3398215132Syongari /* Request PME if WOL is requested. */ 3399215132Syongari pmstat = pci_read_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, 2); 3400215132Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 3401215132Syongari if ((ifp->if_capenable & IFCAP_WOL) != 0) 3402215132Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 3403215132Syongari pci_write_config(sc->nfe_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); 3404215132Syongari} 3405