if_nfe.c revision 159952
1159952Sobrien/* $OpenBSD: if_nfe.c,v 1.57 2006/04/26 02:07:29 jsg Exp $ */ 2159952Sobrien 3159952Sobrien/*- 4159952Sobrien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 5159952Sobrien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 6159952Sobrien * 7159952Sobrien * Permission to use, copy, modify, and distribute this software for any 8159952Sobrien * purpose with or without fee is hereby granted, provided that the above 9159952Sobrien * copyright notice and this permission notice appear in all copies. 10159952Sobrien * 11159952Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12159952Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13159952Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14159952Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15159952Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16159952Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17159952Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18159952Sobrien */ 19159952Sobrien 20159952Sobrien/* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 21159952Sobrien 22159952Sobrien#include "bpfilter.h" 23159952Sobrien#include "vlan.h" 24159952Sobrien 25159952Sobrien#include <sys/param.h> 26159952Sobrien#include <sys/endian.h> 27159952Sobrien#include <sys/systm.h> 28159952Sobrien#include <sys/types.h> 29159952Sobrien#include <sys/sockio.h> 30159952Sobrien#include <sys/mbuf.h> 31159952Sobrien#include <sys/queue.h> 32159952Sobrien#include <sys/malloc.h> 33159952Sobrien#include <sys/kernel.h> 34159952Sobrien#include <sys/device.h> 35159952Sobrien#include <sys/socket.h> 36159952Sobrien 37159952Sobrien#include <machine/bus.h> 38159952Sobrien 39159952Sobrien#include <net/if.h> 40159952Sobrien#include <net/if_dl.h> 41159952Sobrien#include <net/if_media.h> 42159952Sobrien 43159952Sobrien#ifdef INET 44159952Sobrien#include <netinet/in.h> 45159952Sobrien#include <netinet/in_systm.h> 46159952Sobrien#include <netinet/in_var.h> 47159952Sobrien#include <netinet/ip.h> 48159952Sobrien#include <netinet/if_ether.h> 49159952Sobrien#endif 50159952Sobrien 51159952Sobrien#if NVLAN > 0 52159952Sobrien#include <net/if_types.h> 53159952Sobrien#include <net/if_vlan_var.h> 54159952Sobrien#endif 55159952Sobrien 56159952Sobrien#if NBPFILTER > 0 57159952Sobrien#include <net/bpf.h> 58159952Sobrien#endif 59159952Sobrien 60159952Sobrien#include <dev/mii/mii.h> 61159952Sobrien#include <dev/mii/miivar.h> 62159952Sobrien 63159952Sobrien#include <dev/pci/pcireg.h> 64159952Sobrien#include <dev/pci/pcivar.h> 65159952Sobrien#include <dev/pci/pcidevs.h> 66159952Sobrien 67159952Sobrien#include <dev/pci/if_nfereg.h> 68159952Sobrien#include <dev/pci/if_nfevar.h> 69159952Sobrien 70159952Sobrienint nfe_match(struct device *, void *, void *); 71159952Sobrienvoid nfe_attach(struct device *, struct device *, void *); 72159952Sobrienvoid nfe_power(int, void *); 73159952Sobrienvoid nfe_miibus_statchg(struct device *); 74159952Sobrienint nfe_miibus_readreg(struct device *, int, int); 75159952Sobrienvoid nfe_miibus_writereg(struct device *, int, int, int); 76159952Sobrienint nfe_intr(void *); 77159952Sobrienint nfe_ioctl(struct ifnet *, u_long, caddr_t); 78159952Sobrienvoid nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 79159952Sobrienvoid nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 80159952Sobrienvoid nfe_txdesc32_rsync(struct nfe_softc *, int, int, int); 81159952Sobrienvoid nfe_txdesc64_rsync(struct nfe_softc *, int, int, int); 82159952Sobrienvoid nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 83159952Sobrienvoid nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 84159952Sobrienvoid nfe_rxeof(struct nfe_softc *); 85159952Sobrienvoid nfe_txeof(struct nfe_softc *); 86159952Sobrienint nfe_encap(struct nfe_softc *, struct mbuf *); 87159952Sobrienvoid nfe_start(struct ifnet *); 88159952Sobrienvoid nfe_watchdog(struct ifnet *); 89159952Sobrienint nfe_init(struct ifnet *); 90159952Sobrienvoid nfe_stop(struct ifnet *, int); 91159952Sobrienstruct nfe_jbuf *nfe_jalloc(struct nfe_softc *); 92159952Sobrienvoid nfe_jfree(caddr_t, u_int, void *); 93159952Sobrienint nfe_jpool_alloc(struct nfe_softc *); 94159952Sobrienvoid nfe_jpool_free(struct nfe_softc *); 95159952Sobrienint nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 96159952Sobrienvoid nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 97159952Sobrienvoid nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 98159952Sobrienint nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 99159952Sobrienvoid nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 100159952Sobrienvoid nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 101159952Sobrienint nfe_ifmedia_upd(struct ifnet *); 102159952Sobrienvoid nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 103159952Sobrienvoid nfe_setmulti(struct nfe_softc *); 104159952Sobrienvoid nfe_get_macaddr(struct nfe_softc *, uint8_t *); 105159952Sobrienvoid nfe_set_macaddr(struct nfe_softc *, const uint8_t *); 106159952Sobrienvoid nfe_tick(void *); 107159952Sobrien 108159952Sobrienstruct cfattach nfe_ca = { 109159952Sobrien sizeof (struct nfe_softc), nfe_match, nfe_attach 110159952Sobrien}; 111159952Sobrien 112159952Sobrienstruct cfdriver nfe_cd = { 113159952Sobrien NULL, "nfe", DV_IFNET 114159952Sobrien}; 115159952Sobrien 116159952Sobrien/*#define NFE_NO_JUMBO*/ 117159952Sobrien 118159952Sobrien#ifdef NFE_DEBUG 119159952Sobrienint nfedebug = 0; 120159952Sobrien#define DPRINTF(x) do { if (nfedebug) printf x; } while (0) 121159952Sobrien#define DPRINTFN(n,x) do { if (nfedebug >= (n)) printf x; } while (0) 122159952Sobrien#else 123159952Sobrien#define DPRINTF(x) 124159952Sobrien#define DPRINTFN(n,x) 125159952Sobrien#endif 126159952Sobrien 127159952Sobrienconst struct pci_matchid nfe_devices[] = { 128159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN }, 129159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN }, 130159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1 }, 131159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN2 }, 132159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN3 }, 133159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4 }, 134159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN5 }, 135159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN1 }, 136159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN2 }, 137159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1 }, 138159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2 }, 139159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN1 }, 140159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN2 }, 141159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1 }, 142159952Sobrien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2 } 143159952Sobrien}; 144159952Sobrien 145159952Sobrienint 146159952Sobriennfe_match(struct device *dev, void *match, void *aux) 147159952Sobrien{ 148159952Sobrien return pci_matchbyid((struct pci_attach_args *)aux, nfe_devices, 149159952Sobrien sizeof (nfe_devices) / sizeof (nfe_devices[0])); 150159952Sobrien} 151159952Sobrien 152159952Sobrienvoid 153159952Sobriennfe_attach(struct device *parent, struct device *self, void *aux) 154159952Sobrien{ 155159952Sobrien struct nfe_softc *sc = (struct nfe_softc *)self; 156159952Sobrien struct pci_attach_args *pa = aux; 157159952Sobrien pci_chipset_tag_t pc = pa->pa_pc; 158159952Sobrien pci_intr_handle_t ih; 159159952Sobrien const char *intrstr; 160159952Sobrien struct ifnet *ifp; 161159952Sobrien bus_size_t memsize; 162159952Sobrien pcireg_t memtype; 163159952Sobrien 164159952Sobrien memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, NFE_PCI_BA); 165159952Sobrien switch (memtype) { 166159952Sobrien case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: 167159952Sobrien case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: 168159952Sobrien if (pci_mapreg_map(pa, NFE_PCI_BA, memtype, 0, &sc->sc_memt, 169159952Sobrien &sc->sc_memh, NULL, &memsize, 0) == 0) 170159952Sobrien break; 171159952Sobrien /* FALLTHROUGH */ 172159952Sobrien default: 173159952Sobrien printf(": could not map mem space\n"); 174159952Sobrien return; 175159952Sobrien } 176159952Sobrien 177159952Sobrien if (pci_intr_map(pa, &ih) != 0) { 178159952Sobrien printf(": could not map interrupt\n"); 179159952Sobrien return; 180159952Sobrien } 181159952Sobrien 182159952Sobrien intrstr = pci_intr_string(pc, ih); 183159952Sobrien sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, nfe_intr, sc, 184159952Sobrien sc->sc_dev.dv_xname); 185159952Sobrien if (sc->sc_ih == NULL) { 186159952Sobrien printf(": could not establish interrupt"); 187159952Sobrien if (intrstr != NULL) 188159952Sobrien printf(" at %s", intrstr); 189159952Sobrien printf("\n"); 190159952Sobrien return; 191159952Sobrien } 192159952Sobrien printf(": %s", intrstr); 193159952Sobrien 194159952Sobrien sc->sc_dmat = pa->pa_dmat; 195159952Sobrien 196159952Sobrien nfe_get_macaddr(sc, sc->sc_arpcom.ac_enaddr); 197159952Sobrien printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); 198159952Sobrien 199159952Sobrien sc->sc_flags = 0; 200159952Sobrien 201159952Sobrien switch (PCI_PRODUCT(pa->pa_id)) { 202159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 203159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 204159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 205159952Sobrien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 206159952Sobrien sc->sc_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 207159952Sobrien break; 208159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 209159952Sobrien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 210159952Sobrien sc->sc_flags |= NFE_40BIT_ADDR; 211159952Sobrien break; 212159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 213159952Sobrien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 214159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 215159952Sobrien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 216159952Sobrien sc->sc_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 217159952Sobrien break; 218159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 219159952Sobrien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 220159952Sobrien sc->sc_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 221159952Sobrien NFE_HW_VLAN; 222159952Sobrien break; 223159952Sobrien } 224159952Sobrien 225159952Sobrien#ifndef NFE_NO_JUMBO 226159952Sobrien /* enable jumbo frames for adapters that support it */ 227159952Sobrien if (sc->sc_flags & NFE_JUMBO_SUP) 228159952Sobrien sc->sc_flags |= NFE_USE_JUMBO; 229159952Sobrien#endif 230159952Sobrien 231159952Sobrien /* 232159952Sobrien * Allocate Tx and Rx rings. 233159952Sobrien */ 234159952Sobrien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 235159952Sobrien printf("%s: could not allocate Tx ring\n", 236159952Sobrien sc->sc_dev.dv_xname); 237159952Sobrien return; 238159952Sobrien } 239159952Sobrien 240159952Sobrien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 241159952Sobrien printf("%s: could not allocate Rx ring\n", 242159952Sobrien sc->sc_dev.dv_xname); 243159952Sobrien nfe_free_tx_ring(sc, &sc->txq); 244159952Sobrien return; 245159952Sobrien } 246159952Sobrien 247159952Sobrien ifp = &sc->sc_arpcom.ac_if; 248159952Sobrien ifp->if_softc = sc; 249159952Sobrien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 250159952Sobrien ifp->if_ioctl = nfe_ioctl; 251159952Sobrien ifp->if_start = nfe_start; 252159952Sobrien ifp->if_watchdog = nfe_watchdog; 253159952Sobrien ifp->if_init = nfe_init; 254159952Sobrien ifp->if_baudrate = IF_Gbps(1); 255159952Sobrien IFQ_SET_MAXLEN(&ifp->if_snd, NFE_IFQ_MAXLEN); 256159952Sobrien IFQ_SET_READY(&ifp->if_snd); 257159952Sobrien strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 258159952Sobrien 259159952Sobrien ifp->if_capabilities = IFCAP_VLAN_MTU; 260159952Sobrien#if NVLAN > 0 261159952Sobrien if (sc->sc_flags & NFE_HW_VLAN) 262159952Sobrien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 263159952Sobrien#endif 264159952Sobrien#ifdef NFE_CSUM 265159952Sobrien if (sc->sc_flags & NFE_HW_CSUM) { 266159952Sobrien ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | 267159952Sobrien IFCAP_CSUM_UDPv4; 268159952Sobrien } 269159952Sobrien#endif 270159952Sobrien 271159952Sobrien sc->sc_mii.mii_ifp = ifp; 272159952Sobrien sc->sc_mii.mii_readreg = nfe_miibus_readreg; 273159952Sobrien sc->sc_mii.mii_writereg = nfe_miibus_writereg; 274159952Sobrien sc->sc_mii.mii_statchg = nfe_miibus_statchg; 275159952Sobrien 276159952Sobrien ifmedia_init(&sc->sc_mii.mii_media, 0, nfe_ifmedia_upd, 277159952Sobrien nfe_ifmedia_sts); 278159952Sobrien mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, 279159952Sobrien MII_OFFSET_ANY, 0); 280159952Sobrien if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { 281159952Sobrien printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); 282159952Sobrien ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL, 283159952Sobrien 0, NULL); 284159952Sobrien ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL); 285159952Sobrien } else 286159952Sobrien ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO); 287159952Sobrien 288159952Sobrien if_attach(ifp); 289159952Sobrien ether_ifattach(ifp); 290159952Sobrien 291159952Sobrien timeout_set(&sc->sc_tick_ch, nfe_tick, sc); 292159952Sobrien 293159952Sobrien sc->sc_powerhook = powerhook_establish(nfe_power, sc); 294159952Sobrien} 295159952Sobrien 296159952Sobrienvoid 297159952Sobriennfe_power(int why, void *arg) 298159952Sobrien{ 299159952Sobrien struct nfe_softc *sc = arg; 300159952Sobrien struct ifnet *ifp; 301159952Sobrien 302159952Sobrien if (why == PWR_RESUME) { 303159952Sobrien ifp = &sc->sc_arpcom.ac_if; 304159952Sobrien if (ifp->if_flags & IFF_UP) { 305159952Sobrien nfe_init(ifp); 306159952Sobrien if (ifp->if_flags & IFF_RUNNING) 307159952Sobrien nfe_start(ifp); 308159952Sobrien } 309159952Sobrien } 310159952Sobrien} 311159952Sobrien 312159952Sobrienvoid 313159952Sobriennfe_miibus_statchg(struct device *dev) 314159952Sobrien{ 315159952Sobrien struct nfe_softc *sc = (struct nfe_softc *)dev; 316159952Sobrien struct mii_data *mii = &sc->sc_mii; 317159952Sobrien uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 318159952Sobrien 319159952Sobrien phy = NFE_READ(sc, NFE_PHY_IFACE); 320159952Sobrien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 321159952Sobrien 322159952Sobrien seed = NFE_READ(sc, NFE_RNDSEED); 323159952Sobrien seed &= ~NFE_SEED_MASK; 324159952Sobrien 325159952Sobrien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 326159952Sobrien phy |= NFE_PHY_HDX; /* half-duplex */ 327159952Sobrien misc |= NFE_MISC1_HDX; 328159952Sobrien } 329159952Sobrien 330159952Sobrien switch (IFM_SUBTYPE(mii->mii_media_active)) { 331159952Sobrien case IFM_1000_T: /* full-duplex only */ 332159952Sobrien link |= NFE_MEDIA_1000T; 333159952Sobrien seed |= NFE_SEED_1000T; 334159952Sobrien phy |= NFE_PHY_1000T; 335159952Sobrien break; 336159952Sobrien case IFM_100_TX: 337159952Sobrien link |= NFE_MEDIA_100TX; 338159952Sobrien seed |= NFE_SEED_100TX; 339159952Sobrien phy |= NFE_PHY_100TX; 340159952Sobrien break; 341159952Sobrien case IFM_10_T: 342159952Sobrien link |= NFE_MEDIA_10T; 343159952Sobrien seed |= NFE_SEED_10T; 344159952Sobrien break; 345159952Sobrien } 346159952Sobrien 347159952Sobrien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 348159952Sobrien 349159952Sobrien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 350159952Sobrien NFE_WRITE(sc, NFE_MISC1, misc); 351159952Sobrien NFE_WRITE(sc, NFE_LINKSPEED, link); 352159952Sobrien} 353159952Sobrien 354159952Sobrienint 355159952Sobriennfe_miibus_readreg(struct device *dev, int phy, int reg) 356159952Sobrien{ 357159952Sobrien struct nfe_softc *sc = (struct nfe_softc *)dev; 358159952Sobrien uint32_t val; 359159952Sobrien int ntries; 360159952Sobrien 361159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 362159952Sobrien 363159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 364159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 365159952Sobrien DELAY(100); 366159952Sobrien } 367159952Sobrien 368159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 369159952Sobrien 370159952Sobrien for (ntries = 0; ntries < 1000; ntries++) { 371159952Sobrien DELAY(100); 372159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 373159952Sobrien break; 374159952Sobrien } 375159952Sobrien if (ntries == 1000) { 376159952Sobrien DPRINTFN(2, ("%s: timeout waiting for PHY\n", 377159952Sobrien sc->sc_dev.dv_xname)); 378159952Sobrien return 0; 379159952Sobrien } 380159952Sobrien 381159952Sobrien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 382159952Sobrien DPRINTFN(2, ("%s: could not read PHY\n", 383159952Sobrien sc->sc_dev.dv_xname)); 384159952Sobrien return 0; 385159952Sobrien } 386159952Sobrien 387159952Sobrien val = NFE_READ(sc, NFE_PHY_DATA); 388159952Sobrien if (val != 0xffffffff && val != 0) 389159952Sobrien sc->mii_phyaddr = phy; 390159952Sobrien 391159952Sobrien DPRINTFN(2, ("%s: mii read phy %d reg 0x%x ret 0x%x\n", 392159952Sobrien sc->sc_dev.dv_xname, phy, reg, val)); 393159952Sobrien 394159952Sobrien return val; 395159952Sobrien} 396159952Sobrien 397159952Sobrienvoid 398159952Sobriennfe_miibus_writereg(struct device *dev, int phy, int reg, int val) 399159952Sobrien{ 400159952Sobrien struct nfe_softc *sc = (struct nfe_softc *)dev; 401159952Sobrien uint32_t ctl; 402159952Sobrien int ntries; 403159952Sobrien 404159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 405159952Sobrien 406159952Sobrien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 407159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 408159952Sobrien DELAY(100); 409159952Sobrien } 410159952Sobrien 411159952Sobrien NFE_WRITE(sc, NFE_PHY_DATA, val); 412159952Sobrien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 413159952Sobrien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 414159952Sobrien 415159952Sobrien for (ntries = 0; ntries < 1000; ntries++) { 416159952Sobrien DELAY(100); 417159952Sobrien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 418159952Sobrien break; 419159952Sobrien } 420159952Sobrien#ifdef NFE_DEBUG 421159952Sobrien if (nfedebug >= 2 && ntries == 1000) 422159952Sobrien printf("could not write to PHY\n"); 423159952Sobrien#endif 424159952Sobrien} 425159952Sobrien 426159952Sobrienint 427159952Sobriennfe_intr(void *arg) 428159952Sobrien{ 429159952Sobrien struct nfe_softc *sc = arg; 430159952Sobrien struct ifnet *ifp = &sc->sc_arpcom.ac_if; 431159952Sobrien uint32_t r; 432159952Sobrien 433159952Sobrien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) 434159952Sobrien return 0; /* not for us */ 435159952Sobrien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 436159952Sobrien 437159952Sobrien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 438159952Sobrien 439159952Sobrien if (r & NFE_IRQ_LINK) { 440159952Sobrien NFE_READ(sc, NFE_PHY_STATUS); 441159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 442159952Sobrien DPRINTF(("%s: link state changed\n", sc->sc_dev.dv_xname)); 443159952Sobrien } 444159952Sobrien 445159952Sobrien if (ifp->if_flags & IFF_RUNNING) { 446159952Sobrien /* check Rx ring */ 447159952Sobrien nfe_rxeof(sc); 448159952Sobrien 449159952Sobrien /* check Tx ring */ 450159952Sobrien nfe_txeof(sc); 451159952Sobrien } 452159952Sobrien 453159952Sobrien return 1; 454159952Sobrien} 455159952Sobrien 456159952Sobrienint 457159952Sobriennfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 458159952Sobrien{ 459159952Sobrien struct nfe_softc *sc = ifp->if_softc; 460159952Sobrien struct ifreq *ifr = (struct ifreq *)data; 461159952Sobrien struct ifaddr *ifa = (struct ifaddr *)data; 462159952Sobrien int s, error = 0; 463159952Sobrien 464159952Sobrien s = splnet(); 465159952Sobrien 466159952Sobrien if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) { 467159952Sobrien splx(s); 468159952Sobrien return error; 469159952Sobrien } 470159952Sobrien 471159952Sobrien switch (cmd) { 472159952Sobrien case SIOCSIFADDR: 473159952Sobrien ifp->if_flags |= IFF_UP; 474159952Sobrien if (!(ifp->if_flags & IFF_RUNNING)) 475159952Sobrien nfe_init(ifp); 476159952Sobrien#ifdef INET 477159952Sobrien if (ifa->ifa_addr->sa_family == AF_INET) 478159952Sobrien arp_ifinit(&sc->sc_arpcom, ifa); 479159952Sobrien#endif 480159952Sobrien break; 481159952Sobrien case SIOCSIFMTU: 482159952Sobrien if (ifr->ifr_mtu < ETHERMIN || 483159952Sobrien ((sc->sc_flags & NFE_USE_JUMBO) && 484159952Sobrien ifr->ifr_mtu > ETHERMTU_JUMBO) || 485159952Sobrien (!(sc->sc_flags & NFE_USE_JUMBO) && 486159952Sobrien ifr->ifr_mtu > ETHERMTU)) 487159952Sobrien error = EINVAL; 488159952Sobrien else if (ifp->if_mtu != ifr->ifr_mtu) 489159952Sobrien ifp->if_mtu = ifr->ifr_mtu; 490159952Sobrien break; 491159952Sobrien case SIOCSIFFLAGS: 492159952Sobrien if (ifp->if_flags & IFF_UP) { 493159952Sobrien /* 494159952Sobrien * If only the PROMISC or ALLMULTI flag changes, then 495159952Sobrien * don't do a full re-init of the chip, just update 496159952Sobrien * the Rx filter. 497159952Sobrien */ 498159952Sobrien if ((ifp->if_flags & IFF_RUNNING) && 499159952Sobrien ((ifp->if_flags ^ sc->sc_if_flags) & 500159952Sobrien (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 501159952Sobrien nfe_setmulti(sc); 502159952Sobrien } else { 503159952Sobrien if (!(ifp->if_flags & IFF_RUNNING)) 504159952Sobrien nfe_init(ifp); 505159952Sobrien } 506159952Sobrien } else { 507159952Sobrien if (ifp->if_flags & IFF_RUNNING) 508159952Sobrien nfe_stop(ifp, 1); 509159952Sobrien } 510159952Sobrien sc->sc_if_flags = ifp->if_flags; 511159952Sobrien break; 512159952Sobrien case SIOCADDMULTI: 513159952Sobrien case SIOCDELMULTI: 514159952Sobrien error = (cmd == SIOCADDMULTI) ? 515159952Sobrien ether_addmulti(ifr, &sc->sc_arpcom) : 516159952Sobrien ether_delmulti(ifr, &sc->sc_arpcom); 517159952Sobrien 518159952Sobrien if (error == ENETRESET) { 519159952Sobrien if (ifp->if_flags & IFF_RUNNING) 520159952Sobrien nfe_setmulti(sc); 521159952Sobrien error = 0; 522159952Sobrien } 523159952Sobrien break; 524159952Sobrien case SIOCSIFMEDIA: 525159952Sobrien case SIOCGIFMEDIA: 526159952Sobrien error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 527159952Sobrien break; 528159952Sobrien default: 529159952Sobrien error = EINVAL; 530159952Sobrien } 531159952Sobrien 532159952Sobrien splx(s); 533159952Sobrien 534159952Sobrien return error; 535159952Sobrien} 536159952Sobrien 537159952Sobrienvoid 538159952Sobriennfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 539159952Sobrien{ 540159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 541159952Sobrien (caddr_t)desc32 - (caddr_t)sc->txq.desc32, 542159952Sobrien sizeof (struct nfe_desc32), ops); 543159952Sobrien} 544159952Sobrien 545159952Sobrienvoid 546159952Sobriennfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 547159952Sobrien{ 548159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 549159952Sobrien (caddr_t)desc64 - (caddr_t)sc->txq.desc64, 550159952Sobrien sizeof (struct nfe_desc64), ops); 551159952Sobrien} 552159952Sobrien 553159952Sobrienvoid 554159952Sobriennfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 555159952Sobrien{ 556159952Sobrien if (end > start) { 557159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 558159952Sobrien (caddr_t)&sc->txq.desc32[start] - (caddr_t)sc->txq.desc32, 559159952Sobrien (caddr_t)&sc->txq.desc32[end] - 560159952Sobrien (caddr_t)&sc->txq.desc32[start], ops); 561159952Sobrien return; 562159952Sobrien } 563159952Sobrien /* sync from 'start' to end of ring */ 564159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 565159952Sobrien (caddr_t)&sc->txq.desc32[start] - (caddr_t)sc->txq.desc32, 566159952Sobrien (caddr_t)&sc->txq.desc32[NFE_TX_RING_COUNT] - 567159952Sobrien (caddr_t)&sc->txq.desc32[start], ops); 568159952Sobrien 569159952Sobrien /* sync from start of ring to 'end' */ 570159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 0, 571159952Sobrien (caddr_t)&sc->txq.desc32[end] - (caddr_t)sc->txq.desc32, ops); 572159952Sobrien} 573159952Sobrien 574159952Sobrienvoid 575159952Sobriennfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 576159952Sobrien{ 577159952Sobrien if (end > start) { 578159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 579159952Sobrien (caddr_t)&sc->txq.desc64[start] - (caddr_t)sc->txq.desc64, 580159952Sobrien (caddr_t)&sc->txq.desc64[end] - 581159952Sobrien (caddr_t)&sc->txq.desc64[start], ops); 582159952Sobrien return; 583159952Sobrien } 584159952Sobrien /* sync from 'start' to end of ring */ 585159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 586159952Sobrien (caddr_t)&sc->txq.desc64[start] - (caddr_t)sc->txq.desc64, 587159952Sobrien (caddr_t)&sc->txq.desc64[NFE_TX_RING_COUNT] - 588159952Sobrien (caddr_t)&sc->txq.desc64[start], ops); 589159952Sobrien 590159952Sobrien /* sync from start of ring to 'end' */ 591159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 0, 592159952Sobrien (caddr_t)&sc->txq.desc64[end] - (caddr_t)sc->txq.desc64, ops); 593159952Sobrien} 594159952Sobrien 595159952Sobrienvoid 596159952Sobriennfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 597159952Sobrien{ 598159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->rxq.map, 599159952Sobrien (caddr_t)desc32 - (caddr_t)sc->rxq.desc32, 600159952Sobrien sizeof (struct nfe_desc32), ops); 601159952Sobrien} 602159952Sobrien 603159952Sobrienvoid 604159952Sobriennfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 605159952Sobrien{ 606159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->rxq.map, 607159952Sobrien (caddr_t)desc64 - (caddr_t)sc->rxq.desc64, 608159952Sobrien sizeof (struct nfe_desc64), ops); 609159952Sobrien} 610159952Sobrien 611159952Sobrienvoid 612159952Sobriennfe_rxeof(struct nfe_softc *sc) 613159952Sobrien{ 614159952Sobrien struct ifnet *ifp = &sc->sc_arpcom.ac_if; 615159952Sobrien struct nfe_desc32 *desc32; 616159952Sobrien struct nfe_desc64 *desc64; 617159952Sobrien struct nfe_rx_data *data; 618159952Sobrien struct nfe_jbuf *jbuf; 619159952Sobrien struct mbuf *m, *mnew; 620159952Sobrien bus_addr_t physaddr; 621159952Sobrien uint16_t flags; 622159952Sobrien int error, len; 623159952Sobrien 624159952Sobrien for (;;) { 625159952Sobrien data = &sc->rxq.data[sc->rxq.cur]; 626159952Sobrien 627159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 628159952Sobrien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 629159952Sobrien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 630159952Sobrien 631159952Sobrien flags = letoh16(desc64->flags); 632159952Sobrien len = letoh16(desc64->length) & 0x3fff; 633159952Sobrien } else { 634159952Sobrien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 635159952Sobrien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 636159952Sobrien 637159952Sobrien flags = letoh16(desc32->flags); 638159952Sobrien len = letoh16(desc32->length) & 0x3fff; 639159952Sobrien } 640159952Sobrien 641159952Sobrien if (flags & NFE_RX_READY) 642159952Sobrien break; 643159952Sobrien 644159952Sobrien if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 645159952Sobrien if (!(flags & NFE_RX_VALID_V1)) 646159952Sobrien goto skip; 647159952Sobrien 648159952Sobrien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 649159952Sobrien flags &= ~NFE_RX_ERROR; 650159952Sobrien len--; /* fix buffer length */ 651159952Sobrien } 652159952Sobrien } else { 653159952Sobrien if (!(flags & NFE_RX_VALID_V2)) 654159952Sobrien goto skip; 655159952Sobrien 656159952Sobrien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 657159952Sobrien flags &= ~NFE_RX_ERROR; 658159952Sobrien len--; /* fix buffer length */ 659159952Sobrien } 660159952Sobrien } 661159952Sobrien 662159952Sobrien if (flags & NFE_RX_ERROR) { 663159952Sobrien ifp->if_ierrors++; 664159952Sobrien goto skip; 665159952Sobrien } 666159952Sobrien 667159952Sobrien /* 668159952Sobrien * Try to allocate a new mbuf for this ring element and load 669159952Sobrien * it before processing the current mbuf. If the ring element 670159952Sobrien * cannot be loaded, drop the received packet and reuse the 671159952Sobrien * old mbuf. In the unlikely case that the old mbuf can't be 672159952Sobrien * reloaded either, explicitly panic. 673159952Sobrien */ 674159952Sobrien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 675159952Sobrien if (mnew == NULL) { 676159952Sobrien ifp->if_ierrors++; 677159952Sobrien goto skip; 678159952Sobrien } 679159952Sobrien 680159952Sobrien if (sc->sc_flags & NFE_USE_JUMBO) { 681159952Sobrien if ((jbuf = nfe_jalloc(sc)) == NULL) { 682159952Sobrien m_freem(mnew); 683159952Sobrien ifp->if_ierrors++; 684159952Sobrien goto skip; 685159952Sobrien } 686159952Sobrien MEXTADD(mnew, jbuf->buf, NFE_JBYTES, 0, nfe_jfree, sc); 687159952Sobrien 688159952Sobrien bus_dmamap_sync(sc->sc_dmat, sc->rxq.jmap, 689159952Sobrien mtod(data->m, caddr_t) - sc->rxq.jpool, NFE_JBYTES, 690159952Sobrien BUS_DMASYNC_POSTREAD); 691159952Sobrien 692159952Sobrien physaddr = jbuf->physaddr; 693159952Sobrien } else { 694159952Sobrien MCLGET(mnew, M_DONTWAIT); 695159952Sobrien if (!(mnew->m_flags & M_EXT)) { 696159952Sobrien m_freem(mnew); 697159952Sobrien ifp->if_ierrors++; 698159952Sobrien goto skip; 699159952Sobrien } 700159952Sobrien 701159952Sobrien bus_dmamap_sync(sc->sc_dmat, data->map, 0, 702159952Sobrien data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); 703159952Sobrien bus_dmamap_unload(sc->sc_dmat, data->map); 704159952Sobrien 705159952Sobrien error = bus_dmamap_load(sc->sc_dmat, data->map, 706159952Sobrien mtod(mnew, void *), MCLBYTES, NULL, 707159952Sobrien BUS_DMA_READ | BUS_DMA_NOWAIT); 708159952Sobrien if (error != 0) { 709159952Sobrien m_freem(mnew); 710159952Sobrien 711159952Sobrien /* try to reload the old mbuf */ 712159952Sobrien error = bus_dmamap_load(sc->sc_dmat, data->map, 713159952Sobrien mtod(data->m, void *), MCLBYTES, NULL, 714159952Sobrien BUS_DMA_READ | BUS_DMA_NOWAIT); 715159952Sobrien if (error != 0) { 716159952Sobrien /* very unlikely that it will fail.. */ 717159952Sobrien panic("%s: could not load old rx mbuf", 718159952Sobrien sc->sc_dev.dv_xname); 719159952Sobrien } 720159952Sobrien ifp->if_ierrors++; 721159952Sobrien goto skip; 722159952Sobrien } 723159952Sobrien physaddr = data->map->dm_segs[0].ds_addr; 724159952Sobrien } 725159952Sobrien 726159952Sobrien /* 727159952Sobrien * New mbuf successfully loaded, update Rx ring and continue 728159952Sobrien * processing. 729159952Sobrien */ 730159952Sobrien m = data->m; 731159952Sobrien data->m = mnew; 732159952Sobrien 733159952Sobrien /* finalize mbuf */ 734159952Sobrien m->m_pkthdr.len = m->m_len = len; 735159952Sobrien m->m_pkthdr.rcvif = ifp; 736159952Sobrien 737159952Sobrien#ifdef notyet 738159952Sobrien if (sc->sc_flags & NFE_HW_CSUM) { 739159952Sobrien if (flags & NFE_RX_IP_CSUMOK) 740159952Sobrien m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 741159952Sobrien if (flags & NFE_RX_UDP_CSUMOK) 742159952Sobrien m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK; 743159952Sobrien if (flags & NFE_RX_TCP_CSUMOK) 744159952Sobrien m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK; 745159952Sobrien } 746159952Sobrien#elif defined(NFE_CSUM) 747159952Sobrien if ((sc->sc_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) 748159952Sobrien m->m_pkthdr.csum_flags = M_IPV4_CSUM_IN_OK; 749159952Sobrien#endif 750159952Sobrien 751159952Sobrien#if NBPFILTER > 0 752159952Sobrien if (ifp->if_bpf) 753159952Sobrien bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); 754159952Sobrien#endif 755159952Sobrien ifp->if_ipackets++; 756159952Sobrien ether_input_mbuf(ifp, m); 757159952Sobrien 758159952Sobrien /* update mapping address in h/w descriptor */ 759159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 760159952Sobrien#if defined(__LP64__) 761159952Sobrien desc64->physaddr[0] = htole32(physaddr >> 32); 762159952Sobrien#endif 763159952Sobrien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 764159952Sobrien } else { 765159952Sobrien desc32->physaddr = htole32(physaddr); 766159952Sobrien } 767159952Sobrien 768159952Sobrienskip: if (sc->sc_flags & NFE_40BIT_ADDR) { 769159952Sobrien desc64->length = htole16(sc->rxq.bufsz); 770159952Sobrien desc64->flags = htole16(NFE_RX_READY); 771159952Sobrien 772159952Sobrien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 773159952Sobrien } else { 774159952Sobrien desc32->length = htole16(sc->rxq.bufsz); 775159952Sobrien desc32->flags = htole16(NFE_RX_READY); 776159952Sobrien 777159952Sobrien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 778159952Sobrien } 779159952Sobrien 780159952Sobrien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 781159952Sobrien } 782159952Sobrien} 783159952Sobrien 784159952Sobrienvoid 785159952Sobriennfe_txeof(struct nfe_softc *sc) 786159952Sobrien{ 787159952Sobrien struct ifnet *ifp = &sc->sc_arpcom.ac_if; 788159952Sobrien struct nfe_desc32 *desc32; 789159952Sobrien struct nfe_desc64 *desc64; 790159952Sobrien struct nfe_tx_data *data = NULL; 791159952Sobrien uint16_t flags; 792159952Sobrien 793159952Sobrien while (sc->txq.next != sc->txq.cur) { 794159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 795159952Sobrien desc64 = &sc->txq.desc64[sc->txq.next]; 796159952Sobrien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 797159952Sobrien 798159952Sobrien flags = letoh16(desc64->flags); 799159952Sobrien } else { 800159952Sobrien desc32 = &sc->txq.desc32[sc->txq.next]; 801159952Sobrien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 802159952Sobrien 803159952Sobrien flags = letoh16(desc32->flags); 804159952Sobrien } 805159952Sobrien 806159952Sobrien if (flags & NFE_TX_VALID) 807159952Sobrien break; 808159952Sobrien 809159952Sobrien data = &sc->txq.data[sc->txq.next]; 810159952Sobrien 811159952Sobrien if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 812159952Sobrien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 813159952Sobrien goto skip; 814159952Sobrien 815159952Sobrien if ((flags & NFE_TX_ERROR_V1) != 0) { 816159952Sobrien printf("%s: tx v1 error 0x%04b\n", 817159952Sobrien sc->sc_dev.dv_xname, flags, NFE_V1_TXERR); 818159952Sobrien ifp->if_oerrors++; 819159952Sobrien } else 820159952Sobrien ifp->if_opackets++; 821159952Sobrien } else { 822159952Sobrien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 823159952Sobrien goto skip; 824159952Sobrien 825159952Sobrien if ((flags & NFE_TX_ERROR_V2) != 0) { 826159952Sobrien printf("%s: tx v2 error 0x%04b\n", 827159952Sobrien sc->sc_dev.dv_xname, flags, NFE_V2_TXERR); 828159952Sobrien ifp->if_oerrors++; 829159952Sobrien } else 830159952Sobrien ifp->if_opackets++; 831159952Sobrien } 832159952Sobrien 833159952Sobrien if (data->m == NULL) { /* should not get there */ 834159952Sobrien printf("%s: last fragment bit w/o associated mbuf!\n", 835159952Sobrien sc->sc_dev.dv_xname); 836159952Sobrien goto skip; 837159952Sobrien } 838159952Sobrien 839159952Sobrien /* last fragment of the mbuf chain transmitted */ 840159952Sobrien bus_dmamap_sync(sc->sc_dmat, data->active, 0, 841159952Sobrien data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE); 842159952Sobrien bus_dmamap_unload(sc->sc_dmat, data->active); 843159952Sobrien m_freem(data->m); 844159952Sobrien data->m = NULL; 845159952Sobrien 846159952Sobrien ifp->if_timer = 0; 847159952Sobrien 848159952Sobrienskip: sc->txq.queued--; 849159952Sobrien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 850159952Sobrien } 851159952Sobrien 852159952Sobrien if (data != NULL) { /* at least one slot freed */ 853159952Sobrien ifp->if_flags &= ~IFF_OACTIVE; 854159952Sobrien nfe_start(ifp); 855159952Sobrien } 856159952Sobrien} 857159952Sobrien 858159952Sobrienint 859159952Sobriennfe_encap(struct nfe_softc *sc, struct mbuf *m0) 860159952Sobrien{ 861159952Sobrien struct nfe_desc32 *desc32; 862159952Sobrien struct nfe_desc64 *desc64; 863159952Sobrien struct nfe_tx_data *data; 864159952Sobrien bus_dmamap_t map; 865159952Sobrien uint16_t flags = NFE_TX_VALID; 866159952Sobrien#if NVLAN > 0 867159952Sobrien uint32_t vtag = 0; 868159952Sobrien#endif 869159952Sobrien int error, i; 870159952Sobrien 871159952Sobrien map = sc->txq.data[sc->txq.cur].map; 872159952Sobrien 873159952Sobrien error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, BUS_DMA_NOWAIT); 874159952Sobrien if (error != 0) { 875159952Sobrien printf("%s: could not map mbuf (error %d)\n", 876159952Sobrien sc->sc_dev.dv_xname, error); 877159952Sobrien return error; 878159952Sobrien } 879159952Sobrien 880159952Sobrien if (sc->txq.queued + map->dm_nsegs >= NFE_TX_RING_COUNT - 1) { 881159952Sobrien bus_dmamap_unload(sc->sc_dmat, map); 882159952Sobrien return ENOBUFS; 883159952Sobrien } 884159952Sobrien 885159952Sobrien#if NVLAN > 0 886159952Sobrien /* setup h/w VLAN tagging */ 887159952Sobrien if ((m0->m_flags & (M_PROTO1 | M_PKTHDR)) == (M_PROTO1 | M_PKTHDR) && 888159952Sobrien m0->m_pkthdr.rcvif != NULL) { 889159952Sobrien struct ifvlan *ifv = m0->m_pkthdr.rcvif->if_softc; 890159952Sobrien vtag = NFE_TX_VTAG | htons(ifv->ifv_tag); 891159952Sobrien } 892159952Sobrien#endif 893159952Sobrien#ifdef NFE_CSUM 894159952Sobrien if (m0->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) 895159952Sobrien flags |= NFE_TX_IP_CSUM; 896159952Sobrien if (m0->m_pkthdr.csum_flags & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) 897159952Sobrien flags |= NFE_TX_TCP_CSUM; 898159952Sobrien#endif 899159952Sobrien 900159952Sobrien for (i = 0; i < map->dm_nsegs; i++) { 901159952Sobrien data = &sc->txq.data[sc->txq.cur]; 902159952Sobrien 903159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 904159952Sobrien desc64 = &sc->txq.desc64[sc->txq.cur]; 905159952Sobrien#if defined(__LP64__) 906159952Sobrien desc64->physaddr[0] = 907159952Sobrien htole32(map->dm_segs[i].ds_addr >> 32); 908159952Sobrien#endif 909159952Sobrien desc64->physaddr[1] = 910159952Sobrien htole32(map->dm_segs[i].ds_addr & 0xffffffff); 911159952Sobrien desc64->length = htole16(map->dm_segs[i].ds_len - 1); 912159952Sobrien desc64->flags = htole16(flags); 913159952Sobrien#if NVLAN > 0 914159952Sobrien desc64->vtag = htole32(vtag); 915159952Sobrien#endif 916159952Sobrien } else { 917159952Sobrien desc32 = &sc->txq.desc32[sc->txq.cur]; 918159952Sobrien 919159952Sobrien desc32->physaddr = htole32(map->dm_segs[i].ds_addr); 920159952Sobrien desc32->length = htole16(map->dm_segs[i].ds_len - 1); 921159952Sobrien desc32->flags = htole16(flags); 922159952Sobrien } 923159952Sobrien 924159952Sobrien /* csum flags and vtag belong to the first fragment only */ 925159952Sobrien if (map->dm_nsegs > 1) { 926159952Sobrien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 927159952Sobrien#if NVLAN > 0 928159952Sobrien vtag = 0; 929159952Sobrien#endif 930159952Sobrien } 931159952Sobrien 932159952Sobrien sc->txq.queued++; 933159952Sobrien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 934159952Sobrien } 935159952Sobrien 936159952Sobrien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 937159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 938159952Sobrien flags |= NFE_TX_LASTFRAG_V2; 939159952Sobrien desc64->flags = htole16(flags); 940159952Sobrien } else { 941159952Sobrien if (sc->sc_flags & NFE_JUMBO_SUP) 942159952Sobrien flags |= NFE_TX_LASTFRAG_V2; 943159952Sobrien else 944159952Sobrien flags |= NFE_TX_LASTFRAG_V1; 945159952Sobrien desc32->flags = htole16(flags); 946159952Sobrien } 947159952Sobrien 948159952Sobrien data->m = m0; 949159952Sobrien data->active = map; 950159952Sobrien 951159952Sobrien bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 952159952Sobrien BUS_DMASYNC_PREWRITE); 953159952Sobrien 954159952Sobrien return 0; 955159952Sobrien} 956159952Sobrien 957159952Sobrienvoid 958159952Sobriennfe_start(struct ifnet *ifp) 959159952Sobrien{ 960159952Sobrien struct nfe_softc *sc = ifp->if_softc; 961159952Sobrien int old = sc->txq.cur; 962159952Sobrien struct mbuf *m0; 963159952Sobrien 964159952Sobrien for (;;) { 965159952Sobrien IFQ_POLL(&ifp->if_snd, m0); 966159952Sobrien if (m0 == NULL) 967159952Sobrien break; 968159952Sobrien 969159952Sobrien if (nfe_encap(sc, m0) != 0) { 970159952Sobrien ifp->if_flags |= IFF_OACTIVE; 971159952Sobrien break; 972159952Sobrien } 973159952Sobrien 974159952Sobrien /* packet put in h/w queue, remove from s/w queue */ 975159952Sobrien IFQ_DEQUEUE(&ifp->if_snd, m0); 976159952Sobrien 977159952Sobrien#if NBPFILTER > 0 978159952Sobrien if (ifp->if_bpf != NULL) 979159952Sobrien bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT); 980159952Sobrien#endif 981159952Sobrien } 982159952Sobrien if (sc->txq.cur == old) /* nothing sent */ 983159952Sobrien return; 984159952Sobrien 985159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) 986159952Sobrien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 987159952Sobrien else 988159952Sobrien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 989159952Sobrien 990159952Sobrien /* kick Tx */ 991159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 992159952Sobrien 993159952Sobrien /* 994159952Sobrien * Set a timeout in case the chip goes out to lunch. 995159952Sobrien */ 996159952Sobrien ifp->if_timer = 5; 997159952Sobrien} 998159952Sobrien 999159952Sobrienvoid 1000159952Sobriennfe_watchdog(struct ifnet *ifp) 1001159952Sobrien{ 1002159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1003159952Sobrien 1004159952Sobrien printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname); 1005159952Sobrien 1006159952Sobrien nfe_init(ifp); 1007159952Sobrien 1008159952Sobrien ifp->if_oerrors++; 1009159952Sobrien} 1010159952Sobrien 1011159952Sobrienint 1012159952Sobriennfe_init(struct ifnet *ifp) 1013159952Sobrien{ 1014159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1015159952Sobrien uint32_t tmp; 1016159952Sobrien 1017159952Sobrien nfe_stop(ifp, 0); 1018159952Sobrien 1019159952Sobrien NFE_WRITE(sc, NFE_TX_UNK, 0); 1020159952Sobrien NFE_WRITE(sc, NFE_STATUS, 0); 1021159952Sobrien 1022159952Sobrien sc->rxtxctl = NFE_RXTX_BIT2; 1023159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) 1024159952Sobrien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1025159952Sobrien else if (sc->sc_flags & NFE_JUMBO_SUP) 1026159952Sobrien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 1027159952Sobrien#ifdef NFE_CSUM 1028159952Sobrien if (sc->sc_flags & NFE_HW_CSUM) 1029159952Sobrien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1030159952Sobrien#endif 1031159952Sobrien#if NVLAN > 0 1032159952Sobrien /* 1033159952Sobrien * Although the adapter is capable of stripping VLAN tags from received 1034159952Sobrien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1035159952Sobrien * purpose. This will be done in software by our network stack. 1036159952Sobrien */ 1037159952Sobrien if (sc->sc_flags & NFE_HW_VLAN) 1038159952Sobrien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1039159952Sobrien#endif 1040159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1041159952Sobrien DELAY(10); 1042159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1043159952Sobrien 1044159952Sobrien#if NVLAN 1045159952Sobrien if (sc->sc_flags & NFE_HW_VLAN) 1046159952Sobrien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1047159952Sobrien#endif 1048159952Sobrien 1049159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1050159952Sobrien 1051159952Sobrien /* set MAC address */ 1052159952Sobrien nfe_set_macaddr(sc, sc->sc_arpcom.ac_enaddr); 1053159952Sobrien 1054159952Sobrien /* tell MAC where rings are in memory */ 1055159952Sobrien#ifdef __LP64__ 1056159952Sobrien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1057159952Sobrien#endif 1058159952Sobrien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1059159952Sobrien#ifdef __LP64__ 1060159952Sobrien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1061159952Sobrien#endif 1062159952Sobrien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1063159952Sobrien 1064159952Sobrien NFE_WRITE(sc, NFE_RING_SIZE, 1065159952Sobrien (NFE_RX_RING_COUNT - 1) << 16 | 1066159952Sobrien (NFE_TX_RING_COUNT - 1)); 1067159952Sobrien 1068159952Sobrien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1069159952Sobrien 1070159952Sobrien /* force MAC to wakeup */ 1071159952Sobrien tmp = NFE_READ(sc, NFE_PWR_STATE); 1072159952Sobrien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1073159952Sobrien DELAY(10); 1074159952Sobrien tmp = NFE_READ(sc, NFE_PWR_STATE); 1075159952Sobrien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1076159952Sobrien 1077159952Sobrien#if 1 1078159952Sobrien /* configure interrupts coalescing/mitigation */ 1079159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1080159952Sobrien#else 1081159952Sobrien /* no interrupt mitigation: one interrupt per packet */ 1082159952Sobrien NFE_WRITE(sc, NFE_IMTIMER, 970); 1083159952Sobrien#endif 1084159952Sobrien 1085159952Sobrien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1086159952Sobrien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1087159952Sobrien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1088159952Sobrien 1089159952Sobrien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1090159952Sobrien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1091159952Sobrien 1092159952Sobrien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1093159952Sobrien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1094159952Sobrien 1095159952Sobrien sc->rxtxctl &= ~NFE_RXTX_BIT2; 1096159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1097159952Sobrien DELAY(10); 1098159952Sobrien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1099159952Sobrien 1100159952Sobrien /* set Rx filter */ 1101159952Sobrien nfe_setmulti(sc); 1102159952Sobrien 1103159952Sobrien nfe_ifmedia_upd(ifp); 1104159952Sobrien 1105159952Sobrien /* enable Rx */ 1106159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1107159952Sobrien 1108159952Sobrien /* enable Tx */ 1109159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1110159952Sobrien 1111159952Sobrien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1112159952Sobrien 1113159952Sobrien /* enable interrupts */ 1114159952Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1115159952Sobrien 1116159952Sobrien timeout_add(&sc->sc_tick_ch, hz); 1117159952Sobrien 1118159952Sobrien ifp->if_flags |= IFF_RUNNING; 1119159952Sobrien ifp->if_flags &= ~IFF_OACTIVE; 1120159952Sobrien 1121159952Sobrien return 0; 1122159952Sobrien} 1123159952Sobrien 1124159952Sobrienvoid 1125159952Sobriennfe_stop(struct ifnet *ifp, int disable) 1126159952Sobrien{ 1127159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1128159952Sobrien 1129159952Sobrien timeout_del(&sc->sc_tick_ch); 1130159952Sobrien 1131159952Sobrien ifp->if_timer = 0; 1132159952Sobrien ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1133159952Sobrien 1134159952Sobrien mii_down(&sc->sc_mii); 1135159952Sobrien 1136159952Sobrien /* abort Tx */ 1137159952Sobrien NFE_WRITE(sc, NFE_TX_CTL, 0); 1138159952Sobrien 1139159952Sobrien /* disable Rx */ 1140159952Sobrien NFE_WRITE(sc, NFE_RX_CTL, 0); 1141159952Sobrien 1142159952Sobrien /* disable interrupts */ 1143159952Sobrien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1144159952Sobrien 1145159952Sobrien /* reset Tx and Rx rings */ 1146159952Sobrien nfe_reset_tx_ring(sc, &sc->txq); 1147159952Sobrien nfe_reset_rx_ring(sc, &sc->rxq); 1148159952Sobrien} 1149159952Sobrien 1150159952Sobrienint 1151159952Sobriennfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1152159952Sobrien{ 1153159952Sobrien struct nfe_desc32 *desc32; 1154159952Sobrien struct nfe_desc64 *desc64; 1155159952Sobrien struct nfe_rx_data *data; 1156159952Sobrien struct nfe_jbuf *jbuf; 1157159952Sobrien void **desc; 1158159952Sobrien bus_addr_t physaddr; 1159159952Sobrien int i, nsegs, error, descsize; 1160159952Sobrien 1161159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 1162159952Sobrien desc = (void **)&ring->desc64; 1163159952Sobrien descsize = sizeof (struct nfe_desc64); 1164159952Sobrien } else { 1165159952Sobrien desc = (void **)&ring->desc32; 1166159952Sobrien descsize = sizeof (struct nfe_desc32); 1167159952Sobrien } 1168159952Sobrien 1169159952Sobrien ring->cur = ring->next = 0; 1170159952Sobrien ring->bufsz = MCLBYTES; 1171159952Sobrien 1172159952Sobrien error = bus_dmamap_create(sc->sc_dmat, NFE_RX_RING_COUNT * descsize, 1, 1173159952Sobrien NFE_RX_RING_COUNT * descsize, 0, BUS_DMA_NOWAIT, &ring->map); 1174159952Sobrien if (error != 0) { 1175159952Sobrien printf("%s: could not create desc DMA map\n", 1176159952Sobrien sc->sc_dev.dv_xname); 1177159952Sobrien goto fail; 1178159952Sobrien } 1179159952Sobrien 1180159952Sobrien error = bus_dmamem_alloc(sc->sc_dmat, NFE_RX_RING_COUNT * descsize, 1181159952Sobrien PAGE_SIZE, 0, &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); 1182159952Sobrien if (error != 0) { 1183159952Sobrien printf("%s: could not allocate DMA memory\n", 1184159952Sobrien sc->sc_dev.dv_xname); 1185159952Sobrien goto fail; 1186159952Sobrien } 1187159952Sobrien 1188159952Sobrien error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, 1189159952Sobrien NFE_RX_RING_COUNT * descsize, (caddr_t *)desc, BUS_DMA_NOWAIT); 1190159952Sobrien if (error != 0) { 1191159952Sobrien printf("%s: could not map desc DMA memory\n", 1192159952Sobrien sc->sc_dev.dv_xname); 1193159952Sobrien goto fail; 1194159952Sobrien } 1195159952Sobrien 1196159952Sobrien error = bus_dmamap_load(sc->sc_dmat, ring->map, *desc, 1197159952Sobrien NFE_RX_RING_COUNT * descsize, NULL, BUS_DMA_NOWAIT); 1198159952Sobrien if (error != 0) { 1199159952Sobrien printf("%s: could not load desc DMA map\n", 1200159952Sobrien sc->sc_dev.dv_xname); 1201159952Sobrien goto fail; 1202159952Sobrien } 1203159952Sobrien 1204159952Sobrien bzero(*desc, NFE_RX_RING_COUNT * descsize); 1205159952Sobrien ring->physaddr = ring->map->dm_segs[0].ds_addr; 1206159952Sobrien 1207159952Sobrien if (sc->sc_flags & NFE_USE_JUMBO) { 1208159952Sobrien ring->bufsz = NFE_JBYTES; 1209159952Sobrien if ((error = nfe_jpool_alloc(sc)) != 0) { 1210159952Sobrien printf("%s: could not allocate jumbo frames\n", 1211159952Sobrien sc->sc_dev.dv_xname); 1212159952Sobrien goto fail; 1213159952Sobrien } 1214159952Sobrien } 1215159952Sobrien 1216159952Sobrien /* 1217159952Sobrien * Pre-allocate Rx buffers and populate Rx ring. 1218159952Sobrien */ 1219159952Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1220159952Sobrien data = &sc->rxq.data[i]; 1221159952Sobrien 1222159952Sobrien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 1223159952Sobrien if (data->m == NULL) { 1224159952Sobrien printf("%s: could not allocate rx mbuf\n", 1225159952Sobrien sc->sc_dev.dv_xname); 1226159952Sobrien error = ENOMEM; 1227159952Sobrien goto fail; 1228159952Sobrien } 1229159952Sobrien 1230159952Sobrien if (sc->sc_flags & NFE_USE_JUMBO) { 1231159952Sobrien if ((jbuf = nfe_jalloc(sc)) == NULL) { 1232159952Sobrien printf("%s: could not allocate jumbo buffer\n", 1233159952Sobrien sc->sc_dev.dv_xname); 1234159952Sobrien goto fail; 1235159952Sobrien } 1236159952Sobrien MEXTADD(data->m, jbuf->buf, NFE_JBYTES, 0, nfe_jfree, 1237159952Sobrien sc); 1238159952Sobrien 1239159952Sobrien physaddr = jbuf->physaddr; 1240159952Sobrien } else { 1241159952Sobrien error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 1242159952Sobrien MCLBYTES, 0, BUS_DMA_NOWAIT, &data->map); 1243159952Sobrien if (error != 0) { 1244159952Sobrien printf("%s: could not create DMA map\n", 1245159952Sobrien sc->sc_dev.dv_xname); 1246159952Sobrien goto fail; 1247159952Sobrien } 1248159952Sobrien MCLGET(data->m, M_DONTWAIT); 1249159952Sobrien if (!(data->m->m_flags & M_EXT)) { 1250159952Sobrien printf("%s: could not allocate mbuf cluster\n", 1251159952Sobrien sc->sc_dev.dv_xname); 1252159952Sobrien error = ENOMEM; 1253159952Sobrien goto fail; 1254159952Sobrien } 1255159952Sobrien 1256159952Sobrien error = bus_dmamap_load(sc->sc_dmat, data->map, 1257159952Sobrien mtod(data->m, void *), MCLBYTES, NULL, 1258159952Sobrien BUS_DMA_READ | BUS_DMA_NOWAIT); 1259159952Sobrien if (error != 0) { 1260159952Sobrien printf("%s: could not load rx buf DMA map", 1261159952Sobrien sc->sc_dev.dv_xname); 1262159952Sobrien goto fail; 1263159952Sobrien } 1264159952Sobrien physaddr = data->map->dm_segs[0].ds_addr; 1265159952Sobrien } 1266159952Sobrien 1267159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 1268159952Sobrien desc64 = &sc->rxq.desc64[i]; 1269159952Sobrien#if defined(__LP64__) 1270159952Sobrien desc64->physaddr[0] = htole32(physaddr >> 32); 1271159952Sobrien#endif 1272159952Sobrien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1273159952Sobrien desc64->length = htole16(sc->rxq.bufsz); 1274159952Sobrien desc64->flags = htole16(NFE_RX_READY); 1275159952Sobrien } else { 1276159952Sobrien desc32 = &sc->rxq.desc32[i]; 1277159952Sobrien desc32->physaddr = htole32(physaddr); 1278159952Sobrien desc32->length = htole16(sc->rxq.bufsz); 1279159952Sobrien desc32->flags = htole16(NFE_RX_READY); 1280159952Sobrien } 1281159952Sobrien } 1282159952Sobrien 1283159952Sobrien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, 1284159952Sobrien BUS_DMASYNC_PREWRITE); 1285159952Sobrien 1286159952Sobrien return 0; 1287159952Sobrien 1288159952Sobrienfail: nfe_free_rx_ring(sc, ring); 1289159952Sobrien return error; 1290159952Sobrien} 1291159952Sobrien 1292159952Sobrienvoid 1293159952Sobriennfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1294159952Sobrien{ 1295159952Sobrien int i; 1296159952Sobrien 1297159952Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1298159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 1299159952Sobrien ring->desc64[i].length = htole16(ring->bufsz); 1300159952Sobrien ring->desc64[i].flags = htole16(NFE_RX_READY); 1301159952Sobrien } else { 1302159952Sobrien ring->desc32[i].length = htole16(ring->bufsz); 1303159952Sobrien ring->desc32[i].flags = htole16(NFE_RX_READY); 1304159952Sobrien } 1305159952Sobrien } 1306159952Sobrien 1307159952Sobrien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, 1308159952Sobrien BUS_DMASYNC_PREWRITE); 1309159952Sobrien 1310159952Sobrien ring->cur = ring->next = 0; 1311159952Sobrien} 1312159952Sobrien 1313159952Sobrienvoid 1314159952Sobriennfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1315159952Sobrien{ 1316159952Sobrien struct nfe_rx_data *data; 1317159952Sobrien void *desc; 1318159952Sobrien int i, descsize; 1319159952Sobrien 1320159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 1321159952Sobrien desc = ring->desc64; 1322159952Sobrien descsize = sizeof (struct nfe_desc64); 1323159952Sobrien } else { 1324159952Sobrien desc = ring->desc32; 1325159952Sobrien descsize = sizeof (struct nfe_desc32); 1326159952Sobrien } 1327159952Sobrien 1328159952Sobrien if (desc != NULL) { 1329159952Sobrien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, 1330159952Sobrien ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1331159952Sobrien bus_dmamap_unload(sc->sc_dmat, ring->map); 1332159952Sobrien bus_dmamem_unmap(sc->sc_dmat, (caddr_t)desc, 1333159952Sobrien NFE_RX_RING_COUNT * descsize); 1334159952Sobrien bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); 1335159952Sobrien } 1336159952Sobrien 1337159952Sobrien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1338159952Sobrien data = &ring->data[i]; 1339159952Sobrien 1340159952Sobrien if (data->map != NULL) { 1341159952Sobrien bus_dmamap_sync(sc->sc_dmat, data->map, 0, 1342159952Sobrien data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1343159952Sobrien bus_dmamap_unload(sc->sc_dmat, data->map); 1344159952Sobrien bus_dmamap_destroy(sc->sc_dmat, data->map); 1345159952Sobrien } 1346159952Sobrien if (data->m != NULL) 1347159952Sobrien m_freem(data->m); 1348159952Sobrien } 1349159952Sobrien} 1350159952Sobrien 1351159952Sobrienstruct nfe_jbuf * 1352159952Sobriennfe_jalloc(struct nfe_softc *sc) 1353159952Sobrien{ 1354159952Sobrien struct nfe_jbuf *jbuf; 1355159952Sobrien 1356159952Sobrien jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 1357159952Sobrien if (jbuf == NULL) 1358159952Sobrien return NULL; 1359159952Sobrien SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 1360159952Sobrien return jbuf; 1361159952Sobrien} 1362159952Sobrien 1363159952Sobrien/* 1364159952Sobrien * This is called automatically by the network stack when the mbuf is freed. 1365159952Sobrien * Caution must be taken that the NIC might be reset by the time the mbuf is 1366159952Sobrien * freed. 1367159952Sobrien */ 1368159952Sobrienvoid 1369159952Sobriennfe_jfree(caddr_t buf, u_int size, void *arg) 1370159952Sobrien{ 1371159952Sobrien struct nfe_softc *sc = arg; 1372159952Sobrien struct nfe_jbuf *jbuf; 1373159952Sobrien int i; 1374159952Sobrien 1375159952Sobrien /* find the jbuf from the base pointer */ 1376159952Sobrien i = (buf - sc->rxq.jpool) / NFE_JBYTES; 1377159952Sobrien if (i < 0 || i >= NFE_JPOOL_COUNT) { 1378159952Sobrien printf("%s: request to free a buffer (%p) not managed by us\n", 1379159952Sobrien sc->sc_dev.dv_xname, buf); 1380159952Sobrien return; 1381159952Sobrien } 1382159952Sobrien jbuf = &sc->rxq.jbuf[i]; 1383159952Sobrien 1384159952Sobrien /* ..and put it back in the free list */ 1385159952Sobrien SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext); 1386159952Sobrien} 1387159952Sobrien 1388159952Sobrienint 1389159952Sobriennfe_jpool_alloc(struct nfe_softc *sc) 1390159952Sobrien{ 1391159952Sobrien struct nfe_rx_ring *ring = &sc->rxq; 1392159952Sobrien struct nfe_jbuf *jbuf; 1393159952Sobrien bus_addr_t physaddr; 1394159952Sobrien caddr_t buf; 1395159952Sobrien int i, nsegs, error; 1396159952Sobrien 1397159952Sobrien /* 1398159952Sobrien * Allocate a big chunk of DMA'able memory. 1399159952Sobrien */ 1400159952Sobrien error = bus_dmamap_create(sc->sc_dmat, NFE_JPOOL_SIZE, 1, 1401159952Sobrien NFE_JPOOL_SIZE, 0, BUS_DMA_NOWAIT, &ring->jmap); 1402159952Sobrien if (error != 0) { 1403159952Sobrien printf("%s: could not create jumbo DMA map\n", 1404159952Sobrien sc->sc_dev.dv_xname); 1405159952Sobrien goto fail; 1406159952Sobrien } 1407159952Sobrien 1408159952Sobrien error = bus_dmamem_alloc(sc->sc_dmat, NFE_JPOOL_SIZE, PAGE_SIZE, 0, 1409159952Sobrien &ring->jseg, 1, &nsegs, BUS_DMA_NOWAIT); 1410159952Sobrien if (error != 0) { 1411159952Sobrien printf("%s could not allocate jumbo DMA memory\n", 1412159952Sobrien sc->sc_dev.dv_xname); 1413159952Sobrien goto fail; 1414159952Sobrien } 1415159952Sobrien 1416159952Sobrien error = bus_dmamem_map(sc->sc_dmat, &ring->jseg, nsegs, NFE_JPOOL_SIZE, 1417159952Sobrien &ring->jpool, BUS_DMA_NOWAIT); 1418159952Sobrien if (error != 0) { 1419159952Sobrien printf("%s: could not map jumbo DMA memory\n", 1420159952Sobrien sc->sc_dev.dv_xname); 1421159952Sobrien goto fail; 1422159952Sobrien } 1423159952Sobrien 1424159952Sobrien error = bus_dmamap_load(sc->sc_dmat, ring->jmap, ring->jpool, 1425159952Sobrien NFE_JPOOL_SIZE, NULL, BUS_DMA_READ | BUS_DMA_NOWAIT); 1426159952Sobrien if (error != 0) { 1427159952Sobrien printf("%s: could not load jumbo DMA map\n", 1428159952Sobrien sc->sc_dev.dv_xname); 1429159952Sobrien goto fail; 1430159952Sobrien } 1431159952Sobrien 1432159952Sobrien /* ..and split it into 9KB chunks */ 1433159952Sobrien SLIST_INIT(&ring->jfreelist); 1434159952Sobrien 1435159952Sobrien buf = ring->jpool; 1436159952Sobrien physaddr = ring->jmap->dm_segs[0].ds_addr; 1437159952Sobrien for (i = 0; i < NFE_JPOOL_COUNT; i++) { 1438159952Sobrien jbuf = &ring->jbuf[i]; 1439159952Sobrien 1440159952Sobrien jbuf->buf = buf; 1441159952Sobrien jbuf->physaddr = physaddr; 1442159952Sobrien 1443159952Sobrien SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 1444159952Sobrien 1445159952Sobrien buf += NFE_JBYTES; 1446159952Sobrien physaddr += NFE_JBYTES; 1447159952Sobrien } 1448159952Sobrien 1449159952Sobrien return 0; 1450159952Sobrien 1451159952Sobrienfail: nfe_jpool_free(sc); 1452159952Sobrien return error; 1453159952Sobrien} 1454159952Sobrien 1455159952Sobrienvoid 1456159952Sobriennfe_jpool_free(struct nfe_softc *sc) 1457159952Sobrien{ 1458159952Sobrien struct nfe_rx_ring *ring = &sc->rxq; 1459159952Sobrien 1460159952Sobrien if (ring->jmap != NULL) { 1461159952Sobrien bus_dmamap_sync(sc->sc_dmat, ring->jmap, 0, 1462159952Sobrien ring->jmap->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1463159952Sobrien bus_dmamap_unload(sc->sc_dmat, ring->jmap); 1464159952Sobrien bus_dmamap_destroy(sc->sc_dmat, ring->jmap); 1465159952Sobrien } 1466159952Sobrien if (ring->jpool != NULL) { 1467159952Sobrien bus_dmamem_unmap(sc->sc_dmat, ring->jpool, NFE_JPOOL_SIZE); 1468159952Sobrien bus_dmamem_free(sc->sc_dmat, &ring->jseg, 1); 1469159952Sobrien } 1470159952Sobrien} 1471159952Sobrien 1472159952Sobrienint 1473159952Sobriennfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1474159952Sobrien{ 1475159952Sobrien int i, nsegs, error; 1476159952Sobrien void **desc; 1477159952Sobrien int descsize; 1478159952Sobrien 1479159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 1480159952Sobrien desc = (void **)&ring->desc64; 1481159952Sobrien descsize = sizeof (struct nfe_desc64); 1482159952Sobrien } else { 1483159952Sobrien desc = (void **)&ring->desc32; 1484159952Sobrien descsize = sizeof (struct nfe_desc32); 1485159952Sobrien } 1486159952Sobrien 1487159952Sobrien ring->queued = 0; 1488159952Sobrien ring->cur = ring->next = 0; 1489159952Sobrien 1490159952Sobrien error = bus_dmamap_create(sc->sc_dmat, NFE_TX_RING_COUNT * descsize, 1, 1491159952Sobrien NFE_TX_RING_COUNT * descsize, 0, BUS_DMA_NOWAIT, &ring->map); 1492159952Sobrien 1493159952Sobrien if (error != 0) { 1494159952Sobrien printf("%s: could not create desc DMA map\n", 1495159952Sobrien sc->sc_dev.dv_xname); 1496159952Sobrien goto fail; 1497159952Sobrien } 1498159952Sobrien 1499159952Sobrien error = bus_dmamem_alloc(sc->sc_dmat, NFE_TX_RING_COUNT * descsize, 1500159952Sobrien PAGE_SIZE, 0, &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); 1501159952Sobrien if (error != 0) { 1502159952Sobrien printf("%s: could not allocate DMA memory\n", 1503159952Sobrien sc->sc_dev.dv_xname); 1504159952Sobrien goto fail; 1505159952Sobrien } 1506159952Sobrien 1507159952Sobrien error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, 1508159952Sobrien NFE_TX_RING_COUNT * descsize, (caddr_t *)desc, BUS_DMA_NOWAIT); 1509159952Sobrien if (error != 0) { 1510159952Sobrien printf("%s: could not map desc DMA memory\n", 1511159952Sobrien sc->sc_dev.dv_xname); 1512159952Sobrien goto fail; 1513159952Sobrien } 1514159952Sobrien 1515159952Sobrien error = bus_dmamap_load(sc->sc_dmat, ring->map, *desc, 1516159952Sobrien NFE_TX_RING_COUNT * descsize, NULL, BUS_DMA_NOWAIT); 1517159952Sobrien if (error != 0) { 1518159952Sobrien printf("%s: could not load desc DMA map\n", 1519159952Sobrien sc->sc_dev.dv_xname); 1520159952Sobrien goto fail; 1521159952Sobrien } 1522159952Sobrien 1523159952Sobrien bzero(*desc, NFE_TX_RING_COUNT * descsize); 1524159952Sobrien ring->physaddr = ring->map->dm_segs[0].ds_addr; 1525159952Sobrien 1526159952Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1527159952Sobrien error = bus_dmamap_create(sc->sc_dmat, NFE_JBYTES, 1528159952Sobrien NFE_MAX_SCATTER, NFE_JBYTES, 0, BUS_DMA_NOWAIT, 1529159952Sobrien &ring->data[i].map); 1530159952Sobrien if (error != 0) { 1531159952Sobrien printf("%s: could not create DMA map\n", 1532159952Sobrien sc->sc_dev.dv_xname); 1533159952Sobrien goto fail; 1534159952Sobrien } 1535159952Sobrien } 1536159952Sobrien 1537159952Sobrien return 0; 1538159952Sobrien 1539159952Sobrienfail: nfe_free_tx_ring(sc, ring); 1540159952Sobrien return error; 1541159952Sobrien} 1542159952Sobrien 1543159952Sobrienvoid 1544159952Sobriennfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1545159952Sobrien{ 1546159952Sobrien struct nfe_tx_data *data; 1547159952Sobrien int i; 1548159952Sobrien 1549159952Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1550159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) 1551159952Sobrien ring->desc64[i].flags = 0; 1552159952Sobrien else 1553159952Sobrien ring->desc32[i].flags = 0; 1554159952Sobrien 1555159952Sobrien data = &ring->data[i]; 1556159952Sobrien 1557159952Sobrien if (data->m != NULL) { 1558159952Sobrien bus_dmamap_sync(sc->sc_dmat, data->active, 0, 1559159952Sobrien data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1560159952Sobrien bus_dmamap_unload(sc->sc_dmat, data->active); 1561159952Sobrien m_freem(data->m); 1562159952Sobrien data->m = NULL; 1563159952Sobrien } 1564159952Sobrien } 1565159952Sobrien 1566159952Sobrien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, 1567159952Sobrien BUS_DMASYNC_PREWRITE); 1568159952Sobrien 1569159952Sobrien ring->queued = 0; 1570159952Sobrien ring->cur = ring->next = 0; 1571159952Sobrien} 1572159952Sobrien 1573159952Sobrienvoid 1574159952Sobriennfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1575159952Sobrien{ 1576159952Sobrien struct nfe_tx_data *data; 1577159952Sobrien void *desc; 1578159952Sobrien int i, descsize; 1579159952Sobrien 1580159952Sobrien if (sc->sc_flags & NFE_40BIT_ADDR) { 1581159952Sobrien desc = ring->desc64; 1582159952Sobrien descsize = sizeof (struct nfe_desc64); 1583159952Sobrien } else { 1584159952Sobrien desc = ring->desc32; 1585159952Sobrien descsize = sizeof (struct nfe_desc32); 1586159952Sobrien } 1587159952Sobrien 1588159952Sobrien if (desc != NULL) { 1589159952Sobrien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, 1590159952Sobrien ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1591159952Sobrien bus_dmamap_unload(sc->sc_dmat, ring->map); 1592159952Sobrien bus_dmamem_unmap(sc->sc_dmat, (caddr_t)desc, 1593159952Sobrien NFE_TX_RING_COUNT * descsize); 1594159952Sobrien bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); 1595159952Sobrien } 1596159952Sobrien 1597159952Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1598159952Sobrien data = &ring->data[i]; 1599159952Sobrien 1600159952Sobrien if (data->m != NULL) { 1601159952Sobrien bus_dmamap_sync(sc->sc_dmat, data->active, 0, 1602159952Sobrien data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1603159952Sobrien bus_dmamap_unload(sc->sc_dmat, data->active); 1604159952Sobrien m_freem(data->m); 1605159952Sobrien } 1606159952Sobrien } 1607159952Sobrien 1608159952Sobrien /* ..and now actually destroy the DMA mappings */ 1609159952Sobrien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1610159952Sobrien data = &ring->data[i]; 1611159952Sobrien if (data->map == NULL) 1612159952Sobrien continue; 1613159952Sobrien bus_dmamap_destroy(sc->sc_dmat, data->map); 1614159952Sobrien } 1615159952Sobrien} 1616159952Sobrien 1617159952Sobrienint 1618159952Sobriennfe_ifmedia_upd(struct ifnet *ifp) 1619159952Sobrien{ 1620159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1621159952Sobrien struct mii_data *mii = &sc->sc_mii; 1622159952Sobrien struct mii_softc *miisc; 1623159952Sobrien 1624159952Sobrien if (mii->mii_instance != 0) { 1625159952Sobrien LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1626159952Sobrien mii_phy_reset(miisc); 1627159952Sobrien } 1628159952Sobrien return mii_mediachg(mii); 1629159952Sobrien} 1630159952Sobrien 1631159952Sobrienvoid 1632159952Sobriennfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1633159952Sobrien{ 1634159952Sobrien struct nfe_softc *sc = ifp->if_softc; 1635159952Sobrien struct mii_data *mii = &sc->sc_mii; 1636159952Sobrien 1637159952Sobrien mii_pollstat(mii); 1638159952Sobrien ifmr->ifm_status = mii->mii_media_status; 1639159952Sobrien ifmr->ifm_active = mii->mii_media_active; 1640159952Sobrien} 1641159952Sobrien 1642159952Sobrienvoid 1643159952Sobriennfe_setmulti(struct nfe_softc *sc) 1644159952Sobrien{ 1645159952Sobrien struct arpcom *ac = &sc->sc_arpcom; 1646159952Sobrien struct ifnet *ifp = &ac->ac_if; 1647159952Sobrien struct ether_multi *enm; 1648159952Sobrien struct ether_multistep step; 1649159952Sobrien uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 1650159952Sobrien uint32_t filter = NFE_RXFILTER_MAGIC; 1651159952Sobrien int i; 1652159952Sobrien 1653159952Sobrien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1654159952Sobrien bzero(addr, ETHER_ADDR_LEN); 1655159952Sobrien bzero(mask, ETHER_ADDR_LEN); 1656159952Sobrien goto done; 1657159952Sobrien } 1658159952Sobrien 1659159952Sobrien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1660159952Sobrien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1661159952Sobrien 1662159952Sobrien ETHER_FIRST_MULTI(step, ac, enm); 1663159952Sobrien while (enm != NULL) { 1664159952Sobrien if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { 1665159952Sobrien ifp->if_flags |= IFF_ALLMULTI; 1666159952Sobrien bzero(addr, ETHER_ADDR_LEN); 1667159952Sobrien bzero(mask, ETHER_ADDR_LEN); 1668159952Sobrien goto done; 1669159952Sobrien } 1670159952Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1671159952Sobrien addr[i] &= enm->enm_addrlo[i]; 1672159952Sobrien mask[i] &= ~enm->enm_addrlo[i]; 1673159952Sobrien } 1674159952Sobrien ETHER_NEXT_MULTI(step, enm); 1675159952Sobrien } 1676159952Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) 1677159952Sobrien mask[i] |= addr[i]; 1678159952Sobrien 1679159952Sobriendone: 1680159952Sobrien addr[0] |= 0x01; /* make sure multicast bit is set */ 1681159952Sobrien 1682159952Sobrien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1683159952Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1684159952Sobrien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1685159952Sobrien addr[5] << 8 | addr[4]); 1686159952Sobrien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1687159952Sobrien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1688159952Sobrien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1689159952Sobrien mask[5] << 8 | mask[4]); 1690159952Sobrien 1691159952Sobrien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1692159952Sobrien NFE_WRITE(sc, NFE_RXFILTER, filter); 1693159952Sobrien} 1694159952Sobrien 1695159952Sobrienvoid 1696159952Sobriennfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 1697159952Sobrien{ 1698159952Sobrien uint32_t tmp; 1699159952Sobrien 1700159952Sobrien tmp = NFE_READ(sc, NFE_MACADDR_LO); 1701159952Sobrien addr[0] = (tmp >> 8) & 0xff; 1702159952Sobrien addr[1] = (tmp & 0xff); 1703159952Sobrien 1704159952Sobrien tmp = NFE_READ(sc, NFE_MACADDR_HI); 1705159952Sobrien addr[2] = (tmp >> 24) & 0xff; 1706159952Sobrien addr[3] = (tmp >> 16) & 0xff; 1707159952Sobrien addr[4] = (tmp >> 8) & 0xff; 1708159952Sobrien addr[5] = (tmp & 0xff); 1709159952Sobrien} 1710159952Sobrien 1711159952Sobrienvoid 1712159952Sobriennfe_set_macaddr(struct nfe_softc *sc, const uint8_t *addr) 1713159952Sobrien{ 1714159952Sobrien NFE_WRITE(sc, NFE_MACADDR_LO, 1715159952Sobrien addr[5] << 8 | addr[4]); 1716159952Sobrien NFE_WRITE(sc, NFE_MACADDR_HI, 1717159952Sobrien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1718159952Sobrien} 1719159952Sobrien 1720159952Sobrienvoid 1721159952Sobriennfe_tick(void *arg) 1722159952Sobrien{ 1723159952Sobrien struct nfe_softc *sc = arg; 1724159952Sobrien int s; 1725159952Sobrien 1726159952Sobrien s = splnet(); 1727159952Sobrien mii_tick(&sc->sc_mii); 1728159952Sobrien splx(s); 1729159952Sobrien 1730159952Sobrien timeout_add(&sc->sc_tick_ch, hz); 1731159952Sobrien} 1732