1257c5577SDavid E. O'Brien /* $OpenBSD: if_nfe.c,v 1.57 2006/04/26 02:07:29 jsg Exp $ */ 2257c5577SDavid E. O'Brien 3257c5577SDavid E. O'Brien /*- 4257c5577SDavid E. O'Brien * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 5257c5577SDavid E. O'Brien * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 6257c5577SDavid E. O'Brien * 7257c5577SDavid E. O'Brien * Permission to use, copy, modify, and distribute this software for any 8257c5577SDavid E. O'Brien * purpose with or without fee is hereby granted, provided that the above 9257c5577SDavid E. O'Brien * copyright notice and this permission notice appear in all copies. 10257c5577SDavid E. O'Brien * 11257c5577SDavid E. O'Brien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12257c5577SDavid E. O'Brien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13257c5577SDavid E. O'Brien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14257c5577SDavid E. O'Brien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15257c5577SDavid E. O'Brien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16257c5577SDavid E. O'Brien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17257c5577SDavid E. O'Brien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18257c5577SDavid E. O'Brien */ 19257c5577SDavid E. O'Brien 20257c5577SDavid E. O'Brien /* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 21257c5577SDavid E. O'Brien 22257c5577SDavid E. O'Brien #include "bpfilter.h" 23257c5577SDavid E. O'Brien #include "vlan.h" 24257c5577SDavid E. O'Brien 25257c5577SDavid E. O'Brien #include <sys/param.h> 26257c5577SDavid E. O'Brien #include <sys/endian.h> 27257c5577SDavid E. O'Brien #include <sys/systm.h> 28257c5577SDavid E. O'Brien #include <sys/types.h> 29257c5577SDavid E. O'Brien #include <sys/sockio.h> 30257c5577SDavid E. O'Brien #include <sys/mbuf.h> 31257c5577SDavid E. O'Brien #include <sys/queue.h> 32257c5577SDavid E. O'Brien #include <sys/malloc.h> 33257c5577SDavid E. O'Brien #include <sys/kernel.h> 34257c5577SDavid E. O'Brien #include <sys/device.h> 35257c5577SDavid E. O'Brien #include <sys/socket.h> 36257c5577SDavid E. O'Brien 37257c5577SDavid E. O'Brien #include <machine/bus.h> 38257c5577SDavid E. O'Brien 39257c5577SDavid E. O'Brien #include <net/if.h> 40257c5577SDavid E. O'Brien #include <net/if_dl.h> 41257c5577SDavid E. O'Brien #include <net/if_media.h> 42257c5577SDavid E. O'Brien 43257c5577SDavid E. O'Brien #ifdef INET 44257c5577SDavid E. O'Brien #include <netinet/in.h> 45257c5577SDavid E. O'Brien #include <netinet/in_systm.h> 46257c5577SDavid E. O'Brien #include <netinet/in_var.h> 47257c5577SDavid E. O'Brien #include <netinet/ip.h> 48257c5577SDavid E. O'Brien #include <netinet/if_ether.h> 49257c5577SDavid E. O'Brien #endif 50257c5577SDavid E. O'Brien 51257c5577SDavid E. O'Brien #if NVLAN > 0 52257c5577SDavid E. O'Brien #include <net/if_types.h> 53257c5577SDavid E. O'Brien #include <net/if_vlan_var.h> 54257c5577SDavid E. O'Brien #endif 55257c5577SDavid E. O'Brien 56257c5577SDavid E. O'Brien #if NBPFILTER > 0 57257c5577SDavid E. O'Brien #include <net/bpf.h> 58257c5577SDavid E. O'Brien #endif 59257c5577SDavid E. O'Brien 60257c5577SDavid E. O'Brien #include <dev/mii/mii.h> 61257c5577SDavid E. O'Brien #include <dev/mii/miivar.h> 62257c5577SDavid E. O'Brien 63257c5577SDavid E. O'Brien #include <dev/pci/pcireg.h> 64257c5577SDavid E. O'Brien #include <dev/pci/pcivar.h> 65257c5577SDavid E. O'Brien #include <dev/pci/pcidevs.h> 66257c5577SDavid E. O'Brien 67257c5577SDavid E. O'Brien #include <dev/pci/if_nfereg.h> 68257c5577SDavid E. O'Brien #include <dev/pci/if_nfevar.h> 69257c5577SDavid E. O'Brien 70257c5577SDavid E. O'Brien int nfe_match(struct device *, void *, void *); 71257c5577SDavid E. O'Brien void nfe_attach(struct device *, struct device *, void *); 72257c5577SDavid E. O'Brien void nfe_power(int, void *); 73257c5577SDavid E. O'Brien void nfe_miibus_statchg(struct device *); 74257c5577SDavid E. O'Brien int nfe_miibus_readreg(struct device *, int, int); 75257c5577SDavid E. O'Brien void nfe_miibus_writereg(struct device *, int, int, int); 76257c5577SDavid E. O'Brien int nfe_intr(void *); 77257c5577SDavid E. O'Brien int nfe_ioctl(struct ifnet *, u_long, caddr_t); 78257c5577SDavid E. O'Brien void nfe_txdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 79257c5577SDavid E. O'Brien void nfe_txdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 80257c5577SDavid E. O'Brien void nfe_txdesc32_rsync(struct nfe_softc *, int, int, int); 81257c5577SDavid E. O'Brien void nfe_txdesc64_rsync(struct nfe_softc *, int, int, int); 82257c5577SDavid E. O'Brien void nfe_rxdesc32_sync(struct nfe_softc *, struct nfe_desc32 *, int); 83257c5577SDavid E. O'Brien void nfe_rxdesc64_sync(struct nfe_softc *, struct nfe_desc64 *, int); 84257c5577SDavid E. O'Brien void nfe_rxeof(struct nfe_softc *); 85257c5577SDavid E. O'Brien void nfe_txeof(struct nfe_softc *); 86257c5577SDavid E. O'Brien int nfe_encap(struct nfe_softc *, struct mbuf *); 87257c5577SDavid E. O'Brien void nfe_start(struct ifnet *); 88257c5577SDavid E. O'Brien void nfe_watchdog(struct ifnet *); 89257c5577SDavid E. O'Brien int nfe_init(struct ifnet *); 90257c5577SDavid E. O'Brien void nfe_stop(struct ifnet *, int); 91257c5577SDavid E. O'Brien struct nfe_jbuf *nfe_jalloc(struct nfe_softc *); 92257c5577SDavid E. O'Brien void nfe_jfree(caddr_t, u_int, void *); 93257c5577SDavid E. O'Brien int nfe_jpool_alloc(struct nfe_softc *); 94257c5577SDavid E. O'Brien void nfe_jpool_free(struct nfe_softc *); 95257c5577SDavid E. O'Brien int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 96257c5577SDavid E. O'Brien void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 97257c5577SDavid E. O'Brien void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 98257c5577SDavid E. O'Brien int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 99257c5577SDavid E. O'Brien void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 100257c5577SDavid E. O'Brien void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 101257c5577SDavid E. O'Brien int nfe_ifmedia_upd(struct ifnet *); 102257c5577SDavid E. O'Brien void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 103257c5577SDavid E. O'Brien void nfe_setmulti(struct nfe_softc *); 104257c5577SDavid E. O'Brien void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 105257c5577SDavid E. O'Brien void nfe_set_macaddr(struct nfe_softc *, const uint8_t *); 106257c5577SDavid E. O'Brien void nfe_tick(void *); 107257c5577SDavid E. O'Brien 108257c5577SDavid E. O'Brien struct cfattach nfe_ca = { 109257c5577SDavid E. O'Brien sizeof (struct nfe_softc), nfe_match, nfe_attach 110257c5577SDavid E. O'Brien }; 111257c5577SDavid E. O'Brien 112257c5577SDavid E. O'Brien struct cfdriver nfe_cd = { 113257c5577SDavid E. O'Brien NULL, "nfe", DV_IFNET 114257c5577SDavid E. O'Brien }; 115257c5577SDavid E. O'Brien 116257c5577SDavid E. O'Brien /*#define NFE_NO_JUMBO*/ 117257c5577SDavid E. O'Brien 118257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 119257c5577SDavid E. O'Brien int nfedebug = 0; 120257c5577SDavid E. O'Brien #define DPRINTF(x) do { if (nfedebug) printf x; } while (0) 121257c5577SDavid E. O'Brien #define DPRINTFN(n,x) do { if (nfedebug >= (n)) printf x; } while (0) 122257c5577SDavid E. O'Brien #else 123257c5577SDavid E. O'Brien #define DPRINTF(x) 124257c5577SDavid E. O'Brien #define DPRINTFN(n,x) 125257c5577SDavid E. O'Brien #endif 126257c5577SDavid E. O'Brien 127257c5577SDavid E. O'Brien const struct pci_matchid nfe_devices[] = { 128257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN }, 129257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN }, 130257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1 }, 131257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN2 }, 132257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN3 }, 133257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4 }, 134257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN5 }, 135257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN1 }, 136257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN2 }, 137257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1 }, 138257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2 }, 139257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN1 }, 140257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN2 }, 141257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1 }, 142257c5577SDavid E. O'Brien { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2 } 143257c5577SDavid E. O'Brien }; 144257c5577SDavid E. O'Brien 145257c5577SDavid E. O'Brien int 146257c5577SDavid E. O'Brien nfe_match(struct device *dev, void *match, void *aux) 147257c5577SDavid E. O'Brien { 148257c5577SDavid E. O'Brien return pci_matchbyid((struct pci_attach_args *)aux, nfe_devices, 149257c5577SDavid E. O'Brien sizeof (nfe_devices) / sizeof (nfe_devices[0])); 150257c5577SDavid E. O'Brien } 151257c5577SDavid E. O'Brien 152257c5577SDavid E. O'Brien void 153257c5577SDavid E. O'Brien nfe_attach(struct device *parent, struct device *self, void *aux) 154257c5577SDavid E. O'Brien { 155257c5577SDavid E. O'Brien struct nfe_softc *sc = (struct nfe_softc *)self; 156257c5577SDavid E. O'Brien struct pci_attach_args *pa = aux; 157257c5577SDavid E. O'Brien pci_chipset_tag_t pc = pa->pa_pc; 158257c5577SDavid E. O'Brien pci_intr_handle_t ih; 159257c5577SDavid E. O'Brien const char *intrstr; 160257c5577SDavid E. O'Brien struct ifnet *ifp; 161257c5577SDavid E. O'Brien bus_size_t memsize; 162257c5577SDavid E. O'Brien pcireg_t memtype; 163257c5577SDavid E. O'Brien 164257c5577SDavid E. O'Brien memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, NFE_PCI_BA); 165257c5577SDavid E. O'Brien switch (memtype) { 166257c5577SDavid E. O'Brien case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: 167257c5577SDavid E. O'Brien case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: 168257c5577SDavid E. O'Brien if (pci_mapreg_map(pa, NFE_PCI_BA, memtype, 0, &sc->sc_memt, 169257c5577SDavid E. O'Brien &sc->sc_memh, NULL, &memsize, 0) == 0) 170257c5577SDavid E. O'Brien break; 171257c5577SDavid E. O'Brien /* FALLTHROUGH */ 172257c5577SDavid E. O'Brien default: 173257c5577SDavid E. O'Brien printf(": could not map mem space\n"); 174257c5577SDavid E. O'Brien return; 175257c5577SDavid E. O'Brien } 176257c5577SDavid E. O'Brien 177257c5577SDavid E. O'Brien if (pci_intr_map(pa, &ih) != 0) { 178257c5577SDavid E. O'Brien printf(": could not map interrupt\n"); 179257c5577SDavid E. O'Brien return; 180257c5577SDavid E. O'Brien } 181257c5577SDavid E. O'Brien 182257c5577SDavid E. O'Brien intrstr = pci_intr_string(pc, ih); 183257c5577SDavid E. O'Brien sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, nfe_intr, sc, 184257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 185257c5577SDavid E. O'Brien if (sc->sc_ih == NULL) { 186257c5577SDavid E. O'Brien printf(": could not establish interrupt"); 187257c5577SDavid E. O'Brien if (intrstr != NULL) 188257c5577SDavid E. O'Brien printf(" at %s", intrstr); 189257c5577SDavid E. O'Brien printf("\n"); 190257c5577SDavid E. O'Brien return; 191257c5577SDavid E. O'Brien } 192257c5577SDavid E. O'Brien printf(": %s", intrstr); 193257c5577SDavid E. O'Brien 194257c5577SDavid E. O'Brien sc->sc_dmat = pa->pa_dmat; 195257c5577SDavid E. O'Brien 196257c5577SDavid E. O'Brien nfe_get_macaddr(sc, sc->sc_arpcom.ac_enaddr); 197257c5577SDavid E. O'Brien printf(", address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr)); 198257c5577SDavid E. O'Brien 199257c5577SDavid E. O'Brien sc->sc_flags = 0; 200257c5577SDavid E. O'Brien 201257c5577SDavid E. O'Brien switch (PCI_PRODUCT(pa->pa_id)) { 202257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 203257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 204257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 205257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 206257c5577SDavid E. O'Brien sc->sc_flags |= NFE_JUMBO_SUP | NFE_HW_CSUM; 207257c5577SDavid E. O'Brien break; 208257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 209257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 210257c5577SDavid E. O'Brien sc->sc_flags |= NFE_40BIT_ADDR; 211257c5577SDavid E. O'Brien break; 212257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN1: 213257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_CK804_LAN2: 214257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 215257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 216257c5577SDavid E. O'Brien sc->sc_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM; 217257c5577SDavid E. O'Brien break; 218257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 219257c5577SDavid E. O'Brien case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 220257c5577SDavid E. O'Brien sc->sc_flags |= NFE_JUMBO_SUP | NFE_40BIT_ADDR | NFE_HW_CSUM | 221257c5577SDavid E. O'Brien NFE_HW_VLAN; 222257c5577SDavid E. O'Brien break; 223257c5577SDavid E. O'Brien } 224257c5577SDavid E. O'Brien 225257c5577SDavid E. O'Brien #ifndef NFE_NO_JUMBO 226257c5577SDavid E. O'Brien /* enable jumbo frames for adapters that support it */ 227257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_JUMBO_SUP) 228257c5577SDavid E. O'Brien sc->sc_flags |= NFE_USE_JUMBO; 229257c5577SDavid E. O'Brien #endif 230257c5577SDavid E. O'Brien 231257c5577SDavid E. O'Brien /* 232257c5577SDavid E. O'Brien * Allocate Tx and Rx rings. 233257c5577SDavid E. O'Brien */ 234257c5577SDavid E. O'Brien if (nfe_alloc_tx_ring(sc, &sc->txq) != 0) { 235257c5577SDavid E. O'Brien printf("%s: could not allocate Tx ring\n", 236257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 237257c5577SDavid E. O'Brien return; 238257c5577SDavid E. O'Brien } 239257c5577SDavid E. O'Brien 240257c5577SDavid E. O'Brien if (nfe_alloc_rx_ring(sc, &sc->rxq) != 0) { 241257c5577SDavid E. O'Brien printf("%s: could not allocate Rx ring\n", 242257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 243257c5577SDavid E. O'Brien nfe_free_tx_ring(sc, &sc->txq); 244257c5577SDavid E. O'Brien return; 245257c5577SDavid E. O'Brien } 246257c5577SDavid E. O'Brien 247257c5577SDavid E. O'Brien ifp = &sc->sc_arpcom.ac_if; 248257c5577SDavid E. O'Brien ifp->if_softc = sc; 249257c5577SDavid E. O'Brien ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 250257c5577SDavid E. O'Brien ifp->if_ioctl = nfe_ioctl; 251257c5577SDavid E. O'Brien ifp->if_start = nfe_start; 252257c5577SDavid E. O'Brien ifp->if_watchdog = nfe_watchdog; 253257c5577SDavid E. O'Brien ifp->if_init = nfe_init; 254257c5577SDavid E. O'Brien ifp->if_baudrate = IF_Gbps(1); 255257c5577SDavid E. O'Brien IFQ_SET_MAXLEN(&ifp->if_snd, NFE_IFQ_MAXLEN); 256257c5577SDavid E. O'Brien IFQ_SET_READY(&ifp->if_snd); 257257c5577SDavid E. O'Brien strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 258257c5577SDavid E. O'Brien 259257c5577SDavid E. O'Brien ifp->if_capabilities = IFCAP_VLAN_MTU; 260257c5577SDavid E. O'Brien #if NVLAN > 0 261257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_HW_VLAN) 262257c5577SDavid E. O'Brien ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 263257c5577SDavid E. O'Brien #endif 264257c5577SDavid E. O'Brien #ifdef NFE_CSUM 265257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_HW_CSUM) { 266257c5577SDavid E. O'Brien ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | 267257c5577SDavid E. O'Brien IFCAP_CSUM_UDPv4; 268257c5577SDavid E. O'Brien } 269257c5577SDavid E. O'Brien #endif 270257c5577SDavid E. O'Brien 271257c5577SDavid E. O'Brien sc->sc_mii.mii_ifp = ifp; 272257c5577SDavid E. O'Brien sc->sc_mii.mii_readreg = nfe_miibus_readreg; 273257c5577SDavid E. O'Brien sc->sc_mii.mii_writereg = nfe_miibus_writereg; 274257c5577SDavid E. O'Brien sc->sc_mii.mii_statchg = nfe_miibus_statchg; 275257c5577SDavid E. O'Brien 276257c5577SDavid E. O'Brien ifmedia_init(&sc->sc_mii.mii_media, 0, nfe_ifmedia_upd, 277257c5577SDavid E. O'Brien nfe_ifmedia_sts); 278257c5577SDavid E. O'Brien mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, 279257c5577SDavid E. O'Brien MII_OFFSET_ANY, 0); 280257c5577SDavid E. O'Brien if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { 281257c5577SDavid E. O'Brien printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); 282257c5577SDavid E. O'Brien ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL, 283257c5577SDavid E. O'Brien 0, NULL); 284257c5577SDavid E. O'Brien ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_MANUAL); 285257c5577SDavid E. O'Brien } else 286257c5577SDavid E. O'Brien ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO); 287257c5577SDavid E. O'Brien 288257c5577SDavid E. O'Brien if_attach(ifp); 289257c5577SDavid E. O'Brien ether_ifattach(ifp); 290257c5577SDavid E. O'Brien 291257c5577SDavid E. O'Brien timeout_set(&sc->sc_tick_ch, nfe_tick, sc); 292257c5577SDavid E. O'Brien 293257c5577SDavid E. O'Brien sc->sc_powerhook = powerhook_establish(nfe_power, sc); 294257c5577SDavid E. O'Brien } 295257c5577SDavid E. O'Brien 296257c5577SDavid E. O'Brien void 297257c5577SDavid E. O'Brien nfe_power(int why, void *arg) 298257c5577SDavid E. O'Brien { 299257c5577SDavid E. O'Brien struct nfe_softc *sc = arg; 300257c5577SDavid E. O'Brien struct ifnet *ifp; 301257c5577SDavid E. O'Brien 302257c5577SDavid E. O'Brien if (why == PWR_RESUME) { 303257c5577SDavid E. O'Brien ifp = &sc->sc_arpcom.ac_if; 304257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 305257c5577SDavid E. O'Brien nfe_init(ifp); 306257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_RUNNING) 307257c5577SDavid E. O'Brien nfe_start(ifp); 308257c5577SDavid E. O'Brien } 309257c5577SDavid E. O'Brien } 310257c5577SDavid E. O'Brien } 311257c5577SDavid E. O'Brien 312257c5577SDavid E. O'Brien void 313257c5577SDavid E. O'Brien nfe_miibus_statchg(struct device *dev) 314257c5577SDavid E. O'Brien { 315257c5577SDavid E. O'Brien struct nfe_softc *sc = (struct nfe_softc *)dev; 316257c5577SDavid E. O'Brien struct mii_data *mii = &sc->sc_mii; 317257c5577SDavid E. O'Brien uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 318257c5577SDavid E. O'Brien 319257c5577SDavid E. O'Brien phy = NFE_READ(sc, NFE_PHY_IFACE); 320257c5577SDavid E. O'Brien phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 321257c5577SDavid E. O'Brien 322257c5577SDavid E. O'Brien seed = NFE_READ(sc, NFE_RNDSEED); 323257c5577SDavid E. O'Brien seed &= ~NFE_SEED_MASK; 324257c5577SDavid E. O'Brien 325257c5577SDavid E. O'Brien if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 326257c5577SDavid E. O'Brien phy |= NFE_PHY_HDX; /* half-duplex */ 327257c5577SDavid E. O'Brien misc |= NFE_MISC1_HDX; 328257c5577SDavid E. O'Brien } 329257c5577SDavid E. O'Brien 330257c5577SDavid E. O'Brien switch (IFM_SUBTYPE(mii->mii_media_active)) { 331257c5577SDavid E. O'Brien case IFM_1000_T: /* full-duplex only */ 332257c5577SDavid E. O'Brien link |= NFE_MEDIA_1000T; 333257c5577SDavid E. O'Brien seed |= NFE_SEED_1000T; 334257c5577SDavid E. O'Brien phy |= NFE_PHY_1000T; 335257c5577SDavid E. O'Brien break; 336257c5577SDavid E. O'Brien case IFM_100_TX: 337257c5577SDavid E. O'Brien link |= NFE_MEDIA_100TX; 338257c5577SDavid E. O'Brien seed |= NFE_SEED_100TX; 339257c5577SDavid E. O'Brien phy |= NFE_PHY_100TX; 340257c5577SDavid E. O'Brien break; 341257c5577SDavid E. O'Brien case IFM_10_T: 342257c5577SDavid E. O'Brien link |= NFE_MEDIA_10T; 343257c5577SDavid E. O'Brien seed |= NFE_SEED_10T; 344257c5577SDavid E. O'Brien break; 345257c5577SDavid E. O'Brien } 346257c5577SDavid E. O'Brien 347257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 348257c5577SDavid E. O'Brien 349257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_IFACE, phy); 350257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MISC1, misc); 351257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_LINKSPEED, link); 352257c5577SDavid E. O'Brien } 353257c5577SDavid E. O'Brien 354257c5577SDavid E. O'Brien int 355257c5577SDavid E. O'Brien nfe_miibus_readreg(struct device *dev, int phy, int reg) 356257c5577SDavid E. O'Brien { 357257c5577SDavid E. O'Brien struct nfe_softc *sc = (struct nfe_softc *)dev; 358257c5577SDavid E. O'Brien uint32_t val; 359257c5577SDavid E. O'Brien int ntries; 360257c5577SDavid E. O'Brien 361257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 362257c5577SDavid E. O'Brien 363257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 364257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 365257c5577SDavid E. O'Brien DELAY(100); 366257c5577SDavid E. O'Brien } 367257c5577SDavid E. O'Brien 368257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 369257c5577SDavid E. O'Brien 370257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 371257c5577SDavid E. O'Brien DELAY(100); 372257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 373257c5577SDavid E. O'Brien break; 374257c5577SDavid E. O'Brien } 375257c5577SDavid E. O'Brien if (ntries == 1000) { 376257c5577SDavid E. O'Brien DPRINTFN(2, ("%s: timeout waiting for PHY\n", 377257c5577SDavid E. O'Brien sc->sc_dev.dv_xname)); 378257c5577SDavid E. O'Brien return 0; 379257c5577SDavid E. O'Brien } 380257c5577SDavid E. O'Brien 381257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 382257c5577SDavid E. O'Brien DPRINTFN(2, ("%s: could not read PHY\n", 383257c5577SDavid E. O'Brien sc->sc_dev.dv_xname)); 384257c5577SDavid E. O'Brien return 0; 385257c5577SDavid E. O'Brien } 386257c5577SDavid E. O'Brien 387257c5577SDavid E. O'Brien val = NFE_READ(sc, NFE_PHY_DATA); 388257c5577SDavid E. O'Brien if (val != 0xffffffff && val != 0) 389257c5577SDavid E. O'Brien sc->mii_phyaddr = phy; 390257c5577SDavid E. O'Brien 391257c5577SDavid E. O'Brien DPRINTFN(2, ("%s: mii read phy %d reg 0x%x ret 0x%x\n", 392257c5577SDavid E. O'Brien sc->sc_dev.dv_xname, phy, reg, val)); 393257c5577SDavid E. O'Brien 394257c5577SDavid E. O'Brien return val; 395257c5577SDavid E. O'Brien } 396257c5577SDavid E. O'Brien 397257c5577SDavid E. O'Brien void 398257c5577SDavid E. O'Brien nfe_miibus_writereg(struct device *dev, int phy, int reg, int val) 399257c5577SDavid E. O'Brien { 400257c5577SDavid E. O'Brien struct nfe_softc *sc = (struct nfe_softc *)dev; 401257c5577SDavid E. O'Brien uint32_t ctl; 402257c5577SDavid E. O'Brien int ntries; 403257c5577SDavid E. O'Brien 404257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 405257c5577SDavid E. O'Brien 406257c5577SDavid E. O'Brien if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 407257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 408257c5577SDavid E. O'Brien DELAY(100); 409257c5577SDavid E. O'Brien } 410257c5577SDavid E. O'Brien 411257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_DATA, val); 412257c5577SDavid E. O'Brien ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 413257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_CTL, ctl); 414257c5577SDavid E. O'Brien 415257c5577SDavid E. O'Brien for (ntries = 0; ntries < 1000; ntries++) { 416257c5577SDavid E. O'Brien DELAY(100); 417257c5577SDavid E. O'Brien if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 418257c5577SDavid E. O'Brien break; 419257c5577SDavid E. O'Brien } 420257c5577SDavid E. O'Brien #ifdef NFE_DEBUG 421257c5577SDavid E. O'Brien if (nfedebug >= 2 && ntries == 1000) 422257c5577SDavid E. O'Brien printf("could not write to PHY\n"); 423257c5577SDavid E. O'Brien #endif 424257c5577SDavid E. O'Brien } 425257c5577SDavid E. O'Brien 426257c5577SDavid E. O'Brien int 427257c5577SDavid E. O'Brien nfe_intr(void *arg) 428257c5577SDavid E. O'Brien { 429257c5577SDavid E. O'Brien struct nfe_softc *sc = arg; 430257c5577SDavid E. O'Brien struct ifnet *ifp = &sc->sc_arpcom.ac_if; 431257c5577SDavid E. O'Brien uint32_t r; 432257c5577SDavid E. O'Brien 433257c5577SDavid E. O'Brien if ((r = NFE_READ(sc, NFE_IRQ_STATUS)) == 0) 434257c5577SDavid E. O'Brien return 0; /* not for us */ 435257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_STATUS, r); 436257c5577SDavid E. O'Brien 437257c5577SDavid E. O'Brien DPRINTFN(5, ("nfe_intr: interrupt register %x\n", r)); 438257c5577SDavid E. O'Brien 439257c5577SDavid E. O'Brien if (r & NFE_IRQ_LINK) { 440257c5577SDavid E. O'Brien NFE_READ(sc, NFE_PHY_STATUS); 441257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 442257c5577SDavid E. O'Brien DPRINTF(("%s: link state changed\n", sc->sc_dev.dv_xname)); 443257c5577SDavid E. O'Brien } 444257c5577SDavid E. O'Brien 445257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_RUNNING) { 446257c5577SDavid E. O'Brien /* check Rx ring */ 447257c5577SDavid E. O'Brien nfe_rxeof(sc); 448257c5577SDavid E. O'Brien 449257c5577SDavid E. O'Brien /* check Tx ring */ 450257c5577SDavid E. O'Brien nfe_txeof(sc); 451257c5577SDavid E. O'Brien } 452257c5577SDavid E. O'Brien 453257c5577SDavid E. O'Brien return 1; 454257c5577SDavid E. O'Brien } 455257c5577SDavid E. O'Brien 456257c5577SDavid E. O'Brien int 457257c5577SDavid E. O'Brien nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 458257c5577SDavid E. O'Brien { 459257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 460257c5577SDavid E. O'Brien struct ifreq *ifr = (struct ifreq *)data; 461257c5577SDavid E. O'Brien struct ifaddr *ifa = (struct ifaddr *)data; 462257c5577SDavid E. O'Brien int s, error = 0; 463257c5577SDavid E. O'Brien 464257c5577SDavid E. O'Brien s = splnet(); 465257c5577SDavid E. O'Brien 466257c5577SDavid E. O'Brien if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) { 467257c5577SDavid E. O'Brien splx(s); 468257c5577SDavid E. O'Brien return error; 469257c5577SDavid E. O'Brien } 470257c5577SDavid E. O'Brien 471257c5577SDavid E. O'Brien switch (cmd) { 472257c5577SDavid E. O'Brien case SIOCSIFADDR: 473257c5577SDavid E. O'Brien ifp->if_flags |= IFF_UP; 474257c5577SDavid E. O'Brien if (!(ifp->if_flags & IFF_RUNNING)) 475257c5577SDavid E. O'Brien nfe_init(ifp); 476257c5577SDavid E. O'Brien #ifdef INET 477257c5577SDavid E. O'Brien if (ifa->ifa_addr->sa_family == AF_INET) 478257c5577SDavid E. O'Brien arp_ifinit(&sc->sc_arpcom, ifa); 479257c5577SDavid E. O'Brien #endif 480257c5577SDavid E. O'Brien break; 481257c5577SDavid E. O'Brien case SIOCSIFMTU: 482257c5577SDavid E. O'Brien if (ifr->ifr_mtu < ETHERMIN || 483257c5577SDavid E. O'Brien ((sc->sc_flags & NFE_USE_JUMBO) && 484257c5577SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU_JUMBO) || 485257c5577SDavid E. O'Brien (!(sc->sc_flags & NFE_USE_JUMBO) && 486257c5577SDavid E. O'Brien ifr->ifr_mtu > ETHERMTU)) 487257c5577SDavid E. O'Brien error = EINVAL; 488257c5577SDavid E. O'Brien else if (ifp->if_mtu != ifr->ifr_mtu) 489257c5577SDavid E. O'Brien ifp->if_mtu = ifr->ifr_mtu; 490257c5577SDavid E. O'Brien break; 491257c5577SDavid E. O'Brien case SIOCSIFFLAGS: 492257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_UP) { 493257c5577SDavid E. O'Brien /* 494257c5577SDavid E. O'Brien * If only the PROMISC or ALLMULTI flag changes, then 495257c5577SDavid E. O'Brien * don't do a full re-init of the chip, just update 496257c5577SDavid E. O'Brien * the Rx filter. 497257c5577SDavid E. O'Brien */ 498257c5577SDavid E. O'Brien if ((ifp->if_flags & IFF_RUNNING) && 499257c5577SDavid E. O'Brien ((ifp->if_flags ^ sc->sc_if_flags) & 500257c5577SDavid E. O'Brien (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 501257c5577SDavid E. O'Brien nfe_setmulti(sc); 502257c5577SDavid E. O'Brien } else { 503257c5577SDavid E. O'Brien if (!(ifp->if_flags & IFF_RUNNING)) 504257c5577SDavid E. O'Brien nfe_init(ifp); 505257c5577SDavid E. O'Brien } 506257c5577SDavid E. O'Brien } else { 507257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_RUNNING) 508257c5577SDavid E. O'Brien nfe_stop(ifp, 1); 509257c5577SDavid E. O'Brien } 510257c5577SDavid E. O'Brien sc->sc_if_flags = ifp->if_flags; 511257c5577SDavid E. O'Brien break; 512257c5577SDavid E. O'Brien case SIOCADDMULTI: 513257c5577SDavid E. O'Brien case SIOCDELMULTI: 514257c5577SDavid E. O'Brien error = (cmd == SIOCADDMULTI) ? 515257c5577SDavid E. O'Brien ether_addmulti(ifr, &sc->sc_arpcom) : 516257c5577SDavid E. O'Brien ether_delmulti(ifr, &sc->sc_arpcom); 517257c5577SDavid E. O'Brien 518257c5577SDavid E. O'Brien if (error == ENETRESET) { 519257c5577SDavid E. O'Brien if (ifp->if_flags & IFF_RUNNING) 520257c5577SDavid E. O'Brien nfe_setmulti(sc); 521257c5577SDavid E. O'Brien error = 0; 522257c5577SDavid E. O'Brien } 523257c5577SDavid E. O'Brien break; 524257c5577SDavid E. O'Brien case SIOCSIFMEDIA: 525257c5577SDavid E. O'Brien case SIOCGIFMEDIA: 526257c5577SDavid E. O'Brien error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 527257c5577SDavid E. O'Brien break; 528257c5577SDavid E. O'Brien default: 529257c5577SDavid E. O'Brien error = EINVAL; 530257c5577SDavid E. O'Brien } 531257c5577SDavid E. O'Brien 532257c5577SDavid E. O'Brien splx(s); 533257c5577SDavid E. O'Brien 534257c5577SDavid E. O'Brien return error; 535257c5577SDavid E. O'Brien } 536257c5577SDavid E. O'Brien 537257c5577SDavid E. O'Brien void 538257c5577SDavid E. O'Brien nfe_txdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 539257c5577SDavid E. O'Brien { 540257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 541257c5577SDavid E. O'Brien (caddr_t)desc32 - (caddr_t)sc->txq.desc32, 542257c5577SDavid E. O'Brien sizeof (struct nfe_desc32), ops); 543257c5577SDavid E. O'Brien } 544257c5577SDavid E. O'Brien 545257c5577SDavid E. O'Brien void 546257c5577SDavid E. O'Brien nfe_txdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 547257c5577SDavid E. O'Brien { 548257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 549257c5577SDavid E. O'Brien (caddr_t)desc64 - (caddr_t)sc->txq.desc64, 550257c5577SDavid E. O'Brien sizeof (struct nfe_desc64), ops); 551257c5577SDavid E. O'Brien } 552257c5577SDavid E. O'Brien 553257c5577SDavid E. O'Brien void 554257c5577SDavid E. O'Brien nfe_txdesc32_rsync(struct nfe_softc *sc, int start, int end, int ops) 555257c5577SDavid E. O'Brien { 556257c5577SDavid E. O'Brien if (end > start) { 557257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 558257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc32[start] - (caddr_t)sc->txq.desc32, 559257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc32[end] - 560257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc32[start], ops); 561257c5577SDavid E. O'Brien return; 562257c5577SDavid E. O'Brien } 563257c5577SDavid E. O'Brien /* sync from 'start' to end of ring */ 564257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 565257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc32[start] - (caddr_t)sc->txq.desc32, 566257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc32[NFE_TX_RING_COUNT] - 567257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc32[start], ops); 568257c5577SDavid E. O'Brien 569257c5577SDavid E. O'Brien /* sync from start of ring to 'end' */ 570257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 0, 571257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc32[end] - (caddr_t)sc->txq.desc32, ops); 572257c5577SDavid E. O'Brien } 573257c5577SDavid E. O'Brien 574257c5577SDavid E. O'Brien void 575257c5577SDavid E. O'Brien nfe_txdesc64_rsync(struct nfe_softc *sc, int start, int end, int ops) 576257c5577SDavid E. O'Brien { 577257c5577SDavid E. O'Brien if (end > start) { 578257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 579257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc64[start] - (caddr_t)sc->txq.desc64, 580257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc64[end] - 581257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc64[start], ops); 582257c5577SDavid E. O'Brien return; 583257c5577SDavid E. O'Brien } 584257c5577SDavid E. O'Brien /* sync from 'start' to end of ring */ 585257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 586257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc64[start] - (caddr_t)sc->txq.desc64, 587257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc64[NFE_TX_RING_COUNT] - 588257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc64[start], ops); 589257c5577SDavid E. O'Brien 590257c5577SDavid E. O'Brien /* sync from start of ring to 'end' */ 591257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->txq.map, 0, 592257c5577SDavid E. O'Brien (caddr_t)&sc->txq.desc64[end] - (caddr_t)sc->txq.desc64, ops); 593257c5577SDavid E. O'Brien } 594257c5577SDavid E. O'Brien 595257c5577SDavid E. O'Brien void 596257c5577SDavid E. O'Brien nfe_rxdesc32_sync(struct nfe_softc *sc, struct nfe_desc32 *desc32, int ops) 597257c5577SDavid E. O'Brien { 598257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->rxq.map, 599257c5577SDavid E. O'Brien (caddr_t)desc32 - (caddr_t)sc->rxq.desc32, 600257c5577SDavid E. O'Brien sizeof (struct nfe_desc32), ops); 601257c5577SDavid E. O'Brien } 602257c5577SDavid E. O'Brien 603257c5577SDavid E. O'Brien void 604257c5577SDavid E. O'Brien nfe_rxdesc64_sync(struct nfe_softc *sc, struct nfe_desc64 *desc64, int ops) 605257c5577SDavid E. O'Brien { 606257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->rxq.map, 607257c5577SDavid E. O'Brien (caddr_t)desc64 - (caddr_t)sc->rxq.desc64, 608257c5577SDavid E. O'Brien sizeof (struct nfe_desc64), ops); 609257c5577SDavid E. O'Brien } 610257c5577SDavid E. O'Brien 611257c5577SDavid E. O'Brien void 612257c5577SDavid E. O'Brien nfe_rxeof(struct nfe_softc *sc) 613257c5577SDavid E. O'Brien { 614257c5577SDavid E. O'Brien struct ifnet *ifp = &sc->sc_arpcom.ac_if; 615257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 616257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 617257c5577SDavid E. O'Brien struct nfe_rx_data *data; 618257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 619257c5577SDavid E. O'Brien struct mbuf *m, *mnew; 620257c5577SDavid E. O'Brien bus_addr_t physaddr; 621257c5577SDavid E. O'Brien uint16_t flags; 622257c5577SDavid E. O'Brien int error, len; 623257c5577SDavid E. O'Brien 624257c5577SDavid E. O'Brien for (;;) { 625257c5577SDavid E. O'Brien data = &sc->rxq.data[sc->rxq.cur]; 626257c5577SDavid E. O'Brien 627257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 628257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[sc->rxq.cur]; 629257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 630257c5577SDavid E. O'Brien 631257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 632257c5577SDavid E. O'Brien len = letoh16(desc64->length) & 0x3fff; 633257c5577SDavid E. O'Brien } else { 634257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[sc->rxq.cur]; 635257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 636257c5577SDavid E. O'Brien 637257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 638257c5577SDavid E. O'Brien len = letoh16(desc32->length) & 0x3fff; 639257c5577SDavid E. O'Brien } 640257c5577SDavid E. O'Brien 641257c5577SDavid E. O'Brien if (flags & NFE_RX_READY) 642257c5577SDavid E. O'Brien break; 643257c5577SDavid E. O'Brien 644257c5577SDavid E. O'Brien if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 645257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V1)) 646257c5577SDavid E. O'Brien goto skip; 647257c5577SDavid E. O'Brien 648257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 649257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 650257c5577SDavid E. O'Brien len--; /* fix buffer length */ 651257c5577SDavid E. O'Brien } 652257c5577SDavid E. O'Brien } else { 653257c5577SDavid E. O'Brien if (!(flags & NFE_RX_VALID_V2)) 654257c5577SDavid E. O'Brien goto skip; 655257c5577SDavid E. O'Brien 656257c5577SDavid E. O'Brien if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 657257c5577SDavid E. O'Brien flags &= ~NFE_RX_ERROR; 658257c5577SDavid E. O'Brien len--; /* fix buffer length */ 659257c5577SDavid E. O'Brien } 660257c5577SDavid E. O'Brien } 661257c5577SDavid E. O'Brien 662257c5577SDavid E. O'Brien if (flags & NFE_RX_ERROR) { 663257c5577SDavid E. O'Brien ifp->if_ierrors++; 664257c5577SDavid E. O'Brien goto skip; 665257c5577SDavid E. O'Brien } 666257c5577SDavid E. O'Brien 667257c5577SDavid E. O'Brien /* 668257c5577SDavid E. O'Brien * Try to allocate a new mbuf for this ring element and load 669257c5577SDavid E. O'Brien * it before processing the current mbuf. If the ring element 670257c5577SDavid E. O'Brien * cannot be loaded, drop the received packet and reuse the 671257c5577SDavid E. O'Brien * old mbuf. In the unlikely case that the old mbuf can't be 672257c5577SDavid E. O'Brien * reloaded either, explicitly panic. 673257c5577SDavid E. O'Brien */ 674257c5577SDavid E. O'Brien MGETHDR(mnew, M_DONTWAIT, MT_DATA); 675257c5577SDavid E. O'Brien if (mnew == NULL) { 676257c5577SDavid E. O'Brien ifp->if_ierrors++; 677257c5577SDavid E. O'Brien goto skip; 678257c5577SDavid E. O'Brien } 679257c5577SDavid E. O'Brien 680257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_USE_JUMBO) { 681257c5577SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 682257c5577SDavid E. O'Brien m_freem(mnew); 683257c5577SDavid E. O'Brien ifp->if_ierrors++; 684257c5577SDavid E. O'Brien goto skip; 685257c5577SDavid E. O'Brien } 686257c5577SDavid E. O'Brien MEXTADD(mnew, jbuf->buf, NFE_JBYTES, 0, nfe_jfree, sc); 687257c5577SDavid E. O'Brien 688257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, sc->rxq.jmap, 689257c5577SDavid E. O'Brien mtod(data->m, caddr_t) - sc->rxq.jpool, NFE_JBYTES, 690257c5577SDavid E. O'Brien BUS_DMASYNC_POSTREAD); 691257c5577SDavid E. O'Brien 692257c5577SDavid E. O'Brien physaddr = jbuf->physaddr; 693257c5577SDavid E. O'Brien } else { 694257c5577SDavid E. O'Brien MCLGET(mnew, M_DONTWAIT); 695257c5577SDavid E. O'Brien if (!(mnew->m_flags & M_EXT)) { 696257c5577SDavid E. O'Brien m_freem(mnew); 697257c5577SDavid E. O'Brien ifp->if_ierrors++; 698257c5577SDavid E. O'Brien goto skip; 699257c5577SDavid E. O'Brien } 700257c5577SDavid E. O'Brien 701257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, data->map, 0, 702257c5577SDavid E. O'Brien data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); 703257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, data->map); 704257c5577SDavid E. O'Brien 705257c5577SDavid E. O'Brien error = bus_dmamap_load(sc->sc_dmat, data->map, 706257c5577SDavid E. O'Brien mtod(mnew, void *), MCLBYTES, NULL, 707257c5577SDavid E. O'Brien BUS_DMA_READ | BUS_DMA_NOWAIT); 708257c5577SDavid E. O'Brien if (error != 0) { 709257c5577SDavid E. O'Brien m_freem(mnew); 710257c5577SDavid E. O'Brien 711257c5577SDavid E. O'Brien /* try to reload the old mbuf */ 712257c5577SDavid E. O'Brien error = bus_dmamap_load(sc->sc_dmat, data->map, 713257c5577SDavid E. O'Brien mtod(data->m, void *), MCLBYTES, NULL, 714257c5577SDavid E. O'Brien BUS_DMA_READ | BUS_DMA_NOWAIT); 715257c5577SDavid E. O'Brien if (error != 0) { 716257c5577SDavid E. O'Brien /* very unlikely that it will fail.. */ 717257c5577SDavid E. O'Brien panic("%s: could not load old rx mbuf", 718257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 719257c5577SDavid E. O'Brien } 720257c5577SDavid E. O'Brien ifp->if_ierrors++; 721257c5577SDavid E. O'Brien goto skip; 722257c5577SDavid E. O'Brien } 723257c5577SDavid E. O'Brien physaddr = data->map->dm_segs[0].ds_addr; 724257c5577SDavid E. O'Brien } 725257c5577SDavid E. O'Brien 726257c5577SDavid E. O'Brien /* 727257c5577SDavid E. O'Brien * New mbuf successfully loaded, update Rx ring and continue 728257c5577SDavid E. O'Brien * processing. 729257c5577SDavid E. O'Brien */ 730257c5577SDavid E. O'Brien m = data->m; 731257c5577SDavid E. O'Brien data->m = mnew; 732257c5577SDavid E. O'Brien 733257c5577SDavid E. O'Brien /* finalize mbuf */ 734257c5577SDavid E. O'Brien m->m_pkthdr.len = m->m_len = len; 735257c5577SDavid E. O'Brien m->m_pkthdr.rcvif = ifp; 736257c5577SDavid E. O'Brien 737257c5577SDavid E. O'Brien #ifdef notyet 738257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_HW_CSUM) { 739257c5577SDavid E. O'Brien if (flags & NFE_RX_IP_CSUMOK) 740257c5577SDavid E. O'Brien m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 741257c5577SDavid E. O'Brien if (flags & NFE_RX_UDP_CSUMOK) 742257c5577SDavid E. O'Brien m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK; 743257c5577SDavid E. O'Brien if (flags & NFE_RX_TCP_CSUMOK) 744257c5577SDavid E. O'Brien m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK; 745257c5577SDavid E. O'Brien } 746257c5577SDavid E. O'Brien #elif defined(NFE_CSUM) 747257c5577SDavid E. O'Brien if ((sc->sc_flags & NFE_HW_CSUM) && (flags & NFE_RX_CSUMOK)) 748257c5577SDavid E. O'Brien m->m_pkthdr.csum_flags = M_IPV4_CSUM_IN_OK; 749257c5577SDavid E. O'Brien #endif 750257c5577SDavid E. O'Brien 751257c5577SDavid E. O'Brien #if NBPFILTER > 0 752257c5577SDavid E. O'Brien if (ifp->if_bpf) 753257c5577SDavid E. O'Brien bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); 754257c5577SDavid E. O'Brien #endif 755257c5577SDavid E. O'Brien ifp->if_ipackets++; 756257c5577SDavid E. O'Brien ether_input_mbuf(ifp, m); 757257c5577SDavid E. O'Brien 758257c5577SDavid E. O'Brien /* update mapping address in h/w descriptor */ 759257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 760257c5577SDavid E. O'Brien #if defined(__LP64__) 761257c5577SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 762257c5577SDavid E. O'Brien #endif 763257c5577SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 764257c5577SDavid E. O'Brien } else { 765257c5577SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 766257c5577SDavid E. O'Brien } 767257c5577SDavid E. O'Brien 768257c5577SDavid E. O'Brien skip: if (sc->sc_flags & NFE_40BIT_ADDR) { 769257c5577SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 770257c5577SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 771257c5577SDavid E. O'Brien 772257c5577SDavid E. O'Brien nfe_rxdesc64_sync(sc, desc64, BUS_DMASYNC_PREWRITE); 773257c5577SDavid E. O'Brien } else { 774257c5577SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 775257c5577SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 776257c5577SDavid E. O'Brien 777257c5577SDavid E. O'Brien nfe_rxdesc32_sync(sc, desc32, BUS_DMASYNC_PREWRITE); 778257c5577SDavid E. O'Brien } 779257c5577SDavid E. O'Brien 780257c5577SDavid E. O'Brien sc->rxq.cur = (sc->rxq.cur + 1) % NFE_RX_RING_COUNT; 781257c5577SDavid E. O'Brien } 782257c5577SDavid E. O'Brien } 783257c5577SDavid E. O'Brien 784257c5577SDavid E. O'Brien void 785257c5577SDavid E. O'Brien nfe_txeof(struct nfe_softc *sc) 786257c5577SDavid E. O'Brien { 787257c5577SDavid E. O'Brien struct ifnet *ifp = &sc->sc_arpcom.ac_if; 788257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 789257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 790257c5577SDavid E. O'Brien struct nfe_tx_data *data = NULL; 791257c5577SDavid E. O'Brien uint16_t flags; 792257c5577SDavid E. O'Brien 793257c5577SDavid E. O'Brien while (sc->txq.next != sc->txq.cur) { 794257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 795257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.next]; 796257c5577SDavid E. O'Brien nfe_txdesc64_sync(sc, desc64, BUS_DMASYNC_POSTREAD); 797257c5577SDavid E. O'Brien 798257c5577SDavid E. O'Brien flags = letoh16(desc64->flags); 799257c5577SDavid E. O'Brien } else { 800257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.next]; 801257c5577SDavid E. O'Brien nfe_txdesc32_sync(sc, desc32, BUS_DMASYNC_POSTREAD); 802257c5577SDavid E. O'Brien 803257c5577SDavid E. O'Brien flags = letoh16(desc32->flags); 804257c5577SDavid E. O'Brien } 805257c5577SDavid E. O'Brien 806257c5577SDavid E. O'Brien if (flags & NFE_TX_VALID) 807257c5577SDavid E. O'Brien break; 808257c5577SDavid E. O'Brien 809257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.next]; 810257c5577SDavid E. O'Brien 811257c5577SDavid E. O'Brien if ((sc->sc_flags & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 812257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 813257c5577SDavid E. O'Brien goto skip; 814257c5577SDavid E. O'Brien 815257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V1) != 0) { 816257c5577SDavid E. O'Brien printf("%s: tx v1 error 0x%04b\n", 817257c5577SDavid E. O'Brien sc->sc_dev.dv_xname, flags, NFE_V1_TXERR); 818257c5577SDavid E. O'Brien ifp->if_oerrors++; 819257c5577SDavid E. O'Brien } else 820257c5577SDavid E. O'Brien ifp->if_opackets++; 821257c5577SDavid E. O'Brien } else { 822257c5577SDavid E. O'Brien if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 823257c5577SDavid E. O'Brien goto skip; 824257c5577SDavid E. O'Brien 825257c5577SDavid E. O'Brien if ((flags & NFE_TX_ERROR_V2) != 0) { 826257c5577SDavid E. O'Brien printf("%s: tx v2 error 0x%04b\n", 827257c5577SDavid E. O'Brien sc->sc_dev.dv_xname, flags, NFE_V2_TXERR); 828257c5577SDavid E. O'Brien ifp->if_oerrors++; 829257c5577SDavid E. O'Brien } else 830257c5577SDavid E. O'Brien ifp->if_opackets++; 831257c5577SDavid E. O'Brien } 832257c5577SDavid E. O'Brien 833257c5577SDavid E. O'Brien if (data->m == NULL) { /* should not get there */ 834257c5577SDavid E. O'Brien printf("%s: last fragment bit w/o associated mbuf!\n", 835257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 836257c5577SDavid E. O'Brien goto skip; 837257c5577SDavid E. O'Brien } 838257c5577SDavid E. O'Brien 839257c5577SDavid E. O'Brien /* last fragment of the mbuf chain transmitted */ 840257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, data->active, 0, 841257c5577SDavid E. O'Brien data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE); 842257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, data->active); 843257c5577SDavid E. O'Brien m_freem(data->m); 844257c5577SDavid E. O'Brien data->m = NULL; 845257c5577SDavid E. O'Brien 846257c5577SDavid E. O'Brien ifp->if_timer = 0; 847257c5577SDavid E. O'Brien 848257c5577SDavid E. O'Brien skip: sc->txq.queued--; 849257c5577SDavid E. O'Brien sc->txq.next = (sc->txq.next + 1) % NFE_TX_RING_COUNT; 850257c5577SDavid E. O'Brien } 851257c5577SDavid E. O'Brien 852257c5577SDavid E. O'Brien if (data != NULL) { /* at least one slot freed */ 853257c5577SDavid E. O'Brien ifp->if_flags &= ~IFF_OACTIVE; 854257c5577SDavid E. O'Brien nfe_start(ifp); 855257c5577SDavid E. O'Brien } 856257c5577SDavid E. O'Brien } 857257c5577SDavid E. O'Brien 858257c5577SDavid E. O'Brien int 859257c5577SDavid E. O'Brien nfe_encap(struct nfe_softc *sc, struct mbuf *m0) 860257c5577SDavid E. O'Brien { 861257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 862257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 863257c5577SDavid E. O'Brien struct nfe_tx_data *data; 864257c5577SDavid E. O'Brien bus_dmamap_t map; 865257c5577SDavid E. O'Brien uint16_t flags = NFE_TX_VALID; 866257c5577SDavid E. O'Brien #if NVLAN > 0 867257c5577SDavid E. O'Brien uint32_t vtag = 0; 868257c5577SDavid E. O'Brien #endif 869257c5577SDavid E. O'Brien int error, i; 870257c5577SDavid E. O'Brien 871257c5577SDavid E. O'Brien map = sc->txq.data[sc->txq.cur].map; 872257c5577SDavid E. O'Brien 873257c5577SDavid E. O'Brien error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, BUS_DMA_NOWAIT); 874257c5577SDavid E. O'Brien if (error != 0) { 875257c5577SDavid E. O'Brien printf("%s: could not map mbuf (error %d)\n", 876257c5577SDavid E. O'Brien sc->sc_dev.dv_xname, error); 877257c5577SDavid E. O'Brien return error; 878257c5577SDavid E. O'Brien } 879257c5577SDavid E. O'Brien 880257c5577SDavid E. O'Brien if (sc->txq.queued + map->dm_nsegs >= NFE_TX_RING_COUNT - 1) { 881257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, map); 882257c5577SDavid E. O'Brien return ENOBUFS; 883257c5577SDavid E. O'Brien } 884257c5577SDavid E. O'Brien 885257c5577SDavid E. O'Brien #if NVLAN > 0 886257c5577SDavid E. O'Brien /* setup h/w VLAN tagging */ 887257c5577SDavid E. O'Brien if ((m0->m_flags & (M_PROTO1 | M_PKTHDR)) == (M_PROTO1 | M_PKTHDR) && 888257c5577SDavid E. O'Brien m0->m_pkthdr.rcvif != NULL) { 889257c5577SDavid E. O'Brien struct ifvlan *ifv = m0->m_pkthdr.rcvif->if_softc; 890257c5577SDavid E. O'Brien vtag = NFE_TX_VTAG | htons(ifv->ifv_tag); 891257c5577SDavid E. O'Brien } 892257c5577SDavid E. O'Brien #endif 893257c5577SDavid E. O'Brien #ifdef NFE_CSUM 894257c5577SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) 895257c5577SDavid E. O'Brien flags |= NFE_TX_IP_CSUM; 896257c5577SDavid E. O'Brien if (m0->m_pkthdr.csum_flags & (M_TCPV4_CSUM_OUT | M_UDPV4_CSUM_OUT)) 897257c5577SDavid E. O'Brien flags |= NFE_TX_TCP_CSUM; 898257c5577SDavid E. O'Brien #endif 899257c5577SDavid E. O'Brien 900257c5577SDavid E. O'Brien for (i = 0; i < map->dm_nsegs; i++) { 901257c5577SDavid E. O'Brien data = &sc->txq.data[sc->txq.cur]; 902257c5577SDavid E. O'Brien 903257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 904257c5577SDavid E. O'Brien desc64 = &sc->txq.desc64[sc->txq.cur]; 905257c5577SDavid E. O'Brien #if defined(__LP64__) 906257c5577SDavid E. O'Brien desc64->physaddr[0] = 907257c5577SDavid E. O'Brien htole32(map->dm_segs[i].ds_addr >> 32); 908257c5577SDavid E. O'Brien #endif 909257c5577SDavid E. O'Brien desc64->physaddr[1] = 910257c5577SDavid E. O'Brien htole32(map->dm_segs[i].ds_addr & 0xffffffff); 911257c5577SDavid E. O'Brien desc64->length = htole16(map->dm_segs[i].ds_len - 1); 912257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 913257c5577SDavid E. O'Brien #if NVLAN > 0 914257c5577SDavid E. O'Brien desc64->vtag = htole32(vtag); 915257c5577SDavid E. O'Brien #endif 916257c5577SDavid E. O'Brien } else { 917257c5577SDavid E. O'Brien desc32 = &sc->txq.desc32[sc->txq.cur]; 918257c5577SDavid E. O'Brien 919257c5577SDavid E. O'Brien desc32->physaddr = htole32(map->dm_segs[i].ds_addr); 920257c5577SDavid E. O'Brien desc32->length = htole16(map->dm_segs[i].ds_len - 1); 921257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 922257c5577SDavid E. O'Brien } 923257c5577SDavid E. O'Brien 924257c5577SDavid E. O'Brien /* csum flags and vtag belong to the first fragment only */ 925257c5577SDavid E. O'Brien if (map->dm_nsegs > 1) { 926257c5577SDavid E. O'Brien flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 927257c5577SDavid E. O'Brien #if NVLAN > 0 928257c5577SDavid E. O'Brien vtag = 0; 929257c5577SDavid E. O'Brien #endif 930257c5577SDavid E. O'Brien } 931257c5577SDavid E. O'Brien 932257c5577SDavid E. O'Brien sc->txq.queued++; 933257c5577SDavid E. O'Brien sc->txq.cur = (sc->txq.cur + 1) % NFE_TX_RING_COUNT; 934257c5577SDavid E. O'Brien } 935257c5577SDavid E. O'Brien 936257c5577SDavid E. O'Brien /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 937257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 938257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 939257c5577SDavid E. O'Brien desc64->flags = htole16(flags); 940257c5577SDavid E. O'Brien } else { 941257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_JUMBO_SUP) 942257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V2; 943257c5577SDavid E. O'Brien else 944257c5577SDavid E. O'Brien flags |= NFE_TX_LASTFRAG_V1; 945257c5577SDavid E. O'Brien desc32->flags = htole16(flags); 946257c5577SDavid E. O'Brien } 947257c5577SDavid E. O'Brien 948257c5577SDavid E. O'Brien data->m = m0; 949257c5577SDavid E. O'Brien data->active = map; 950257c5577SDavid E. O'Brien 951257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 952257c5577SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 953257c5577SDavid E. O'Brien 954257c5577SDavid E. O'Brien return 0; 955257c5577SDavid E. O'Brien } 956257c5577SDavid E. O'Brien 957257c5577SDavid E. O'Brien void 958257c5577SDavid E. O'Brien nfe_start(struct ifnet *ifp) 959257c5577SDavid E. O'Brien { 960257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 961257c5577SDavid E. O'Brien int old = sc->txq.cur; 962257c5577SDavid E. O'Brien struct mbuf *m0; 963257c5577SDavid E. O'Brien 964257c5577SDavid E. O'Brien for (;;) { 965257c5577SDavid E. O'Brien IFQ_POLL(&ifp->if_snd, m0); 966257c5577SDavid E. O'Brien if (m0 == NULL) 967257c5577SDavid E. O'Brien break; 968257c5577SDavid E. O'Brien 969257c5577SDavid E. O'Brien if (nfe_encap(sc, m0) != 0) { 970257c5577SDavid E. O'Brien ifp->if_flags |= IFF_OACTIVE; 971257c5577SDavid E. O'Brien break; 972257c5577SDavid E. O'Brien } 973257c5577SDavid E. O'Brien 974257c5577SDavid E. O'Brien /* packet put in h/w queue, remove from s/w queue */ 975257c5577SDavid E. O'Brien IFQ_DEQUEUE(&ifp->if_snd, m0); 976257c5577SDavid E. O'Brien 977257c5577SDavid E. O'Brien #if NBPFILTER > 0 978257c5577SDavid E. O'Brien if (ifp->if_bpf != NULL) 979257c5577SDavid E. O'Brien bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT); 980257c5577SDavid E. O'Brien #endif 981257c5577SDavid E. O'Brien } 982257c5577SDavid E. O'Brien if (sc->txq.cur == old) /* nothing sent */ 983257c5577SDavid E. O'Brien return; 984257c5577SDavid E. O'Brien 985257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) 986257c5577SDavid E. O'Brien nfe_txdesc64_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 987257c5577SDavid E. O'Brien else 988257c5577SDavid E. O'Brien nfe_txdesc32_rsync(sc, old, sc->txq.cur, BUS_DMASYNC_PREWRITE); 989257c5577SDavid E. O'Brien 990257c5577SDavid E. O'Brien /* kick Tx */ 991257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 992257c5577SDavid E. O'Brien 993257c5577SDavid E. O'Brien /* 994257c5577SDavid E. O'Brien * Set a timeout in case the chip goes out to lunch. 995257c5577SDavid E. O'Brien */ 996257c5577SDavid E. O'Brien ifp->if_timer = 5; 997257c5577SDavid E. O'Brien } 998257c5577SDavid E. O'Brien 999257c5577SDavid E. O'Brien void 1000257c5577SDavid E. O'Brien nfe_watchdog(struct ifnet *ifp) 1001257c5577SDavid E. O'Brien { 1002257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1003257c5577SDavid E. O'Brien 1004257c5577SDavid E. O'Brien printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname); 1005257c5577SDavid E. O'Brien 1006257c5577SDavid E. O'Brien nfe_init(ifp); 1007257c5577SDavid E. O'Brien 1008257c5577SDavid E. O'Brien ifp->if_oerrors++; 1009257c5577SDavid E. O'Brien } 1010257c5577SDavid E. O'Brien 1011257c5577SDavid E. O'Brien int 1012257c5577SDavid E. O'Brien nfe_init(struct ifnet *ifp) 1013257c5577SDavid E. O'Brien { 1014257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1015257c5577SDavid E. O'Brien uint32_t tmp; 1016257c5577SDavid E. O'Brien 1017257c5577SDavid E. O'Brien nfe_stop(ifp, 0); 1018257c5577SDavid E. O'Brien 1019257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_UNK, 0); 1020257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, 0); 1021257c5577SDavid E. O'Brien 1022257c5577SDavid E. O'Brien sc->rxtxctl = NFE_RXTX_BIT2; 1023257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) 1024257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V3MAGIC; 1025257c5577SDavid E. O'Brien else if (sc->sc_flags & NFE_JUMBO_SUP) 1026257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_V2MAGIC; 1027257c5577SDavid E. O'Brien #ifdef NFE_CSUM 1028257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_HW_CSUM) 1029257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_RXCSUM; 1030257c5577SDavid E. O'Brien #endif 1031257c5577SDavid E. O'Brien #if NVLAN > 0 1032257c5577SDavid E. O'Brien /* 1033257c5577SDavid E. O'Brien * Although the adapter is capable of stripping VLAN tags from received 1034257c5577SDavid E. O'Brien * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1035257c5577SDavid E. O'Brien * purpose. This will be done in software by our network stack. 1036257c5577SDavid E. O'Brien */ 1037257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_HW_VLAN) 1038257c5577SDavid E. O'Brien sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1039257c5577SDavid E. O'Brien #endif 1040257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1041257c5577SDavid E. O'Brien DELAY(10); 1042257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1043257c5577SDavid E. O'Brien 1044257c5577SDavid E. O'Brien #if NVLAN 1045257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_HW_VLAN) 1046257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1047257c5577SDavid E. O'Brien #endif 1048257c5577SDavid E. O'Brien 1049257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, 0); 1050257c5577SDavid E. O'Brien 1051257c5577SDavid E. O'Brien /* set MAC address */ 1052257c5577SDavid E. O'Brien nfe_set_macaddr(sc, sc->sc_arpcom.ac_enaddr); 1053257c5577SDavid E. O'Brien 1054257c5577SDavid E. O'Brien /* tell MAC where rings are in memory */ 1055257c5577SDavid E. O'Brien #ifdef __LP64__ 1056257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, sc->rxq.physaddr >> 32); 1057257c5577SDavid E. O'Brien #endif 1058257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, sc->rxq.physaddr & 0xffffffff); 1059257c5577SDavid E. O'Brien #ifdef __LP64__ 1060257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, sc->txq.physaddr >> 32); 1061257c5577SDavid E. O'Brien #endif 1062257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, sc->txq.physaddr & 0xffffffff); 1063257c5577SDavid E. O'Brien 1064257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RING_SIZE, 1065257c5577SDavid E. O'Brien (NFE_RX_RING_COUNT - 1) << 16 | 1066257c5577SDavid E. O'Brien (NFE_TX_RING_COUNT - 1)); 1067257c5577SDavid E. O'Brien 1068257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1069257c5577SDavid E. O'Brien 1070257c5577SDavid E. O'Brien /* force MAC to wakeup */ 1071257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1072257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1073257c5577SDavid E. O'Brien DELAY(10); 1074257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_PWR_STATE); 1075257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1076257c5577SDavid E. O'Brien 1077257c5577SDavid E. O'Brien #if 1 1078257c5577SDavid E. O'Brien /* configure interrupts coalescing/mitigation */ 1079257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, NFE_IM_DEFAULT); 1080257c5577SDavid E. O'Brien #else 1081257c5577SDavid E. O'Brien /* no interrupt mitigation: one interrupt per packet */ 1082257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IMTIMER, 970); 1083257c5577SDavid E. O'Brien #endif 1084257c5577SDavid E. O'Brien 1085257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1086257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1087257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1088257c5577SDavid E. O'Brien 1089257c5577SDavid E. O'Brien /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1090257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1091257c5577SDavid E. O'Brien 1092257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1093257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_WOL_CTL, NFE_WOL_MAGIC); 1094257c5577SDavid E. O'Brien 1095257c5577SDavid E. O'Brien sc->rxtxctl &= ~NFE_RXTX_BIT2; 1096257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1097257c5577SDavid E. O'Brien DELAY(10); 1098257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1099257c5577SDavid E. O'Brien 1100257c5577SDavid E. O'Brien /* set Rx filter */ 1101257c5577SDavid E. O'Brien nfe_setmulti(sc); 1102257c5577SDavid E. O'Brien 1103257c5577SDavid E. O'Brien nfe_ifmedia_upd(ifp); 1104257c5577SDavid E. O'Brien 1105257c5577SDavid E. O'Brien /* enable Rx */ 1106257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1107257c5577SDavid E. O'Brien 1108257c5577SDavid E. O'Brien /* enable Tx */ 1109257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1110257c5577SDavid E. O'Brien 1111257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1112257c5577SDavid E. O'Brien 1113257c5577SDavid E. O'Brien /* enable interrupts */ 1114257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_WANTED); 1115257c5577SDavid E. O'Brien 1116257c5577SDavid E. O'Brien timeout_add(&sc->sc_tick_ch, hz); 1117257c5577SDavid E. O'Brien 1118257c5577SDavid E. O'Brien ifp->if_flags |= IFF_RUNNING; 1119257c5577SDavid E. O'Brien ifp->if_flags &= ~IFF_OACTIVE; 1120257c5577SDavid E. O'Brien 1121257c5577SDavid E. O'Brien return 0; 1122257c5577SDavid E. O'Brien } 1123257c5577SDavid E. O'Brien 1124257c5577SDavid E. O'Brien void 1125257c5577SDavid E. O'Brien nfe_stop(struct ifnet *ifp, int disable) 1126257c5577SDavid E. O'Brien { 1127257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1128257c5577SDavid E. O'Brien 1129257c5577SDavid E. O'Brien timeout_del(&sc->sc_tick_ch); 1130257c5577SDavid E. O'Brien 1131257c5577SDavid E. O'Brien ifp->if_timer = 0; 1132257c5577SDavid E. O'Brien ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1133257c5577SDavid E. O'Brien 1134257c5577SDavid E. O'Brien mii_down(&sc->sc_mii); 1135257c5577SDavid E. O'Brien 1136257c5577SDavid E. O'Brien /* abort Tx */ 1137257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_TX_CTL, 0); 1138257c5577SDavid E. O'Brien 1139257c5577SDavid E. O'Brien /* disable Rx */ 1140257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RX_CTL, 0); 1141257c5577SDavid E. O'Brien 1142257c5577SDavid E. O'Brien /* disable interrupts */ 1143257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1144257c5577SDavid E. O'Brien 1145257c5577SDavid E. O'Brien /* reset Tx and Rx rings */ 1146257c5577SDavid E. O'Brien nfe_reset_tx_ring(sc, &sc->txq); 1147257c5577SDavid E. O'Brien nfe_reset_rx_ring(sc, &sc->rxq); 1148257c5577SDavid E. O'Brien } 1149257c5577SDavid E. O'Brien 1150257c5577SDavid E. O'Brien int 1151257c5577SDavid E. O'Brien nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1152257c5577SDavid E. O'Brien { 1153257c5577SDavid E. O'Brien struct nfe_desc32 *desc32; 1154257c5577SDavid E. O'Brien struct nfe_desc64 *desc64; 1155257c5577SDavid E. O'Brien struct nfe_rx_data *data; 1156257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 1157257c5577SDavid E. O'Brien void **desc; 1158257c5577SDavid E. O'Brien bus_addr_t physaddr; 1159257c5577SDavid E. O'Brien int i, nsegs, error, descsize; 1160257c5577SDavid E. O'Brien 1161257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 1162257c5577SDavid E. O'Brien desc = (void **)&ring->desc64; 1163257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1164257c5577SDavid E. O'Brien } else { 1165257c5577SDavid E. O'Brien desc = (void **)&ring->desc32; 1166257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1167257c5577SDavid E. O'Brien } 1168257c5577SDavid E. O'Brien 1169257c5577SDavid E. O'Brien ring->cur = ring->next = 0; 1170257c5577SDavid E. O'Brien ring->bufsz = MCLBYTES; 1171257c5577SDavid E. O'Brien 1172257c5577SDavid E. O'Brien error = bus_dmamap_create(sc->sc_dmat, NFE_RX_RING_COUNT * descsize, 1, 1173257c5577SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, 0, BUS_DMA_NOWAIT, &ring->map); 1174257c5577SDavid E. O'Brien if (error != 0) { 1175257c5577SDavid E. O'Brien printf("%s: could not create desc DMA map\n", 1176257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1177257c5577SDavid E. O'Brien goto fail; 1178257c5577SDavid E. O'Brien } 1179257c5577SDavid E. O'Brien 1180257c5577SDavid E. O'Brien error = bus_dmamem_alloc(sc->sc_dmat, NFE_RX_RING_COUNT * descsize, 1181257c5577SDavid E. O'Brien PAGE_SIZE, 0, &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); 1182257c5577SDavid E. O'Brien if (error != 0) { 1183257c5577SDavid E. O'Brien printf("%s: could not allocate DMA memory\n", 1184257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1185257c5577SDavid E. O'Brien goto fail; 1186257c5577SDavid E. O'Brien } 1187257c5577SDavid E. O'Brien 1188257c5577SDavid E. O'Brien error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, 1189257c5577SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, (caddr_t *)desc, BUS_DMA_NOWAIT); 1190257c5577SDavid E. O'Brien if (error != 0) { 1191257c5577SDavid E. O'Brien printf("%s: could not map desc DMA memory\n", 1192257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1193257c5577SDavid E. O'Brien goto fail; 1194257c5577SDavid E. O'Brien } 1195257c5577SDavid E. O'Brien 1196257c5577SDavid E. O'Brien error = bus_dmamap_load(sc->sc_dmat, ring->map, *desc, 1197257c5577SDavid E. O'Brien NFE_RX_RING_COUNT * descsize, NULL, BUS_DMA_NOWAIT); 1198257c5577SDavid E. O'Brien if (error != 0) { 1199257c5577SDavid E. O'Brien printf("%s: could not load desc DMA map\n", 1200257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1201257c5577SDavid E. O'Brien goto fail; 1202257c5577SDavid E. O'Brien } 1203257c5577SDavid E. O'Brien 1204257c5577SDavid E. O'Brien bzero(*desc, NFE_RX_RING_COUNT * descsize); 1205257c5577SDavid E. O'Brien ring->physaddr = ring->map->dm_segs[0].ds_addr; 1206257c5577SDavid E. O'Brien 1207257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_USE_JUMBO) { 1208257c5577SDavid E. O'Brien ring->bufsz = NFE_JBYTES; 1209257c5577SDavid E. O'Brien if ((error = nfe_jpool_alloc(sc)) != 0) { 1210257c5577SDavid E. O'Brien printf("%s: could not allocate jumbo frames\n", 1211257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1212257c5577SDavid E. O'Brien goto fail; 1213257c5577SDavid E. O'Brien } 1214257c5577SDavid E. O'Brien } 1215257c5577SDavid E. O'Brien 1216257c5577SDavid E. O'Brien /* 1217257c5577SDavid E. O'Brien * Pre-allocate Rx buffers and populate Rx ring. 1218257c5577SDavid E. O'Brien */ 1219257c5577SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1220257c5577SDavid E. O'Brien data = &sc->rxq.data[i]; 1221257c5577SDavid E. O'Brien 1222257c5577SDavid E. O'Brien MGETHDR(data->m, M_DONTWAIT, MT_DATA); 1223257c5577SDavid E. O'Brien if (data->m == NULL) { 1224257c5577SDavid E. O'Brien printf("%s: could not allocate rx mbuf\n", 1225257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1226257c5577SDavid E. O'Brien error = ENOMEM; 1227257c5577SDavid E. O'Brien goto fail; 1228257c5577SDavid E. O'Brien } 1229257c5577SDavid E. O'Brien 1230257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_USE_JUMBO) { 1231257c5577SDavid E. O'Brien if ((jbuf = nfe_jalloc(sc)) == NULL) { 1232257c5577SDavid E. O'Brien printf("%s: could not allocate jumbo buffer\n", 1233257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1234257c5577SDavid E. O'Brien goto fail; 1235257c5577SDavid E. O'Brien } 1236257c5577SDavid E. O'Brien MEXTADD(data->m, jbuf->buf, NFE_JBYTES, 0, nfe_jfree, 1237257c5577SDavid E. O'Brien sc); 1238257c5577SDavid E. O'Brien 1239257c5577SDavid E. O'Brien physaddr = jbuf->physaddr; 1240257c5577SDavid E. O'Brien } else { 1241257c5577SDavid E. O'Brien error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 1242257c5577SDavid E. O'Brien MCLBYTES, 0, BUS_DMA_NOWAIT, &data->map); 1243257c5577SDavid E. O'Brien if (error != 0) { 1244257c5577SDavid E. O'Brien printf("%s: could not create DMA map\n", 1245257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1246257c5577SDavid E. O'Brien goto fail; 1247257c5577SDavid E. O'Brien } 1248257c5577SDavid E. O'Brien MCLGET(data->m, M_DONTWAIT); 1249257c5577SDavid E. O'Brien if (!(data->m->m_flags & M_EXT)) { 1250257c5577SDavid E. O'Brien printf("%s: could not allocate mbuf cluster\n", 1251257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1252257c5577SDavid E. O'Brien error = ENOMEM; 1253257c5577SDavid E. O'Brien goto fail; 1254257c5577SDavid E. O'Brien } 1255257c5577SDavid E. O'Brien 1256257c5577SDavid E. O'Brien error = bus_dmamap_load(sc->sc_dmat, data->map, 1257257c5577SDavid E. O'Brien mtod(data->m, void *), MCLBYTES, NULL, 1258257c5577SDavid E. O'Brien BUS_DMA_READ | BUS_DMA_NOWAIT); 1259257c5577SDavid E. O'Brien if (error != 0) { 1260257c5577SDavid E. O'Brien printf("%s: could not load rx buf DMA map", 1261257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1262257c5577SDavid E. O'Brien goto fail; 1263257c5577SDavid E. O'Brien } 1264257c5577SDavid E. O'Brien physaddr = data->map->dm_segs[0].ds_addr; 1265257c5577SDavid E. O'Brien } 1266257c5577SDavid E. O'Brien 1267257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 1268257c5577SDavid E. O'Brien desc64 = &sc->rxq.desc64[i]; 1269257c5577SDavid E. O'Brien #if defined(__LP64__) 1270257c5577SDavid E. O'Brien desc64->physaddr[0] = htole32(physaddr >> 32); 1271257c5577SDavid E. O'Brien #endif 1272257c5577SDavid E. O'Brien desc64->physaddr[1] = htole32(physaddr & 0xffffffff); 1273257c5577SDavid E. O'Brien desc64->length = htole16(sc->rxq.bufsz); 1274257c5577SDavid E. O'Brien desc64->flags = htole16(NFE_RX_READY); 1275257c5577SDavid E. O'Brien } else { 1276257c5577SDavid E. O'Brien desc32 = &sc->rxq.desc32[i]; 1277257c5577SDavid E. O'Brien desc32->physaddr = htole32(physaddr); 1278257c5577SDavid E. O'Brien desc32->length = htole16(sc->rxq.bufsz); 1279257c5577SDavid E. O'Brien desc32->flags = htole16(NFE_RX_READY); 1280257c5577SDavid E. O'Brien } 1281257c5577SDavid E. O'Brien } 1282257c5577SDavid E. O'Brien 1283257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, 1284257c5577SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 1285257c5577SDavid E. O'Brien 1286257c5577SDavid E. O'Brien return 0; 1287257c5577SDavid E. O'Brien 1288257c5577SDavid E. O'Brien fail: nfe_free_rx_ring(sc, ring); 1289257c5577SDavid E. O'Brien return error; 1290257c5577SDavid E. O'Brien } 1291257c5577SDavid E. O'Brien 1292257c5577SDavid E. O'Brien void 1293257c5577SDavid E. O'Brien nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1294257c5577SDavid E. O'Brien { 1295257c5577SDavid E. O'Brien int i; 1296257c5577SDavid E. O'Brien 1297257c5577SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1298257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 1299257c5577SDavid E. O'Brien ring->desc64[i].length = htole16(ring->bufsz); 1300257c5577SDavid E. O'Brien ring->desc64[i].flags = htole16(NFE_RX_READY); 1301257c5577SDavid E. O'Brien } else { 1302257c5577SDavid E. O'Brien ring->desc32[i].length = htole16(ring->bufsz); 1303257c5577SDavid E. O'Brien ring->desc32[i].flags = htole16(NFE_RX_READY); 1304257c5577SDavid E. O'Brien } 1305257c5577SDavid E. O'Brien } 1306257c5577SDavid E. O'Brien 1307257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, 1308257c5577SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 1309257c5577SDavid E. O'Brien 1310257c5577SDavid E. O'Brien ring->cur = ring->next = 0; 1311257c5577SDavid E. O'Brien } 1312257c5577SDavid E. O'Brien 1313257c5577SDavid E. O'Brien void 1314257c5577SDavid E. O'Brien nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1315257c5577SDavid E. O'Brien { 1316257c5577SDavid E. O'Brien struct nfe_rx_data *data; 1317257c5577SDavid E. O'Brien void *desc; 1318257c5577SDavid E. O'Brien int i, descsize; 1319257c5577SDavid E. O'Brien 1320257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 1321257c5577SDavid E. O'Brien desc = ring->desc64; 1322257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1323257c5577SDavid E. O'Brien } else { 1324257c5577SDavid E. O'Brien desc = ring->desc32; 1325257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1326257c5577SDavid E. O'Brien } 1327257c5577SDavid E. O'Brien 1328257c5577SDavid E. O'Brien if (desc != NULL) { 1329257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, 1330257c5577SDavid E. O'Brien ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1331257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, ring->map); 1332257c5577SDavid E. O'Brien bus_dmamem_unmap(sc->sc_dmat, (caddr_t)desc, 1333257c5577SDavid E. O'Brien NFE_RX_RING_COUNT * descsize); 1334257c5577SDavid E. O'Brien bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); 1335257c5577SDavid E. O'Brien } 1336257c5577SDavid E. O'Brien 1337257c5577SDavid E. O'Brien for (i = 0; i < NFE_RX_RING_COUNT; i++) { 1338257c5577SDavid E. O'Brien data = &ring->data[i]; 1339257c5577SDavid E. O'Brien 1340257c5577SDavid E. O'Brien if (data->map != NULL) { 1341257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, data->map, 0, 1342257c5577SDavid E. O'Brien data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); 1343257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, data->map); 1344257c5577SDavid E. O'Brien bus_dmamap_destroy(sc->sc_dmat, data->map); 1345257c5577SDavid E. O'Brien } 1346257c5577SDavid E. O'Brien if (data->m != NULL) 1347257c5577SDavid E. O'Brien m_freem(data->m); 1348257c5577SDavid E. O'Brien } 1349257c5577SDavid E. O'Brien } 1350257c5577SDavid E. O'Brien 1351257c5577SDavid E. O'Brien struct nfe_jbuf * 1352257c5577SDavid E. O'Brien nfe_jalloc(struct nfe_softc *sc) 1353257c5577SDavid E. O'Brien { 1354257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 1355257c5577SDavid E. O'Brien 1356257c5577SDavid E. O'Brien jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 1357257c5577SDavid E. O'Brien if (jbuf == NULL) 1358257c5577SDavid E. O'Brien return NULL; 1359257c5577SDavid E. O'Brien SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 1360257c5577SDavid E. O'Brien return jbuf; 1361257c5577SDavid E. O'Brien } 1362257c5577SDavid E. O'Brien 1363257c5577SDavid E. O'Brien /* 1364257c5577SDavid E. O'Brien * This is called automatically by the network stack when the mbuf is freed. 1365257c5577SDavid E. O'Brien * Caution must be taken that the NIC might be reset by the time the mbuf is 1366257c5577SDavid E. O'Brien * freed. 1367257c5577SDavid E. O'Brien */ 1368257c5577SDavid E. O'Brien void 1369257c5577SDavid E. O'Brien nfe_jfree(caddr_t buf, u_int size, void *arg) 1370257c5577SDavid E. O'Brien { 1371257c5577SDavid E. O'Brien struct nfe_softc *sc = arg; 1372257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 1373257c5577SDavid E. O'Brien int i; 1374257c5577SDavid E. O'Brien 1375257c5577SDavid E. O'Brien /* find the jbuf from the base pointer */ 1376257c5577SDavid E. O'Brien i = (buf - sc->rxq.jpool) / NFE_JBYTES; 1377257c5577SDavid E. O'Brien if (i < 0 || i >= NFE_JPOOL_COUNT) { 1378257c5577SDavid E. O'Brien printf("%s: request to free a buffer (%p) not managed by us\n", 1379257c5577SDavid E. O'Brien sc->sc_dev.dv_xname, buf); 1380257c5577SDavid E. O'Brien return; 1381257c5577SDavid E. O'Brien } 1382257c5577SDavid E. O'Brien jbuf = &sc->rxq.jbuf[i]; 1383257c5577SDavid E. O'Brien 1384257c5577SDavid E. O'Brien /* ..and put it back in the free list */ 1385257c5577SDavid E. O'Brien SLIST_INSERT_HEAD(&sc->rxq.jfreelist, jbuf, jnext); 1386257c5577SDavid E. O'Brien } 1387257c5577SDavid E. O'Brien 1388257c5577SDavid E. O'Brien int 1389257c5577SDavid E. O'Brien nfe_jpool_alloc(struct nfe_softc *sc) 1390257c5577SDavid E. O'Brien { 1391257c5577SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 1392257c5577SDavid E. O'Brien struct nfe_jbuf *jbuf; 1393257c5577SDavid E. O'Brien bus_addr_t physaddr; 1394257c5577SDavid E. O'Brien caddr_t buf; 1395257c5577SDavid E. O'Brien int i, nsegs, error; 1396257c5577SDavid E. O'Brien 1397257c5577SDavid E. O'Brien /* 1398257c5577SDavid E. O'Brien * Allocate a big chunk of DMA'able memory. 1399257c5577SDavid E. O'Brien */ 1400257c5577SDavid E. O'Brien error = bus_dmamap_create(sc->sc_dmat, NFE_JPOOL_SIZE, 1, 1401257c5577SDavid E. O'Brien NFE_JPOOL_SIZE, 0, BUS_DMA_NOWAIT, &ring->jmap); 1402257c5577SDavid E. O'Brien if (error != 0) { 1403257c5577SDavid E. O'Brien printf("%s: could not create jumbo DMA map\n", 1404257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1405257c5577SDavid E. O'Brien goto fail; 1406257c5577SDavid E. O'Brien } 1407257c5577SDavid E. O'Brien 1408257c5577SDavid E. O'Brien error = bus_dmamem_alloc(sc->sc_dmat, NFE_JPOOL_SIZE, PAGE_SIZE, 0, 1409257c5577SDavid E. O'Brien &ring->jseg, 1, &nsegs, BUS_DMA_NOWAIT); 1410257c5577SDavid E. O'Brien if (error != 0) { 1411257c5577SDavid E. O'Brien printf("%s could not allocate jumbo DMA memory\n", 1412257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1413257c5577SDavid E. O'Brien goto fail; 1414257c5577SDavid E. O'Brien } 1415257c5577SDavid E. O'Brien 1416257c5577SDavid E. O'Brien error = bus_dmamem_map(sc->sc_dmat, &ring->jseg, nsegs, NFE_JPOOL_SIZE, 1417257c5577SDavid E. O'Brien &ring->jpool, BUS_DMA_NOWAIT); 1418257c5577SDavid E. O'Brien if (error != 0) { 1419257c5577SDavid E. O'Brien printf("%s: could not map jumbo DMA memory\n", 1420257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1421257c5577SDavid E. O'Brien goto fail; 1422257c5577SDavid E. O'Brien } 1423257c5577SDavid E. O'Brien 1424257c5577SDavid E. O'Brien error = bus_dmamap_load(sc->sc_dmat, ring->jmap, ring->jpool, 1425257c5577SDavid E. O'Brien NFE_JPOOL_SIZE, NULL, BUS_DMA_READ | BUS_DMA_NOWAIT); 1426257c5577SDavid E. O'Brien if (error != 0) { 1427257c5577SDavid E. O'Brien printf("%s: could not load jumbo DMA map\n", 1428257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1429257c5577SDavid E. O'Brien goto fail; 1430257c5577SDavid E. O'Brien } 1431257c5577SDavid E. O'Brien 1432257c5577SDavid E. O'Brien /* ..and split it into 9KB chunks */ 1433257c5577SDavid E. O'Brien SLIST_INIT(&ring->jfreelist); 1434257c5577SDavid E. O'Brien 1435257c5577SDavid E. O'Brien buf = ring->jpool; 1436257c5577SDavid E. O'Brien physaddr = ring->jmap->dm_segs[0].ds_addr; 1437257c5577SDavid E. O'Brien for (i = 0; i < NFE_JPOOL_COUNT; i++) { 1438257c5577SDavid E. O'Brien jbuf = &ring->jbuf[i]; 1439257c5577SDavid E. O'Brien 1440257c5577SDavid E. O'Brien jbuf->buf = buf; 1441257c5577SDavid E. O'Brien jbuf->physaddr = physaddr; 1442257c5577SDavid E. O'Brien 1443257c5577SDavid E. O'Brien SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 1444257c5577SDavid E. O'Brien 1445257c5577SDavid E. O'Brien buf += NFE_JBYTES; 1446257c5577SDavid E. O'Brien physaddr += NFE_JBYTES; 1447257c5577SDavid E. O'Brien } 1448257c5577SDavid E. O'Brien 1449257c5577SDavid E. O'Brien return 0; 1450257c5577SDavid E. O'Brien 1451257c5577SDavid E. O'Brien fail: nfe_jpool_free(sc); 1452257c5577SDavid E. O'Brien return error; 1453257c5577SDavid E. O'Brien } 1454257c5577SDavid E. O'Brien 1455257c5577SDavid E. O'Brien void 1456257c5577SDavid E. O'Brien nfe_jpool_free(struct nfe_softc *sc) 1457257c5577SDavid E. O'Brien { 1458257c5577SDavid E. O'Brien struct nfe_rx_ring *ring = &sc->rxq; 1459257c5577SDavid E. O'Brien 1460257c5577SDavid E. O'Brien if (ring->jmap != NULL) { 1461257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, ring->jmap, 0, 1462257c5577SDavid E. O'Brien ring->jmap->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1463257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, ring->jmap); 1464257c5577SDavid E. O'Brien bus_dmamap_destroy(sc->sc_dmat, ring->jmap); 1465257c5577SDavid E. O'Brien } 1466257c5577SDavid E. O'Brien if (ring->jpool != NULL) { 1467257c5577SDavid E. O'Brien bus_dmamem_unmap(sc->sc_dmat, ring->jpool, NFE_JPOOL_SIZE); 1468257c5577SDavid E. O'Brien bus_dmamem_free(sc->sc_dmat, &ring->jseg, 1); 1469257c5577SDavid E. O'Brien } 1470257c5577SDavid E. O'Brien } 1471257c5577SDavid E. O'Brien 1472257c5577SDavid E. O'Brien int 1473257c5577SDavid E. O'Brien nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1474257c5577SDavid E. O'Brien { 1475257c5577SDavid E. O'Brien int i, nsegs, error; 1476257c5577SDavid E. O'Brien void **desc; 1477257c5577SDavid E. O'Brien int descsize; 1478257c5577SDavid E. O'Brien 1479257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 1480257c5577SDavid E. O'Brien desc = (void **)&ring->desc64; 1481257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1482257c5577SDavid E. O'Brien } else { 1483257c5577SDavid E. O'Brien desc = (void **)&ring->desc32; 1484257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1485257c5577SDavid E. O'Brien } 1486257c5577SDavid E. O'Brien 1487257c5577SDavid E. O'Brien ring->queued = 0; 1488257c5577SDavid E. O'Brien ring->cur = ring->next = 0; 1489257c5577SDavid E. O'Brien 1490257c5577SDavid E. O'Brien error = bus_dmamap_create(sc->sc_dmat, NFE_TX_RING_COUNT * descsize, 1, 1491257c5577SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, 0, BUS_DMA_NOWAIT, &ring->map); 1492257c5577SDavid E. O'Brien 1493257c5577SDavid E. O'Brien if (error != 0) { 1494257c5577SDavid E. O'Brien printf("%s: could not create desc DMA map\n", 1495257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1496257c5577SDavid E. O'Brien goto fail; 1497257c5577SDavid E. O'Brien } 1498257c5577SDavid E. O'Brien 1499257c5577SDavid E. O'Brien error = bus_dmamem_alloc(sc->sc_dmat, NFE_TX_RING_COUNT * descsize, 1500257c5577SDavid E. O'Brien PAGE_SIZE, 0, &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); 1501257c5577SDavid E. O'Brien if (error != 0) { 1502257c5577SDavid E. O'Brien printf("%s: could not allocate DMA memory\n", 1503257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1504257c5577SDavid E. O'Brien goto fail; 1505257c5577SDavid E. O'Brien } 1506257c5577SDavid E. O'Brien 1507257c5577SDavid E. O'Brien error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, 1508257c5577SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, (caddr_t *)desc, BUS_DMA_NOWAIT); 1509257c5577SDavid E. O'Brien if (error != 0) { 1510257c5577SDavid E. O'Brien printf("%s: could not map desc DMA memory\n", 1511257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1512257c5577SDavid E. O'Brien goto fail; 1513257c5577SDavid E. O'Brien } 1514257c5577SDavid E. O'Brien 1515257c5577SDavid E. O'Brien error = bus_dmamap_load(sc->sc_dmat, ring->map, *desc, 1516257c5577SDavid E. O'Brien NFE_TX_RING_COUNT * descsize, NULL, BUS_DMA_NOWAIT); 1517257c5577SDavid E. O'Brien if (error != 0) { 1518257c5577SDavid E. O'Brien printf("%s: could not load desc DMA map\n", 1519257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1520257c5577SDavid E. O'Brien goto fail; 1521257c5577SDavid E. O'Brien } 1522257c5577SDavid E. O'Brien 1523257c5577SDavid E. O'Brien bzero(*desc, NFE_TX_RING_COUNT * descsize); 1524257c5577SDavid E. O'Brien ring->physaddr = ring->map->dm_segs[0].ds_addr; 1525257c5577SDavid E. O'Brien 1526257c5577SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1527257c5577SDavid E. O'Brien error = bus_dmamap_create(sc->sc_dmat, NFE_JBYTES, 1528257c5577SDavid E. O'Brien NFE_MAX_SCATTER, NFE_JBYTES, 0, BUS_DMA_NOWAIT, 1529257c5577SDavid E. O'Brien &ring->data[i].map); 1530257c5577SDavid E. O'Brien if (error != 0) { 1531257c5577SDavid E. O'Brien printf("%s: could not create DMA map\n", 1532257c5577SDavid E. O'Brien sc->sc_dev.dv_xname); 1533257c5577SDavid E. O'Brien goto fail; 1534257c5577SDavid E. O'Brien } 1535257c5577SDavid E. O'Brien } 1536257c5577SDavid E. O'Brien 1537257c5577SDavid E. O'Brien return 0; 1538257c5577SDavid E. O'Brien 1539257c5577SDavid E. O'Brien fail: nfe_free_tx_ring(sc, ring); 1540257c5577SDavid E. O'Brien return error; 1541257c5577SDavid E. O'Brien } 1542257c5577SDavid E. O'Brien 1543257c5577SDavid E. O'Brien void 1544257c5577SDavid E. O'Brien nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1545257c5577SDavid E. O'Brien { 1546257c5577SDavid E. O'Brien struct nfe_tx_data *data; 1547257c5577SDavid E. O'Brien int i; 1548257c5577SDavid E. O'Brien 1549257c5577SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1550257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) 1551257c5577SDavid E. O'Brien ring->desc64[i].flags = 0; 1552257c5577SDavid E. O'Brien else 1553257c5577SDavid E. O'Brien ring->desc32[i].flags = 0; 1554257c5577SDavid E. O'Brien 1555257c5577SDavid E. O'Brien data = &ring->data[i]; 1556257c5577SDavid E. O'Brien 1557257c5577SDavid E. O'Brien if (data->m != NULL) { 1558257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, data->active, 0, 1559257c5577SDavid E. O'Brien data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1560257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, data->active); 1561257c5577SDavid E. O'Brien m_freem(data->m); 1562257c5577SDavid E. O'Brien data->m = NULL; 1563257c5577SDavid E. O'Brien } 1564257c5577SDavid E. O'Brien } 1565257c5577SDavid E. O'Brien 1566257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, 1567257c5577SDavid E. O'Brien BUS_DMASYNC_PREWRITE); 1568257c5577SDavid E. O'Brien 1569257c5577SDavid E. O'Brien ring->queued = 0; 1570257c5577SDavid E. O'Brien ring->cur = ring->next = 0; 1571257c5577SDavid E. O'Brien } 1572257c5577SDavid E. O'Brien 1573257c5577SDavid E. O'Brien void 1574257c5577SDavid E. O'Brien nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1575257c5577SDavid E. O'Brien { 1576257c5577SDavid E. O'Brien struct nfe_tx_data *data; 1577257c5577SDavid E. O'Brien void *desc; 1578257c5577SDavid E. O'Brien int i, descsize; 1579257c5577SDavid E. O'Brien 1580257c5577SDavid E. O'Brien if (sc->sc_flags & NFE_40BIT_ADDR) { 1581257c5577SDavid E. O'Brien desc = ring->desc64; 1582257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc64); 1583257c5577SDavid E. O'Brien } else { 1584257c5577SDavid E. O'Brien desc = ring->desc32; 1585257c5577SDavid E. O'Brien descsize = sizeof (struct nfe_desc32); 1586257c5577SDavid E. O'Brien } 1587257c5577SDavid E. O'Brien 1588257c5577SDavid E. O'Brien if (desc != NULL) { 1589257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, ring->map, 0, 1590257c5577SDavid E. O'Brien ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1591257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, ring->map); 1592257c5577SDavid E. O'Brien bus_dmamem_unmap(sc->sc_dmat, (caddr_t)desc, 1593257c5577SDavid E. O'Brien NFE_TX_RING_COUNT * descsize); 1594257c5577SDavid E. O'Brien bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); 1595257c5577SDavid E. O'Brien } 1596257c5577SDavid E. O'Brien 1597257c5577SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1598257c5577SDavid E. O'Brien data = &ring->data[i]; 1599257c5577SDavid E. O'Brien 1600257c5577SDavid E. O'Brien if (data->m != NULL) { 1601257c5577SDavid E. O'Brien bus_dmamap_sync(sc->sc_dmat, data->active, 0, 1602257c5577SDavid E. O'Brien data->active->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1603257c5577SDavid E. O'Brien bus_dmamap_unload(sc->sc_dmat, data->active); 1604257c5577SDavid E. O'Brien m_freem(data->m); 1605257c5577SDavid E. O'Brien } 1606257c5577SDavid E. O'Brien } 1607257c5577SDavid E. O'Brien 1608257c5577SDavid E. O'Brien /* ..and now actually destroy the DMA mappings */ 1609257c5577SDavid E. O'Brien for (i = 0; i < NFE_TX_RING_COUNT; i++) { 1610257c5577SDavid E. O'Brien data = &ring->data[i]; 1611257c5577SDavid E. O'Brien if (data->map == NULL) 1612257c5577SDavid E. O'Brien continue; 1613257c5577SDavid E. O'Brien bus_dmamap_destroy(sc->sc_dmat, data->map); 1614257c5577SDavid E. O'Brien } 1615257c5577SDavid E. O'Brien } 1616257c5577SDavid E. O'Brien 1617257c5577SDavid E. O'Brien int 1618257c5577SDavid E. O'Brien nfe_ifmedia_upd(struct ifnet *ifp) 1619257c5577SDavid E. O'Brien { 1620257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1621257c5577SDavid E. O'Brien struct mii_data *mii = &sc->sc_mii; 1622257c5577SDavid E. O'Brien struct mii_softc *miisc; 1623257c5577SDavid E. O'Brien 1624257c5577SDavid E. O'Brien if (mii->mii_instance != 0) { 1625257c5577SDavid E. O'Brien LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1626257c5577SDavid E. O'Brien mii_phy_reset(miisc); 1627257c5577SDavid E. O'Brien } 1628257c5577SDavid E. O'Brien return mii_mediachg(mii); 1629257c5577SDavid E. O'Brien } 1630257c5577SDavid E. O'Brien 1631257c5577SDavid E. O'Brien void 1632257c5577SDavid E. O'Brien nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1633257c5577SDavid E. O'Brien { 1634257c5577SDavid E. O'Brien struct nfe_softc *sc = ifp->if_softc; 1635257c5577SDavid E. O'Brien struct mii_data *mii = &sc->sc_mii; 1636257c5577SDavid E. O'Brien 1637257c5577SDavid E. O'Brien mii_pollstat(mii); 1638257c5577SDavid E. O'Brien ifmr->ifm_status = mii->mii_media_status; 1639257c5577SDavid E. O'Brien ifmr->ifm_active = mii->mii_media_active; 1640257c5577SDavid E. O'Brien } 1641257c5577SDavid E. O'Brien 1642257c5577SDavid E. O'Brien void 1643257c5577SDavid E. O'Brien nfe_setmulti(struct nfe_softc *sc) 1644257c5577SDavid E. O'Brien { 1645257c5577SDavid E. O'Brien struct arpcom *ac = &sc->sc_arpcom; 1646257c5577SDavid E. O'Brien struct ifnet *ifp = &ac->ac_if; 1647257c5577SDavid E. O'Brien struct ether_multi *enm; 1648257c5577SDavid E. O'Brien struct ether_multistep step; 1649257c5577SDavid E. O'Brien uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 1650257c5577SDavid E. O'Brien uint32_t filter = NFE_RXFILTER_MAGIC; 1651257c5577SDavid E. O'Brien int i; 1652257c5577SDavid E. O'Brien 1653257c5577SDavid E. O'Brien if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1654257c5577SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 1655257c5577SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 1656257c5577SDavid E. O'Brien goto done; 1657257c5577SDavid E. O'Brien } 1658257c5577SDavid E. O'Brien 1659257c5577SDavid E. O'Brien bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 1660257c5577SDavid E. O'Brien bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 1661257c5577SDavid E. O'Brien 1662257c5577SDavid E. O'Brien ETHER_FIRST_MULTI(step, ac, enm); 1663257c5577SDavid E. O'Brien while (enm != NULL) { 1664257c5577SDavid E. O'Brien if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { 1665257c5577SDavid E. O'Brien ifp->if_flags |= IFF_ALLMULTI; 1666257c5577SDavid E. O'Brien bzero(addr, ETHER_ADDR_LEN); 1667257c5577SDavid E. O'Brien bzero(mask, ETHER_ADDR_LEN); 1668257c5577SDavid E. O'Brien goto done; 1669257c5577SDavid E. O'Brien } 1670257c5577SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) { 1671257c5577SDavid E. O'Brien addr[i] &= enm->enm_addrlo[i]; 1672257c5577SDavid E. O'Brien mask[i] &= ~enm->enm_addrlo[i]; 1673257c5577SDavid E. O'Brien } 1674257c5577SDavid E. O'Brien ETHER_NEXT_MULTI(step, enm); 1675257c5577SDavid E. O'Brien } 1676257c5577SDavid E. O'Brien for (i = 0; i < ETHER_ADDR_LEN; i++) 1677257c5577SDavid E. O'Brien mask[i] |= addr[i]; 1678257c5577SDavid E. O'Brien 1679257c5577SDavid E. O'Brien done: 1680257c5577SDavid E. O'Brien addr[0] |= 0x01; /* make sure multicast bit is set */ 1681257c5577SDavid E. O'Brien 1682257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_HI, 1683257c5577SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1684257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIADDR_LO, 1685257c5577SDavid E. O'Brien addr[5] << 8 | addr[4]); 1686257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_HI, 1687257c5577SDavid E. O'Brien mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 1688257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MULTIMASK_LO, 1689257c5577SDavid E. O'Brien mask[5] << 8 | mask[4]); 1690257c5577SDavid E. O'Brien 1691257c5577SDavid E. O'Brien filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 1692257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_RXFILTER, filter); 1693257c5577SDavid E. O'Brien } 1694257c5577SDavid E. O'Brien 1695257c5577SDavid E. O'Brien void 1696257c5577SDavid E. O'Brien nfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 1697257c5577SDavid E. O'Brien { 1698257c5577SDavid E. O'Brien uint32_t tmp; 1699257c5577SDavid E. O'Brien 1700257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_LO); 1701257c5577SDavid E. O'Brien addr[0] = (tmp >> 8) & 0xff; 1702257c5577SDavid E. O'Brien addr[1] = (tmp & 0xff); 1703257c5577SDavid E. O'Brien 1704257c5577SDavid E. O'Brien tmp = NFE_READ(sc, NFE_MACADDR_HI); 1705257c5577SDavid E. O'Brien addr[2] = (tmp >> 24) & 0xff; 1706257c5577SDavid E. O'Brien addr[3] = (tmp >> 16) & 0xff; 1707257c5577SDavid E. O'Brien addr[4] = (tmp >> 8) & 0xff; 1708257c5577SDavid E. O'Brien addr[5] = (tmp & 0xff); 1709257c5577SDavid E. O'Brien } 1710257c5577SDavid E. O'Brien 1711257c5577SDavid E. O'Brien void 1712257c5577SDavid E. O'Brien nfe_set_macaddr(struct nfe_softc *sc, const uint8_t *addr) 1713257c5577SDavid E. O'Brien { 1714257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_LO, 1715257c5577SDavid E. O'Brien addr[5] << 8 | addr[4]); 1716257c5577SDavid E. O'Brien NFE_WRITE(sc, NFE_MACADDR_HI, 1717257c5577SDavid E. O'Brien addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 1718257c5577SDavid E. O'Brien } 1719257c5577SDavid E. O'Brien 1720257c5577SDavid E. O'Brien void 1721257c5577SDavid E. O'Brien nfe_tick(void *arg) 1722257c5577SDavid E. O'Brien { 1723257c5577SDavid E. O'Brien struct nfe_softc *sc = arg; 1724257c5577SDavid E. O'Brien int s; 1725257c5577SDavid E. O'Brien 1726257c5577SDavid E. O'Brien s = splnet(); 1727257c5577SDavid E. O'Brien mii_tick(&sc->sc_mii); 1728257c5577SDavid E. O'Brien splx(s); 1729257c5577SDavid E. O'Brien 1730257c5577SDavid E. O'Brien timeout_add(&sc->sc_tick_ch, hz); 1731257c5577SDavid E. O'Brien } 1732