if_nfe.c revision 176859
1159967Sobrien/* $OpenBSD: if_nfe.c,v 1.54 2006/04/07 12:38:12 jsg Exp $ */ 2159952Sobrien 3159952Sobrien/*- 4159967Sobrien * Copyright (c) 2006 Shigeaki Tagashira <shigeaki@se.hiroshima-u.ac.jp> 5159952Sobrien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 6159952Sobrien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 7159952Sobrien * 8159952Sobrien * Permission to use, copy, modify, and distribute this software for any 9159952Sobrien * purpose with or without fee is hereby granted, provided that the above 10159952Sobrien * copyright notice and this permission notice appear in all copies. 11159952Sobrien * 12159952Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13159952Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14159952Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15159952Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16159952Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17159952Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18159952Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19159952Sobrien */ 20159952Sobrien 21159952Sobrien/* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 22159952Sobrien 23159967Sobrien#include <sys/cdefs.h> 24159967Sobrien__FBSDID("$FreeBSD: head/sys/dev/nfe/if_nfe.c 176859 2008-03-06 01:47:53Z yongari $"); 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); 80170589Syongaristatic void nfe_power(struct nfe_softc *); 81163503Sobrienstatic int nfe_miibus_readreg(device_t, int, int); 82163503Sobrienstatic int nfe_miibus_writereg(device_t, int, int, int); 83163503Sobrienstatic void nfe_miibus_statchg(device_t); 84170589Syongaristatic void nfe_link_task(void *, int); 85170589Syongaristatic void nfe_set_intr(struct nfe_softc *); 86170589Syongaristatic __inline void nfe_enable_intr(struct nfe_softc *); 87170589Syongaristatic __inline void nfe_disable_intr(struct nfe_softc *); 88163503Sobrienstatic int nfe_ioctl(struct ifnet *, u_long, caddr_t); 89170589Syongaristatic void nfe_alloc_msix(struct nfe_softc *, int); 90170589Syongaristatic int nfe_intr(void *); 91170589Syongaristatic void nfe_int_task(void *, int); 92170589Syongaristatic __inline void nfe_discard_rxbuf(struct nfe_softc *, int); 93170589Syongaristatic __inline void nfe_discard_jrxbuf(struct nfe_softc *, int); 94170589Syongaristatic int nfe_newbuf(struct nfe_softc *, int); 95170589Syongaristatic int nfe_jnewbuf(struct nfe_softc *, int); 96170589Syongaristatic int nfe_rxeof(struct nfe_softc *, int); 97170589Syongaristatic int nfe_jrxeof(struct nfe_softc *, int); 98159967Sobrienstatic void nfe_txeof(struct nfe_softc *); 99170589Syongaristatic int nfe_encap(struct nfe_softc *, struct mbuf **); 100159967Sobrienstatic void nfe_setmulti(struct nfe_softc *); 101170589Syongaristatic void nfe_tx_task(void *, int); 102159967Sobrienstatic void nfe_start(struct ifnet *); 103159967Sobrienstatic void nfe_watchdog(struct ifnet *); 104159967Sobrienstatic void nfe_init(void *); 105159967Sobrienstatic void nfe_init_locked(void *); 106170589Syongaristatic void nfe_stop(struct ifnet *); 107159967Sobrienstatic int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 108171559Syongaristatic void nfe_alloc_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 109170589Syongaristatic int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 110170589Syongaristatic int nfe_init_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 111159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 112170589Syongaristatic void nfe_free_jrx_ring(struct nfe_softc *, struct nfe_jrx_ring *); 113159967Sobrienstatic int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 114170589Syongaristatic void nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 115159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 116159967Sobrienstatic int nfe_ifmedia_upd(struct ifnet *); 117159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 118159967Sobrienstatic void nfe_tick(void *); 119170589Syongaristatic void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 120170589Syongaristatic void nfe_set_macaddr(struct nfe_softc *, uint8_t *); 121170589Syongaristatic void nfe_dma_map_segs(void *, bus_dma_segment_t *, int, int); 122159952Sobrien 123170589Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int); 124170589Syongaristatic int sysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS); 125170589Syongari 126159952Sobrien#ifdef NFE_DEBUG 127170589Syongaristatic int nfedebug = 0; 128170589Syongari#define DPRINTF(sc, ...) do { \ 129170589Syongari if (nfedebug) \ 130170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 131170589Syongari} while (0) 132170589Syongari#define DPRINTFN(sc, n, ...) do { \ 133170589Syongari if (nfedebug >= (n)) \ 134170589Syongari device_printf((sc)->nfe_dev, __VA_ARGS__); \ 135170589Syongari} while (0) 136159952Sobrien#else 137170589Syongari#define DPRINTF(sc, ...) 138170589Syongari#define DPRINTFN(sc, n, ...) 139159952Sobrien#endif 140159952Sobrien 141159967Sobrien#define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 142159967Sobrien#define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 143159967Sobrien#define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 144159967Sobrien 145170589Syongari/* Tunables. */ 146170589Syongaristatic int msi_disable = 0; 147170589Syongaristatic int msix_disable = 0; 148171559Syongaristatic int jumbo_disable = 0; 149170589SyongariTUNABLE_INT("hw.nfe.msi_disable", &msi_disable); 150170589SyongariTUNABLE_INT("hw.nfe.msix_disable", &msix_disable); 151171559SyongariTUNABLE_INT("hw.nfe.jumbo_disable", &jumbo_disable); 152159967Sobrien 153159967Sobrienstatic device_method_t nfe_methods[] = { 154159967Sobrien /* Device interface */ 155159967Sobrien DEVMETHOD(device_probe, nfe_probe), 156159967Sobrien DEVMETHOD(device_attach, nfe_attach), 157159967Sobrien DEVMETHOD(device_detach, nfe_detach), 158170589Syongari DEVMETHOD(device_suspend, nfe_suspend), 159170589Syongari DEVMETHOD(device_resume, nfe_resume), 160159967Sobrien DEVMETHOD(device_shutdown, nfe_shutdown), 161159967Sobrien 162159967Sobrien /* bus interface */ 163159967Sobrien DEVMETHOD(bus_print_child, bus_generic_print_child), 164159967Sobrien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 165159967Sobrien 166159967Sobrien /* MII interface */ 167159967Sobrien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 168159967Sobrien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 169163503Sobrien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 170159967Sobrien 171170589Syongari { NULL, NULL } 172159952Sobrien}; 173159952Sobrien 174159967Sobrienstatic driver_t nfe_driver = { 175159967Sobrien "nfe", 176159967Sobrien nfe_methods, 177159967Sobrien sizeof(struct nfe_softc) 178159967Sobrien}; 179159967Sobrien 180159967Sobrienstatic devclass_t nfe_devclass; 181159967Sobrien 182159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 183159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 184159967Sobrien 185159967Sobrienstatic struct nfe_type nfe_devs[] = { 186159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 187163503Sobrien "NVIDIA nForce MCP Networking Adapter"}, 188159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 189163503Sobrien "NVIDIA nForce2 MCP2 Networking Adapter"}, 190159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 191163503Sobrien "NVIDIA nForce2 400 MCP4 Networking Adapter"}, 192159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 193163503Sobrien "NVIDIA nForce2 400 MCP5 Networking Adapter"}, 194163437Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 195163503Sobrien "NVIDIA nForce3 MCP3 Networking Adapter"}, 196159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 197163503Sobrien "NVIDIA nForce3 250 MCP6 Networking Adapter"}, 198159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 199163503Sobrien "NVIDIA nForce3 MCP7 Networking Adapter"}, 200159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 201163503Sobrien "NVIDIA nForce4 CK804 MCP8 Networking Adapter"}, 202159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 203163503Sobrien "NVIDIA nForce4 CK804 MCP9 Networking Adapter"}, 204159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 205170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP10 */ 206159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 207170589Syongari "NVIDIA nForce MCP04 Networking Adapter"}, /* MCP11 */ 208159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 209163503Sobrien "NVIDIA nForce 430 MCP12 Networking Adapter"}, 210159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 211163503Sobrien "NVIDIA nForce 430 MCP13 Networking Adapter"}, 212159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 213163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 214159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 215163503Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 216162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 217163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 218162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 219163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 220162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 221163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 222170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4, 223163503Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 224162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 225163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 226162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 227163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 228162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 229163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 230170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4, 231163503Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 232170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1, 233170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 234170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2, 235170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 236170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3, 237170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 238170589Syongari {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4, 239170589Syongari "NVIDIA nForce MCP67 Networking Adapter"}, 240159967Sobrien {0, 0, NULL} 241159967Sobrien}; 242159967Sobrien 243159967Sobrien 244159967Sobrien/* Probe for supported hardware ID's */ 245159967Sobrienstatic int 246159967Sobriennfe_probe(device_t dev) 247159952Sobrien{ 248159967Sobrien struct nfe_type *t; 249159967Sobrien 250159967Sobrien t = nfe_devs; 251159967Sobrien /* Check for matching PCI DEVICE ID's */ 252159967Sobrien while (t->name != NULL) { 253159967Sobrien if ((pci_get_vendor(dev) == t->vid_id) && 254159967Sobrien (pci_get_device(dev) == t->dev_id)) { 255159967Sobrien device_set_desc(dev, t->name); 256170589Syongari return (BUS_PROBE_DEFAULT); 257159967Sobrien } 258159967Sobrien t++; 259159967Sobrien } 260159967Sobrien 261159967Sobrien return (ENXIO); 262159952Sobrien} 263159952Sobrien 264170589Syongaristatic void 265170589Syongarinfe_alloc_msix(struct nfe_softc *sc, int count) 266170589Syongari{ 267170589Syongari int rid; 268163503Sobrien 269170589Syongari rid = PCIR_BAR(2); 270170589Syongari sc->nfe_msix_res = bus_alloc_resource_any(sc->nfe_dev, SYS_RES_MEMORY, 271170589Syongari &rid, RF_ACTIVE); 272170589Syongari if (sc->nfe_msix_res == NULL) { 273170589Syongari device_printf(sc->nfe_dev, 274170589Syongari "couldn't allocate MSIX table resource\n"); 275170589Syongari return; 276170589Syongari } 277170589Syongari rid = PCIR_BAR(3); 278170589Syongari sc->nfe_msix_pba_res = bus_alloc_resource_any(sc->nfe_dev, 279170589Syongari SYS_RES_MEMORY, &rid, RF_ACTIVE); 280170589Syongari if (sc->nfe_msix_pba_res == NULL) { 281170589Syongari device_printf(sc->nfe_dev, 282170589Syongari "couldn't allocate MSIX PBA resource\n"); 283170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, PCIR_BAR(2), 284170589Syongari sc->nfe_msix_res); 285170589Syongari sc->nfe_msix_res = NULL; 286170589Syongari return; 287170589Syongari } 288170589Syongari 289170589Syongari if (pci_alloc_msix(sc->nfe_dev, &count) == 0) { 290170589Syongari if (count == NFE_MSI_MESSAGES) { 291170589Syongari if (bootverbose) 292170589Syongari device_printf(sc->nfe_dev, 293170589Syongari "Using %d MSIX messages\n", count); 294170589Syongari sc->nfe_msix = 1; 295170589Syongari } else { 296170589Syongari if (bootverbose) 297170589Syongari device_printf(sc->nfe_dev, 298170589Syongari "couldn't allocate MSIX\n"); 299170589Syongari pci_release_msi(sc->nfe_dev); 300170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 301170589Syongari PCIR_BAR(3), sc->nfe_msix_pba_res); 302170589Syongari bus_release_resource(sc->nfe_dev, SYS_RES_MEMORY, 303170589Syongari PCIR_BAR(2), sc->nfe_msix_res); 304170589Syongari sc->nfe_msix_pba_res = NULL; 305170589Syongari sc->nfe_msix_res = NULL; 306170589Syongari } 307170589Syongari } 308170589Syongari} 309170589Syongari 310159967Sobrienstatic int 311159967Sobriennfe_attach(device_t dev) 312159952Sobrien{ 313159967Sobrien struct nfe_softc *sc; 314159952Sobrien struct ifnet *ifp; 315170589Syongari bus_addr_t dma_addr_max; 316170589Syongari int error = 0, i, msic, reg, rid; 317159952Sobrien 318159967Sobrien sc = device_get_softc(dev); 319159967Sobrien sc->nfe_dev = dev; 320159952Sobrien 321159967Sobrien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 322170589Syongari MTX_DEF); 323159967Sobrien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 324170589Syongari TASK_INIT(&sc->nfe_link_task, 0, nfe_link_task, sc); 325159967Sobrien 326163503Sobrien pci_enable_busmaster(dev); 327159967Sobrien 328170589Syongari rid = PCIR_BAR(0); 329170589Syongari sc->nfe_res[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 330170589Syongari RF_ACTIVE); 331170589Syongari if (sc->nfe_res[0] == NULL) { 332170589Syongari device_printf(dev, "couldn't map memory resources\n"); 333170589Syongari mtx_destroy(&sc->nfe_mtx); 334170589Syongari return (ENXIO); 335170589Syongari } 336159967Sobrien 337170589Syongari if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 338170589Syongari uint16_t v, width; 339170589Syongari 340170589Syongari v = pci_read_config(dev, reg + 0x08, 2); 341170589Syongari /* Change max. read request size to 4096. */ 342170589Syongari v &= ~(7 << 12); 343170589Syongari v |= (5 << 12); 344170589Syongari pci_write_config(dev, reg + 0x08, v, 2); 345170589Syongari 346170589Syongari v = pci_read_config(dev, reg + 0x0c, 2); 347170589Syongari /* link capability */ 348170589Syongari v = (v >> 4) & 0x0f; 349170589Syongari width = pci_read_config(dev, reg + 0x12, 2); 350170589Syongari /* negotiated link width */ 351170589Syongari width = (width >> 4) & 0x3f; 352170589Syongari if (v != width) 353170589Syongari device_printf(sc->nfe_dev, 354170589Syongari "warning, negotiated width of link(x%d) != " 355170589Syongari "max. width of link(x%d)\n", width, v); 356159952Sobrien } 357159952Sobrien 358159967Sobrien /* Allocate interrupt */ 359170589Syongari if (msix_disable == 0 || msi_disable == 0) { 360170589Syongari if (msix_disable == 0 && 361170589Syongari (msic = pci_msix_count(dev)) == NFE_MSI_MESSAGES) 362170589Syongari nfe_alloc_msix(sc, msic); 363170589Syongari if (msi_disable == 0 && sc->nfe_msix == 0 && 364170589Syongari (msic = pci_msi_count(dev)) == NFE_MSI_MESSAGES && 365170589Syongari pci_alloc_msi(dev, &msic) == 0) { 366170589Syongari if (msic == NFE_MSI_MESSAGES) { 367170589Syongari if (bootverbose) 368170589Syongari device_printf(dev, 369170589Syongari "Using %d MSI messages\n", msic); 370170589Syongari sc->nfe_msi = 1; 371170589Syongari } else 372170589Syongari pci_release_msi(dev); 373170589Syongari } 374170589Syongari } 375159967Sobrien 376170589Syongari if (sc->nfe_msix == 0 && sc->nfe_msi == 0) { 377170589Syongari rid = 0; 378170589Syongari sc->nfe_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 379170589Syongari RF_SHAREABLE | RF_ACTIVE); 380170589Syongari if (sc->nfe_irq[0] == NULL) { 381170589Syongari device_printf(dev, "couldn't allocate IRQ resources\n"); 382170589Syongari error = ENXIO; 383170589Syongari goto fail; 384170589Syongari } 385170589Syongari } else { 386170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 387170589Syongari sc->nfe_irq[i] = bus_alloc_resource_any(dev, 388170589Syongari SYS_RES_IRQ, &rid, RF_ACTIVE); 389170589Syongari if (sc->nfe_irq[i] == NULL) { 390170589Syongari device_printf(dev, 391170589Syongari "couldn't allocate IRQ resources for " 392170589Syongari "message %d\n", rid); 393170589Syongari error = ENXIO; 394170589Syongari goto fail; 395170589Syongari } 396170589Syongari } 397170589Syongari /* Map interrupts to vector 0. */ 398170589Syongari if (sc->nfe_msix != 0) { 399170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP0, 0); 400170589Syongari NFE_WRITE(sc, NFE_MSIX_MAP1, 0); 401170589Syongari } else if (sc->nfe_msi != 0) { 402170589Syongari NFE_WRITE(sc, NFE_MSI_MAP0, 0); 403170589Syongari NFE_WRITE(sc, NFE_MSI_MAP1, 0); 404170589Syongari } 405159952Sobrien } 406159952Sobrien 407170589Syongari /* Set IRQ status/mask register. */ 408170589Syongari sc->nfe_irq_status = NFE_IRQ_STATUS; 409170589Syongari sc->nfe_irq_mask = NFE_IRQ_MASK; 410170589Syongari sc->nfe_intrs = NFE_IRQ_WANTED; 411170589Syongari sc->nfe_nointrs = 0; 412170589Syongari if (sc->nfe_msix != 0) { 413170589Syongari sc->nfe_irq_status = NFE_MSIX_IRQ_STATUS; 414170589Syongari sc->nfe_nointrs = NFE_IRQ_WANTED; 415170589Syongari } else if (sc->nfe_msi != 0) { 416170589Syongari sc->nfe_irq_mask = NFE_MSI_IRQ_MASK; 417170589Syongari sc->nfe_intrs = NFE_MSI_VECTOR_0_ENABLED; 418170589Syongari } 419159952Sobrien 420170589Syongari sc->nfe_devid = pci_get_device(dev); 421170589Syongari sc->nfe_revid = pci_get_revid(dev); 422159967Sobrien sc->nfe_flags = 0; 423159952Sobrien 424170589Syongari switch (sc->nfe_devid) { 425159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 426159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 427159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 428159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 429159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 430159952Sobrien break; 431159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 432159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 433170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT; 434159952Sobrien break; 435159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 436159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 437159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 438159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 439159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 440159952Sobrien break; 441159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 442159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 443163503Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 444170589Syongari NFE_HW_VLAN | NFE_PWR_MGMT | NFE_TX_FLOW_CTRL; 445159952Sobrien break; 446170589Syongari 447162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 448162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 449162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 450162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 451170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 452170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 453170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 454170589Syongari case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 455170589Syongari sc->nfe_flags |= NFE_40BIT_ADDR | NFE_PWR_MGMT | 456173377Syongari NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL; 457162212Sobrien break; 458162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 459162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 460162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 461162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 462170589Syongari sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | 463173377Syongari NFE_PWR_MGMT | NFE_CORRECT_MACADDR | NFE_TX_FLOW_CTRL; 464163503Sobrien break; 465159952Sobrien } 466159952Sobrien 467170589Syongari nfe_power(sc); 468170589Syongari /* Check for reversed ethernet address */ 469170589Syongari if ((NFE_READ(sc, NFE_TX_UNK) & NFE_MAC_ADDR_INORDER) != 0) 470170589Syongari sc->nfe_flags |= NFE_CORRECT_MACADDR; 471170589Syongari nfe_get_macaddr(sc, sc->eaddr); 472159952Sobrien /* 473159967Sobrien * Allocate the parent bus DMA tag appropriate for PCI. 474159967Sobrien */ 475170589Syongari dma_addr_max = BUS_SPACE_MAXADDR_32BIT; 476170589Syongari if ((sc->nfe_flags & NFE_40BIT_ADDR) != 0) 477170589Syongari dma_addr_max = NFE_DMA_MAXADDR; 478170589Syongari error = bus_dma_tag_create( 479170589Syongari bus_get_dma_tag(sc->nfe_dev), /* parent */ 480163503Sobrien 1, 0, /* alignment, boundary */ 481170589Syongari dma_addr_max, /* lowaddr */ 482163503Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 483163503Sobrien NULL, NULL, /* filter, filterarg */ 484170589Syongari BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ 485163503Sobrien BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 486170589Syongari 0, /* flags */ 487163503Sobrien NULL, NULL, /* lockfunc, lockarg */ 488163503Sobrien &sc->nfe_parent_tag); 489159967Sobrien if (error) 490159967Sobrien goto fail; 491159967Sobrien 492164650Sobrien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 493164650Sobrien if (ifp == NULL) { 494170589Syongari device_printf(dev, "can not if_alloc()\n"); 495164650Sobrien error = ENOSPC; 496164650Sobrien goto fail; 497164650Sobrien } 498170589Syongari TASK_INIT(&sc->nfe_tx_task, 1, nfe_tx_task, ifp); 499164650Sobrien 500159967Sobrien /* 501159952Sobrien * Allocate Tx and Rx rings. 502159952Sobrien */ 503170589Syongari if ((error = nfe_alloc_tx_ring(sc, &sc->txq)) != 0) 504159967Sobrien goto fail; 505159952Sobrien 506170589Syongari if ((error = nfe_alloc_rx_ring(sc, &sc->rxq)) != 0) 507159967Sobrien goto fail; 508170589Syongari 509171559Syongari nfe_alloc_jrx_ring(sc, &sc->jrxq); 510170589Syongari 511170589Syongari SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 512170589Syongari SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 513170589Syongari OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW, 514170589Syongari &sc->nfe_process_limit, 0, sysctl_hw_nfe_proc_limit, "I", 515170589Syongari "max number of Rx events to process"); 516170589Syongari 517170589Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 518170589Syongari error = resource_int_value(device_get_name(dev), device_get_unit(dev), 519170589Syongari "process_limit", &sc->nfe_process_limit); 520170589Syongari if (error == 0) { 521170589Syongari if (sc->nfe_process_limit < NFE_PROC_MIN || 522170589Syongari sc->nfe_process_limit > NFE_PROC_MAX) { 523170589Syongari device_printf(dev, "process_limit value out of range; " 524170589Syongari "using default: %d\n", NFE_PROC_DEFAULT); 525170589Syongari sc->nfe_process_limit = NFE_PROC_DEFAULT; 526170589Syongari } 527159952Sobrien } 528159952Sobrien 529159952Sobrien ifp->if_softc = sc; 530159967Sobrien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 531170589Syongari ifp->if_mtu = ETHERMTU; 532159952Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 533159952Sobrien ifp->if_ioctl = nfe_ioctl; 534159952Sobrien ifp->if_start = nfe_start; 535170589Syongari ifp->if_hwassist = 0; 536170589Syongari ifp->if_capabilities = 0; 537170589Syongari ifp->if_watchdog = NULL; 538159952Sobrien ifp->if_init = nfe_init; 539170589Syongari IFQ_SET_MAXLEN(&ifp->if_snd, NFE_TX_RING_COUNT - 1); 540170589Syongari ifp->if_snd.ifq_drv_maxlen = NFE_TX_RING_COUNT - 1; 541170589Syongari IFQ_SET_READY(&ifp->if_snd); 542159952Sobrien 543170589Syongari if (sc->nfe_flags & NFE_HW_CSUM) { 544170589Syongari ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4; 545170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES | CSUM_TSO; 546170589Syongari } 547170589Syongari ifp->if_capenable = ifp->if_capabilities; 548164650Sobrien 549170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 550170589Syongari /* VLAN capability setup. */ 551170589Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 552170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) { 553159952Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 554170589Syongari if ((ifp->if_capabilities & IFCAP_HWCSUM) != 0) 555170589Syongari ifp->if_capabilities |= IFCAP_VLAN_HWCSUM; 556159952Sobrien } 557159967Sobrien ifp->if_capenable = ifp->if_capabilities; 558159952Sobrien 559170589Syongari /* 560170589Syongari * Tell the upper layer(s) we support long frames. 561170589Syongari * Must appear after the call to ether_ifattach() because 562170589Syongari * ether_ifattach() sets ifi_hdrlen to the default value. 563170589Syongari */ 564170589Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 565170589Syongari 566159967Sobrien#ifdef DEVICE_POLLING 567159967Sobrien ifp->if_capabilities |= IFCAP_POLLING; 568159967Sobrien#endif 569159952Sobrien 570159967Sobrien /* Do MII setup */ 571163503Sobrien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, 572163503Sobrien nfe_ifmedia_sts)) { 573170589Syongari device_printf(dev, "MII without any phy!\n"); 574159967Sobrien error = ENXIO; 575159967Sobrien goto fail; 576159967Sobrien } 577159967Sobrien ether_ifattach(ifp, sc->eaddr); 578159952Sobrien 579170589Syongari TASK_INIT(&sc->nfe_int_task, 0, nfe_int_task, sc); 580170589Syongari sc->nfe_tq = taskqueue_create_fast("nfe_taskq", M_WAITOK, 581170589Syongari taskqueue_thread_enqueue, &sc->nfe_tq); 582170589Syongari taskqueue_start_threads(&sc->nfe_tq, 1, PI_NET, "%s taskq", 583170589Syongari device_get_nameunit(sc->nfe_dev)); 584170589Syongari error = 0; 585170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 586170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[0], 587170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 588170589Syongari &sc->nfe_intrhand[0]); 589170589Syongari } else { 590170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 591170589Syongari error = bus_setup_intr(dev, sc->nfe_irq[i], 592170589Syongari INTR_TYPE_NET | INTR_MPSAFE, nfe_intr, NULL, sc, 593170589Syongari &sc->nfe_intrhand[i]); 594170589Syongari if (error != 0) 595170589Syongari break; 596170589Syongari } 597170589Syongari } 598159967Sobrien if (error) { 599170589Syongari device_printf(dev, "couldn't set up irq\n"); 600170589Syongari taskqueue_free(sc->nfe_tq); 601170589Syongari sc->nfe_tq = NULL; 602159967Sobrien ether_ifdetach(ifp); 603159967Sobrien goto fail; 604159967Sobrien } 605159967Sobrien 606159967Sobrienfail: 607159967Sobrien if (error) 608159967Sobrien nfe_detach(dev); 609159967Sobrien 610159967Sobrien return (error); 611159952Sobrien} 612159952Sobrien 613159967Sobrien 614159967Sobrienstatic int 615159967Sobriennfe_detach(device_t dev) 616159952Sobrien{ 617163503Sobrien struct nfe_softc *sc; 618163503Sobrien struct ifnet *ifp; 619170589Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 620170589Syongari int i, rid; 621159952Sobrien 622159967Sobrien sc = device_get_softc(dev); 623159967Sobrien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 624159967Sobrien ifp = sc->nfe_ifp; 625159967Sobrien 626159967Sobrien#ifdef DEVICE_POLLING 627170589Syongari if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING) 628159967Sobrien ether_poll_deregister(ifp); 629159967Sobrien#endif 630159967Sobrien if (device_is_attached(dev)) { 631164649Sobrien NFE_LOCK(sc); 632170589Syongari nfe_stop(ifp); 633159967Sobrien ifp->if_flags &= ~IFF_UP; 634164649Sobrien NFE_UNLOCK(sc); 635159967Sobrien callout_drain(&sc->nfe_stat_ch); 636170589Syongari taskqueue_drain(taskqueue_fast, &sc->nfe_tx_task); 637170589Syongari taskqueue_drain(taskqueue_swi, &sc->nfe_link_task); 638159967Sobrien ether_ifdetach(ifp); 639159967Sobrien } 640159967Sobrien 641170589Syongari if (ifp) { 642170589Syongari /* restore ethernet address */ 643170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 644170589Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) { 645170589Syongari eaddr[i] = sc->eaddr[5 - i]; 646170589Syongari } 647170589Syongari } else 648170589Syongari bcopy(sc->eaddr, eaddr, ETHER_ADDR_LEN); 649170589Syongari nfe_set_macaddr(sc, eaddr); 650159967Sobrien if_free(ifp); 651170589Syongari } 652159967Sobrien if (sc->nfe_miibus) 653159967Sobrien device_delete_child(dev, sc->nfe_miibus); 654159967Sobrien bus_generic_detach(dev); 655170589Syongari if (sc->nfe_tq != NULL) { 656170589Syongari taskqueue_drain(sc->nfe_tq, &sc->nfe_int_task); 657170589Syongari taskqueue_free(sc->nfe_tq); 658170589Syongari sc->nfe_tq = NULL; 659170589Syongari } 660159967Sobrien 661170589Syongari for (i = 0; i < NFE_MSI_MESSAGES; i++) { 662170589Syongari if (sc->nfe_intrhand[i] != NULL) { 663170589Syongari bus_teardown_intr(dev, sc->nfe_irq[i], 664170589Syongari sc->nfe_intrhand[i]); 665170589Syongari sc->nfe_intrhand[i] = NULL; 666170589Syongari } 667170589Syongari } 668159967Sobrien 669170589Syongari if (sc->nfe_msi == 0 && sc->nfe_msix == 0) { 670170589Syongari if (sc->nfe_irq[0] != NULL) 671170589Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, 672170589Syongari sc->nfe_irq[0]); 673170589Syongari } else { 674170589Syongari for (i = 0, rid = 1; i < NFE_MSI_MESSAGES; i++, rid++) { 675170589Syongari if (sc->nfe_irq[i] != NULL) { 676170589Syongari bus_release_resource(dev, SYS_RES_IRQ, rid, 677170589Syongari sc->nfe_irq[i]); 678170589Syongari sc->nfe_irq[i] = NULL; 679170589Syongari } 680170589Syongari } 681170589Syongari pci_release_msi(dev); 682170589Syongari } 683170589Syongari if (sc->nfe_msix_pba_res != NULL) { 684170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(3), 685170589Syongari sc->nfe_msix_pba_res); 686170589Syongari sc->nfe_msix_pba_res = NULL; 687170589Syongari } 688170589Syongari if (sc->nfe_msix_res != NULL) { 689170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(2), 690170589Syongari sc->nfe_msix_res); 691170589Syongari sc->nfe_msix_res = NULL; 692170589Syongari } 693170589Syongari if (sc->nfe_res[0] != NULL) { 694170589Syongari bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), 695170589Syongari sc->nfe_res[0]); 696170589Syongari sc->nfe_res[0] = NULL; 697170589Syongari } 698170589Syongari 699159967Sobrien nfe_free_tx_ring(sc, &sc->txq); 700159967Sobrien nfe_free_rx_ring(sc, &sc->rxq); 701170589Syongari nfe_free_jrx_ring(sc, &sc->jrxq); 702159967Sobrien 703170589Syongari if (sc->nfe_parent_tag) { 704159967Sobrien bus_dma_tag_destroy(sc->nfe_parent_tag); 705170589Syongari sc->nfe_parent_tag = NULL; 706170589Syongari } 707159967Sobrien 708159967Sobrien mtx_destroy(&sc->nfe_mtx); 709159967Sobrien 710159967Sobrien return (0); 711159952Sobrien} 712159952Sobrien 713159967Sobrien 714170589Syongaristatic int 715170589Syongarinfe_suspend(device_t dev) 716170589Syongari{ 717170589Syongari struct nfe_softc *sc; 718170589Syongari 719170589Syongari sc = device_get_softc(dev); 720170589Syongari 721170589Syongari NFE_LOCK(sc); 722170589Syongari nfe_stop(sc->nfe_ifp); 723170589Syongari sc->nfe_suspended = 1; 724170589Syongari NFE_UNLOCK(sc); 725170589Syongari 726170589Syongari return (0); 727170589Syongari} 728170589Syongari 729170589Syongari 730170589Syongaristatic int 731170589Syongarinfe_resume(device_t dev) 732170589Syongari{ 733170589Syongari struct nfe_softc *sc; 734170589Syongari struct ifnet *ifp; 735170589Syongari 736170589Syongari sc = device_get_softc(dev); 737170589Syongari 738170589Syongari NFE_LOCK(sc); 739170589Syongari ifp = sc->nfe_ifp; 740170589Syongari if (ifp->if_flags & IFF_UP) 741170589Syongari nfe_init_locked(sc); 742170589Syongari sc->nfe_suspended = 0; 743170589Syongari NFE_UNLOCK(sc); 744170589Syongari 745170589Syongari return (0); 746170589Syongari} 747170589Syongari 748170589Syongari 749170589Syongari/* Take PHY/NIC out of powerdown, from Linux */ 750159967Sobrienstatic void 751170589Syongarinfe_power(struct nfe_softc *sc) 752170589Syongari{ 753170589Syongari uint32_t pwr; 754170589Syongari 755170589Syongari if ((sc->nfe_flags & NFE_PWR_MGMT) == 0) 756170589Syongari return; 757170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | NFE_RXTX_BIT2); 758170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, NFE_MAC_RESET_MAGIC); 759170589Syongari DELAY(100); 760170589Syongari NFE_WRITE(sc, NFE_MAC_RESET, 0); 761170589Syongari DELAY(100); 762170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT2); 763170589Syongari pwr = NFE_READ(sc, NFE_PWR2_CTL); 764170589Syongari pwr &= ~NFE_PWR2_WAKEUP_MASK; 765170589Syongari if (sc->nfe_revid >= 0xa3 && 766170589Syongari (sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN1 || 767170589Syongari sc->nfe_devid == PCI_PRODUCT_NVIDIA_NFORCE430_LAN2)) 768170589Syongari pwr |= NFE_PWR2_REVA3; 769170589Syongari NFE_WRITE(sc, NFE_PWR2_CTL, pwr); 770170589Syongari} 771170589Syongari 772170589Syongari 773170589Syongaristatic void 774159967Sobriennfe_miibus_statchg(device_t dev) 775159952Sobrien{ 776159967Sobrien struct nfe_softc *sc; 777170589Syongari 778170589Syongari sc = device_get_softc(dev); 779170589Syongari taskqueue_enqueue(taskqueue_swi, &sc->nfe_link_task); 780170589Syongari} 781170589Syongari 782170589Syongari 783170589Syongaristatic void 784170589Syongarinfe_link_task(void *arg, int pending) 785170589Syongari{ 786170589Syongari struct nfe_softc *sc; 787159967Sobrien struct mii_data *mii; 788170589Syongari struct ifnet *ifp; 789170589Syongari uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 790170589Syongari uint32_t gmask, rxctl, txctl, val; 791159952Sobrien 792170589Syongari sc = (struct nfe_softc *)arg; 793170589Syongari 794170589Syongari NFE_LOCK(sc); 795170589Syongari 796159967Sobrien mii = device_get_softc(sc->nfe_miibus); 797170589Syongari ifp = sc->nfe_ifp; 798170589Syongari if (mii == NULL || ifp == NULL) { 799170589Syongari NFE_UNLOCK(sc); 800170589Syongari return; 801170589Syongari } 802159967Sobrien 803170589Syongari if (mii->mii_media_status & IFM_ACTIVE) { 804170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) 805170589Syongari sc->nfe_link = 1; 806170589Syongari } else 807170589Syongari sc->nfe_link = 0; 808170589Syongari 809159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 810159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 811159952Sobrien 812159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 813159952Sobrien seed &= ~NFE_SEED_MASK; 814159952Sobrien 815170589Syongari if (((mii->mii_media_active & IFM_GMASK) & IFM_FDX) == 0) { 816159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 817159952Sobrien misc |= NFE_MISC1_HDX; 818159952Sobrien } 819159952Sobrien 820159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 821159952Sobrien case IFM_1000_T: /* full-duplex only */ 822159952Sobrien link |= NFE_MEDIA_1000T; 823159952Sobrien seed |= NFE_SEED_1000T; 824159952Sobrien phy |= NFE_PHY_1000T; 825159952Sobrien break; 826159952Sobrien case IFM_100_TX: 827159952Sobrien link |= NFE_MEDIA_100TX; 828159952Sobrien seed |= NFE_SEED_100TX; 829159952Sobrien phy |= NFE_PHY_100TX; 830159952Sobrien break; 831159952Sobrien case IFM_10_T: 832159952Sobrien link |= NFE_MEDIA_10T; 833159952Sobrien seed |= NFE_SEED_10T; 834159952Sobrien break; 835159952Sobrien } 836159952Sobrien 837170589Syongari if ((phy & 0x10000000) != 0) { 838170589Syongari if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 839170589Syongari val = NFE_R1_MAGIC_1000; 840170589Syongari else 841170589Syongari val = NFE_R1_MAGIC_10_100; 842170589Syongari } else 843170589Syongari val = NFE_R1_MAGIC_DEFAULT; 844170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, val); 845170589Syongari 846159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 847159952Sobrien 848159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 849159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 850159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 851170589Syongari 852170589Syongari gmask = mii->mii_media_active & IFM_GMASK; 853170589Syongari if ((gmask & IFM_FDX) != 0) { 854170589Syongari /* It seems all hardwares supports Rx pause frames. */ 855170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 856170589Syongari if ((gmask & IFM_FLAG0) != 0) 857170589Syongari val |= NFE_PFF_RX_PAUSE; 858170589Syongari else 859170589Syongari val &= ~NFE_PFF_RX_PAUSE; 860170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 861170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 862170589Syongari val = NFE_READ(sc, NFE_MISC1); 863170589Syongari if ((gmask & IFM_FLAG1) != 0) { 864170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 865170589Syongari NFE_TX_PAUSE_FRAME_ENABLE); 866170589Syongari val |= NFE_MISC1_TX_PAUSE; 867170589Syongari } else { 868170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 869170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 870170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 871170589Syongari } 872170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 873170589Syongari } 874170589Syongari } else { 875170589Syongari /* disable rx/tx pause frames */ 876170589Syongari val = NFE_READ(sc, NFE_RXFILTER); 877170589Syongari val &= ~NFE_PFF_RX_PAUSE; 878170589Syongari NFE_WRITE(sc, NFE_RXFILTER, val); 879170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) { 880170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, 881170589Syongari NFE_TX_PAUSE_FRAME_DISABLE); 882170589Syongari val = NFE_READ(sc, NFE_MISC1); 883170589Syongari val &= ~NFE_MISC1_TX_PAUSE; 884170589Syongari NFE_WRITE(sc, NFE_MISC1, val); 885170589Syongari } 886170589Syongari } 887170589Syongari 888170589Syongari txctl = NFE_READ(sc, NFE_TX_CTL); 889170589Syongari rxctl = NFE_READ(sc, NFE_RX_CTL); 890170589Syongari if (sc->nfe_link != 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 891170589Syongari txctl |= NFE_TX_START; 892170589Syongari rxctl |= NFE_RX_START; 893170589Syongari } else { 894170589Syongari txctl &= ~NFE_TX_START; 895170589Syongari rxctl &= ~NFE_RX_START; 896170589Syongari } 897172164Syongari NFE_WRITE(sc, NFE_TX_CTL, txctl); 898172164Syongari NFE_WRITE(sc, NFE_RX_CTL, rxctl); 899170589Syongari 900170589Syongari NFE_UNLOCK(sc); 901159952Sobrien} 902159952Sobrien 903163503Sobrien 904159967Sobrienstatic int 905159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg) 906159952Sobrien{ 907159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 908170589Syongari uint32_t val; 909159952Sobrien int ntries; 910159952Sobrien 911159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 912159952Sobrien 913159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 914159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 915159952Sobrien DELAY(100); 916159952Sobrien } 917159952Sobrien 918159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 919159952Sobrien 920170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 921159952Sobrien DELAY(100); 922159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 923159952Sobrien break; 924159952Sobrien } 925170589Syongari if (ntries == NFE_TIMEOUT) { 926170589Syongari DPRINTFN(sc, 2, "timeout waiting for PHY\n"); 927159952Sobrien return 0; 928159952Sobrien } 929159952Sobrien 930159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 931170589Syongari DPRINTFN(sc, 2, "could not read PHY\n"); 932159952Sobrien return 0; 933159952Sobrien } 934159952Sobrien 935159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 936159952Sobrien if (val != 0xffffffff && val != 0) 937159952Sobrien sc->mii_phyaddr = phy; 938159952Sobrien 939170589Syongari DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 940159952Sobrien 941170589Syongari return (val); 942159952Sobrien} 943159952Sobrien 944163503Sobrien 945159967Sobrienstatic int 946159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val) 947159952Sobrien{ 948159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 949170589Syongari uint32_t ctl; 950163503Sobrien int ntries; 951159952Sobrien 952159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 953159952Sobrien 954159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 955159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 956159952Sobrien DELAY(100); 957159952Sobrien } 958159952Sobrien 959159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 960159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 961159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 962159952Sobrien 963170589Syongari for (ntries = 0; ntries < NFE_TIMEOUT; ntries++) { 964159952Sobrien DELAY(100); 965159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 966159952Sobrien break; 967159952Sobrien } 968159952Sobrien#ifdef NFE_DEBUG 969170589Syongari if (nfedebug >= 2 && ntries == NFE_TIMEOUT) 970170589Syongari device_printf(sc->nfe_dev, "could not write to PHY\n"); 971159952Sobrien#endif 972170589Syongari return (0); 973159952Sobrien} 974159952Sobrien 975170589Syongaristruct nfe_dmamap_arg { 976170589Syongari bus_addr_t nfe_busaddr; 977170589Syongari}; 978170589Syongari 979159967Sobrienstatic int 980159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 981159952Sobrien{ 982170589Syongari struct nfe_dmamap_arg ctx; 983159967Sobrien struct nfe_rx_data *data; 984170589Syongari void *desc; 985159967Sobrien int i, error, descsize; 986159967Sobrien 987159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 988170589Syongari desc = ring->desc64; 989159967Sobrien descsize = sizeof (struct nfe_desc64); 990159967Sobrien } else { 991170589Syongari desc = ring->desc32; 992159967Sobrien descsize = sizeof (struct nfe_desc32); 993159967Sobrien } 994159967Sobrien 995159967Sobrien ring->cur = ring->next = 0; 996159967Sobrien 997163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 998170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 999170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1000170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1001170589Syongari NULL, NULL, /* filter, filterarg */ 1002170589Syongari NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1003170589Syongari NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 1004170589Syongari 0, /* flags */ 1005170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1006170589Syongari &ring->rx_desc_tag); 1007159967Sobrien if (error != 0) { 1008170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1009159967Sobrien goto fail; 1010159967Sobrien } 1011159967Sobrien 1012159967Sobrien /* allocate memory to desc */ 1013170589Syongari error = bus_dmamem_alloc(ring->rx_desc_tag, &desc, BUS_DMA_WAITOK | 1014170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->rx_desc_map); 1015159967Sobrien if (error != 0) { 1016170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1017159967Sobrien goto fail; 1018159967Sobrien } 1019170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1020170589Syongari ring->desc64 = desc; 1021170589Syongari else 1022170589Syongari ring->desc32 = desc; 1023159967Sobrien 1024159967Sobrien /* map desc to device visible address space */ 1025170589Syongari ctx.nfe_busaddr = 0; 1026170589Syongari error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, desc, 1027170589Syongari NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1028159967Sobrien if (error != 0) { 1029170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1030159967Sobrien goto fail; 1031159967Sobrien } 1032170589Syongari ring->physaddr = ctx.nfe_busaddr; 1033159967Sobrien 1034170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1035170589Syongari 1, 0, /* alignment, boundary */ 1036170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1037170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1038170589Syongari NULL, NULL, /* filter, filterarg */ 1039170589Syongari MCLBYTES, 1, /* maxsize, nsegments */ 1040170589Syongari MCLBYTES, /* maxsegsize */ 1041170589Syongari 0, /* flags */ 1042170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1043170589Syongari &ring->rx_data_tag); 1044170589Syongari if (error != 0) { 1045170589Syongari device_printf(sc->nfe_dev, "could not create Rx DMA tag\n"); 1046170589Syongari goto fail; 1047170589Syongari } 1048159967Sobrien 1049170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, &ring->rx_spare_map); 1050170589Syongari if (error != 0) { 1051170589Syongari device_printf(sc->nfe_dev, 1052170589Syongari "could not create Rx DMA spare map\n"); 1053170589Syongari goto fail; 1054170589Syongari } 1055170589Syongari 1056159967Sobrien /* 1057159967Sobrien * Pre-allocate Rx buffers and populate Rx ring. 1058159967Sobrien */ 1059159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1060159967Sobrien data = &sc->rxq.data[i]; 1061170589Syongari data->rx_data_map = NULL; 1062170589Syongari data->m = NULL; 1063170589Syongari error = bus_dmamap_create(ring->rx_data_tag, 0, 1064170589Syongari &data->rx_data_map); 1065164651Sobrien if (error != 0) { 1066170589Syongari device_printf(sc->nfe_dev, 1067170589Syongari "could not create Rx DMA map\n"); 1068164651Sobrien goto fail; 1069164651Sobrien } 1070170589Syongari } 1071159967Sobrien 1072170589Syongarifail: 1073170589Syongari return (error); 1074170589Syongari} 1075170589Syongari 1076170589Syongari 1077171559Syongaristatic void 1078170589Syongarinfe_alloc_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1079170589Syongari{ 1080170589Syongari struct nfe_dmamap_arg ctx; 1081170589Syongari struct nfe_rx_data *data; 1082170589Syongari void *desc; 1083170589Syongari int i, error, descsize; 1084170589Syongari 1085170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1086171559Syongari return; 1087171559Syongari if (jumbo_disable != 0) { 1088171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support\n"); 1089171559Syongari sc->nfe_jumbo_disable = 1; 1090171559Syongari return; 1091171559Syongari } 1092170589Syongari 1093170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1094170589Syongari desc = ring->jdesc64; 1095170589Syongari descsize = sizeof (struct nfe_desc64); 1096170589Syongari } else { 1097170589Syongari desc = ring->jdesc32; 1098170589Syongari descsize = sizeof (struct nfe_desc32); 1099170589Syongari } 1100170589Syongari 1101170589Syongari ring->jcur = ring->jnext = 0; 1102170589Syongari 1103170589Syongari /* Create DMA tag for jumbo Rx ring. */ 1104170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1105170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1106170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1107170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1108170589Syongari NULL, NULL, /* filter, filterarg */ 1109170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsize */ 1110170589Syongari 1, /* nsegments */ 1111170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, /* maxsegsize */ 1112170589Syongari 0, /* flags */ 1113170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1114170589Syongari &ring->jrx_desc_tag); 1115170589Syongari if (error != 0) { 1116170589Syongari device_printf(sc->nfe_dev, 1117170589Syongari "could not create jumbo ring DMA tag\n"); 1118170589Syongari goto fail; 1119170589Syongari } 1120170589Syongari 1121170589Syongari /* Create DMA tag for jumbo Rx buffers. */ 1122170589Syongari error = bus_dma_tag_create(sc->nfe_parent_tag, 1123170589Syongari PAGE_SIZE, 0, /* alignment, boundary */ 1124170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1125170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1126170589Syongari NULL, NULL, /* filter, filterarg */ 1127176859Syongari MJUM9BYTES, /* maxsize */ 1128170589Syongari 1, /* nsegments */ 1129176859Syongari MJUM9BYTES, /* maxsegsize */ 1130170589Syongari 0, /* flags */ 1131170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1132170589Syongari &ring->jrx_data_tag); 1133170589Syongari if (error != 0) { 1134170589Syongari device_printf(sc->nfe_dev, 1135170589Syongari "could not create jumbo Rx buffer DMA tag\n"); 1136170589Syongari goto fail; 1137170589Syongari } 1138170589Syongari 1139170589Syongari /* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */ 1140170589Syongari error = bus_dmamem_alloc(ring->jrx_desc_tag, &desc, BUS_DMA_WAITOK | 1141170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->jrx_desc_map); 1142170589Syongari if (error != 0) { 1143170589Syongari device_printf(sc->nfe_dev, 1144170589Syongari "could not allocate DMA'able memory for jumbo Rx ring\n"); 1145170589Syongari goto fail; 1146170589Syongari } 1147170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1148170589Syongari ring->jdesc64 = desc; 1149170589Syongari else 1150170589Syongari ring->jdesc32 = desc; 1151170589Syongari 1152170589Syongari ctx.nfe_busaddr = 0; 1153170589Syongari error = bus_dmamap_load(ring->jrx_desc_tag, ring->jrx_desc_map, desc, 1154170589Syongari NFE_JUMBO_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1155170589Syongari if (error != 0) { 1156170589Syongari device_printf(sc->nfe_dev, 1157170589Syongari "could not load DMA'able memory for jumbo Rx ring\n"); 1158170589Syongari goto fail; 1159170589Syongari } 1160170589Syongari ring->jphysaddr = ctx.nfe_busaddr; 1161170589Syongari 1162170589Syongari /* Create DMA maps for jumbo Rx buffers. */ 1163170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, &ring->jrx_spare_map); 1164170589Syongari if (error != 0) { 1165170589Syongari device_printf(sc->nfe_dev, 1166170589Syongari "could not create jumbo Rx DMA spare map\n"); 1167170589Syongari goto fail; 1168170589Syongari } 1169170589Syongari 1170170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1171170589Syongari data = &sc->jrxq.jdata[i]; 1172170589Syongari data->rx_data_map = NULL; 1173170589Syongari data->m = NULL; 1174170589Syongari error = bus_dmamap_create(ring->jrx_data_tag, 0, 1175164651Sobrien &data->rx_data_map); 1176164651Sobrien if (error != 0) { 1177170589Syongari device_printf(sc->nfe_dev, 1178170589Syongari "could not create jumbo Rx DMA map\n"); 1179164651Sobrien goto fail; 1180164651Sobrien } 1181170589Syongari } 1182159967Sobrien 1183171559Syongari return; 1184159967Sobrien 1185170589Syongarifail: 1186171559Syongari /* 1187171559Syongari * Running without jumbo frame support is ok for most cases 1188171559Syongari * so don't fail on creating dma tag/map for jumbo frame. 1189171559Syongari */ 1190170589Syongari nfe_free_jrx_ring(sc, ring); 1191171559Syongari device_printf(sc->nfe_dev, "disabling jumbo frame support due to " 1192171559Syongari "resource shortage\n"); 1193171559Syongari sc->nfe_jumbo_disable = 1; 1194170589Syongari} 1195159967Sobrien 1196159967Sobrien 1197170589Syongaristatic int 1198170589Syongarinfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1199170589Syongari{ 1200170589Syongari void *desc; 1201170589Syongari size_t descsize; 1202170589Syongari int i; 1203159967Sobrien 1204170589Syongari ring->cur = ring->next = 0; 1205170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1206170589Syongari desc = ring->desc64; 1207170589Syongari descsize = sizeof (struct nfe_desc64); 1208170589Syongari } else { 1209170589Syongari desc = ring->desc32; 1210170589Syongari descsize = sizeof (struct nfe_desc32); 1211159967Sobrien } 1212170589Syongari bzero(desc, descsize * NFE_RX_RING_COUNT); 1213170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1214170589Syongari if (nfe_newbuf(sc, i) != 0) 1215170589Syongari return (ENOBUFS); 1216170589Syongari } 1217159967Sobrien 1218163503Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, 1219170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1220159967Sobrien 1221170589Syongari return (0); 1222159967Sobrien} 1223159967Sobrien 1224163503Sobrien 1225170589Syongaristatic int 1226170589Syongarinfe_init_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1227159967Sobrien{ 1228170589Syongari void *desc; 1229170589Syongari size_t descsize; 1230159967Sobrien int i; 1231159967Sobrien 1232170589Syongari ring->jcur = ring->jnext = 0; 1233170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1234170589Syongari desc = ring->jdesc64; 1235170589Syongari descsize = sizeof (struct nfe_desc64); 1236170589Syongari } else { 1237170589Syongari desc = ring->jdesc32; 1238170589Syongari descsize = sizeof (struct nfe_desc32); 1239159952Sobrien } 1240176859Syongari bzero(desc, descsize * NFE_JUMBO_RX_RING_COUNT); 1241170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1242170589Syongari if (nfe_jnewbuf(sc, i) != 0) 1243170589Syongari return (ENOBUFS); 1244170589Syongari } 1245159952Sobrien 1246170589Syongari bus_dmamap_sync(ring->jrx_desc_tag, ring->jrx_desc_map, 1247170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1248159952Sobrien 1249170589Syongari return (0); 1250159967Sobrien} 1251159967Sobrien 1252159967Sobrien 1253159967Sobrienstatic void 1254159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1255159967Sobrien{ 1256159967Sobrien struct nfe_rx_data *data; 1257159967Sobrien void *desc; 1258159967Sobrien int i, descsize; 1259159967Sobrien 1260159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1261159967Sobrien desc = ring->desc64; 1262159967Sobrien descsize = sizeof (struct nfe_desc64); 1263159967Sobrien } else { 1264159967Sobrien desc = ring->desc32; 1265159967Sobrien descsize = sizeof (struct nfe_desc32); 1266159952Sobrien } 1267159952Sobrien 1268170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1269170589Syongari data = &ring->data[i]; 1270170589Syongari if (data->rx_data_map != NULL) { 1271170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1272170589Syongari data->rx_data_map); 1273170589Syongari data->rx_data_map = NULL; 1274170589Syongari } 1275170589Syongari if (data->m != NULL) { 1276170589Syongari m_freem(data->m); 1277170589Syongari data->m = NULL; 1278170589Syongari } 1279170589Syongari } 1280170589Syongari if (ring->rx_data_tag != NULL) { 1281170589Syongari if (ring->rx_spare_map != NULL) { 1282170589Syongari bus_dmamap_destroy(ring->rx_data_tag, 1283170589Syongari ring->rx_spare_map); 1284170589Syongari ring->rx_spare_map = NULL; 1285170589Syongari } 1286170589Syongari bus_dma_tag_destroy(ring->rx_data_tag); 1287170589Syongari ring->rx_data_tag = NULL; 1288170589Syongari } 1289170589Syongari 1290159967Sobrien if (desc != NULL) { 1291159967Sobrien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 1292159967Sobrien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 1293170589Syongari ring->desc64 = NULL; 1294170589Syongari ring->desc32 = NULL; 1295170589Syongari ring->rx_desc_map = NULL; 1296170589Syongari } 1297170589Syongari if (ring->rx_desc_tag != NULL) { 1298159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 1299170589Syongari ring->rx_desc_tag = NULL; 1300159967Sobrien } 1301170589Syongari} 1302159967Sobrien 1303164650Sobrien 1304170589Syongaristatic void 1305170589Syongarinfe_free_jrx_ring(struct nfe_softc *sc, struct nfe_jrx_ring *ring) 1306170589Syongari{ 1307170589Syongari struct nfe_rx_data *data; 1308170589Syongari void *desc; 1309170589Syongari int i, descsize; 1310170589Syongari 1311170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) == 0) 1312170589Syongari return; 1313170589Syongari 1314170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1315170589Syongari desc = ring->jdesc64; 1316170589Syongari descsize = sizeof (struct nfe_desc64); 1317170589Syongari } else { 1318170589Syongari desc = ring->jdesc32; 1319170589Syongari descsize = sizeof (struct nfe_desc32); 1320170589Syongari } 1321170589Syongari 1322170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 1323170589Syongari data = &ring->jdata[i]; 1324164651Sobrien if (data->rx_data_map != NULL) { 1325170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1326164651Sobrien data->rx_data_map); 1327170589Syongari data->rx_data_map = NULL; 1328164651Sobrien } 1329170589Syongari if (data->m != NULL) { 1330164651Sobrien m_freem(data->m); 1331170589Syongari data->m = NULL; 1332170589Syongari } 1333164651Sobrien } 1334170589Syongari if (ring->jrx_data_tag != NULL) { 1335170589Syongari if (ring->jrx_spare_map != NULL) { 1336170589Syongari bus_dmamap_destroy(ring->jrx_data_tag, 1337170589Syongari ring->jrx_spare_map); 1338170589Syongari ring->jrx_spare_map = NULL; 1339170589Syongari } 1340170589Syongari bus_dma_tag_destroy(ring->jrx_data_tag); 1341170589Syongari ring->jrx_data_tag = NULL; 1342170589Syongari } 1343170589Syongari 1344170589Syongari if (desc != NULL) { 1345170589Syongari bus_dmamap_unload(ring->jrx_desc_tag, ring->jrx_desc_map); 1346170589Syongari bus_dmamem_free(ring->jrx_desc_tag, desc, ring->jrx_desc_map); 1347170589Syongari ring->jdesc64 = NULL; 1348170589Syongari ring->jdesc32 = NULL; 1349170589Syongari ring->jrx_desc_map = NULL; 1350170589Syongari } 1351176859Syongari 1352170589Syongari if (ring->jrx_desc_tag != NULL) { 1353170589Syongari bus_dma_tag_destroy(ring->jrx_desc_tag); 1354170589Syongari ring->jrx_desc_tag = NULL; 1355170589Syongari } 1356159952Sobrien} 1357159952Sobrien 1358163503Sobrien 1359159967Sobrienstatic int 1360159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1361159952Sobrien{ 1362170589Syongari struct nfe_dmamap_arg ctx; 1363159967Sobrien int i, error; 1364170589Syongari void *desc; 1365159967Sobrien int descsize; 1366159952Sobrien 1367159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1368170589Syongari desc = ring->desc64; 1369159967Sobrien descsize = sizeof (struct nfe_desc64); 1370159967Sobrien } else { 1371170589Syongari desc = ring->desc32; 1372159967Sobrien descsize = sizeof (struct nfe_desc32); 1373159967Sobrien } 1374159952Sobrien 1375159967Sobrien ring->queued = 0; 1376159967Sobrien ring->cur = ring->next = 0; 1377159967Sobrien 1378163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1379170589Syongari NFE_RING_ALIGN, 0, /* alignment, boundary */ 1380170589Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 1381170589Syongari BUS_SPACE_MAXADDR, /* highaddr */ 1382170589Syongari NULL, NULL, /* filter, filterarg */ 1383170589Syongari NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 1384170589Syongari NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 1385170589Syongari 0, /* flags */ 1386170589Syongari NULL, NULL, /* lockfunc, lockarg */ 1387170589Syongari &ring->tx_desc_tag); 1388159967Sobrien if (error != 0) { 1389170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA tag\n"); 1390159967Sobrien goto fail; 1391159952Sobrien } 1392159952Sobrien 1393170589Syongari error = bus_dmamem_alloc(ring->tx_desc_tag, &desc, BUS_DMA_WAITOK | 1394170589Syongari BUS_DMA_COHERENT | BUS_DMA_ZERO, &ring->tx_desc_map); 1395159967Sobrien if (error != 0) { 1396170589Syongari device_printf(sc->nfe_dev, "could not create desc DMA map\n"); 1397159967Sobrien goto fail; 1398159967Sobrien } 1399170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) 1400170589Syongari ring->desc64 = desc; 1401170589Syongari else 1402170589Syongari ring->desc32 = desc; 1403159967Sobrien 1404170589Syongari ctx.nfe_busaddr = 0; 1405170589Syongari error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, desc, 1406170589Syongari NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ctx, 0); 1407159967Sobrien if (error != 0) { 1408170589Syongari device_printf(sc->nfe_dev, "could not load desc DMA map\n"); 1409159967Sobrien goto fail; 1410159967Sobrien } 1411170589Syongari ring->physaddr = ctx.nfe_busaddr; 1412159967Sobrien 1413163503Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 1414170589Syongari 1, 0, 1415170589Syongari BUS_SPACE_MAXADDR, 1416170589Syongari BUS_SPACE_MAXADDR, 1417170589Syongari NULL, NULL, 1418170595Syongari NFE_TSO_MAXSIZE, 1419170589Syongari NFE_MAX_SCATTER, 1420170595Syongari NFE_TSO_MAXSGSIZE, 1421170589Syongari 0, 1422170589Syongari NULL, NULL, 1423170589Syongari &ring->tx_data_tag); 1424159967Sobrien if (error != 0) { 1425170589Syongari device_printf(sc->nfe_dev, "could not create Tx DMA tag\n"); 1426170589Syongari goto fail; 1427159967Sobrien } 1428159967Sobrien 1429159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1430163503Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, 1431163503Sobrien &ring->data[i].tx_data_map); 1432159967Sobrien if (error != 0) { 1433170589Syongari device_printf(sc->nfe_dev, 1434170589Syongari "could not create Tx DMA map\n"); 1435159967Sobrien goto fail; 1436159967Sobrien } 1437159967Sobrien } 1438159967Sobrien 1439170589Syongarifail: 1440170589Syongari return (error); 1441159967Sobrien} 1442159967Sobrien 1443159967Sobrien 1444159967Sobrienstatic void 1445170589Syongarinfe_init_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1446159967Sobrien{ 1447170589Syongari void *desc; 1448170589Syongari size_t descsize; 1449159967Sobrien 1450170589Syongari sc->nfe_force_tx = 0; 1451170589Syongari ring->queued = 0; 1452170589Syongari ring->cur = ring->next = 0; 1453170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1454170589Syongari desc = ring->desc64; 1455170589Syongari descsize = sizeof (struct nfe_desc64); 1456170589Syongari } else { 1457170589Syongari desc = ring->desc32; 1458170589Syongari descsize = sizeof (struct nfe_desc32); 1459159967Sobrien } 1460170589Syongari bzero(desc, descsize * NFE_TX_RING_COUNT); 1461159967Sobrien 1462163503Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1463170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1464159967Sobrien} 1465159967Sobrien 1466163503Sobrien 1467159967Sobrienstatic void 1468159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1469159967Sobrien{ 1470159967Sobrien struct nfe_tx_data *data; 1471159967Sobrien void *desc; 1472159967Sobrien int i, descsize; 1473159967Sobrien 1474159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1475159967Sobrien desc = ring->desc64; 1476159967Sobrien descsize = sizeof (struct nfe_desc64); 1477159967Sobrien } else { 1478159967Sobrien desc = ring->desc32; 1479159967Sobrien descsize = sizeof (struct nfe_desc32); 1480159967Sobrien } 1481159967Sobrien 1482159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1483159967Sobrien data = &ring->data[i]; 1484159967Sobrien 1485159967Sobrien if (data->m != NULL) { 1486170589Syongari bus_dmamap_sync(ring->tx_data_tag, data->tx_data_map, 1487163503Sobrien BUS_DMASYNC_POSTWRITE); 1488170589Syongari bus_dmamap_unload(ring->tx_data_tag, data->tx_data_map); 1489159967Sobrien m_freem(data->m); 1490170589Syongari data->m = NULL; 1491159967Sobrien } 1492170589Syongari if (data->tx_data_map != NULL) { 1493170589Syongari bus_dmamap_destroy(ring->tx_data_tag, 1494170589Syongari data->tx_data_map); 1495170589Syongari data->tx_data_map = NULL; 1496170589Syongari } 1497159967Sobrien } 1498159967Sobrien 1499170589Syongari if (ring->tx_data_tag != NULL) { 1500170589Syongari bus_dma_tag_destroy(ring->tx_data_tag); 1501170589Syongari ring->tx_data_tag = NULL; 1502159967Sobrien } 1503159967Sobrien 1504170589Syongari if (desc != NULL) { 1505170589Syongari bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, 1506170589Syongari BUS_DMASYNC_POSTWRITE); 1507170589Syongari bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1508170589Syongari bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1509170589Syongari ring->desc64 = NULL; 1510170589Syongari ring->desc32 = NULL; 1511170589Syongari ring->tx_desc_map = NULL; 1512170589Syongari bus_dma_tag_destroy(ring->tx_desc_tag); 1513170589Syongari ring->tx_desc_tag = NULL; 1514170589Syongari } 1515159967Sobrien} 1516159967Sobrien 1517159967Sobrien#ifdef DEVICE_POLLING 1518159967Sobrienstatic poll_handler_t nfe_poll; 1519159967Sobrien 1520163503Sobrien 1521159967Sobrienstatic void 1522159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1523159967Sobrien{ 1524164360Sobrien struct nfe_softc *sc = ifp->if_softc; 1525170589Syongari uint32_t r; 1526159967Sobrien 1527159967Sobrien NFE_LOCK(sc); 1528159967Sobrien 1529159967Sobrien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1530170589Syongari NFE_UNLOCK(sc); 1531159967Sobrien return; 1532159967Sobrien } 1533159967Sobrien 1534171559Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1535171559Syongari nfe_jrxeof(sc, count); 1536171559Syongari else 1537171559Syongari nfe_rxeof(sc, count); 1538159967Sobrien nfe_txeof(sc); 1539159967Sobrien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1540173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task); 1541159967Sobrien 1542159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1543170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1544170589Syongari NFE_UNLOCK(sc); 1545163503Sobrien return; 1546163503Sobrien } 1547170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1548159967Sobrien 1549163503Sobrien if (r & NFE_IRQ_LINK) { 1550163503Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1551163503Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1552170589Syongari DPRINTF(sc, "link state changed\n"); 1553163503Sobrien } 1554159967Sobrien } 1555170589Syongari NFE_UNLOCK(sc); 1556159967Sobrien} 1557159967Sobrien#endif /* DEVICE_POLLING */ 1558159967Sobrien 1559170589Syongaristatic void 1560170589Syongarinfe_set_intr(struct nfe_softc *sc) 1561170589Syongari{ 1562159967Sobrien 1563170589Syongari if (sc->nfe_msi != 0) 1564170589Syongari NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1565170589Syongari} 1566170589Syongari 1567170589Syongari 1568170589Syongari/* In MSIX, a write to mask reegisters behaves as XOR. */ 1569170589Syongaristatic __inline void 1570170589Syongarinfe_enable_intr(struct nfe_softc *sc) 1571170589Syongari{ 1572170589Syongari 1573170589Syongari if (sc->nfe_msix != 0) { 1574170589Syongari /* XXX Should have a better way to enable interrupts! */ 1575170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) == 0) 1576170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1577170589Syongari } else 1578170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_intrs); 1579170589Syongari} 1580170589Syongari 1581170589Syongari 1582170589Syongaristatic __inline void 1583170589Syongarinfe_disable_intr(struct nfe_softc *sc) 1584170589Syongari{ 1585170589Syongari 1586170589Syongari if (sc->nfe_msix != 0) { 1587170589Syongari /* XXX Should have a better way to disable interrupts! */ 1588170589Syongari if (NFE_READ(sc, sc->nfe_irq_mask) != 0) 1589170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1590170589Syongari } else 1591170589Syongari NFE_WRITE(sc, sc->nfe_irq_mask, sc->nfe_nointrs); 1592170589Syongari} 1593170589Syongari 1594170589Syongari 1595159967Sobrienstatic int 1596159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1597159967Sobrien{ 1598170589Syongari struct nfe_softc *sc; 1599170589Syongari struct ifreq *ifr; 1600163503Sobrien struct mii_data *mii; 1601170589Syongari int error, init, mask; 1602159967Sobrien 1603170589Syongari sc = ifp->if_softc; 1604170589Syongari ifr = (struct ifreq *) data; 1605170589Syongari error = 0; 1606170589Syongari init = 0; 1607159952Sobrien switch (cmd) { 1608159952Sobrien case SIOCSIFMTU: 1609170589Syongari if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > NFE_JUMBO_MTU) 1610159952Sobrien error = EINVAL; 1611170589Syongari else if (ifp->if_mtu != ifr->ifr_mtu) { 1612171559Syongari if ((((sc->nfe_flags & NFE_JUMBO_SUP) == 0) || 1613171559Syongari (sc->nfe_jumbo_disable != 0)) && 1614170589Syongari ifr->ifr_mtu > ETHERMTU) 1615170589Syongari error = EINVAL; 1616170589Syongari else { 1617170589Syongari NFE_LOCK(sc); 1618170589Syongari ifp->if_mtu = ifr->ifr_mtu; 1619170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1620170589Syongari nfe_init_locked(sc); 1621170589Syongari NFE_UNLOCK(sc); 1622164650Sobrien } 1623164650Sobrien } 1624159952Sobrien break; 1625159952Sobrien case SIOCSIFFLAGS: 1626159967Sobrien NFE_LOCK(sc); 1627159952Sobrien if (ifp->if_flags & IFF_UP) { 1628159952Sobrien /* 1629159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1630159952Sobrien * don't do a full re-init of the chip, just update 1631159952Sobrien * the Rx filter. 1632159952Sobrien */ 1633159967Sobrien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1634159967Sobrien ((ifp->if_flags ^ sc->nfe_if_flags) & 1635159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1636159952Sobrien nfe_setmulti(sc); 1637159967Sobrien else 1638159967Sobrien nfe_init_locked(sc); 1639159952Sobrien } else { 1640159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1641170589Syongari nfe_stop(ifp); 1642159952Sobrien } 1643159967Sobrien sc->nfe_if_flags = ifp->if_flags; 1644159967Sobrien NFE_UNLOCK(sc); 1645159967Sobrien error = 0; 1646159952Sobrien break; 1647159952Sobrien case SIOCADDMULTI: 1648159952Sobrien case SIOCDELMULTI: 1649170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1650159967Sobrien NFE_LOCK(sc); 1651159967Sobrien nfe_setmulti(sc); 1652159967Sobrien NFE_UNLOCK(sc); 1653159952Sobrien error = 0; 1654159952Sobrien } 1655159952Sobrien break; 1656159952Sobrien case SIOCSIFMEDIA: 1657159952Sobrien case SIOCGIFMEDIA: 1658159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1659159967Sobrien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1660159952Sobrien break; 1661159967Sobrien case SIOCSIFCAP: 1662170589Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1663159967Sobrien#ifdef DEVICE_POLLING 1664170589Syongari if ((mask & IFCAP_POLLING) != 0) { 1665170589Syongari if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { 1666159967Sobrien error = ether_poll_register(nfe_poll, ifp); 1667159967Sobrien if (error) 1668170589Syongari break; 1669159967Sobrien NFE_LOCK(sc); 1670170589Syongari nfe_disable_intr(sc); 1671163503Sobrien ifp->if_capenable |= IFCAP_POLLING; 1672159967Sobrien NFE_UNLOCK(sc); 1673159967Sobrien } else { 1674159967Sobrien error = ether_poll_deregister(ifp); 1675159967Sobrien /* Enable interrupt even in error case */ 1676159967Sobrien NFE_LOCK(sc); 1677170589Syongari nfe_enable_intr(sc); 1678159967Sobrien ifp->if_capenable &= ~IFCAP_POLLING; 1679159967Sobrien NFE_UNLOCK(sc); 1680159967Sobrien } 1681159967Sobrien } 1682163503Sobrien#endif /* DEVICE_POLLING */ 1683170589Syongari if ((sc->nfe_flags & NFE_HW_CSUM) != 0 && 1684170589Syongari (mask & IFCAP_HWCSUM) != 0) { 1685159967Sobrien ifp->if_capenable ^= IFCAP_HWCSUM; 1686170589Syongari if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 && 1687170589Syongari (IFCAP_TXCSUM & ifp->if_capabilities) != 0) 1688170589Syongari ifp->if_hwassist |= NFE_CSUM_FEATURES; 1689159967Sobrien else 1690170589Syongari ifp->if_hwassist &= ~NFE_CSUM_FEATURES; 1691170589Syongari init++; 1692159967Sobrien } 1693170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0 && 1694170589Syongari (mask & IFCAP_VLAN_HWTAGGING) != 0) { 1695170589Syongari ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1696170589Syongari init++; 1697170589Syongari } 1698170589Syongari /* 1699170589Syongari * XXX 1700170589Syongari * It seems that VLAN stripping requires Rx checksum offload. 1701170589Syongari * Unfortunately FreeBSD has no way to disable only Rx side 1702170589Syongari * VLAN stripping. So when we know Rx checksum offload is 1703170589Syongari * disabled turn entire hardware VLAN assist off. 1704170589Syongari */ 1705170589Syongari if ((sc->nfe_flags & (NFE_HW_CSUM | NFE_HW_VLAN)) == 1706170589Syongari (NFE_HW_CSUM | NFE_HW_VLAN)) { 1707170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) == 0) 1708170589Syongari ifp->if_capenable &= ~IFCAP_VLAN_HWTAGGING; 1709170589Syongari } 1710170589Syongari 1711170589Syongari if ((sc->nfe_flags & NFE_HW_CSUM) != 0 && 1712170589Syongari (mask & IFCAP_TSO4) != 0) { 1713170589Syongari ifp->if_capenable ^= IFCAP_TSO4; 1714170589Syongari if ((IFCAP_TSO4 & ifp->if_capenable) != 0 && 1715170589Syongari (IFCAP_TSO4 & ifp->if_capabilities) != 0) 1716170589Syongari ifp->if_hwassist |= CSUM_TSO; 1717170589Syongari else 1718170589Syongari ifp->if_hwassist &= ~CSUM_TSO; 1719170589Syongari } 1720170589Syongari 1721170589Syongari if (init > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1722170589Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1723164656Sobrien nfe_init(sc); 1724170589Syongari } 1725170589Syongari if ((sc->nfe_flags & NFE_HW_VLAN) != 0) 1726170589Syongari VLAN_CAPABILITIES(ifp); 1727159967Sobrien break; 1728159952Sobrien default: 1729159967Sobrien error = ether_ioctl(ifp, cmd, data); 1730159967Sobrien break; 1731159952Sobrien } 1732159952Sobrien 1733170589Syongari return (error); 1734159952Sobrien} 1735159952Sobrien 1736159967Sobrien 1737170589Syongaristatic int 1738163503Sobriennfe_intr(void *arg) 1739159967Sobrien{ 1740170589Syongari struct nfe_softc *sc; 1741170589Syongari uint32_t status; 1742170589Syongari 1743170589Syongari sc = (struct nfe_softc *)arg; 1744170589Syongari 1745170589Syongari status = NFE_READ(sc, sc->nfe_irq_status); 1746170589Syongari if (status == 0 || status == 0xffffffff) 1747170589Syongari return (FILTER_STRAY); 1748170589Syongari nfe_disable_intr(sc); 1749173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1750170589Syongari 1751170589Syongari return (FILTER_HANDLED); 1752170589Syongari} 1753170589Syongari 1754170589Syongari 1755170589Syongaristatic void 1756170589Syongarinfe_int_task(void *arg, int pending) 1757170589Syongari{ 1758159967Sobrien struct nfe_softc *sc = arg; 1759159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1760170589Syongari uint32_t r; 1761170589Syongari int domore; 1762159967Sobrien 1763163503Sobrien NFE_LOCK(sc); 1764159967Sobrien 1765170589Syongari if ((r = NFE_READ(sc, sc->nfe_irq_status)) == 0) { 1766170589Syongari nfe_enable_intr(sc); 1767170589Syongari NFE_UNLOCK(sc); 1768170589Syongari return; /* not for us */ 1769170589Syongari } 1770170589Syongari NFE_WRITE(sc, sc->nfe_irq_status, r); 1771170589Syongari 1772170589Syongari DPRINTFN(sc, 5, "nfe_intr: interrupt register %x\n", r); 1773170589Syongari 1774159967Sobrien#ifdef DEVICE_POLLING 1775159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) { 1776159967Sobrien NFE_UNLOCK(sc); 1777159967Sobrien return; 1778159967Sobrien } 1779159967Sobrien#endif 1780159967Sobrien 1781172169Syongari if (r & NFE_IRQ_LINK) { 1782172169Syongari NFE_READ(sc, NFE_PHY_STATUS); 1783172169Syongari NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1784172169Syongari DPRINTF(sc, "link state changed\n"); 1785172169Syongari } 1786172169Syongari 1787170589Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1788163503Sobrien NFE_UNLOCK(sc); 1789170589Syongari nfe_enable_intr(sc); 1790170589Syongari return; 1791159967Sobrien } 1792159967Sobrien 1793170589Syongari domore = 0; 1794170589Syongari /* check Rx ring */ 1795170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) 1796170589Syongari domore = nfe_jrxeof(sc, sc->nfe_process_limit); 1797170589Syongari else 1798170589Syongari domore = nfe_rxeof(sc, sc->nfe_process_limit); 1799170589Syongari /* check Tx ring */ 1800170589Syongari nfe_txeof(sc); 1801159967Sobrien 1802170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1803173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task); 1804159967Sobrien 1805159967Sobrien NFE_UNLOCK(sc); 1806159967Sobrien 1807170589Syongari if (domore || (NFE_READ(sc, sc->nfe_irq_status) != 0)) { 1808173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_int_task); 1809170589Syongari return; 1810170589Syongari } 1811170589Syongari 1812170589Syongari /* Reenable interrupts. */ 1813170589Syongari nfe_enable_intr(sc); 1814159967Sobrien} 1815159967Sobrien 1816163503Sobrien 1817170589Syongaristatic __inline void 1818170589Syongarinfe_discard_rxbuf(struct nfe_softc *sc, int idx) 1819159952Sobrien{ 1820170589Syongari struct nfe_desc32 *desc32; 1821170589Syongari struct nfe_desc64 *desc64; 1822170589Syongari struct nfe_rx_data *data; 1823170589Syongari struct mbuf *m; 1824163503Sobrien 1825170589Syongari data = &sc->rxq.data[idx]; 1826170589Syongari m = data->m; 1827170589Syongari 1828170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1829170589Syongari desc64 = &sc->rxq.desc64[idx]; 1830170589Syongari /* VLAN packet may have overwritten it. */ 1831170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1832170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1833170589Syongari desc64->length = htole16(m->m_len); 1834170589Syongari desc64->flags = htole16(NFE_RX_READY); 1835170589Syongari } else { 1836170589Syongari desc32 = &sc->rxq.desc32[idx]; 1837170589Syongari desc32->length = htole16(m->m_len); 1838170589Syongari desc32->flags = htole16(NFE_RX_READY); 1839170589Syongari } 1840159952Sobrien} 1841159952Sobrien 1842163503Sobrien 1843170589Syongaristatic __inline void 1844170589Syongarinfe_discard_jrxbuf(struct nfe_softc *sc, int idx) 1845159952Sobrien{ 1846170589Syongari struct nfe_desc32 *desc32; 1847170589Syongari struct nfe_desc64 *desc64; 1848170589Syongari struct nfe_rx_data *data; 1849170589Syongari struct mbuf *m; 1850163503Sobrien 1851170589Syongari data = &sc->jrxq.jdata[idx]; 1852170589Syongari m = data->m; 1853170589Syongari 1854170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1855170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 1856170589Syongari /* VLAN packet may have overwritten it. */ 1857170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(data->paddr)); 1858170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(data->paddr)); 1859170589Syongari desc64->length = htole16(m->m_len); 1860170589Syongari desc64->flags = htole16(NFE_RX_READY); 1861170589Syongari } else { 1862170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 1863170589Syongari desc32->length = htole16(m->m_len); 1864170589Syongari desc32->flags = htole16(NFE_RX_READY); 1865170589Syongari } 1866159952Sobrien} 1867159952Sobrien 1868163503Sobrien 1869170589Syongaristatic int 1870170589Syongarinfe_newbuf(struct nfe_softc *sc, int idx) 1871159952Sobrien{ 1872170589Syongari struct nfe_rx_data *data; 1873170589Syongari struct nfe_desc32 *desc32; 1874170589Syongari struct nfe_desc64 *desc64; 1875170589Syongari struct mbuf *m; 1876170589Syongari bus_dma_segment_t segs[1]; 1877170589Syongari bus_dmamap_t map; 1878170589Syongari int nsegs; 1879163503Sobrien 1880170589Syongari m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1881170589Syongari if (m == NULL) 1882170589Syongari return (ENOBUFS); 1883159952Sobrien 1884170589Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 1885170589Syongari m_adj(m, ETHER_ALIGN); 1886163503Sobrien 1887170589Syongari if (bus_dmamap_load_mbuf_sg(sc->rxq.rx_data_tag, sc->rxq.rx_spare_map, 1888170589Syongari m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 1889170589Syongari m_freem(m); 1890170589Syongari return (ENOBUFS); 1891170589Syongari } 1892170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1893163503Sobrien 1894170589Syongari data = &sc->rxq.data[idx]; 1895170589Syongari if (data->m != NULL) { 1896170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 1897170589Syongari BUS_DMASYNC_POSTREAD); 1898170589Syongari bus_dmamap_unload(sc->rxq.rx_data_tag, data->rx_data_map); 1899170589Syongari } 1900170589Syongari map = data->rx_data_map; 1901170589Syongari data->rx_data_map = sc->rxq.rx_spare_map; 1902170589Syongari sc->rxq.rx_spare_map = map; 1903170589Syongari bus_dmamap_sync(sc->rxq.rx_data_tag, data->rx_data_map, 1904170589Syongari BUS_DMASYNC_PREREAD); 1905170589Syongari data->paddr = segs[0].ds_addr; 1906170589Syongari data->m = m; 1907170589Syongari /* update mapping address in h/w descriptor */ 1908170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1909170589Syongari desc64 = &sc->rxq.desc64[idx]; 1910170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 1911170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 1912170589Syongari desc64->length = htole16(segs[0].ds_len); 1913170589Syongari desc64->flags = htole16(NFE_RX_READY); 1914170589Syongari } else { 1915170589Syongari desc32 = &sc->rxq.desc32[idx]; 1916170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 1917170589Syongari desc32->length = htole16(segs[0].ds_len); 1918170589Syongari desc32->flags = htole16(NFE_RX_READY); 1919170589Syongari } 1920170589Syongari 1921170589Syongari return (0); 1922159952Sobrien} 1923159952Sobrien 1924163503Sobrien 1925170589Syongaristatic int 1926170589Syongarinfe_jnewbuf(struct nfe_softc *sc, int idx) 1927159952Sobrien{ 1928170589Syongari struct nfe_rx_data *data; 1929170589Syongari struct nfe_desc32 *desc32; 1930170589Syongari struct nfe_desc64 *desc64; 1931170589Syongari struct mbuf *m; 1932170589Syongari bus_dma_segment_t segs[1]; 1933170589Syongari bus_dmamap_t map; 1934170589Syongari int nsegs; 1935163503Sobrien 1936176859Syongari m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 1937170589Syongari if (m == NULL) 1938170589Syongari return (ENOBUFS); 1939170589Syongari if ((m->m_flags & M_EXT) == 0) { 1940170589Syongari m_freem(m); 1941170589Syongari return (ENOBUFS); 1942170589Syongari } 1943176859Syongari m->m_pkthdr.len = m->m_len = MJUM9BYTES; 1944170589Syongari m_adj(m, ETHER_ALIGN); 1945159952Sobrien 1946170589Syongari if (bus_dmamap_load_mbuf_sg(sc->jrxq.jrx_data_tag, 1947170589Syongari sc->jrxq.jrx_spare_map, m, segs, &nsegs, BUS_DMA_NOWAIT) != 0) { 1948170589Syongari m_freem(m); 1949170589Syongari return (ENOBUFS); 1950170589Syongari } 1951170589Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1952163503Sobrien 1953170589Syongari data = &sc->jrxq.jdata[idx]; 1954170589Syongari if (data->m != NULL) { 1955170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 1956170589Syongari BUS_DMASYNC_POSTREAD); 1957170589Syongari bus_dmamap_unload(sc->jrxq.jrx_data_tag, data->rx_data_map); 1958170589Syongari } 1959170589Syongari map = data->rx_data_map; 1960170589Syongari data->rx_data_map = sc->jrxq.jrx_spare_map; 1961170589Syongari sc->jrxq.jrx_spare_map = map; 1962170589Syongari bus_dmamap_sync(sc->jrxq.jrx_data_tag, data->rx_data_map, 1963170589Syongari BUS_DMASYNC_PREREAD); 1964170589Syongari data->paddr = segs[0].ds_addr; 1965170589Syongari data->m = m; 1966170589Syongari /* update mapping address in h/w descriptor */ 1967170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 1968170589Syongari desc64 = &sc->jrxq.jdesc64[idx]; 1969170589Syongari desc64->physaddr[0] = htole32(NFE_ADDR_HI(segs[0].ds_addr)); 1970170589Syongari desc64->physaddr[1] = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 1971170589Syongari desc64->length = htole16(segs[0].ds_len); 1972170589Syongari desc64->flags = htole16(NFE_RX_READY); 1973170589Syongari } else { 1974170589Syongari desc32 = &sc->jrxq.jdesc32[idx]; 1975170589Syongari desc32->physaddr = htole32(NFE_ADDR_LO(segs[0].ds_addr)); 1976170589Syongari desc32->length = htole16(segs[0].ds_len); 1977170589Syongari desc32->flags = htole16(NFE_RX_READY); 1978170589Syongari } 1979159967Sobrien 1980170589Syongari return (0); 1981159952Sobrien} 1982159952Sobrien 1983163503Sobrien 1984170589Syongaristatic int 1985170589Syongarinfe_rxeof(struct nfe_softc *sc, int count) 1986159952Sobrien{ 1987159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1988170589Syongari struct nfe_desc32 *desc32; 1989170589Syongari struct nfe_desc64 *desc64; 1990159952Sobrien struct nfe_rx_data *data; 1991170589Syongari struct mbuf *m; 1992170589Syongari uint16_t flags; 1993170589Syongari int len, prog; 1994170589Syongari uint32_t vtag = 0; 1995159952Sobrien 1996159967Sobrien NFE_LOCK_ASSERT(sc); 1997159967Sobrien 1998170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 1999170589Syongari BUS_DMASYNC_POSTREAD); 2000159967Sobrien 2001170589Syongari for (prog = 0;;NFE_INC(sc->rxq.cur, NFE_RX_RING_COUNT), vtag = 0) { 2002170589Syongari if (count <= 0) 2003170589Syongari break; 2004170589Syongari count--; 2005159967Sobrien 2006159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 2007159952Sobrien 2008159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2009159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 2010170589Syongari vtag = le32toh(desc64->physaddr[1]); 2011170589Syongari flags = le16toh(desc64->flags); 2012170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2013159952Sobrien } else { 2014159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 2015170589Syongari flags = le16toh(desc32->flags); 2016170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2017159952Sobrien } 2018159952Sobrien 2019159952Sobrien if (flags & NFE_RX_READY) 2020159952Sobrien break; 2021170589Syongari prog++; 2022159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2023170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2024170589Syongari ifp->if_ierrors++; 2025170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2026170589Syongari continue; 2027170589Syongari } 2028159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2029159952Sobrien flags &= ~NFE_RX_ERROR; 2030159952Sobrien len--; /* fix buffer length */ 2031159952Sobrien } 2032159952Sobrien } else { 2033170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2034170589Syongari ifp->if_ierrors++; 2035170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2036170589Syongari continue; 2037170589Syongari } 2038159952Sobrien 2039159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2040159952Sobrien flags &= ~NFE_RX_ERROR; 2041159952Sobrien len--; /* fix buffer length */ 2042159952Sobrien } 2043159952Sobrien } 2044159952Sobrien 2045159952Sobrien if (flags & NFE_RX_ERROR) { 2046159952Sobrien ifp->if_ierrors++; 2047170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2048170589Syongari continue; 2049159952Sobrien } 2050159952Sobrien 2051170589Syongari m = data->m; 2052170589Syongari if (nfe_newbuf(sc, sc->rxq.cur) != 0) { 2053170589Syongari ifp->if_iqdrops++; 2054170589Syongari nfe_discard_rxbuf(sc, sc->rxq.cur); 2055170589Syongari continue; 2056159952Sobrien } 2057159952Sobrien 2058170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2059170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2060170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2061170589Syongari m->m_flags |= M_VLANTAG; 2062164651Sobrien } 2063159952Sobrien 2064170589Syongari m->m_pkthdr.len = m->m_len = len; 2065170589Syongari m->m_pkthdr.rcvif = ifp; 2066164651Sobrien 2067170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2068170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2069170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2070170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2071170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2072170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2073170589Syongari m->m_pkthdr.csum_flags |= 2074170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2075170589Syongari m->m_pkthdr.csum_data = 0xffff; 2076170589Syongari } 2077159952Sobrien } 2078170589Syongari } 2079170589Syongari 2080170589Syongari ifp->if_ipackets++; 2081170589Syongari 2082170589Syongari NFE_UNLOCK(sc); 2083170589Syongari (*ifp->if_input)(ifp, m); 2084170589Syongari NFE_LOCK(sc); 2085170589Syongari } 2086170589Syongari 2087170589Syongari if (prog > 0) 2088170589Syongari bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, 2089170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2090170589Syongari 2091170589Syongari return (count > 0 ? 0 : EAGAIN); 2092170589Syongari} 2093170589Syongari 2094170589Syongari 2095170589Syongaristatic int 2096170589Syongarinfe_jrxeof(struct nfe_softc *sc, int count) 2097170589Syongari{ 2098170589Syongari struct ifnet *ifp = sc->nfe_ifp; 2099170589Syongari struct nfe_desc32 *desc32; 2100170589Syongari struct nfe_desc64 *desc64; 2101170589Syongari struct nfe_rx_data *data; 2102170589Syongari struct mbuf *m; 2103170589Syongari uint16_t flags; 2104170589Syongari int len, prog; 2105170589Syongari uint32_t vtag = 0; 2106170589Syongari 2107170589Syongari NFE_LOCK_ASSERT(sc); 2108170589Syongari 2109170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2110170589Syongari BUS_DMASYNC_POSTREAD); 2111170589Syongari 2112170589Syongari for (prog = 0;;NFE_INC(sc->jrxq.jcur, NFE_JUMBO_RX_RING_COUNT), 2113170589Syongari vtag = 0) { 2114170589Syongari if (count <= 0) 2115170589Syongari break; 2116170589Syongari count--; 2117170589Syongari 2118170589Syongari data = &sc->jrxq.jdata[sc->jrxq.jcur]; 2119170589Syongari 2120170589Syongari if (sc->nfe_flags & NFE_40BIT_ADDR) { 2121170589Syongari desc64 = &sc->jrxq.jdesc64[sc->jrxq.jcur]; 2122170589Syongari vtag = le32toh(desc64->physaddr[1]); 2123170589Syongari flags = le16toh(desc64->flags); 2124170589Syongari len = le16toh(desc64->length) & NFE_RX_LEN_MASK; 2125170589Syongari } else { 2126170589Syongari desc32 = &sc->jrxq.jdesc32[sc->jrxq.jcur]; 2127170589Syongari flags = le16toh(desc32->flags); 2128170589Syongari len = le16toh(desc32->length) & NFE_RX_LEN_MASK; 2129170589Syongari } 2130170589Syongari 2131170589Syongari if (flags & NFE_RX_READY) 2132170589Syongari break; 2133170589Syongari prog++; 2134170589Syongari if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2135170589Syongari if (!(flags & NFE_RX_VALID_V1)) { 2136170589Syongari ifp->if_ierrors++; 2137170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2138170589Syongari continue; 2139170589Syongari } 2140170589Syongari if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 2141170589Syongari flags &= ~NFE_RX_ERROR; 2142170589Syongari len--; /* fix buffer length */ 2143170589Syongari } 2144170589Syongari } else { 2145170589Syongari if (!(flags & NFE_RX_VALID_V2)) { 2146170589Syongari ifp->if_ierrors++; 2147170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2148170589Syongari continue; 2149170589Syongari } 2150170589Syongari 2151170589Syongari if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 2152170589Syongari flags &= ~NFE_RX_ERROR; 2153170589Syongari len--; /* fix buffer length */ 2154170589Syongari } 2155170589Syongari } 2156170589Syongari 2157170589Syongari if (flags & NFE_RX_ERROR) { 2158164651Sobrien ifp->if_ierrors++; 2159170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2160170589Syongari continue; 2161164651Sobrien } 2162159952Sobrien 2163159952Sobrien m = data->m; 2164170589Syongari if (nfe_jnewbuf(sc, sc->jrxq.jcur) != 0) { 2165170589Syongari ifp->if_iqdrops++; 2166170589Syongari nfe_discard_jrxbuf(sc, sc->jrxq.jcur); 2167170589Syongari continue; 2168170589Syongari } 2169159952Sobrien 2170170589Syongari if ((vtag & NFE_RX_VTAG) != 0 && 2171170589Syongari (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 2172170589Syongari m->m_pkthdr.ether_vtag = vtag & 0xffff; 2173170589Syongari m->m_flags |= M_VLANTAG; 2174170589Syongari } 2175170589Syongari 2176159952Sobrien m->m_pkthdr.len = m->m_len = len; 2177159952Sobrien m->m_pkthdr.rcvif = ifp; 2178159952Sobrien 2179170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 2180170589Syongari if ((flags & NFE_RX_IP_CSUMOK) != 0) { 2181170589Syongari m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 2182159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 2183170589Syongari if ((flags & NFE_RX_TCP_CSUMOK) != 0 || 2184170589Syongari (flags & NFE_RX_UDP_CSUMOK) != 0) { 2185170589Syongari m->m_pkthdr.csum_flags |= 2186170589Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 2187170589Syongari m->m_pkthdr.csum_data = 0xffff; 2188170589Syongari } 2189159967Sobrien } 2190159952Sobrien } 2191159952Sobrien 2192159952Sobrien ifp->if_ipackets++; 2193159952Sobrien 2194159967Sobrien NFE_UNLOCK(sc); 2195159967Sobrien (*ifp->if_input)(ifp, m); 2196159967Sobrien NFE_LOCK(sc); 2197170589Syongari } 2198159967Sobrien 2199170589Syongari if (prog > 0) 2200170589Syongari bus_dmamap_sync(sc->jrxq.jrx_desc_tag, sc->jrxq.jrx_desc_map, 2201170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2202159952Sobrien 2203170589Syongari return (count > 0 ? 0 : EAGAIN); 2204159952Sobrien} 2205159952Sobrien 2206163503Sobrien 2207163503Sobrienstatic void 2208163503Sobriennfe_txeof(struct nfe_softc *sc) 2209159952Sobrien{ 2210159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2211159952Sobrien struct nfe_desc32 *desc32; 2212159952Sobrien struct nfe_desc64 *desc64; 2213159952Sobrien struct nfe_tx_data *data = NULL; 2214170589Syongari uint16_t flags; 2215170589Syongari int cons, prog; 2216159952Sobrien 2217159967Sobrien NFE_LOCK_ASSERT(sc); 2218159967Sobrien 2219170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2220170589Syongari BUS_DMASYNC_POSTREAD); 2221170589Syongari 2222170589Syongari prog = 0; 2223170589Syongari for (cons = sc->txq.next; cons != sc->txq.cur; 2224170589Syongari NFE_INC(cons, NFE_TX_RING_COUNT)) { 2225159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2226170589Syongari desc64 = &sc->txq.desc64[cons]; 2227170589Syongari flags = le16toh(desc64->flags); 2228159952Sobrien } else { 2229170589Syongari desc32 = &sc->txq.desc32[cons]; 2230170589Syongari flags = le16toh(desc32->flags); 2231159952Sobrien } 2232159952Sobrien 2233159952Sobrien if (flags & NFE_TX_VALID) 2234159952Sobrien break; 2235159952Sobrien 2236170589Syongari prog++; 2237170589Syongari sc->txq.queued--; 2238170589Syongari data = &sc->txq.data[cons]; 2239159952Sobrien 2240159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 2241170589Syongari if ((flags & NFE_TX_LASTFRAG_V1) == 0) 2242170589Syongari continue; 2243159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 2244170589Syongari device_printf(sc->nfe_dev, 2245170589Syongari "tx v1 error 0x%4b\n", flags, NFE_V1_TXERR); 2246159967Sobrien 2247159952Sobrien ifp->if_oerrors++; 2248159952Sobrien } else 2249159952Sobrien ifp->if_opackets++; 2250159952Sobrien } else { 2251170589Syongari if ((flags & NFE_TX_LASTFRAG_V2) == 0) 2252170589Syongari continue; 2253159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 2254170589Syongari device_printf(sc->nfe_dev, 2255170589Syongari "tx v2 error 0x%4b\n", flags, NFE_V2_TXERR); 2256159952Sobrien ifp->if_oerrors++; 2257159952Sobrien } else 2258159952Sobrien ifp->if_opackets++; 2259159952Sobrien } 2260159952Sobrien 2261159952Sobrien /* last fragment of the mbuf chain transmitted */ 2262170589Syongari KASSERT(data->m != NULL, ("%s: freeing NULL mbuf!", __func__)); 2263170589Syongari bus_dmamap_sync(sc->txq.tx_data_tag, data->tx_data_map, 2264159967Sobrien BUS_DMASYNC_POSTWRITE); 2265170589Syongari bus_dmamap_unload(sc->txq.tx_data_tag, data->tx_data_map); 2266159952Sobrien m_freem(data->m); 2267159952Sobrien data->m = NULL; 2268159952Sobrien } 2269159952Sobrien 2270170589Syongari if (prog > 0) { 2271170589Syongari sc->nfe_force_tx = 0; 2272170589Syongari sc->txq.next = cons; 2273159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2274170589Syongari if (sc->txq.queued == 0) 2275170589Syongari sc->nfe_watchdog_timer = 0; 2276159952Sobrien } 2277159952Sobrien} 2278159952Sobrien 2279163503Sobrienstatic int 2280170589Syongarinfe_encap(struct nfe_softc *sc, struct mbuf **m_head) 2281159952Sobrien{ 2282170589Syongari struct nfe_desc32 *desc32 = NULL; 2283170589Syongari struct nfe_desc64 *desc64 = NULL; 2284159952Sobrien bus_dmamap_t map; 2285163503Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 2286170589Syongari int error, i, nsegs, prod, si; 2287170589Syongari uint32_t tso_segsz; 2288170589Syongari uint16_t cflags, flags; 2289170589Syongari struct mbuf *m; 2290159952Sobrien 2291170589Syongari prod = si = sc->txq.cur; 2292170589Syongari map = sc->txq.data[prod].tx_data_map; 2293159952Sobrien 2294170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, *m_head, segs, 2295159967Sobrien &nsegs, BUS_DMA_NOWAIT); 2296170589Syongari if (error == EFBIG) { 2297175418Sjhb m = m_collapse(*m_head, M_DONTWAIT, NFE_MAX_SCATTER); 2298170589Syongari if (m == NULL) { 2299170589Syongari m_freem(*m_head); 2300170589Syongari *m_head = NULL; 2301170589Syongari return (ENOBUFS); 2302170589Syongari } 2303170589Syongari *m_head = m; 2304170589Syongari error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, 2305170589Syongari *m_head, segs, &nsegs, BUS_DMA_NOWAIT); 2306170589Syongari if (error != 0) { 2307170589Syongari m_freem(*m_head); 2308170589Syongari *m_head = NULL; 2309170589Syongari return (ENOBUFS); 2310170589Syongari } 2311170589Syongari } else if (error != 0) 2312170589Syongari return (error); 2313170589Syongari if (nsegs == 0) { 2314170589Syongari m_freem(*m_head); 2315170589Syongari *m_head = NULL; 2316170589Syongari return (EIO); 2317159952Sobrien } 2318159952Sobrien 2319170589Syongari if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 2) { 2320159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 2321170589Syongari return (ENOBUFS); 2322159952Sobrien } 2323159952Sobrien 2324170589Syongari m = *m_head; 2325170589Syongari cflags = flags = 0; 2326170589Syongari tso_segsz = 0; 2327170589Syongari if ((m->m_pkthdr.csum_flags & NFE_CSUM_FEATURES) != 0) { 2328170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) 2329170589Syongari cflags |= NFE_TX_IP_CSUM; 2330170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) 2331170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2332170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) 2333170589Syongari cflags |= NFE_TX_TCP_UDP_CSUM; 2334164656Sobrien } 2335170589Syongari if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { 2336170589Syongari tso_segsz = (uint32_t)m->m_pkthdr.tso_segsz << 2337170589Syongari NFE_TX_TSO_SHIFT; 2338170589Syongari cflags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_UDP_CSUM); 2339170589Syongari cflags |= NFE_TX_TSO; 2340170589Syongari } 2341159967Sobrien 2342159967Sobrien for (i = 0; i < nsegs; i++) { 2343159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2344170589Syongari desc64 = &sc->txq.desc64[prod]; 2345170589Syongari desc64->physaddr[0] = 2346170589Syongari htole32(NFE_ADDR_HI(segs[i].ds_addr)); 2347170589Syongari desc64->physaddr[1] = 2348170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2349170589Syongari desc64->vtag = 0; 2350159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 2351159952Sobrien desc64->flags = htole16(flags); 2352159952Sobrien } else { 2353170589Syongari desc32 = &sc->txq.desc32[prod]; 2354170589Syongari desc32->physaddr = 2355170589Syongari htole32(NFE_ADDR_LO(segs[i].ds_addr)); 2356159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 2357159952Sobrien desc32->flags = htole16(flags); 2358159952Sobrien } 2359159952Sobrien 2360170589Syongari /* 2361170589Syongari * Setting of the valid bit in the first descriptor is 2362170589Syongari * deferred until the whole chain is fully setup. 2363170589Syongari */ 2364170589Syongari flags |= NFE_TX_VALID; 2365163503Sobrien 2366159952Sobrien sc->txq.queued++; 2367170589Syongari NFE_INC(prod, NFE_TX_RING_COUNT); 2368159952Sobrien } 2369159952Sobrien 2370170589Syongari /* 2371170589Syongari * the whole mbuf chain has been DMA mapped, fix last/first descriptor. 2372170589Syongari * csum flags, vtag and TSO belong to the first fragment only. 2373170589Syongari */ 2374159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 2375170589Syongari desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 2376170589Syongari desc64 = &sc->txq.desc64[si]; 2377170589Syongari if ((m->m_flags & M_VLANTAG) != 0) 2378170589Syongari desc64->vtag = htole32(NFE_TX_VTAG | 2379170589Syongari m->m_pkthdr.ether_vtag); 2380170589Syongari if (tso_segsz != 0) { 2381170589Syongari /* 2382170589Syongari * XXX 2383170589Syongari * The following indicates the descriptor element 2384170589Syongari * is a 32bit quantity. 2385170589Syongari */ 2386170589Syongari desc64->length |= htole16((uint16_t)tso_segsz); 2387170589Syongari desc64->flags |= htole16(tso_segsz >> 16); 2388170589Syongari } 2389170589Syongari /* 2390170589Syongari * finally, set the valid/checksum/TSO bit in the first 2391170589Syongari * descriptor. 2392170589Syongari */ 2393170589Syongari desc64->flags |= htole16(NFE_TX_VALID | cflags); 2394159952Sobrien } else { 2395159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 2396170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V2); 2397159952Sobrien else 2398170589Syongari desc32->flags |= htole16(NFE_TX_LASTFRAG_V1); 2399170589Syongari desc32 = &sc->txq.desc32[si]; 2400170589Syongari if (tso_segsz != 0) { 2401170589Syongari /* 2402170589Syongari * XXX 2403170589Syongari * The following indicates the descriptor element 2404170589Syongari * is a 32bit quantity. 2405170589Syongari */ 2406170589Syongari desc32->length |= htole16((uint16_t)tso_segsz); 2407170589Syongari desc32->flags |= htole16(tso_segsz >> 16); 2408170589Syongari } 2409170589Syongari /* 2410170589Syongari * finally, set the valid/checksum/TSO bit in the first 2411170589Syongari * descriptor. 2412170589Syongari */ 2413170589Syongari desc32->flags |= htole16(NFE_TX_VALID | cflags); 2414159952Sobrien } 2415159952Sobrien 2416170589Syongari sc->txq.cur = prod; 2417170589Syongari prod = (prod + NFE_TX_RING_COUNT - 1) % NFE_TX_RING_COUNT; 2418170589Syongari sc->txq.data[si].tx_data_map = sc->txq.data[prod].tx_data_map; 2419170589Syongari sc->txq.data[prod].tx_data_map = map; 2420170589Syongari sc->txq.data[prod].m = m; 2421159952Sobrien 2422159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 2423159952Sobrien 2424170589Syongari return (0); 2425159952Sobrien} 2426159952Sobrien 2427159967Sobrien 2428163503Sobrienstatic void 2429163503Sobriennfe_setmulti(struct nfe_softc *sc) 2430159952Sobrien{ 2431159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2432163503Sobrien struct ifmultiaddr *ifma; 2433163503Sobrien int i; 2434170589Syongari uint32_t filter; 2435170589Syongari uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2436170589Syongari uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 2437163503Sobrien 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2438163503Sobrien }; 2439159967Sobrien 2440159967Sobrien NFE_LOCK_ASSERT(sc); 2441159967Sobrien 2442159967Sobrien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2443159967Sobrien bzero(addr, ETHER_ADDR_LEN); 2444159967Sobrien bzero(mask, ETHER_ADDR_LEN); 2445159967Sobrien goto done; 2446159967Sobrien } 2447159967Sobrien 2448159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2449159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2450159967Sobrien 2451159967Sobrien IF_ADDR_LOCK(ifp); 2452159967Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2453159967Sobrien u_char *addrp; 2454159967Sobrien 2455159967Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 2456159967Sobrien continue; 2457159967Sobrien 2458159967Sobrien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 2459159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2460159967Sobrien u_int8_t mcaddr = addrp[i]; 2461159967Sobrien addr[i] &= mcaddr; 2462159967Sobrien mask[i] &= ~mcaddr; 2463159967Sobrien } 2464159967Sobrien } 2465159967Sobrien IF_ADDR_UNLOCK(ifp); 2466159967Sobrien 2467159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 2468159967Sobrien mask[i] |= addr[i]; 2469159967Sobrien } 2470159967Sobrien 2471159967Sobriendone: 2472159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 2473159967Sobrien 2474159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 2475159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2476159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 2477159967Sobrien addr[5] << 8 | addr[4]); 2478159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 2479159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2480159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 2481159967Sobrien mask[5] << 8 | mask[4]); 2482159967Sobrien 2483170589Syongari filter = NFE_READ(sc, NFE_RXFILTER); 2484170589Syongari filter &= NFE_PFF_RX_PAUSE; 2485170589Syongari filter |= NFE_RXFILTER_MAGIC; 2486170589Syongari filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PFF_PROMISC : NFE_PFF_U2M; 2487159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 2488159967Sobrien} 2489159967Sobrien 2490163503Sobrien 2491163503Sobrienstatic void 2492170589Syongarinfe_tx_task(void *arg, int pending) 2493159967Sobrien{ 2494170589Syongari struct ifnet *ifp; 2495159967Sobrien 2496170589Syongari ifp = (struct ifnet *)arg; 2497170589Syongari nfe_start(ifp); 2498159967Sobrien} 2499159967Sobrien 2500163503Sobrien 2501163503Sobrienstatic void 2502170589Syongarinfe_start(struct ifnet *ifp) 2503159967Sobrien{ 2504159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2505163503Sobrien struct mbuf *m0; 2506170589Syongari int enq; 2507159952Sobrien 2508170589Syongari NFE_LOCK(sc); 2509170589Syongari 2510170589Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 2511170589Syongari IFF_DRV_RUNNING || sc->nfe_link == 0) { 2512170589Syongari NFE_UNLOCK(sc); 2513159967Sobrien return; 2514159967Sobrien } 2515159967Sobrien 2516170589Syongari for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { 2517170589Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); 2518159952Sobrien if (m0 == NULL) 2519159952Sobrien break; 2520159952Sobrien 2521170589Syongari if (nfe_encap(sc, &m0) != 0) { 2522170589Syongari if (m0 == NULL) 2523170589Syongari break; 2524170589Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m0); 2525159967Sobrien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 2526159952Sobrien break; 2527159952Sobrien } 2528170589Syongari enq++; 2529167190Scsjp ETHER_BPF_MTAP(ifp, m0); 2530159952Sobrien } 2531159952Sobrien 2532170589Syongari if (enq > 0) { 2533170589Syongari bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, 2534170589Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2535159952Sobrien 2536170589Syongari /* kick Tx */ 2537170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2538159952Sobrien 2539170589Syongari /* 2540170589Syongari * Set a timeout in case the chip goes out to lunch. 2541170589Syongari */ 2542170589Syongari sc->nfe_watchdog_timer = 5; 2543170589Syongari } 2544159967Sobrien 2545170589Syongari NFE_UNLOCK(sc); 2546159952Sobrien} 2547159952Sobrien 2548163503Sobrien 2549163503Sobrienstatic void 2550163503Sobriennfe_watchdog(struct ifnet *ifp) 2551159952Sobrien{ 2552159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2553159952Sobrien 2554170589Syongari if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) 2555170589Syongari return; 2556159952Sobrien 2557170589Syongari /* Check if we've lost Tx completion interrupt. */ 2558170589Syongari nfe_txeof(sc); 2559170589Syongari if (sc->txq.queued == 0) { 2560170589Syongari if_printf(ifp, "watchdog timeout (missed Tx interrupts) " 2561170589Syongari "-- recovering\n"); 2562170589Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2563173674Ssam taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task); 2564170589Syongari return; 2565170589Syongari } 2566170589Syongari /* Check if we've lost start Tx command. */ 2567170589Syongari sc->nfe_force_tx++; 2568170589Syongari if (sc->nfe_force_tx <= 3) { 2569170589Syongari /* 2570170589Syongari * If this is the case for watchdog timeout, the following 2571170589Syongari * code should go to nfe_txeof(). 2572170589Syongari */ 2573170589Syongari NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 2574170589Syongari return; 2575170589Syongari } 2576170589Syongari sc->nfe_force_tx = 0; 2577170589Syongari 2578170589Syongari if_printf(ifp, "watchdog timeout\n"); 2579170589Syongari 2580159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2581159952Sobrien ifp->if_oerrors++; 2582170589Syongari nfe_init_locked(sc); 2583159952Sobrien} 2584159952Sobrien 2585163503Sobrien 2586163503Sobrienstatic void 2587163503Sobriennfe_init(void *xsc) 2588159952Sobrien{ 2589159967Sobrien struct nfe_softc *sc = xsc; 2590159952Sobrien 2591159967Sobrien NFE_LOCK(sc); 2592159967Sobrien nfe_init_locked(sc); 2593159967Sobrien NFE_UNLOCK(sc); 2594159967Sobrien} 2595159967Sobrien 2596163503Sobrien 2597163503Sobrienstatic void 2598163503Sobriennfe_init_locked(void *xsc) 2599159967Sobrien{ 2600159967Sobrien struct nfe_softc *sc = xsc; 2601159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 2602159967Sobrien struct mii_data *mii; 2603170589Syongari uint32_t val; 2604170589Syongari int error; 2605159967Sobrien 2606159967Sobrien NFE_LOCK_ASSERT(sc); 2607159967Sobrien 2608159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2609159967Sobrien 2610170589Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2611159967Sobrien return; 2612170589Syongari 2613170589Syongari nfe_stop(ifp); 2614170589Syongari 2615170589Syongari sc->nfe_framesize = ifp->if_mtu + NFE_RX_HEADERS; 2616170589Syongari 2617170589Syongari nfe_init_tx_ring(sc, &sc->txq); 2618170589Syongari if (sc->nfe_framesize > (MCLBYTES - ETHER_HDR_LEN)) 2619170589Syongari error = nfe_init_jrx_ring(sc, &sc->jrxq); 2620170589Syongari else 2621170589Syongari error = nfe_init_rx_ring(sc, &sc->rxq); 2622170589Syongari if (error != 0) { 2623170589Syongari device_printf(sc->nfe_dev, 2624170589Syongari "initialization failed: no memory for rx buffers\n"); 2625170589Syongari nfe_stop(ifp); 2626170589Syongari return; 2627159967Sobrien } 2628159967Sobrien 2629170589Syongari val = 0; 2630170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) != 0) 2631170589Syongari val |= NFE_MAC_ADDR_INORDER; 2632170589Syongari NFE_WRITE(sc, NFE_TX_UNK, val); 2633159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 2634159952Sobrien 2635170589Syongari if ((sc->nfe_flags & NFE_TX_FLOW_CTRL) != 0) 2636170589Syongari NFE_WRITE(sc, NFE_TX_PAUSE_FRAME, NFE_TX_PAUSE_FRAME_DISABLE); 2637170589Syongari 2638159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 2639159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 2640159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 2641159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 2642159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 2643164656Sobrien 2644170589Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) 2645159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 2646170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2647170589Syongari sc->rxtxctl |= NFE_RXTX_VTAG_INSERT | NFE_RXTX_VTAG_STRIP; 2648159967Sobrien 2649159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 2650159952Sobrien DELAY(10); 2651159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2652159952Sobrien 2653170589Syongari if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) 2654159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 2655170589Syongari else 2656170589Syongari NFE_WRITE(sc, NFE_VTAG_CTL, 0); 2657159952Sobrien 2658159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 2659159952Sobrien 2660159952Sobrien /* set MAC address */ 2661170589Syongari nfe_set_macaddr(sc, IF_LLADDR(ifp)); 2662159952Sobrien 2663159952Sobrien /* tell MAC where rings are in memory */ 2664170589Syongari if (sc->nfe_framesize > MCLBYTES - ETHER_HDR_LEN) { 2665170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2666170589Syongari NFE_ADDR_HI(sc->jrxq.jphysaddr)); 2667170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2668170589Syongari NFE_ADDR_LO(sc->jrxq.jphysaddr)); 2669170589Syongari } else { 2670170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 2671170589Syongari NFE_ADDR_HI(sc->rxq.physaddr)); 2672170589Syongari NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, 2673170589Syongari NFE_ADDR_LO(sc->rxq.physaddr)); 2674170589Syongari } 2675170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, NFE_ADDR_HI(sc->txq.physaddr)); 2676170589Syongari NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 2677159952Sobrien 2678159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 2679159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 2680159952Sobrien (NFE_TX_RING_COUNT - 1)); 2681159952Sobrien 2682170589Syongari NFE_WRITE(sc, NFE_RXBUFSZ, sc->nfe_framesize); 2683159952Sobrien 2684159952Sobrien /* force MAC to wakeup */ 2685170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2686170589Syongari if ((val & NFE_PWR_WAKEUP) == 0) 2687170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_WAKEUP); 2688159952Sobrien DELAY(10); 2689170589Syongari val = NFE_READ(sc, NFE_PWR_STATE); 2690170589Syongari NFE_WRITE(sc, NFE_PWR_STATE, val | NFE_PWR_VALID); 2691159952Sobrien 2692159952Sobrien#if 1 2693159952Sobrien /* configure interrupts coalescing/mitigation */ 2694159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 2695159952Sobrien#else 2696159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 2697159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 2698159952Sobrien#endif 2699159952Sobrien 2700170589Syongari NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC_10_100); 2701159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 2702159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 2703159952Sobrien 2704159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 2705159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 2706159952Sobrien 2707159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 2708159952Sobrien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 2709159952Sobrien 2710159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 2711159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 2712159952Sobrien DELAY(10); 2713159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 2714159952Sobrien 2715159952Sobrien /* set Rx filter */ 2716159952Sobrien nfe_setmulti(sc); 2717159952Sobrien 2718159952Sobrien /* enable Rx */ 2719159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 2720159952Sobrien 2721159952Sobrien /* enable Tx */ 2722159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 2723159952Sobrien 2724159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 2725159952Sobrien 2726159967Sobrien#ifdef DEVICE_POLLING 2727159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) 2728170589Syongari nfe_disable_intr(sc); 2729159967Sobrien else 2730159967Sobrien#endif 2731170589Syongari nfe_set_intr(sc); 2732170589Syongari nfe_enable_intr(sc); /* enable interrupts */ 2733159952Sobrien 2734159967Sobrien ifp->if_drv_flags |= IFF_DRV_RUNNING; 2735159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 2736159952Sobrien 2737159967Sobrien sc->nfe_link = 0; 2738170589Syongari mii_mediachg(mii); 2739159952Sobrien 2740170589Syongari callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2741159952Sobrien} 2742159952Sobrien 2743163503Sobrien 2744163503Sobrienstatic void 2745170589Syongarinfe_stop(struct ifnet *ifp) 2746159952Sobrien{ 2747159952Sobrien struct nfe_softc *sc = ifp->if_softc; 2748170589Syongari struct nfe_rx_ring *rx_ring; 2749170589Syongari struct nfe_jrx_ring *jrx_ring; 2750170589Syongari struct nfe_tx_ring *tx_ring; 2751170589Syongari struct nfe_rx_data *rdata; 2752170589Syongari struct nfe_tx_data *tdata; 2753170589Syongari int i; 2754159952Sobrien 2755159967Sobrien NFE_LOCK_ASSERT(sc); 2756159952Sobrien 2757170589Syongari sc->nfe_watchdog_timer = 0; 2758159967Sobrien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2759159952Sobrien 2760159967Sobrien callout_stop(&sc->nfe_stat_ch); 2761159967Sobrien 2762159952Sobrien /* abort Tx */ 2763159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 2764159952Sobrien 2765159952Sobrien /* disable Rx */ 2766159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 2767159952Sobrien 2768159952Sobrien /* disable interrupts */ 2769170589Syongari nfe_disable_intr(sc); 2770159952Sobrien 2771159967Sobrien sc->nfe_link = 0; 2772159967Sobrien 2773170589Syongari /* free Rx and Tx mbufs still in the queues. */ 2774170589Syongari rx_ring = &sc->rxq; 2775170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2776170589Syongari rdata = &rx_ring->data[i]; 2777170589Syongari if (rdata->m != NULL) { 2778170589Syongari bus_dmamap_sync(rx_ring->rx_data_tag, 2779170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2780170589Syongari bus_dmamap_unload(rx_ring->rx_data_tag, 2781170589Syongari rdata->rx_data_map); 2782170589Syongari m_freem(rdata->m); 2783170589Syongari rdata->m = NULL; 2784170589Syongari } 2785170589Syongari } 2786159952Sobrien 2787170589Syongari if ((sc->nfe_flags & NFE_JUMBO_SUP) != 0) { 2788170589Syongari jrx_ring = &sc->jrxq; 2789170589Syongari for (i = 0; i < NFE_JUMBO_RX_RING_COUNT; i++) { 2790170589Syongari rdata = &jrx_ring->jdata[i]; 2791170589Syongari if (rdata->m != NULL) { 2792170589Syongari bus_dmamap_sync(jrx_ring->jrx_data_tag, 2793170589Syongari rdata->rx_data_map, BUS_DMASYNC_POSTREAD); 2794170589Syongari bus_dmamap_unload(jrx_ring->jrx_data_tag, 2795170589Syongari rdata->rx_data_map); 2796170589Syongari m_freem(rdata->m); 2797170589Syongari rdata->m = NULL; 2798170589Syongari } 2799170589Syongari } 2800170589Syongari } 2801170589Syongari 2802170589Syongari tx_ring = &sc->txq; 2803170589Syongari for (i = 0; i < NFE_RX_RING_COUNT; i++) { 2804170589Syongari tdata = &tx_ring->data[i]; 2805170589Syongari if (tdata->m != NULL) { 2806170589Syongari bus_dmamap_sync(tx_ring->tx_data_tag, 2807170589Syongari tdata->tx_data_map, BUS_DMASYNC_POSTWRITE); 2808170589Syongari bus_dmamap_unload(tx_ring->tx_data_tag, 2809170589Syongari tdata->tx_data_map); 2810170589Syongari m_freem(tdata->m); 2811170589Syongari tdata->m = NULL; 2812170589Syongari } 2813170589Syongari } 2814159952Sobrien} 2815159952Sobrien 2816163503Sobrien 2817163503Sobrienstatic int 2818163503Sobriennfe_ifmedia_upd(struct ifnet *ifp) 2819159952Sobrien{ 2820159967Sobrien struct nfe_softc *sc = ifp->if_softc; 2821170589Syongari struct mii_data *mii; 2822159952Sobrien 2823159967Sobrien NFE_LOCK(sc); 2824159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2825159967Sobrien mii_mediachg(mii); 2826170589Syongari NFE_UNLOCK(sc); 2827159967Sobrien 2828159967Sobrien return (0); 2829159952Sobrien} 2830159952Sobrien 2831163503Sobrien 2832163503Sobrienstatic void 2833163503Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2834159952Sobrien{ 2835163503Sobrien struct nfe_softc *sc; 2836163503Sobrien struct mii_data *mii; 2837159952Sobrien 2838159967Sobrien sc = ifp->if_softc; 2839159952Sobrien 2840159967Sobrien NFE_LOCK(sc); 2841159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2842159967Sobrien mii_pollstat(mii); 2843159967Sobrien NFE_UNLOCK(sc); 2844159952Sobrien 2845159967Sobrien ifmr->ifm_active = mii->mii_media_active; 2846159967Sobrien ifmr->ifm_status = mii->mii_media_status; 2847159952Sobrien} 2848159952Sobrien 2849163503Sobrien 2850170589Syongarivoid 2851159967Sobriennfe_tick(void *xsc) 2852159952Sobrien{ 2853159967Sobrien struct nfe_softc *sc; 2854163503Sobrien struct mii_data *mii; 2855163503Sobrien struct ifnet *ifp; 2856159952Sobrien 2857170589Syongari sc = (struct nfe_softc *)xsc; 2858159952Sobrien 2859163503Sobrien NFE_LOCK_ASSERT(sc); 2860159952Sobrien 2861159967Sobrien ifp = sc->nfe_ifp; 2862159952Sobrien 2863159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2864159967Sobrien mii_tick(mii); 2865170589Syongari nfe_watchdog(ifp); 2866159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2867159952Sobrien} 2868159952Sobrien 2869159952Sobrien 2870173839Syongaristatic int 2871163503Sobriennfe_shutdown(device_t dev) 2872159952Sobrien{ 2873159967Sobrien struct nfe_softc *sc; 2874159967Sobrien struct ifnet *ifp; 2875159952Sobrien 2876159967Sobrien sc = device_get_softc(dev); 2877159952Sobrien 2878159967Sobrien NFE_LOCK(sc); 2879159967Sobrien ifp = sc->nfe_ifp; 2880170589Syongari nfe_stop(ifp); 2881159967Sobrien /* nfe_reset(sc); */ 2882159967Sobrien NFE_UNLOCK(sc); 2883173839Syongari 2884173839Syongari return (0); 2885159952Sobrien} 2886159952Sobrien 2887159952Sobrien 2888163503Sobrienstatic void 2889170589Syongarinfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 2890159952Sobrien{ 2891170589Syongari uint32_t val; 2892159952Sobrien 2893170589Syongari if ((sc->nfe_flags & NFE_CORRECT_MACADDR) == 0) { 2894170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 2895170589Syongari addr[0] = (val >> 8) & 0xff; 2896170589Syongari addr[1] = (val & 0xff); 2897159952Sobrien 2898170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 2899170589Syongari addr[2] = (val >> 24) & 0xff; 2900170589Syongari addr[3] = (val >> 16) & 0xff; 2901170589Syongari addr[4] = (val >> 8) & 0xff; 2902170589Syongari addr[5] = (val & 0xff); 2903170589Syongari } else { 2904170589Syongari val = NFE_READ(sc, NFE_MACADDR_LO); 2905170589Syongari addr[5] = (val >> 8) & 0xff; 2906170589Syongari addr[4] = (val & 0xff); 2907170589Syongari 2908170589Syongari val = NFE_READ(sc, NFE_MACADDR_HI); 2909170589Syongari addr[3] = (val >> 24) & 0xff; 2910170589Syongari addr[2] = (val >> 16) & 0xff; 2911170589Syongari addr[1] = (val >> 8) & 0xff; 2912170589Syongari addr[0] = (val & 0xff); 2913170589Syongari } 2914159952Sobrien} 2915159952Sobrien 2916163503Sobrien 2917163503Sobrienstatic void 2918170589Syongarinfe_set_macaddr(struct nfe_softc *sc, uint8_t *addr) 2919159952Sobrien{ 2920159967Sobrien 2921159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 2922159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 2923159967Sobrien addr[1] << 8 | addr[0]); 2924159952Sobrien} 2925159952Sobrien 2926163503Sobrien 2927159967Sobrien/* 2928159967Sobrien * Map a single buffer address. 2929159967Sobrien */ 2930159967Sobrien 2931159967Sobrienstatic void 2932170589Syongarinfe_dma_map_segs(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2933159952Sobrien{ 2934170589Syongari struct nfe_dmamap_arg *ctx; 2935159952Sobrien 2936170589Syongari if (error != 0) 2937159967Sobrien return; 2938159952Sobrien 2939159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2940159967Sobrien 2941170589Syongari ctx = (struct nfe_dmamap_arg *)arg; 2942170589Syongari ctx->nfe_busaddr = segs[0].ds_addr; 2943170589Syongari} 2944159967Sobrien 2945170589Syongari 2946170589Syongaristatic int 2947170589Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high) 2948170589Syongari{ 2949170589Syongari int error, value; 2950170589Syongari 2951170589Syongari if (!arg1) 2952170589Syongari return (EINVAL); 2953170589Syongari value = *(int *)arg1; 2954170589Syongari error = sysctl_handle_int(oidp, &value, 0, req); 2955170589Syongari if (error || !req->newptr) 2956170589Syongari return (error); 2957170589Syongari if (value < low || value > high) 2958170589Syongari return (EINVAL); 2959170589Syongari *(int *)arg1 = value; 2960170589Syongari 2961170589Syongari return (0); 2962159952Sobrien} 2963170589Syongari 2964170589Syongari 2965170589Syongaristatic int 2966170589Syongarisysctl_hw_nfe_proc_limit(SYSCTL_HANDLER_ARGS) 2967170589Syongari{ 2968170589Syongari 2969170589Syongari return (sysctl_int_range(oidp, arg1, arg2, req, NFE_PROC_MIN, 2970170589Syongari NFE_PROC_MAX)); 2971170589Syongari} 2972