if_nfe.c revision 162212
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 162212 2006-09-11 07:31:55Z obrien $"); 25159952Sobrien 26159967Sobrien/* Uncomment the following line to enable polling. */ 27159967Sobrien/* #define DEVICE_POLLING */ 28159967Sobrien 29159967Sobrien#define NFE_NO_JUMBO 30159967Sobrien#define NFE_CSUM 31159967Sobrien#define NFE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 32159967Sobrien#define NVLAN 0 33159967Sobrien 34159967Sobrien#ifdef HAVE_KERNEL_OPTION_HEADERS 35159967Sobrien#include "opt_device_polling.h" 36159967Sobrien#endif 37159967Sobrien 38159952Sobrien#include <sys/param.h> 39159952Sobrien#include <sys/endian.h> 40159952Sobrien#include <sys/systm.h> 41159952Sobrien#include <sys/sockio.h> 42159952Sobrien#include <sys/mbuf.h> 43159952Sobrien#include <sys/malloc.h> 44159967Sobrien#include <sys/module.h> 45159952Sobrien#include <sys/kernel.h> 46159952Sobrien#include <sys/socket.h> 47159967Sobrien#include <sys/taskqueue.h> 48159952Sobrien 49159952Sobrien#include <net/if.h> 50159967Sobrien#include <net/if_arp.h> 51159967Sobrien#include <net/ethernet.h> 52159952Sobrien#include <net/if_dl.h> 53159952Sobrien#include <net/if_media.h> 54159952Sobrien#include <net/if_types.h> 55159952Sobrien#include <net/if_vlan_var.h> 56159952Sobrien 57159952Sobrien#include <net/bpf.h> 58159952Sobrien 59159967Sobrien#include <machine/bus.h> 60159967Sobrien#include <machine/resource.h> 61159967Sobrien#include <sys/bus.h> 62159967Sobrien#include <sys/rman.h> 63159967Sobrien 64159952Sobrien#include <dev/mii/mii.h> 65159952Sobrien#include <dev/mii/miivar.h> 66159952Sobrien 67159952Sobrien#include <dev/pci/pcireg.h> 68159952Sobrien#include <dev/pci/pcivar.h> 69159952Sobrien 70159967Sobrien#include <dev/nfe/if_nfereg.h> 71159967Sobrien#include <dev/nfe/if_nfevar.h> 72159952Sobrien 73159967SobrienMODULE_DEPEND(nfe, pci, 1, 1, 1); 74159967SobrienMODULE_DEPEND(nfe, ether, 1, 1, 1); 75159967SobrienMODULE_DEPEND(nfe, miibus, 1, 1, 1); 76159967Sobrien#include "miibus_if.h" 77159952Sobrien 78159967Sobrienstatic int nfe_probe (device_t); 79159967Sobrienstatic int nfe_attach (device_t); 80159967Sobrienstatic int nfe_detach (device_t); 81159967Sobrienstatic void nfe_shutdown(device_t); 82159967Sobrienstatic int nfe_miibus_readreg (device_t, int, int); 83159967Sobrienstatic int nfe_miibus_writereg (device_t, int, int, int); 84159967Sobrienstatic void nfe_miibus_statchg (device_t); 85159967Sobrienstatic int nfe_ioctl(struct ifnet *, u_long, caddr_t); 86159967Sobrienstatic void nfe_intr(void *); 87159967Sobrienstatic void nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 88159967Sobrienstatic void nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 89159967Sobrienstatic void nfe_txdesc32_rsync(struct nfe_softc *, int, int, int); 90159967Sobrienstatic void nfe_txdesc64_rsync(struct nfe_softc *, int, int, int); 91159967Sobrienstatic void nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 92159967Sobrienstatic void nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 93159967Sobrienstatic void nfe_rxeof(struct nfe_softc *); 94159967Sobrienstatic void nfe_txeof(struct nfe_softc *); 95159967Sobrienstatic int nfe_encap(struct nfe_softc *, struct mbuf *); 96159967Sobrienstatic struct nfe_jbuf *nfe_jalloc(struct nfe_softc *); 97159967Sobrienstatic void nfe_jfree(void *, void *); 98159967Sobrienstatic int nfe_jpool_alloc(struct nfe_softc *); 99159967Sobrienstatic void nfe_jpool_free(struct nfe_softc *); 100159967Sobrienstatic void nfe_setmulti(struct nfe_softc *); 101159967Sobrienstatic void nfe_start(struct ifnet *); 102159967Sobrienstatic void nfe_start_locked(struct ifnet *); 103159967Sobrienstatic void nfe_watchdog(struct ifnet *); 104159967Sobrienstatic void nfe_init(void *); 105159967Sobrienstatic void nfe_init_locked(void *); 106159967Sobrienstatic void nfe_stop(struct ifnet *, int); 107159967Sobrienstatic int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 108159967Sobrienstatic void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 109159967Sobrienstatic void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 110159967Sobrienstatic int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 111159967Sobrienstatic void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 112159967Sobrienstatic void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 113159967Sobrienstatic int nfe_ifmedia_upd(struct ifnet *); 114159967Sobrienstatic int nfe_ifmedia_upd_locked(struct ifnet *); 115159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 116159967Sobrienstatic void nfe_tick(void *); 117159967Sobrienstatic void nfe_tick_locked(struct nfe_softc *); 118159967Sobrienstatic void nfe_get_macaddr(struct nfe_softc *, u_char *); 119159967Sobrienstatic void nfe_set_macaddr(struct nfe_softc *, u_char *); 120159967Sobrienstatic void nfe_dma_map_segs (void *, bus_dma_segment_t *, int, int); 121159967Sobrien#ifdef DEVICE_POLLING 122159967Sobrienstatic void nfe_poll_locked(struct ifnet *, enum poll_cmd, int); 123159967Sobrien#endif 124159952Sobrien 125159952Sobrien#ifdef NFE_DEBUG 126159952Sobrienint nfedebug = 0; 127159952Sobrien#define DPRINTF(x) do { if (nfedebug) printf x; } while (0) 128159952Sobrien#define DPRINTFN(n,x) do { if (nfedebug >= (n)) printf x; } while (0) 129159952Sobrien#else 130159952Sobrien#define DPRINTF(x) 131159952Sobrien#define DPRINTFN(n,x) 132159952Sobrien#endif 133159952Sobrien 134159967Sobrien#define NFE_LOCK(_sc) mtx_lock(&(_sc)->nfe_mtx) 135159967Sobrien#define NFE_UNLOCK(_sc) mtx_unlock(&(_sc)->nfe_mtx) 136159967Sobrien#define NFE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->nfe_mtx, MA_OWNED) 137159967Sobrien 138159967Sobrien#define letoh16(x) le16toh(x) 139159967Sobrien 140159967Sobrien#define NV_RID 0x10 141159967Sobrien 142159967Sobrienstatic device_method_t nfe_methods[] = { 143159967Sobrien /* Device interface */ 144159967Sobrien DEVMETHOD(device_probe, nfe_probe), 145159967Sobrien DEVMETHOD(device_attach, nfe_attach), 146159967Sobrien DEVMETHOD(device_detach, nfe_detach), 147159967Sobrien DEVMETHOD(device_shutdown, nfe_shutdown), 148159967Sobrien 149159967Sobrien /* bus interface */ 150159967Sobrien DEVMETHOD(bus_print_child, bus_generic_print_child), 151159967Sobrien DEVMETHOD(bus_driver_added, bus_generic_driver_added), 152159967Sobrien 153159967Sobrien /* MII interface */ 154159967Sobrien DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 155159967Sobrien DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 156159967Sobrien DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 157159967Sobrien 158159967Sobrien { 0, 0 } 159159952Sobrien}; 160159952Sobrien 161159967Sobrienstatic driver_t nfe_driver = { 162159967Sobrien "nfe", 163159967Sobrien nfe_methods, 164159967Sobrien sizeof(struct nfe_softc) 165159967Sobrien}; 166159967Sobrien 167159967Sobrienstatic devclass_t nfe_devclass; 168159967Sobrien 169159967SobrienDRIVER_MODULE(nfe, pci, nfe_driver, nfe_devclass, 0, 0); 170159967SobrienDRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, 0, 0); 171159967Sobrien 172159967Sobrienstatic struct nfe_type nfe_devs[] = { 173159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 174159967Sobrien "NVIDIA nForce Networking Adapter"}, 175159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 176159967Sobrien "NVIDIA nForce2 Networking Adapter"}, 177159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 178159967Sobrien "NVIDIA nForce3 Networking Adapter"}, 179159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN1, 180159967Sobrien "NVIDIA nForce2 400 Networking Adapter"}, 181159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_LAN2, 182159967Sobrien "NVIDIA nForce2 400 Networking Adapter"}, 183159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_LAN, 184159967Sobrien "NVIDIA nForce3 250 Networking Adapter"}, 185159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 186159967Sobrien "NVIDIA nForce3 Networking Adapter"}, 187159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN1, 188159967Sobrien "NVIDIA nForce4 Networking Adapter"}, 189159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_LAN2, 190159967Sobrien "NVIDIA nForce4 Networking Adapter"}, 191159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 192159967Sobrien "NVIDIA nForce MCP04 Networking Adapter"}, 193159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 194159967Sobrien "NVIDIA nForce MCP04 Networking Adapter"}, 195159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN1, 196159967Sobrien "NVIDIA nForce 430 Networking Adapter"}, 197159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE430_LAN2, 198159967Sobrien "NVIDIA nForce 430 Networking Adapter"}, 199159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 200159967Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 201159967Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 202159967Sobrien "NVIDIA nForce MCP55 Networking Adapter"}, 203162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 204162212Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 205162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 206162212Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 207162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 208162212Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 209162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 210162212Sobrien "NVIDIA nForce MCP61 Networking Adapter"}, 211162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 212162212Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 213162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 214162212Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 215162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 216162212Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 217162212Sobrien {PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 218162212Sobrien "NVIDIA nForce MCP65 Networking Adapter"}, 219159967Sobrien {0, 0, NULL} 220159967Sobrien}; 221159967Sobrien 222159967Sobrien 223159967Sobrien/* Probe for supported hardware ID's */ 224159967Sobrienstatic int 225159967Sobriennfe_probe(device_t dev) 226159952Sobrien{ 227159967Sobrien struct nfe_type *t; 228159967Sobrien 229159967Sobrien t = nfe_devs; 230159967Sobrien /* Check for matching PCI DEVICE ID's */ 231159967Sobrien while (t->name != NULL) { 232159967Sobrien if ((pci_get_vendor(dev) == t->vid_id) && 233159967Sobrien (pci_get_device(dev) == t->dev_id)) { 234159967Sobrien device_set_desc(dev, t->name); 235159967Sobrien return (0); 236159967Sobrien } 237159967Sobrien t++; 238159967Sobrien } 239159967Sobrien 240159967Sobrien return (ENXIO); 241159952Sobrien} 242159952Sobrien 243159967Sobrienstatic int 244159967Sobriennfe_attach(device_t dev) 245159952Sobrien{ 246159967Sobrien struct nfe_softc *sc; 247159952Sobrien struct ifnet *ifp; 248159967Sobrien int unit, error = 0, rid; 249159952Sobrien 250159967Sobrien sc = device_get_softc(dev); 251159967Sobrien unit = device_get_unit(dev); 252159967Sobrien sc->nfe_dev = dev; 253159967Sobrien sc->nfe_unit = unit; 254159952Sobrien 255159967Sobrien mtx_init(&sc->nfe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 256159967Sobrien MTX_DEF | MTX_RECURSE); 257159967Sobrien callout_init_mtx(&sc->nfe_stat_ch, &sc->nfe_mtx, 0); 258159967Sobrien 259159967Sobrien 260159967Sobrien pci_enable_busmaster(dev); 261159967Sobrien 262159967Sobrien rid = NV_RID; 263159967Sobrien sc->nfe_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 264159967Sobrien 0, ~0, 1, RF_ACTIVE); 265159967Sobrien 266159967Sobrien if (sc->nfe_res == NULL) { 267159967Sobrien printf ("nfe%d: couldn't map ports/memory\n", unit); 268159967Sobrien error = ENXIO; 269159967Sobrien goto fail; 270159952Sobrien } 271159952Sobrien 272159967Sobrien sc->nfe_memt = rman_get_bustag(sc->nfe_res); 273159967Sobrien sc->nfe_memh = rman_get_bushandle(sc->nfe_res); 274159967Sobrien 275159967Sobrien /* Allocate interrupt */ 276159967Sobrien rid = 0; 277159967Sobrien sc->nfe_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 278159967Sobrien 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 279159967Sobrien 280159967Sobrien if (sc->nfe_irq == NULL) { 281159967Sobrien printf("nfe%d: couldn't map interrupt\n", unit); 282159967Sobrien error = ENXIO; 283159967Sobrien goto fail; 284159952Sobrien } 285159952Sobrien 286159967Sobrien nfe_get_macaddr(sc, sc->eaddr); 287159952Sobrien 288159967Sobrien sc->nfe_flags = 0; 289159952Sobrien 290159967Sobrien switch (pci_get_device(dev)) { 291159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 292159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 293159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 294159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 295159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 296159952Sobrien break; 297159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 298159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 299159967Sobrien sc->nfe_flags |= NFE_40BIT_ADDR; 300159952Sobrien break; 301159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 302159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 303159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 304159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 305159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 306159952Sobrien break; 307159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 308159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 309159967Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | NFE_HW_VLAN; 310159952Sobrien break; 311162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 312162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 313162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 314162212Sobrien case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 315162212Sobrien sc->nfe_flags |= NFE_40BIT_ADDR; 316162212Sobrien break; 317162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 318162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 319162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 320162212Sobrien case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 321162212Sobrien sc->nfe_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 322162212Sobrien break; 323159952Sobrien } 324159952Sobrien 325159952Sobrien#ifndef NFE_NO_JUMBO 326159952Sobrien /* enable jumbo frames for adapters that support it */ 327159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 328159967Sobrien sc->nfe_flags |= NFE_USE_JUMBO; 329159952Sobrien#endif 330159952Sobrien 331159952Sobrien /* 332159967Sobrien * Allocate the parent bus DMA tag appropriate for PCI. 333159967Sobrien */ 334159967Sobrien#define NFE_NSEG_NEW 32 335159967Sobrien error = bus_dma_tag_create(NULL, /* parent */ 336159967Sobrien 1, 0, /* alignment, boundary */ 337159967Sobrien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 338159967Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 339159967Sobrien NULL, NULL, /* filter, filterarg */ 340159967Sobrien MAXBSIZE, NFE_NSEG_NEW, /* maxsize, nsegments */ 341159967Sobrien BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 342159967Sobrien BUS_DMA_ALLOCNOW, /* flags */ 343159967Sobrien NULL, NULL, /* lockfunc, lockarg */ 344159967Sobrien &sc->nfe_parent_tag); 345159967Sobrien if (error) 346159967Sobrien goto fail; 347159967Sobrien 348159967Sobrien /* 349159952Sobrien * Allocate Tx and Rx rings. 350159952Sobrien */ 351159952Sobrien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 352159967Sobrien printf("nfe%d: could not allocate Tx ring\n", unit); 353159967Sobrien error = ENXIO; 354159967Sobrien goto fail; 355159952Sobrien } 356159952Sobrien 357159952Sobrien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 358159967Sobrien printf("nfe%d: could not allocate Rx ring\n", unit); 359159952Sobrien nfe_free_tx_ring(sc, &sc->txq); 360159967Sobrien error = ENXIO; 361159967Sobrien goto fail; 362159952Sobrien } 363159952Sobrien 364159967Sobrien ifp = sc->nfe_ifp = if_alloc(IFT_ETHER); 365159967Sobrien if (ifp == NULL) { 366159967Sobrien printf("nfe%d: can not if_alloc()\n", unit); 367159967Sobrien error = ENOSPC; 368159967Sobrien goto fail; 369159967Sobrien } 370159967Sobrien 371159952Sobrien ifp->if_softc = sc; 372159967Sobrien if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 373159967Sobrien ifp->if_mtu = ETHERMTU; 374159952Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 375159952Sobrien ifp->if_ioctl = nfe_ioctl; 376159952Sobrien ifp->if_start = nfe_start; 377159967Sobrien /* ifp->if_hwassist = NFE_CSUM_FEATURES; */ 378159952Sobrien ifp->if_watchdog = nfe_watchdog; 379159952Sobrien ifp->if_init = nfe_init; 380159952Sobrien ifp->if_baudrate = IF_Gbps(1); 381159967Sobrien ifp->if_snd.ifq_maxlen = NFE_IFQ_MAXLEN; 382159952Sobrien 383159952Sobrien ifp->if_capabilities = IFCAP_VLAN_MTU; 384159952Sobrien#if NVLAN > 0 385159967Sobrien if (sc->nfe_flags & NFE_HW_VLAN) 386159952Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 387159952Sobrien#endif 388159952Sobrien#ifdef NFE_CSUM 389159967Sobrien if (sc->nfe_flags & NFE_HW_CSUM) { 390159967Sobrien ifp->if_capabilities |= IFCAP_HWCSUM; 391159952Sobrien } 392159952Sobrien#endif 393159967Sobrien ifp->if_capenable = ifp->if_capabilities; 394159952Sobrien 395159967Sobrien#ifdef DEVICE_POLLING 396159967Sobrien ifp->if_capabilities |= IFCAP_POLLING; 397159967Sobrien#endif 398159952Sobrien 399159967Sobrien /* Do MII setup */ 400159967Sobrien if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, nfe_ifmedia_sts)) { 401159967Sobrien printf("nfe%d: MII without any phy!\n", unit); 402159967Sobrien error = ENXIO; 403159967Sobrien goto fail; 404159967Sobrien } 405159952Sobrien 406159967Sobrien ether_ifattach(ifp, sc->eaddr); 407159952Sobrien 408159967Sobrien error = bus_setup_intr(dev, sc->nfe_irq, INTR_TYPE_NET|INTR_MPSAFE, 409159967Sobrien nfe_intr, sc, &sc->nfe_intrhand); 410159952Sobrien 411159967Sobrien if (error) { 412159967Sobrien printf("nfe%d: couldn't set up irq\n", unit); 413159967Sobrien ether_ifdetach(ifp); 414159967Sobrien goto fail; 415159967Sobrien } 416159967Sobrien 417159967Sobrienfail: 418159967Sobrien if (error) 419159967Sobrien nfe_detach(dev); 420159967Sobrien 421159967Sobrien return (error); 422159952Sobrien} 423159952Sobrien 424159967Sobrien 425159967Sobrienstatic int 426159967Sobriennfe_detach(device_t dev) 427159952Sobrien{ 428159967Sobrien struct nfe_softc *sc; 429159967Sobrien struct ifnet *ifp; 430159967Sobrien u_char eaddr[ETHER_ADDR_LEN]; 431159967Sobrien int i; 432159952Sobrien 433159967Sobrien sc = device_get_softc(dev); 434159967Sobrien KASSERT(mtx_initialized(&sc->nfe_mtx), ("nfe mutex not initialized")); 435159967Sobrien ifp = sc->nfe_ifp; 436159967Sobrien 437159967Sobrien#ifdef DEVICE_POLLING 438159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) 439159967Sobrien ether_poll_deregister(ifp); 440159967Sobrien#endif 441159967Sobrien 442159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 443159967Sobrien eaddr[i] = sc->eaddr[5 - i]; 444159952Sobrien } 445159967Sobrien nfe_set_macaddr(sc, eaddr); 446159967Sobrien 447159967Sobrien if (device_is_attached(dev)) { 448159967Sobrien nfe_stop(ifp, 1); 449159967Sobrien ifp->if_flags &= ~IFF_UP; 450159967Sobrien callout_drain(&sc->nfe_stat_ch); 451159967Sobrien ether_ifdetach(ifp); 452159967Sobrien } 453159967Sobrien 454159967Sobrien if (ifp) 455159967Sobrien if_free(ifp); 456159967Sobrien if (sc->nfe_miibus) 457159967Sobrien device_delete_child(dev, sc->nfe_miibus); 458159967Sobrien bus_generic_detach(dev); 459159967Sobrien 460159967Sobrien if (sc->nfe_intrhand) 461159967Sobrien bus_teardown_intr(dev, sc->nfe_irq, sc->nfe_intrhand); 462159967Sobrien if (sc->nfe_irq) 463159967Sobrien bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nfe_irq); 464159967Sobrien if (sc->nfe_res) 465159967Sobrien bus_release_resource(dev, SYS_RES_MEMORY, NV_RID, sc->nfe_res); 466159967Sobrien 467159967Sobrien nfe_free_tx_ring(sc, &sc->txq); 468159967Sobrien nfe_free_rx_ring(sc, &sc->rxq); 469159967Sobrien 470159967Sobrien if (sc->nfe_parent_tag) 471159967Sobrien bus_dma_tag_destroy(sc->nfe_parent_tag); 472159967Sobrien 473159967Sobrien mtx_destroy(&sc->nfe_mtx); 474159967Sobrien 475159967Sobrien return (0); 476159952Sobrien} 477159952Sobrien 478159967Sobrien 479159967Sobrienstatic void 480159967Sobriennfe_miibus_statchg(device_t dev) 481159952Sobrien{ 482159967Sobrien struct nfe_softc *sc; 483159967Sobrien struct mii_data *mii; 484159967Sobrien u_int32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 485159952Sobrien 486159967Sobrien sc = device_get_softc(dev); 487159967Sobrien mii = device_get_softc(sc->nfe_miibus); 488159967Sobrien 489159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 490159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 491159952Sobrien 492159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 493159952Sobrien seed &= ~NFE_SEED_MASK; 494159952Sobrien 495159952Sobrien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 496159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 497159952Sobrien misc |= NFE_MISC1_HDX; 498159952Sobrien } 499159952Sobrien 500159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 501159952Sobrien case IFM_1000_T: /* full-duplex only */ 502159952Sobrien link |= NFE_MEDIA_1000T; 503159952Sobrien seed |= NFE_SEED_1000T; 504159952Sobrien phy |= NFE_PHY_1000T; 505159952Sobrien break; 506159952Sobrien case IFM_100_TX: 507159952Sobrien link |= NFE_MEDIA_100TX; 508159952Sobrien seed |= NFE_SEED_100TX; 509159952Sobrien phy |= NFE_PHY_100TX; 510159952Sobrien break; 511159952Sobrien case IFM_10_T: 512159952Sobrien link |= NFE_MEDIA_10T; 513159952Sobrien seed |= NFE_SEED_10T; 514159952Sobrien break; 515159952Sobrien } 516159952Sobrien 517159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 518159952Sobrien 519159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 520159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 521159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 522159952Sobrien} 523159952Sobrien 524159967Sobrienstatic int 525159967Sobriennfe_miibus_readreg(device_t dev, int phy, int reg) 526159952Sobrien{ 527159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 528159967Sobrien u_int32_t val; 529159952Sobrien int ntries; 530159952Sobrien 531159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 532159952Sobrien 533159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 534159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 535159952Sobrien DELAY(100); 536159952Sobrien } 537159952Sobrien 538159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 539159952Sobrien 540159952Sobrien for (ntries = 0; ntries < 1000; ntries++) { 541159952Sobrien DELAY(100); 542159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 543159952Sobrien break; 544159952Sobrien } 545159952Sobrien if (ntries == 1000) { 546159967Sobrien DPRINTFN(2, ("nfe%d: timeout waiting for PHY\n", sc->nfe_unit)); 547159952Sobrien return 0; 548159952Sobrien } 549159952Sobrien 550159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 551159967Sobrien DPRINTFN(2, ("nfe%d: could not read PHY\n", sc->nfe_unit)); 552159952Sobrien return 0; 553159952Sobrien } 554159952Sobrien 555159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 556159952Sobrien if (val != 0xffffffff && val != 0) 557159952Sobrien sc->mii_phyaddr = phy; 558159952Sobrien 559159967Sobrien DPRINTFN(2, ("nfe%d: mii read phy %d reg 0x%x ret 0x%x\n", sc->nfe_unit, phy, reg, val)); 560159952Sobrien 561159952Sobrien return val; 562159952Sobrien} 563159952Sobrien 564159967Sobrienstatic int 565159967Sobriennfe_miibus_writereg(device_t dev, int phy, int reg, int val) 566159952Sobrien{ 567159967Sobrien struct nfe_softc *sc = device_get_softc(dev); 568159967Sobrien u_int32_t ctl; 569159967Sobrien int ntries; 570159952Sobrien 571159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 572159952Sobrien 573159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 574159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 575159952Sobrien DELAY(100); 576159952Sobrien } 577159952Sobrien 578159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 579159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 580159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 581159952Sobrien 582159952Sobrien for (ntries = 0; ntries < 1000; ntries++) { 583159952Sobrien DELAY(100); 584159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 585159952Sobrien break; 586159952Sobrien } 587159952Sobrien#ifdef NFE_DEBUG 588159952Sobrien if (nfedebug >= 2 && ntries == 1000) 589159952Sobrien printf("could not write to PHY\n"); 590159952Sobrien#endif 591159967Sobrien return 0; 592159952Sobrien} 593159952Sobrien 594159967Sobrienstatic int 595159967Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 596159952Sobrien{ 597159967Sobrien struct nfe_desc32 *desc32; 598159967Sobrien struct nfe_desc64 *desc64; 599159967Sobrien struct nfe_rx_data *data; 600159967Sobrien struct nfe_jbuf *jbuf; 601159967Sobrien void **desc; 602159967Sobrien bus_addr_t physaddr; 603159967Sobrien int i, error, descsize; 604159967Sobrien 605159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 606159967Sobrien desc = (void **)&ring->desc64; 607159967Sobrien descsize = sizeof (struct nfe_desc64); 608159967Sobrien } else { 609159967Sobrien desc = (void **)&ring->desc32; 610159967Sobrien descsize = sizeof (struct nfe_desc32); 611159967Sobrien } 612159967Sobrien 613159967Sobrien ring->cur = ring->next = 0; 614159967Sobrien ring->bufsz = MCLBYTES; 615159967Sobrien 616159967Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 617159967Sobrien PAGE_SIZE, 0, /* alignment, boundary */ 618159967Sobrien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 619159967Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 620159967Sobrien NULL, NULL, /* filter, filterarg */ 621159967Sobrien NFE_RX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 622159967Sobrien NFE_RX_RING_COUNT * descsize, /* maxsegsize */ 623159967Sobrien BUS_DMA_ALLOCNOW, /* flags */ 624159967Sobrien NULL, NULL, /* lockfunc, lockarg */ 625159967Sobrien &ring->rx_desc_tag); 626159967Sobrien if (error != 0) { 627159967Sobrien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 628159967Sobrien goto fail; 629159967Sobrien } 630159967Sobrien 631159967Sobrien /* allocate memory to desc */ 632159967Sobrien error = bus_dmamem_alloc(ring->rx_desc_tag, (void **)desc, BUS_DMA_NOWAIT, &ring->rx_desc_map); 633159967Sobrien if (error != 0) { 634159967Sobrien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 635159967Sobrien goto fail; 636159967Sobrien } 637159967Sobrien 638159967Sobrien /* map desc to device visible address space */ 639159967Sobrien error = bus_dmamap_load(ring->rx_desc_tag, ring->rx_desc_map, *desc, 640159967Sobrien NFE_RX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->rx_desc_segs, BUS_DMA_NOWAIT); 641159967Sobrien if (error != 0) { 642159967Sobrien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 643159967Sobrien goto fail; 644159967Sobrien } 645159967Sobrien 646159967Sobrien bzero(*desc, NFE_RX_RING_COUNT * descsize); 647159967Sobrien ring->rx_desc_addr = ring->rx_desc_segs.ds_addr; 648159967Sobrien ring->physaddr = ring->rx_desc_addr; 649159967Sobrien 650159967Sobrien if (sc->nfe_flags & NFE_USE_JUMBO) { 651159967Sobrien ring->bufsz = NFE_JBYTES; 652159967Sobrien if ((error = nfe_jpool_alloc(sc)) != 0) { 653159967Sobrien printf("nfe%d: could not allocate jumbo frames\n", sc->nfe_unit); 654159967Sobrien goto fail; 655159967Sobrien } 656159967Sobrien } 657159967Sobrien 658159967Sobrien /* 659159967Sobrien * Pre-allocate Rx buffers and populate Rx ring. 660159967Sobrien */ 661159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 662159967Sobrien data = &sc->rxq.data[i]; 663159967Sobrien 664159967Sobrien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 665159967Sobrien if (data->m == NULL) { 666159967Sobrien printf("nfe%d: could not allocate rx mbuf\n", sc->nfe_unit); 667159967Sobrien error = ENOMEM; 668159967Sobrien goto fail; 669159967Sobrien } 670159967Sobrien 671159967Sobrien if (sc->nfe_flags & NFE_USE_JUMBO) { 672159967Sobrien if ((jbuf = nfe_jalloc(sc)) == NULL) { 673159967Sobrien printf("nfe%d: could not allocate jumbo buffer\n", sc->nfe_unit); 674159967Sobrien goto fail; 675159967Sobrien } 676159967Sobrien data->m->m_data = (void *)jbuf->buf; 677159967Sobrien data->m->m_len = data->m->m_pkthdr.len = NFE_JBYTES; 678159967Sobrien MEXTADD(data->m, jbuf->buf, NFE_JBYTES, nfe_jfree, (struct nfe_softc *)sc, 0, EXT_NET_DRV); 679159967Sobrien /* m_adj(data->m, ETHER_ALIGN); */ 680159967Sobrien physaddr = jbuf->physaddr; 681159967Sobrien } else { 682159967Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 683161284Sru ETHER_ALIGN, 0, /* alignment, boundary */ 684159967Sobrien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 685159967Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 686159967Sobrien NULL, NULL, /* filter, filterarg */ 687159967Sobrien MCLBYTES, 1, /* maxsize, nsegments */ 688159967Sobrien MCLBYTES, /* maxsegsize */ 689159967Sobrien BUS_DMA_ALLOCNOW, /* flags */ 690159967Sobrien NULL, NULL, /* lockfunc, lockarg */ 691159967Sobrien &data->rx_data_tag); 692159967Sobrien if (error != 0) { 693159967Sobrien printf("nfe%d: could not create DMA map\n", sc->nfe_unit); 694159967Sobrien goto fail; 695159967Sobrien } 696159967Sobrien 697159967Sobrien error = bus_dmamap_create(data->rx_data_tag, 0, &data->rx_data_map); 698159967Sobrien if (error != 0) { 699159967Sobrien printf("nfe%d: could not allocate mbuf cluster\n", sc->nfe_unit); 700159967Sobrien goto fail; 701159967Sobrien } 702159967Sobrien 703159967Sobrien MCLGET(data->m, M_DONTWAIT); 704159967Sobrien if (!(data->m->m_flags & M_EXT)) { 705159967Sobrien error = ENOMEM; 706159967Sobrien goto fail; 707159967Sobrien } 708159967Sobrien 709159967Sobrien error = bus_dmamap_load(data->rx_data_tag, data->rx_data_map, mtod(data->m, void *), 710159967Sobrien MCLBYTES, nfe_dma_map_segs, &data->rx_data_segs, BUS_DMA_NOWAIT); 711159967Sobrien if (error != 0) { 712161284Sru printf("nfe%d: could not load rx buf DMA map\n", sc->nfe_unit); 713159967Sobrien goto fail; 714159967Sobrien } 715159967Sobrien 716159967Sobrien data->rx_data_addr = data->rx_data_segs.ds_addr; 717159967Sobrien physaddr = data->rx_data_addr; 718159967Sobrien 719159967Sobrien } 720159967Sobrien 721159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 722159967Sobrien desc64 = &sc->rxq.desc64[i]; 723159967Sobrien#if defined(__LP64__) 724159967Sobrien desc64->physaddr[0] = htole32(physaddr >> 32); 725159967Sobrien#endif 726159967Sobrien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 727159967Sobrien desc64->length = htole16(sc->rxq.bufsz); 728159967Sobrien desc64->flags = htole16(NFE_RX_READY); 729159967Sobrien } else { 730159967Sobrien desc32 = &sc->rxq.desc32[i]; 731159967Sobrien desc32->physaddr = htole32(physaddr); 732159967Sobrien desc32->length = htole16(sc->rxq.bufsz); 733159967Sobrien desc32->flags = htole16(NFE_RX_READY); 734159967Sobrien } 735159967Sobrien 736159967Sobrien } 737159967Sobrien 738159967Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, BUS_DMASYNC_PREWRITE); 739159967Sobrien 740159967Sobrien return 0; 741159967Sobrien 742159967Sobrienfail: nfe_free_rx_ring(sc, ring); 743159967Sobrien 744159967Sobrien return error; 745159967Sobrien} 746159967Sobrien 747159967Sobrienstatic int 748159967Sobriennfe_jpool_alloc(struct nfe_softc *sc) 749159967Sobrien{ 750159967Sobrien struct nfe_rx_ring *ring = &sc->rxq; 751159967Sobrien struct nfe_jbuf *jbuf; 752159967Sobrien bus_addr_t physaddr; 753159967Sobrien caddr_t buf; 754159967Sobrien int i, error; 755159967Sobrien 756159967Sobrien /* 757159967Sobrien * Allocate a big chunk of DMA'able memory. 758159967Sobrien */ 759159967Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 760159967Sobrien PAGE_SIZE, 0, /* alignment, boundary */ 761159967Sobrien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 762159967Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 763159967Sobrien NULL, NULL, /* filter, filterarg */ 764159967Sobrien NFE_JPOOL_SIZE, 1, /* maxsize, nsegments */ 765159967Sobrien NFE_JPOOL_SIZE, /* maxsegsize */ 766159967Sobrien BUS_DMA_ALLOCNOW, /* flags */ 767159967Sobrien NULL, NULL, /* lockfunc, lockarg */ 768159967Sobrien &ring->rx_jumbo_tag); 769159967Sobrien if (error != 0) { 770159967Sobrien printf("nfe%d: could not create jumbo DMA tag\n", sc->nfe_unit); 771159967Sobrien goto fail; 772159967Sobrien } 773159967Sobrien error = bus_dmamem_alloc(ring->rx_jumbo_tag, (void **)&ring->jpool, BUS_DMA_NOWAIT, &ring->rx_jumbo_map); 774159967Sobrien if (error != 0) { 775159967Sobrien printf("nfe%d: could not create jumbo DMA memory\n", sc->nfe_unit); 776159967Sobrien goto fail; 777159967Sobrien } 778159967Sobrien 779159967Sobrien error = bus_dmamap_load(ring->rx_jumbo_tag, ring->rx_jumbo_map, ring->jpool, 780159967Sobrien NFE_JPOOL_SIZE, nfe_dma_map_segs, &ring->rx_jumbo_segs, BUS_DMA_NOWAIT); 781159967Sobrien if (error != 0) { 782159967Sobrien printf("nfe%d: could not load jumbo DMA map\n", sc->nfe_unit); 783159967Sobrien goto fail; 784159967Sobrien } 785159967Sobrien 786159967Sobrien /* ..and split it into 9KB chunks */ 787159967Sobrien SLIST_INIT(&ring->jfreelist); 788159967Sobrien 789159967Sobrien buf = ring->jpool; 790159967Sobrien ring->rx_jumbo_addr = ring->rx_jumbo_segs.ds_addr; 791159967Sobrien physaddr = ring->rx_jumbo_addr; 792159967Sobrien 793159967Sobrien for (i = 0; i < NFE_JPOOL_COUNT; i++) { 794159967Sobrien jbuf = &ring->jbuf[i]; 795159967Sobrien 796159967Sobrien jbuf->buf = buf; 797159967Sobrien jbuf->physaddr = physaddr; 798159967Sobrien 799159967Sobrien SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 800159967Sobrien 801159967Sobrien buf += NFE_JBYTES; 802159967Sobrien physaddr += NFE_JBYTES; 803159967Sobrien } 804159967Sobrien 805159967Sobrien return 0; 806159967Sobrien 807159967Sobrienfail: nfe_jpool_free(sc); 808159967Sobrien return error; 809159967Sobrien} 810159967Sobrien 811159967Sobrien 812159967Sobrienstatic void 813159967Sobriennfe_jpool_free(struct nfe_softc *sc) 814159967Sobrien{ 815159967Sobrien struct nfe_rx_ring *ring = &sc->rxq; 816159967Sobrien 817159967Sobrien if (ring->jpool != NULL) { 818159967Sobrien#if 0 819159967Sobrien bus_dmamem_unmap(ring->rx_jumbo_tag, ring->jpool, NFE_JPOOL_SIZE); 820159967Sobrien#endif 821159967Sobrien bus_dmamem_free(ring->rx_jumbo_tag, &ring->rx_jumbo_segs, ring->rx_jumbo_map); 822159967Sobrien } 823159967Sobrien if (ring->rx_jumbo_map != NULL) { 824159967Sobrien bus_dmamap_sync(ring->rx_jumbo_tag, ring->rx_jumbo_map, BUS_DMASYNC_POSTWRITE); 825159967Sobrien bus_dmamap_unload(ring->rx_jumbo_tag, ring->rx_jumbo_map); 826159967Sobrien bus_dmamap_destroy(ring->rx_jumbo_tag, ring->rx_jumbo_map); 827159967Sobrien } 828159967Sobrien} 829159967Sobrien 830159967Sobrienstatic struct nfe_jbuf * 831159967Sobriennfe_jalloc(struct nfe_softc *sc) 832159967Sobrien{ 833159967Sobrien struct nfe_jbuf *jbuf; 834159967Sobrien 835159967Sobrien jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 836159967Sobrien if (jbuf == NULL) 837159967Sobrien return NULL; 838159967Sobrien SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 839159967Sobrien return jbuf; 840159967Sobrien} 841159967Sobrien 842159967Sobrien/* 843159967Sobrien * This is called automatically by the network stack when the mbuf is freed. 844159967Sobrien * Caution must be taken that the NIC might be reset by the time the mbuf is 845159967Sobrien * freed. 846159967Sobrien */ 847159967Sobrienstatic void 848159967Sobriennfe_jfree(void *buf, void *arg) 849159967Sobrien{ 850159952Sobrien struct nfe_softc *sc = arg; 851159967Sobrien struct nfe_jbuf *jbuf; 852159967Sobrien int i; 853159952Sobrien 854159967Sobrien /* find the jbuf from the base pointer */ 855159967Sobrien i = ((vm_offset_t)buf - (vm_offset_t)sc->rxq.jpool) / NFE_JBYTES; 856159967Sobrien if (i < 0 || i >= NFE_JPOOL_COUNT) { 857159967Sobrien printf("nfe%d: request to free a buffer (%p) not managed by us\n", sc->nfe_unit, buf); 858159967Sobrien return; 859159967Sobrien } 860159967Sobrien jbuf = &sc->rxq.jbuf[i]; 861159952Sobrien 862159967Sobrien /* ..and put it back in the free list */ 863159967Sobrien SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext); 864159967Sobrien} 865159952Sobrien 866159967Sobrien 867159967Sobrienstatic void 868159967Sobriennfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 869159967Sobrien{ 870159967Sobrien int i; 871159967Sobrien 872159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 873159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 874159967Sobrien ring->desc64[i].length = htole16(ring->bufsz); 875159967Sobrien ring->desc64[i].flags = htole16(NFE_RX_READY); 876159967Sobrien } else { 877159967Sobrien ring->desc32[i].length = htole16(ring->bufsz); 878159967Sobrien ring->desc32[i].flags = htole16(NFE_RX_READY); 879159967Sobrien } 880159952Sobrien } 881159952Sobrien 882159967Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, BUS_DMASYNC_PREWRITE); 883159952Sobrien 884159967Sobrien ring->cur = ring->next = 0; 885159967Sobrien} 886159967Sobrien 887159967Sobrien 888159967Sobrienstatic void 889159967Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 890159967Sobrien{ 891159967Sobrien struct nfe_rx_data *data; 892159967Sobrien void *desc; 893159967Sobrien int i, descsize; 894159967Sobrien 895159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 896159967Sobrien desc = ring->desc64; 897159967Sobrien descsize = sizeof (struct nfe_desc64); 898159967Sobrien } else { 899159967Sobrien desc = ring->desc32; 900159967Sobrien descsize = sizeof (struct nfe_desc32); 901159952Sobrien } 902159952Sobrien 903159967Sobrien if (desc != NULL) { 904159967Sobrien bus_dmamap_sync(ring->rx_desc_tag, ring->rx_desc_map, BUS_DMASYNC_POSTWRITE); 905159967Sobrien bus_dmamap_unload(ring->rx_desc_tag, ring->rx_desc_map); 906159967Sobrien bus_dmamem_free(ring->rx_desc_tag, desc, ring->rx_desc_map); 907159967Sobrien bus_dma_tag_destroy(ring->rx_desc_tag); 908159967Sobrien } 909159967Sobrien 910159967Sobrien 911159967Sobrien if (sc->nfe_flags & NFE_USE_JUMBO) { 912159967Sobrien nfe_jpool_free(sc); 913159967Sobrien } else { 914159967Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 915159967Sobrien data = &ring->data[i]; 916159967Sobrien 917159967Sobrien if (data->rx_data_map != NULL) { 918159967Sobrien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, BUS_DMASYNC_POSTREAD); 919159967Sobrien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 920159967Sobrien bus_dmamap_destroy(data->rx_data_tag, data->rx_data_map); 921159967Sobrien bus_dma_tag_destroy(data->rx_data_tag); 922159967Sobrien } 923159967Sobrien if (data->m != NULL) 924159967Sobrien m_freem(data->m); 925159967Sobrien } 926159967Sobrien } 927159952Sobrien} 928159952Sobrien 929159967Sobrienstatic int 930159967Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 931159952Sobrien{ 932159967Sobrien int i, error; 933159967Sobrien void **desc; 934159967Sobrien int descsize; 935159952Sobrien 936159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 937159967Sobrien desc = (void **)&ring->desc64; 938159967Sobrien descsize = sizeof (struct nfe_desc64); 939159967Sobrien } else { 940159967Sobrien desc = (void **)&ring->desc32; 941159967Sobrien descsize = sizeof (struct nfe_desc32); 942159967Sobrien } 943159952Sobrien 944159967Sobrien ring->queued = 0; 945159967Sobrien ring->cur = ring->next = 0; 946159967Sobrien 947159967Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 948159967Sobrien PAGE_SIZE, 0, /* alignment, boundary */ 949159967Sobrien BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 950159967Sobrien BUS_SPACE_MAXADDR, /* highaddr */ 951159967Sobrien NULL, NULL, /* filter, filterarg */ 952159967Sobrien NFE_TX_RING_COUNT * descsize, 1, /* maxsize, nsegments */ 953159967Sobrien NFE_TX_RING_COUNT * descsize, /* maxsegsize */ 954159967Sobrien BUS_DMA_ALLOCNOW, /* flags */ 955159967Sobrien NULL, NULL, /* lockfunc, lockarg */ 956159967Sobrien &ring->tx_desc_tag); 957159967Sobrien if (error != 0) { 958159967Sobrien printf("nfe%d: could not create desc DMA tag\n", sc->nfe_unit); 959159967Sobrien goto fail; 960159952Sobrien } 961159952Sobrien 962159967Sobrien error = bus_dmamem_alloc(ring->tx_desc_tag, (void **)desc, BUS_DMA_NOWAIT, &ring->tx_desc_map); 963159967Sobrien if (error != 0) { 964159967Sobrien printf("nfe%d: could not create desc DMA map\n", sc->nfe_unit); 965159967Sobrien goto fail; 966159967Sobrien } 967159967Sobrien 968159967Sobrien error = bus_dmamap_load(ring->tx_desc_tag, ring->tx_desc_map, *desc, 969159967Sobrien NFE_TX_RING_COUNT * descsize, nfe_dma_map_segs, &ring->tx_desc_segs, BUS_DMA_NOWAIT); 970159967Sobrien if (error != 0) { 971159967Sobrien printf("nfe%d: could not load desc DMA map\n", sc->nfe_unit); 972159967Sobrien goto fail; 973159967Sobrien } 974159967Sobrien 975159967Sobrien bzero(*desc, NFE_TX_RING_COUNT * descsize); 976159967Sobrien 977159967Sobrien ring->tx_desc_addr = ring->tx_desc_segs.ds_addr; 978159967Sobrien ring->physaddr = ring->tx_desc_addr; 979159967Sobrien 980159967Sobrien error = bus_dma_tag_create(sc->nfe_parent_tag, 981159967Sobrien ETHER_ALIGN, 0, 982159967Sobrien BUS_SPACE_MAXADDR_32BIT, 983159967Sobrien BUS_SPACE_MAXADDR, 984159967Sobrien NULL, NULL, 985159967Sobrien NFE_JBYTES, NFE_MAX_SCATTER, 986159967Sobrien NFE_JBYTES, 987159967Sobrien BUS_DMA_ALLOCNOW, 988159967Sobrien NULL, NULL, 989159967Sobrien &ring->tx_data_tag); 990159967Sobrien if (error != 0) { 991159967Sobrien printf("nfe%d: could not create DMA tag\n", sc->nfe_unit); 992159967Sobrien goto fail; 993159967Sobrien } 994159967Sobrien 995159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 996159967Sobrien error = bus_dmamap_create(ring->tx_data_tag, 0, &ring->data[i].tx_data_map); 997159967Sobrien if (error != 0) { 998159967Sobrien printf("nfe%d: could not create DMA map\n", sc->nfe_unit); 999159967Sobrien goto fail; 1000159967Sobrien } 1001159967Sobrien } 1002159967Sobrien 1003159967Sobrien return 0; 1004159967Sobrien 1005159967Sobrienfail: nfe_free_tx_ring(sc, ring); 1006159967Sobrien return error; 1007159967Sobrien} 1008159967Sobrien 1009159967Sobrien 1010159967Sobrienstatic void 1011159967Sobriennfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1012159967Sobrien{ 1013159967Sobrien struct nfe_tx_data *data; 1014159967Sobrien int i; 1015159967Sobrien 1016159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1017159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 1018159967Sobrien ring->desc64[i].flags = 0; 1019159967Sobrien else 1020159967Sobrien ring->desc32[i].flags = 0; 1021159967Sobrien 1022159967Sobrien data = &ring->data[i]; 1023159967Sobrien 1024159967Sobrien if (data->m != NULL) { 1025159967Sobrien bus_dmamap_sync(ring->tx_data_tag, data->active, BUS_DMASYNC_POSTWRITE); 1026159967Sobrien bus_dmamap_unload(ring->tx_data_tag, data->active); 1027159967Sobrien m_freem(data->m); 1028159967Sobrien data->m = NULL; 1029159967Sobrien } 1030159967Sobrien } 1031159967Sobrien 1032159967Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, BUS_DMASYNC_PREWRITE); 1033159967Sobrien 1034159967Sobrien ring->queued = 0; 1035159967Sobrien ring->cur = ring->next = 0; 1036159967Sobrien} 1037159967Sobrien 1038159967Sobrienstatic void 1039159967Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1040159967Sobrien{ 1041159967Sobrien struct nfe_tx_data *data; 1042159967Sobrien void *desc; 1043159967Sobrien int i, descsize; 1044159967Sobrien 1045159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1046159967Sobrien desc = ring->desc64; 1047159967Sobrien descsize = sizeof (struct nfe_desc64); 1048159967Sobrien } else { 1049159967Sobrien desc = ring->desc32; 1050159967Sobrien descsize = sizeof (struct nfe_desc32); 1051159967Sobrien } 1052159967Sobrien 1053159967Sobrien if (desc != NULL) { 1054159967Sobrien bus_dmamap_sync(ring->tx_desc_tag, ring->tx_desc_map, BUS_DMASYNC_POSTWRITE); 1055159967Sobrien bus_dmamap_unload(ring->tx_desc_tag, ring->tx_desc_map); 1056159967Sobrien bus_dmamem_free(ring->tx_desc_tag, desc, ring->tx_desc_map); 1057159967Sobrien bus_dma_tag_destroy(ring->tx_desc_tag); 1058159967Sobrien } 1059159967Sobrien 1060159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1061159967Sobrien data = &ring->data[i]; 1062159967Sobrien 1063159967Sobrien if (data->m != NULL) { 1064159967Sobrien bus_dmamap_sync(ring->tx_data_tag, data->active, BUS_DMASYNC_POSTWRITE); 1065159967Sobrien bus_dmamap_unload(ring->tx_data_tag, data->active); 1066159967Sobrien m_freem(data->m); 1067159967Sobrien } 1068159967Sobrien } 1069159967Sobrien 1070159967Sobrien /* ..and now actually destroy the DMA mappings */ 1071159967Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1072159967Sobrien data = &ring->data[i]; 1073159967Sobrien if (data->tx_data_map == NULL) 1074159967Sobrien continue; 1075159967Sobrien bus_dmamap_destroy(ring->tx_data_tag, data->tx_data_map); 1076159967Sobrien } 1077159967Sobrien 1078159967Sobrien bus_dma_tag_destroy(ring->tx_data_tag); 1079159967Sobrien} 1080159967Sobrien 1081159967Sobrien#ifdef DEVICE_POLLING 1082159967Sobrienstatic poll_handler_t nfe_poll; 1083159967Sobrien 1084159967Sobrienstatic void 1085159967Sobriennfe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1086159967Sobrien{ 1087159967Sobrien struct nfe_softc *sc = ifp->if_softc; 1088159967Sobrien 1089159967Sobrien NFE_LOCK(sc); 1090159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1091159967Sobrien nfe_poll_locked(ifp, cmd, count); 1092159967Sobrien NFE_UNLOCK(sc); 1093159967Sobrien} 1094159967Sobrien 1095159967Sobrien 1096159967Sobrienstatic void 1097159967Sobriennfe_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) 1098159967Sobrien{ 1099159967Sobrien struct nfe_softc *sc = ifp->if_softc; 1100159967Sobrien u_int32_t r; 1101159967Sobrien 1102159967Sobrien NFE_LOCK_ASSERT(sc); 1103159967Sobrien 1104159967Sobrien if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1105159967Sobrien return; 1106159967Sobrien } 1107159967Sobrien 1108159967Sobrien sc->rxcycles = count; 1109159967Sobrien nfe_rxeof(sc); 1110159967Sobrien nfe_txeof(sc); 1111159967Sobrien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1112159967Sobrien nfe_start_locked(ifp); 1113159967Sobrien 1114159967Sobrien if (cmd == POLL_AND_CHECK_STATUS) { 1115159967Sobrien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1116159967Sobrien return; 1117159967Sobrien } 1118159967Sobrien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1119159967Sobrien 1120159967Sobrien if (r & NFE_IRQ_LINK) { 1121159967Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1122159967Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1123159967Sobrien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1124159967Sobrien } 1125159967Sobrien } 1126159967Sobrien} 1127159967Sobrien#endif /* DEVICE_POLLING */ 1128159967Sobrien 1129159967Sobrien 1130159967Sobrienstatic int 1131159967Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1132159967Sobrien{ 1133159967Sobrien int error = 0; 1134159967Sobrien struct nfe_softc *sc = ifp->if_softc; 1135159967Sobrien struct ifreq *ifr = (struct ifreq *) data; 1136159967Sobrien struct mii_data *mii; 1137159967Sobrien 1138159952Sobrien switch (cmd) { 1139159952Sobrien case SIOCSIFMTU: 1140159952Sobrien if (ifr->ifr_mtu < ETHERMIN || 1141159967Sobrien ((sc->nfe_flags & NFE_USE_JUMBO) && 1142159952Sobrien ifr->ifr_mtu > ETHERMTU_JUMBO) || 1143159967Sobrien (!(sc->nfe_flags & NFE_USE_JUMBO) && 1144159952Sobrien ifr->ifr_mtu > ETHERMTU)) 1145159952Sobrien error = EINVAL; 1146159967Sobrien else if (ifp->if_mtu != ifr->ifr_mtu) { 1147159952Sobrien ifp->if_mtu = ifr->ifr_mtu; 1148159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1149159967Sobrien nfe_init(sc); 1150159967Sobrien } 1151159952Sobrien break; 1152159952Sobrien case SIOCSIFFLAGS: 1153159967Sobrien NFE_LOCK(sc); 1154159952Sobrien if (ifp->if_flags & IFF_UP) { 1155159952Sobrien /* 1156159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 1157159952Sobrien * don't do a full re-init of the chip, just update 1158159952Sobrien * the Rx filter. 1159159952Sobrien */ 1160159967Sobrien if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && 1161159967Sobrien ((ifp->if_flags ^ sc->nfe_if_flags) & 1162159967Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) 1163159952Sobrien nfe_setmulti(sc); 1164159967Sobrien else 1165159967Sobrien nfe_init_locked(sc); 1166159952Sobrien } else { 1167159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1168159952Sobrien nfe_stop(ifp, 1); 1169159952Sobrien } 1170159967Sobrien sc->nfe_if_flags = ifp->if_flags; 1171159967Sobrien NFE_UNLOCK(sc); 1172159967Sobrien error = 0; 1173159952Sobrien break; 1174159952Sobrien case SIOCADDMULTI: 1175159952Sobrien case SIOCDELMULTI: 1176159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1177159967Sobrien NFE_LOCK(sc); 1178159967Sobrien nfe_setmulti(sc); 1179159967Sobrien NFE_UNLOCK(sc); 1180159952Sobrien error = 0; 1181159952Sobrien } 1182159952Sobrien break; 1183159952Sobrien case SIOCSIFMEDIA: 1184159952Sobrien case SIOCGIFMEDIA: 1185159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1186159967Sobrien error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1187159952Sobrien break; 1188159967Sobrien case SIOCSIFCAP: 1189159967Sobrien { 1190159967Sobrien int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1191159967Sobrien#ifdef DEVICE_POLLING 1192159967Sobrien if (mask & IFCAP_POLLING) { 1193159967Sobrien if (ifr->ifr_reqcap & IFCAP_POLLING) { 1194159967Sobrien error = ether_poll_register(nfe_poll, ifp); 1195159967Sobrien if (error) 1196159967Sobrien return(error); 1197159967Sobrien NFE_LOCK(sc); 1198159967Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1199159967Sobrien ifp->if_capenable |= IFCAP_POLLING; 1200159967Sobrien NFE_UNLOCK(sc); 1201159967Sobrien } else { 1202159967Sobrien error = ether_poll_deregister(ifp); 1203159967Sobrien /* Enable interrupt even in error case */ 1204159967Sobrien NFE_LOCK(sc); 1205159967Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1206159967Sobrien ifp->if_capenable &= ~IFCAP_POLLING; 1207159967Sobrien NFE_UNLOCK(sc); 1208159967Sobrien } 1209159967Sobrien } 1210159967Sobrien#endif 1211159967Sobrien if (mask & IFCAP_HWCSUM) { 1212159967Sobrien ifp->if_capenable ^= IFCAP_HWCSUM; 1213159967Sobrien if (IFCAP_HWCSUM & ifp->if_capenable && 1214159967Sobrien IFCAP_HWCSUM & ifp->if_capabilities) 1215159967Sobrien ifp->if_hwassist = NFE_CSUM_FEATURES; 1216159967Sobrien else 1217159967Sobrien ifp->if_hwassist = 0; 1218159967Sobrien } 1219159967Sobrien } 1220159967Sobrien break; 1221159967Sobrien 1222159952Sobrien default: 1223159967Sobrien error = ether_ioctl(ifp, cmd, data); 1224159967Sobrien break; 1225159952Sobrien } 1226159952Sobrien 1227159952Sobrien return error; 1228159952Sobrien} 1229159952Sobrien 1230159967Sobrien 1231159967Sobrienstatic void nfe_intr(void *arg) 1232159967Sobrien{ 1233159967Sobrien struct nfe_softc *sc = arg; 1234159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1235159967Sobrien u_int32_t r; 1236159967Sobrien 1237159967Sobrien NFE_LOCK(sc); 1238159967Sobrien 1239159967Sobrien#ifdef DEVICE_POLLING 1240159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) { 1241159967Sobrien NFE_UNLOCK(sc); 1242159967Sobrien return; 1243159967Sobrien } 1244159967Sobrien#endif 1245159967Sobrien 1246159967Sobrien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) { 1247159967Sobrien NFE_UNLOCK(sc); 1248159967Sobrien return; /* not for us */ 1249159967Sobrien } 1250159967Sobrien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 1251159967Sobrien 1252159967Sobrien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 1253159967Sobrien 1254159967Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1255159967Sobrien 1256159967Sobrien if (r & NFE_IRQ_LINK) { 1257159967Sobrien NFE_READ(sc, NFE_PHY_STATUS); 1258159967Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1259159967Sobrien DPRINTF(("nfe%d: link state changed\n", sc->nfe_unit)); 1260159967Sobrien } 1261159967Sobrien 1262159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1263159967Sobrien /* check Rx ring */ 1264159967Sobrien nfe_rxeof(sc); 1265159967Sobrien /* check Tx ring */ 1266159967Sobrien nfe_txeof(sc); 1267159967Sobrien } 1268159967Sobrien 1269159967Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1270159967Sobrien 1271159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING && 1272159967Sobrien !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1273159967Sobrien nfe_start_locked(ifp); 1274159967Sobrien 1275159967Sobrien NFE_UNLOCK(sc); 1276159967Sobrien 1277159967Sobrien return; 1278159967Sobrien} 1279159967Sobrien 1280159967Sobrienstatic void 1281159952Sobriennfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1282159952Sobrien{ 1283159967Sobrien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1284159952Sobrien} 1285159952Sobrien 1286159967Sobrienstatic void 1287159952Sobriennfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1288159952Sobrien{ 1289159967Sobrien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1290159952Sobrien} 1291159952Sobrien 1292159967Sobrienstatic void 1293159952Sobriennfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 1294159952Sobrien{ 1295159967Sobrien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1296159952Sobrien} 1297159952Sobrien 1298159967Sobrienstatic void 1299159952Sobriennfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 1300159952Sobrien{ 1301159967Sobrien bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, ops); 1302159952Sobrien} 1303159952Sobrien 1304159967Sobrienstatic void 1305159952Sobriennfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 1306159952Sobrien{ 1307159967Sobrien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1308159952Sobrien} 1309159952Sobrien 1310159967Sobrienstatic void 1311159952Sobriennfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 1312159952Sobrien{ 1313159967Sobrien 1314159967Sobrien bus_dmamap_sync(sc->rxq.rx_desc_tag, sc->rxq.rx_desc_map, ops); 1315159952Sobrien} 1316159952Sobrien 1317159967Sobrienstatic void nfe_rxeof(struct nfe_softc *sc) 1318159952Sobrien{ 1319159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1320159967Sobrien struct nfe_desc32 *desc32=NULL; 1321159967Sobrien struct nfe_desc64 *desc64=NULL; 1322159952Sobrien struct nfe_rx_data *data; 1323159952Sobrien struct nfe_jbuf *jbuf; 1324159952Sobrien struct mbuf *m, *mnew; 1325159952Sobrien bus_addr_t physaddr; 1326159967Sobrien u_int16_t flags; 1327159952Sobrien int error, len; 1328159967Sobrien#if NVLAN > 1 1329159967Sobrien u_int16_t vlan_tag = 0; 1330159967Sobrien int have_tag = 0; 1331159967Sobrien#endif 1332159952Sobrien 1333159967Sobrien NFE_LOCK_ASSERT(sc); 1334159967Sobrien 1335159952Sobrien for (;;) { 1336159967Sobrien 1337159967Sobrien#ifdef DEVICE_POLLING 1338159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) { 1339159967Sobrien if (sc->rxcycles <= 0) 1340159967Sobrien break; 1341159967Sobrien sc->rxcycles--; 1342159967Sobrien } 1343159967Sobrien#endif 1344159967Sobrien 1345159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 1346159952Sobrien 1347159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1348159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 1349159952Sobrien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1350159952Sobrien 1351159952Sobrien flags = letoh16(desc64->flags); 1352159952Sobrien len = letoh16(desc64->length) & 0x3fff; 1353159967Sobrien 1354159967Sobrien#if NVLAN > 1 1355159967Sobrien if (flags & NFE_TX_VLAN_TAG) { 1356159967Sobrien have_tag = 1; 1357159967Sobrien vlan_tag = desc64->vtag; 1358159967Sobrien } 1359159967Sobrien#endif 1360159967Sobrien 1361159952Sobrien } else { 1362159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 1363159952Sobrien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1364159952Sobrien 1365159952Sobrien flags = letoh16(desc32->flags); 1366159952Sobrien len = letoh16(desc32->length) & 0x3fff; 1367159952Sobrien } 1368159952Sobrien 1369159952Sobrien if (flags & NFE_RX_READY) 1370159952Sobrien break; 1371159952Sobrien 1372159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1373159952Sobrien if (!(flags & NFE_RX_VALID_V1)) 1374159952Sobrien goto skip; 1375159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 1376159952Sobrien flags &= ~NFE_RX_ERROR; 1377159952Sobrien len--; /* fix buffer length */ 1378159952Sobrien } 1379159952Sobrien } else { 1380159952Sobrien if (!(flags & NFE_RX_VALID_V2)) 1381159952Sobrien goto skip; 1382159952Sobrien 1383159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 1384159952Sobrien flags &= ~NFE_RX_ERROR; 1385159952Sobrien len--; /* fix buffer length */ 1386159952Sobrien } 1387159952Sobrien } 1388159952Sobrien 1389159952Sobrien if (flags & NFE_RX_ERROR) { 1390159952Sobrien ifp->if_ierrors++; 1391159952Sobrien goto skip; 1392159952Sobrien } 1393159952Sobrien 1394159952Sobrien /* 1395159952Sobrien * Try to allocate a new mbuf for this ring element and load 1396159952Sobrien * it before processing the current mbuf. If the ring element 1397159952Sobrien * cannot be loaded, drop the received packet and reuse the 1398159952Sobrien * old mbuf. In the unlikely case that the old mbuf can't be 1399159952Sobrien * reloaded either, explicitly panic. 1400159952Sobrien */ 1401159952Sobrien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 1402159952Sobrien if (mnew == NULL) { 1403159952Sobrien ifp->if_ierrors++; 1404159952Sobrien goto skip; 1405159952Sobrien } 1406159952Sobrien 1407159967Sobrien if (sc->nfe_flags & NFE_USE_JUMBO) { 1408159952Sobrien if ((jbuf = nfe_jalloc(sc)) == NULL) { 1409159952Sobrien m_freem(mnew); 1410159952Sobrien ifp->if_ierrors++; 1411159952Sobrien goto skip; 1412159952Sobrien } 1413159967Sobrien mnew->m_data = (void *)jbuf->buf; 1414159967Sobrien mnew->m_len = mnew->m_pkthdr.len = NFE_JBYTES; 1415159967Sobrien MEXTADD(mnew, jbuf->buf, NFE_JBYTES, nfe_jfree, 1416159967Sobrien (struct nfe_softc *)sc, 0 , EXT_NET_DRV); 1417159952Sobrien 1418159967Sobrien bus_dmamap_sync(sc->rxq.rx_jumbo_tag, 1419159967Sobrien sc->rxq.rx_jumbo_map, BUS_DMASYNC_POSTREAD); 1420159952Sobrien physaddr = jbuf->physaddr; 1421159952Sobrien } else { 1422159952Sobrien MCLGET(mnew, M_DONTWAIT); 1423159952Sobrien if (!(mnew->m_flags & M_EXT)) { 1424159952Sobrien m_freem(mnew); 1425159952Sobrien ifp->if_ierrors++; 1426159952Sobrien goto skip; 1427159952Sobrien } 1428159952Sobrien 1429159967Sobrien bus_dmamap_sync(data->rx_data_tag, data->rx_data_map, 1430159967Sobrien BUS_DMASYNC_POSTREAD); 1431159967Sobrien bus_dmamap_unload(data->rx_data_tag, data->rx_data_map); 1432159967Sobrien error = bus_dmamap_load(data->rx_data_tag, 1433159967Sobrien data->rx_data_map, mtod(mnew, void *), MCLBYTES, 1434159967Sobrien nfe_dma_map_segs, &data->rx_data_segs, 1435159967Sobrien BUS_DMA_NOWAIT); 1436159952Sobrien if (error != 0) { 1437159952Sobrien m_freem(mnew); 1438159952Sobrien 1439159952Sobrien /* try to reload the old mbuf */ 1440159967Sobrien error = bus_dmamap_load(data->rx_data_tag, 1441159967Sobrien data->rx_data_map, mtod(data->m, void *), 1442159967Sobrien MCLBYTES, nfe_dma_map_segs, 1443159967Sobrien &data->rx_data_segs, BUS_DMA_NOWAIT); 1444159952Sobrien if (error != 0) { 1445159952Sobrien /* very unlikely that it will fail.. */ 1446159967Sobrien panic("nfe%d: could not load old rx mbuf", 1447159967Sobrien sc->nfe_unit); 1448159952Sobrien } 1449159952Sobrien ifp->if_ierrors++; 1450159952Sobrien goto skip; 1451159952Sobrien } 1452159967Sobrien data->rx_data_addr = data->rx_data_segs.ds_addr; 1453159967Sobrien physaddr = data->rx_data_addr; 1454159952Sobrien } 1455159952Sobrien 1456159952Sobrien /* 1457159952Sobrien * New mbuf successfully loaded, update Rx ring and continue 1458159952Sobrien * processing. 1459159952Sobrien */ 1460159952Sobrien m = data->m; 1461159952Sobrien data->m = mnew; 1462159952Sobrien 1463159952Sobrien /* finalize mbuf */ 1464159952Sobrien m->m_pkthdr.len = m->m_len = len; 1465159952Sobrien m->m_pkthdr.rcvif = ifp; 1466159952Sobrien 1467159967Sobrien 1468159967Sobrien#if defined(NFE_CSUM) 1469159967Sobrien if ((sc->nfe_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) { 1470159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1471159967Sobrien if (flags & NFE_RX_IP_CSUMOK_V2) { 1472159967Sobrien m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1473159967Sobrien } 1474159967Sobrien if (flags & NFE_RX_UDP_CSUMOK_V2 || 1475159967Sobrien flags & NFE_RX_TCP_CSUMOK_V2) { 1476159967Sobrien m->m_pkthdr.csum_flags |= 1477159967Sobrien CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 1478159967Sobrien m->m_pkthdr.csum_data = 0xffff; 1479159967Sobrien } 1480159952Sobrien } 1481159952Sobrien#endif 1482159952Sobrien 1483159967Sobrien#if NVLAN > 1 1484159967Sobrien if (have_tag) { 1485159967Sobrien VLAN_INPUT_TAG_NEW(ifp, m, vlan_tag); 1486159967Sobrien if (m == NULL) 1487159967Sobrien continue; 1488159967Sobrien } 1489159952Sobrien#endif 1490159967Sobrien 1491159952Sobrien ifp->if_ipackets++; 1492159952Sobrien 1493159967Sobrien NFE_UNLOCK(sc); 1494159967Sobrien (*ifp->if_input)(ifp, m); 1495159967Sobrien NFE_LOCK(sc); 1496159967Sobrien 1497159952Sobrien /* update mapping address in h/w descriptor */ 1498159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1499159952Sobrien#if defined(__LP64__) 1500159952Sobrien desc64->physaddr[0] = htole32(physaddr >> 32); 1501159952Sobrien#endif 1502159952Sobrien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1503159952Sobrien } else { 1504159952Sobrien desc32->physaddr = htole32(physaddr); 1505159952Sobrien } 1506159952Sobrien 1507159967Sobrienskip: if (sc->nfe_flags & NFE_40BIT_ADDR) { 1508159952Sobrien desc64->length = htole16(sc->rxq.bufsz); 1509159952Sobrien desc64->flags = htole16(NFE_RX_READY); 1510159952Sobrien 1511159952Sobrien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 1512159952Sobrien } else { 1513159952Sobrien desc32->length = htole16(sc->rxq.bufsz); 1514159952Sobrien desc32->flags = htole16(NFE_RX_READY); 1515159952Sobrien 1516159952Sobrien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 1517159952Sobrien } 1518159952Sobrien 1519159952Sobrien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 1520159952Sobrien } 1521159952Sobrien} 1522159952Sobrien 1523159967Sobrienstatic void nfe_txeof(struct nfe_softc *sc) 1524159952Sobrien{ 1525159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1526159952Sobrien struct nfe_desc32 *desc32; 1527159952Sobrien struct nfe_desc64 *desc64; 1528159952Sobrien struct nfe_tx_data *data = NULL; 1529159967Sobrien u_int16_t flags; 1530159952Sobrien 1531159967Sobrien NFE_LOCK_ASSERT(sc); 1532159967Sobrien 1533159952Sobrien while (sc->txq.next != sc->txq.cur) { 1534159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1535159952Sobrien desc64 = &sc->txq.desc64[sc->txq.next]; 1536159952Sobrien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 1537159952Sobrien 1538159952Sobrien flags = letoh16(desc64->flags); 1539159952Sobrien } else { 1540159952Sobrien desc32 = &sc->txq.desc32[sc->txq.next]; 1541159952Sobrien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 1542159952Sobrien 1543159952Sobrien flags = letoh16(desc32->flags); 1544159952Sobrien } 1545159952Sobrien 1546159952Sobrien if (flags & NFE_TX_VALID) 1547159952Sobrien break; 1548159952Sobrien 1549159952Sobrien data = &sc->txq.data[sc->txq.next]; 1550159952Sobrien 1551159967Sobrien if ((sc->nfe_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1552159952Sobrien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 1553159952Sobrien goto skip; 1554159952Sobrien 1555159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 1556159967Sobrien printf("nfe%d: tx v1 error 0x%4b\n", 1557159967Sobrien sc->nfe_unit, flags, NFE_V1_TXERR); 1558159967Sobrien 1559159952Sobrien ifp->if_oerrors++; 1560159952Sobrien } else 1561159952Sobrien ifp->if_opackets++; 1562159952Sobrien } else { 1563159952Sobrien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 1564159952Sobrien goto skip; 1565159952Sobrien 1566159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 1567159967Sobrien printf("nfe%d: tx v1 error 0x%4b\n", 1568159967Sobrien sc->nfe_unit, flags, NFE_V2_TXERR); 1569159967Sobrien 1570159952Sobrien ifp->if_oerrors++; 1571159952Sobrien } else 1572159952Sobrien ifp->if_opackets++; 1573159952Sobrien } 1574159952Sobrien 1575159952Sobrien if (data->m == NULL) { /* should not get there */ 1576159967Sobrien printf("nfe%d: last fragment bit w/o associated mbuf!\n", 1577159967Sobrien sc->nfe_unit); 1578159952Sobrien goto skip; 1579159952Sobrien } 1580159952Sobrien 1581159952Sobrien /* last fragment of the mbuf chain transmitted */ 1582159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, data->active, 1583159967Sobrien BUS_DMASYNC_POSTWRITE); 1584159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, data->active); 1585159952Sobrien m_freem(data->m); 1586159952Sobrien data->m = NULL; 1587159952Sobrien 1588159952Sobrien ifp->if_timer = 0; 1589159952Sobrien 1590159952Sobrienskip: sc->txq.queued--; 1591159952Sobrien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 1592159952Sobrien } 1593159952Sobrien 1594159952Sobrien if (data != NULL) { /* at least one slot freed */ 1595159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1596159967Sobrien nfe_start_locked(ifp); 1597159952Sobrien } 1598159952Sobrien} 1599159952Sobrien 1600159967Sobrienstatic int nfe_encap(struct nfe_softc *sc, struct mbuf *m0) 1601159952Sobrien{ 1602159967Sobrien struct nfe_desc32 *desc32=NULL; 1603159967Sobrien struct nfe_desc64 *desc64=NULL; 1604159967Sobrien struct nfe_tx_data *data=NULL; 1605159952Sobrien bus_dmamap_t map; 1606159967Sobrien u_int16_t flags = NFE_TX_VALID; 1607159952Sobrien#if NVLAN > 0 1608159967Sobrien struct m_tag *vtag; 1609159952Sobrien#endif 1610159967Sobrien bus_dma_segment_t segs[NFE_MAX_SCATTER]; 1611159967Sobrien int nsegs; 1612159952Sobrien int error, i; 1613159952Sobrien 1614159967Sobrien map = sc->txq.data[sc->txq.cur].tx_data_map; 1615159952Sobrien 1616159967Sobrien error = bus_dmamap_load_mbuf_sg(sc->txq.tx_data_tag, map, m0, segs, 1617159967Sobrien &nsegs, BUS_DMA_NOWAIT); 1618159967Sobrien 1619159952Sobrien if (error != 0) { 1620159967Sobrien printf("nfe%d: could not map mbuf (error %d)\n", sc->nfe_unit, 1621159967Sobrien error); 1622159952Sobrien return error; 1623159952Sobrien } 1624159952Sobrien 1625159967Sobrien if (sc->txq.queued + nsegs >= NFE_TX_RING_COUNT - 1) { 1626159967Sobrien bus_dmamap_unload(sc->txq.tx_data_tag, map); 1627159952Sobrien return ENOBUFS; 1628159952Sobrien } 1629159952Sobrien 1630159967Sobrien 1631159952Sobrien#if NVLAN > 0 1632159952Sobrien /* setup h/w VLAN tagging */ 1633159967Sobrien vtag = VLAN_OUTPUT_TAG(sc->nfe_ifp, m0); 1634159952Sobrien#endif 1635159967Sobrien 1636159952Sobrien#ifdef NFE_CSUM 1637159967Sobrien if (m0->m_pkthdr.csum_flags & CSUM_IP) 1638159952Sobrien flags |= NFE_TX_IP_CSUM; 1639159967Sobrien if (m0->m_pkthdr.csum_flags & CSUM_TCP) 1640159952Sobrien flags |= NFE_TX_TCP_CSUM; 1641159967Sobrien if (m0->m_pkthdr.csum_flags & CSUM_UDP) 1642159967Sobrien flags |= NFE_TX_TCP_CSUM; 1643159952Sobrien#endif 1644159952Sobrien 1645159967Sobrien for (i = 0; i < nsegs; i++) { 1646159952Sobrien data = &sc->txq.data[sc->txq.cur]; 1647159952Sobrien 1648159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1649159952Sobrien desc64 = &sc->txq.desc64[sc->txq.cur]; 1650159952Sobrien#if defined(__LP64__) 1651159967Sobrien desc64->physaddr[0] = htole32(segs[i].ds_addr >> 32); 1652159952Sobrien#endif 1653159967Sobrien desc64->physaddr[1] = htole32(segs[i].ds_addr & 1654159967Sobrien 0xffffffff); 1655159967Sobrien desc64->length = htole16(segs[i].ds_len - 1); 1656159952Sobrien desc64->flags = htole16(flags); 1657159952Sobrien#if NVLAN > 0 1658159967Sobrien desc64->vtag = htole32(NFE_TX_VTAG | 1659159967Sobrien VLAN_TAG_VALUE(vtag)); 1660159952Sobrien#endif 1661159952Sobrien } else { 1662159952Sobrien desc32 = &sc->txq.desc32[sc->txq.cur]; 1663159952Sobrien 1664159967Sobrien desc32->physaddr = htole32(segs[i].ds_addr); 1665159967Sobrien desc32->length = htole16(segs[i].ds_len - 1); 1666159952Sobrien desc32->flags = htole16(flags); 1667159952Sobrien } 1668159952Sobrien 1669159952Sobrien /* csum flags and vtag belong to the first fragment only */ 1670159967Sobrien if (nsegs > 1) { 1671159952Sobrien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 1672159952Sobrien#if NVLAN > 0 1673159952Sobrien vtag = 0; 1674159952Sobrien#endif 1675159952Sobrien } 1676159967Sobrien 1677159952Sobrien sc->txq.queued++; 1678159952Sobrien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 1679159952Sobrien } 1680159952Sobrien 1681159952Sobrien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 1682159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) { 1683159952Sobrien flags |= NFE_TX_LASTFRAG_V2; 1684159952Sobrien desc64->flags = htole16(flags); 1685159952Sobrien } else { 1686159967Sobrien if (sc->nfe_flags & NFE_JUMBO_SUP) 1687159952Sobrien flags |= NFE_TX_LASTFRAG_V2; 1688159952Sobrien else 1689159952Sobrien flags |= NFE_TX_LASTFRAG_V1; 1690159952Sobrien desc32->flags = htole16(flags); 1691159952Sobrien } 1692159952Sobrien 1693159952Sobrien data->m = m0; 1694159952Sobrien data->active = map; 1695159967Sobrien data->nsegs = nsegs; 1696159952Sobrien 1697159967Sobrien bus_dmamap_sync(sc->txq.tx_data_tag, map, BUS_DMASYNC_PREWRITE); 1698159952Sobrien 1699159952Sobrien return 0; 1700159952Sobrien} 1701159952Sobrien 1702159967Sobrien 1703159967Sobrienstatic void nfe_setmulti(struct nfe_softc *sc) 1704159952Sobrien{ 1705159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1706159967Sobrien struct ifmultiaddr *ifma; 1707159967Sobrien u_int8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 1708159967Sobrien u_int32_t filter = NFE_RXFILTER_MAGIC; 1709159967Sobrien u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = 1710159967Sobrien { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 1711159967Sobrien int i; 1712159967Sobrien 1713159967Sobrien NFE_LOCK_ASSERT(sc); 1714159967Sobrien 1715159967Sobrien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1716159967Sobrien bzero(addr, ETHER_ADDR_LEN); 1717159967Sobrien bzero(mask, ETHER_ADDR_LEN); 1718159967Sobrien goto done; 1719159967Sobrien } 1720159967Sobrien 1721159967Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1722159967Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1723159967Sobrien 1724159967Sobrien IF_ADDR_LOCK(ifp); 1725159967Sobrien TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1726159967Sobrien u_char *addrp; 1727159967Sobrien 1728159967Sobrien if (ifma->ifma_addr->sa_family != AF_LINK) 1729159967Sobrien continue; 1730159967Sobrien 1731159967Sobrien addrp = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); 1732159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1733159967Sobrien u_int8_t mcaddr = addrp[i]; 1734159967Sobrien addr[i] &= mcaddr; 1735159967Sobrien mask[i] &= ~mcaddr; 1736159967Sobrien } 1737159967Sobrien } 1738159967Sobrien IF_ADDR_UNLOCK(ifp); 1739159967Sobrien 1740159967Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1741159967Sobrien mask[i] |= addr[i]; 1742159967Sobrien } 1743159967Sobrien 1744159967Sobriendone: 1745159967Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 1746159967Sobrien 1747159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1748159967Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1749159967Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1750159967Sobrien addr[5] << 8 | addr[4]); 1751159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1752159967Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1753159967Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1754159967Sobrien mask[5] << 8 | mask[4]); 1755159967Sobrien 1756159967Sobrien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1757159967Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 1758159967Sobrien} 1759159967Sobrien 1760159967Sobrienstatic void nfe_start(struct ifnet *ifp) 1761159967Sobrien{ 1762159967Sobrien struct nfe_softc *sc; 1763159967Sobrien 1764159967Sobrien sc = ifp->if_softc; 1765159967Sobrien NFE_LOCK(sc); 1766159967Sobrien nfe_start_locked(ifp); 1767159967Sobrien NFE_UNLOCK(sc); 1768159967Sobrien} 1769159967Sobrien 1770159967Sobrienstatic void nfe_start_locked(struct ifnet *ifp) 1771159967Sobrien{ 1772159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1773159952Sobrien int old = sc->txq.cur; 1774159952Sobrien struct mbuf *m0; 1775159952Sobrien 1776159967Sobrien if (!sc->nfe_link || ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1777159967Sobrien return; 1778159967Sobrien } 1779159967Sobrien 1780159952Sobrien for (;;) { 1781159952Sobrien IFQ_POLL(&ifp->if_snd, m0); 1782159952Sobrien if (m0 == NULL) 1783159952Sobrien break; 1784159952Sobrien 1785159952Sobrien if (nfe_encap(sc, m0) != 0) { 1786159967Sobrien ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1787159952Sobrien break; 1788159952Sobrien } 1789159952Sobrien 1790159952Sobrien /* packet put in h/w queue, remove from s/w queue */ 1791159952Sobrien IFQ_DEQUEUE(&ifp->if_snd, m0); 1792159952Sobrien 1793159967Sobrien BPF_MTAP(ifp, m0); 1794159952Sobrien } 1795159967Sobrien if (sc->txq.cur == old) { /* nothing sent */ 1796159952Sobrien return; 1797159967Sobrien } 1798159952Sobrien 1799159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 1800159952Sobrien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1801159952Sobrien else 1802159952Sobrien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 1803159952Sobrien 1804159952Sobrien /* kick Tx */ 1805159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1806159952Sobrien 1807159952Sobrien /* 1808159952Sobrien * Set a timeout in case the chip goes out to lunch. 1809159952Sobrien */ 1810159952Sobrien ifp->if_timer = 5; 1811159967Sobrien 1812159967Sobrien return; 1813159952Sobrien} 1814159952Sobrien 1815159967Sobrienstatic void nfe_watchdog(struct ifnet *ifp) 1816159952Sobrien{ 1817159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1818159952Sobrien 1819159967Sobrien printf("nfe%d: watchdog timeout\n", sc->nfe_unit); 1820159952Sobrien 1821159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1822159967Sobrien nfe_init(sc); 1823159952Sobrien 1824159952Sobrien ifp->if_oerrors++; 1825159967Sobrien 1826159967Sobrien return; 1827159952Sobrien} 1828159952Sobrien 1829159967Sobrienstatic void nfe_init(void *xsc) 1830159952Sobrien{ 1831159967Sobrien struct nfe_softc *sc = xsc; 1832159952Sobrien 1833159967Sobrien NFE_LOCK(sc); 1834159967Sobrien nfe_init_locked(sc); 1835159967Sobrien NFE_UNLOCK(sc); 1836159967Sobrien 1837159967Sobrien return; 1838159967Sobrien} 1839159967Sobrien 1840159967Sobrienstatic void nfe_init_locked(void *xsc) 1841159967Sobrien{ 1842159967Sobrien struct nfe_softc *sc = xsc; 1843159967Sobrien struct ifnet *ifp = sc->nfe_ifp; 1844159967Sobrien struct mii_data *mii; 1845159967Sobrien u_int32_t tmp; 1846159967Sobrien 1847159967Sobrien NFE_LOCK_ASSERT(sc); 1848159967Sobrien 1849159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1850159967Sobrien 1851159967Sobrien if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1852159967Sobrien return; 1853159967Sobrien } 1854159967Sobrien 1855159952Sobrien nfe_stop(ifp, 0); 1856159952Sobrien 1857159952Sobrien NFE_WRITE(sc, NFE_TX_UNK, 0); 1858159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 1859159952Sobrien 1860159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 1861159967Sobrien if (sc->nfe_flags & NFE_40BIT_ADDR) 1862159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1863159967Sobrien else if (sc->nfe_flags & NFE_JUMBO_SUP) 1864159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 1865159952Sobrien#ifdef NFE_CSUM 1866159967Sobrien if (sc->nfe_flags & NFE_HW_CSUM) 1867159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1868159952Sobrien#endif 1869159967Sobrien 1870159952Sobrien#if NVLAN > 0 1871159952Sobrien /* 1872159952Sobrien * Although the adapter is capable of stripping VLAN tags from received 1873159952Sobrien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1874159952Sobrien * purpose. This will be done in software by our network stack. 1875159952Sobrien */ 1876159967Sobrien if (sc->nfe_flags & NFE_HW_VLAN) 1877159952Sobrien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1878159952Sobrien#endif 1879159967Sobrien 1880159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1881159952Sobrien DELAY(10); 1882159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1883159952Sobrien 1884159952Sobrien#if NVLAN 1885159967Sobrien if (sc->nfe_flags & NFE_HW_VLAN) 1886159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1887159952Sobrien#endif 1888159952Sobrien 1889159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1890159952Sobrien 1891159952Sobrien /* set MAC address */ 1892159967Sobrien nfe_set_macaddr(sc, sc->eaddr); 1893159952Sobrien 1894159952Sobrien /* tell MAC where rings are in memory */ 1895159952Sobrien#ifdef __LP64__ 1896159952Sobrien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1897159952Sobrien#endif 1898159952Sobrien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1899159952Sobrien#ifdef __LP64__ 1900159952Sobrien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1901159952Sobrien#endif 1902159952Sobrien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1903159952Sobrien 1904159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 1905159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 1906159952Sobrien (NFE_TX_RING_COUNT - 1)); 1907159952Sobrien 1908159952Sobrien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1909159952Sobrien 1910159952Sobrien /* force MAC to wakeup */ 1911159952Sobrien tmp = NFE_READ(sc, NFE_PWR_STATE); 1912159952Sobrien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1913159952Sobrien DELAY(10); 1914159952Sobrien tmp = NFE_READ(sc, NFE_PWR_STATE); 1915159952Sobrien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1916159952Sobrien 1917159952Sobrien#if 1 1918159952Sobrien /* configure interrupts coalescing/mitigation */ 1919159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1920159952Sobrien#else 1921159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 1922159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 1923159952Sobrien#endif 1924159952Sobrien 1925159952Sobrien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1926159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1927159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1928159952Sobrien 1929159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1930159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1931159952Sobrien 1932159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1933159952Sobrien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1934159952Sobrien 1935159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 1936159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1937159952Sobrien DELAY(10); 1938159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1939159952Sobrien 1940159952Sobrien /* set Rx filter */ 1941159952Sobrien nfe_setmulti(sc); 1942159952Sobrien 1943159952Sobrien nfe_ifmedia_upd(ifp); 1944159952Sobrien 1945159967Sobrien nfe_tick_locked(sc); 1946159967Sobrien 1947159952Sobrien /* enable Rx */ 1948159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1949159952Sobrien 1950159952Sobrien /* enable Tx */ 1951159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1952159952Sobrien 1953159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1954159952Sobrien 1955159967Sobrien#ifdef DEVICE_POLLING 1956159967Sobrien if (ifp->if_capenable & IFCAP_POLLING) 1957159967Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1958159967Sobrien else 1959159967Sobrien#endif 1960159967Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); /* enable interrupts */ 1961159952Sobrien 1962159967Sobrien ifp->if_drv_flags |= IFF_DRV_RUNNING; 1963159967Sobrien ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1964159952Sobrien 1965159967Sobrien sc->nfe_link = 0; 1966159952Sobrien 1967159967Sobrien return; 1968159952Sobrien} 1969159952Sobrien 1970159967Sobrienstatic void nfe_stop(struct ifnet *ifp, int disable) 1971159952Sobrien{ 1972159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1973159967Sobrien struct mii_data *mii; 1974159952Sobrien 1975159967Sobrien NFE_LOCK_ASSERT(sc); 1976159952Sobrien 1977159952Sobrien ifp->if_timer = 0; 1978159967Sobrien ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1979159952Sobrien 1980159967Sobrien mii = device_get_softc(sc->nfe_miibus); 1981159952Sobrien 1982159967Sobrien callout_stop(&sc->nfe_stat_ch); 1983159967Sobrien 1984159952Sobrien /* abort Tx */ 1985159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 1986159952Sobrien 1987159952Sobrien /* disable Rx */ 1988159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 1989159952Sobrien 1990159952Sobrien /* disable interrupts */ 1991159952Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1992159952Sobrien 1993159967Sobrien sc->nfe_link = 0; 1994159967Sobrien 1995159952Sobrien /* reset Tx and Rx rings */ 1996159952Sobrien nfe_reset_tx_ring(sc, &sc->txq); 1997159952Sobrien nfe_reset_rx_ring(sc, &sc->rxq); 1998159952Sobrien 1999159967Sobrien return; 2000159952Sobrien} 2001159952Sobrien 2002159967Sobrienstatic int nfe_ifmedia_upd(struct ifnet *ifp) 2003159952Sobrien{ 2004159967Sobrien struct nfe_softc *sc = ifp->if_softc; 2005159952Sobrien 2006159967Sobrien NFE_LOCK(sc); 2007159967Sobrien nfe_ifmedia_upd_locked(ifp); 2008159967Sobrien NFE_UNLOCK(sc); 2009159967Sobrien return (0); 2010159952Sobrien} 2011159952Sobrien 2012159967Sobrienstatic int nfe_ifmedia_upd_locked(struct ifnet *ifp) 2013159952Sobrien{ 2014159967Sobrien struct nfe_softc *sc = ifp->if_softc; 2015159967Sobrien struct mii_data *mii; 2016159952Sobrien 2017159967Sobrien NFE_LOCK_ASSERT(sc); 2018159952Sobrien 2019159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2020159952Sobrien 2021159967Sobrien if (mii->mii_instance) { 2022159967Sobrien struct mii_softc *miisc; 2023159967Sobrien for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 2024159967Sobrien miisc = LIST_NEXT(miisc, mii_list)) { 2025159967Sobrien mii_phy_reset(miisc); 2026159952Sobrien } 2027159952Sobrien } 2028159967Sobrien mii_mediachg(mii); 2029159967Sobrien 2030159967Sobrien return (0); 2031159952Sobrien} 2032159952Sobrien 2033159967Sobrienstatic void nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2034159952Sobrien{ 2035159967Sobrien struct nfe_softc *sc; 2036159967Sobrien struct mii_data *mii; 2037159952Sobrien 2038159967Sobrien sc = ifp->if_softc; 2039159952Sobrien 2040159967Sobrien NFE_LOCK(sc); 2041159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2042159967Sobrien mii_pollstat(mii); 2043159967Sobrien NFE_UNLOCK(sc); 2044159952Sobrien 2045159967Sobrien ifmr->ifm_active = mii->mii_media_active; 2046159967Sobrien ifmr->ifm_status = mii->mii_media_status; 2047159952Sobrien 2048159967Sobrien return; 2049159952Sobrien} 2050159952Sobrien 2051159967Sobrienstatic void 2052159967Sobriennfe_tick(void *xsc) 2053159952Sobrien{ 2054159967Sobrien struct nfe_softc *sc; 2055159952Sobrien 2056159967Sobrien sc = xsc; 2057159952Sobrien 2058159967Sobrien NFE_LOCK(sc); 2059159967Sobrien nfe_tick_locked(sc); 2060159967Sobrien NFE_UNLOCK(sc); 2061159952Sobrien} 2062159952Sobrien 2063159952Sobrien 2064159967Sobrienvoid nfe_tick_locked(struct nfe_softc *arg) 2065159952Sobrien{ 2066159967Sobrien struct nfe_softc *sc; 2067159967Sobrien struct mii_data *mii; 2068159967Sobrien struct ifnet *ifp; 2069159952Sobrien 2070159967Sobrien sc = arg; 2071159952Sobrien 2072159967Sobrien NFE_LOCK_ASSERT(sc); 2073159952Sobrien 2074159967Sobrien ifp = sc->nfe_ifp; 2075159952Sobrien 2076159967Sobrien mii = device_get_softc(sc->nfe_miibus); 2077159967Sobrien mii_tick(mii); 2078159952Sobrien 2079159967Sobrien if (!sc->nfe_link) { 2080159967Sobrien if (mii->mii_media_status & IFM_ACTIVE && 2081159967Sobrien IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 2082159967Sobrien sc->nfe_link++; 2083159967Sobrien if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T 2084159967Sobrien && bootverbose) 2085159967Sobrien if_printf(sc->nfe_ifp, "gigabit link up\n"); 2086159967Sobrien if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 2087159967Sobrien nfe_start_locked(ifp); 2088159952Sobrien } 2089159952Sobrien } 2090159967Sobrien callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); 2091159952Sobrien 2092159967Sobrien return; 2093159952Sobrien} 2094159952Sobrien 2095159952Sobrien 2096159967Sobrienstatic void nfe_shutdown(device_t dev) 2097159952Sobrien{ 2098159967Sobrien struct nfe_softc *sc; 2099159967Sobrien struct ifnet *ifp; 2100159952Sobrien 2101159967Sobrien sc = device_get_softc(dev); 2102159952Sobrien 2103159967Sobrien NFE_LOCK(sc); 2104159967Sobrien ifp = sc->nfe_ifp; 2105159967Sobrien nfe_stop(ifp,0); 2106159967Sobrien /* nfe_reset(sc); */ 2107159967Sobrien NFE_UNLOCK(sc); 2108159952Sobrien 2109159967Sobrien return; 2110159952Sobrien} 2111159952Sobrien 2112159952Sobrien 2113159967Sobrienstatic void nfe_get_macaddr(struct nfe_softc *sc, u_char *addr) 2114159952Sobrien{ 2115159952Sobrien uint32_t tmp; 2116159952Sobrien 2117159952Sobrien tmp = NFE_READ(sc, NFE_MACADDR_LO); 2118159952Sobrien addr[0] = (tmp >> 8) & 0xff; 2119159952Sobrien addr[1] = (tmp & 0xff); 2120159952Sobrien 2121159952Sobrien tmp = NFE_READ(sc, NFE_MACADDR_HI); 2122159952Sobrien addr[2] = (tmp >> 24) & 0xff; 2123159952Sobrien addr[3] = (tmp >> 16) & 0xff; 2124159952Sobrien addr[4] = (tmp >> 8) & 0xff; 2125159952Sobrien addr[5] = (tmp & 0xff); 2126159952Sobrien} 2127159952Sobrien 2128159967Sobrienstatic void nfe_set_macaddr(struct nfe_softc *sc, u_char *addr) 2129159952Sobrien{ 2130159967Sobrien 2131159967Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, addr[5] << 8 | addr[4]); 2132159967Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, addr[3] << 24 | addr[2] << 16 | 2133159967Sobrien addr[1] << 8 | addr[0]); 2134159952Sobrien} 2135159952Sobrien 2136159967Sobrien/* 2137159967Sobrien * Map a single buffer address. 2138159967Sobrien */ 2139159967Sobrien 2140159967Sobrienstatic void 2141159967Sobriennfe_dma_map_segs(arg, segs, nseg, error) 2142159967Sobrien void *arg; 2143159967Sobrien bus_dma_segment_t *segs; 2144159967Sobrien int error, nseg; 2145159952Sobrien{ 2146159952Sobrien 2147159967Sobrien if (error) 2148159967Sobrien return; 2149159952Sobrien 2150159967Sobrien KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 2151159967Sobrien 2152159967Sobrien *(bus_dma_segment_t *)arg = *segs; 2153159967Sobrien 2154159967Sobrien return; 2155159952Sobrien} 2156