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 *); 121ae813fd8SSepherosa Ziehau static void nfe_start(struct ifnet *); 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 346ae813fd8SSepherosa Ziehau { 0, 0 } 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 649d2e51f8dSSepherosa Ziehau #ifdef IFPOLL_ENABLE 650d2e51f8dSSepherosa Ziehau ifpoll_compat_setup(&sc->sc_npoll, 651d2e51f8dSSepherosa Ziehau &sc->sc_sysctl_ctx, sc->sc_sysctl_tree, device_get_unit(dev), 652d2e51f8dSSepherosa Ziehau ifp->if_serializer); 653d2e51f8dSSepherosa Ziehau #endif 654d2e51f8dSSepherosa Ziehau 655ae813fd8SSepherosa Ziehau error = bus_setup_intr(dev, sc->sc_irq_res, INTR_MPSAFE, nfe_intr, sc, 656ae813fd8SSepherosa Ziehau &sc->sc_ih, ifp->if_serializer); 657ae813fd8SSepherosa Ziehau if (error) { 658ae813fd8SSepherosa Ziehau device_printf(dev, "could not setup intr\n"); 659ae813fd8SSepherosa Ziehau ether_ifdetach(ifp); 660ae813fd8SSepherosa Ziehau goto fail; 661ae813fd8SSepherosa Ziehau } 662ae813fd8SSepherosa Ziehau 663*dfd3b18bSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->sc_irq_res)); 6649db4b353SSepherosa 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); 902*dfd3b18bSSepherosa 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); 906*dfd3b18bSSepherosa 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) { 1123ae813fd8SSepherosa Ziehau ifp->if_ierrors++; 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) { 1134ae813fd8SSepherosa Ziehau ifp->if_ierrors++; 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 1158ae813fd8SSepherosa Ziehau ifp->if_ipackets++; 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); 1194ae813fd8SSepherosa Ziehau ifp->if_oerrors++; 1195ae813fd8SSepherosa Ziehau } else { 1196ae813fd8SSepherosa Ziehau ifp->if_opackets++; 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); 1205ae813fd8SSepherosa Ziehau ifp->if_oerrors++; 1206ae813fd8SSepherosa Ziehau } else { 1207ae813fd8SSepherosa Ziehau ifp->if_opackets++; 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 1359ae813fd8SSepherosa Ziehau nfe_start(struct ifnet *ifp) 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 1366c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1367c0dcc88eSSepherosa Ziehau 13689ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) 1369ae813fd8SSepherosa Ziehau return; 1370ae813fd8SSepherosa Ziehau 1371ae813fd8SSepherosa Ziehau for (;;) { 1372d378110eSSepherosa Ziehau int error; 1373d378110eSSepherosa Ziehau 1374d378110eSSepherosa Ziehau if (sc->sc_tx_ring_count - ring->queued < 1375d378110eSSepherosa Ziehau sc->sc_tx_spare + NFE_NSEG_RSVD) { 1376d378110eSSepherosa Ziehau if (oactive) { 13779ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1378d378110eSSepherosa Ziehau break; 1379d378110eSSepherosa Ziehau } 1380d378110eSSepherosa Ziehau 1381d378110eSSepherosa Ziehau nfe_txeof(sc, 0); 1382d378110eSSepherosa Ziehau oactive = 1; 1383d378110eSSepherosa Ziehau continue; 1384d378110eSSepherosa Ziehau } 1385d378110eSSepherosa Ziehau 1386ae813fd8SSepherosa Ziehau m0 = ifq_dequeue(&ifp->if_snd, NULL); 1387ae813fd8SSepherosa Ziehau if (m0 == NULL) 1388ae813fd8SSepherosa Ziehau break; 1389ae813fd8SSepherosa Ziehau 1390b637f170SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m0); 1391ae813fd8SSepherosa Ziehau 1392d378110eSSepherosa Ziehau error = nfe_encap(sc, ring, m0); 1393d378110eSSepherosa Ziehau if (error) { 1394d378110eSSepherosa Ziehau ifp->if_oerrors++; 1395d378110eSSepherosa Ziehau if (error == EFBIG) { 1396d378110eSSepherosa Ziehau if (oactive) { 13979ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd); 1398ae813fd8SSepherosa Ziehau break; 1399ae813fd8SSepherosa Ziehau } 1400d378110eSSepherosa Ziehau nfe_txeof(sc, 0); 1401d378110eSSepherosa Ziehau oactive = 1; 1402d378110eSSepherosa Ziehau } 1403d378110eSSepherosa Ziehau continue; 1404d378110eSSepherosa Ziehau } else { 1405d378110eSSepherosa Ziehau oactive = 0; 1406d378110eSSepherosa Ziehau } 1407ae813fd8SSepherosa Ziehau ++count; 1408ae813fd8SSepherosa Ziehau 1409ae813fd8SSepherosa Ziehau /* 1410ae813fd8SSepherosa Ziehau * NOTE: 1411ae813fd8SSepherosa Ziehau * `m0' may be freed in nfe_encap(), so 1412ae813fd8SSepherosa Ziehau * it should not be touched any more. 1413ae813fd8SSepherosa Ziehau */ 1414ae813fd8SSepherosa Ziehau } 14158ed6a3afSSepherosa Ziehau 1416ae813fd8SSepherosa Ziehau if (count == 0) /* nothing sent */ 1417ae813fd8SSepherosa Ziehau return; 1418ae813fd8SSepherosa Ziehau 1419ae813fd8SSepherosa Ziehau /* Kick Tx */ 1420ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_KICKTX | sc->rxtxctl); 1421ae813fd8SSepherosa Ziehau 1422ae813fd8SSepherosa Ziehau /* 1423ae813fd8SSepherosa Ziehau * Set a timeout in case the chip goes out to lunch. 1424ae813fd8SSepherosa Ziehau */ 1425ae813fd8SSepherosa Ziehau ifp->if_timer = 5; 1426ae813fd8SSepherosa Ziehau } 1427ae813fd8SSepherosa Ziehau 1428ae813fd8SSepherosa Ziehau static void 1429ae813fd8SSepherosa Ziehau nfe_watchdog(struct ifnet *ifp) 1430ae813fd8SSepherosa Ziehau { 1431ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 1432ae813fd8SSepherosa Ziehau 1433c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1434c0dcc88eSSepherosa Ziehau 1435ae813fd8SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) { 1436ae813fd8SSepherosa Ziehau if_printf(ifp, "watchdog timeout - lost interrupt recovered\n"); 1437d378110eSSepherosa Ziehau nfe_txeof(sc, 1); 1438ae813fd8SSepherosa Ziehau return; 1439ae813fd8SSepherosa Ziehau } 1440ae813fd8SSepherosa Ziehau 1441ae813fd8SSepherosa Ziehau if_printf(ifp, "watchdog timeout\n"); 1442ae813fd8SSepherosa Ziehau 1443ae813fd8SSepherosa Ziehau nfe_init(ifp->if_softc); 1444ae813fd8SSepherosa Ziehau 1445ae813fd8SSepherosa Ziehau ifp->if_oerrors++; 1446ae813fd8SSepherosa Ziehau } 1447ae813fd8SSepherosa Ziehau 1448ae813fd8SSepherosa Ziehau static void 1449ae813fd8SSepherosa Ziehau nfe_init(void *xsc) 1450ae813fd8SSepherosa Ziehau { 1451ae813fd8SSepherosa Ziehau struct nfe_softc *sc = xsc; 1452ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1453ae813fd8SSepherosa Ziehau uint32_t tmp; 1454ae813fd8SSepherosa Ziehau int error; 1455ae813fd8SSepherosa Ziehau 1456c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1457c0dcc88eSSepherosa Ziehau 1458ae813fd8SSepherosa Ziehau nfe_stop(sc); 1459ae813fd8SSepherosa Ziehau 146088d487c3SSepherosa Ziehau if ((sc->sc_caps & NFE_NO_PWRCTL) == 0) 1461faaea42eSSepherosa Ziehau nfe_mac_reset(sc); 1462faaea42eSSepherosa Ziehau 1463a455c52eSSepherosa Ziehau /* 1464a455c52eSSepherosa Ziehau * NOTE: 1465a455c52eSSepherosa Ziehau * Switching between jumbo frames and normal frames should 1466a455c52eSSepherosa Ziehau * be done _after_ nfe_stop() but _before_ nfe_init_rx_ring(). 1467a455c52eSSepherosa Ziehau */ 1468a455c52eSSepherosa Ziehau if (ifp->if_mtu > ETHERMTU) { 14695dc1e30eSSepherosa Ziehau sc->sc_flags |= NFE_F_USE_JUMBO; 1470a455c52eSSepherosa Ziehau sc->rxq.bufsz = NFE_JBYTES; 1471d378110eSSepherosa Ziehau sc->sc_tx_spare = NFE_NSEG_SPARE_JUMBO; 1472a455c52eSSepherosa Ziehau if (bootverbose) 1473a455c52eSSepherosa Ziehau if_printf(ifp, "use jumbo frames\n"); 1474a455c52eSSepherosa Ziehau } else { 14755dc1e30eSSepherosa Ziehau sc->sc_flags &= ~NFE_F_USE_JUMBO; 1476a455c52eSSepherosa Ziehau sc->rxq.bufsz = MCLBYTES; 1477d378110eSSepherosa Ziehau sc->sc_tx_spare = NFE_NSEG_SPARE; 1478a455c52eSSepherosa Ziehau if (bootverbose) 1479a455c52eSSepherosa Ziehau if_printf(ifp, "use non-jumbo frames\n"); 1480a455c52eSSepherosa Ziehau } 1481a455c52eSSepherosa Ziehau 1482ae813fd8SSepherosa Ziehau error = nfe_init_tx_ring(sc, &sc->txq); 1483ae813fd8SSepherosa Ziehau if (error) { 1484ae813fd8SSepherosa Ziehau nfe_stop(sc); 1485ae813fd8SSepherosa Ziehau return; 1486ae813fd8SSepherosa Ziehau } 1487ae813fd8SSepherosa Ziehau 1488ae813fd8SSepherosa Ziehau error = nfe_init_rx_ring(sc, &sc->rxq); 1489ae813fd8SSepherosa Ziehau if (error) { 1490ae813fd8SSepherosa Ziehau nfe_stop(sc); 1491ae813fd8SSepherosa Ziehau return; 1492ae813fd8SSepherosa Ziehau } 1493ae813fd8SSepherosa Ziehau 1494fd9c8397SSepherosa Ziehau NFE_WRITE(sc, NFE_TX_POLL, 0); 1495ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_STATUS, 0); 1496ae813fd8SSepherosa Ziehau 1497faaea42eSSepherosa Ziehau sc->rxtxctl = NFE_RXTX_BIT2 | sc->rxtxctl_desc; 149811db6c57SSepherosa Ziehau 1499bf2a5992SSepherosa Ziehau if (ifp->if_capenable & IFCAP_RXCSUM) 1500ae813fd8SSepherosa Ziehau sc->rxtxctl |= NFE_RXTX_RXCSUM; 1501ae813fd8SSepherosa Ziehau 1502ae813fd8SSepherosa Ziehau /* 1503ae813fd8SSepherosa Ziehau * Although the adapter is capable of stripping VLAN tags from received 1504ae813fd8SSepherosa Ziehau * frames (NFE_RXTX_VTAG_STRIP), we do not enable this functionality on 1505ae813fd8SSepherosa Ziehau * purpose. This will be done in software by our network stack. 1506ae813fd8SSepherosa Ziehau */ 150788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_HW_VLAN) 1508ae813fd8SSepherosa Ziehau sc->rxtxctl |= NFE_RXTX_VTAG_INSERT; 1509ae813fd8SSepherosa Ziehau 1510ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | sc->rxtxctl); 1511ae813fd8SSepherosa Ziehau DELAY(10); 1512ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1513ae813fd8SSepherosa Ziehau 151488d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_HW_VLAN) 1515ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_VTAG_CTL, NFE_VTAG_ENABLE); 1516ae813fd8SSepherosa Ziehau 1517ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R6, 0); 1518ae813fd8SSepherosa Ziehau 1519ae813fd8SSepherosa Ziehau /* set MAC address */ 1520ae813fd8SSepherosa Ziehau nfe_set_macaddr(sc, sc->arpcom.ac_enaddr); 1521ae813fd8SSepherosa Ziehau 1522ae813fd8SSepherosa Ziehau /* tell MAC where rings are in memory */ 15237752918dSSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 15247752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_RX_RING_ADDR_HI, 15257752918dSSepherosa Ziehau NFE_ADDR_HI(sc->rxq.physaddr)); 15267752918dSSepherosa Ziehau } 15277752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_RX_RING_ADDR_LO, NFE_ADDR_LO(sc->rxq.physaddr)); 15287752918dSSepherosa Ziehau 15297752918dSSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 15307752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_TX_RING_ADDR_HI, 15317752918dSSepherosa Ziehau NFE_ADDR_HI(sc->txq.physaddr)); 15327752918dSSepherosa Ziehau } 15337752918dSSepherosa Ziehau NFE_WRITE(sc, NFE_TX_RING_ADDR_LO, NFE_ADDR_LO(sc->txq.physaddr)); 1534ae813fd8SSepherosa Ziehau 1535ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RING_SIZE, 1536ec9403d0SSepherosa Ziehau (sc->sc_rx_ring_count - 1) << 16 | 1537b4633098SSepherosa Ziehau (sc->sc_tx_ring_count - 1)); 1538ae813fd8SSepherosa Ziehau 1539ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXBUFSZ, sc->rxq.bufsz); 1540ae813fd8SSepherosa Ziehau 1541ae813fd8SSepherosa Ziehau /* force MAC to wakeup */ 1542ae813fd8SSepherosa Ziehau tmp = NFE_READ(sc, NFE_PWR_STATE); 1543ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_WAKEUP); 1544ae813fd8SSepherosa Ziehau DELAY(10); 1545ae813fd8SSepherosa Ziehau tmp = NFE_READ(sc, NFE_PWR_STATE); 1546ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PWR_STATE, tmp | NFE_PWR_VALID); 1547ae813fd8SSepherosa Ziehau 1548ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R1, NFE_R1_MAGIC); 1549ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R2, NFE_R2_MAGIC); 1550ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R6, NFE_R6_MAGIC); 1551ae813fd8SSepherosa Ziehau 1552ae813fd8SSepherosa Ziehau /* update MAC knowledge of PHY; generates a NFE_IRQ_LINK interrupt */ 1553ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_STATUS, sc->mii_phyaddr << 24 | NFE_STATUS_MAGIC); 1554ae813fd8SSepherosa Ziehau 1555ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_SETUP_R4, NFE_R4_MAGIC); 1556ae813fd8SSepherosa Ziehau 1557ae813fd8SSepherosa Ziehau sc->rxtxctl &= ~NFE_RXTX_BIT2; 1558ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, sc->rxtxctl); 1559ae813fd8SSepherosa Ziehau DELAY(10); 1560ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_BIT1 | sc->rxtxctl); 1561ae813fd8SSepherosa Ziehau 1562ae813fd8SSepherosa Ziehau /* set Rx filter */ 1563ae813fd8SSepherosa Ziehau nfe_setmulti(sc); 1564ae813fd8SSepherosa Ziehau 1565ae813fd8SSepherosa Ziehau nfe_ifmedia_upd(ifp); 1566ae813fd8SSepherosa Ziehau 1567ae813fd8SSepherosa Ziehau /* enable Rx */ 1568ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RX_CTL, NFE_RX_START); 1569ae813fd8SSepherosa Ziehau 1570ae813fd8SSepherosa Ziehau /* enable Tx */ 1571ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_TX_CTL, NFE_TX_START); 1572ae813fd8SSepherosa Ziehau 1573ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_PHY_STATUS, 0xf); 1574ae813fd8SSepherosa Ziehau 1575d2e51f8dSSepherosa Ziehau #ifdef IFPOLL_ENABLE 1576d2e51f8dSSepherosa Ziehau if (ifp->if_flags & IFF_NPOLLING) 157704b9ef8dSSepherosa Ziehau nfe_disable_intrs(sc); 157804b9ef8dSSepherosa Ziehau else 1579ae813fd8SSepherosa Ziehau #endif 158004b9ef8dSSepherosa Ziehau nfe_enable_intrs(sc); 1581ae813fd8SSepherosa Ziehau 1582ae813fd8SSepherosa Ziehau callout_reset(&sc->sc_tick_ch, hz, nfe_tick, sc); 1583ae813fd8SSepherosa Ziehau 1584ae813fd8SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 15859ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 1586751890abSMatthew Dillon 1587751890abSMatthew Dillon /* 1588751890abSMatthew Dillon * If we had stuff in the tx ring before its all cleaned out now 1589751890abSMatthew Dillon * so we are not going to get an interrupt, jump-start any pending 1590751890abSMatthew Dillon * output. 1591751890abSMatthew Dillon */ 1592d378110eSSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 15939db4b353SSepherosa Ziehau if_devstart(ifp); 1594ae813fd8SSepherosa Ziehau } 1595ae813fd8SSepherosa Ziehau 1596ae813fd8SSepherosa Ziehau static void 1597ae813fd8SSepherosa Ziehau nfe_stop(struct nfe_softc *sc) 1598ae813fd8SSepherosa Ziehau { 1599ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 160053f1d017SSepherosa Ziehau uint32_t rxtxctl = sc->rxtxctl_desc | NFE_RXTX_BIT2; 160153f1d017SSepherosa Ziehau int i; 1602ae813fd8SSepherosa Ziehau 1603c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 1604c0dcc88eSSepherosa Ziehau 1605ae813fd8SSepherosa Ziehau callout_stop(&sc->sc_tick_ch); 1606ae813fd8SSepherosa Ziehau 1607ae813fd8SSepherosa Ziehau ifp->if_timer = 0; 16089ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING; 16099ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd); 161004b9ef8dSSepherosa Ziehau sc->sc_flags &= ~NFE_F_IRQ_TIMER; 1611ae813fd8SSepherosa Ziehau 161253f1d017SSepherosa Ziehau #define WAITMAX 50000 161353f1d017SSepherosa Ziehau 1614d1daf8afSMatthew Dillon /* 161553f1d017SSepherosa Ziehau * Abort Tx 1616d1daf8afSMatthew Dillon */ 1617ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_TX_CTL, 0); 161853f1d017SSepherosa Ziehau for (i = 0; i < WAITMAX; ++i) { 161953f1d017SSepherosa Ziehau DELAY(100); 162053f1d017SSepherosa Ziehau if ((NFE_READ(sc, NFE_TX_STATUS) & NFE_TX_STATUS_BUSY) == 0) 162153f1d017SSepherosa Ziehau break; 162253f1d017SSepherosa Ziehau } 162353f1d017SSepherosa Ziehau if (i == WAITMAX) 162453f1d017SSepherosa Ziehau if_printf(ifp, "can't stop TX\n"); 162553f1d017SSepherosa Ziehau DELAY(100); 1626ae813fd8SSepherosa Ziehau 162753f1d017SSepherosa Ziehau /* 162853f1d017SSepherosa Ziehau * Disable Rx 162953f1d017SSepherosa Ziehau */ 1630ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RX_CTL, 0); 163153f1d017SSepherosa Ziehau for (i = 0; i < WAITMAX; ++i) { 163253f1d017SSepherosa Ziehau DELAY(100); 163353f1d017SSepherosa Ziehau if ((NFE_READ(sc, NFE_RX_STATUS) & NFE_RX_STATUS_BUSY) == 0) 163453f1d017SSepherosa Ziehau break; 163553f1d017SSepherosa Ziehau } 163653f1d017SSepherosa Ziehau if (i == WAITMAX) 163753f1d017SSepherosa Ziehau if_printf(ifp, "can't stop RX\n"); 163853f1d017SSepherosa Ziehau DELAY(100); 163953f1d017SSepherosa Ziehau 164053f1d017SSepherosa Ziehau #undef WAITMAX 164153f1d017SSepherosa Ziehau 164253f1d017SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | rxtxctl); 164353f1d017SSepherosa Ziehau DELAY(10); 164453f1d017SSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, rxtxctl); 1645ae813fd8SSepherosa Ziehau 1646ae813fd8SSepherosa Ziehau /* Disable interrupts */ 1647ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_MASK, 0); 1648ae813fd8SSepherosa Ziehau 1649ae813fd8SSepherosa Ziehau /* Reset Tx and Rx rings */ 1650ae813fd8SSepherosa Ziehau nfe_reset_tx_ring(sc, &sc->txq); 1651ae813fd8SSepherosa Ziehau nfe_reset_rx_ring(sc, &sc->rxq); 1652ae813fd8SSepherosa Ziehau } 1653ae813fd8SSepherosa Ziehau 1654ae813fd8SSepherosa Ziehau static int 1655ae813fd8SSepherosa Ziehau nfe_alloc_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1656ae813fd8SSepherosa Ziehau { 1657ae813fd8SSepherosa Ziehau int i, j, error, descsize; 1658244a9aa3SSepherosa Ziehau bus_dmamem_t dmem; 1659ae813fd8SSepherosa Ziehau void **desc; 1660ae813fd8SSepherosa Ziehau 166188d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1662da44240fSMatthew Dillon desc = (void *)&ring->desc64; 1663ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc64); 1664ae813fd8SSepherosa Ziehau } else { 1665da44240fSMatthew Dillon desc = (void *)&ring->desc32; 1666ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc32); 1667ae813fd8SSepherosa Ziehau } 1668ae813fd8SSepherosa Ziehau 1669ae813fd8SSepherosa Ziehau ring->bufsz = MCLBYTES; 1670ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 1671ae813fd8SSepherosa Ziehau 1672244a9aa3SSepherosa Ziehau error = bus_dmamem_coherent(sc->sc_dtag, PAGE_SIZE, 0, 1673244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1674ec9403d0SSepherosa Ziehau sc->sc_rx_ring_count * descsize, 1675244a9aa3SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem); 1676ae813fd8SSepherosa Ziehau if (error) { 1677ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1678244a9aa3SSepherosa Ziehau "could not create RX desc ring\n"); 1679ae813fd8SSepherosa Ziehau return error; 1680ae813fd8SSepherosa Ziehau } 1681244a9aa3SSepherosa Ziehau ring->tag = dmem.dmem_tag; 1682244a9aa3SSepherosa Ziehau ring->map = dmem.dmem_map; 1683244a9aa3SSepherosa Ziehau *desc = dmem.dmem_addr; 1684244a9aa3SSepherosa Ziehau ring->physaddr = dmem.dmem_busaddr; 1685ae813fd8SSepherosa Ziehau 168688d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_JUMBO_SUP) { 1687c58816edSSepherosa Ziehau ring->jbuf = 1688c58816edSSepherosa Ziehau kmalloc(sizeof(struct nfe_jbuf) * NFE_JPOOL_COUNT(sc), 168956fa71a9SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 169056fa71a9SSepherosa Ziehau 1691ae813fd8SSepherosa Ziehau error = nfe_jpool_alloc(sc, ring); 1692ae813fd8SSepherosa Ziehau if (error) { 1693ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1694ae813fd8SSepherosa Ziehau "could not allocate jumbo frames\n"); 169556fa71a9SSepherosa Ziehau kfree(ring->jbuf, M_DEVBUF); 169656fa71a9SSepherosa Ziehau ring->jbuf = NULL; 169756fa71a9SSepherosa Ziehau /* Allow jumbo frame allocation to fail */ 1698ae813fd8SSepherosa Ziehau } 1699ae813fd8SSepherosa Ziehau } 1700ae813fd8SSepherosa Ziehau 170156fa71a9SSepherosa Ziehau ring->data = kmalloc(sizeof(struct nfe_rx_data) * sc->sc_rx_ring_count, 170256fa71a9SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 170356fa71a9SSepherosa Ziehau 1704244a9aa3SSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 1705244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1706ae813fd8SSepherosa Ziehau NULL, NULL, 1707244a9aa3SSepherosa Ziehau MCLBYTES, 1, MCLBYTES, 1708244a9aa3SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK, 1709244a9aa3SSepherosa Ziehau &ring->data_tag); 1710ae813fd8SSepherosa Ziehau if (error) { 1711ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1712ae813fd8SSepherosa Ziehau "could not create RX mbuf DMA tag\n"); 1713ae813fd8SSepherosa Ziehau return error; 1714ae813fd8SSepherosa Ziehau } 1715ae813fd8SSepherosa Ziehau 1716ae813fd8SSepherosa Ziehau /* Create a spare RX mbuf DMA map */ 1717244a9aa3SSepherosa Ziehau error = bus_dmamap_create(ring->data_tag, BUS_DMA_WAITOK, 1718244a9aa3SSepherosa Ziehau &ring->data_tmpmap); 1719ae813fd8SSepherosa Ziehau if (error) { 1720ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1721ae813fd8SSepherosa Ziehau "could not create spare RX mbuf DMA map\n"); 1722ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 1723ae813fd8SSepherosa Ziehau ring->data_tag = NULL; 1724ae813fd8SSepherosa Ziehau return error; 1725ae813fd8SSepherosa Ziehau } 1726ae813fd8SSepherosa Ziehau 1727ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; i++) { 1728244a9aa3SSepherosa Ziehau error = bus_dmamap_create(ring->data_tag, BUS_DMA_WAITOK, 1729ae813fd8SSepherosa Ziehau &ring->data[i].map); 1730ae813fd8SSepherosa Ziehau if (error) { 1731ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1732ae813fd8SSepherosa Ziehau "could not create %dth RX mbuf DMA mapn", i); 1733ae813fd8SSepherosa Ziehau goto fail; 1734ae813fd8SSepherosa Ziehau } 1735ae813fd8SSepherosa Ziehau } 1736ae813fd8SSepherosa Ziehau return 0; 1737ae813fd8SSepherosa Ziehau fail: 1738ae813fd8SSepherosa Ziehau for (j = 0; j < i; ++j) 1739ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data[i].map); 1740ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data_tmpmap); 1741ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 1742ae813fd8SSepherosa Ziehau ring->data_tag = NULL; 1743ae813fd8SSepherosa Ziehau return error; 1744ae813fd8SSepherosa Ziehau } 1745ae813fd8SSepherosa Ziehau 1746ae813fd8SSepherosa Ziehau static void 1747ae813fd8SSepherosa Ziehau nfe_reset_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1748ae813fd8SSepherosa Ziehau { 1749ae813fd8SSepherosa Ziehau int i; 1750ae813fd8SSepherosa Ziehau 1751ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; i++) { 1752ae813fd8SSepherosa Ziehau struct nfe_rx_data *data = &ring->data[i]; 1753ae813fd8SSepherosa Ziehau 1754ae813fd8SSepherosa Ziehau if (data->m != NULL) { 17555dc1e30eSSepherosa Ziehau if ((sc->sc_flags & NFE_F_USE_JUMBO) == 0) 1756ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 1757ae813fd8SSepherosa Ziehau m_freem(data->m); 1758ae813fd8SSepherosa Ziehau data->m = NULL; 1759ae813fd8SSepherosa Ziehau } 1760ae813fd8SSepherosa Ziehau } 1761ae813fd8SSepherosa Ziehau 1762ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 1763ae813fd8SSepherosa Ziehau } 1764ae813fd8SSepherosa Ziehau 1765ae813fd8SSepherosa Ziehau static int 1766ae813fd8SSepherosa Ziehau nfe_init_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1767ae813fd8SSepherosa Ziehau { 1768ae813fd8SSepherosa Ziehau int i; 1769ae813fd8SSepherosa Ziehau 1770ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; ++i) { 1771ae813fd8SSepherosa Ziehau int error; 1772ae813fd8SSepherosa Ziehau 1773ae813fd8SSepherosa Ziehau /* XXX should use a function pointer */ 17745dc1e30eSSepherosa Ziehau if (sc->sc_flags & NFE_F_USE_JUMBO) 1775ae813fd8SSepherosa Ziehau error = nfe_newbuf_jumbo(sc, ring, i, 1); 1776ae813fd8SSepherosa Ziehau else 1777ae813fd8SSepherosa Ziehau error = nfe_newbuf_std(sc, ring, i, 1); 1778ae813fd8SSepherosa Ziehau if (error) { 1779ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1780ae813fd8SSepherosa Ziehau "could not allocate RX buffer\n"); 1781ae813fd8SSepherosa Ziehau return error; 1782ae813fd8SSepherosa Ziehau } 1783ae813fd8SSepherosa Ziehau nfe_set_ready_rxdesc(sc, ring, i); 1784ae813fd8SSepherosa Ziehau } 1785ae813fd8SSepherosa Ziehau return 0; 1786ae813fd8SSepherosa Ziehau } 1787ae813fd8SSepherosa Ziehau 1788ae813fd8SSepherosa Ziehau static void 1789ae813fd8SSepherosa Ziehau nfe_free_rx_ring(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1790ae813fd8SSepherosa Ziehau { 1791ae813fd8SSepherosa Ziehau if (ring->data_tag != NULL) { 1792ae813fd8SSepherosa Ziehau struct nfe_rx_data *data; 1793ae813fd8SSepherosa Ziehau int i; 1794ae813fd8SSepherosa Ziehau 1795ec9403d0SSepherosa Ziehau for (i = 0; i < sc->sc_rx_ring_count; i++) { 1796ae813fd8SSepherosa Ziehau data = &ring->data[i]; 1797ae813fd8SSepherosa Ziehau 1798ae813fd8SSepherosa Ziehau if (data->m != NULL) { 1799ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 1800ae813fd8SSepherosa Ziehau m_freem(data->m); 1801ae813fd8SSepherosa Ziehau } 1802ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, data->map); 1803ae813fd8SSepherosa Ziehau } 1804ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data_tmpmap); 1805ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 1806ae813fd8SSepherosa Ziehau } 1807ae813fd8SSepherosa Ziehau 1808ae813fd8SSepherosa Ziehau nfe_jpool_free(sc, ring); 1809ae813fd8SSepherosa Ziehau 1810a455c52eSSepherosa Ziehau if (ring->jbuf != NULL) 1811a455c52eSSepherosa Ziehau kfree(ring->jbuf, M_DEVBUF); 1812a455c52eSSepherosa Ziehau if (ring->data != NULL) 1813a455c52eSSepherosa Ziehau kfree(ring->data, M_DEVBUF); 1814a455c52eSSepherosa Ziehau 1815ae813fd8SSepherosa Ziehau if (ring->tag != NULL) { 1816ae813fd8SSepherosa Ziehau void *desc; 1817ae813fd8SSepherosa Ziehau 181888d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 1819ae813fd8SSepherosa Ziehau desc = ring->desc64; 1820ae813fd8SSepherosa Ziehau else 1821ae813fd8SSepherosa Ziehau desc = ring->desc32; 1822ae813fd8SSepherosa Ziehau 1823ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->tag, ring->map); 1824ae813fd8SSepherosa Ziehau bus_dmamem_free(ring->tag, desc, ring->map); 1825ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->tag); 1826ae813fd8SSepherosa Ziehau } 1827ae813fd8SSepherosa Ziehau } 1828ae813fd8SSepherosa Ziehau 1829ae813fd8SSepherosa Ziehau static struct nfe_jbuf * 1830ae813fd8SSepherosa Ziehau nfe_jalloc(struct nfe_softc *sc) 1831ae813fd8SSepherosa Ziehau { 1832ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 1833ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf; 1834ae813fd8SSepherosa Ziehau 1835ae813fd8SSepherosa Ziehau lwkt_serialize_enter(&sc->sc_jbuf_serializer); 1836ae813fd8SSepherosa Ziehau 1837ae813fd8SSepherosa Ziehau jbuf = SLIST_FIRST(&sc->rxq.jfreelist); 1838ae813fd8SSepherosa Ziehau if (jbuf != NULL) { 1839ae813fd8SSepherosa Ziehau SLIST_REMOVE_HEAD(&sc->rxq.jfreelist, jnext); 1840ae813fd8SSepherosa Ziehau jbuf->inuse = 1; 1841ae813fd8SSepherosa Ziehau } else { 1842ae813fd8SSepherosa Ziehau if_printf(ifp, "no free jumbo buffer\n"); 1843ae813fd8SSepherosa Ziehau } 1844ae813fd8SSepherosa Ziehau 1845ae813fd8SSepherosa Ziehau lwkt_serialize_exit(&sc->sc_jbuf_serializer); 1846ae813fd8SSepherosa Ziehau 1847ae813fd8SSepherosa Ziehau return jbuf; 1848ae813fd8SSepherosa Ziehau } 1849ae813fd8SSepherosa Ziehau 1850ae813fd8SSepherosa Ziehau static void 1851ae813fd8SSepherosa Ziehau nfe_jfree(void *arg) 1852ae813fd8SSepherosa Ziehau { 1853ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf = arg; 1854ae813fd8SSepherosa Ziehau struct nfe_softc *sc = jbuf->sc; 1855ae813fd8SSepherosa Ziehau struct nfe_rx_ring *ring = jbuf->ring; 1856ae813fd8SSepherosa Ziehau 1857ae813fd8SSepherosa Ziehau if (&ring->jbuf[jbuf->slot] != jbuf) 1858ed20d0e3SSascha Wildner panic("%s: free wrong jumbo buffer", __func__); 1859ae813fd8SSepherosa Ziehau else if (jbuf->inuse == 0) 1860ed20d0e3SSascha Wildner panic("%s: jumbo buffer already freed", __func__); 1861ae813fd8SSepherosa Ziehau 1862ae813fd8SSepherosa Ziehau lwkt_serialize_enter(&sc->sc_jbuf_serializer); 1863ae813fd8SSepherosa Ziehau atomic_subtract_int(&jbuf->inuse, 1); 1864ae813fd8SSepherosa Ziehau if (jbuf->inuse == 0) 1865ae813fd8SSepherosa Ziehau SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 1866ae813fd8SSepherosa Ziehau lwkt_serialize_exit(&sc->sc_jbuf_serializer); 1867ae813fd8SSepherosa Ziehau } 1868ae813fd8SSepherosa Ziehau 1869ae813fd8SSepherosa Ziehau static void 1870ae813fd8SSepherosa Ziehau nfe_jref(void *arg) 1871ae813fd8SSepherosa Ziehau { 1872ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf = arg; 1873ae813fd8SSepherosa Ziehau struct nfe_rx_ring *ring = jbuf->ring; 1874ae813fd8SSepherosa Ziehau 1875ae813fd8SSepherosa Ziehau if (&ring->jbuf[jbuf->slot] != jbuf) 1876ed20d0e3SSascha Wildner panic("%s: ref wrong jumbo buffer", __func__); 1877ae813fd8SSepherosa Ziehau else if (jbuf->inuse == 0) 1878ed20d0e3SSascha Wildner panic("%s: jumbo buffer already freed", __func__); 1879ae813fd8SSepherosa Ziehau 188006406609SSepherosa Ziehau atomic_add_int(&jbuf->inuse, 1); 1881ae813fd8SSepherosa Ziehau } 1882ae813fd8SSepherosa Ziehau 1883ae813fd8SSepherosa Ziehau static int 1884ae813fd8SSepherosa Ziehau nfe_jpool_alloc(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1885ae813fd8SSepherosa Ziehau { 1886ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf; 1887244a9aa3SSepherosa Ziehau bus_dmamem_t dmem; 1888ae813fd8SSepherosa Ziehau bus_addr_t physaddr; 1889ae813fd8SSepherosa Ziehau caddr_t buf; 1890ae813fd8SSepherosa Ziehau int i, error; 1891ae813fd8SSepherosa Ziehau 1892ae813fd8SSepherosa Ziehau /* 1893ae813fd8SSepherosa Ziehau * Allocate a big chunk of DMA'able memory. 1894ae813fd8SSepherosa Ziehau */ 1895244a9aa3SSepherosa Ziehau error = bus_dmamem_coherent(sc->sc_dtag, PAGE_SIZE, 0, 1896244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1897c58816edSSepherosa Ziehau NFE_JPOOL_SIZE(sc), 1898244a9aa3SSepherosa Ziehau BUS_DMA_WAITOK, &dmem); 1899ae813fd8SSepherosa Ziehau if (error) { 1900ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1901244a9aa3SSepherosa Ziehau "could not create jumbo buffer\n"); 1902ae813fd8SSepherosa Ziehau return error; 1903ae813fd8SSepherosa Ziehau } 1904244a9aa3SSepherosa Ziehau ring->jtag = dmem.dmem_tag; 1905244a9aa3SSepherosa Ziehau ring->jmap = dmem.dmem_map; 1906244a9aa3SSepherosa Ziehau ring->jpool = dmem.dmem_addr; 1907244a9aa3SSepherosa Ziehau physaddr = dmem.dmem_busaddr; 1908ae813fd8SSepherosa Ziehau 1909ae813fd8SSepherosa Ziehau /* ..and split it into 9KB chunks */ 1910ae813fd8SSepherosa Ziehau SLIST_INIT(&ring->jfreelist); 1911ae813fd8SSepherosa Ziehau 1912ae813fd8SSepherosa Ziehau buf = ring->jpool; 1913c58816edSSepherosa Ziehau for (i = 0; i < NFE_JPOOL_COUNT(sc); i++) { 1914ae813fd8SSepherosa Ziehau jbuf = &ring->jbuf[i]; 1915ae813fd8SSepherosa Ziehau 1916ae813fd8SSepherosa Ziehau jbuf->sc = sc; 1917ae813fd8SSepherosa Ziehau jbuf->ring = ring; 1918ae813fd8SSepherosa Ziehau jbuf->inuse = 0; 1919ae813fd8SSepherosa Ziehau jbuf->slot = i; 1920ae813fd8SSepherosa Ziehau jbuf->buf = buf; 1921ae813fd8SSepherosa Ziehau jbuf->physaddr = physaddr; 1922ae813fd8SSepherosa Ziehau 1923ae813fd8SSepherosa Ziehau SLIST_INSERT_HEAD(&ring->jfreelist, jbuf, jnext); 1924ae813fd8SSepherosa Ziehau 1925ae813fd8SSepherosa Ziehau buf += NFE_JBYTES; 1926ae813fd8SSepherosa Ziehau physaddr += NFE_JBYTES; 1927ae813fd8SSepherosa Ziehau } 1928ae813fd8SSepherosa Ziehau 1929ae813fd8SSepherosa Ziehau return 0; 1930ae813fd8SSepherosa Ziehau } 1931ae813fd8SSepherosa Ziehau 1932ae813fd8SSepherosa Ziehau static void 1933ae813fd8SSepherosa Ziehau nfe_jpool_free(struct nfe_softc *sc, struct nfe_rx_ring *ring) 1934ae813fd8SSepherosa Ziehau { 1935ae813fd8SSepherosa Ziehau if (ring->jtag != NULL) { 1936ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->jtag, ring->jmap); 1937ae813fd8SSepherosa Ziehau bus_dmamem_free(ring->jtag, ring->jpool, ring->jmap); 1938ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->jtag); 1939ae813fd8SSepherosa Ziehau } 1940ae813fd8SSepherosa Ziehau } 1941ae813fd8SSepherosa Ziehau 1942ae813fd8SSepherosa Ziehau static int 1943ae813fd8SSepherosa Ziehau nfe_alloc_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 1944ae813fd8SSepherosa Ziehau { 1945ae813fd8SSepherosa Ziehau int i, j, error, descsize; 1946244a9aa3SSepherosa Ziehau bus_dmamem_t dmem; 1947ae813fd8SSepherosa Ziehau void **desc; 1948ae813fd8SSepherosa Ziehau 194988d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 1950da44240fSMatthew Dillon desc = (void *)&ring->desc64; 1951ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc64); 1952ae813fd8SSepherosa Ziehau } else { 1953da44240fSMatthew Dillon desc = (void *)&ring->desc32; 1954ae813fd8SSepherosa Ziehau descsize = sizeof(struct nfe_desc32); 1955ae813fd8SSepherosa Ziehau } 1956ae813fd8SSepherosa Ziehau 1957ae813fd8SSepherosa Ziehau ring->queued = 0; 1958ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 1959ae813fd8SSepherosa Ziehau 1960244a9aa3SSepherosa Ziehau error = bus_dmamem_coherent(sc->sc_dtag, PAGE_SIZE, 0, 1961244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1962b4633098SSepherosa Ziehau sc->sc_tx_ring_count * descsize, 1963244a9aa3SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem); 1964ae813fd8SSepherosa Ziehau if (error) { 1965ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1966244a9aa3SSepherosa Ziehau "could not create TX desc ring\n"); 1967ae813fd8SSepherosa Ziehau return error; 1968ae813fd8SSepherosa Ziehau } 1969244a9aa3SSepherosa Ziehau ring->tag = dmem.dmem_tag; 1970244a9aa3SSepherosa Ziehau ring->map = dmem.dmem_map; 1971244a9aa3SSepherosa Ziehau *desc = dmem.dmem_addr; 1972244a9aa3SSepherosa Ziehau ring->physaddr = dmem.dmem_busaddr; 1973ae813fd8SSepherosa Ziehau 1974b4633098SSepherosa Ziehau ring->data = kmalloc(sizeof(struct nfe_tx_data) * sc->sc_tx_ring_count, 1975b4633098SSepherosa Ziehau M_DEVBUF, M_WAITOK | M_ZERO); 1976b4633098SSepherosa Ziehau 1977244a9aa3SSepherosa Ziehau error = bus_dma_tag_create(sc->sc_dtag, 1, 0, 1978244a9aa3SSepherosa Ziehau BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 1979ae813fd8SSepherosa Ziehau NULL, NULL, 1980244a9aa3SSepherosa Ziehau NFE_JBYTES, NFE_MAX_SCATTER, MCLBYTES, 198190a9e482SSepherosa Ziehau BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 1982244a9aa3SSepherosa Ziehau &ring->data_tag); 1983ae813fd8SSepherosa Ziehau if (error) { 1984ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1985ae813fd8SSepherosa Ziehau "could not create TX buf DMA tag\n"); 1986ae813fd8SSepherosa Ziehau return error; 1987ae813fd8SSepherosa Ziehau } 1988ae813fd8SSepherosa Ziehau 1989b4633098SSepherosa Ziehau for (i = 0; i < sc->sc_tx_ring_count; i++) { 1990244a9aa3SSepherosa Ziehau error = bus_dmamap_create(ring->data_tag, 199190a9e482SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, 1992ae813fd8SSepherosa Ziehau &ring->data[i].map); 1993ae813fd8SSepherosa Ziehau if (error) { 1994ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 1995ae813fd8SSepherosa Ziehau "could not create %dth TX buf DMA map\n", i); 1996ae813fd8SSepherosa Ziehau goto fail; 1997ae813fd8SSepherosa Ziehau } 1998ae813fd8SSepherosa Ziehau } 1999ae813fd8SSepherosa Ziehau 2000ae813fd8SSepherosa Ziehau return 0; 2001ae813fd8SSepherosa Ziehau fail: 2002ae813fd8SSepherosa Ziehau for (j = 0; j < i; ++j) 2003ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, ring->data[i].map); 2004ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 2005ae813fd8SSepherosa Ziehau ring->data_tag = NULL; 2006ae813fd8SSepherosa Ziehau return error; 2007ae813fd8SSepherosa Ziehau } 2008ae813fd8SSepherosa Ziehau 2009ae813fd8SSepherosa Ziehau static void 2010ae813fd8SSepherosa Ziehau nfe_reset_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 2011ae813fd8SSepherosa Ziehau { 2012ae813fd8SSepherosa Ziehau int i; 2013ae813fd8SSepherosa Ziehau 2014b4633098SSepherosa Ziehau for (i = 0; i < sc->sc_tx_ring_count; i++) { 2015ae813fd8SSepherosa Ziehau struct nfe_tx_data *data = &ring->data[i]; 2016ae813fd8SSepherosa Ziehau 201788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 2018ae813fd8SSepherosa Ziehau ring->desc64[i].flags = 0; 2019ae813fd8SSepherosa Ziehau else 2020ae813fd8SSepherosa Ziehau ring->desc32[i].flags = 0; 2021ae813fd8SSepherosa Ziehau 2022ae813fd8SSepherosa Ziehau if (data->m != NULL) { 2023ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 2024ae813fd8SSepherosa Ziehau m_freem(data->m); 2025ae813fd8SSepherosa Ziehau data->m = NULL; 2026ae813fd8SSepherosa Ziehau } 2027ae813fd8SSepherosa Ziehau } 2028ae813fd8SSepherosa Ziehau 2029ae813fd8SSepherosa Ziehau ring->queued = 0; 2030ae813fd8SSepherosa Ziehau ring->cur = ring->next = 0; 2031ae813fd8SSepherosa Ziehau } 2032ae813fd8SSepherosa Ziehau 2033ae813fd8SSepherosa Ziehau static int 2034ae813fd8SSepherosa Ziehau nfe_init_tx_ring(struct nfe_softc *sc __unused, 2035ae813fd8SSepherosa Ziehau struct nfe_tx_ring *ring __unused) 2036ae813fd8SSepherosa Ziehau { 2037ae813fd8SSepherosa Ziehau return 0; 2038ae813fd8SSepherosa Ziehau } 2039ae813fd8SSepherosa Ziehau 2040ae813fd8SSepherosa Ziehau static void 2041ae813fd8SSepherosa Ziehau nfe_free_tx_ring(struct nfe_softc *sc, struct nfe_tx_ring *ring) 2042ae813fd8SSepherosa Ziehau { 2043ae813fd8SSepherosa Ziehau if (ring->data_tag != NULL) { 2044ae813fd8SSepherosa Ziehau struct nfe_tx_data *data; 2045ae813fd8SSepherosa Ziehau int i; 2046ae813fd8SSepherosa Ziehau 2047b4633098SSepherosa Ziehau for (i = 0; i < sc->sc_tx_ring_count; ++i) { 2048ae813fd8SSepherosa Ziehau data = &ring->data[i]; 2049ae813fd8SSepherosa Ziehau 2050ae813fd8SSepherosa Ziehau if (data->m != NULL) { 2051ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 2052ae813fd8SSepherosa Ziehau m_freem(data->m); 2053ae813fd8SSepherosa Ziehau } 2054ae813fd8SSepherosa Ziehau bus_dmamap_destroy(ring->data_tag, data->map); 2055ae813fd8SSepherosa Ziehau } 2056ae813fd8SSepherosa Ziehau 2057ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->data_tag); 2058ae813fd8SSepherosa Ziehau } 2059ae813fd8SSepherosa Ziehau 2060b4633098SSepherosa Ziehau if (ring->data != NULL) 2061b4633098SSepherosa Ziehau kfree(ring->data, M_DEVBUF); 2062b4633098SSepherosa Ziehau 2063ae813fd8SSepherosa Ziehau if (ring->tag != NULL) { 2064ae813fd8SSepherosa Ziehau void *desc; 2065ae813fd8SSepherosa Ziehau 206688d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) 2067ae813fd8SSepherosa Ziehau desc = ring->desc64; 2068ae813fd8SSepherosa Ziehau else 2069ae813fd8SSepherosa Ziehau desc = ring->desc32; 2070ae813fd8SSepherosa Ziehau 2071ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->tag, ring->map); 2072ae813fd8SSepherosa Ziehau bus_dmamem_free(ring->tag, desc, ring->map); 2073ae813fd8SSepherosa Ziehau bus_dma_tag_destroy(ring->tag); 2074ae813fd8SSepherosa Ziehau } 2075ae813fd8SSepherosa Ziehau } 2076ae813fd8SSepherosa Ziehau 2077ae813fd8SSepherosa Ziehau static int 2078ae813fd8SSepherosa Ziehau nfe_ifmedia_upd(struct ifnet *ifp) 2079ae813fd8SSepherosa Ziehau { 2080ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 2081ae813fd8SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2082ae813fd8SSepherosa Ziehau 2083c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 2084c0dcc88eSSepherosa Ziehau 2085ae813fd8SSepherosa Ziehau if (mii->mii_instance != 0) { 2086ae813fd8SSepherosa Ziehau struct mii_softc *miisc; 2087ae813fd8SSepherosa Ziehau 2088ae813fd8SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 2089ae813fd8SSepherosa Ziehau mii_phy_reset(miisc); 2090ae813fd8SSepherosa Ziehau } 2091ae813fd8SSepherosa Ziehau mii_mediachg(mii); 2092ae813fd8SSepherosa Ziehau 2093ae813fd8SSepherosa Ziehau return 0; 2094ae813fd8SSepherosa Ziehau } 2095ae813fd8SSepherosa Ziehau 2096ae813fd8SSepherosa Ziehau static void 2097ae813fd8SSepherosa Ziehau nfe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 2098ae813fd8SSepherosa Ziehau { 2099ae813fd8SSepherosa Ziehau struct nfe_softc *sc = ifp->if_softc; 2100ae813fd8SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2101ae813fd8SSepherosa Ziehau 2102c0dcc88eSSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 2103c0dcc88eSSepherosa Ziehau 2104ae813fd8SSepherosa Ziehau mii_pollstat(mii); 2105ae813fd8SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 2106ae813fd8SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 2107ae813fd8SSepherosa Ziehau } 2108ae813fd8SSepherosa Ziehau 2109ae813fd8SSepherosa Ziehau static void 2110ae813fd8SSepherosa Ziehau nfe_setmulti(struct nfe_softc *sc) 2111ae813fd8SSepherosa Ziehau { 2112ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2113ae813fd8SSepherosa Ziehau struct ifmultiaddr *ifma; 2114ae813fd8SSepherosa Ziehau uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; 2115ae813fd8SSepherosa Ziehau uint32_t filter = NFE_RXFILTER_MAGIC; 2116ae813fd8SSepherosa Ziehau int i; 2117ae813fd8SSepherosa Ziehau 2118ae813fd8SSepherosa Ziehau if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 2119ae813fd8SSepherosa Ziehau bzero(addr, ETHER_ADDR_LEN); 2120ae813fd8SSepherosa Ziehau bzero(mask, ETHER_ADDR_LEN); 2121ae813fd8SSepherosa Ziehau goto done; 2122ae813fd8SSepherosa Ziehau } 2123ae813fd8SSepherosa Ziehau 2124ae813fd8SSepherosa Ziehau bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); 2125ae813fd8SSepherosa Ziehau bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); 2126ae813fd8SSepherosa Ziehau 2127441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2128ae813fd8SSepherosa Ziehau caddr_t maddr; 2129ae813fd8SSepherosa Ziehau 2130ae813fd8SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 2131ae813fd8SSepherosa Ziehau continue; 2132ae813fd8SSepherosa Ziehau 2133ae813fd8SSepherosa Ziehau maddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2134ae813fd8SSepherosa Ziehau for (i = 0; i < ETHER_ADDR_LEN; i++) { 2135ae813fd8SSepherosa Ziehau addr[i] &= maddr[i]; 2136ae813fd8SSepherosa Ziehau mask[i] &= ~maddr[i]; 2137ae813fd8SSepherosa Ziehau } 2138ae813fd8SSepherosa Ziehau } 2139ae813fd8SSepherosa Ziehau 2140ae813fd8SSepherosa Ziehau for (i = 0; i < ETHER_ADDR_LEN; i++) 2141ae813fd8SSepherosa Ziehau mask[i] |= addr[i]; 2142ae813fd8SSepherosa Ziehau 2143ae813fd8SSepherosa Ziehau done: 2144ae813fd8SSepherosa Ziehau addr[0] |= 0x01; /* make sure multicast bit is set */ 2145ae813fd8SSepherosa Ziehau 2146ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIADDR_HI, 2147ae813fd8SSepherosa Ziehau addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2148ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIADDR_LO, 2149ae813fd8SSepherosa Ziehau addr[5] << 8 | addr[4]); 2150ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIMASK_HI, 2151ae813fd8SSepherosa Ziehau mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); 2152ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MULTIMASK_LO, 2153ae813fd8SSepherosa Ziehau mask[5] << 8 | mask[4]); 2154ae813fd8SSepherosa Ziehau 2155ae813fd8SSepherosa Ziehau filter |= (ifp->if_flags & IFF_PROMISC) ? NFE_PROMISC : NFE_U2M; 2156ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_RXFILTER, filter); 2157ae813fd8SSepherosa Ziehau } 2158ae813fd8SSepherosa Ziehau 2159ae813fd8SSepherosa Ziehau static void 2160ae813fd8SSepherosa Ziehau nfe_get_macaddr(struct nfe_softc *sc, uint8_t *addr) 2161ae813fd8SSepherosa Ziehau { 2162ece56005SSepherosa Ziehau uint32_t lo, hi; 2163ae813fd8SSepherosa Ziehau 2164ece56005SSepherosa Ziehau lo = NFE_READ(sc, NFE_MACADDR_LO); 2165ece56005SSepherosa Ziehau hi = NFE_READ(sc, NFE_MACADDR_HI); 2166ece56005SSepherosa Ziehau if (sc->sc_caps & NFE_FIX_EADDR) { 2167ece56005SSepherosa Ziehau addr[0] = (lo >> 8) & 0xff; 2168ece56005SSepherosa Ziehau addr[1] = (lo & 0xff); 2169ae813fd8SSepherosa Ziehau 2170ece56005SSepherosa Ziehau addr[2] = (hi >> 24) & 0xff; 2171ece56005SSepherosa Ziehau addr[3] = (hi >> 16) & 0xff; 2172ece56005SSepherosa Ziehau addr[4] = (hi >> 8) & 0xff; 2173ece56005SSepherosa Ziehau addr[5] = (hi & 0xff); 2174ece56005SSepherosa Ziehau } else { 2175ece56005SSepherosa Ziehau addr[0] = (hi & 0xff); 2176ece56005SSepherosa Ziehau addr[1] = (hi >> 8) & 0xff; 2177ece56005SSepherosa Ziehau addr[2] = (hi >> 16) & 0xff; 2178ece56005SSepherosa Ziehau addr[3] = (hi >> 24) & 0xff; 2179ece56005SSepherosa Ziehau 2180ece56005SSepherosa Ziehau addr[4] = (lo & 0xff); 2181ece56005SSepherosa Ziehau addr[5] = (lo >> 8) & 0xff; 2182ece56005SSepherosa Ziehau } 2183ae813fd8SSepherosa Ziehau } 2184ae813fd8SSepherosa Ziehau 2185ae813fd8SSepherosa Ziehau static void 2186ae813fd8SSepherosa Ziehau nfe_set_macaddr(struct nfe_softc *sc, const uint8_t *addr) 2187ae813fd8SSepherosa Ziehau { 2188ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_LO, 2189ae813fd8SSepherosa Ziehau addr[5] << 8 | addr[4]); 2190ae813fd8SSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_HI, 2191ae813fd8SSepherosa Ziehau addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2192ae813fd8SSepherosa Ziehau } 2193ae813fd8SSepherosa Ziehau 2194ae813fd8SSepherosa Ziehau static void 2195ae813fd8SSepherosa Ziehau nfe_tick(void *arg) 2196ae813fd8SSepherosa Ziehau { 2197ae813fd8SSepherosa Ziehau struct nfe_softc *sc = arg; 2198ae813fd8SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 2199ae813fd8SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->sc_miibus); 2200ae813fd8SSepherosa Ziehau 2201ae813fd8SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2202ae813fd8SSepherosa Ziehau 2203ae813fd8SSepherosa Ziehau mii_tick(mii); 2204ae813fd8SSepherosa Ziehau callout_reset(&sc->sc_tick_ch, hz, nfe_tick, sc); 2205ae813fd8SSepherosa Ziehau 2206ae813fd8SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2207ae813fd8SSepherosa Ziehau } 2208ae813fd8SSepherosa Ziehau 2209ae813fd8SSepherosa Ziehau static int 2210ae813fd8SSepherosa Ziehau nfe_newbuf_std(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx, 2211ae813fd8SSepherosa Ziehau int wait) 2212ae813fd8SSepherosa Ziehau { 2213ae813fd8SSepherosa Ziehau struct nfe_rx_data *data = &ring->data[idx]; 2214ae813fd8SSepherosa Ziehau bus_dma_segment_t seg; 2215ae813fd8SSepherosa Ziehau bus_dmamap_t map; 2216ae813fd8SSepherosa Ziehau struct mbuf *m; 2217b6bb439dSSepherosa Ziehau int nsegs, error; 2218ae813fd8SSepherosa Ziehau 2219ae813fd8SSepherosa Ziehau m = m_getcl(wait ? MB_WAIT : MB_DONTWAIT, MT_DATA, M_PKTHDR); 2220ae813fd8SSepherosa Ziehau if (m == NULL) 2221ae813fd8SSepherosa Ziehau return ENOBUFS; 2222ae813fd8SSepherosa Ziehau m->m_len = m->m_pkthdr.len = MCLBYTES; 2223f81efabeSMatthew Dillon 2224f81efabeSMatthew Dillon /* 2225f81efabeSMatthew Dillon * Aligning the payload improves access times. 2226f81efabeSMatthew Dillon */ 2227f81efabeSMatthew Dillon if (sc->sc_caps & NFE_WORDALIGN) 2228f81efabeSMatthew Dillon m_adj(m, ETHER_ALIGN); 2229ae813fd8SSepherosa Ziehau 2230b6bb439dSSepherosa Ziehau error = bus_dmamap_load_mbuf_segment(ring->data_tag, ring->data_tmpmap, 2231b6bb439dSSepherosa Ziehau m, &seg, 1, &nsegs, BUS_DMA_NOWAIT); 2232b6bb439dSSepherosa Ziehau if (error) { 2233ae813fd8SSepherosa Ziehau m_freem(m); 223477cdd7f0SSepherosa Ziehau if (wait) { 223577cdd7f0SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 223677cdd7f0SSepherosa Ziehau "could map RX mbuf %d\n", error); 223777cdd7f0SSepherosa Ziehau } 2238ae813fd8SSepherosa Ziehau return error; 2239ae813fd8SSepherosa Ziehau } 2240ae813fd8SSepherosa Ziehau 2241e679c149SSepherosa Ziehau if (data->m != NULL) { 2242e679c149SSepherosa Ziehau /* Sync and unload originally mapped mbuf */ 2243e679c149SSepherosa Ziehau bus_dmamap_sync(ring->data_tag, data->map, 2244e679c149SSepherosa Ziehau BUS_DMASYNC_POSTREAD); 2245ae813fd8SSepherosa Ziehau bus_dmamap_unload(ring->data_tag, data->map); 2246e679c149SSepherosa Ziehau } 2247ae813fd8SSepherosa Ziehau 2248ae813fd8SSepherosa Ziehau /* Swap this DMA map with tmp DMA map */ 2249ae813fd8SSepherosa Ziehau map = data->map; 2250ae813fd8SSepherosa Ziehau data->map = ring->data_tmpmap; 2251ae813fd8SSepherosa Ziehau ring->data_tmpmap = map; 2252ae813fd8SSepherosa Ziehau 2253ae813fd8SSepherosa Ziehau /* Caller is assumed to have collected the old mbuf */ 2254ae813fd8SSepherosa Ziehau data->m = m; 2255ae813fd8SSepherosa Ziehau 2256ae813fd8SSepherosa Ziehau nfe_set_paddr_rxdesc(sc, ring, idx, seg.ds_addr); 2257ae813fd8SSepherosa Ziehau return 0; 2258ae813fd8SSepherosa Ziehau } 2259ae813fd8SSepherosa Ziehau 2260ae813fd8SSepherosa Ziehau static int 2261ae813fd8SSepherosa Ziehau nfe_newbuf_jumbo(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx, 2262ae813fd8SSepherosa Ziehau int wait) 2263ae813fd8SSepherosa Ziehau { 2264ae813fd8SSepherosa Ziehau struct nfe_rx_data *data = &ring->data[idx]; 2265ae813fd8SSepherosa Ziehau struct nfe_jbuf *jbuf; 2266ae813fd8SSepherosa Ziehau struct mbuf *m; 2267ae813fd8SSepherosa Ziehau 2268ae813fd8SSepherosa Ziehau MGETHDR(m, wait ? MB_WAIT : MB_DONTWAIT, MT_DATA); 2269ae813fd8SSepherosa Ziehau if (m == NULL) 2270ae813fd8SSepherosa Ziehau return ENOBUFS; 2271ae813fd8SSepherosa Ziehau 2272ae813fd8SSepherosa Ziehau jbuf = nfe_jalloc(sc); 2273ae813fd8SSepherosa Ziehau if (jbuf == NULL) { 2274ae813fd8SSepherosa Ziehau m_freem(m); 2275ae813fd8SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "jumbo allocation failed " 2276ae813fd8SSepherosa Ziehau "-- packet dropped!\n"); 2277ae813fd8SSepherosa Ziehau return ENOBUFS; 2278ae813fd8SSepherosa Ziehau } 2279ae813fd8SSepherosa Ziehau 2280ae813fd8SSepherosa Ziehau m->m_ext.ext_arg = jbuf; 2281ae813fd8SSepherosa Ziehau m->m_ext.ext_buf = jbuf->buf; 2282ae813fd8SSepherosa Ziehau m->m_ext.ext_free = nfe_jfree; 2283ae813fd8SSepherosa Ziehau m->m_ext.ext_ref = nfe_jref; 2284ae813fd8SSepherosa Ziehau m->m_ext.ext_size = NFE_JBYTES; 2285ae813fd8SSepherosa Ziehau 2286ae813fd8SSepherosa Ziehau m->m_data = m->m_ext.ext_buf; 2287ae813fd8SSepherosa Ziehau m->m_flags |= M_EXT; 2288ae813fd8SSepherosa Ziehau m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 2289f81efabeSMatthew Dillon 2290f81efabeSMatthew Dillon /* 2291f81efabeSMatthew Dillon * Aligning the payload improves access times. 2292f81efabeSMatthew Dillon */ 2293f81efabeSMatthew Dillon if (sc->sc_caps & NFE_WORDALIGN) 2294f81efabeSMatthew Dillon m_adj(m, ETHER_ALIGN); 2295ae813fd8SSepherosa Ziehau 2296ae813fd8SSepherosa Ziehau /* Caller is assumed to have collected the old mbuf */ 2297ae813fd8SSepherosa Ziehau data->m = m; 2298ae813fd8SSepherosa Ziehau 2299ae813fd8SSepherosa Ziehau nfe_set_paddr_rxdesc(sc, ring, idx, jbuf->physaddr); 2300ae813fd8SSepherosa Ziehau return 0; 2301ae813fd8SSepherosa Ziehau } 2302ae813fd8SSepherosa Ziehau 2303ae813fd8SSepherosa Ziehau static void 2304ae813fd8SSepherosa Ziehau nfe_set_paddr_rxdesc(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx, 2305ae813fd8SSepherosa Ziehau bus_addr_t physaddr) 2306ae813fd8SSepherosa Ziehau { 230788d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 2308ae813fd8SSepherosa Ziehau struct nfe_desc64 *desc64 = &ring->desc64[idx]; 2309ae813fd8SSepherosa Ziehau 23107752918dSSepherosa Ziehau desc64->physaddr[0] = htole32(NFE_ADDR_HI(physaddr)); 23117752918dSSepherosa Ziehau desc64->physaddr[1] = htole32(NFE_ADDR_LO(physaddr)); 2312ae813fd8SSepherosa Ziehau } else { 2313ae813fd8SSepherosa Ziehau struct nfe_desc32 *desc32 = &ring->desc32[idx]; 2314ae813fd8SSepherosa Ziehau 2315ae813fd8SSepherosa Ziehau desc32->physaddr = htole32(physaddr); 2316ae813fd8SSepherosa Ziehau } 2317ae813fd8SSepherosa Ziehau } 2318ae813fd8SSepherosa Ziehau 2319ae813fd8SSepherosa Ziehau static void 2320ae813fd8SSepherosa Ziehau nfe_set_ready_rxdesc(struct nfe_softc *sc, struct nfe_rx_ring *ring, int idx) 2321ae813fd8SSepherosa Ziehau { 232288d487c3SSepherosa Ziehau if (sc->sc_caps & NFE_40BIT_ADDR) { 2323ae813fd8SSepherosa Ziehau struct nfe_desc64 *desc64 = &ring->desc64[idx]; 2324ae813fd8SSepherosa Ziehau 2325ae813fd8SSepherosa Ziehau desc64->length = htole16(ring->bufsz); 2326ae813fd8SSepherosa Ziehau desc64->flags = htole16(NFE_RX_READY); 2327ae813fd8SSepherosa Ziehau } else { 2328ae813fd8SSepherosa Ziehau struct nfe_desc32 *desc32 = &ring->desc32[idx]; 2329ae813fd8SSepherosa Ziehau 2330ae813fd8SSepherosa Ziehau desc32->length = htole16(ring->bufsz); 2331ae813fd8SSepherosa Ziehau desc32->flags = htole16(NFE_RX_READY); 2332ae813fd8SSepherosa Ziehau } 2333ae813fd8SSepherosa Ziehau } 2334ec9403d0SSepherosa Ziehau 2335ec9403d0SSepherosa Ziehau static int 2336ec9403d0SSepherosa Ziehau nfe_sysctl_imtime(SYSCTL_HANDLER_ARGS) 2337ec9403d0SSepherosa Ziehau { 2338ec9403d0SSepherosa Ziehau struct nfe_softc *sc = arg1; 2339ec9403d0SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 234004b9ef8dSSepherosa Ziehau uint32_t flags; 2341ec9403d0SSepherosa Ziehau int error, v; 2342ec9403d0SSepherosa Ziehau 2343ec9403d0SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 2344ec9403d0SSepherosa Ziehau 234504b9ef8dSSepherosa Ziehau flags = sc->sc_flags & ~NFE_F_DYN_IM; 2346ec9403d0SSepherosa Ziehau v = sc->sc_imtime; 234704b9ef8dSSepherosa Ziehau if (sc->sc_flags & NFE_F_DYN_IM) 234804b9ef8dSSepherosa Ziehau v = -v; 234904b9ef8dSSepherosa Ziehau 2350ec9403d0SSepherosa Ziehau error = sysctl_handle_int(oidp, &v, 0, req); 2351ec9403d0SSepherosa Ziehau if (error || req->newptr == NULL) 2352ec9403d0SSepherosa Ziehau goto back; 235304b9ef8dSSepherosa Ziehau 235404b9ef8dSSepherosa Ziehau if (v < 0) { 235504b9ef8dSSepherosa Ziehau flags |= NFE_F_DYN_IM; 235604b9ef8dSSepherosa Ziehau v = -v; 2357ec9403d0SSepherosa Ziehau } 2358ec9403d0SSepherosa Ziehau 235904b9ef8dSSepherosa Ziehau if (v != sc->sc_imtime || (flags ^ sc->sc_flags)) { 2360c00ddf33SMatthew Dillon if (NFE_IMTIME(v) == 0) 2361c00ddf33SMatthew Dillon v = 0; 2362ec9403d0SSepherosa Ziehau sc->sc_imtime = v; 236304b9ef8dSSepherosa Ziehau sc->sc_flags = flags; 2364ec9403d0SSepherosa Ziehau sc->sc_irq_enable = NFE_IRQ_ENABLE(sc); 2365ec9403d0SSepherosa Ziehau 2366d2e51f8dSSepherosa Ziehau if ((ifp->if_flags & (IFF_NPOLLING | IFF_RUNNING)) 2367ec9403d0SSepherosa Ziehau == IFF_RUNNING) { 2368c00ddf33SMatthew Dillon nfe_enable_intrs(sc); 2369ec9403d0SSepherosa Ziehau } 2370ec9403d0SSepherosa Ziehau } 2371ec9403d0SSepherosa Ziehau back: 2372ec9403d0SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 2373ec9403d0SSepherosa Ziehau return error; 2374ec9403d0SSepherosa Ziehau } 2375faaea42eSSepherosa Ziehau 2376faaea42eSSepherosa Ziehau static void 2377faaea42eSSepherosa Ziehau nfe_powerup(device_t dev) 2378faaea42eSSepherosa Ziehau { 2379faaea42eSSepherosa Ziehau struct nfe_softc *sc = device_get_softc(dev); 2380faaea42eSSepherosa Ziehau uint32_t pwr_state; 2381faaea42eSSepherosa Ziehau uint16_t did; 2382faaea42eSSepherosa Ziehau 2383faaea42eSSepherosa Ziehau /* 2384faaea42eSSepherosa Ziehau * Bring MAC and PHY out of low power state 2385faaea42eSSepherosa Ziehau */ 2386faaea42eSSepherosa Ziehau 2387faaea42eSSepherosa Ziehau pwr_state = NFE_READ(sc, NFE_PWR_STATE2) & ~NFE_PWRUP_MASK; 2388faaea42eSSepherosa Ziehau 2389faaea42eSSepherosa Ziehau did = pci_get_device(dev); 2390faaea42eSSepherosa Ziehau if ((did == PCI_PRODUCT_NVIDIA_MCP51_LAN1 || 2391faaea42eSSepherosa Ziehau did == PCI_PRODUCT_NVIDIA_MCP51_LAN2) && 2392faaea42eSSepherosa Ziehau pci_get_revid(dev) >= 0xa3) 2393faaea42eSSepherosa Ziehau pwr_state |= NFE_PWRUP_REV_A3; 2394faaea42eSSepherosa Ziehau 2395faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_PWR_STATE2, pwr_state); 2396faaea42eSSepherosa Ziehau } 2397faaea42eSSepherosa Ziehau 2398faaea42eSSepherosa Ziehau static void 2399faaea42eSSepherosa Ziehau nfe_mac_reset(struct nfe_softc *sc) 2400faaea42eSSepherosa Ziehau { 2401faaea42eSSepherosa Ziehau uint32_t rxtxctl = sc->rxtxctl_desc | NFE_RXTX_BIT2; 2402faaea42eSSepherosa Ziehau uint32_t macaddr_hi, macaddr_lo, tx_poll; 2403faaea42eSSepherosa Ziehau 2404faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, NFE_RXTX_RESET | rxtxctl); 2405faaea42eSSepherosa Ziehau 2406faaea42eSSepherosa Ziehau /* Save several registers for later restoration */ 2407faaea42eSSepherosa Ziehau macaddr_hi = NFE_READ(sc, NFE_MACADDR_HI); 2408faaea42eSSepherosa Ziehau macaddr_lo = NFE_READ(sc, NFE_MACADDR_LO); 2409faaea42eSSepherosa Ziehau tx_poll = NFE_READ(sc, NFE_TX_POLL); 2410faaea42eSSepherosa Ziehau 2411faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MAC_RESET, NFE_RESET_ASSERT); 2412faaea42eSSepherosa Ziehau DELAY(100); 2413faaea42eSSepherosa Ziehau 2414faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MAC_RESET, 0); 2415faaea42eSSepherosa Ziehau DELAY(100); 2416faaea42eSSepherosa Ziehau 2417faaea42eSSepherosa Ziehau /* Restore saved registers */ 2418faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_HI, macaddr_hi); 2419faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_MACADDR_LO, macaddr_lo); 2420faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_TX_POLL, tx_poll); 2421faaea42eSSepherosa Ziehau 2422faaea42eSSepherosa Ziehau NFE_WRITE(sc, NFE_RXTX_CTL, rxtxctl); 2423faaea42eSSepherosa Ziehau } 242404b9ef8dSSepherosa Ziehau 242504b9ef8dSSepherosa Ziehau static void 242604b9ef8dSSepherosa Ziehau nfe_enable_intrs(struct nfe_softc *sc) 242704b9ef8dSSepherosa Ziehau { 242804b9ef8dSSepherosa Ziehau /* 242904b9ef8dSSepherosa Ziehau * NFE_IMTIMER generates a periodic interrupt via NFE_IRQ_TIMER. 243004b9ef8dSSepherosa Ziehau * It is unclear how wide the timer is. Base programming does 243104b9ef8dSSepherosa Ziehau * not seem to effect NFE_IRQ_TX_DONE or NFE_IRQ_RX_DONE so 243204b9ef8dSSepherosa Ziehau * we don't get any interrupt moderation. TX moderation is 243304b9ef8dSSepherosa Ziehau * possible by using the timer interrupt instead of TX_DONE. 243404b9ef8dSSepherosa Ziehau * 243504b9ef8dSSepherosa Ziehau * It is unclear whether there are other bits that can be 243604b9ef8dSSepherosa Ziehau * set to make the NFE device actually do interrupt moderation 243704b9ef8dSSepherosa Ziehau * on the RX side. 243804b9ef8dSSepherosa Ziehau * 243904b9ef8dSSepherosa Ziehau * For now set a 128uS interval as a placemark, but don't use 244004b9ef8dSSepherosa Ziehau * the timer. 244104b9ef8dSSepherosa Ziehau */ 244204b9ef8dSSepherosa Ziehau if (sc->sc_imtime == 0) 244304b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IMTIMER, NFE_IMTIME_DEFAULT); 244404b9ef8dSSepherosa Ziehau else 244504b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IMTIMER, NFE_IMTIME(sc->sc_imtime)); 244604b9ef8dSSepherosa Ziehau 244704b9ef8dSSepherosa Ziehau /* Enable interrupts */ 244804b9ef8dSSepherosa Ziehau NFE_WRITE(sc, NFE_IRQ_MASK, sc->sc_irq_enable); 244904b9ef8dSSepherosa Ziehau 245004b9ef8dSSepherosa Ziehau if (sc->sc_irq_enable & NFE_IRQ_TIMER) 245104b9ef8dSSepherosa Ziehau sc->sc_flags |= NFE_F_IRQ_TIMER; 245204b9ef8dSSepherosa Ziehau else 245304b9ef8dSSepherosa Ziehau sc->sc_flags &= ~NFE_F_IRQ_TIMER; 245404b9ef8dSSepherosa Ziehau } 2455