1ae813fd8SSepherosa Ziehau /* $OpenBSD: if_nfe.c,v 1.63 2006/06/17 18:00:43 brad Exp $ */ 2ae813fd8SSepherosa Ziehau 3ae813fd8SSepherosa Ziehau /* 4ae813fd8SSepherosa Ziehau * Copyright (c) 2006 The DragonFly Project. All rights reserved. 5ae813fd8SSepherosa Ziehau * 6ae813fd8SSepherosa Ziehau * This code is derived from software contributed to The DragonFly Project 7ae813fd8SSepherosa Ziehau * by Sepherosa Ziehau <sepherosa@gmail.com> and 8ae813fd8SSepherosa Ziehau * Matthew Dillon <dillon@apollo.backplane.com> 9ae813fd8SSepherosa Ziehau * 10ae813fd8SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 11ae813fd8SSepherosa Ziehau * modification, are permitted provided that the following conditions 12ae813fd8SSepherosa Ziehau * are met: 13ae813fd8SSepherosa Ziehau * 14ae813fd8SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 15ae813fd8SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 16ae813fd8SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 17ae813fd8SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in 18ae813fd8SSepherosa Ziehau * the documentation and/or other materials provided with the 19ae813fd8SSepherosa Ziehau * distribution. 20ae813fd8SSepherosa Ziehau * 3. Neither the name of The DragonFly Project nor the names of its 21ae813fd8SSepherosa Ziehau * contributors may be used to endorse or promote products derived 22ae813fd8SSepherosa Ziehau * from this software without specific, prior written permission. 23ae813fd8SSepherosa Ziehau * 24ae813fd8SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25ae813fd8SSepherosa Ziehau * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26ae813fd8SSepherosa Ziehau * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27ae813fd8SSepherosa Ziehau * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28ae813fd8SSepherosa Ziehau * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29ae813fd8SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 30ae813fd8SSepherosa Ziehau * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31ae813fd8SSepherosa Ziehau * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32ae813fd8SSepherosa Ziehau * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33ae813fd8SSepherosa Ziehau * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34ae813fd8SSepherosa Ziehau * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35ae813fd8SSepherosa Ziehau * SUCH DAMAGE. 36ae813fd8SSepherosa Ziehau */ 37ae813fd8SSepherosa Ziehau 38ae813fd8SSepherosa Ziehau /* 39ae813fd8SSepherosa Ziehau * Copyright (c) 2006 Damien Bergamini <damien.bergamini@free.fr> 40ae813fd8SSepherosa Ziehau * Copyright (c) 2005, 2006 Jonathan Gray <jsg@openbsd.org> 41ae813fd8SSepherosa Ziehau * 42ae813fd8SSepherosa Ziehau * Permission to use, copy, modify, and distribute this software for any 43ae813fd8SSepherosa Ziehau * purpose with or without fee is hereby granted, provided that the above 44ae813fd8SSepherosa Ziehau * copyright notice and this permission notice appear in all copies. 45ae813fd8SSepherosa Ziehau * 46ae813fd8SSepherosa Ziehau * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 47ae813fd8SSepherosa Ziehau * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 48ae813fd8SSepherosa Ziehau * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 49ae813fd8SSepherosa Ziehau * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 50ae813fd8SSepherosa Ziehau * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 51ae813fd8SSepherosa Ziehau * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 52ae813fd8SSepherosa Ziehau * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 53ae813fd8SSepherosa Ziehau */ 54ae813fd8SSepherosa Ziehau 55ae813fd8SSepherosa Ziehau /* Driver for NVIDIA nForce MCP Fast Ethernet and Gigabit Ethernet */ 56ae813fd8SSepherosa Ziehau 57d2e51f8dSSepherosa Ziehau #include "opt_ifpoll.h" 58ae813fd8SSepherosa Ziehau 59ae813fd8SSepherosa Ziehau #include <sys/param.h> 60ae813fd8SSepherosa Ziehau #include <sys/endian.h> 61ae813fd8SSepherosa Ziehau #include <sys/kernel.h> 62ae813fd8SSepherosa Ziehau #include <sys/bus.h> 639db4b353SSepherosa Ziehau #include <sys/interrupt.h> 64ae813fd8SSepherosa Ziehau #include <sys/proc.h> 65ae813fd8SSepherosa Ziehau #include <sys/rman.h> 66ae813fd8SSepherosa Ziehau #include <sys/serialize.h> 67ae813fd8SSepherosa Ziehau #include <sys/socket.h> 68ae813fd8SSepherosa Ziehau #include <sys/sockio.h> 69ae813fd8SSepherosa Ziehau #include <sys/sysctl.h> 70ae813fd8SSepherosa Ziehau 71ae813fd8SSepherosa Ziehau #include <net/ethernet.h> 72ae813fd8SSepherosa Ziehau #include <net/if.h> 73ae813fd8SSepherosa Ziehau #include <net/bpf.h> 74ae813fd8SSepherosa Ziehau #include <net/if_arp.h> 75ae813fd8SSepherosa Ziehau #include <net/if_dl.h> 76ae813fd8SSepherosa Ziehau #include <net/if_media.h> 77d2e51f8dSSepherosa Ziehau #include <net/if_poll.h> 78ae813fd8SSepherosa Ziehau #include <net/ifq_var.h> 79ae813fd8SSepherosa Ziehau #include <net/if_types.h> 80ae813fd8SSepherosa Ziehau #include <net/if_var.h> 81ae813fd8SSepherosa Ziehau #include <net/vlan/if_vlan_var.h> 82b637f170SSepherosa Ziehau #include <net/vlan/if_vlan_ether.h> 83ae813fd8SSepherosa Ziehau 84ae813fd8SSepherosa Ziehau #include <bus/pci/pcireg.h> 85ae813fd8SSepherosa Ziehau #include <bus/pci/pcivar.h> 86ae813fd8SSepherosa Ziehau #include <bus/pci/pcidevs.h> 87ae813fd8SSepherosa Ziehau 88ae813fd8SSepherosa Ziehau #include <dev/netif/mii_layer/mii.h> 89ae813fd8SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 90ae813fd8SSepherosa Ziehau 91ae813fd8SSepherosa Ziehau #include "miibus_if.h" 92ae813fd8SSepherosa Ziehau 9311db6c57SSepherosa Ziehau #include <dev/netif/nfe/if_nfereg.h> 9411db6c57SSepherosa Ziehau #include <dev/netif/nfe/if_nfevar.h> 9511db6c57SSepherosa Ziehau 9611db6c57SSepherosa Ziehau #define NFE_CSUM 9711db6c57SSepherosa Ziehau #define NFE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 98ae813fd8SSepherosa Ziehau 99ae813fd8SSepherosa Ziehau static int nfe_probe(device_t); 100ae813fd8SSepherosa Ziehau static int nfe_attach(device_t); 101ae813fd8SSepherosa Ziehau static int nfe_detach(device_t); 102ae813fd8SSepherosa Ziehau static void nfe_shutdown(device_t); 103ae813fd8SSepherosa Ziehau static int nfe_resume(device_t); 104ae813fd8SSepherosa Ziehau static int nfe_suspend(device_t); 105ae813fd8SSepherosa Ziehau 106ae813fd8SSepherosa Ziehau static int nfe_miibus_readreg(device_t, int, int); 107ae813fd8SSepherosa Ziehau static void nfe_miibus_writereg(device_t, int, int, int); 108ae813fd8SSepherosa Ziehau static void nfe_miibus_statchg(device_t); 109ae813fd8SSepherosa Ziehau 110d2e51f8dSSepherosa Ziehau #ifdef IFPOLL_ENABLE 111d2e51f8dSSepherosa Ziehau static void nfe_npoll(struct ifnet *, struct ifpoll_info *); 112d2e51f8dSSepherosa Ziehau static void nfe_npoll_compat(struct ifnet *, void *, int); 113afd270efSSylvestre Gallon static void nfe_disable_intrs(struct nfe_softc *); 114ae813fd8SSepherosa Ziehau #endif 115ae813fd8SSepherosa Ziehau static void nfe_intr(void *); 116ae813fd8SSepherosa Ziehau static int nfe_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 11704b9ef8dSSepherosa Ziehau static int nfe_rxeof(struct nfe_softc *); 118d378110eSSepherosa Ziehau static int nfe_txeof(struct nfe_softc *, int); 119ae813fd8SSepherosa Ziehau static int nfe_encap(struct nfe_softc *, struct nfe_tx_ring *, 120ae813fd8SSepherosa Ziehau struct mbuf *); 121f0a26983SSepherosa Ziehau static void nfe_start(struct ifnet *, struct ifaltq_subque *); 122ae813fd8SSepherosa Ziehau static void nfe_watchdog(struct ifnet *); 123ae813fd8SSepherosa Ziehau static void nfe_init(void *); 124ae813fd8SSepherosa Ziehau static void nfe_stop(struct nfe_softc *); 125ae813fd8SSepherosa Ziehau static struct nfe_jbuf *nfe_jalloc(struct nfe_softc *); 126ae813fd8SSepherosa Ziehau static void nfe_jfree(void *); 127ae813fd8SSepherosa Ziehau static void nfe_jref(void *); 128ae813fd8SSepherosa Ziehau static int nfe_jpool_alloc(struct nfe_softc *, struct nfe_rx_ring *); 129ae813fd8SSepherosa Ziehau static void nfe_jpool_free(struct nfe_softc *, struct nfe_rx_ring *); 130ae813fd8SSepherosa Ziehau static int nfe_alloc_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 131ae813fd8SSepherosa Ziehau static void nfe_reset_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 132ae813fd8SSepherosa Ziehau static int nfe_init_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 133ae813fd8SSepherosa Ziehau static void nfe_free_rx_ring(struct nfe_softc *, struct nfe_rx_ring *); 134ae813fd8SSepherosa Ziehau static int nfe_alloc_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 135ae813fd8SSepherosa Ziehau static void nfe_reset_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 136ae813fd8SSepherosa Ziehau static int nfe_init_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 137ae813fd8SSepherosa Ziehau static void nfe_free_tx_ring(struct nfe_softc *, struct nfe_tx_ring *); 138ae813fd8SSepherosa Ziehau static int nfe_ifmedia_upd(struct ifnet *); 139ae813fd8SSepherosa Ziehau static void nfe_ifmedia_sts(struct ifnet *, struct ifmediareq *); 140ae813fd8SSepherosa Ziehau static void nfe_setmulti(struct nfe_softc *); 141ae813fd8SSepherosa Ziehau static void nfe_get_macaddr(struct nfe_softc *, uint8_t *); 142ae813fd8SSepherosa Ziehau static void nfe_set_macaddr(struct nfe_softc *, const uint8_t *); 143faaea42eSSepherosa Ziehau static void nfe_powerup(device_t); 144faaea42eSSepherosa Ziehau static void nfe_mac_reset(struct nfe_softc *); 145ae813fd8SSepherosa Ziehau static void nfe_tick(void *); 146ae813fd8SSepherosa Ziehau static void nfe_set_paddr_rxdesc(struct nfe_softc *, struct nfe_rx_ring *, 147ae813fd8SSepherosa Ziehau int, bus_addr_t); 148ae813fd8SSepherosa Ziehau static void nfe_set_ready_rxdesc(struct nfe_softc *, struct nfe_rx_ring *, 149ae813fd8SSepherosa Ziehau int); 150ae813fd8SSepherosa Ziehau static int nfe_newbuf_std(struct nfe_softc *, struct nfe_rx_ring *, int, 151ae813fd8SSepherosa Ziehau int); 152ae813fd8SSepherosa Ziehau static int nfe_newbuf_jumbo(struct nfe_softc *, struct nfe_rx_ring *, int, 153ae813fd8SSepherosa Ziehau int); 15404b9ef8dSSepherosa Ziehau static void nfe_enable_intrs(struct nfe_softc *); 155ae813fd8SSepherosa Ziehau 156ec9403d0SSepherosa Ziehau static int nfe_sysctl_imtime(SYSCTL_HANDLER_ARGS); 157ec9403d0SSepherosa Ziehau 158ae813fd8SSepherosa Ziehau #define NFE_DEBUG 159ae813fd8SSepherosa Ziehau #ifdef NFE_DEBUG 160ae813fd8SSepherosa Ziehau 161ae813fd8SSepherosa Ziehau static int nfe_debug = 0; 162a455c52eSSepherosa Ziehau static int nfe_rx_ring_count = NFE_RX_RING_DEF_COUNT; 163b4633098SSepherosa Ziehau static int nfe_tx_ring_count = NFE_TX_RING_DEF_COUNT; 164c00ddf33SMatthew Dillon /* 1655df3a6aaSMatthew Dillon * hw timer simulated interrupt moderation @4000Hz. Negative values 1665df3a6aaSMatthew Dillon * disable the timer when the discrete interrupt rate falls below 1675df3a6aaSMatthew Dillon * the moderation rate. 168c00ddf33SMatthew Dillon * 169c00ddf33SMatthew Dillon * XXX 8000Hz might be better but if the interrupt is shared it can 170c00ddf33SMatthew Dillon * blow out the cpu. 171c00ddf33SMatthew Dillon */ 1725df3a6aaSMatthew Dillon static int nfe_imtime = -250; /* uS */ 173a455c52eSSepherosa Ziehau 174a455c52eSSepherosa Ziehau TUNABLE_INT("hw.nfe.rx_ring_count", &nfe_rx_ring_count); 175b4633098SSepherosa Ziehau TUNABLE_INT("hw.nfe.tx_ring_count", &nfe_tx_ring_count); 176c4eebf3aSThomas Nikolajsen TUNABLE_INT("hw.nfe.imtimer", &nfe_imtime); 177ec9403d0SSepherosa Ziehau TUNABLE_INT("hw.nfe.debug", &nfe_debug); 178ae813fd8SSepherosa Ziehau 179ae813fd8SSepherosa Ziehau #define DPRINTF(sc, fmt, ...) do { \ 180ec9403d0SSepherosa Ziehau if ((sc)->sc_debug) { \ 181ae813fd8SSepherosa Ziehau if_printf(&(sc)->arpcom.ac_if, \ 182ae813fd8SSepherosa Ziehau fmt, __VA_ARGS__); \ 183ae813fd8SSepherosa Ziehau } \ 184ae813fd8SSepherosa Ziehau } while (0) 185ae813fd8SSepherosa Ziehau 186ae813fd8SSepherosa Ziehau #define DPRINTFN(sc, lv, fmt, ...) do { \ 187ec9403d0SSepherosa Ziehau if ((sc)->sc_debug >= (lv)) { \ 188ae813fd8SSepherosa Ziehau if_printf(&(sc)->arpcom.ac_if, \ 189ae813fd8SSepherosa Ziehau fmt, __VA_ARGS__); \ 190ae813fd8SSepherosa Ziehau } \ 191ae813fd8SSepherosa Ziehau } while (0) 192ae813fd8SSepherosa Ziehau 193ae813fd8SSepherosa Ziehau #else /* !NFE_DEBUG */ 194ae813fd8SSepherosa Ziehau 195ae813fd8SSepherosa Ziehau #define DPRINTF(sc, fmt, ...) 196ae813fd8SSepherosa Ziehau #define DPRINTFN(sc, lv, fmt, ...) 197ae813fd8SSepherosa Ziehau 198ae813fd8SSepherosa Ziehau #endif /* NFE_DEBUG */ 199ae813fd8SSepherosa Ziehau 200ae813fd8SSepherosa Ziehau static const struct nfe_dev { 201ae813fd8SSepherosa Ziehau uint16_t vid; 202ae813fd8SSepherosa Ziehau uint16_t did; 203ae813fd8SSepherosa Ziehau const char *desc; 204ae813fd8SSepherosa Ziehau } nfe_devices[] = { 205ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_LAN, 20687e3db44SThomas E. Spanjaard "NVIDIA nForce Fast Ethernet" }, 207ae813fd8SSepherosa Ziehau 208ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_LAN, 20987e3db44SThomas E. Spanjaard "NVIDIA nForce2 Fast Ethernet" }, 210ae813fd8SSepherosa Ziehau 211ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN1, 212ae813fd8SSepherosa Ziehau "NVIDIA nForce3 Gigabit Ethernet" }, 213ae813fd8SSepherosa Ziehau 21487e3db44SThomas E. Spanjaard /* XXX TGEN the next chip can also be found in the nForce2 Ultra 400Gb 21587e3db44SThomas E. Spanjaard chipset, and possibly also the 400R; it might be both nForce2- and 21687e3db44SThomas E. Spanjaard nForce3-based boards can use the same MCPs (= southbridges) */ 217ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN2, 218ae813fd8SSepherosa Ziehau "NVIDIA nForce3 Gigabit Ethernet" }, 219ae813fd8SSepherosa Ziehau 220ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN3, 221ae813fd8SSepherosa Ziehau "NVIDIA nForce3 Gigabit Ethernet" }, 222ae813fd8SSepherosa Ziehau 223ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN4, 224ae813fd8SSepherosa Ziehau "NVIDIA nForce3 Gigabit Ethernet" }, 225ae813fd8SSepherosa Ziehau 226ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_LAN5, 227ae813fd8SSepherosa Ziehau "NVIDIA nForce3 Gigabit Ethernet" }, 228ae813fd8SSepherosa Ziehau 229ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN1, 230ae813fd8SSepherosa Ziehau "NVIDIA CK804 Gigabit Ethernet" }, 231ae813fd8SSepherosa Ziehau 232ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_CK804_LAN2, 233ae813fd8SSepherosa Ziehau "NVIDIA CK804 Gigabit Ethernet" }, 234ae813fd8SSepherosa Ziehau 235ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN1, 236ae813fd8SSepherosa Ziehau "NVIDIA MCP04 Gigabit Ethernet" }, 237ae813fd8SSepherosa Ziehau 238ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_LAN2, 239ae813fd8SSepherosa Ziehau "NVIDIA MCP04 Gigabit Ethernet" }, 240ae813fd8SSepherosa Ziehau 241ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN1, 242ae813fd8SSepherosa Ziehau "NVIDIA MCP51 Gigabit Ethernet" }, 243ae813fd8SSepherosa Ziehau 244ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_LAN2, 245ae813fd8SSepherosa Ziehau "NVIDIA MCP51 Gigabit Ethernet" }, 246ae813fd8SSepherosa Ziehau 247ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN1, 248ae813fd8SSepherosa Ziehau "NVIDIA MCP55 Gigabit Ethernet" }, 249ae813fd8SSepherosa Ziehau 250ae813fd8SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_LAN2, 2519d1ecb21SSepherosa Ziehau "NVIDIA MCP55 Gigabit Ethernet" }, 2529d1ecb21SSepherosa Ziehau 2539d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN1, 2549d1ecb21SSepherosa Ziehau "NVIDIA MCP61 Gigabit Ethernet" }, 2559d1ecb21SSepherosa Ziehau 2569d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN2, 2579d1ecb21SSepherosa Ziehau "NVIDIA MCP61 Gigabit Ethernet" }, 2589d1ecb21SSepherosa Ziehau 2599d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN3, 2609d1ecb21SSepherosa Ziehau "NVIDIA MCP61 Gigabit Ethernet" }, 2619d1ecb21SSepherosa Ziehau 2629d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_LAN4, 2639d1ecb21SSepherosa Ziehau "NVIDIA MCP61 Gigabit Ethernet" }, 2649d1ecb21SSepherosa Ziehau 2659d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN1, 2669d1ecb21SSepherosa Ziehau "NVIDIA MCP65 Gigabit Ethernet" }, 2679d1ecb21SSepherosa Ziehau 2689d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN2, 2699d1ecb21SSepherosa Ziehau "NVIDIA MCP65 Gigabit Ethernet" }, 2709d1ecb21SSepherosa Ziehau 2719d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN3, 2729d1ecb21SSepherosa Ziehau "NVIDIA MCP65 Gigabit Ethernet" }, 2739d1ecb21SSepherosa Ziehau 2749d1ecb21SSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_LAN4, 275df290cacSSepherosa Ziehau "NVIDIA MCP65 Gigabit Ethernet" }, 276df290cacSSepherosa Ziehau 277df290cacSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN1, 278df290cacSSepherosa Ziehau "NVIDIA MCP67 Gigabit Ethernet" }, 279df290cacSSepherosa Ziehau 280df290cacSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN2, 281df290cacSSepherosa Ziehau "NVIDIA MCP67 Gigabit Ethernet" }, 282df290cacSSepherosa Ziehau 283df290cacSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN3, 284df290cacSSepherosa Ziehau "NVIDIA MCP67 Gigabit Ethernet" }, 285df290cacSSepherosa Ziehau 286df290cacSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_LAN4, 2871d67eefeSSepherosa Ziehau "NVIDIA MCP67 Gigabit Ethernet" }, 2881d67eefeSSepherosa Ziehau 2891d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN1, 2901d67eefeSSepherosa Ziehau "NVIDIA MCP73 Gigabit Ethernet" }, 2911d67eefeSSepherosa Ziehau 2921d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN2, 2931d67eefeSSepherosa Ziehau "NVIDIA MCP73 Gigabit Ethernet" }, 2941d67eefeSSepherosa Ziehau 2951d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN3, 2961d67eefeSSepherosa Ziehau "NVIDIA MCP73 Gigabit Ethernet" }, 2971d67eefeSSepherosa Ziehau 2981d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_LAN4, 2991d67eefeSSepherosa Ziehau "NVIDIA MCP73 Gigabit Ethernet" }, 3001d67eefeSSepherosa Ziehau 3011d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN1, 3021d67eefeSSepherosa Ziehau "NVIDIA MCP77 Gigabit Ethernet" }, 3031d67eefeSSepherosa Ziehau 3041d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN2, 3051d67eefeSSepherosa Ziehau "NVIDIA MCP77 Gigabit Ethernet" }, 3061d67eefeSSepherosa Ziehau 3071d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN3, 3081d67eefeSSepherosa Ziehau "NVIDIA MCP77 Gigabit Ethernet" }, 3091d67eefeSSepherosa Ziehau 3101d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_LAN4, 3111d67eefeSSepherosa Ziehau "NVIDIA MCP77 Gigabit Ethernet" }, 3121d67eefeSSepherosa Ziehau 3131d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN1, 3141d67eefeSSepherosa Ziehau "NVIDIA MCP79 Gigabit Ethernet" }, 3151d67eefeSSepherosa Ziehau 3161d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN2, 3171d67eefeSSepherosa Ziehau "NVIDIA MCP79 Gigabit Ethernet" }, 3181d67eefeSSepherosa Ziehau 3191d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN3, 3201d67eefeSSepherosa Ziehau "NVIDIA MCP79 Gigabit Ethernet" }, 3211d67eefeSSepherosa Ziehau 3221d67eefeSSepherosa Ziehau { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_LAN4, 3231d67eefeSSepherosa Ziehau "NVIDIA MCP79 Gigabit Ethernet" }, 3241d67eefeSSepherosa Ziehau 3251d67eefeSSepherosa Ziehau { 0, 0, NULL } 326ae813fd8SSepherosa Ziehau }; 327ae813fd8SSepherosa Ziehau 328ae813fd8SSepherosa Ziehau static device_method_t nfe_methods[] = { 329ae813fd8SSepherosa Ziehau /* Device interface */ 330ae813fd8SSepherosa Ziehau DEVMETHOD(device_probe, nfe_probe), 331ae813fd8SSepherosa Ziehau DEVMETHOD(device_attach, nfe_attach), 332ae813fd8SSepherosa Ziehau DEVMETHOD(device_detach, nfe_detach), 333ae813fd8SSepherosa Ziehau DEVMETHOD(device_suspend, nfe_suspend), 334ae813fd8SSepherosa Ziehau DEVMETHOD(device_resume, nfe_resume), 335ae813fd8SSepherosa Ziehau DEVMETHOD(device_shutdown, nfe_shutdown), 336ae813fd8SSepherosa Ziehau 337ae813fd8SSepherosa Ziehau /* Bus interface */ 338ae813fd8SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 339ae813fd8SSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 340ae813fd8SSepherosa Ziehau 341ae813fd8SSepherosa Ziehau /* MII interface */ 342ae813fd8SSepherosa Ziehau DEVMETHOD(miibus_readreg, nfe_miibus_readreg), 343ae813fd8SSepherosa Ziehau DEVMETHOD(miibus_writereg, nfe_miibus_writereg), 344ae813fd8SSepherosa Ziehau DEVMETHOD(miibus_statchg, nfe_miibus_statchg), 345ae813fd8SSepherosa Ziehau 346d3c9c58eSSascha Wildner DEVMETHOD_END 347ae813fd8SSepherosa Ziehau }; 348ae813fd8SSepherosa Ziehau 349ae813fd8SSepherosa Ziehau static driver_t nfe_driver = { 350ae813fd8SSepherosa Ziehau "nfe", 351ae813fd8SSepherosa Ziehau nfe_methods, 352ae813fd8SSepherosa Ziehau sizeof(struct nfe_softc) 353ae813fd8SSepherosa Ziehau }; 354ae813fd8SSepherosa Ziehau 355ae813fd8SSepherosa Ziehau static devclass_t nfe_devclass; 356ae813fd8SSepherosa Ziehau 357ae813fd8SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_nfe); 358ae813fd8SSepherosa Ziehau MODULE_DEPEND(if_nfe, miibus, 1, 1, 1); 359aa2b9d05SSascha Wildner DRIVER_MODULE(if_nfe, pci, nfe_driver, nfe_devclass, NULL, NULL); 360aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, nfe, miibus_driver, miibus_devclass, NULL, NULL); 361ae813fd8SSepherosa Ziehau 362f81efabeSMatthew Dillon /* 363f81efabeSMatthew Dillon * NOTE: NFE_WORDALIGN support is guesswork right now. 364f81efabeSMatthew Dillon */ 365ae813fd8SSepherosa Ziehau static int 366ae813fd8SSepherosa Ziehau nfe_probe(device_t dev) 367ae813fd8SSepherosa Ziehau { 368ae813fd8SSepherosa Ziehau const struct nfe_dev *n; 369ae813fd8SSepherosa Ziehau uint16_t vid, did; 370ae813fd8SSepherosa Ziehau 371ae813fd8SSepherosa Ziehau vid = pci_get_vendor(dev); 372ae813fd8SSepherosa Ziehau did = pci_get_device(dev); 373ae813fd8SSepherosa Ziehau for (n = nfe_devices; n->desc != NULL; ++n) { 374ae813fd8SSepherosa Ziehau if (vid == n->vid && did == n->did) { 375ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 376ae813fd8SSepherosa Ziehau 377ae813fd8SSepherosa Ziehau switch (did) { 378f678f57eSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_NFORCE_LAN: 379f678f57eSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_NFORCE2_LAN: 380f678f57eSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_NFORCE3_LAN1: 381ece56005SSepherosa Ziehau sc->sc_caps = NFE_NO_PWRCTL | 382ece56005SSepherosa Ziehau NFE_FIX_EADDR; 383f678f57eSSepherosa Ziehau break; 384ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_NFORCE3_LAN2: 385ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_NFORCE3_LAN3: 386ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_NFORCE3_LAN4: 387ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_NFORCE3_LAN5: 38888d487c3SSepherosa Ziehau sc->sc_caps = NFE_JUMBO_SUP | 389f678f57eSSepherosa Ziehau NFE_HW_CSUM | 390ece56005SSepherosa Ziehau NFE_NO_PWRCTL | 391ece56005SSepherosa Ziehau NFE_FIX_EADDR; 392ae813fd8SSepherosa Ziehau break; 393ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP51_LAN1: 394ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP51_LAN2: 395ece56005SSepherosa Ziehau sc->sc_caps = NFE_FIX_EADDR; 396ece56005SSepherosa Ziehau /* FALL THROUGH */ 3979d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP61_LAN1: 3989d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP61_LAN2: 3999d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP61_LAN3: 4009d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP61_LAN4: 401df290cacSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP67_LAN1: 402df290cacSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP67_LAN2: 403df290cacSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP67_LAN3: 404df290cacSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP67_LAN4: 4051d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP73_LAN1: 4061d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP73_LAN2: 4071d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP73_LAN3: 4081d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP73_LAN4: 409ece56005SSepherosa Ziehau sc->sc_caps |= NFE_40BIT_ADDR; 410ae813fd8SSepherosa Ziehau break; 411ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_CK804_LAN1: 412ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_CK804_LAN2: 413ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP04_LAN1: 414ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP04_LAN2: 41588d487c3SSepherosa Ziehau sc->sc_caps = NFE_JUMBO_SUP | 416972538a5SSepherosa Ziehau NFE_40BIT_ADDR | 417f678f57eSSepherosa Ziehau NFE_HW_CSUM | 418ece56005SSepherosa Ziehau NFE_NO_PWRCTL | 419ece56005SSepherosa Ziehau NFE_FIX_EADDR; 420972538a5SSepherosa Ziehau break; 4219d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP65_LAN1: 4229d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP65_LAN2: 4239d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP65_LAN3: 4249d1ecb21SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP65_LAN4: 42588d487c3SSepherosa Ziehau sc->sc_caps = NFE_JUMBO_SUP | 426972538a5SSepherosa Ziehau NFE_40BIT_ADDR; 427ae813fd8SSepherosa Ziehau break; 428ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP55_LAN1: 429ae813fd8SSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP55_LAN2: 43088d487c3SSepherosa Ziehau sc->sc_caps = NFE_JUMBO_SUP | 431ae813fd8SSepherosa Ziehau NFE_40BIT_ADDR | 432ae813fd8SSepherosa Ziehau NFE_HW_CSUM | 433ece56005SSepherosa Ziehau NFE_HW_VLAN | 434ece56005SSepherosa Ziehau NFE_FIX_EADDR; 435ae813fd8SSepherosa Ziehau break; 4361d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP77_LAN1: 4371d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP77_LAN2: 4381d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP77_LAN3: 4391d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP77_LAN4: 4401d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP79_LAN1: 4411d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP79_LAN2: 4421d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP79_LAN3: 4431d67eefeSSepherosa Ziehau case PCI_PRODUCT_NVIDIA_MCP79_LAN4: 44488d487c3SSepherosa Ziehau sc->sc_caps = NFE_40BIT_ADDR | 445f81efabeSMatthew Dillon NFE_HW_CSUM | 446f81efabeSMatthew Dillon NFE_WORDALIGN; 4471d67eefeSSepherosa Ziehau break; 448ae813fd8SSepherosa Ziehau } 449ae813fd8SSepherosa Ziehau 450ae813fd8SSepherosa Ziehau device_set_desc(dev, n->desc); 451dbcd0c9bSMatthew Dillon device_set_async_attach(dev, TRUE); 452ae813fd8SSepherosa Ziehau return 0; 453ae813fd8SSepherosa Ziehau } 454ae813fd8SSepherosa Ziehau } 455ae813fd8SSepherosa Ziehau return ENXIO; 456ae813fd8SSepherosa Ziehau } 457ae813fd8SSepherosa Ziehau 458ae813fd8SSepherosa Ziehau static int 459ae813fd8SSepherosa Ziehau nfe_attach(device_t dev) 460ae813fd8SSepherosa Ziehau { 461ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 462ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 463ae813fd8SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 464244a9aa3SSepherosa Ziehau bus_addr_t lowaddr; 465ae813fd8SSepherosa Ziehau int error; 466ae813fd8SSepherosa Ziehau 467ae813fd8SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 468ae813fd8SSepherosa Ziehau lwkt_serialize_init(&sc->sc_jbuf_serializer); 469ae813fd8SSepherosa Ziehau 470ec9403d0SSepherosa Ziehau /* 471ec9403d0SSepherosa Ziehau * Initialize sysctl variables 472ec9403d0SSepherosa Ziehau */ 473ec9403d0SSepherosa Ziehau sc->sc_rx_ring_count = nfe_rx_ring_count; 474b4633098SSepherosa Ziehau sc->sc_tx_ring_count = nfe_tx_ring_count; 475ec9403d0SSepherosa Ziehau sc->sc_debug = nfe_debug; 47604b9ef8dSSepherosa Ziehau if (nfe_imtime < 0) { 47704b9ef8dSSepherosa Ziehau sc->sc_flags |= NFE_F_DYN_IM; 47804b9ef8dSSepherosa Ziehau sc->sc_imtime = -nfe_imtime; 47904b9ef8dSSepherosa Ziehau } else { 48004b9ef8dSSepherosa Ziehau sc->sc_imtime = nfe_imtime; 48104b9ef8dSSepherosa Ziehau } 48204b9ef8dSSepherosa Ziehau sc->sc_irq_enable = NFE_IRQ_ENABLE(sc); 483ec9403d0SSepherosa Ziehau 484ae813fd8SSepherosa Ziehau sc->sc_mem_rid = PCIR_BAR(0); 485ae813fd8SSepherosa Ziehau 48688d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 487faaea42eSSepherosa Ziehau sc->rxtxctl_desc = NFE_RXTX_DESC_V3; 48888d487c3SSepherosa Ziehau else if (sc->sc_caps & NFE_JUMBO_SUP) 489faaea42eSSepherosa Ziehau sc->rxtxctl_desc = NFE_RXTX_DESC_V2; 490faaea42eSSepherosa Ziehau 491ae813fd8SSepherosa Ziehau #ifndef BURN_BRIDGES 492ae813fd8SSepherosa Ziehau if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 493ae813fd8SSepherosa Ziehau uint32_t mem, irq; 494ae813fd8SSepherosa Ziehau 495ae813fd8SSepherosa Ziehau mem = pci_read_config(dev, sc->sc_mem_rid, 4); 496ae813fd8SSepherosa Ziehau irq = pci_read_config(dev, PCIR_INTLINE, 4); 497ae813fd8SSepherosa Ziehau 498ae813fd8SSepherosa Ziehau device_printf(dev, "chip is in D%d power mode " 499ae813fd8SSepherosa Ziehau "-- setting to D0\n", pci_get_powerstate(dev)); 500ae813fd8SSepherosa Ziehau 501ae813fd8SSepherosa Ziehau pci_set_powerstate(dev, PCI_POWERSTATE_D0); 502ae813fd8SSepherosa Ziehau 503ae813fd8SSepherosa Ziehau pci_write_config(dev, sc->sc_mem_rid, mem, 4); 504ae813fd8SSepherosa Ziehau pci_write_config(dev, PCIR_INTLINE, irq, 4); 505ae813fd8SSepherosa Ziehau } 506ae813fd8SSepherosa Ziehau #endif /* !BURN_BRIDGE */ 507ae813fd8SSepherosa Ziehau 508ae813fd8SSepherosa Ziehau /* Enable bus mastering */ 509ae813fd8SSepherosa Ziehau pci_enable_busmaster(dev); 510ae813fd8SSepherosa Ziehau 511ae813fd8SSepherosa Ziehau /* Allocate IO memory */ 512ae813fd8SSepherosa Ziehau sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 513ae813fd8SSepherosa Ziehau &sc->sc_mem_rid, RF_ACTIVE); 514ae813fd8SSepherosa Ziehau if (sc->sc_mem_res == NULL) { 515c6218e1eSSascha Wildner device_printf(dev, "could not allocate io memory\n"); 516ae813fd8SSepherosa Ziehau return ENXIO; 517ae813fd8SSepherosa Ziehau } 518ae813fd8SSepherosa Ziehau sc->sc_memh = rman_get_bushandle(sc->sc_mem_res); 519ae813fd8SSepherosa Ziehau sc->sc_memt = rman_get_bustag(sc->sc_mem_res); 520ae813fd8SSepherosa Ziehau 521ae813fd8SSepherosa Ziehau /* Allocate IRQ */ 522ae813fd8SSepherosa Ziehau sc->sc_irq_rid = 0; 523ae813fd8SSepherosa Ziehau sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 524ae813fd8SSepherosa Ziehau &sc->sc_irq_rid, 525ae813fd8SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE); 526ae813fd8SSepherosa Ziehau if (sc->sc_irq_res == NULL) { 527ae813fd8SSepherosa Ziehau device_printf(dev, "could not allocate irq\n"); 528ae813fd8SSepherosa Ziehau error = ENXIO; 529ae813fd8SSepherosa Ziehau goto fail; 530ae813fd8SSepherosa Ziehau } 531ae813fd8SSepherosa Ziehau 532755f8683SSepherosa Ziehau /* Disable WOL */ 533755f8683SSepherosa Ziehau NFE_WRITE(sc, NFE_WOL_CTL, 0); 534755f8683SSepherosa Ziehau 53588d487c3SSepherosa Ziehau if ((sc->sc_caps & NFE_NO_PWRCTL) == 0) 536faaea42eSSepherosa Ziehau nfe_powerup(dev); 537faaea42eSSepherosa Ziehau 538ae813fd8SSepherosa Ziehau nfe_get_macaddr(sc, eaddr); 539ae813fd8SSepherosa Ziehau 540ae813fd8SSepherosa Ziehau /* 541244a9aa3SSepherosa Ziehau * Allocate top level DMA tag 542244a9aa3SSepherosa Ziehau */ 543244a9aa3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 544244a9aa3SSepherosa Ziehau lowaddr = NFE_BUS_SPACE_MAXADDR; 545244a9aa3SSepherosa Ziehau else 546244a9aa3SSepherosa Ziehau lowaddr = BUS_SPACE_MAXADDR_32BIT; 547244a9aa3SSepherosa Ziehau error = bus_dma_tag_create(NULL, /* parent */ 548244a9aa3SSepherosa Ziehau 1, 0, /* alignment, boundary */ 549244a9aa3SSepherosa Ziehau lowaddr, /* lowaddr */ 550244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 551244a9aa3SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 552244a9aa3SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 553244a9aa3SSepherosa Ziehau 0, /* nsegments */ 554244a9aa3SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 555244a9aa3SSepherosa Ziehau 0, /* flags */ 556244a9aa3SSepherosa Ziehau &sc->sc_dtag); 557244a9aa3SSepherosa Ziehau if (error) { 558244a9aa3SSepherosa Ziehau device_printf(dev, "could not allocate parent dma tag\n"); 559244a9aa3SSepherosa Ziehau goto fail; 560244a9aa3SSepherosa Ziehau } 561244a9aa3SSepherosa Ziehau 562244a9aa3SSepherosa Ziehau /* 563ae813fd8SSepherosa Ziehau * Allocate Tx and Rx rings. 564ae813fd8SSepherosa Ziehau */ 565ae813fd8SSepherosa Ziehau error = nfe_alloc_tx_ring(sc, &sc->txq); 566ae813fd8SSepherosa Ziehau if (error) { 567ae813fd8SSepherosa Ziehau device_printf(dev, "could not allocate Tx ring\n"); 568ae813fd8SSepherosa Ziehau goto fail; 569ae813fd8SSepherosa Ziehau } 570ae813fd8SSepherosa Ziehau 571ae813fd8SSepherosa Ziehau error = nfe_alloc_rx_ring(sc, &sc->rxq); 572ae813fd8SSepherosa Ziehau if (error) { 573ae813fd8SSepherosa Ziehau device_printf(dev, "could not allocate Rx ring\n"); 574ae813fd8SSepherosa Ziehau goto fail; 575ae813fd8SSepherosa Ziehau } 576ae813fd8SSepherosa Ziehau 577ec9403d0SSepherosa Ziehau /* 578ec9403d0SSepherosa Ziehau * Create sysctl tree 579ec9403d0SSepherosa Ziehau */ 580ec9403d0SSepherosa Ziehau sysctl_ctx_init(&sc->sc_sysctl_ctx); 581ec9403d0SSepherosa Ziehau sc->sc_sysctl_tree = SYSCTL_ADD_NODE(&sc->sc_sysctl_ctx, 582ec9403d0SSepherosa Ziehau SYSCTL_STATIC_CHILDREN(_hw), 583ec9403d0SSepherosa Ziehau OID_AUTO, 584ec9403d0SSepherosa Ziehau device_get_nameunit(dev), 585ec9403d0SSepherosa Ziehau CTLFLAG_RD, 0, ""); 586ec9403d0SSepherosa Ziehau if (sc->sc_sysctl_tree == NULL) { 587ec9403d0SSepherosa Ziehau device_printf(dev, "can't add sysctl node\n"); 588ec9403d0SSepherosa Ziehau error = ENXIO; 589ec9403d0SSepherosa Ziehau goto fail; 590ec9403d0SSepherosa Ziehau } 591ec9403d0SSepherosa Ziehau SYSCTL_ADD_PROC(&sc->sc_sysctl_ctx, 592ec9403d0SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), 593ec9403d0SSepherosa Ziehau OID_AUTO, "imtimer", CTLTYPE_INT | CTLFLAG_RW, 594ec9403d0SSepherosa Ziehau sc, 0, nfe_sysctl_imtime, "I", 595ec9403d0SSepherosa Ziehau "Interrupt moderation time (usec). " 59604b9ef8dSSepherosa Ziehau "0 to disable interrupt moderation."); 59756fa71a9SSepherosa Ziehau SYSCTL_ADD_INT(&sc->sc_sysctl_ctx, 59856fa71a9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, 599ec9403d0SSepherosa Ziehau "rx_ring_count", CTLFLAG_RD, &sc->sc_rx_ring_count, 600ec9403d0SSepherosa Ziehau 0, "RX ring count"); 60156fa71a9SSepherosa Ziehau SYSCTL_ADD_INT(&sc->sc_sysctl_ctx, 60256fa71a9SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, 603b4633098SSepherosa Ziehau "tx_ring_count", CTLFLAG_RD, &sc->sc_tx_ring_count, 604b4633098SSepherosa Ziehau 0, "TX ring count"); 605b4633098SSepherosa Ziehau SYSCTL_ADD_INT(&sc->sc_sysctl_ctx, 606b4633098SSepherosa Ziehau SYSCTL_CHILDREN(sc->sc_sysctl_tree), OID_AUTO, 607ec9403d0SSepherosa Ziehau "debug", CTLFLAG_RW, &sc->sc_debug, 608ec9403d0SSepherosa Ziehau 0, "control debugging printfs"); 609ec9403d0SSepherosa Ziehau 610ae813fd8SSepherosa Ziehau error = mii_phy_probe(dev, &sc->sc_miibus, nfe_ifmedia_upd, 611ae813fd8SSepherosa Ziehau nfe_ifmedia_sts); 612ae813fd8SSepherosa Ziehau if (error) { 613ae813fd8SSepherosa Ziehau device_printf(dev, "MII without any phy\n"); 614ae813fd8SSepherosa Ziehau goto fail; 615ae813fd8SSepherosa Ziehau } 616ae813fd8SSepherosa Ziehau 617ae813fd8SSepherosa Ziehau ifp->if_softc = sc; 618ae813fd8SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 619ae813fd8SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 620ae813fd8SSepherosa Ziehau ifp->if_ioctl = nfe_ioctl; 621ae813fd8SSepherosa Ziehau ifp->if_start = nfe_start; 622d2e51f8dSSepherosa Ziehau #ifdef IFPOLL_ENABLE 623d2e51f8dSSepherosa Ziehau ifp->if_npoll = nfe_npoll; 624ae813fd8SSepherosa Ziehau #endif 625ae813fd8SSepherosa Ziehau ifp->if_watchdog = nfe_watchdog; 626ae813fd8SSepherosa Ziehau ifp->if_init = nfe_init; 627d378110eSSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, sc->sc_tx_ring_count); 628ae813fd8SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 629ae813fd8SSepherosa Ziehau 630ae813fd8SSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_MTU; 631ae813fd8SSepherosa Ziehau 63288d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_HW_VLAN) 633ae813fd8SSepherosa Ziehau ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 634ae813fd8SSepherosa Ziehau 635ae813fd8SSepherosa Ziehau #ifdef NFE_CSUM 63688d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_HW_CSUM) { 63711db6c57SSepherosa Ziehau ifp->if_capabilities |= IFCAP_HWCSUM; 63811db6c57SSepherosa Ziehau ifp->if_hwassist = NFE_CSUM_FEATURES; 639ae813fd8SSepherosa Ziehau } 64011db6c57SSepherosa Ziehau #else 64188d487c3SSepherosa Ziehau sc->sc_caps &= ~NFE_HW_CSUM; 642ae813fd8SSepherosa Ziehau #endif 643ae813fd8SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 644ae813fd8SSepherosa Ziehau 645ae813fd8SSepherosa Ziehau callout_init(&sc->sc_tick_ch); 646ae813fd8SSepherosa Ziehau 647ae813fd8SSepherosa Ziehau ether_ifattach(ifp, eaddr, NULL); 648ae813fd8SSepherosa Ziehau 649*4c77af2dSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->sc_irq_res)); 650*4c77af2dSSepherosa Ziehau 651d2e51f8dSSepherosa Ziehau #ifdef IFPOLL_ENABLE 652d2e51f8dSSepherosa Ziehau ifpoll_compat_setup(&sc->sc_npoll, 653d2e51f8dSSepherosa Ziehau &sc->sc_sysctl_ctx, sc->sc_sysctl_tree, device_get_unit(dev), 654d2e51f8dSSepherosa Ziehau ifp->if_serializer); 655d2e51f8dSSepherosa Ziehau #endif 656d2e51f8dSSepherosa Ziehau 657ae813fd8SSepherosa Ziehau error = bus_setup_intr(dev, sc->sc_irq_res, INTR_MPSAFE, nfe_intr, sc, 658ae813fd8SSepherosa Ziehau &sc->sc_ih, ifp->if_serializer); 659ae813fd8SSepherosa Ziehau if (error) { 660ae813fd8SSepherosa Ziehau device_printf(dev, "could not setup intr\n"); 661ae813fd8SSepherosa Ziehau ether_ifdetach(ifp); 662ae813fd8SSepherosa Ziehau goto fail; 663ae813fd8SSepherosa Ziehau } 664ae813fd8SSepherosa Ziehau 665ae813fd8SSepherosa Ziehau return 0; 666ae813fd8SSepherosa Ziehau fail: 667ae813fd8SSepherosa Ziehau nfe_detach(dev); 668ae813fd8SSepherosa Ziehau return error; 669ae813fd8SSepherosa Ziehau } 670ae813fd8SSepherosa Ziehau 671ae813fd8SSepherosa Ziehau static int 672ae813fd8SSepherosa Ziehau nfe_detach(device_t dev) 673ae813fd8SSepherosa Ziehau { 674ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 675ae813fd8SSepherosa Ziehau 676ae813fd8SSepherosa Ziehau if (device_is_attached(dev)) { 677ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 678ae813fd8SSepherosa Ziehau 679ae813fd8SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 680ae813fd8SSepherosa Ziehau nfe_stop(sc); 681ae813fd8SSepherosa Ziehau bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_ih); 682ae813fd8SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 683ae813fd8SSepherosa Ziehau 684ae813fd8SSepherosa Ziehau ether_ifdetach(ifp); 685ae813fd8SSepherosa Ziehau } 686ae813fd8SSepherosa Ziehau 687ae813fd8SSepherosa Ziehau if (sc->sc_miibus != NULL) 688ae813fd8SSepherosa Ziehau device_delete_child(dev, sc->sc_miibus); 689ae813fd8SSepherosa Ziehau bus_generic_detach(dev); 690ae813fd8SSepherosa Ziehau 691ec9403d0SSepherosa Ziehau if (sc->sc_sysctl_tree != NULL) 692ec9403d0SSepherosa Ziehau sysctl_ctx_free(&sc->sc_sysctl_ctx); 693ec9403d0SSepherosa Ziehau 694ae813fd8SSepherosa Ziehau if (sc->sc_irq_res != NULL) { 695ae813fd8SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, 696ae813fd8SSepherosa Ziehau sc->sc_irq_res); 697ae813fd8SSepherosa Ziehau } 698ae813fd8SSepherosa Ziehau 699ae813fd8SSepherosa Ziehau if (sc->sc_mem_res != NULL) { 700ae813fd8SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, 701ae813fd8SSepherosa Ziehau sc->sc_mem_res); 702ae813fd8SSepherosa Ziehau } 703ae813fd8SSepherosa Ziehau 704ae813fd8SSepherosa Ziehau nfe_free_tx_ring(sc, &sc->txq); 705ae813fd8SSepherosa Ziehau nfe_free_rx_ring(sc, &sc->rxq); 706244a9aa3SSepherosa Ziehau if (sc->sc_dtag != NULL) 707244a9aa3SSepherosa Ziehau bus_dma_tag_destroy(sc->sc_dtag); 708ae813fd8SSepherosa Ziehau 709ae813fd8SSepherosa Ziehau return 0; 710ae813fd8SSepherosa Ziehau } 711ae813fd8SSepherosa Ziehau 712ae813fd8SSepherosa Ziehau static void 713ae813fd8SSepherosa Ziehau nfe_shutdown(device_t dev) 714ae813fd8SSepherosa Ziehau { 715ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 716ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 717ae813fd8SSepherosa Ziehau 718ae813fd8SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 719ae813fd8SSepherosa Ziehau nfe_stop(sc); 720ae813fd8SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 721ae813fd8SSepherosa Ziehau } 722ae813fd8SSepherosa Ziehau 723ae813fd8SSepherosa Ziehau static int 724ae813fd8SSepherosa Ziehau nfe_suspend(device_t dev) 725ae813fd8SSepherosa Ziehau { 726ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 727ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 728ae813fd8SSepherosa Ziehau 729ae813fd8SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 730ae813fd8SSepherosa Ziehau nfe_stop(sc); 731ae813fd8SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 732ae813fd8SSepherosa Ziehau 733ae813fd8SSepherosa Ziehau return 0; 734ae813fd8SSepherosa Ziehau } 735ae813fd8SSepherosa Ziehau 736ae813fd8SSepherosa Ziehau static int 737ae813fd8SSepherosa Ziehau nfe_resume(device_t dev) 738ae813fd8SSepherosa Ziehau { 739ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 740ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 741ae813fd8SSepherosa Ziehau 742ae813fd8SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 743751890abSMatthew Dillon if (ifp->if_flags & IFF_UP) 7443ffca68aSSepherosa Ziehau nfe_init(sc); 745ae813fd8SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 746ae813fd8SSepherosa Ziehau 747ae813fd8SSepherosa Ziehau return 0; 748ae813fd8SSepherosa Ziehau } 749ae813fd8SSepherosa Ziehau 750ae813fd8SSepherosa Ziehau static void 751ae813fd8SSepherosa Ziehau nfe_miibus_statchg(device_t dev) 752ae813fd8SSepherosa Ziehau { 753ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 754ae813fd8SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 755ae813fd8SSepherosa Ziehau uint32_t phy, seed, misc = NFE_MISC1_MAGIC, link = NFE_MEDIA_SET; 756ae813fd8SSepherosa Ziehau 757c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(sc->arpcom.ac_if.if_serializer); 758c0dcc88eSSepherosa Ziehau 759ae813fd8SSepherosa Ziehau phy = NFE_READ(sc, NFE_PHY_IFACE); 760ae813fd8SSepherosa Ziehau phy &= ~(NFE_PHY_HDX | NFE_PHY_100TX | NFE_PHY_1000T); 761ae813fd8SSepherosa Ziehau 762ae813fd8SSepherosa Ziehau seed = NFE_READ(sc, NFE_RNDSEED); 763ae813fd8SSepherosa Ziehau seed &= ~NFE_SEED_MASK; 764ae813fd8SSepherosa Ziehau 765ae813fd8SSepherosa Ziehau if ((mii->mii_media_active & IFM_GMASK) == IFM_HDX) { 766ae813fd8SSepherosa Ziehau phy |= NFE_PHY_HDX; /* half-duplex */ 767ae813fd8SSepherosa Ziehau misc |= NFE_MISC1_HDX; 768ae813fd8SSepherosa Ziehau } 769ae813fd8SSepherosa Ziehau 770ae813fd8SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) { 771ae813fd8SSepherosa Ziehau case IFM_1000_T: /* full-duplex only */ 772ae813fd8SSepherosa Ziehau link |= NFE_MEDIA_1000T; 773ae813fd8SSepherosa Ziehau seed |= NFE_SEED_1000T; 774ae813fd8SSepherosa Ziehau phy |= NFE_PHY_1000T; 775ae813fd8SSepherosa Ziehau break; 776ae813fd8SSepherosa Ziehau case IFM_100_TX: 777ae813fd8SSepherosa Ziehau link |= NFE_MEDIA_100TX; 778ae813fd8SSepherosa Ziehau seed |= NFE_SEED_100TX; 779ae813fd8SSepherosa Ziehau phy |= NFE_PHY_100TX; 780ae813fd8SSepherosa Ziehau break; 781ae813fd8SSepherosa Ziehau case IFM_10_T: 782ae813fd8SSepherosa Ziehau link |= NFE_MEDIA_10T; 783ae813fd8SSepherosa Ziehau seed |= NFE_SEED_10T; 784ae813fd8SSepherosa Ziehau break; 785ae813fd8SSepherosa Ziehau } 786ae813fd8SSepherosa Ziehau 787ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RNDSEED, seed); /* XXX: gigabit NICs only? */ 788ae813fd8SSepherosa Ziehau 789ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_IFACE, phy); 790ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MISC1, misc); 791ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_LINKSPEED, link); 792ae813fd8SSepherosa Ziehau } 793ae813fd8SSepherosa Ziehau 794ae813fd8SSepherosa Ziehau static int 795ae813fd8SSepherosa Ziehau nfe_miibus_readreg(device_t dev, int phy, int reg) 796ae813fd8SSepherosa Ziehau { 797ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 798ae813fd8SSepherosa Ziehau uint32_t val; 799ae813fd8SSepherosa Ziehau int ntries; 800ae813fd8SSepherosa Ziehau 801ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 802ae813fd8SSepherosa Ziehau 803ae813fd8SSepherosa Ziehau if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 804ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 805ae813fd8SSepherosa Ziehau DELAY(100); 806ae813fd8SSepherosa Ziehau } 807ae813fd8SSepherosa Ziehau 808ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_CTL, (phy << NFE_PHYADD_SHIFT) | reg); 809ae813fd8SSepherosa Ziehau 810ae813fd8SSepherosa Ziehau for (ntries = 0; ntries < 1000; ntries++) { 811ae813fd8SSepherosa Ziehau DELAY(100); 812ae813fd8SSepherosa Ziehau if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 813ae813fd8SSepherosa Ziehau break; 814ae813fd8SSepherosa Ziehau } 815ae813fd8SSepherosa Ziehau if (ntries == 1000) { 816ae813fd8SSepherosa Ziehau DPRINTFN(sc, 2, "timeout waiting for PHY %s\n", ""); 817ae813fd8SSepherosa Ziehau return 0; 818ae813fd8SSepherosa Ziehau } 819ae813fd8SSepherosa Ziehau 820ae813fd8SSepherosa Ziehau if (NFE_READ(sc, NFE_PHY_STATUS) & NFE_PHY_ERROR) { 821ae813fd8SSepherosa Ziehau DPRINTFN(sc, 2, "could not read PHY %s\n", ""); 822ae813fd8SSepherosa Ziehau return 0; 823ae813fd8SSepherosa Ziehau } 824ae813fd8SSepherosa Ziehau 825ae813fd8SSepherosa Ziehau val = NFE_READ(sc, NFE_PHY_DATA); 826ae813fd8SSepherosa Ziehau if (val != 0xffffffff && val != 0) 827ae813fd8SSepherosa Ziehau sc->mii_phyaddr = phy; 828ae813fd8SSepherosa Ziehau 829ae813fd8SSepherosa Ziehau DPRINTFN(sc, 2, "mii read phy %d reg 0x%x ret 0x%x\n", phy, reg, val); 830ae813fd8SSepherosa Ziehau 831ae813fd8SSepherosa Ziehau return val; 832ae813fd8SSepherosa Ziehau } 833ae813fd8SSepherosa Ziehau 834ae813fd8SSepherosa Ziehau static void 835ae813fd8SSepherosa Ziehau nfe_miibus_writereg(device_t dev, int phy, int reg, int val) 836ae813fd8SSepherosa Ziehau { 837ae813fd8SSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 838ae813fd8SSepherosa Ziehau uint32_t ctl; 839ae813fd8SSepherosa Ziehau int ntries; 840ae813fd8SSepherosa Ziehau 841ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 842ae813fd8SSepherosa Ziehau 843ae813fd8SSepherosa Ziehau if (NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY) { 844ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_CTL, NFE_PHY_BUSY); 845ae813fd8SSepherosa Ziehau DELAY(100); 846ae813fd8SSepherosa Ziehau } 847ae813fd8SSepherosa Ziehau 848ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_DATA, val); 849ae813fd8SSepherosa Ziehau ctl = NFE_PHY_WRITE | (phy << NFE_PHYADD_SHIFT) | reg; 850ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_CTL, ctl); 851ae813fd8SSepherosa Ziehau 852ae813fd8SSepherosa Ziehau for (ntries = 0; ntries < 1000; ntries++) { 853ae813fd8SSepherosa Ziehau DELAY(100); 854ae813fd8SSepherosa Ziehau if (!(NFE_READ(sc, NFE_PHY_CTL) & NFE_PHY_BUSY)) 855ae813fd8SSepherosa Ziehau break; 856ae813fd8SSepherosa Ziehau } 857ae813fd8SSepherosa Ziehau 858ae813fd8SSepherosa Ziehau #ifdef NFE_DEBUG 859ae813fd8SSepherosa Ziehau if (ntries == 1000) 860ae813fd8SSepherosa Ziehau DPRINTFN(sc, 2, "could not write to PHY %s\n", ""); 861ae813fd8SSepherosa Ziehau #endif 862ae813fd8SSepherosa Ziehau } 863ae813fd8SSepherosa Ziehau 864d2e51f8dSSepherosa Ziehau #ifdef IFPOLL_ENABLE 865ae813fd8SSepherosa Ziehau 866ae813fd8SSepherosa Ziehau static void 867d2e51f8dSSepherosa Ziehau nfe_npoll_compat(struct ifnet *ifp, void *arg __unused, int count __unused) 868ae813fd8SSepherosa Ziehau { 869ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 870ae813fd8SSepherosa Ziehau 871ec9403d0SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 872ec9403d0SSepherosa Ziehau 873ae813fd8SSepherosa Ziehau nfe_rxeof(sc); 874d378110eSSepherosa Ziehau nfe_txeof(sc, 1); 875ae813fd8SSepherosa Ziehau } 876d2e51f8dSSepherosa Ziehau 877d2e51f8dSSepherosa Ziehau static void 878d2e51f8dSSepherosa Ziehau nfe_disable_intrs(struct nfe_softc *sc) 879d2e51f8dSSepherosa Ziehau { 880d2e51f8dSSepherosa Ziehau /* Disable interrupts */ 881d2e51f8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_MASK, 0); 882d2e51f8dSSepherosa Ziehau sc->sc_flags &= ~NFE_F_IRQ_TIMER; 883d2e51f8dSSepherosa Ziehau sc->sc_npoll.ifpc_stcount = 0; 884d2e51f8dSSepherosa Ziehau } 885d2e51f8dSSepherosa Ziehau 886d2e51f8dSSepherosa Ziehau static void 887d2e51f8dSSepherosa Ziehau nfe_npoll(struct ifnet *ifp, struct ifpoll_info *info) 888d2e51f8dSSepherosa Ziehau { 889d2e51f8dSSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 890d2e51f8dSSepherosa Ziehau 891d2e51f8dSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 892d2e51f8dSSepherosa Ziehau 893d2e51f8dSSepherosa Ziehau if (info != NULL) { 894d2e51f8dSSepherosa Ziehau int cpuid = sc->sc_npoll.ifpc_cpuid; 895d2e51f8dSSepherosa Ziehau 896d2e51f8dSSepherosa Ziehau info->ifpi_rx[cpuid].poll_func = nfe_npoll_compat; 897d2e51f8dSSepherosa Ziehau info->ifpi_rx[cpuid].arg = NULL; 898d2e51f8dSSepherosa Ziehau info->ifpi_rx[cpuid].serializer = ifp->if_serializer; 899d2e51f8dSSepherosa Ziehau 900d2e51f8dSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 901d2e51f8dSSepherosa Ziehau nfe_disable_intrs(sc); 902dfd3b18bSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, cpuid); 903d2e51f8dSSepherosa Ziehau } else { 904d2e51f8dSSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 905d2e51f8dSSepherosa Ziehau nfe_enable_intrs(sc); 906dfd3b18bSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->sc_irq_res)); 907ae813fd8SSepherosa Ziehau } 908ae813fd8SSepherosa Ziehau } 909ae813fd8SSepherosa Ziehau 910d2e51f8dSSepherosa Ziehau #endif /* IFPOLL_ENABLE */ 911ae813fd8SSepherosa Ziehau 912ae813fd8SSepherosa Ziehau static void 913ae813fd8SSepherosa Ziehau nfe_intr(void *arg) 914ae813fd8SSepherosa Ziehau { 915ae813fd8SSepherosa Ziehau struct nfe_softc *sc = arg; 916ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 917ae813fd8SSepherosa Ziehau uint32_t r; 918ae813fd8SSepherosa Ziehau 919ae813fd8SSepherosa Ziehau r = NFE_READ(sc, NFE_IRQ_STATUS); 920ae813fd8SSepherosa Ziehau if (r == 0) 921ae813fd8SSepherosa Ziehau return; /* not for us */ 922ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_STATUS, r); 923ae813fd8SSepherosa Ziehau 924c00ddf33SMatthew Dillon if (sc->sc_rate_second != time_second) { 925c00ddf33SMatthew Dillon /* 926c00ddf33SMatthew Dillon * Calculate sc_rate_avg - interrupts per second. 927c00ddf33SMatthew Dillon */ 928c00ddf33SMatthew Dillon sc->sc_rate_second = time_second; 929c00ddf33SMatthew Dillon if (sc->sc_rate_avg < sc->sc_rate_acc) 930c00ddf33SMatthew Dillon sc->sc_rate_avg = sc->sc_rate_acc; 931c00ddf33SMatthew Dillon else 932c00ddf33SMatthew Dillon sc->sc_rate_avg = (sc->sc_rate_avg * 3 + 933c00ddf33SMatthew Dillon sc->sc_rate_acc) / 4; 934c00ddf33SMatthew Dillon sc->sc_rate_acc = 0; 935c00ddf33SMatthew Dillon } else if (sc->sc_rate_avg < sc->sc_rate_acc) { 936c00ddf33SMatthew Dillon /* 937c00ddf33SMatthew Dillon * Don't wait for a tick to roll over if we are taking 938c00ddf33SMatthew Dillon * a lot of interrupts. 939c00ddf33SMatthew Dillon */ 940c00ddf33SMatthew Dillon sc->sc_rate_avg = sc->sc_rate_acc; 941c00ddf33SMatthew Dillon } 942c00ddf33SMatthew Dillon 943ae813fd8SSepherosa Ziehau DPRINTFN(sc, 5, "%s: interrupt register %x\n", __func__, r); 944ae813fd8SSepherosa Ziehau 945ae813fd8SSepherosa Ziehau if (r & NFE_IRQ_LINK) { 946ae813fd8SSepherosa Ziehau NFE_READ(sc, NFE_PHY_STATUS); 947ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 948ae813fd8SSepherosa Ziehau DPRINTF(sc, "link state changed %s\n", ""); 949ae813fd8SSepherosa Ziehau } 950ae813fd8SSepherosa Ziehau 951ae813fd8SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 95204b9ef8dSSepherosa Ziehau int ret; 953c00ddf33SMatthew Dillon int rate; 95404b9ef8dSSepherosa Ziehau 955ae813fd8SSepherosa Ziehau /* check Rx ring */ 95604b9ef8dSSepherosa Ziehau ret = nfe_rxeof(sc); 957ae813fd8SSepherosa Ziehau 958ae813fd8SSepherosa Ziehau /* check Tx ring */ 959d378110eSSepherosa Ziehau ret |= nfe_txeof(sc, 1); 96004b9ef8dSSepherosa Ziehau 961c00ddf33SMatthew Dillon /* update the rate accumulator */ 962c00ddf33SMatthew Dillon if (ret) 963c00ddf33SMatthew Dillon ++sc->sc_rate_acc; 964c00ddf33SMatthew Dillon 96504b9ef8dSSepherosa Ziehau if (sc->sc_flags & NFE_F_DYN_IM) { 966c00ddf33SMatthew Dillon rate = 1000000 / sc->sc_imtime; 967c00ddf33SMatthew Dillon if ((sc->sc_flags & NFE_F_IRQ_TIMER) == 0 && 968c00ddf33SMatthew Dillon sc->sc_rate_avg > rate) { 96904b9ef8dSSepherosa Ziehau /* 970c00ddf33SMatthew Dillon * Use the hardware timer to reduce the 971c00ddf33SMatthew Dillon * interrupt rate if the discrete interrupt 972c00ddf33SMatthew Dillon * rate has exceeded our threshold. 97304b9ef8dSSepherosa Ziehau */ 97404b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_IMTIMER); 97504b9ef8dSSepherosa Ziehau sc->sc_flags |= NFE_F_IRQ_TIMER; 976c00ddf33SMatthew Dillon } else if ((sc->sc_flags & NFE_F_IRQ_TIMER) && 977c00ddf33SMatthew Dillon sc->sc_rate_avg <= rate) { 97804b9ef8dSSepherosa Ziehau /* 979c00ddf33SMatthew Dillon * Use discrete TX/RX interrupts if the rate 980c00ddf33SMatthew Dillon * has fallen below our threshold. 98104b9ef8dSSepherosa Ziehau */ 98204b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_MASK, NFE_IRQ_NOIMTIMER); 98304b9ef8dSSepherosa Ziehau sc->sc_flags &= ~NFE_F_IRQ_TIMER; 98446d50f4bSSepherosa Ziehau 98546d50f4bSSepherosa Ziehau /* 98646d50f4bSSepherosa Ziehau * Recollect, mainly to avoid the possible race 98746d50f4bSSepherosa Ziehau * introduced by changing interrupt masks. 98846d50f4bSSepherosa Ziehau */ 98946d50f4bSSepherosa Ziehau nfe_rxeof(sc); 99046d50f4bSSepherosa Ziehau nfe_txeof(sc, 1); 99104b9ef8dSSepherosa Ziehau } 99204b9ef8dSSepherosa Ziehau } 993ae813fd8SSepherosa Ziehau } 994ae813fd8SSepherosa Ziehau } 995ae813fd8SSepherosa Ziehau 996ae813fd8SSepherosa Ziehau static int 997ae813fd8SSepherosa Ziehau nfe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 998ae813fd8SSepherosa Ziehau { 999ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 1000ae813fd8SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 1001ae813fd8SSepherosa Ziehau struct mii_data *mii; 100256fa71a9SSepherosa Ziehau int error = 0, mask, jumbo_cap; 1003ae813fd8SSepherosa Ziehau 1004c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1005c0dcc88eSSepherosa Ziehau 1006ae813fd8SSepherosa Ziehau switch (cmd) { 1007ae813fd8SSepherosa Ziehau case SIOCSIFMTU: 100856fa71a9SSepherosa Ziehau if ((sc->sc_caps & NFE_JUMBO_SUP) && sc->rxq.jbuf != NULL) 100956fa71a9SSepherosa Ziehau jumbo_cap = 1; 101056fa71a9SSepherosa Ziehau else 101156fa71a9SSepherosa Ziehau jumbo_cap = 0; 101256fa71a9SSepherosa Ziehau 101356fa71a9SSepherosa Ziehau if ((jumbo_cap && ifr->ifr_mtu > NFE_JUMBO_MTU) || 101456fa71a9SSepherosa Ziehau (!jumbo_cap && ifr->ifr_mtu > ETHERMTU)) { 1015a455c52eSSepherosa Ziehau return EINVAL; 1016a455c52eSSepherosa Ziehau } else if (ifp->if_mtu != ifr->ifr_mtu) { 1017a455c52eSSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 101856fa71a9SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1019a455c52eSSepherosa Ziehau nfe_init(sc); 1020a455c52eSSepherosa Ziehau } 1021ae813fd8SSepherosa Ziehau break; 1022ae813fd8SSepherosa Ziehau case SIOCSIFFLAGS: 1023ae813fd8SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 1024ae813fd8SSepherosa Ziehau /* 1025ae813fd8SSepherosa Ziehau * If only the PROMISC or ALLMULTI flag changes, then 1026ae813fd8SSepherosa Ziehau * don't do a full re-init of the chip, just update 1027ae813fd8SSepherosa Ziehau * the Rx filter. 1028ae813fd8SSepherosa Ziehau */ 1029ae813fd8SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) && 1030ae813fd8SSepherosa Ziehau ((ifp->if_flags ^ sc->sc_if_flags) & 1031ae813fd8SSepherosa Ziehau (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 1032ae813fd8SSepherosa Ziehau nfe_setmulti(sc); 1033ae813fd8SSepherosa Ziehau } else { 1034ae813fd8SSepherosa Ziehau if (!(ifp->if_flags & IFF_RUNNING)) 1035ae813fd8SSepherosa Ziehau nfe_init(sc); 1036ae813fd8SSepherosa Ziehau } 1037ae813fd8SSepherosa Ziehau } else { 1038ae813fd8SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1039ae813fd8SSepherosa Ziehau nfe_stop(sc); 1040ae813fd8SSepherosa Ziehau } 1041ae813fd8SSepherosa Ziehau sc->sc_if_flags = ifp->if_flags; 1042ae813fd8SSepherosa Ziehau break; 1043ae813fd8SSepherosa Ziehau case SIOCADDMULTI: 1044ae813fd8SSepherosa Ziehau case SIOCDELMULTI: 1045ae813fd8SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 1046ae813fd8SSepherosa Ziehau nfe_setmulti(sc); 1047ae813fd8SSepherosa Ziehau break; 1048ae813fd8SSepherosa Ziehau case SIOCSIFMEDIA: 1049ae813fd8SSepherosa Ziehau case SIOCGIFMEDIA: 1050ae813fd8SSepherosa Ziehau mii = device_get_softc(sc->sc_miibus); 1051ae813fd8SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 1052ae813fd8SSepherosa Ziehau break; 1053ae813fd8SSepherosa Ziehau case SIOCSIFCAP: 1054bf2a5992SSepherosa Ziehau mask = (ifr->ifr_reqcap ^ ifp->if_capenable) & IFCAP_HWCSUM; 1055bf2a5992SSepherosa Ziehau if (mask && (ifp->if_capabilities & IFCAP_HWCSUM)) { 1056bf2a5992SSepherosa Ziehau ifp->if_capenable ^= mask; 1057bf2a5992SSepherosa Ziehau if (IFCAP_TXCSUM & ifp->if_capenable) 105811db6c57SSepherosa Ziehau ifp->if_hwassist = NFE_CSUM_FEATURES; 1059bf2a5992SSepherosa Ziehau else 1060bf2a5992SSepherosa Ziehau ifp->if_hwassist = 0; 106111db6c57SSepherosa Ziehau 106211db6c57SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 106311db6c57SSepherosa Ziehau nfe_init(sc); 1064ae813fd8SSepherosa Ziehau } 1065ae813fd8SSepherosa Ziehau break; 1066ae813fd8SSepherosa Ziehau default: 1067ae813fd8SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data); 1068ae813fd8SSepherosa Ziehau break; 1069ae813fd8SSepherosa Ziehau } 1070ae813fd8SSepherosa Ziehau return error; 1071ae813fd8SSepherosa Ziehau } 1072ae813fd8SSepherosa Ziehau 107304b9ef8dSSepherosa Ziehau static int 1074ae813fd8SSepherosa Ziehau nfe_rxeof(struct nfe_softc *sc) 1075ae813fd8SSepherosa Ziehau { 1076ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1077ae813fd8SSepherosa Ziehau struct nfe_rx_ring *ring = &sc->rxq; 1078ae813fd8SSepherosa Ziehau int reap; 1079ae813fd8SSepherosa Ziehau 1080ae813fd8SSepherosa Ziehau reap = 0; 1081ae813fd8SSepherosa Ziehau for (;;) { 1082ae813fd8SSepherosa Ziehau struct nfe_rx_data *data = &ring->data[ring->cur]; 1083ae813fd8SSepherosa Ziehau struct mbuf *m; 1084ae813fd8SSepherosa Ziehau uint16_t flags; 1085ae813fd8SSepherosa Ziehau int len, error; 1086ae813fd8SSepherosa Ziehau 108788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1088ae813fd8SSepherosa Ziehau struct nfe_desc64 *desc64 = &ring->desc64[ring->cur]; 1089ae813fd8SSepherosa Ziehau 1090ae813fd8SSepherosa Ziehau flags = le16toh(desc64->flags); 1091ae813fd8SSepherosa Ziehau len = le16toh(desc64->length) & 0x3fff; 1092ae813fd8SSepherosa Ziehau } else { 1093ae813fd8SSepherosa Ziehau struct nfe_desc32 *desc32 = &ring->desc32[ring->cur]; 1094ae813fd8SSepherosa Ziehau 1095ae813fd8SSepherosa Ziehau flags = le16toh(desc32->flags); 1096ae813fd8SSepherosa Ziehau len = le16toh(desc32->length) & 0x3fff; 1097ae813fd8SSepherosa Ziehau } 1098ae813fd8SSepherosa Ziehau 1099ae813fd8SSepherosa Ziehau if (flags & NFE_RX_READY) 1100ae813fd8SSepherosa Ziehau break; 1101ae813fd8SSepherosa Ziehau 1102ae813fd8SSepherosa Ziehau reap = 1; 1103ae813fd8SSepherosa Ziehau 110488d487c3SSepherosa Ziehau if ((sc->sc_caps & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1105ae813fd8SSepherosa Ziehau if (!(flags & NFE_RX_VALID_V1)) 1106ae813fd8SSepherosa Ziehau goto skip; 1107ae813fd8SSepherosa Ziehau 1108ae813fd8SSepherosa Ziehau if ((flags & NFE_RX_FIXME_V1) == NFE_RX_FIXME_V1) { 1109ae813fd8SSepherosa Ziehau flags &= ~NFE_RX_ERROR; 1110ae813fd8SSepherosa Ziehau len--; /* fix buffer length */ 1111ae813fd8SSepherosa Ziehau } 1112ae813fd8SSepherosa Ziehau } else { 1113ae813fd8SSepherosa Ziehau if (!(flags & NFE_RX_VALID_V2)) 1114ae813fd8SSepherosa Ziehau goto skip; 1115ae813fd8SSepherosa Ziehau 1116ae813fd8SSepherosa Ziehau if ((flags & NFE_RX_FIXME_V2) == NFE_RX_FIXME_V2) { 1117ae813fd8SSepherosa Ziehau flags &= ~NFE_RX_ERROR; 1118ae813fd8SSepherosa Ziehau len--; /* fix buffer length */ 1119ae813fd8SSepherosa Ziehau } 1120ae813fd8SSepherosa Ziehau } 1121ae813fd8SSepherosa Ziehau 1122ae813fd8SSepherosa Ziehau if (flags & NFE_RX_ERROR) { 1123d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 1124ae813fd8SSepherosa Ziehau goto skip; 1125ae813fd8SSepherosa Ziehau } 1126ae813fd8SSepherosa Ziehau 1127ae813fd8SSepherosa Ziehau m = data->m; 1128ae813fd8SSepherosa Ziehau 11295dc1e30eSSepherosa Ziehau if (sc->sc_flags & NFE_F_USE_JUMBO) 1130ae813fd8SSepherosa Ziehau error = nfe_newbuf_jumbo(sc, ring, ring->cur, 0); 1131ae813fd8SSepherosa Ziehau else 1132ae813fd8SSepherosa Ziehau error = nfe_newbuf_std(sc, ring, ring->cur, 0); 1133ae813fd8SSepherosa Ziehau if (error) { 1134d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1); 1135ae813fd8SSepherosa Ziehau goto skip; 1136ae813fd8SSepherosa Ziehau } 1137ae813fd8SSepherosa Ziehau 1138ae813fd8SSepherosa Ziehau /* finalize mbuf */ 1139ae813fd8SSepherosa Ziehau m->m_pkthdr.len = m->m_len = len; 1140ae813fd8SSepherosa Ziehau m->m_pkthdr.rcvif = ifp; 1141ae813fd8SSepherosa Ziehau 1142bf2a5992SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_RXCSUM) && 114311db6c57SSepherosa Ziehau (flags & NFE_RX_CSUMOK)) { 11448b712a27SSepherosa Ziehau if (flags & NFE_RX_IP_CSUMOK_V2) { 11458b712a27SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | 11468b712a27SSepherosa Ziehau CSUM_IP_VALID; 11478b712a27SSepherosa Ziehau } 114811db6c57SSepherosa Ziehau 114911db6c57SSepherosa Ziehau if (flags & 115011db6c57SSepherosa Ziehau (NFE_RX_UDP_CSUMOK_V2 | NFE_RX_TCP_CSUMOK_V2)) { 115111db6c57SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | 1152fbb35ef0SSepherosa Ziehau CSUM_PSEUDO_HDR | 1153fbb35ef0SSepherosa Ziehau CSUM_FRAG_NOT_CHECKED; 115411db6c57SSepherosa Ziehau m->m_pkthdr.csum_data = 0xffff; 1155ae813fd8SSepherosa Ziehau } 115611db6c57SSepherosa Ziehau } 1157ae813fd8SSepherosa Ziehau 1158d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1); 1159eda7db08SSepherosa Ziehau ifp->if_input(ifp, m); 1160ae813fd8SSepherosa Ziehau skip: 1161ae813fd8SSepherosa Ziehau nfe_set_ready_rxdesc(sc, ring, ring->cur); 1162ec9403d0SSepherosa Ziehau sc->rxq.cur = (sc->rxq.cur + 1) % sc->sc_rx_ring_count; 1163ae813fd8SSepherosa Ziehau } 116404b9ef8dSSepherosa Ziehau return reap; 1165ae813fd8SSepherosa Ziehau } 1166ae813fd8SSepherosa Ziehau 116704b9ef8dSSepherosa Ziehau static int 1168d378110eSSepherosa Ziehau nfe_txeof(struct nfe_softc *sc, int start) 1169ae813fd8SSepherosa Ziehau { 1170ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1171ae813fd8SSepherosa Ziehau struct nfe_tx_ring *ring = &sc->txq; 1172ae813fd8SSepherosa Ziehau struct nfe_tx_data *data = NULL; 1173ae813fd8SSepherosa Ziehau 1174ae813fd8SSepherosa Ziehau while (ring->next != ring->cur) { 1175ae813fd8SSepherosa Ziehau uint16_t flags; 1176ae813fd8SSepherosa Ziehau 117788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 1178ae813fd8SSepherosa Ziehau flags = le16toh(ring->desc64[ring->next].flags); 1179ae813fd8SSepherosa Ziehau else 1180ae813fd8SSepherosa Ziehau flags = le16toh(ring->desc32[ring->next].flags); 1181ae813fd8SSepherosa Ziehau 1182ae813fd8SSepherosa Ziehau if (flags & NFE_TX_VALID) 1183ae813fd8SSepherosa Ziehau break; 1184ae813fd8SSepherosa Ziehau 1185ae813fd8SSepherosa Ziehau data = &ring->data[ring->next]; 1186ae813fd8SSepherosa Ziehau 118788d487c3SSepherosa Ziehau if ((sc->sc_caps & (NFE_JUMBO_SUP | NFE_40BIT_ADDR)) == 0) { 1188ae813fd8SSepherosa Ziehau if (!(flags & NFE_TX_LASTFRAG_V1) && data->m == NULL) 1189ae813fd8SSepherosa Ziehau goto skip; 1190ae813fd8SSepherosa Ziehau 1191ae813fd8SSepherosa Ziehau if ((flags & NFE_TX_ERROR_V1) != 0) { 1192ae813fd8SSepherosa Ziehau if_printf(ifp, "tx v1 error 0x%4b\n", flags, 1193ae813fd8SSepherosa Ziehau NFE_V1_TXERR); 1194d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1195ae813fd8SSepherosa Ziehau } else { 1196d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 1197ae813fd8SSepherosa Ziehau } 1198ae813fd8SSepherosa Ziehau } else { 1199ae813fd8SSepherosa Ziehau if (!(flags & NFE_TX_LASTFRAG_V2) && data->m == NULL) 1200ae813fd8SSepherosa Ziehau goto skip; 1201ae813fd8SSepherosa Ziehau 1202ae813fd8SSepherosa Ziehau if ((flags & NFE_TX_ERROR_V2) != 0) { 1203ae813fd8SSepherosa Ziehau if_printf(ifp, "tx v2 error 0x%4b\n", flags, 1204ae813fd8SSepherosa Ziehau NFE_V2_TXERR); 1205d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1206ae813fd8SSepherosa Ziehau } else { 1207d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 1208ae813fd8SSepherosa Ziehau } 1209ae813fd8SSepherosa Ziehau } 1210ae813fd8SSepherosa Ziehau 1211ae813fd8SSepherosa Ziehau if (data->m == NULL) { /* should not get there */ 1212ae813fd8SSepherosa Ziehau if_printf(ifp, 1213ae813fd8SSepherosa Ziehau "last fragment bit w/o associated mbuf!\n"); 1214ae813fd8SSepherosa Ziehau goto skip; 1215ae813fd8SSepherosa Ziehau } 1216ae813fd8SSepherosa Ziehau 1217ae813fd8SSepherosa Ziehau /* last fragment of the mbuf chain transmitted */ 1218ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 1219ae813fd8SSepherosa Ziehau m_freem(data->m); 1220ae813fd8SSepherosa Ziehau data->m = NULL; 1221ae813fd8SSepherosa Ziehau skip: 1222ae813fd8SSepherosa Ziehau ring->queued--; 1223ae813fd8SSepherosa Ziehau KKASSERT(ring->queued >= 0); 1224b4633098SSepherosa Ziehau ring->next = (ring->next + 1) % sc->sc_tx_ring_count; 1225ae813fd8SSepherosa Ziehau } 1226ae813fd8SSepherosa Ziehau 1227d378110eSSepherosa Ziehau if (sc->sc_tx_ring_count - ring->queued >= 1228d378110eSSepherosa Ziehau sc->sc_tx_spare + NFE_NSEG_RSVD) 12299ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 1230d378110eSSepherosa Ziehau 1231d378110eSSepherosa Ziehau if (ring->queued == 0) 1232d378110eSSepherosa Ziehau ifp->if_timer = 0; 1233d378110eSSepherosa Ziehau 1234d378110eSSepherosa Ziehau if (start && !ifq_is_empty(&ifp->if_snd)) 12359db4b353SSepherosa Ziehau if_devstart(ifp); 1236d378110eSSepherosa Ziehau 1237d378110eSSepherosa Ziehau if (data != NULL) 123804b9ef8dSSepherosa Ziehau return 1; 1239d378110eSSepherosa Ziehau else 124004b9ef8dSSepherosa Ziehau return 0; 1241ae813fd8SSepherosa Ziehau } 1242ae813fd8SSepherosa Ziehau 1243ae813fd8SSepherosa Ziehau static int 1244ae813fd8SSepherosa Ziehau nfe_encap(struct nfe_softc *sc, struct nfe_tx_ring *ring, struct mbuf *m0) 1245ae813fd8SSepherosa Ziehau { 1246ae813fd8SSepherosa Ziehau bus_dma_segment_t segs[NFE_MAX_SCATTER]; 1247ae813fd8SSepherosa Ziehau struct nfe_tx_data *data, *data_map; 1248ae813fd8SSepherosa Ziehau bus_dmamap_t map; 1249ae813fd8SSepherosa Ziehau struct nfe_desc64 *desc64 = NULL; 1250ae813fd8SSepherosa Ziehau struct nfe_desc32 *desc32 = NULL; 1251ae813fd8SSepherosa Ziehau uint16_t flags = 0; 1252ae813fd8SSepherosa Ziehau uint32_t vtag = 0; 1253b6bb439dSSepherosa Ziehau int error, i, j, maxsegs, nsegs; 1254ae813fd8SSepherosa Ziehau 1255ae813fd8SSepherosa Ziehau data = &ring->data[ring->cur]; 1256ae813fd8SSepherosa Ziehau map = data->map; 1257ae813fd8SSepherosa Ziehau data_map = data; /* Remember who owns the DMA map */ 1258ae813fd8SSepherosa Ziehau 1259d378110eSSepherosa Ziehau maxsegs = (sc->sc_tx_ring_count - ring->queued) - NFE_NSEG_RSVD; 1260d378110eSSepherosa Ziehau if (maxsegs > NFE_MAX_SCATTER) 1261d378110eSSepherosa Ziehau maxsegs = NFE_MAX_SCATTER; 1262d378110eSSepherosa Ziehau KASSERT(maxsegs >= sc->sc_tx_spare, 1263ed20d0e3SSascha Wildner ("not enough segments %d,%d", maxsegs, sc->sc_tx_spare)); 1264d378110eSSepherosa Ziehau 1265b6bb439dSSepherosa Ziehau error = bus_dmamap_load_mbuf_defrag(ring->data_tag, map, &m0, 1266b6bb439dSSepherosa Ziehau segs, maxsegs, &nsegs, BUS_DMA_NOWAIT); 1267b6bb439dSSepherosa Ziehau if (error) 1268ae813fd8SSepherosa Ziehau goto back; 1269e679c149SSepherosa Ziehau bus_dmamap_sync(ring->data_tag, map, BUS_DMASYNC_PREWRITE); 1270ae813fd8SSepherosa Ziehau 1271ae813fd8SSepherosa Ziehau error = 0; 1272ae813fd8SSepherosa Ziehau 1273ae813fd8SSepherosa Ziehau /* setup h/w VLAN tagging */ 127483790f85SSepherosa Ziehau if (m0->m_flags & M_VLANTAG) 127583790f85SSepherosa Ziehau vtag = m0->m_pkthdr.ether_vlantag; 1276ae813fd8SSepherosa Ziehau 1277bf2a5992SSepherosa Ziehau if (sc->arpcom.ac_if.if_capenable & IFCAP_TXCSUM) { 127811db6c57SSepherosa Ziehau if (m0->m_pkthdr.csum_flags & CSUM_IP) 1279ae813fd8SSepherosa Ziehau flags |= NFE_TX_IP_CSUM; 128011db6c57SSepherosa Ziehau if (m0->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) 1281ae813fd8SSepherosa Ziehau flags |= NFE_TX_TCP_CSUM; 128211db6c57SSepherosa Ziehau } 1283ae813fd8SSepherosa Ziehau 1284ae813fd8SSepherosa Ziehau /* 1285ae813fd8SSepherosa Ziehau * XXX urm. somebody is unaware of how hardware works. You 1286ae813fd8SSepherosa Ziehau * absolutely CANNOT set NFE_TX_VALID on the next descriptor in 1287ae813fd8SSepherosa Ziehau * the ring until the entire chain is actually *VALID*. Otherwise 1288ae813fd8SSepherosa Ziehau * the hardware may encounter a partially initialized chain that 1289ae813fd8SSepherosa Ziehau * is marked as being ready to go when it in fact is not ready to 1290ae813fd8SSepherosa Ziehau * go. 1291ae813fd8SSepherosa Ziehau */ 1292ae813fd8SSepherosa Ziehau 1293b6bb439dSSepherosa Ziehau for (i = 0; i < nsegs; i++) { 1294b4633098SSepherosa Ziehau j = (ring->cur + i) % sc->sc_tx_ring_count; 1295ae813fd8SSepherosa Ziehau data = &ring->data[j]; 1296ae813fd8SSepherosa Ziehau 129788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1298ae813fd8SSepherosa Ziehau desc64 = &ring->desc64[j]; 1299ae813fd8SSepherosa Ziehau desc64->physaddr[0] = 13007752918dSSepherosa Ziehau htole32(NFE_ADDR_HI(segs[i].ds_addr)); 1301ae813fd8SSepherosa Ziehau desc64->physaddr[1] = 13027752918dSSepherosa Ziehau htole32(NFE_ADDR_LO(segs[i].ds_addr)); 1303ae813fd8SSepherosa Ziehau desc64->length = htole16(segs[i].ds_len - 1); 1304ae813fd8SSepherosa Ziehau desc64->vtag = htole32(vtag); 1305ae813fd8SSepherosa Ziehau desc64->flags = htole16(flags); 1306ae813fd8SSepherosa Ziehau } else { 1307ae813fd8SSepherosa Ziehau desc32 = &ring->desc32[j]; 1308ae813fd8SSepherosa Ziehau desc32->physaddr = htole32(segs[i].ds_addr); 1309ae813fd8SSepherosa Ziehau desc32->length = htole16(segs[i].ds_len - 1); 1310ae813fd8SSepherosa Ziehau desc32->flags = htole16(flags); 1311ae813fd8SSepherosa Ziehau } 1312ae813fd8SSepherosa Ziehau 1313ae813fd8SSepherosa Ziehau /* csum flags and vtag belong to the first fragment only */ 1314ae813fd8SSepherosa Ziehau flags &= ~(NFE_TX_IP_CSUM | NFE_TX_TCP_CSUM); 1315ae813fd8SSepherosa Ziehau vtag = 0; 1316ae813fd8SSepherosa Ziehau 1317ae813fd8SSepherosa Ziehau ring->queued++; 1318b4633098SSepherosa Ziehau KKASSERT(ring->queued <= sc->sc_tx_ring_count); 1319ae813fd8SSepherosa Ziehau } 1320ae813fd8SSepherosa Ziehau 1321ae813fd8SSepherosa Ziehau /* the whole mbuf chain has been DMA mapped, fix last descriptor */ 132288d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1323ae813fd8SSepherosa Ziehau desc64->flags |= htole16(NFE_TX_LASTFRAG_V2); 1324ae813fd8SSepherosa Ziehau } else { 132588d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_JUMBO_SUP) 1326ae813fd8SSepherosa Ziehau flags = NFE_TX_LASTFRAG_V2; 1327ae813fd8SSepherosa Ziehau else 1328ae813fd8SSepherosa Ziehau flags = NFE_TX_LASTFRAG_V1; 1329ae813fd8SSepherosa Ziehau desc32->flags |= htole16(flags); 1330ae813fd8SSepherosa Ziehau } 1331ae813fd8SSepherosa Ziehau 1332ae813fd8SSepherosa Ziehau /* 1333ae813fd8SSepherosa Ziehau * Set NFE_TX_VALID backwards so the hardware doesn't see the 1334ae813fd8SSepherosa Ziehau * whole mess until the first descriptor in the map is flagged. 1335ae813fd8SSepherosa Ziehau */ 1336b6bb439dSSepherosa Ziehau for (i = nsegs - 1; i >= 0; --i) { 1337b4633098SSepherosa Ziehau j = (ring->cur + i) % sc->sc_tx_ring_count; 133888d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1339ae813fd8SSepherosa Ziehau desc64 = &ring->desc64[j]; 1340ae813fd8SSepherosa Ziehau desc64->flags |= htole16(NFE_TX_VALID); 1341ae813fd8SSepherosa Ziehau } else { 1342ae813fd8SSepherosa Ziehau desc32 = &ring->desc32[j]; 1343ae813fd8SSepherosa Ziehau desc32->flags |= htole16(NFE_TX_VALID); 1344ae813fd8SSepherosa Ziehau } 1345ae813fd8SSepherosa Ziehau } 1346b6bb439dSSepherosa Ziehau ring->cur = (ring->cur + nsegs) % sc->sc_tx_ring_count; 1347ae813fd8SSepherosa Ziehau 1348ae813fd8SSepherosa Ziehau /* Exchange DMA map */ 1349ae813fd8SSepherosa Ziehau data_map->map = data->map; 1350ae813fd8SSepherosa Ziehau data->map = map; 1351ae813fd8SSepherosa Ziehau data->m = m0; 1352ae813fd8SSepherosa Ziehau back: 1353ae813fd8SSepherosa Ziehau if (error) 1354ae813fd8SSepherosa Ziehau m_freem(m0); 1355ae813fd8SSepherosa Ziehau return error; 1356ae813fd8SSepherosa Ziehau } 1357ae813fd8SSepherosa Ziehau 1358ae813fd8SSepherosa Ziehau static void 1359f0a26983SSepherosa Ziehau nfe_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 1360ae813fd8SSepherosa Ziehau { 1361ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 1362ae813fd8SSepherosa Ziehau struct nfe_tx_ring *ring = &sc->txq; 1363d378110eSSepherosa Ziehau int count = 0, oactive = 0; 1364ae813fd8SSepherosa Ziehau struct mbuf *m0; 1365ae813fd8SSepherosa Ziehau 1366f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 1367c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1368c0dcc88eSSepherosa Ziehau 13699ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) 1370ae813fd8SSepherosa Ziehau return; 1371ae813fd8SSepherosa Ziehau 1372ae813fd8SSepherosa Ziehau for (;;) { 1373d378110eSSepherosa Ziehau int error; 1374d378110eSSepherosa Ziehau 1375d378110eSSepherosa Ziehau if (sc->sc_tx_ring_count - ring->queued < 1376d378110eSSepherosa Ziehau sc->sc_tx_spare + NFE_NSEG_RSVD) { 1377d378110eSSepherosa Ziehau if (oactive) { 13789ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1379d378110eSSepherosa Ziehau break; 1380d378110eSSepherosa Ziehau } 1381d378110eSSepherosa Ziehau 1382d378110eSSepherosa Ziehau nfe_txeof(sc, 0); 1383d378110eSSepherosa Ziehau oactive = 1; 1384d378110eSSepherosa Ziehau continue; 1385d378110eSSepherosa Ziehau } 1386d378110eSSepherosa Ziehau 1387ae813fd8SSepherosa Ziehau m0 = ifq_dequeue(&ifp->if_snd, NULL); 1388ae813fd8SSepherosa Ziehau if (m0 == NULL) 1389ae813fd8SSepherosa Ziehau break; 1390ae813fd8SSepherosa Ziehau 1391b637f170SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m0); 1392ae813fd8SSepherosa Ziehau 1393d378110eSSepherosa Ziehau error = nfe_encap(sc, ring, m0); 1394d378110eSSepherosa Ziehau if (error) { 1395d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1396d378110eSSepherosa Ziehau if (error == EFBIG) { 1397d378110eSSepherosa Ziehau if (oactive) { 13989ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1399ae813fd8SSepherosa Ziehau break; 1400ae813fd8SSepherosa Ziehau } 1401d378110eSSepherosa Ziehau nfe_txeof(sc, 0); 1402d378110eSSepherosa Ziehau oactive = 1; 1403d378110eSSepherosa Ziehau } 1404d378110eSSepherosa Ziehau continue; 1405d378110eSSepherosa Ziehau } else { 1406d378110eSSepherosa Ziehau oactive = 0; 1407d378110eSSepherosa Ziehau } 1408ae813fd8SSepherosa Ziehau ++count; 1409ae813fd8SSepherosa Ziehau 1410ae813fd8SSepherosa Ziehau /* 1411ae813fd8SSepherosa Ziehau * NOTE: 1412ae813fd8SSepherosa Ziehau * `m0' may be freed in nfe_encap(), so 1413ae813fd8SSepherosa Ziehau * it should not be touched any more. 1414ae813fd8SSepherosa Ziehau */ 1415ae813fd8SSepherosa Ziehau } 14168ed6a3afSSepherosa Ziehau 1417ae813fd8SSepherosa Ziehau if (count == 0) /* nothing sent */ 1418ae813fd8SSepherosa Ziehau return; 1419ae813fd8SSepherosa Ziehau 1420ae813fd8SSepherosa Ziehau /* Kick Tx */ 1421ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1422ae813fd8SSepherosa Ziehau 1423ae813fd8SSepherosa Ziehau /* 1424ae813fd8SSepherosa Ziehau * Set a timeout in case the chip goes out to lunch. 1425ae813fd8SSepherosa Ziehau */ 1426ae813fd8SSepherosa Ziehau ifp->if_timer = 5; 1427ae813fd8SSepherosa Ziehau } 1428ae813fd8SSepherosa Ziehau 1429ae813fd8SSepherosa Ziehau static void 1430ae813fd8SSepherosa Ziehau nfe_watchdog(struct ifnet *ifp) 1431ae813fd8SSepherosa Ziehau { 1432ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 1433ae813fd8SSepherosa Ziehau 1434c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1435c0dcc88eSSepherosa Ziehau 1436ae813fd8SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 1437ae813fd8SSepherosa Ziehau if_printf(ifp, "watchdog timeout - lost interrupt recovered\n"); 1438d378110eSSepherosa Ziehau nfe_txeof(sc, 1); 1439ae813fd8SSepherosa Ziehau return; 1440ae813fd8SSepherosa Ziehau } 1441ae813fd8SSepherosa Ziehau 1442ae813fd8SSepherosa Ziehau if_printf(ifp, "watchdog timeout\n"); 1443ae813fd8SSepherosa Ziehau 1444ae813fd8SSepherosa Ziehau nfe_init(ifp->if_softc); 1445ae813fd8SSepherosa Ziehau 1446d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 1447ae813fd8SSepherosa Ziehau } 1448ae813fd8SSepherosa Ziehau 1449ae813fd8SSepherosa Ziehau static void 1450ae813fd8SSepherosa Ziehau nfe_init(void *xsc) 1451ae813fd8SSepherosa Ziehau { 1452ae813fd8SSepherosa Ziehau struct nfe_softc *sc = xsc; 1453ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1454ae813fd8SSepherosa Ziehau uint32_t tmp; 1455ae813fd8SSepherosa Ziehau int error; 1456ae813fd8SSepherosa Ziehau 1457c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1458c0dcc88eSSepherosa Ziehau 1459ae813fd8SSepherosa Ziehau nfe_stop(sc); 1460ae813fd8SSepherosa Ziehau 146188d487c3SSepherosa Ziehau if ((sc->sc_caps & NFE_NO_PWRCTL) == 0) 1462faaea42eSSepherosa Ziehau nfe_mac_reset(sc); 1463faaea42eSSepherosa Ziehau 1464a455c52eSSepherosa Ziehau /* 1465a455c52eSSepherosa Ziehau * NOTE: 1466a455c52eSSepherosa Ziehau * Switching between jumbo frames and normal frames should 1467a455c52eSSepherosa Ziehau * be done _after_ nfe_stop() but _before_ nfe_init_rx_ring(). 1468a455c52eSSepherosa Ziehau */ 1469a455c52eSSepherosa Ziehau if (ifp->if_mtu > ETHERMTU) { 14705dc1e30eSSepherosa Ziehau sc->sc_flags |= NFE_F_USE_JUMBO; 1471a455c52eSSepherosa Ziehau sc->rxq.bufsz = NFE_JBYTES; 1472d378110eSSepherosa Ziehau sc->sc_tx_spare = NFE_NSEG_SPARE_JUMBO; 1473a455c52eSSepherosa Ziehau if (bootverbose) 1474a455c52eSSepherosa Ziehau if_printf(ifp, "use jumbo frames\n"); 1475a455c52eSSepherosa Ziehau } else { 14765dc1e30eSSepherosa Ziehau sc->sc_flags &= ~NFE_F_USE_JUMBO; 1477a455c52eSSepherosa Ziehau sc->rxq.bufsz = MCLBYTES; 1478d378110eSSepherosa Ziehau sc->sc_tx_spare = NFE_NSEG_SPARE; 1479a455c52eSSepherosa Ziehau if (bootverbose) 1480a455c52eSSepherosa Ziehau if_printf(ifp, "use non-jumbo frames\n"); 1481a455c52eSSepherosa Ziehau } 1482a455c52eSSepherosa Ziehau 1483ae813fd8SSepherosa Ziehau error = nfe_init_tx_ring(sc, &sc->txq); 1484ae813fd8SSepherosa Ziehau if (error) { 1485ae813fd8SSepherosa Ziehau nfe_stop(sc); 1486ae813fd8SSepherosa Ziehau return; 1487ae813fd8SSepherosa Ziehau } 1488ae813fd8SSepherosa Ziehau 1489ae813fd8SSepherosa Ziehau error = nfe_init_rx_ring(sc, &sc->rxq); 1490ae813fd8SSepherosa Ziehau if (error) { 1491ae813fd8SSepherosa Ziehau nfe_stop(sc); 1492ae813fd8SSepherosa Ziehau return; 1493ae813fd8SSepherosa Ziehau } 1494ae813fd8SSepherosa Ziehau 1495fd9c8397SSepherosa Ziehau NFE_WRITE(sc, NFE_TX_POLL, 0); 1496ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_STATUS, 0); 1497ae813fd8SSepherosa Ziehau 1498faaea42eSSepherosa Ziehau sc->rxtxctl = NFE_RXTX_BIT2 | sc->rxtxctl_desc; 149911db6c57SSepherosa Ziehau 1500bf2a5992SSepherosa Ziehau if (ifp->if_capenable & IFCAP_RXCSUM) 1501ae813fd8SSepherosa Ziehau sc->rxtxctl |= NFE_RXTX_RXCSUM; 1502ae813fd8SSepherosa Ziehau 1503ae813fd8SSepherosa Ziehau /* 1504ae813fd8SSepherosa Ziehau * Although the adapter is capable of stripping VLAN tags from received 1505ae813fd8SSepherosa Ziehau * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1506ae813fd8SSepherosa Ziehau * purpose. This will be done in software by our network stack. 1507ae813fd8SSepherosa Ziehau */ 150888d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_HW_VLAN) 1509ae813fd8SSepherosa Ziehau sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1510ae813fd8SSepherosa Ziehau 1511ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1512ae813fd8SSepherosa Ziehau DELAY(10); 1513ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1514ae813fd8SSepherosa Ziehau 151588d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_HW_VLAN) 1516ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1517ae813fd8SSepherosa Ziehau 1518ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R6, 0); 1519ae813fd8SSepherosa Ziehau 1520ae813fd8SSepherosa Ziehau /* set MAC address */ 1521ae813fd8SSepherosa Ziehau nfe_set_macaddr(sc, sc->arpcom.ac_enaddr); 1522ae813fd8SSepherosa Ziehau 1523ae813fd8SSepherosa Ziehau /* tell MAC where rings are in memory */ 15247752918dSSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 15257752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 15267752918dSSepherosa Ziehau NFE_ADDR_HI(sc->rxq.physaddr)); 15277752918dSSepherosa Ziehau } 15287752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, NFE_ADDR_LO(sc->rxq.physaddr)); 15297752918dSSepherosa Ziehau 15307752918dSSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 15317752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, 15327752918dSSepherosa Ziehau NFE_ADDR_HI(sc->txq.physaddr)); 15337752918dSSepherosa Ziehau } 15347752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 1535ae813fd8SSepherosa Ziehau 1536ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RING_SIZE, 1537ec9403d0SSepherosa Ziehau (sc->sc_rx_ring_count - 1) << 16 | 1538b4633098SSepherosa Ziehau (sc->sc_tx_ring_count - 1)); 1539ae813fd8SSepherosa Ziehau 1540ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1541ae813fd8SSepherosa Ziehau 1542ae813fd8SSepherosa Ziehau /* force MAC to wakeup */ 1543ae813fd8SSepherosa Ziehau tmp = NFE_READ(sc, NFE_PWR_STATE); 1544ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1545ae813fd8SSepherosa Ziehau DELAY(10); 1546ae813fd8SSepherosa Ziehau tmp = NFE_READ(sc, NFE_PWR_STATE); 1547ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1548ae813fd8SSepherosa Ziehau 1549ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1550ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1551ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1552ae813fd8SSepherosa Ziehau 1553ae813fd8SSepherosa Ziehau /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1554ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1555ae813fd8SSepherosa Ziehau 1556ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1557ae813fd8SSepherosa Ziehau 1558ae813fd8SSepherosa Ziehau sc->rxtxctl &= ~NFE_RXTX_BIT2; 1559ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1560ae813fd8SSepherosa Ziehau DELAY(10); 1561ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1562ae813fd8SSepherosa Ziehau 1563ae813fd8SSepherosa Ziehau /* set Rx filter */ 1564ae813fd8SSepherosa Ziehau nfe_setmulti(sc); 1565ae813fd8SSepherosa Ziehau 1566ae813fd8SSepherosa Ziehau nfe_ifmedia_upd(ifp); 1567ae813fd8SSepherosa Ziehau 1568ae813fd8SSepherosa Ziehau /* enable Rx */ 1569ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1570ae813fd8SSepherosa Ziehau 1571ae813fd8SSepherosa Ziehau /* enable Tx */ 1572ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1573ae813fd8SSepherosa Ziehau 1574ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1575ae813fd8SSepherosa Ziehau 1576d2e51f8dSSepherosa Ziehau #ifdef IFPOLL_ENABLE 1577d2e51f8dSSepherosa Ziehau if (ifp->if_flags & IFF_NPOLLING) 157804b9ef8dSSepherosa Ziehau nfe_disable_intrs(sc); 157904b9ef8dSSepherosa Ziehau else 1580ae813fd8SSepherosa Ziehau #endif 158104b9ef8dSSepherosa Ziehau nfe_enable_intrs(sc); 1582ae813fd8SSepherosa Ziehau 1583ae813fd8SSepherosa Ziehau callout_reset(&sc->sc_tick_ch, hz, nfe_tick, sc); 1584ae813fd8SSepherosa Ziehau 1585ae813fd8SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 15869ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 1587751890abSMatthew Dillon 1588751890abSMatthew Dillon /* 1589751890abSMatthew Dillon * If we had stuff in the tx ring before its all cleaned out now 1590751890abSMatthew Dillon * so we are not going to get an interrupt, jump-start any pending 1591751890abSMatthew Dillon * output. 1592751890abSMatthew Dillon */ 1593d378110eSSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 15949db4b353SSepherosa Ziehau if_devstart(ifp); 1595ae813fd8SSepherosa Ziehau } 1596ae813fd8SSepherosa Ziehau 1597ae813fd8SSepherosa Ziehau static void 1598ae813fd8SSepherosa Ziehau nfe_stop(struct nfe_softc *sc) 1599ae813fd8SSepherosa Ziehau { 1600ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 160153f1d017SSepherosa Ziehau uint32_t rxtxctl = sc->rxtxctl_desc | NFE_RXTX_BIT2; 160253f1d017SSepherosa Ziehau int i; 1603ae813fd8SSepherosa Ziehau 1604c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1605c0dcc88eSSepherosa Ziehau 1606ae813fd8SSepherosa Ziehau callout_stop(&sc->sc_tick_ch); 1607ae813fd8SSepherosa Ziehau 1608ae813fd8SSepherosa Ziehau ifp->if_timer = 0; 16099ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 16109ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 161104b9ef8dSSepherosa Ziehau sc->sc_flags &= ~NFE_F_IRQ_TIMER; 1612ae813fd8SSepherosa Ziehau 161353f1d017SSepherosa Ziehau #define WAITMAX 50000 161453f1d017SSepherosa Ziehau 1615d1daf8afSMatthew Dillon /* 161653f1d017SSepherosa Ziehau * Abort Tx 1617d1daf8afSMatthew Dillon */ 1618ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_TX_CTL, 0); 161953f1d017SSepherosa Ziehau for (i = 0; i < WAITMAX; ++i) { 162053f1d017SSepherosa Ziehau DELAY(100); 162153f1d017SSepherosa Ziehau if ((NFE_READ(sc, NFE_TX_STATUS) & NFE_TX_STATUS_BUSY) == 0) 162253f1d017SSepherosa Ziehau break; 162353f1d017SSepherosa Ziehau } 162453f1d017SSepherosa Ziehau if (i == WAITMAX) 162553f1d017SSepherosa Ziehau if_printf(ifp, "can't stop TX\n"); 162653f1d017SSepherosa Ziehau DELAY(100); 1627ae813fd8SSepherosa Ziehau 162853f1d017SSepherosa Ziehau /* 162953f1d017SSepherosa Ziehau * Disable Rx 163053f1d017SSepherosa Ziehau */ 1631ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RX_CTL, 0); 163253f1d017SSepherosa Ziehau for (i = 0; i < WAITMAX; ++i) { 163353f1d017SSepherosa Ziehau DELAY(100); 163453f1d017SSepherosa Ziehau if ((NFE_READ(sc, NFE_RX_STATUS) & NFE_RX_STATUS_BUSY) == 0) 163553f1d017SSepherosa Ziehau break; 163653f1d017SSepherosa Ziehau } 163753f1d017SSepherosa Ziehau if (i == WAITMAX) 163853f1d017SSepherosa Ziehau if_printf(ifp, "can't stop RX\n"); 163953f1d017SSepherosa Ziehau DELAY(100); 164053f1d017SSepherosa Ziehau 164153f1d017SSepherosa Ziehau #undef WAITMAX 164253f1d017SSepherosa Ziehau 164353f1d017SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | rxtxctl); 164453f1d017SSepherosa Ziehau DELAY(10); 164553f1d017SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, rxtxctl); 1646ae813fd8SSepherosa Ziehau 1647ae813fd8SSepherosa Ziehau /* Disable interrupts */ 1648ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1649ae813fd8SSepherosa Ziehau 1650ae813fd8SSepherosa Ziehau /* Reset Tx and Rx rings */ 1651ae813fd8SSepherosa Ziehau nfe_reset_tx_ring(sc, &sc->txq); 1652ae813fd8SSepherosa Ziehau nfe_reset_rx_ring(sc, &sc->rxq); 1653ae813fd8SSepherosa Ziehau } 1654ae813fd8SSepherosa Ziehau 1655ae813fd8SSepherosa Ziehau static int 1656ae813fd8SSepherosa Ziehau nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1657ae813fd8SSepherosa Ziehau { 1658ae813fd8SSepherosa Ziehau int i, j, error, descsize; 1659244a9aa3SSepherosa Ziehau bus_dmamem_t dmem; 1660ae813fd8SSepherosa Ziehau void **desc; 1661ae813fd8SSepherosa Ziehau 166288d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1663da44240fSMatthew Dillon desc = (void *)&ring->desc64; 1664ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc64); 1665ae813fd8SSepherosa Ziehau } else { 1666da44240fSMatthew Dillon desc = (void *)&ring->desc32; 1667ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc32); 1668ae813fd8SSepherosa Ziehau } 1669ae813fd8SSepherosa Ziehau 1670ae813fd8SSepherosa Ziehau ring->bufsz = MCLBYTES; 1671ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 1672ae813fd8SSepherosa Ziehau 1673244a9aa3SSepherosa Ziehau error = bus_dmamem_coherent(sc->sc_dtag, PAGE_SIZE, 0, 1674244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1675ec9403d0SSepherosa Ziehau sc->sc_rx_ring_count * descsize, 1676244a9aa3SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem); 1677ae813fd8SSepherosa Ziehau if (error) { 1678ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1679244a9aa3SSepherosa Ziehau "could not create RX desc ring\n"); 1680ae813fd8SSepherosa Ziehau return error; 1681ae813fd8SSepherosa Ziehau } 1682244a9aa3SSepherosa Ziehau ring->tag = dmem.dmem_tag; 1683244a9aa3SSepherosa Ziehau ring->map = dmem.dmem_map; 1684244a9aa3SSepherosa Ziehau *desc = dmem.dmem_addr; 1685244a9aa3SSepherosa Ziehau ring->physaddr = dmem.dmem_busaddr; 1686ae813fd8SSepherosa Ziehau 168788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_JUMBO_SUP) { 1688c58816edSSepherosa Ziehau ring->jbuf = 1689c58816edSSepherosa Ziehau kmalloc(sizeof(struct nfe_jbuf) * NFE_JPOOL_COUNT(sc), 169056fa71a9SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 169156fa71a9SSepherosa Ziehau 1692ae813fd8SSepherosa Ziehau error = nfe_jpool_alloc(sc, ring); 1693ae813fd8SSepherosa Ziehau if (error) { 1694ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1695ae813fd8SSepherosa Ziehau "could not allocate jumbo frames\n"); 169656fa71a9SSepherosa Ziehau kfree(ring->jbuf, M_DEVBUF); 169756fa71a9SSepherosa Ziehau ring->jbuf = NULL; 169856fa71a9SSepherosa Ziehau /* Allow jumbo frame allocation to fail */ 1699ae813fd8SSepherosa Ziehau } 1700ae813fd8SSepherosa Ziehau } 1701ae813fd8SSepherosa Ziehau 170256fa71a9SSepherosa Ziehau ring->data = kmalloc(sizeof(struct nfe_rx_data) * sc->sc_rx_ring_count, 170356fa71a9SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 170456fa71a9SSepherosa Ziehau 1705244a9aa3SSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 1706244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1707ae813fd8SSepherosa Ziehau NULL, NULL, 1708244a9aa3SSepherosa Ziehau MCLBYTES, 1, MCLBYTES, 1709244a9aa3SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK, 1710244a9aa3SSepherosa Ziehau &ring->data_tag); 1711ae813fd8SSepherosa Ziehau if (error) { 1712ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1713ae813fd8SSepherosa Ziehau "could not create RX mbuf DMA tag\n"); 1714ae813fd8SSepherosa Ziehau return error; 1715ae813fd8SSepherosa Ziehau } 1716ae813fd8SSepherosa Ziehau 1717ae813fd8SSepherosa Ziehau /* Create a spare RX mbuf DMA map */ 1718244a9aa3SSepherosa Ziehau error = bus_dmamap_create(ring->data_tag, BUS_DMA_WAITOK, 1719244a9aa3SSepherosa Ziehau &ring->data_tmpmap); 1720ae813fd8SSepherosa Ziehau if (error) { 1721ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1722ae813fd8SSepherosa Ziehau "could not create spare RX mbuf DMA map\n"); 1723ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 1724ae813fd8SSepherosa Ziehau ring->data_tag = NULL; 1725ae813fd8SSepherosa Ziehau return error; 1726ae813fd8SSepherosa Ziehau } 1727ae813fd8SSepherosa Ziehau 1728ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; i++) { 1729244a9aa3SSepherosa Ziehau error = bus_dmamap_create(ring->data_tag, BUS_DMA_WAITOK, 1730ae813fd8SSepherosa Ziehau &ring->data[i].map); 1731ae813fd8SSepherosa Ziehau if (error) { 1732ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1733ae813fd8SSepherosa Ziehau "could not create %dth RX mbuf DMA mapn", i); 1734ae813fd8SSepherosa Ziehau goto fail; 1735ae813fd8SSepherosa Ziehau } 1736ae813fd8SSepherosa Ziehau } 1737ae813fd8SSepherosa Ziehau return 0; 1738ae813fd8SSepherosa Ziehau fail: 1739ae813fd8SSepherosa Ziehau for (j = 0; j < i; ++j) 1740ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data[i].map); 1741ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data_tmpmap); 1742ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 1743ae813fd8SSepherosa Ziehau ring->data_tag = NULL; 1744ae813fd8SSepherosa Ziehau return error; 1745ae813fd8SSepherosa Ziehau } 1746ae813fd8SSepherosa Ziehau 1747ae813fd8SSepherosa Ziehau static void 1748ae813fd8SSepherosa Ziehau nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1749ae813fd8SSepherosa Ziehau { 1750ae813fd8SSepherosa Ziehau int i; 1751ae813fd8SSepherosa Ziehau 1752ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; i++) { 1753ae813fd8SSepherosa Ziehau struct nfe_rx_data *data = &ring->data[i]; 1754ae813fd8SSepherosa Ziehau 1755ae813fd8SSepherosa Ziehau if (data->m != NULL) { 17565dc1e30eSSepherosa Ziehau if ((sc->sc_flags & NFE_F_USE_JUMBO) == 0) 1757ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 1758ae813fd8SSepherosa Ziehau m_freem(data->m); 1759ae813fd8SSepherosa Ziehau data->m = NULL; 1760ae813fd8SSepherosa Ziehau } 1761ae813fd8SSepherosa Ziehau } 1762ae813fd8SSepherosa Ziehau 1763ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 1764ae813fd8SSepherosa Ziehau } 1765ae813fd8SSepherosa Ziehau 1766ae813fd8SSepherosa Ziehau static int 1767ae813fd8SSepherosa Ziehau nfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1768ae813fd8SSepherosa Ziehau { 1769ae813fd8SSepherosa Ziehau int i; 1770ae813fd8SSepherosa Ziehau 1771ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; ++i) { 1772ae813fd8SSepherosa Ziehau int error; 1773ae813fd8SSepherosa Ziehau 1774ae813fd8SSepherosa Ziehau /* XXX should use a function pointer */ 17755dc1e30eSSepherosa Ziehau if (sc->sc_flags & NFE_F_USE_JUMBO) 1776ae813fd8SSepherosa Ziehau error = nfe_newbuf_jumbo(sc, ring, i, 1); 1777ae813fd8SSepherosa Ziehau else 1778ae813fd8SSepherosa Ziehau error = nfe_newbuf_std(sc, ring, i, 1); 1779ae813fd8SSepherosa Ziehau if (error) { 1780ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1781ae813fd8SSepherosa Ziehau "could not allocate RX buffer\n"); 1782ae813fd8SSepherosa Ziehau return error; 1783ae813fd8SSepherosa Ziehau } 1784ae813fd8SSepherosa Ziehau nfe_set_ready_rxdesc(sc, ring, i); 1785ae813fd8SSepherosa Ziehau } 1786ae813fd8SSepherosa Ziehau return 0; 1787ae813fd8SSepherosa Ziehau } 1788ae813fd8SSepherosa Ziehau 1789ae813fd8SSepherosa Ziehau static void 1790ae813fd8SSepherosa Ziehau nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1791ae813fd8SSepherosa Ziehau { 1792ae813fd8SSepherosa Ziehau if (ring->data_tag != NULL) { 1793ae813fd8SSepherosa Ziehau struct nfe_rx_data *data; 1794ae813fd8SSepherosa Ziehau int i; 1795ae813fd8SSepherosa Ziehau 1796ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; i++) { 1797ae813fd8SSepherosa Ziehau data = &ring->data[i]; 1798ae813fd8SSepherosa Ziehau 1799ae813fd8SSepherosa Ziehau if (data->m != NULL) { 1800ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 1801ae813fd8SSepherosa Ziehau m_freem(data->m); 1802ae813fd8SSepherosa Ziehau } 1803ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, data->map); 1804ae813fd8SSepherosa Ziehau } 1805ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data_tmpmap); 1806ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 1807ae813fd8SSepherosa Ziehau } 1808ae813fd8SSepherosa Ziehau 1809ae813fd8SSepherosa Ziehau nfe_jpool_free(sc, ring); 1810ae813fd8SSepherosa Ziehau 1811a455c52eSSepherosa Ziehau if (ring->jbuf != NULL) 1812a455c52eSSepherosa Ziehau kfree(ring->jbuf, M_DEVBUF); 1813a455c52eSSepherosa Ziehau if (ring->data != NULL) 1814a455c52eSSepherosa Ziehau kfree(ring->data, M_DEVBUF); 1815a455c52eSSepherosa Ziehau 1816ae813fd8SSepherosa Ziehau if (ring->tag != NULL) { 1817ae813fd8SSepherosa Ziehau void *desc; 1818ae813fd8SSepherosa Ziehau 181988d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 1820ae813fd8SSepherosa Ziehau desc = ring->desc64; 1821ae813fd8SSepherosa Ziehau else 1822ae813fd8SSepherosa Ziehau desc = ring->desc32; 1823ae813fd8SSepherosa Ziehau 1824ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->tag, ring->map); 1825ae813fd8SSepherosa Ziehau bus_dmamem_free(ring->tag, desc, ring->map); 1826ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->tag); 1827ae813fd8SSepherosa Ziehau } 1828ae813fd8SSepherosa Ziehau } 1829ae813fd8SSepherosa Ziehau 1830ae813fd8SSepherosa Ziehau static struct nfe_jbuf * 1831ae813fd8SSepherosa Ziehau nfe_jalloc(struct nfe_softc *sc) 1832ae813fd8SSepherosa Ziehau { 1833ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1834ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf; 1835ae813fd8SSepherosa Ziehau 1836ae813fd8SSepherosa Ziehau lwkt_serialize_enter(&sc->sc_jbuf_serializer); 1837ae813fd8SSepherosa Ziehau 1838ae813fd8SSepherosa Ziehau jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 1839ae813fd8SSepherosa Ziehau if (jbuf != NULL) { 1840ae813fd8SSepherosa Ziehau SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 1841ae813fd8SSepherosa Ziehau jbuf->inuse = 1; 1842ae813fd8SSepherosa Ziehau } else { 1843ae813fd8SSepherosa Ziehau if_printf(ifp, "no free jumbo buffer\n"); 1844ae813fd8SSepherosa Ziehau } 1845ae813fd8SSepherosa Ziehau 1846ae813fd8SSepherosa Ziehau lwkt_serialize_exit(&sc->sc_jbuf_serializer); 1847ae813fd8SSepherosa Ziehau 1848ae813fd8SSepherosa Ziehau return jbuf; 1849ae813fd8SSepherosa Ziehau } 1850ae813fd8SSepherosa Ziehau 1851ae813fd8SSepherosa Ziehau static void 1852ae813fd8SSepherosa Ziehau nfe_jfree(void *arg) 1853ae813fd8SSepherosa Ziehau { 1854ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf = arg; 1855ae813fd8SSepherosa Ziehau struct nfe_softc *sc = jbuf->sc; 1856ae813fd8SSepherosa Ziehau struct nfe_rx_ring *ring = jbuf->ring; 1857ae813fd8SSepherosa Ziehau 1858ae813fd8SSepherosa Ziehau if (&ring->jbuf[jbuf->slot] != jbuf) 1859ed20d0e3SSascha Wildner panic("%s: free wrong jumbo buffer", __func__); 1860ae813fd8SSepherosa Ziehau else if (jbuf->inuse == 0) 1861ed20d0e3SSascha Wildner panic("%s: jumbo buffer already freed", __func__); 1862ae813fd8SSepherosa Ziehau 1863ae813fd8SSepherosa Ziehau lwkt_serialize_enter(&sc->sc_jbuf_serializer); 1864ae813fd8SSepherosa Ziehau atomic_subtract_int(&jbuf->inuse, 1); 1865ae813fd8SSepherosa Ziehau if (jbuf->inuse == 0) 1866ae813fd8SSepherosa Ziehau SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 1867ae813fd8SSepherosa Ziehau lwkt_serialize_exit(&sc->sc_jbuf_serializer); 1868ae813fd8SSepherosa Ziehau } 1869ae813fd8SSepherosa Ziehau 1870ae813fd8SSepherosa Ziehau static void 1871ae813fd8SSepherosa Ziehau nfe_jref(void *arg) 1872ae813fd8SSepherosa Ziehau { 1873ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf = arg; 1874ae813fd8SSepherosa Ziehau struct nfe_rx_ring *ring = jbuf->ring; 1875ae813fd8SSepherosa Ziehau 1876ae813fd8SSepherosa Ziehau if (&ring->jbuf[jbuf->slot] != jbuf) 1877ed20d0e3SSascha Wildner panic("%s: ref wrong jumbo buffer", __func__); 1878ae813fd8SSepherosa Ziehau else if (jbuf->inuse == 0) 1879ed20d0e3SSascha Wildner panic("%s: jumbo buffer already freed", __func__); 1880ae813fd8SSepherosa Ziehau 188106406609SSepherosa Ziehau atomic_add_int(&jbuf->inuse, 1); 1882ae813fd8SSepherosa Ziehau } 1883ae813fd8SSepherosa Ziehau 1884ae813fd8SSepherosa Ziehau static int 1885ae813fd8SSepherosa Ziehau nfe_jpool_alloc(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1886ae813fd8SSepherosa Ziehau { 1887ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf; 1888244a9aa3SSepherosa Ziehau bus_dmamem_t dmem; 1889ae813fd8SSepherosa Ziehau bus_addr_t physaddr; 1890ae813fd8SSepherosa Ziehau caddr_t buf; 1891ae813fd8SSepherosa Ziehau int i, error; 1892ae813fd8SSepherosa Ziehau 1893ae813fd8SSepherosa Ziehau /* 1894ae813fd8SSepherosa Ziehau * Allocate a big chunk of DMA'able memory. 1895ae813fd8SSepherosa Ziehau */ 1896244a9aa3SSepherosa Ziehau error = bus_dmamem_coherent(sc->sc_dtag, PAGE_SIZE, 0, 1897244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1898c58816edSSepherosa Ziehau NFE_JPOOL_SIZE(sc), 1899244a9aa3SSepherosa Ziehau BUS_DMA_WAITOK, &dmem); 1900ae813fd8SSepherosa Ziehau if (error) { 1901ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1902244a9aa3SSepherosa Ziehau "could not create jumbo buffer\n"); 1903ae813fd8SSepherosa Ziehau return error; 1904ae813fd8SSepherosa Ziehau } 1905244a9aa3SSepherosa Ziehau ring->jtag = dmem.dmem_tag; 1906244a9aa3SSepherosa Ziehau ring->jmap = dmem.dmem_map; 1907244a9aa3SSepherosa Ziehau ring->jpool = dmem.dmem_addr; 1908244a9aa3SSepherosa Ziehau physaddr = dmem.dmem_busaddr; 1909ae813fd8SSepherosa Ziehau 1910ae813fd8SSepherosa Ziehau /* ..and split it into 9KB chunks */ 1911ae813fd8SSepherosa Ziehau SLIST_INIT(&ring->jfreelist); 1912ae813fd8SSepherosa Ziehau 1913ae813fd8SSepherosa Ziehau buf = ring->jpool; 1914c58816edSSepherosa Ziehau for (i = 0; i < NFE_JPOOL_COUNT(sc); i++) { 1915ae813fd8SSepherosa Ziehau jbuf = &ring->jbuf[i]; 1916ae813fd8SSepherosa Ziehau 1917ae813fd8SSepherosa Ziehau jbuf->sc = sc; 1918ae813fd8SSepherosa Ziehau jbuf->ring = ring; 1919ae813fd8SSepherosa Ziehau jbuf->inuse = 0; 1920ae813fd8SSepherosa Ziehau jbuf->slot = i; 1921ae813fd8SSepherosa Ziehau jbuf->buf = buf; 1922ae813fd8SSepherosa Ziehau jbuf->physaddr = physaddr; 1923ae813fd8SSepherosa Ziehau 1924ae813fd8SSepherosa Ziehau SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 1925ae813fd8SSepherosa Ziehau 1926ae813fd8SSepherosa Ziehau buf += NFE_JBYTES; 1927ae813fd8SSepherosa Ziehau physaddr += NFE_JBYTES; 1928ae813fd8SSepherosa Ziehau } 1929ae813fd8SSepherosa Ziehau 1930ae813fd8SSepherosa Ziehau return 0; 1931ae813fd8SSepherosa Ziehau } 1932ae813fd8SSepherosa Ziehau 1933ae813fd8SSepherosa Ziehau static void 1934ae813fd8SSepherosa Ziehau nfe_jpool_free(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1935ae813fd8SSepherosa Ziehau { 1936ae813fd8SSepherosa Ziehau if (ring->jtag != NULL) { 1937ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->jtag, ring->jmap); 1938ae813fd8SSepherosa Ziehau bus_dmamem_free(ring->jtag, ring->jpool, ring->jmap); 1939ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->jtag); 1940ae813fd8SSepherosa Ziehau } 1941ae813fd8SSepherosa Ziehau } 1942ae813fd8SSepherosa Ziehau 1943ae813fd8SSepherosa Ziehau static int 1944ae813fd8SSepherosa Ziehau nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1945ae813fd8SSepherosa Ziehau { 1946ae813fd8SSepherosa Ziehau int i, j, error, descsize; 1947244a9aa3SSepherosa Ziehau bus_dmamem_t dmem; 1948ae813fd8SSepherosa Ziehau void **desc; 1949ae813fd8SSepherosa Ziehau 195088d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1951da44240fSMatthew Dillon desc = (void *)&ring->desc64; 1952ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc64); 1953ae813fd8SSepherosa Ziehau } else { 1954da44240fSMatthew Dillon desc = (void *)&ring->desc32; 1955ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc32); 1956ae813fd8SSepherosa Ziehau } 1957ae813fd8SSepherosa Ziehau 1958ae813fd8SSepherosa Ziehau ring->queued = 0; 1959ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 1960ae813fd8SSepherosa Ziehau 1961244a9aa3SSepherosa Ziehau error = bus_dmamem_coherent(sc->sc_dtag, PAGE_SIZE, 0, 1962244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1963b4633098SSepherosa Ziehau sc->sc_tx_ring_count * descsize, 1964244a9aa3SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem); 1965ae813fd8SSepherosa Ziehau if (error) { 1966ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1967244a9aa3SSepherosa Ziehau "could not create TX desc ring\n"); 1968ae813fd8SSepherosa Ziehau return error; 1969ae813fd8SSepherosa Ziehau } 1970244a9aa3SSepherosa Ziehau ring->tag = dmem.dmem_tag; 1971244a9aa3SSepherosa Ziehau ring->map = dmem.dmem_map; 1972244a9aa3SSepherosa Ziehau *desc = dmem.dmem_addr; 1973244a9aa3SSepherosa Ziehau ring->physaddr = dmem.dmem_busaddr; 1974ae813fd8SSepherosa Ziehau 1975b4633098SSepherosa Ziehau ring->data = kmalloc(sizeof(struct nfe_tx_data) * sc->sc_tx_ring_count, 1976b4633098SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 1977b4633098SSepherosa Ziehau 1978244a9aa3SSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 1979244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1980ae813fd8SSepherosa Ziehau NULL, NULL, 1981244a9aa3SSepherosa Ziehau NFE_JBYTES, NFE_MAX_SCATTER, MCLBYTES, 198290a9e482SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 1983244a9aa3SSepherosa Ziehau &ring->data_tag); 1984ae813fd8SSepherosa Ziehau if (error) { 1985ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1986ae813fd8SSepherosa Ziehau "could not create TX buf DMA tag\n"); 1987ae813fd8SSepherosa Ziehau return error; 1988ae813fd8SSepherosa Ziehau } 1989ae813fd8SSepherosa Ziehau 1990b4633098SSepherosa Ziehau for (i = 0; i < sc->sc_tx_ring_count; i++) { 1991244a9aa3SSepherosa Ziehau error = bus_dmamap_create(ring->data_tag, 199290a9e482SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 1993ae813fd8SSepherosa Ziehau &ring->data[i].map); 1994ae813fd8SSepherosa Ziehau if (error) { 1995ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1996ae813fd8SSepherosa Ziehau "could not create %dth TX buf DMA map\n", i); 1997ae813fd8SSepherosa Ziehau goto fail; 1998ae813fd8SSepherosa Ziehau } 1999ae813fd8SSepherosa Ziehau } 2000ae813fd8SSepherosa Ziehau 2001ae813fd8SSepherosa Ziehau return 0; 2002ae813fd8SSepherosa Ziehau fail: 2003ae813fd8SSepherosa Ziehau for (j = 0; j < i; ++j) 2004ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data[i].map); 2005ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 2006ae813fd8SSepherosa Ziehau ring->data_tag = NULL; 2007ae813fd8SSepherosa Ziehau return error; 2008ae813fd8SSepherosa Ziehau } 2009ae813fd8SSepherosa Ziehau 2010ae813fd8SSepherosa Ziehau static void 2011ae813fd8SSepherosa Ziehau nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 2012ae813fd8SSepherosa Ziehau { 2013ae813fd8SSepherosa Ziehau int i; 2014ae813fd8SSepherosa Ziehau 2015b4633098SSepherosa Ziehau for (i = 0; i < sc->sc_tx_ring_count; i++) { 2016ae813fd8SSepherosa Ziehau struct nfe_tx_data *data = &ring->data[i]; 2017ae813fd8SSepherosa Ziehau 201888d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 2019ae813fd8SSepherosa Ziehau ring->desc64[i].flags = 0; 2020ae813fd8SSepherosa Ziehau else 2021ae813fd8SSepherosa Ziehau ring->desc32[i].flags = 0; 2022ae813fd8SSepherosa Ziehau 2023ae813fd8SSepherosa Ziehau if (data->m != NULL) { 2024ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 2025ae813fd8SSepherosa Ziehau m_freem(data->m); 2026ae813fd8SSepherosa Ziehau data->m = NULL; 2027ae813fd8SSepherosa Ziehau } 2028ae813fd8SSepherosa Ziehau } 2029ae813fd8SSepherosa Ziehau 2030ae813fd8SSepherosa Ziehau ring->queued = 0; 2031ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 2032ae813fd8SSepherosa Ziehau } 2033ae813fd8SSepherosa Ziehau 2034ae813fd8SSepherosa Ziehau static int 2035ae813fd8SSepherosa Ziehau nfe_init_tx_ring(struct nfe_softc *sc __unused, 2036ae813fd8SSepherosa Ziehau struct nfe_tx_ring *ring __unused) 2037ae813fd8SSepherosa Ziehau { 2038ae813fd8SSepherosa Ziehau return 0; 2039ae813fd8SSepherosa Ziehau } 2040ae813fd8SSepherosa Ziehau 2041ae813fd8SSepherosa Ziehau static void 2042ae813fd8SSepherosa Ziehau nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 2043ae813fd8SSepherosa Ziehau { 2044ae813fd8SSepherosa Ziehau if (ring->data_tag != NULL) { 2045ae813fd8SSepherosa Ziehau struct nfe_tx_data *data; 2046ae813fd8SSepherosa Ziehau int i; 2047ae813fd8SSepherosa Ziehau 2048b4633098SSepherosa Ziehau for (i = 0; i < sc->sc_tx_ring_count; ++i) { 2049ae813fd8SSepherosa Ziehau data = &ring->data[i]; 2050ae813fd8SSepherosa Ziehau 2051ae813fd8SSepherosa Ziehau if (data->m != NULL) { 2052ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 2053ae813fd8SSepherosa Ziehau m_freem(data->m); 2054ae813fd8SSepherosa Ziehau } 2055ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, data->map); 2056ae813fd8SSepherosa Ziehau } 2057ae813fd8SSepherosa Ziehau 2058ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 2059ae813fd8SSepherosa Ziehau } 2060ae813fd8SSepherosa Ziehau 2061b4633098SSepherosa Ziehau if (ring->data != NULL) 2062b4633098SSepherosa Ziehau kfree(ring->data, M_DEVBUF); 2063b4633098SSepherosa Ziehau 2064ae813fd8SSepherosa Ziehau if (ring->tag != NULL) { 2065ae813fd8SSepherosa Ziehau void *desc; 2066ae813fd8SSepherosa Ziehau 206788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 2068ae813fd8SSepherosa Ziehau desc = ring->desc64; 2069ae813fd8SSepherosa Ziehau else 2070ae813fd8SSepherosa Ziehau desc = ring->desc32; 2071ae813fd8SSepherosa Ziehau 2072ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->tag, ring->map); 2073ae813fd8SSepherosa Ziehau bus_dmamem_free(ring->tag, desc, ring->map); 2074ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->tag); 2075ae813fd8SSepherosa Ziehau } 2076ae813fd8SSepherosa Ziehau } 2077ae813fd8SSepherosa Ziehau 2078ae813fd8SSepherosa Ziehau static int 2079ae813fd8SSepherosa Ziehau nfe_ifmedia_upd(struct ifnet *ifp) 2080ae813fd8SSepherosa Ziehau { 2081ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 2082ae813fd8SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2083ae813fd8SSepherosa Ziehau 2084c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 2085c0dcc88eSSepherosa Ziehau 2086ae813fd8SSepherosa Ziehau if (mii->mii_instance != 0) { 2087ae813fd8SSepherosa Ziehau struct mii_softc *miisc; 2088ae813fd8SSepherosa Ziehau 2089ae813fd8SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 2090ae813fd8SSepherosa Ziehau mii_phy_reset(miisc); 2091ae813fd8SSepherosa Ziehau } 2092ae813fd8SSepherosa Ziehau mii_mediachg(mii); 2093ae813fd8SSepherosa Ziehau 2094ae813fd8SSepherosa Ziehau return 0; 2095ae813fd8SSepherosa Ziehau } 2096ae813fd8SSepherosa Ziehau 2097ae813fd8SSepherosa Ziehau static void 2098ae813fd8SSepherosa Ziehau nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2099ae813fd8SSepherosa Ziehau { 2100ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 2101ae813fd8SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2102ae813fd8SSepherosa Ziehau 2103c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 2104c0dcc88eSSepherosa Ziehau 2105ae813fd8SSepherosa Ziehau mii_pollstat(mii); 2106ae813fd8SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 2107ae813fd8SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 2108ae813fd8SSepherosa Ziehau } 2109ae813fd8SSepherosa Ziehau 2110ae813fd8SSepherosa Ziehau static void 2111ae813fd8SSepherosa Ziehau nfe_setmulti(struct nfe_softc *sc) 2112ae813fd8SSepherosa Ziehau { 2113ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2114ae813fd8SSepherosa Ziehau struct ifmultiaddr *ifma; 2115ae813fd8SSepherosa Ziehau uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2116ae813fd8SSepherosa Ziehau uint32_t filter = NFE_RXFILTER_MAGIC; 2117ae813fd8SSepherosa Ziehau int i; 2118ae813fd8SSepherosa Ziehau 2119ae813fd8SSepherosa Ziehau if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2120ae813fd8SSepherosa Ziehau bzero(addr, ETHER_ADDR_LEN); 2121ae813fd8SSepherosa Ziehau bzero(mask, ETHER_ADDR_LEN); 2122ae813fd8SSepherosa Ziehau goto done; 2123ae813fd8SSepherosa Ziehau } 2124ae813fd8SSepherosa Ziehau 2125ae813fd8SSepherosa Ziehau bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2126ae813fd8SSepherosa Ziehau bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2127ae813fd8SSepherosa Ziehau 2128441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2129ae813fd8SSepherosa Ziehau caddr_t maddr; 2130ae813fd8SSepherosa Ziehau 2131ae813fd8SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 2132ae813fd8SSepherosa Ziehau continue; 2133ae813fd8SSepherosa Ziehau 2134ae813fd8SSepherosa Ziehau maddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2135ae813fd8SSepherosa Ziehau for (i = 0; i < ETHER_ADDR_LEN; i++) { 2136ae813fd8SSepherosa Ziehau addr[i] &= maddr[i]; 2137ae813fd8SSepherosa Ziehau mask[i] &= ~maddr[i]; 2138ae813fd8SSepherosa Ziehau } 2139ae813fd8SSepherosa Ziehau } 2140ae813fd8SSepherosa Ziehau 2141ae813fd8SSepherosa Ziehau for (i = 0; i < ETHER_ADDR_LEN; i++) 2142ae813fd8SSepherosa Ziehau mask[i] |= addr[i]; 2143ae813fd8SSepherosa Ziehau 2144ae813fd8SSepherosa Ziehau done: 2145ae813fd8SSepherosa Ziehau addr[0] |= 0x01; /* make sure multicast bit is set */ 2146ae813fd8SSepherosa Ziehau 2147ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIADDR_HI, 2148ae813fd8SSepherosa Ziehau addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2149ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIADDR_LO, 2150ae813fd8SSepherosa Ziehau addr[5] << 8 | addr[4]); 2151ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIMASK_HI, 2152ae813fd8SSepherosa Ziehau mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2153ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIMASK_LO, 2154ae813fd8SSepherosa Ziehau mask[5] << 8 | mask[4]); 2155ae813fd8SSepherosa Ziehau 2156ae813fd8SSepherosa Ziehau filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 2157ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXFILTER, filter); 2158ae813fd8SSepherosa Ziehau } 2159ae813fd8SSepherosa Ziehau 2160ae813fd8SSepherosa Ziehau static void 2161ae813fd8SSepherosa Ziehau nfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 2162ae813fd8SSepherosa Ziehau { 2163ece56005SSepherosa Ziehau uint32_t lo, hi; 2164ae813fd8SSepherosa Ziehau 2165ece56005SSepherosa Ziehau lo = NFE_READ(sc, NFE_MACADDR_LO); 2166ece56005SSepherosa Ziehau hi = NFE_READ(sc, NFE_MACADDR_HI); 2167ece56005SSepherosa Ziehau if (sc->sc_caps & NFE_FIX_EADDR) { 2168ece56005SSepherosa Ziehau addr[0] = (lo >> 8) & 0xff; 2169ece56005SSepherosa Ziehau addr[1] = (lo & 0xff); 2170ae813fd8SSepherosa Ziehau 2171ece56005SSepherosa Ziehau addr[2] = (hi >> 24) & 0xff; 2172ece56005SSepherosa Ziehau addr[3] = (hi >> 16) & 0xff; 2173ece56005SSepherosa Ziehau addr[4] = (hi >> 8) & 0xff; 2174ece56005SSepherosa Ziehau addr[5] = (hi & 0xff); 2175ece56005SSepherosa Ziehau } else { 2176ece56005SSepherosa Ziehau addr[0] = (hi & 0xff); 2177ece56005SSepherosa Ziehau addr[1] = (hi >> 8) & 0xff; 2178ece56005SSepherosa Ziehau addr[2] = (hi >> 16) & 0xff; 2179ece56005SSepherosa Ziehau addr[3] = (hi >> 24) & 0xff; 2180ece56005SSepherosa Ziehau 2181ece56005SSepherosa Ziehau addr[4] = (lo & 0xff); 2182ece56005SSepherosa Ziehau addr[5] = (lo >> 8) & 0xff; 2183ece56005SSepherosa Ziehau } 2184ae813fd8SSepherosa Ziehau } 2185ae813fd8SSepherosa Ziehau 2186ae813fd8SSepherosa Ziehau static void 2187ae813fd8SSepherosa Ziehau nfe_set_macaddr(struct nfe_softc *sc, const uint8_t *addr) 2188ae813fd8SSepherosa Ziehau { 2189ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_LO, 2190ae813fd8SSepherosa Ziehau addr[5] << 8 | addr[4]); 2191ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_HI, 2192ae813fd8SSepherosa Ziehau addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2193ae813fd8SSepherosa Ziehau } 2194ae813fd8SSepherosa Ziehau 2195ae813fd8SSepherosa Ziehau static void 2196ae813fd8SSepherosa Ziehau nfe_tick(void *arg) 2197ae813fd8SSepherosa Ziehau { 2198ae813fd8SSepherosa Ziehau struct nfe_softc *sc = arg; 2199ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2200ae813fd8SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2201ae813fd8SSepherosa Ziehau 2202ae813fd8SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2203ae813fd8SSepherosa Ziehau 2204ae813fd8SSepherosa Ziehau mii_tick(mii); 2205ae813fd8SSepherosa Ziehau callout_reset(&sc->sc_tick_ch, hz, nfe_tick, sc); 2206ae813fd8SSepherosa Ziehau 2207ae813fd8SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2208ae813fd8SSepherosa Ziehau } 2209ae813fd8SSepherosa Ziehau 2210ae813fd8SSepherosa Ziehau static int 2211ae813fd8SSepherosa Ziehau nfe_newbuf_std(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx, 2212ae813fd8SSepherosa Ziehau int wait) 2213ae813fd8SSepherosa Ziehau { 2214ae813fd8SSepherosa Ziehau struct nfe_rx_data *data = &ring->data[idx]; 2215ae813fd8SSepherosa Ziehau bus_dma_segment_t seg; 2216ae813fd8SSepherosa Ziehau bus_dmamap_t map; 2217ae813fd8SSepherosa Ziehau struct mbuf *m; 2218b6bb439dSSepherosa Ziehau int nsegs, error; 2219ae813fd8SSepherosa Ziehau 2220ae813fd8SSepherosa Ziehau m = m_getcl(wait ? MB_WAIT : MB_DONTWAIT, MT_DATA, M_PKTHDR); 2221ae813fd8SSepherosa Ziehau if (m == NULL) 2222ae813fd8SSepherosa Ziehau return ENOBUFS; 2223ae813fd8SSepherosa Ziehau m->m_len = m->m_pkthdr.len = MCLBYTES; 2224f81efabeSMatthew Dillon 2225f81efabeSMatthew Dillon /* 2226f81efabeSMatthew Dillon * Aligning the payload improves access times. 2227f81efabeSMatthew Dillon */ 2228f81efabeSMatthew Dillon if (sc->sc_caps & NFE_WORDALIGN) 2229f81efabeSMatthew Dillon m_adj(m, ETHER_ALIGN); 2230ae813fd8SSepherosa Ziehau 2231b6bb439dSSepherosa Ziehau error = bus_dmamap_load_mbuf_segment(ring->data_tag, ring->data_tmpmap, 2232b6bb439dSSepherosa Ziehau m, &seg, 1, &nsegs, BUS_DMA_NOWAIT); 2233b6bb439dSSepherosa Ziehau if (error) { 2234ae813fd8SSepherosa Ziehau m_freem(m); 223577cdd7f0SSepherosa Ziehau if (wait) { 223677cdd7f0SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 223777cdd7f0SSepherosa Ziehau "could map RX mbuf %d\n", error); 223877cdd7f0SSepherosa Ziehau } 2239ae813fd8SSepherosa Ziehau return error; 2240ae813fd8SSepherosa Ziehau } 2241ae813fd8SSepherosa Ziehau 2242e679c149SSepherosa Ziehau if (data->m != NULL) { 2243e679c149SSepherosa Ziehau /* Sync and unload originally mapped mbuf */ 2244e679c149SSepherosa Ziehau bus_dmamap_sync(ring->data_tag, data->map, 2245e679c149SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 2246ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 2247e679c149SSepherosa Ziehau } 2248ae813fd8SSepherosa Ziehau 2249ae813fd8SSepherosa Ziehau /* Swap this DMA map with tmp DMA map */ 2250ae813fd8SSepherosa Ziehau map = data->map; 2251ae813fd8SSepherosa Ziehau data->map = ring->data_tmpmap; 2252ae813fd8SSepherosa Ziehau ring->data_tmpmap = map; 2253ae813fd8SSepherosa Ziehau 2254ae813fd8SSepherosa Ziehau /* Caller is assumed to have collected the old mbuf */ 2255ae813fd8SSepherosa Ziehau data->m = m; 2256ae813fd8SSepherosa Ziehau 2257ae813fd8SSepherosa Ziehau nfe_set_paddr_rxdesc(sc, ring, idx, seg.ds_addr); 2258ae813fd8SSepherosa Ziehau return 0; 2259ae813fd8SSepherosa Ziehau } 2260ae813fd8SSepherosa Ziehau 2261ae813fd8SSepherosa Ziehau static int 2262ae813fd8SSepherosa Ziehau nfe_newbuf_jumbo(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx, 2263ae813fd8SSepherosa Ziehau int wait) 2264ae813fd8SSepherosa Ziehau { 2265ae813fd8SSepherosa Ziehau struct nfe_rx_data *data = &ring->data[idx]; 2266ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf; 2267ae813fd8SSepherosa Ziehau struct mbuf *m; 2268ae813fd8SSepherosa Ziehau 2269ae813fd8SSepherosa Ziehau MGETHDR(m, wait ? MB_WAIT : MB_DONTWAIT, MT_DATA); 2270ae813fd8SSepherosa Ziehau if (m == NULL) 2271ae813fd8SSepherosa Ziehau return ENOBUFS; 2272ae813fd8SSepherosa Ziehau 2273ae813fd8SSepherosa Ziehau jbuf = nfe_jalloc(sc); 2274ae813fd8SSepherosa Ziehau if (jbuf == NULL) { 2275ae813fd8SSepherosa Ziehau m_freem(m); 2276ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "jumbo allocation failed " 2277ae813fd8SSepherosa Ziehau "-- packet dropped!\n"); 2278ae813fd8SSepherosa Ziehau return ENOBUFS; 2279ae813fd8SSepherosa Ziehau } 2280ae813fd8SSepherosa Ziehau 2281ae813fd8SSepherosa Ziehau m->m_ext.ext_arg = jbuf; 2282ae813fd8SSepherosa Ziehau m->m_ext.ext_buf = jbuf->buf; 2283ae813fd8SSepherosa Ziehau m->m_ext.ext_free = nfe_jfree; 2284ae813fd8SSepherosa Ziehau m->m_ext.ext_ref = nfe_jref; 2285ae813fd8SSepherosa Ziehau m->m_ext.ext_size = NFE_JBYTES; 2286ae813fd8SSepherosa Ziehau 2287ae813fd8SSepherosa Ziehau m->m_data = m->m_ext.ext_buf; 2288ae813fd8SSepherosa Ziehau m->m_flags |= M_EXT; 2289ae813fd8SSepherosa Ziehau m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 2290f81efabeSMatthew Dillon 2291f81efabeSMatthew Dillon /* 2292f81efabeSMatthew Dillon * Aligning the payload improves access times. 2293f81efabeSMatthew Dillon */ 2294f81efabeSMatthew Dillon if (sc->sc_caps & NFE_WORDALIGN) 2295f81efabeSMatthew Dillon m_adj(m, ETHER_ALIGN); 2296ae813fd8SSepherosa Ziehau 2297ae813fd8SSepherosa Ziehau /* Caller is assumed to have collected the old mbuf */ 2298ae813fd8SSepherosa Ziehau data->m = m; 2299ae813fd8SSepherosa Ziehau 2300ae813fd8SSepherosa Ziehau nfe_set_paddr_rxdesc(sc, ring, idx, jbuf->physaddr); 2301ae813fd8SSepherosa Ziehau return 0; 2302ae813fd8SSepherosa Ziehau } 2303ae813fd8SSepherosa Ziehau 2304ae813fd8SSepherosa Ziehau static void 2305ae813fd8SSepherosa Ziehau nfe_set_paddr_rxdesc(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx, 2306ae813fd8SSepherosa Ziehau bus_addr_t physaddr) 2307ae813fd8SSepherosa Ziehau { 230888d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 2309ae813fd8SSepherosa Ziehau struct nfe_desc64 *desc64 = &ring->desc64[idx]; 2310ae813fd8SSepherosa Ziehau 23117752918dSSepherosa Ziehau desc64->physaddr[0] = htole32(NFE_ADDR_HI(physaddr)); 23127752918dSSepherosa Ziehau desc64->physaddr[1] = htole32(NFE_ADDR_LO(physaddr)); 2313ae813fd8SSepherosa Ziehau } else { 2314ae813fd8SSepherosa Ziehau struct nfe_desc32 *desc32 = &ring->desc32[idx]; 2315ae813fd8SSepherosa Ziehau 2316ae813fd8SSepherosa Ziehau desc32->physaddr = htole32(physaddr); 2317ae813fd8SSepherosa Ziehau } 2318ae813fd8SSepherosa Ziehau } 2319ae813fd8SSepherosa Ziehau 2320ae813fd8SSepherosa Ziehau static void 2321ae813fd8SSepherosa Ziehau nfe_set_ready_rxdesc(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx) 2322ae813fd8SSepherosa Ziehau { 232388d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 2324ae813fd8SSepherosa Ziehau struct nfe_desc64 *desc64 = &ring->desc64[idx]; 2325ae813fd8SSepherosa Ziehau 2326ae813fd8SSepherosa Ziehau desc64->length = htole16(ring->bufsz); 2327ae813fd8SSepherosa Ziehau desc64->flags = htole16(NFE_RX_READY); 2328ae813fd8SSepherosa Ziehau } else { 2329ae813fd8SSepherosa Ziehau struct nfe_desc32 *desc32 = &ring->desc32[idx]; 2330ae813fd8SSepherosa Ziehau 2331ae813fd8SSepherosa Ziehau desc32->length = htole16(ring->bufsz); 2332ae813fd8SSepherosa Ziehau desc32->flags = htole16(NFE_RX_READY); 2333ae813fd8SSepherosa Ziehau } 2334ae813fd8SSepherosa Ziehau } 2335ec9403d0SSepherosa Ziehau 2336ec9403d0SSepherosa Ziehau static int 2337ec9403d0SSepherosa Ziehau nfe_sysctl_imtime(SYSCTL_HANDLER_ARGS) 2338ec9403d0SSepherosa Ziehau { 2339ec9403d0SSepherosa Ziehau struct nfe_softc *sc = arg1; 2340ec9403d0SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 234104b9ef8dSSepherosa Ziehau uint32_t flags; 2342ec9403d0SSepherosa Ziehau int error, v; 2343ec9403d0SSepherosa Ziehau 2344ec9403d0SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2345ec9403d0SSepherosa Ziehau 234604b9ef8dSSepherosa Ziehau flags = sc->sc_flags & ~NFE_F_DYN_IM; 2347ec9403d0SSepherosa Ziehau v = sc->sc_imtime; 234804b9ef8dSSepherosa Ziehau if (sc->sc_flags & NFE_F_DYN_IM) 234904b9ef8dSSepherosa Ziehau v = -v; 235004b9ef8dSSepherosa Ziehau 2351ec9403d0SSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 2352ec9403d0SSepherosa Ziehau if (error || req->newptr == NULL) 2353ec9403d0SSepherosa Ziehau goto back; 235404b9ef8dSSepherosa Ziehau 235504b9ef8dSSepherosa Ziehau if (v < 0) { 235604b9ef8dSSepherosa Ziehau flags |= NFE_F_DYN_IM; 235704b9ef8dSSepherosa Ziehau v = -v; 2358ec9403d0SSepherosa Ziehau } 2359ec9403d0SSepherosa Ziehau 236004b9ef8dSSepherosa Ziehau if (v != sc->sc_imtime || (flags ^ sc->sc_flags)) { 2361c00ddf33SMatthew Dillon if (NFE_IMTIME(v) == 0) 2362c00ddf33SMatthew Dillon v = 0; 2363ec9403d0SSepherosa Ziehau sc->sc_imtime = v; 236404b9ef8dSSepherosa Ziehau sc->sc_flags = flags; 2365ec9403d0SSepherosa Ziehau sc->sc_irq_enable = NFE_IRQ_ENABLE(sc); 2366ec9403d0SSepherosa Ziehau 2367d2e51f8dSSepherosa Ziehau if ((ifp->if_flags & (IFF_NPOLLING | IFF_RUNNING)) 2368ec9403d0SSepherosa Ziehau == IFF_RUNNING) { 2369c00ddf33SMatthew Dillon nfe_enable_intrs(sc); 2370ec9403d0SSepherosa Ziehau } 2371ec9403d0SSepherosa Ziehau } 2372ec9403d0SSepherosa Ziehau back: 2373ec9403d0SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2374ec9403d0SSepherosa Ziehau return error; 2375ec9403d0SSepherosa Ziehau } 2376faaea42eSSepherosa Ziehau 2377faaea42eSSepherosa Ziehau static void 2378faaea42eSSepherosa Ziehau nfe_powerup(device_t dev) 2379faaea42eSSepherosa Ziehau { 2380faaea42eSSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 2381faaea42eSSepherosa Ziehau uint32_t pwr_state; 2382faaea42eSSepherosa Ziehau uint16_t did; 2383faaea42eSSepherosa Ziehau 2384faaea42eSSepherosa Ziehau /* 2385faaea42eSSepherosa Ziehau * Bring MAC and PHY out of low power state 2386faaea42eSSepherosa Ziehau */ 2387faaea42eSSepherosa Ziehau 2388faaea42eSSepherosa Ziehau pwr_state = NFE_READ(sc, NFE_PWR_STATE2) & ~NFE_PWRUP_MASK; 2389faaea42eSSepherosa Ziehau 2390faaea42eSSepherosa Ziehau did = pci_get_device(dev); 2391faaea42eSSepherosa Ziehau if ((did == PCI_PRODUCT_NVIDIA_MCP51_LAN1 || 2392faaea42eSSepherosa Ziehau did == PCI_PRODUCT_NVIDIA_MCP51_LAN2) && 2393faaea42eSSepherosa Ziehau pci_get_revid(dev) >= 0xa3) 2394faaea42eSSepherosa Ziehau pwr_state |= NFE_PWRUP_REV_A3; 2395faaea42eSSepherosa Ziehau 2396faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_PWR_STATE2, pwr_state); 2397faaea42eSSepherosa Ziehau } 2398faaea42eSSepherosa Ziehau 2399faaea42eSSepherosa Ziehau static void 2400faaea42eSSepherosa Ziehau nfe_mac_reset(struct nfe_softc *sc) 2401faaea42eSSepherosa Ziehau { 2402faaea42eSSepherosa Ziehau uint32_t rxtxctl = sc->rxtxctl_desc | NFE_RXTX_BIT2; 2403faaea42eSSepherosa Ziehau uint32_t macaddr_hi, macaddr_lo, tx_poll; 2404faaea42eSSepherosa Ziehau 2405faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | rxtxctl); 2406faaea42eSSepherosa Ziehau 2407faaea42eSSepherosa Ziehau /* Save several registers for later restoration */ 2408faaea42eSSepherosa Ziehau macaddr_hi = NFE_READ(sc, NFE_MACADDR_HI); 2409faaea42eSSepherosa Ziehau macaddr_lo = NFE_READ(sc, NFE_MACADDR_LO); 2410faaea42eSSepherosa Ziehau tx_poll = NFE_READ(sc, NFE_TX_POLL); 2411faaea42eSSepherosa Ziehau 2412faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MAC_RESET, NFE_RESET_ASSERT); 2413faaea42eSSepherosa Ziehau DELAY(100); 2414faaea42eSSepherosa Ziehau 2415faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MAC_RESET, 0); 2416faaea42eSSepherosa Ziehau DELAY(100); 2417faaea42eSSepherosa Ziehau 2418faaea42eSSepherosa Ziehau /* Restore saved registers */ 2419faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_HI, macaddr_hi); 2420faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_LO, macaddr_lo); 2421faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_TX_POLL, tx_poll); 2422faaea42eSSepherosa Ziehau 2423faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, rxtxctl); 2424faaea42eSSepherosa Ziehau } 242504b9ef8dSSepherosa Ziehau 242604b9ef8dSSepherosa Ziehau static void 242704b9ef8dSSepherosa Ziehau nfe_enable_intrs(struct nfe_softc *sc) 242804b9ef8dSSepherosa Ziehau { 242904b9ef8dSSepherosa Ziehau /* 243004b9ef8dSSepherosa Ziehau * NFE_IMTIMER generates a periodic interrupt via NFE_IRQ_TIMER. 243104b9ef8dSSepherosa Ziehau * It is unclear how wide the timer is. Base programming does 243204b9ef8dSSepherosa Ziehau * not seem to effect NFE_IRQ_TX_DONE or NFE_IRQ_RX_DONE so 243304b9ef8dSSepherosa Ziehau * we don't get any interrupt moderation. TX moderation is 243404b9ef8dSSepherosa Ziehau * possible by using the timer interrupt instead of TX_DONE. 243504b9ef8dSSepherosa Ziehau * 243604b9ef8dSSepherosa Ziehau * It is unclear whether there are other bits that can be 243704b9ef8dSSepherosa Ziehau * set to make the NFE device actually do interrupt moderation 243804b9ef8dSSepherosa Ziehau * on the RX side. 243904b9ef8dSSepherosa Ziehau * 244004b9ef8dSSepherosa Ziehau * For now set a 128uS interval as a placemark, but don't use 244104b9ef8dSSepherosa Ziehau * the timer. 244204b9ef8dSSepherosa Ziehau */ 244304b9ef8dSSepherosa Ziehau if (sc->sc_imtime == 0) 244404b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IMTIMER, NFE_IMTIME_DEFAULT); 244504b9ef8dSSepherosa Ziehau else 244604b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IMTIMER, NFE_IMTIME(sc->sc_imtime)); 244704b9ef8dSSepherosa Ziehau 244804b9ef8dSSepherosa Ziehau /* Enable interrupts */ 244904b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_MASK, sc->sc_irq_enable); 245004b9ef8dSSepherosa Ziehau 245104b9ef8dSSepherosa Ziehau if (sc->sc_irq_enable & NFE_IRQ_TIMER) 245204b9ef8dSSepherosa Ziehau sc->sc_flags |= NFE_F_IRQ_TIMER; 245304b9ef8dSSepherosa Ziehau else 245404b9ef8dSSepherosa Ziehau sc->sc_flags &= ~NFE_F_IRQ_TIMER; 245504b9ef8dSSepherosa Ziehau } 2456