1a8d7fc4aSZbigniew Bodek /* 2a8d7fc4aSZbigniew Bodek * Copyright (c) 2017 Stormshield. 3a8d7fc4aSZbigniew Bodek * Copyright (c) 2017 Semihalf. 4a8d7fc4aSZbigniew Bodek * All rights reserved. 5a8d7fc4aSZbigniew Bodek * 6a8d7fc4aSZbigniew Bodek * Redistribution and use in source and binary forms, with or without 7a8d7fc4aSZbigniew Bodek * modification, are permitted provided that the following conditions 8a8d7fc4aSZbigniew Bodek * are met: 9a8d7fc4aSZbigniew Bodek * 1. Redistributions of source code must retain the above copyright 10a8d7fc4aSZbigniew Bodek * notice, this list of conditions and the following disclaimer. 11a8d7fc4aSZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright 12a8d7fc4aSZbigniew Bodek * notice, this list of conditions and the following disclaimer in the 13a8d7fc4aSZbigniew Bodek * documentation and/or other materials provided with the distribution. 14a8d7fc4aSZbigniew Bodek * 15a8d7fc4aSZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16a8d7fc4aSZbigniew Bodek * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17a8d7fc4aSZbigniew Bodek * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18a8d7fc4aSZbigniew Bodek * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19a8d7fc4aSZbigniew Bodek * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20a8d7fc4aSZbigniew Bodek * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21a8d7fc4aSZbigniew Bodek * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22a8d7fc4aSZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23a8d7fc4aSZbigniew Bodek * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24a8d7fc4aSZbigniew Bodek * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25a8d7fc4aSZbigniew Bodek * POSSIBILITY OF SUCH DAMAGE. 26a8d7fc4aSZbigniew Bodek */ 27a8d7fc4aSZbigniew Bodek 28a8d7fc4aSZbigniew Bodek #include "opt_platform.h" 29fdafd315SWarner Losh 30a8d7fc4aSZbigniew Bodek #include <sys/param.h> 31a8d7fc4aSZbigniew Bodek #include <sys/systm.h> 32a8d7fc4aSZbigniew Bodek #include <sys/endian.h> 33a8d7fc4aSZbigniew Bodek #include <sys/mbuf.h> 34a8d7fc4aSZbigniew Bodek #include <sys/lock.h> 35a8d7fc4aSZbigniew Bodek #include <sys/mutex.h> 36a8d7fc4aSZbigniew Bodek #include <sys/kernel.h> 37a8d7fc4aSZbigniew Bodek #include <sys/module.h> 38a8d7fc4aSZbigniew Bodek #include <sys/socket.h> 39a8d7fc4aSZbigniew Bodek #include <sys/sysctl.h> 40a8d7fc4aSZbigniew Bodek #include <sys/smp.h> 41a8d7fc4aSZbigniew Bodek #include <sys/taskqueue.h> 42a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 43a8d7fc4aSZbigniew Bodek #include <sys/ktr.h> 44a8d7fc4aSZbigniew Bodek #endif 45a8d7fc4aSZbigniew Bodek 46a8d7fc4aSZbigniew Bodek #include <net/ethernet.h> 47a8d7fc4aSZbigniew Bodek #include <net/bpf.h> 48a8d7fc4aSZbigniew Bodek #include <net/if.h> 49a8d7fc4aSZbigniew Bodek #include <net/if_arp.h> 50a8d7fc4aSZbigniew Bodek #include <net/if_dl.h> 51a8d7fc4aSZbigniew Bodek #include <net/if_media.h> 52a8d7fc4aSZbigniew Bodek #include <net/if_types.h> 53a8d7fc4aSZbigniew Bodek #include <net/if_vlan_var.h> 54a8d7fc4aSZbigniew Bodek 55a8d7fc4aSZbigniew Bodek #include <netinet/in_systm.h> 56a8d7fc4aSZbigniew Bodek #include <netinet/in.h> 57a8d7fc4aSZbigniew Bodek #include <netinet/ip.h> 58a8d7fc4aSZbigniew Bodek #include <netinet/tcp_lro.h> 59a8d7fc4aSZbigniew Bodek 60a8d7fc4aSZbigniew Bodek #include <sys/sockio.h> 61a8d7fc4aSZbigniew Bodek #include <sys/bus.h> 62a8d7fc4aSZbigniew Bodek #include <machine/bus.h> 63a8d7fc4aSZbigniew Bodek #include <sys/rman.h> 64a8d7fc4aSZbigniew Bodek #include <machine/resource.h> 65a8d7fc4aSZbigniew Bodek 66be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 674885d6f3SHubert Mazur 68a8d7fc4aSZbigniew Bodek #include <dev/mii/mii.h> 69a8d7fc4aSZbigniew Bodek #include <dev/mii/miivar.h> 70a8d7fc4aSZbigniew Bodek 71a8d7fc4aSZbigniew Bodek #include <dev/mdio/mdio.h> 72a8d7fc4aSZbigniew Bodek 73a8d7fc4aSZbigniew Bodek #include <arm/mv/mvvar.h> 74e314ac07SMarcin Wojtas 75e314ac07SMarcin Wojtas #if !defined(__aarch64__) 76e314ac07SMarcin Wojtas #include <arm/mv/mvreg.h> 77a8d7fc4aSZbigniew Bodek #include <arm/mv/mvwin.h> 78e314ac07SMarcin Wojtas #endif 79a8d7fc4aSZbigniew Bodek 80a8d7fc4aSZbigniew Bodek #include "if_mvnetareg.h" 81a8d7fc4aSZbigniew Bodek #include "if_mvnetavar.h" 82a8d7fc4aSZbigniew Bodek 83a8d7fc4aSZbigniew Bodek #include "miibus_if.h" 84a8d7fc4aSZbigniew Bodek #include "mdio_if.h" 85a8d7fc4aSZbigniew Bodek 86a8d7fc4aSZbigniew Bodek #ifdef MVNETA_DEBUG 87a8d7fc4aSZbigniew Bodek #define STATIC /* nothing */ 88a8d7fc4aSZbigniew Bodek #else 89a8d7fc4aSZbigniew Bodek #define STATIC static 90a8d7fc4aSZbigniew Bodek #endif 91a8d7fc4aSZbigniew Bodek 92a8d7fc4aSZbigniew Bodek #define DASSERT(x) KASSERT((x), (#x)) 93a8d7fc4aSZbigniew Bodek 94e314ac07SMarcin Wojtas #define A3700_TCLK_250MHZ 250000000 95e314ac07SMarcin Wojtas 96a8d7fc4aSZbigniew Bodek /* Device Register Initialization */ 97992fa62bSJustin Hibbits STATIC int mvneta_initreg(if_t); 98a8d7fc4aSZbigniew Bodek 99a8d7fc4aSZbigniew Bodek /* Descriptor Ring Control for each of queues */ 100a8d7fc4aSZbigniew Bodek STATIC int mvneta_ring_alloc_rx_queue(struct mvneta_softc *, int); 101a8d7fc4aSZbigniew Bodek STATIC int mvneta_ring_alloc_tx_queue(struct mvneta_softc *, int); 102a8d7fc4aSZbigniew Bodek STATIC void mvneta_ring_dealloc_rx_queue(struct mvneta_softc *, int); 103a8d7fc4aSZbigniew Bodek STATIC void mvneta_ring_dealloc_tx_queue(struct mvneta_softc *, int); 104a8d7fc4aSZbigniew Bodek STATIC int mvneta_ring_init_rx_queue(struct mvneta_softc *, int); 105a8d7fc4aSZbigniew Bodek STATIC int mvneta_ring_init_tx_queue(struct mvneta_softc *, int); 106a8d7fc4aSZbigniew Bodek STATIC void mvneta_ring_flush_rx_queue(struct mvneta_softc *, int); 107a8d7fc4aSZbigniew Bodek STATIC void mvneta_ring_flush_tx_queue(struct mvneta_softc *, int); 108a8d7fc4aSZbigniew Bodek STATIC void mvneta_dmamap_cb(void *, bus_dma_segment_t *, int, int); 109a8d7fc4aSZbigniew Bodek STATIC int mvneta_dma_create(struct mvneta_softc *); 110a8d7fc4aSZbigniew Bodek 111a8d7fc4aSZbigniew Bodek /* Rx/Tx Queue Control */ 112992fa62bSJustin Hibbits STATIC int mvneta_rx_queue_init(if_t, int); 113992fa62bSJustin Hibbits STATIC int mvneta_tx_queue_init(if_t, int); 114992fa62bSJustin Hibbits STATIC int mvneta_rx_queue_enable(if_t, int); 115992fa62bSJustin Hibbits STATIC int mvneta_tx_queue_enable(if_t, int); 116a8d7fc4aSZbigniew Bodek STATIC void mvneta_rx_lockq(struct mvneta_softc *, int); 117a8d7fc4aSZbigniew Bodek STATIC void mvneta_rx_unlockq(struct mvneta_softc *, int); 118a8d7fc4aSZbigniew Bodek STATIC void mvneta_tx_lockq(struct mvneta_softc *, int); 119a8d7fc4aSZbigniew Bodek STATIC void mvneta_tx_unlockq(struct mvneta_softc *, int); 120a8d7fc4aSZbigniew Bodek 121a8d7fc4aSZbigniew Bodek /* Interrupt Handlers */ 122a8d7fc4aSZbigniew Bodek STATIC void mvneta_disable_intr(struct mvneta_softc *); 123a8d7fc4aSZbigniew Bodek STATIC void mvneta_enable_intr(struct mvneta_softc *); 124a8d7fc4aSZbigniew Bodek STATIC void mvneta_rxtxth_intr(void *); 125a8d7fc4aSZbigniew Bodek STATIC int mvneta_misc_intr(struct mvneta_softc *); 126a8d7fc4aSZbigniew Bodek STATIC void mvneta_tick(void *); 127a8d7fc4aSZbigniew Bodek /* struct ifnet and mii callbacks*/ 128a8d7fc4aSZbigniew Bodek STATIC int mvneta_xmitfast_locked(struct mvneta_softc *, int, struct mbuf **); 129a8d7fc4aSZbigniew Bodek STATIC int mvneta_xmit_locked(struct mvneta_softc *, int); 130a8d7fc4aSZbigniew Bodek #ifdef MVNETA_MULTIQUEUE 131992fa62bSJustin Hibbits STATIC int mvneta_transmit(if_t, struct mbuf *); 132a8d7fc4aSZbigniew Bodek #else /* !MVNETA_MULTIQUEUE */ 133992fa62bSJustin Hibbits STATIC void mvneta_start(if_t); 134a8d7fc4aSZbigniew Bodek #endif 135992fa62bSJustin Hibbits STATIC void mvneta_qflush(if_t); 136a8d7fc4aSZbigniew Bodek STATIC void mvneta_tx_task(void *, int); 137992fa62bSJustin Hibbits STATIC int mvneta_ioctl(if_t, u_long, caddr_t); 138a8d7fc4aSZbigniew Bodek STATIC void mvneta_init(void *); 139a8d7fc4aSZbigniew Bodek STATIC void mvneta_init_locked(void *); 140a8d7fc4aSZbigniew Bodek STATIC void mvneta_stop(struct mvneta_softc *); 141a8d7fc4aSZbigniew Bodek STATIC void mvneta_stop_locked(struct mvneta_softc *); 142992fa62bSJustin Hibbits STATIC int mvneta_mediachange(if_t); 143992fa62bSJustin Hibbits STATIC void mvneta_mediastatus(if_t, struct ifmediareq *); 144a8d7fc4aSZbigniew Bodek STATIC void mvneta_portup(struct mvneta_softc *); 145a8d7fc4aSZbigniew Bodek STATIC void mvneta_portdown(struct mvneta_softc *); 146a8d7fc4aSZbigniew Bodek 147a8d7fc4aSZbigniew Bodek /* Link State Notify */ 148a8d7fc4aSZbigniew Bodek STATIC void mvneta_update_autoneg(struct mvneta_softc *, int); 149a8d7fc4aSZbigniew Bodek STATIC int mvneta_update_media(struct mvneta_softc *, int); 150a8d7fc4aSZbigniew Bodek STATIC void mvneta_adjust_link(struct mvneta_softc *); 151a8d7fc4aSZbigniew Bodek STATIC void mvneta_update_eee(struct mvneta_softc *); 152a8d7fc4aSZbigniew Bodek STATIC void mvneta_update_fc(struct mvneta_softc *); 153a8d7fc4aSZbigniew Bodek STATIC void mvneta_link_isr(struct mvneta_softc *); 154a8d7fc4aSZbigniew Bodek STATIC void mvneta_linkupdate(struct mvneta_softc *, boolean_t); 155a8d7fc4aSZbigniew Bodek STATIC void mvneta_linkup(struct mvneta_softc *); 156a8d7fc4aSZbigniew Bodek STATIC void mvneta_linkdown(struct mvneta_softc *); 157a8d7fc4aSZbigniew Bodek STATIC void mvneta_linkreset(struct mvneta_softc *); 158a8d7fc4aSZbigniew Bodek 159a8d7fc4aSZbigniew Bodek /* Tx Subroutines */ 160a8d7fc4aSZbigniew Bodek STATIC int mvneta_tx_queue(struct mvneta_softc *, struct mbuf **, int); 161992fa62bSJustin Hibbits STATIC void mvneta_tx_set_csumflag(if_t, 162a8d7fc4aSZbigniew Bodek struct mvneta_tx_desc *, struct mbuf *); 163a8d7fc4aSZbigniew Bodek STATIC void mvneta_tx_queue_complete(struct mvneta_softc *, int); 164a8d7fc4aSZbigniew Bodek STATIC void mvneta_tx_drain(struct mvneta_softc *); 165a8d7fc4aSZbigniew Bodek 166a8d7fc4aSZbigniew Bodek /* Rx Subroutines */ 167a8d7fc4aSZbigniew Bodek STATIC int mvneta_rx(struct mvneta_softc *, int, int); 168a8d7fc4aSZbigniew Bodek STATIC void mvneta_rx_queue(struct mvneta_softc *, int, int); 169a8d7fc4aSZbigniew Bodek STATIC void mvneta_rx_queue_refill(struct mvneta_softc *, int); 170992fa62bSJustin Hibbits STATIC void mvneta_rx_set_csumflag(if_t, 171a8d7fc4aSZbigniew Bodek struct mvneta_rx_desc *, struct mbuf *); 172a8d7fc4aSZbigniew Bodek STATIC void mvneta_rx_buf_free(struct mvneta_softc *, struct mvneta_buf *); 173a8d7fc4aSZbigniew Bodek 174a8d7fc4aSZbigniew Bodek /* MAC address filter */ 175a8d7fc4aSZbigniew Bodek STATIC void mvneta_filter_setup(struct mvneta_softc *); 176a8d7fc4aSZbigniew Bodek 177a8d7fc4aSZbigniew Bodek /* sysctl(9) */ 178a8d7fc4aSZbigniew Bodek STATIC int sysctl_read_mib(SYSCTL_HANDLER_ARGS); 179a8d7fc4aSZbigniew Bodek STATIC int sysctl_clear_mib(SYSCTL_HANDLER_ARGS); 180a8d7fc4aSZbigniew Bodek STATIC int sysctl_set_queue_rxthtime(SYSCTL_HANDLER_ARGS); 181a8d7fc4aSZbigniew Bodek STATIC void sysctl_mvneta_init(struct mvneta_softc *); 182a8d7fc4aSZbigniew Bodek 183a8d7fc4aSZbigniew Bodek /* MIB */ 184a8d7fc4aSZbigniew Bodek STATIC void mvneta_clear_mib(struct mvneta_softc *); 185caf552a6SMark Johnston STATIC uint64_t mvneta_read_mib(struct mvneta_softc *, int); 186a8d7fc4aSZbigniew Bodek STATIC void mvneta_update_mib(struct mvneta_softc *); 187a8d7fc4aSZbigniew Bodek 188a8d7fc4aSZbigniew Bodek /* Switch */ 189a8d7fc4aSZbigniew Bodek STATIC boolean_t mvneta_has_switch(device_t); 190a8d7fc4aSZbigniew Bodek 191a8d7fc4aSZbigniew Bodek #define mvneta_sc_lock(sc) mtx_lock(&sc->mtx) 192a8d7fc4aSZbigniew Bodek #define mvneta_sc_unlock(sc) mtx_unlock(&sc->mtx) 193a8d7fc4aSZbigniew Bodek 194a8d7fc4aSZbigniew Bodek STATIC struct mtx mii_mutex; 195a8d7fc4aSZbigniew Bodek STATIC int mii_init = 0; 196a8d7fc4aSZbigniew Bodek 197a8d7fc4aSZbigniew Bodek /* Device */ 198a8d7fc4aSZbigniew Bodek STATIC int mvneta_detach(device_t); 199a8d7fc4aSZbigniew Bodek /* MII */ 200a8d7fc4aSZbigniew Bodek STATIC int mvneta_miibus_readreg(device_t, int, int); 201a8d7fc4aSZbigniew Bodek STATIC int mvneta_miibus_writereg(device_t, int, int, int); 202a8d7fc4aSZbigniew Bodek 203a8d7fc4aSZbigniew Bodek static device_method_t mvneta_methods[] = { 204a8d7fc4aSZbigniew Bodek /* Device interface */ 205a8d7fc4aSZbigniew Bodek DEVMETHOD(device_detach, mvneta_detach), 206a8d7fc4aSZbigniew Bodek /* MII interface */ 207a8d7fc4aSZbigniew Bodek DEVMETHOD(miibus_readreg, mvneta_miibus_readreg), 208a8d7fc4aSZbigniew Bodek DEVMETHOD(miibus_writereg, mvneta_miibus_writereg), 209a8d7fc4aSZbigniew Bodek /* MDIO interface */ 210a8d7fc4aSZbigniew Bodek DEVMETHOD(mdio_readreg, mvneta_miibus_readreg), 211a8d7fc4aSZbigniew Bodek DEVMETHOD(mdio_writereg, mvneta_miibus_writereg), 212a8d7fc4aSZbigniew Bodek 213a8d7fc4aSZbigniew Bodek /* End */ 214a8d7fc4aSZbigniew Bodek DEVMETHOD_END 215a8d7fc4aSZbigniew Bodek }; 216a8d7fc4aSZbigniew Bodek 217a8d7fc4aSZbigniew Bodek DEFINE_CLASS_0(mvneta, mvneta_driver, mvneta_methods, sizeof(struct mvneta_softc)); 218a8d7fc4aSZbigniew Bodek 2193e38757dSJohn Baldwin DRIVER_MODULE(miibus, mvneta, miibus_driver, 0, 0); 2208933f7d6SJohn Baldwin DRIVER_MODULE(mdio, mvneta, mdio_driver, 0, 0); 221a8d7fc4aSZbigniew Bodek MODULE_DEPEND(mvneta, mdio, 1, 1, 1); 222a8d7fc4aSZbigniew Bodek MODULE_DEPEND(mvneta, ether, 1, 1, 1); 223a8d7fc4aSZbigniew Bodek MODULE_DEPEND(mvneta, miibus, 1, 1, 1); 2245572fda3SWojciech Macek MODULE_DEPEND(mvneta, mvxpbm, 1, 1, 1); 225a8d7fc4aSZbigniew Bodek 226a8d7fc4aSZbigniew Bodek /* 227a8d7fc4aSZbigniew Bodek * List of MIB register and names 228a8d7fc4aSZbigniew Bodek */ 229a8d7fc4aSZbigniew Bodek enum mvneta_mib_idx 230a8d7fc4aSZbigniew Bodek { 231a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_GOOD_OCT_IDX, 232a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_BAD_OCT_IDX, 233a8d7fc4aSZbigniew Bodek MVNETA_MIB_TX_MAC_TRNS_ERR_IDX, 234a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_GOOD_FRAME_IDX, 235a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_BAD_FRAME_IDX, 236a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_BCAST_FRAME_IDX, 237a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_MCAST_FRAME_IDX, 238a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_FRAME64_OCT_IDX, 239a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_FRAME127_OCT_IDX, 240a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_FRAME255_OCT_IDX, 241a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_FRAME511_OCT_IDX, 242a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_FRAME1023_OCT_IDX, 243a8d7fc4aSZbigniew Bodek MVNETA_MIB_RX_FRAMEMAX_OCT_IDX, 244a8d7fc4aSZbigniew Bodek MVNETA_MIB_TX_GOOD_OCT_IDX, 245a8d7fc4aSZbigniew Bodek MVNETA_MIB_TX_GOOD_FRAME_IDX, 246a8d7fc4aSZbigniew Bodek MVNETA_MIB_TX_EXCES_COL_IDX, 247a8d7fc4aSZbigniew Bodek MVNETA_MIB_TX_MCAST_FRAME_IDX, 248a8d7fc4aSZbigniew Bodek MVNETA_MIB_TX_BCAST_FRAME_IDX, 249a8d7fc4aSZbigniew Bodek MVNETA_MIB_TX_MAC_CTL_ERR_IDX, 250a8d7fc4aSZbigniew Bodek MVNETA_MIB_FC_SENT_IDX, 251a8d7fc4aSZbigniew Bodek MVNETA_MIB_FC_GOOD_IDX, 252a8d7fc4aSZbigniew Bodek MVNETA_MIB_FC_BAD_IDX, 253a8d7fc4aSZbigniew Bodek MVNETA_MIB_PKT_UNDERSIZE_IDX, 254a8d7fc4aSZbigniew Bodek MVNETA_MIB_PKT_FRAGMENT_IDX, 255a8d7fc4aSZbigniew Bodek MVNETA_MIB_PKT_OVERSIZE_IDX, 256a8d7fc4aSZbigniew Bodek MVNETA_MIB_PKT_JABBER_IDX, 257a8d7fc4aSZbigniew Bodek MVNETA_MIB_MAC_RX_ERR_IDX, 258a8d7fc4aSZbigniew Bodek MVNETA_MIB_MAC_CRC_ERR_IDX, 259a8d7fc4aSZbigniew Bodek MVNETA_MIB_MAC_COL_IDX, 260a8d7fc4aSZbigniew Bodek MVNETA_MIB_MAC_LATE_COL_IDX, 261a8d7fc4aSZbigniew Bodek }; 262a8d7fc4aSZbigniew Bodek 263a8d7fc4aSZbigniew Bodek STATIC struct mvneta_mib_def { 264a8d7fc4aSZbigniew Bodek uint32_t regnum; 265a8d7fc4aSZbigniew Bodek int reg64; 266a8d7fc4aSZbigniew Bodek const char *sysctl_name; 267a8d7fc4aSZbigniew Bodek const char *desc; 268a8d7fc4aSZbigniew Bodek } mvneta_mib_list[] = { 269a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_GOOD_OCT_IDX] = {MVNETA_MIB_RX_GOOD_OCT, 1, 270a8d7fc4aSZbigniew Bodek "rx_good_oct", "Good Octets Rx"}, 271a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_BAD_OCT_IDX] = {MVNETA_MIB_RX_BAD_OCT, 0, 272a8d7fc4aSZbigniew Bodek "rx_bad_oct", "Bad Octets Rx"}, 273a8d7fc4aSZbigniew Bodek [MVNETA_MIB_TX_MAC_TRNS_ERR_IDX] = {MVNETA_MIB_TX_MAC_TRNS_ERR, 0, 274a8d7fc4aSZbigniew Bodek "tx_mac_err", "MAC Transmit Error"}, 275a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_GOOD_FRAME_IDX] = {MVNETA_MIB_RX_GOOD_FRAME, 0, 276a8d7fc4aSZbigniew Bodek "rx_good_frame", "Good Frames Rx"}, 277a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_BAD_FRAME_IDX] = {MVNETA_MIB_RX_BAD_FRAME, 0, 278a8d7fc4aSZbigniew Bodek "rx_bad_frame", "Bad Frames Rx"}, 279a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_BCAST_FRAME_IDX] = {MVNETA_MIB_RX_BCAST_FRAME, 0, 280a8d7fc4aSZbigniew Bodek "rx_bcast_frame", "Broadcast Frames Rx"}, 281a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_MCAST_FRAME_IDX] = {MVNETA_MIB_RX_MCAST_FRAME, 0, 282a8d7fc4aSZbigniew Bodek "rx_mcast_frame", "Multicast Frames Rx"}, 283a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_FRAME64_OCT_IDX] = {MVNETA_MIB_RX_FRAME64_OCT, 0, 284a8d7fc4aSZbigniew Bodek "rx_frame_1_64", "Frame Size 1 - 64"}, 285a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_FRAME127_OCT_IDX] = {MVNETA_MIB_RX_FRAME127_OCT, 0, 286a8d7fc4aSZbigniew Bodek "rx_frame_65_127", "Frame Size 65 - 127"}, 287a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_FRAME255_OCT_IDX] = {MVNETA_MIB_RX_FRAME255_OCT, 0, 288a8d7fc4aSZbigniew Bodek "rx_frame_128_255", "Frame Size 128 - 255"}, 289a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_FRAME511_OCT_IDX] = {MVNETA_MIB_RX_FRAME511_OCT, 0, 290a8d7fc4aSZbigniew Bodek "rx_frame_256_511", "Frame Size 256 - 511"}, 291a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_FRAME1023_OCT_IDX] = {MVNETA_MIB_RX_FRAME1023_OCT, 0, 292a8d7fc4aSZbigniew Bodek "rx_frame_512_1023", "Frame Size 512 - 1023"}, 293a8d7fc4aSZbigniew Bodek [MVNETA_MIB_RX_FRAMEMAX_OCT_IDX] = {MVNETA_MIB_RX_FRAMEMAX_OCT, 0, 294a8d7fc4aSZbigniew Bodek "rx_fame_1024_max", "Frame Size 1024 - Max"}, 295a8d7fc4aSZbigniew Bodek [MVNETA_MIB_TX_GOOD_OCT_IDX] = {MVNETA_MIB_TX_GOOD_OCT, 1, 296a8d7fc4aSZbigniew Bodek "tx_good_oct", "Good Octets Tx"}, 297a8d7fc4aSZbigniew Bodek [MVNETA_MIB_TX_GOOD_FRAME_IDX] = {MVNETA_MIB_TX_GOOD_FRAME, 0, 298a8d7fc4aSZbigniew Bodek "tx_good_frame", "Good Frames Tx"}, 299a8d7fc4aSZbigniew Bodek [MVNETA_MIB_TX_EXCES_COL_IDX] = {MVNETA_MIB_TX_EXCES_COL, 0, 300a8d7fc4aSZbigniew Bodek "tx_exces_collision", "Excessive Collision"}, 301a8d7fc4aSZbigniew Bodek [MVNETA_MIB_TX_MCAST_FRAME_IDX] = {MVNETA_MIB_TX_MCAST_FRAME, 0, 302a8d7fc4aSZbigniew Bodek "tx_mcast_frame", "Multicast Frames Tx"}, 303a8d7fc4aSZbigniew Bodek [MVNETA_MIB_TX_BCAST_FRAME_IDX] = {MVNETA_MIB_TX_BCAST_FRAME, 0, 304a8d7fc4aSZbigniew Bodek "tx_bcast_frame", "Broadcast Frames Tx"}, 305a8d7fc4aSZbigniew Bodek [MVNETA_MIB_TX_MAC_CTL_ERR_IDX] = {MVNETA_MIB_TX_MAC_CTL_ERR, 0, 306a8d7fc4aSZbigniew Bodek "tx_mac_ctl_err", "Unknown MAC Control"}, 307a8d7fc4aSZbigniew Bodek [MVNETA_MIB_FC_SENT_IDX] = {MVNETA_MIB_FC_SENT, 0, 308a8d7fc4aSZbigniew Bodek "fc_tx", "Flow Control Tx"}, 309a8d7fc4aSZbigniew Bodek [MVNETA_MIB_FC_GOOD_IDX] = {MVNETA_MIB_FC_GOOD, 0, 310a8d7fc4aSZbigniew Bodek "fc_rx_good", "Good Flow Control Rx"}, 311a8d7fc4aSZbigniew Bodek [MVNETA_MIB_FC_BAD_IDX] = {MVNETA_MIB_FC_BAD, 0, 312a8d7fc4aSZbigniew Bodek "fc_rx_bad", "Bad Flow Control Rx"}, 313a8d7fc4aSZbigniew Bodek [MVNETA_MIB_PKT_UNDERSIZE_IDX] = {MVNETA_MIB_PKT_UNDERSIZE, 0, 314a8d7fc4aSZbigniew Bodek "pkt_undersize", "Undersized Packets Rx"}, 315a8d7fc4aSZbigniew Bodek [MVNETA_MIB_PKT_FRAGMENT_IDX] = {MVNETA_MIB_PKT_FRAGMENT, 0, 316a8d7fc4aSZbigniew Bodek "pkt_fragment", "Fragmented Packets Rx"}, 317a8d7fc4aSZbigniew Bodek [MVNETA_MIB_PKT_OVERSIZE_IDX] = {MVNETA_MIB_PKT_OVERSIZE, 0, 318a8d7fc4aSZbigniew Bodek "pkt_oversize", "Oversized Packets Rx"}, 319a8d7fc4aSZbigniew Bodek [MVNETA_MIB_PKT_JABBER_IDX] = {MVNETA_MIB_PKT_JABBER, 0, 320a8d7fc4aSZbigniew Bodek "pkt_jabber", "Jabber Packets Rx"}, 321a8d7fc4aSZbigniew Bodek [MVNETA_MIB_MAC_RX_ERR_IDX] = {MVNETA_MIB_MAC_RX_ERR, 0, 322a8d7fc4aSZbigniew Bodek "mac_rx_err", "MAC Rx Errors"}, 323a8d7fc4aSZbigniew Bodek [MVNETA_MIB_MAC_CRC_ERR_IDX] = {MVNETA_MIB_MAC_CRC_ERR, 0, 324a8d7fc4aSZbigniew Bodek "mac_crc_err", "MAC CRC Errors"}, 325a8d7fc4aSZbigniew Bodek [MVNETA_MIB_MAC_COL_IDX] = {MVNETA_MIB_MAC_COL, 0, 326a8d7fc4aSZbigniew Bodek "mac_collision", "MAC Collision"}, 327a8d7fc4aSZbigniew Bodek [MVNETA_MIB_MAC_LATE_COL_IDX] = {MVNETA_MIB_MAC_LATE_COL, 0, 328a8d7fc4aSZbigniew Bodek "mac_late_collision", "MAC Late Collision"}, 329a8d7fc4aSZbigniew Bodek }; 330a8d7fc4aSZbigniew Bodek 331a8d7fc4aSZbigniew Bodek static struct resource_spec res_spec[] = { 332a8d7fc4aSZbigniew Bodek { SYS_RES_MEMORY, 0, RF_ACTIVE }, 333a8d7fc4aSZbigniew Bodek { SYS_RES_IRQ, 0, RF_ACTIVE }, 334a8d7fc4aSZbigniew Bodek { -1, 0} 335a8d7fc4aSZbigniew Bodek }; 336a8d7fc4aSZbigniew Bodek 337a8d7fc4aSZbigniew Bodek static struct { 338a8d7fc4aSZbigniew Bodek driver_intr_t *handler; 339a8d7fc4aSZbigniew Bodek char * description; 340a8d7fc4aSZbigniew Bodek } mvneta_intrs[] = { 341a8d7fc4aSZbigniew Bodek { mvneta_rxtxth_intr, "MVNETA aggregated interrupt" }, 342a8d7fc4aSZbigniew Bodek }; 343a8d7fc4aSZbigniew Bodek 344a8d7fc4aSZbigniew Bodek static int 345a8d7fc4aSZbigniew Bodek mvneta_set_mac_address(struct mvneta_softc *sc, uint8_t *addr) 346a8d7fc4aSZbigniew Bodek { 347a8d7fc4aSZbigniew Bodek unsigned int mac_h; 348a8d7fc4aSZbigniew Bodek unsigned int mac_l; 349a8d7fc4aSZbigniew Bodek 350a8d7fc4aSZbigniew Bodek mac_l = (addr[4] << 8) | (addr[5]); 351a8d7fc4aSZbigniew Bodek mac_h = (addr[0] << 24) | (addr[1] << 16) | 352a8d7fc4aSZbigniew Bodek (addr[2] << 8) | (addr[3] << 0); 353a8d7fc4aSZbigniew Bodek 354a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_MACAL, mac_l); 355a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_MACAH, mac_h); 356a8d7fc4aSZbigniew Bodek return (0); 357a8d7fc4aSZbigniew Bodek } 358a8d7fc4aSZbigniew Bodek 359a8d7fc4aSZbigniew Bodek static int 360a8d7fc4aSZbigniew Bodek mvneta_get_mac_address(struct mvneta_softc *sc, uint8_t *addr) 361a8d7fc4aSZbigniew Bodek { 362a8d7fc4aSZbigniew Bodek uint32_t mac_l, mac_h; 363a8d7fc4aSZbigniew Bodek 364a8d7fc4aSZbigniew Bodek #ifdef FDT 365a8d7fc4aSZbigniew Bodek if (mvneta_fdt_mac_address(sc, addr) == 0) 366a8d7fc4aSZbigniew Bodek return (0); 367a8d7fc4aSZbigniew Bodek #endif 368a8d7fc4aSZbigniew Bodek /* 369a8d7fc4aSZbigniew Bodek * Fall back -- use the currently programmed address. 370a8d7fc4aSZbigniew Bodek */ 371a8d7fc4aSZbigniew Bodek mac_l = MVNETA_READ(sc, MVNETA_MACAL); 372a8d7fc4aSZbigniew Bodek mac_h = MVNETA_READ(sc, MVNETA_MACAH); 373a8d7fc4aSZbigniew Bodek if (mac_l == 0 && mac_h == 0) { 374a8d7fc4aSZbigniew Bodek /* 375a8d7fc4aSZbigniew Bodek * Generate pseudo-random MAC. 376a8d7fc4aSZbigniew Bodek * Set lower part to random number | unit number. 377a8d7fc4aSZbigniew Bodek */ 378a8d7fc4aSZbigniew Bodek mac_l = arc4random() & ~0xff; 379a8d7fc4aSZbigniew Bodek mac_l |= device_get_unit(sc->dev) & 0xff; 380a8d7fc4aSZbigniew Bodek mac_h = arc4random(); 381a8d7fc4aSZbigniew Bodek mac_h &= ~(3 << 24); /* Clear multicast and LAA bits */ 382a8d7fc4aSZbigniew Bodek if (bootverbose) { 383a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 384a8d7fc4aSZbigniew Bodek "Could not acquire MAC address. " 385a8d7fc4aSZbigniew Bodek "Using randomized one.\n"); 386a8d7fc4aSZbigniew Bodek } 387a8d7fc4aSZbigniew Bodek } 388a8d7fc4aSZbigniew Bodek 389a8d7fc4aSZbigniew Bodek addr[0] = (mac_h & 0xff000000) >> 24; 390a8d7fc4aSZbigniew Bodek addr[1] = (mac_h & 0x00ff0000) >> 16; 391a8d7fc4aSZbigniew Bodek addr[2] = (mac_h & 0x0000ff00) >> 8; 392a8d7fc4aSZbigniew Bodek addr[3] = (mac_h & 0x000000ff); 393a8d7fc4aSZbigniew Bodek addr[4] = (mac_l & 0x0000ff00) >> 8; 394a8d7fc4aSZbigniew Bodek addr[5] = (mac_l & 0x000000ff); 395a8d7fc4aSZbigniew Bodek return (0); 396a8d7fc4aSZbigniew Bodek } 397a8d7fc4aSZbigniew Bodek 398a8d7fc4aSZbigniew Bodek STATIC boolean_t 399a8d7fc4aSZbigniew Bodek mvneta_has_switch(device_t self) 400a8d7fc4aSZbigniew Bodek { 4015572fda3SWojciech Macek #ifdef FDT 4025572fda3SWojciech Macek return (mvneta_has_switch_fdt(self)); 4035572fda3SWojciech Macek #endif 404a8d7fc4aSZbigniew Bodek 4055572fda3SWojciech Macek return (false); 406a8d7fc4aSZbigniew Bodek } 407a8d7fc4aSZbigniew Bodek 408a8d7fc4aSZbigniew Bodek STATIC int 409a8d7fc4aSZbigniew Bodek mvneta_dma_create(struct mvneta_softc *sc) 410a8d7fc4aSZbigniew Bodek { 411a8d7fc4aSZbigniew Bodek size_t maxsize, maxsegsz; 412a8d7fc4aSZbigniew Bodek size_t q; 413a8d7fc4aSZbigniew Bodek int error; 414a8d7fc4aSZbigniew Bodek 415a8d7fc4aSZbigniew Bodek /* 416a8d7fc4aSZbigniew Bodek * Create Tx DMA 417a8d7fc4aSZbigniew Bodek */ 418a8d7fc4aSZbigniew Bodek maxsize = maxsegsz = sizeof(struct mvneta_tx_desc) * MVNETA_TX_RING_CNT; 419a8d7fc4aSZbigniew Bodek 420a8d7fc4aSZbigniew Bodek error = bus_dma_tag_create( 421a8d7fc4aSZbigniew Bodek bus_get_dma_tag(sc->dev), /* parent */ 422a8d7fc4aSZbigniew Bodek 16, 0, /* alignment, boundary */ 423a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 424a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR, /* highaddr */ 425a8d7fc4aSZbigniew Bodek NULL, NULL, /* filtfunc, filtfuncarg */ 426a8d7fc4aSZbigniew Bodek maxsize, /* maxsize */ 427a8d7fc4aSZbigniew Bodek 1, /* nsegments */ 428a8d7fc4aSZbigniew Bodek maxsegsz, /* maxsegsz */ 429a8d7fc4aSZbigniew Bodek 0, /* flags */ 430a8d7fc4aSZbigniew Bodek NULL, NULL, /* lockfunc, lockfuncarg */ 431a8d7fc4aSZbigniew Bodek &sc->tx_dtag); /* dmat */ 432a8d7fc4aSZbigniew Bodek if (error != 0) { 433a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 434a8d7fc4aSZbigniew Bodek "Failed to create DMA tag for Tx descriptors.\n"); 435a8d7fc4aSZbigniew Bodek goto fail; 436a8d7fc4aSZbigniew Bodek } 437a8d7fc4aSZbigniew Bodek error = bus_dma_tag_create( 438a8d7fc4aSZbigniew Bodek bus_get_dma_tag(sc->dev), /* parent */ 439a8d7fc4aSZbigniew Bodek 1, 0, /* alignment, boundary */ 440a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 441a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR, /* highaddr */ 442a8d7fc4aSZbigniew Bodek NULL, NULL, /* filtfunc, filtfuncarg */ 44373f20bb3SMarcin Wojtas MVNETA_MAX_FRAME, /* maxsize */ 444a8d7fc4aSZbigniew Bodek MVNETA_TX_SEGLIMIT, /* nsegments */ 44573f20bb3SMarcin Wojtas MVNETA_MAX_FRAME, /* maxsegsz */ 446a8d7fc4aSZbigniew Bodek BUS_DMA_ALLOCNOW, /* flags */ 447a8d7fc4aSZbigniew Bodek NULL, NULL, /* lockfunc, lockfuncarg */ 448a8d7fc4aSZbigniew Bodek &sc->txmbuf_dtag); 449a8d7fc4aSZbigniew Bodek if (error != 0) { 450a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 451a8d7fc4aSZbigniew Bodek "Failed to create DMA tag for Tx mbufs.\n"); 452a8d7fc4aSZbigniew Bodek goto fail; 453a8d7fc4aSZbigniew Bodek } 454a8d7fc4aSZbigniew Bodek 455a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 456a8d7fc4aSZbigniew Bodek error = mvneta_ring_alloc_tx_queue(sc, q); 457a8d7fc4aSZbigniew Bodek if (error != 0) { 458a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 459e314ac07SMarcin Wojtas "Failed to allocate DMA safe memory for TxQ: %zu\n", q); 460a8d7fc4aSZbigniew Bodek goto fail; 461a8d7fc4aSZbigniew Bodek } 462a8d7fc4aSZbigniew Bodek } 463a8d7fc4aSZbigniew Bodek 464a8d7fc4aSZbigniew Bodek /* 465a8d7fc4aSZbigniew Bodek * Create Rx DMA. 466a8d7fc4aSZbigniew Bodek */ 467a8d7fc4aSZbigniew Bodek /* Create tag for Rx descripors */ 468a8d7fc4aSZbigniew Bodek error = bus_dma_tag_create( 469a8d7fc4aSZbigniew Bodek bus_get_dma_tag(sc->dev), /* parent */ 470a8d7fc4aSZbigniew Bodek 32, 0, /* alignment, boundary */ 471a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 472a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR, /* highaddr */ 473a8d7fc4aSZbigniew Bodek NULL, NULL, /* filtfunc, filtfuncarg */ 474a8d7fc4aSZbigniew Bodek sizeof(struct mvneta_rx_desc) * MVNETA_RX_RING_CNT, /* maxsize */ 475a8d7fc4aSZbigniew Bodek 1, /* nsegments */ 476a8d7fc4aSZbigniew Bodek sizeof(struct mvneta_rx_desc) * MVNETA_RX_RING_CNT, /* maxsegsz */ 477a8d7fc4aSZbigniew Bodek 0, /* flags */ 478a8d7fc4aSZbigniew Bodek NULL, NULL, /* lockfunc, lockfuncarg */ 479a8d7fc4aSZbigniew Bodek &sc->rx_dtag); /* dmat */ 480a8d7fc4aSZbigniew Bodek if (error != 0) { 481a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 482a8d7fc4aSZbigniew Bodek "Failed to create DMA tag for Rx descriptors.\n"); 483a8d7fc4aSZbigniew Bodek goto fail; 484a8d7fc4aSZbigniew Bodek } 485a8d7fc4aSZbigniew Bodek 486a8d7fc4aSZbigniew Bodek /* Create tag for Rx buffers */ 487a8d7fc4aSZbigniew Bodek error = bus_dma_tag_create( 488a8d7fc4aSZbigniew Bodek bus_get_dma_tag(sc->dev), /* parent */ 489a8d7fc4aSZbigniew Bodek 32, 0, /* alignment, boundary */ 490a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 491a8d7fc4aSZbigniew Bodek BUS_SPACE_MAXADDR, /* highaddr */ 492a8d7fc4aSZbigniew Bodek NULL, NULL, /* filtfunc, filtfuncarg */ 49373f20bb3SMarcin Wojtas MVNETA_MAX_FRAME, 1, /* maxsize, nsegments */ 49473f20bb3SMarcin Wojtas MVNETA_MAX_FRAME, /* maxsegsz */ 495a8d7fc4aSZbigniew Bodek 0, /* flags */ 496a8d7fc4aSZbigniew Bodek NULL, NULL, /* lockfunc, lockfuncarg */ 497a8d7fc4aSZbigniew Bodek &sc->rxbuf_dtag); /* dmat */ 498a8d7fc4aSZbigniew Bodek if (error != 0) { 499a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 500a8d7fc4aSZbigniew Bodek "Failed to create DMA tag for Rx buffers.\n"); 501a8d7fc4aSZbigniew Bodek goto fail; 502a8d7fc4aSZbigniew Bodek } 503a8d7fc4aSZbigniew Bodek 504a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 505a8d7fc4aSZbigniew Bodek if (mvneta_ring_alloc_rx_queue(sc, q) != 0) { 506a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 507e314ac07SMarcin Wojtas "Failed to allocate DMA safe memory for RxQ: %zu\n", q); 508a8d7fc4aSZbigniew Bodek goto fail; 509a8d7fc4aSZbigniew Bodek } 510a8d7fc4aSZbigniew Bodek } 511a8d7fc4aSZbigniew Bodek 512a8d7fc4aSZbigniew Bodek return (0); 513a8d7fc4aSZbigniew Bodek fail: 514a8d7fc4aSZbigniew Bodek mvneta_detach(sc->dev); 515a8d7fc4aSZbigniew Bodek 516a8d7fc4aSZbigniew Bodek return (error); 517a8d7fc4aSZbigniew Bodek } 518a8d7fc4aSZbigniew Bodek 519a8d7fc4aSZbigniew Bodek /* ARGSUSED */ 520a8d7fc4aSZbigniew Bodek int 521a8d7fc4aSZbigniew Bodek mvneta_attach(device_t self) 522a8d7fc4aSZbigniew Bodek { 523a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 524992fa62bSJustin Hibbits if_t ifp; 525a8d7fc4aSZbigniew Bodek device_t child; 526a8d7fc4aSZbigniew Bodek int ifm_target; 527a8d7fc4aSZbigniew Bodek int q, error; 528e314ac07SMarcin Wojtas #if !defined(__aarch64__) 529a8d7fc4aSZbigniew Bodek uint32_t reg; 530e314ac07SMarcin Wojtas #endif 5314885d6f3SHubert Mazur clk_t clk; 53206c30b2cSAlbert Jakieła 533a8d7fc4aSZbigniew Bodek sc = device_get_softc(self); 534a8d7fc4aSZbigniew Bodek sc->dev = self; 535a8d7fc4aSZbigniew Bodek 536a8d7fc4aSZbigniew Bodek mtx_init(&sc->mtx, "mvneta_sc", NULL, MTX_DEF); 537a8d7fc4aSZbigniew Bodek 538a8d7fc4aSZbigniew Bodek error = bus_alloc_resources(self, res_spec, sc->res); 539a8d7fc4aSZbigniew Bodek if (error) { 540a8d7fc4aSZbigniew Bodek device_printf(self, "could not allocate resources\n"); 541a8d7fc4aSZbigniew Bodek return (ENXIO); 542a8d7fc4aSZbigniew Bodek } 543a8d7fc4aSZbigniew Bodek 544a8d7fc4aSZbigniew Bodek sc->version = MVNETA_READ(sc, MVNETA_PV); 545a8d7fc4aSZbigniew Bodek device_printf(self, "version is %x\n", sc->version); 546a8d7fc4aSZbigniew Bodek callout_init(&sc->tick_ch, 0); 547a8d7fc4aSZbigniew Bodek 548a8d7fc4aSZbigniew Bodek /* 549a8d7fc4aSZbigniew Bodek * make sure DMA engines are in reset state 550a8d7fc4aSZbigniew Bodek */ 551a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXINIT, 0x00000001); 552a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXINIT, 0x00000001); 553a8d7fc4aSZbigniew Bodek 5544885d6f3SHubert Mazur error = clk_get_by_ofw_index(sc->dev, ofw_bus_get_node(sc->dev), 0, 5554885d6f3SHubert Mazur &clk); 5564885d6f3SHubert Mazur if (error != 0) { 55706c30b2cSAlbert Jakieła #if defined(__aarch64__) 5584885d6f3SHubert Mazur device_printf(sc->dev, 5594885d6f3SHubert Mazur "Cannot get clock, using default frequency: %d\n", 5604885d6f3SHubert Mazur A3700_TCLK_250MHZ); 5614885d6f3SHubert Mazur sc->clk_freq = A3700_TCLK_250MHZ; 56206c30b2cSAlbert Jakieła #else 56306c30b2cSAlbert Jakieła device_printf(sc->dev, 56406c30b2cSAlbert Jakieła "Cannot get clock, using get_tclk()\n"); 56506c30b2cSAlbert Jakieła sc->clk_freq = get_tclk(); 56606c30b2cSAlbert Jakieła #endif 5674885d6f3SHubert Mazur } else { 5684885d6f3SHubert Mazur error = clk_get_freq(clk, &sc->clk_freq); 5694885d6f3SHubert Mazur if (error != 0) { 5704885d6f3SHubert Mazur device_printf(sc->dev, 5714885d6f3SHubert Mazur "Cannot obtain frequency from parent clock\n"); 5724885d6f3SHubert Mazur bus_release_resources(sc->dev, res_spec, sc->res); 5734885d6f3SHubert Mazur return (error); 5744885d6f3SHubert Mazur } 5754885d6f3SHubert Mazur } 5764885d6f3SHubert Mazur 577e314ac07SMarcin Wojtas #if !defined(__aarch64__) 578a8d7fc4aSZbigniew Bodek /* 579a8d7fc4aSZbigniew Bodek * Disable port snoop for buffers and descriptors 580a8d7fc4aSZbigniew Bodek * to avoid L2 caching of both without DRAM copy. 581a8d7fc4aSZbigniew Bodek * Obtain coherency settings from the first MBUS 582a8d7fc4aSZbigniew Bodek * window attribute. 583a8d7fc4aSZbigniew Bodek */ 584a8d7fc4aSZbigniew Bodek if ((MVNETA_READ(sc, MV_WIN_NETA_BASE(0)) & IO_WIN_COH_ATTR_MASK) == 0) { 585a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PSNPCFG); 586a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PSNPCFG_DESCSNP_MASK; 587a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PSNPCFG_BUFSNP_MASK; 588a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PSNPCFG, reg); 589a8d7fc4aSZbigniew Bodek } 590e314ac07SMarcin Wojtas #endif 591a8d7fc4aSZbigniew Bodek 592b831f9ceSHubert Mazur error = bus_setup_intr(self, sc->res[1], 593b831f9ceSHubert Mazur INTR_TYPE_NET | INTR_MPSAFE, NULL, mvneta_intrs[0].handler, sc, 594b831f9ceSHubert Mazur &sc->ih_cookie[0]); 595b831f9ceSHubert Mazur if (error) { 596b831f9ceSHubert Mazur device_printf(self, "could not setup %s\n", 597b831f9ceSHubert Mazur mvneta_intrs[0].description); 598b831f9ceSHubert Mazur mvneta_detach(self); 599b831f9ceSHubert Mazur return (error); 600b831f9ceSHubert Mazur } 601b831f9ceSHubert Mazur 602a8d7fc4aSZbigniew Bodek /* 603a8d7fc4aSZbigniew Bodek * MAC address 604a8d7fc4aSZbigniew Bodek */ 605a8d7fc4aSZbigniew Bodek if (mvneta_get_mac_address(sc, sc->enaddr)) { 606a8d7fc4aSZbigniew Bodek device_printf(self, "no mac address.\n"); 607a8d7fc4aSZbigniew Bodek return (ENXIO); 608a8d7fc4aSZbigniew Bodek } 609a8d7fc4aSZbigniew Bodek mvneta_set_mac_address(sc, sc->enaddr); 610a8d7fc4aSZbigniew Bodek 611a8d7fc4aSZbigniew Bodek mvneta_disable_intr(sc); 612a8d7fc4aSZbigniew Bodek 613a8d7fc4aSZbigniew Bodek /* Allocate network interface */ 614a8d7fc4aSZbigniew Bodek ifp = sc->ifp = if_alloc(IFT_ETHER); 615a8d7fc4aSZbigniew Bodek if_initname(ifp, device_get_name(self), device_get_unit(self)); 616a8d7fc4aSZbigniew Bodek 617a8d7fc4aSZbigniew Bodek /* 618a8d7fc4aSZbigniew Bodek * We can support 802.1Q VLAN-sized frames and jumbo 619a8d7fc4aSZbigniew Bodek * Ethernet frames. 620a8d7fc4aSZbigniew Bodek */ 621992fa62bSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU, 0); 622a8d7fc4aSZbigniew Bodek 623992fa62bSJustin Hibbits if_setsoftc(ifp, sc); 624992fa62bSJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 625a8d7fc4aSZbigniew Bodek #ifdef MVNETA_MULTIQUEUE 626992fa62bSJustin Hibbits if_settransmitfn(ifp, mvneta_transmit); 627992fa62bSJustin Hibbits if_setqflushfn(ifp, mvneta_qflush); 628a8d7fc4aSZbigniew Bodek #else /* !MVNETA_MULTIQUEUE */ 629992fa62bSJustin Hibbits if_setstartfn(ifp, mvneta_start); 630992fa62bSJustin Hibbits if_setsendqlen(ifp, MVNETA_TX_RING_CNT - 1); 631992fa62bSJustin Hibbits if_setsendqready(ifp); 632a8d7fc4aSZbigniew Bodek #endif 633992fa62bSJustin Hibbits if_setinitfn(ifp, mvneta_init); 634992fa62bSJustin Hibbits if_setioctlfn(ifp, mvneta_ioctl); 635a8d7fc4aSZbigniew Bodek 636a8d7fc4aSZbigniew Bodek /* 637a8d7fc4aSZbigniew Bodek * We can do IPv4/TCPv4/UDPv4/TCPv6/UDPv6 checksums in hardware. 638a8d7fc4aSZbigniew Bodek */ 639992fa62bSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_HWCSUM, 0); 640a8d7fc4aSZbigniew Bodek 641a8d7fc4aSZbigniew Bodek /* 642a8d7fc4aSZbigniew Bodek * As VLAN hardware tagging is not supported 643a8d7fc4aSZbigniew Bodek * but is necessary to perform VLAN hardware checksums, 644a8d7fc4aSZbigniew Bodek * it is done in the driver 645a8d7fc4aSZbigniew Bodek */ 646992fa62bSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM, 0); 647a8d7fc4aSZbigniew Bodek 648a8d7fc4aSZbigniew Bodek /* 649a8d7fc4aSZbigniew Bodek * Currently IPv6 HW checksum is broken, so make sure it is disabled. 650a8d7fc4aSZbigniew Bodek */ 651992fa62bSJustin Hibbits if_setcapabilitiesbit(ifp, 0, IFCAP_HWCSUM_IPV6); 652992fa62bSJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 653a8d7fc4aSZbigniew Bodek 654a8d7fc4aSZbigniew Bodek /* 655a8d7fc4aSZbigniew Bodek * Disabled option(s): 656a8d7fc4aSZbigniew Bodek * - Support for Large Receive Offload 657a8d7fc4aSZbigniew Bodek */ 658992fa62bSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_LRO, 0); 659a8d7fc4aSZbigniew Bodek 660992fa62bSJustin Hibbits if_sethwassist(ifp, CSUM_IP | CSUM_TCP | CSUM_UDP); 661a8d7fc4aSZbigniew Bodek 66273f20bb3SMarcin Wojtas sc->rx_frame_size = MCLBYTES; /* ether_ifattach() always sets normal mtu */ 66373f20bb3SMarcin Wojtas 664a8d7fc4aSZbigniew Bodek /* 665a8d7fc4aSZbigniew Bodek * Device DMA Buffer allocation. 666a8d7fc4aSZbigniew Bodek * Handles resource deallocation in case of failure. 667a8d7fc4aSZbigniew Bodek */ 668a8d7fc4aSZbigniew Bodek error = mvneta_dma_create(sc); 669a8d7fc4aSZbigniew Bodek if (error != 0) { 670a8d7fc4aSZbigniew Bodek mvneta_detach(self); 671a8d7fc4aSZbigniew Bodek return (error); 672a8d7fc4aSZbigniew Bodek } 673a8d7fc4aSZbigniew Bodek 674a8d7fc4aSZbigniew Bodek /* Initialize queues */ 675a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 676a8d7fc4aSZbigniew Bodek error = mvneta_ring_init_tx_queue(sc, q); 677a8d7fc4aSZbigniew Bodek if (error != 0) { 678a8d7fc4aSZbigniew Bodek mvneta_detach(self); 679a8d7fc4aSZbigniew Bodek return (error); 680a8d7fc4aSZbigniew Bodek } 681a8d7fc4aSZbigniew Bodek } 682a8d7fc4aSZbigniew Bodek 683a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 684a8d7fc4aSZbigniew Bodek error = mvneta_ring_init_rx_queue(sc, q); 685a8d7fc4aSZbigniew Bodek if (error != 0) { 686a8d7fc4aSZbigniew Bodek mvneta_detach(self); 687a8d7fc4aSZbigniew Bodek return (error); 688a8d7fc4aSZbigniew Bodek } 689a8d7fc4aSZbigniew Bodek } 690a8d7fc4aSZbigniew Bodek 691a8d7fc4aSZbigniew Bodek /* 692a8d7fc4aSZbigniew Bodek * Enable DMA engines and Initialize Device Registers. 693a8d7fc4aSZbigniew Bodek */ 694a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXINIT, 0x00000000); 695a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXINIT, 0x00000000); 696a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PACC, MVNETA_PACC_ACCELERATIONMODE_EDM); 697a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 698a8d7fc4aSZbigniew Bodek mvneta_filter_setup(sc); 699a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 700a8d7fc4aSZbigniew Bodek mvneta_initreg(ifp); 701a8d7fc4aSZbigniew Bodek 702a8d7fc4aSZbigniew Bodek /* 703a8d7fc4aSZbigniew Bodek * Now MAC is working, setup MII. 704a8d7fc4aSZbigniew Bodek */ 705a8d7fc4aSZbigniew Bodek if (mii_init == 0) { 706a8d7fc4aSZbigniew Bodek /* 707a8d7fc4aSZbigniew Bodek * MII bus is shared by all MACs and all PHYs in SoC. 708a8d7fc4aSZbigniew Bodek * serializing the bus access should be safe. 709a8d7fc4aSZbigniew Bodek */ 710a8d7fc4aSZbigniew Bodek mtx_init(&mii_mutex, "mvneta_mii", NULL, MTX_DEF); 711a8d7fc4aSZbigniew Bodek mii_init = 1; 712a8d7fc4aSZbigniew Bodek } 713a8d7fc4aSZbigniew Bodek 714a8d7fc4aSZbigniew Bodek /* Attach PHY(s) */ 715a8d7fc4aSZbigniew Bodek if ((sc->phy_addr != MII_PHY_ANY) && (!sc->use_inband_status)) { 716a8d7fc4aSZbigniew Bodek error = mii_attach(self, &sc->miibus, ifp, mvneta_mediachange, 717a8d7fc4aSZbigniew Bodek mvneta_mediastatus, BMSR_DEFCAPMASK, sc->phy_addr, 718a8d7fc4aSZbigniew Bodek MII_OFFSET_ANY, 0); 719a8d7fc4aSZbigniew Bodek if (error != 0) { 720ed166a01SMark Johnston device_printf(self, "MII attach failed, error: %d\n", 721ed166a01SMark Johnston error); 722a8d7fc4aSZbigniew Bodek ether_ifdetach(sc->ifp); 723a8d7fc4aSZbigniew Bodek mvneta_detach(self); 724a8d7fc4aSZbigniew Bodek return (error); 725a8d7fc4aSZbigniew Bodek } 726a8d7fc4aSZbigniew Bodek sc->mii = device_get_softc(sc->miibus); 727a8d7fc4aSZbigniew Bodek sc->phy_attached = 1; 728a8d7fc4aSZbigniew Bodek 729a8d7fc4aSZbigniew Bodek /* Disable auto-negotiation in MAC - rely on PHY layer */ 730a8d7fc4aSZbigniew Bodek mvneta_update_autoneg(sc, FALSE); 731a8d7fc4aSZbigniew Bodek } else if (sc->use_inband_status == TRUE) { 732a8d7fc4aSZbigniew Bodek /* In-band link status */ 733a8d7fc4aSZbigniew Bodek ifmedia_init(&sc->mvneta_ifmedia, 0, mvneta_mediachange, 734a8d7fc4aSZbigniew Bodek mvneta_mediastatus); 735a8d7fc4aSZbigniew Bodek 736a8d7fc4aSZbigniew Bodek /* Configure media */ 737a8d7fc4aSZbigniew Bodek ifmedia_add(&sc->mvneta_ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX, 738a8d7fc4aSZbigniew Bodek 0, NULL); 739a8d7fc4aSZbigniew Bodek ifmedia_add(&sc->mvneta_ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL); 740a8d7fc4aSZbigniew Bodek ifmedia_add(&sc->mvneta_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 741a8d7fc4aSZbigniew Bodek 0, NULL); 742a8d7fc4aSZbigniew Bodek ifmedia_add(&sc->mvneta_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL); 743a8d7fc4aSZbigniew Bodek ifmedia_add(&sc->mvneta_ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 744a8d7fc4aSZbigniew Bodek 0, NULL); 745a8d7fc4aSZbigniew Bodek ifmedia_add(&sc->mvneta_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); 746a8d7fc4aSZbigniew Bodek ifmedia_set(&sc->mvneta_ifmedia, IFM_ETHER | IFM_AUTO); 747a8d7fc4aSZbigniew Bodek 748a8d7fc4aSZbigniew Bodek /* Enable auto-negotiation */ 749a8d7fc4aSZbigniew Bodek mvneta_update_autoneg(sc, TRUE); 750a8d7fc4aSZbigniew Bodek 751a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 752a8d7fc4aSZbigniew Bodek if (MVNETA_IS_LINKUP(sc)) 753a8d7fc4aSZbigniew Bodek mvneta_linkup(sc); 754a8d7fc4aSZbigniew Bodek else 755a8d7fc4aSZbigniew Bodek mvneta_linkdown(sc); 756a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 757a8d7fc4aSZbigniew Bodek 758a8d7fc4aSZbigniew Bodek } else { 759a8d7fc4aSZbigniew Bodek /* Fixed-link, use predefined values */ 760e13a20daSLuiz Otavio O Souza mvneta_update_autoneg(sc, FALSE); 761a8d7fc4aSZbigniew Bodek ifmedia_init(&sc->mvneta_ifmedia, 0, mvneta_mediachange, 762a8d7fc4aSZbigniew Bodek mvneta_mediastatus); 763a8d7fc4aSZbigniew Bodek 764a8d7fc4aSZbigniew Bodek ifm_target = IFM_ETHER; 765a8d7fc4aSZbigniew Bodek switch (sc->phy_speed) { 766a8d7fc4aSZbigniew Bodek case 2500: 767a8d7fc4aSZbigniew Bodek if (sc->phy_mode != MVNETA_PHY_SGMII && 768a8d7fc4aSZbigniew Bodek sc->phy_mode != MVNETA_PHY_QSGMII) { 769a8d7fc4aSZbigniew Bodek device_printf(self, 770a8d7fc4aSZbigniew Bodek "2.5G speed can work only in (Q)SGMII mode\n"); 771a8d7fc4aSZbigniew Bodek ether_ifdetach(sc->ifp); 772a8d7fc4aSZbigniew Bodek mvneta_detach(self); 773a8d7fc4aSZbigniew Bodek return (ENXIO); 774a8d7fc4aSZbigniew Bodek } 775a8d7fc4aSZbigniew Bodek ifm_target |= IFM_2500_T; 776a8d7fc4aSZbigniew Bodek break; 777a8d7fc4aSZbigniew Bodek case 1000: 778a8d7fc4aSZbigniew Bodek ifm_target |= IFM_1000_T; 779a8d7fc4aSZbigniew Bodek break; 780a8d7fc4aSZbigniew Bodek case 100: 781a8d7fc4aSZbigniew Bodek ifm_target |= IFM_100_TX; 782a8d7fc4aSZbigniew Bodek break; 783a8d7fc4aSZbigniew Bodek case 10: 784a8d7fc4aSZbigniew Bodek ifm_target |= IFM_10_T; 785a8d7fc4aSZbigniew Bodek break; 786a8d7fc4aSZbigniew Bodek default: 787a8d7fc4aSZbigniew Bodek ether_ifdetach(sc->ifp); 788a8d7fc4aSZbigniew Bodek mvneta_detach(self); 789a8d7fc4aSZbigniew Bodek return (ENXIO); 790a8d7fc4aSZbigniew Bodek } 791a8d7fc4aSZbigniew Bodek 792a8d7fc4aSZbigniew Bodek if (sc->phy_fdx) 793a8d7fc4aSZbigniew Bodek ifm_target |= IFM_FDX; 794a8d7fc4aSZbigniew Bodek else 795a8d7fc4aSZbigniew Bodek ifm_target |= IFM_HDX; 796a8d7fc4aSZbigniew Bodek 797a8d7fc4aSZbigniew Bodek ifmedia_add(&sc->mvneta_ifmedia, ifm_target, 0, NULL); 798a8d7fc4aSZbigniew Bodek ifmedia_set(&sc->mvneta_ifmedia, ifm_target); 799a8d7fc4aSZbigniew Bodek if_link_state_change(sc->ifp, LINK_STATE_UP); 800a8d7fc4aSZbigniew Bodek 801a8d7fc4aSZbigniew Bodek if (mvneta_has_switch(self)) { 8020fd68d72SMarcin Wojtas if (bootverbose) 8030fd68d72SMarcin Wojtas device_printf(self, "This device is attached to a switch\n"); 8045b56413dSWarner Losh child = device_add_child(sc->dev, "mdio", DEVICE_UNIT_ANY); 805a8d7fc4aSZbigniew Bodek if (child == NULL) { 806a8d7fc4aSZbigniew Bodek ether_ifdetach(sc->ifp); 807a8d7fc4aSZbigniew Bodek mvneta_detach(self); 808a8d7fc4aSZbigniew Bodek return (ENXIO); 809a8d7fc4aSZbigniew Bodek } 81018250ec6SJohn Baldwin bus_attach_children(sc->dev); 81118250ec6SJohn Baldwin bus_attach_children(child); 812a8d7fc4aSZbigniew Bodek } 813a8d7fc4aSZbigniew Bodek 814a8d7fc4aSZbigniew Bodek /* Configure MAC media */ 815a8d7fc4aSZbigniew Bodek mvneta_update_media(sc, ifm_target); 816a8d7fc4aSZbigniew Bodek } 817a8d7fc4aSZbigniew Bodek 818b831f9ceSHubert Mazur ether_ifattach(ifp, sc->enaddr); 819a8d7fc4aSZbigniew Bodek 820a8d7fc4aSZbigniew Bodek callout_reset(&sc->tick_ch, 0, mvneta_tick, sc); 821a8d7fc4aSZbigniew Bodek 822b831f9ceSHubert Mazur sysctl_mvneta_init(sc); 823a8d7fc4aSZbigniew Bodek 824a8d7fc4aSZbigniew Bodek return (0); 825a8d7fc4aSZbigniew Bodek } 826a8d7fc4aSZbigniew Bodek 827a8d7fc4aSZbigniew Bodek STATIC int 828a8d7fc4aSZbigniew Bodek mvneta_detach(device_t dev) 829a8d7fc4aSZbigniew Bodek { 830a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 831a8d7fc4aSZbigniew Bodek int q; 832a8d7fc4aSZbigniew Bodek 833a8d7fc4aSZbigniew Bodek sc = device_get_softc(dev); 834a8d7fc4aSZbigniew Bodek 835b831f9ceSHubert Mazur if (device_is_attached(dev)) { 836a8d7fc4aSZbigniew Bodek mvneta_stop(sc); 837b831f9ceSHubert Mazur callout_drain(&sc->tick_ch); 838b831f9ceSHubert Mazur ether_ifdetach(sc->ifp); 839b831f9ceSHubert Mazur } 840a8d7fc4aSZbigniew Bodek 841a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) 842a8d7fc4aSZbigniew Bodek mvneta_ring_dealloc_rx_queue(sc, q); 843a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) 844a8d7fc4aSZbigniew Bodek mvneta_ring_dealloc_tx_queue(sc, q); 845a8d7fc4aSZbigniew Bodek 846*3ddaf820SJohn Baldwin bus_generic_detach(dev); 847b831f9ceSHubert Mazur 848b831f9ceSHubert Mazur if (sc->ih_cookie[0] != NULL) 849b831f9ceSHubert Mazur bus_teardown_intr(dev, sc->res[1], sc->ih_cookie[0]); 850b831f9ceSHubert Mazur 851a8d7fc4aSZbigniew Bodek if (sc->tx_dtag != NULL) 852a8d7fc4aSZbigniew Bodek bus_dma_tag_destroy(sc->tx_dtag); 853a8d7fc4aSZbigniew Bodek if (sc->rx_dtag != NULL) 854a8d7fc4aSZbigniew Bodek bus_dma_tag_destroy(sc->rx_dtag); 855a8d7fc4aSZbigniew Bodek if (sc->txmbuf_dtag != NULL) 856a8d7fc4aSZbigniew Bodek bus_dma_tag_destroy(sc->txmbuf_dtag); 8573599e81cSMarcin Wojtas if (sc->rxbuf_dtag != NULL) 8583599e81cSMarcin Wojtas bus_dma_tag_destroy(sc->rxbuf_dtag); 859a8d7fc4aSZbigniew Bodek 860a8d7fc4aSZbigniew Bodek bus_release_resources(dev, res_spec, sc->res); 861b831f9ceSHubert Mazur 862b831f9ceSHubert Mazur if (sc->ifp) 863b831f9ceSHubert Mazur if_free(sc->ifp); 864b831f9ceSHubert Mazur 865b831f9ceSHubert Mazur if (mtx_initialized(&sc->mtx)) 866b831f9ceSHubert Mazur mtx_destroy(&sc->mtx); 867b831f9ceSHubert Mazur 868a8d7fc4aSZbigniew Bodek return (0); 869a8d7fc4aSZbigniew Bodek } 870a8d7fc4aSZbigniew Bodek 871a8d7fc4aSZbigniew Bodek /* 872a8d7fc4aSZbigniew Bodek * MII 873a8d7fc4aSZbigniew Bodek */ 874a8d7fc4aSZbigniew Bodek STATIC int 875a8d7fc4aSZbigniew Bodek mvneta_miibus_readreg(device_t dev, int phy, int reg) 876a8d7fc4aSZbigniew Bodek { 877a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 878992fa62bSJustin Hibbits if_t ifp; 879a8d7fc4aSZbigniew Bodek uint32_t smi, val; 880a8d7fc4aSZbigniew Bodek int i; 881a8d7fc4aSZbigniew Bodek 882a8d7fc4aSZbigniew Bodek sc = device_get_softc(dev); 883a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 884a8d7fc4aSZbigniew Bodek 885a8d7fc4aSZbigniew Bodek mtx_lock(&mii_mutex); 886a8d7fc4aSZbigniew Bodek 887a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 888a8d7fc4aSZbigniew Bodek if ((MVNETA_READ(sc, MVNETA_SMI) & MVNETA_SMI_BUSY) == 0) 889a8d7fc4aSZbigniew Bodek break; 890a8d7fc4aSZbigniew Bodek DELAY(1); 891a8d7fc4aSZbigniew Bodek } 892a8d7fc4aSZbigniew Bodek if (i == MVNETA_PHY_TIMEOUT) { 893a8d7fc4aSZbigniew Bodek if_printf(ifp, "SMI busy timeout\n"); 894a8d7fc4aSZbigniew Bodek mtx_unlock(&mii_mutex); 895a8d7fc4aSZbigniew Bodek return (-1); 896a8d7fc4aSZbigniew Bodek } 897a8d7fc4aSZbigniew Bodek 898a8d7fc4aSZbigniew Bodek smi = MVNETA_SMI_PHYAD(phy) | 899a8d7fc4aSZbigniew Bodek MVNETA_SMI_REGAD(reg) | MVNETA_SMI_OPCODE_READ; 900a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_SMI, smi); 901a8d7fc4aSZbigniew Bodek 902a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 903a8d7fc4aSZbigniew Bodek if ((MVNETA_READ(sc, MVNETA_SMI) & MVNETA_SMI_BUSY) == 0) 904a8d7fc4aSZbigniew Bodek break; 905a8d7fc4aSZbigniew Bodek DELAY(1); 906a8d7fc4aSZbigniew Bodek } 907a8d7fc4aSZbigniew Bodek 908a8d7fc4aSZbigniew Bodek if (i == MVNETA_PHY_TIMEOUT) { 909a8d7fc4aSZbigniew Bodek if_printf(ifp, "SMI busy timeout\n"); 910a8d7fc4aSZbigniew Bodek mtx_unlock(&mii_mutex); 911a8d7fc4aSZbigniew Bodek return (-1); 912a8d7fc4aSZbigniew Bodek } 913a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 914a8d7fc4aSZbigniew Bodek smi = MVNETA_READ(sc, MVNETA_SMI); 915a8d7fc4aSZbigniew Bodek if (smi & MVNETA_SMI_READVALID) 916a8d7fc4aSZbigniew Bodek break; 917a8d7fc4aSZbigniew Bodek DELAY(1); 918a8d7fc4aSZbigniew Bodek } 919a8d7fc4aSZbigniew Bodek 920a8d7fc4aSZbigniew Bodek if (i == MVNETA_PHY_TIMEOUT) { 921a8d7fc4aSZbigniew Bodek if_printf(ifp, "SMI busy timeout\n"); 922a8d7fc4aSZbigniew Bodek mtx_unlock(&mii_mutex); 923a8d7fc4aSZbigniew Bodek return (-1); 924a8d7fc4aSZbigniew Bodek } 925a8d7fc4aSZbigniew Bodek 926a8d7fc4aSZbigniew Bodek mtx_unlock(&mii_mutex); 927a8d7fc4aSZbigniew Bodek 928a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 929992fa62bSJustin Hibbits CTR3(KTR_SPARE2, "%s i=%d, timeout=%d\n", if_getname(ifp), i, 930a8d7fc4aSZbigniew Bodek MVNETA_PHY_TIMEOUT); 931a8d7fc4aSZbigniew Bodek #endif 932a8d7fc4aSZbigniew Bodek 933a8d7fc4aSZbigniew Bodek val = smi & MVNETA_SMI_DATA_MASK; 934a8d7fc4aSZbigniew Bodek 935a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 936992fa62bSJustin Hibbits CTR4(KTR_SPARE2, "%s phy=%d, reg=%#x, val=%#x\n", if_getname(ifp), phy, 937a8d7fc4aSZbigniew Bodek reg, val); 938a8d7fc4aSZbigniew Bodek #endif 939a8d7fc4aSZbigniew Bodek return (val); 940a8d7fc4aSZbigniew Bodek } 941a8d7fc4aSZbigniew Bodek 942a8d7fc4aSZbigniew Bodek STATIC int 943a8d7fc4aSZbigniew Bodek mvneta_miibus_writereg(device_t dev, int phy, int reg, int val) 944a8d7fc4aSZbigniew Bodek { 945a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 946992fa62bSJustin Hibbits if_t ifp; 947a8d7fc4aSZbigniew Bodek uint32_t smi; 948a8d7fc4aSZbigniew Bodek int i; 949a8d7fc4aSZbigniew Bodek 950a8d7fc4aSZbigniew Bodek sc = device_get_softc(dev); 951a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 952a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 953992fa62bSJustin Hibbits CTR4(KTR_SPARE2, "%s phy=%d, reg=%#x, val=%#x\n", if_name(ifp), 954a8d7fc4aSZbigniew Bodek phy, reg, val); 955a8d7fc4aSZbigniew Bodek #endif 956a8d7fc4aSZbigniew Bodek 957a8d7fc4aSZbigniew Bodek mtx_lock(&mii_mutex); 958a8d7fc4aSZbigniew Bodek 959a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 960a8d7fc4aSZbigniew Bodek if ((MVNETA_READ(sc, MVNETA_SMI) & MVNETA_SMI_BUSY) == 0) 961a8d7fc4aSZbigniew Bodek break; 962a8d7fc4aSZbigniew Bodek DELAY(1); 963a8d7fc4aSZbigniew Bodek } 964a8d7fc4aSZbigniew Bodek if (i == MVNETA_PHY_TIMEOUT) { 965a8d7fc4aSZbigniew Bodek if_printf(ifp, "SMI busy timeout\n"); 966a8d7fc4aSZbigniew Bodek mtx_unlock(&mii_mutex); 967a8d7fc4aSZbigniew Bodek return (0); 968a8d7fc4aSZbigniew Bodek } 969a8d7fc4aSZbigniew Bodek 970a8d7fc4aSZbigniew Bodek smi = MVNETA_SMI_PHYAD(phy) | MVNETA_SMI_REGAD(reg) | 971a8d7fc4aSZbigniew Bodek MVNETA_SMI_OPCODE_WRITE | (val & MVNETA_SMI_DATA_MASK); 972a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_SMI, smi); 973a8d7fc4aSZbigniew Bodek 974a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_PHY_TIMEOUT; i++) { 975a8d7fc4aSZbigniew Bodek if ((MVNETA_READ(sc, MVNETA_SMI) & MVNETA_SMI_BUSY) == 0) 976a8d7fc4aSZbigniew Bodek break; 977a8d7fc4aSZbigniew Bodek DELAY(1); 978a8d7fc4aSZbigniew Bodek } 979a8d7fc4aSZbigniew Bodek 980a8d7fc4aSZbigniew Bodek mtx_unlock(&mii_mutex); 981a8d7fc4aSZbigniew Bodek 982a8d7fc4aSZbigniew Bodek if (i == MVNETA_PHY_TIMEOUT) 983a8d7fc4aSZbigniew Bodek if_printf(ifp, "phy write timed out\n"); 984a8d7fc4aSZbigniew Bodek 985a8d7fc4aSZbigniew Bodek return (0); 986a8d7fc4aSZbigniew Bodek } 987a8d7fc4aSZbigniew Bodek 988a8d7fc4aSZbigniew Bodek STATIC void 989a8d7fc4aSZbigniew Bodek mvneta_portup(struct mvneta_softc *sc) 990a8d7fc4aSZbigniew Bodek { 991a8d7fc4aSZbigniew Bodek int q; 992a8d7fc4aSZbigniew Bodek 993a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 994a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 995a8d7fc4aSZbigniew Bodek mvneta_rx_queue_enable(sc->ifp, q); 996a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 997a8d7fc4aSZbigniew Bodek } 998a8d7fc4aSZbigniew Bodek 999a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 1000a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, q); 1001a8d7fc4aSZbigniew Bodek mvneta_tx_queue_enable(sc->ifp, q); 1002a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 1003a8d7fc4aSZbigniew Bodek } 1004a8d7fc4aSZbigniew Bodek 1005a8d7fc4aSZbigniew Bodek } 1006a8d7fc4aSZbigniew Bodek 1007a8d7fc4aSZbigniew Bodek STATIC void 1008a8d7fc4aSZbigniew Bodek mvneta_portdown(struct mvneta_softc *sc) 1009a8d7fc4aSZbigniew Bodek { 1010a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1011a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1012a8d7fc4aSZbigniew Bodek int q, cnt; 1013a8d7fc4aSZbigniew Bodek uint32_t reg; 1014a8d7fc4aSZbigniew Bodek 1015a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 1016a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1017a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 1018a8d7fc4aSZbigniew Bodek rx->queue_status = MVNETA_QUEUE_DISABLED; 1019a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 1020a8d7fc4aSZbigniew Bodek } 1021a8d7fc4aSZbigniew Bodek 1022a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 1023a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1024a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, q); 1025a8d7fc4aSZbigniew Bodek tx->queue_status = MVNETA_QUEUE_DISABLED; 1026a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 1027a8d7fc4aSZbigniew Bodek } 1028a8d7fc4aSZbigniew Bodek 1029a8d7fc4aSZbigniew Bodek /* Wait for all Rx activity to terminate. */ 1030a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_RQC) & MVNETA_RQC_EN_MASK; 1031a8d7fc4aSZbigniew Bodek reg = MVNETA_RQC_DIS(reg); 1032a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_RQC, reg); 1033a8d7fc4aSZbigniew Bodek cnt = 0; 1034a8d7fc4aSZbigniew Bodek do { 1035a8d7fc4aSZbigniew Bodek if (cnt >= RX_DISABLE_TIMEOUT) { 1036a8d7fc4aSZbigniew Bodek if_printf(sc->ifp, 1037a8d7fc4aSZbigniew Bodek "timeout for RX stopped. rqc 0x%x\n", reg); 1038a8d7fc4aSZbigniew Bodek break; 1039a8d7fc4aSZbigniew Bodek } 1040a8d7fc4aSZbigniew Bodek cnt++; 1041a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_RQC); 1042a8d7fc4aSZbigniew Bodek } while ((reg & MVNETA_RQC_EN_MASK) != 0); 1043a8d7fc4aSZbigniew Bodek 1044a8d7fc4aSZbigniew Bodek /* Wait for all Tx activity to terminate. */ 1045a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PIE); 1046a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PIE_TXPKTINTRPTENB_MASK; 1047a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PIE, reg); 1048a8d7fc4aSZbigniew Bodek 1049a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PRXTXTIM); 1050a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PRXTXTI_TBTCQ_MASK; 1051a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXTIM, reg); 1052a8d7fc4aSZbigniew Bodek 1053a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_TQC) & MVNETA_TQC_EN_MASK; 1054a8d7fc4aSZbigniew Bodek reg = MVNETA_TQC_DIS(reg); 1055a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_TQC, reg); 1056a8d7fc4aSZbigniew Bodek cnt = 0; 1057a8d7fc4aSZbigniew Bodek do { 1058a8d7fc4aSZbigniew Bodek if (cnt >= TX_DISABLE_TIMEOUT) { 1059a8d7fc4aSZbigniew Bodek if_printf(sc->ifp, 1060a8d7fc4aSZbigniew Bodek "timeout for TX stopped. tqc 0x%x\n", reg); 1061a8d7fc4aSZbigniew Bodek break; 1062a8d7fc4aSZbigniew Bodek } 1063a8d7fc4aSZbigniew Bodek cnt++; 1064a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_TQC); 1065a8d7fc4aSZbigniew Bodek } while ((reg & MVNETA_TQC_EN_MASK) != 0); 1066a8d7fc4aSZbigniew Bodek 1067a8d7fc4aSZbigniew Bodek /* Wait for all Tx FIFO is empty */ 1068a8d7fc4aSZbigniew Bodek cnt = 0; 1069a8d7fc4aSZbigniew Bodek do { 1070a8d7fc4aSZbigniew Bodek if (cnt >= TX_FIFO_EMPTY_TIMEOUT) { 1071a8d7fc4aSZbigniew Bodek if_printf(sc->ifp, 1072a8d7fc4aSZbigniew Bodek "timeout for TX FIFO drained. ps0 0x%x\n", reg); 1073a8d7fc4aSZbigniew Bodek break; 1074a8d7fc4aSZbigniew Bodek } 1075a8d7fc4aSZbigniew Bodek cnt++; 1076a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PS0); 1077a8d7fc4aSZbigniew Bodek } while (((reg & MVNETA_PS0_TXFIFOEMP) == 0) && 1078a8d7fc4aSZbigniew Bodek ((reg & MVNETA_PS0_TXINPROG) != 0)); 1079a8d7fc4aSZbigniew Bodek } 1080a8d7fc4aSZbigniew Bodek 1081a8d7fc4aSZbigniew Bodek /* 1082a8d7fc4aSZbigniew Bodek * Device Register Initialization 1083a8d7fc4aSZbigniew Bodek * reset device registers to device driver default value. 1084a8d7fc4aSZbigniew Bodek * the device is not enabled here. 1085a8d7fc4aSZbigniew Bodek */ 1086a8d7fc4aSZbigniew Bodek STATIC int 1087992fa62bSJustin Hibbits mvneta_initreg(if_t ifp) 1088a8d7fc4aSZbigniew Bodek { 1089a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1090caf552a6SMark Johnston int q; 1091a8d7fc4aSZbigniew Bodek uint32_t reg; 1092a8d7fc4aSZbigniew Bodek 1093992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1094a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 1095992fa62bSJustin Hibbits CTR1(KTR_SPARE2, "%s initializing device register", if_name(ifp)); 1096a8d7fc4aSZbigniew Bodek #endif 1097a8d7fc4aSZbigniew Bodek 1098a8d7fc4aSZbigniew Bodek /* Disable Legacy WRR, Disable EJP, Release from reset. */ 1099a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_TQC_1, 0); 1100a8d7fc4aSZbigniew Bodek /* Enable mbus retry. */ 1101a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_MBUS_CONF, MVNETA_MBUS_RETRY_EN); 1102a8d7fc4aSZbigniew Bodek 1103a8d7fc4aSZbigniew Bodek /* Init TX/RX Queue Registers */ 1104a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 1105a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 1106a8d7fc4aSZbigniew Bodek if (mvneta_rx_queue_init(ifp, q) != 0) { 1107a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 1108a8d7fc4aSZbigniew Bodek "initialization failed: cannot initialize queue\n"); 1109a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 1110a8d7fc4aSZbigniew Bodek return (ENOBUFS); 1111a8d7fc4aSZbigniew Bodek } 1112a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 1113a8d7fc4aSZbigniew Bodek } 1114a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 1115a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, q); 1116a8d7fc4aSZbigniew Bodek if (mvneta_tx_queue_init(ifp, q) != 0) { 1117a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 1118a8d7fc4aSZbigniew Bodek "initialization failed: cannot initialize queue\n"); 1119a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 1120a8d7fc4aSZbigniew Bodek return (ENOBUFS); 1121a8d7fc4aSZbigniew Bodek } 1122a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 1123a8d7fc4aSZbigniew Bodek } 1124a8d7fc4aSZbigniew Bodek 1125a8d7fc4aSZbigniew Bodek /* 1126a8d7fc4aSZbigniew Bodek * Ethernet Unit Control - disable automatic PHY management by HW. 1127a8d7fc4aSZbigniew Bodek * In case the port uses SMI-controlled PHY, poll its status with 1128a8d7fc4aSZbigniew Bodek * mii_tick() and update MAC settings accordingly. 1129a8d7fc4aSZbigniew Bodek */ 1130a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_EUC); 1131a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_EUC_POLLING; 1132a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_EUC, reg); 1133a8d7fc4aSZbigniew Bodek 1134a8d7fc4aSZbigniew Bodek /* EEE: Low Power Idle */ 1135a8d7fc4aSZbigniew Bodek reg = MVNETA_LPIC0_LILIMIT(MVNETA_LPI_LI); 1136a8d7fc4aSZbigniew Bodek reg |= MVNETA_LPIC0_TSLIMIT(MVNETA_LPI_TS); 1137a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_LPIC0, reg); 1138a8d7fc4aSZbigniew Bodek 1139a8d7fc4aSZbigniew Bodek reg = MVNETA_LPIC1_TWLIMIT(MVNETA_LPI_TW); 1140a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_LPIC1, reg); 1141a8d7fc4aSZbigniew Bodek 1142a8d7fc4aSZbigniew Bodek reg = MVNETA_LPIC2_MUSTSET; 1143a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_LPIC2, reg); 1144a8d7fc4aSZbigniew Bodek 1145a8d7fc4aSZbigniew Bodek /* Port MAC Control set 0 */ 1146a8d7fc4aSZbigniew Bodek reg = MVNETA_PMACC0_MUSTSET; /* must write 0x1 */ 1147a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PMACC0_PORTEN; /* port is still disabled */ 1148992fa62bSJustin Hibbits reg |= MVNETA_PMACC0_FRAMESIZELIMIT(if_getmtu(ifp) + MVNETA_ETHER_SIZE); 1149a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMACC0, reg); 1150a8d7fc4aSZbigniew Bodek 1151a8d7fc4aSZbigniew Bodek /* Port MAC Control set 2 */ 1152a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PMACC2); 1153a8d7fc4aSZbigniew Bodek switch (sc->phy_mode) { 1154a8d7fc4aSZbigniew Bodek case MVNETA_PHY_QSGMII: 1155a8d7fc4aSZbigniew Bodek reg |= (MVNETA_PMACC2_PCSEN | MVNETA_PMACC2_RGMIIEN); 1156a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PSERDESCFG, MVNETA_PSERDESCFG_QSGMII); 1157a8d7fc4aSZbigniew Bodek break; 1158a8d7fc4aSZbigniew Bodek case MVNETA_PHY_SGMII: 1159a8d7fc4aSZbigniew Bodek reg |= (MVNETA_PMACC2_PCSEN | MVNETA_PMACC2_RGMIIEN); 1160a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PSERDESCFG, MVNETA_PSERDESCFG_SGMII); 1161a8d7fc4aSZbigniew Bodek break; 1162a8d7fc4aSZbigniew Bodek case MVNETA_PHY_RGMII: 1163a8d7fc4aSZbigniew Bodek case MVNETA_PHY_RGMII_ID: 1164a8d7fc4aSZbigniew Bodek reg |= MVNETA_PMACC2_RGMIIEN; 1165a8d7fc4aSZbigniew Bodek break; 1166a8d7fc4aSZbigniew Bodek } 1167a8d7fc4aSZbigniew Bodek reg |= MVNETA_PMACC2_MUSTSET; 1168a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PMACC2_PORTMACRESET; 1169a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMACC2, reg); 1170a8d7fc4aSZbigniew Bodek 1171a8d7fc4aSZbigniew Bodek /* Port Configuration Extended: enable Tx CRC generation */ 1172a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PXCX); 1173a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PXCX_TXCRCDIS; 1174a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PXCX, reg); 1175a8d7fc4aSZbigniew Bodek 1176a8d7fc4aSZbigniew Bodek /* clear MIB counter registers(clear by read) */ 1177109260d2SMark Johnston mvneta_sc_lock(sc); 1178caf552a6SMark Johnston mvneta_clear_mib(sc); 1179109260d2SMark Johnston mvneta_sc_unlock(sc); 1180a8d7fc4aSZbigniew Bodek 1181a8d7fc4aSZbigniew Bodek /* Set SDC register except IPGINT bits */ 1182a8d7fc4aSZbigniew Bodek reg = MVNETA_SDC_RXBSZ_16_64BITWORDS; 1183a8d7fc4aSZbigniew Bodek reg |= MVNETA_SDC_TXBSZ_16_64BITWORDS; 1184a8d7fc4aSZbigniew Bodek reg |= MVNETA_SDC_BLMR; 1185a8d7fc4aSZbigniew Bodek reg |= MVNETA_SDC_BLMT; 1186a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_SDC, reg); 1187a8d7fc4aSZbigniew Bodek 1188a8d7fc4aSZbigniew Bodek return (0); 1189a8d7fc4aSZbigniew Bodek } 1190a8d7fc4aSZbigniew Bodek 1191a8d7fc4aSZbigniew Bodek STATIC void 1192a8d7fc4aSZbigniew Bodek mvneta_dmamap_cb(void *arg, bus_dma_segment_t * segs, int nseg, int error) 1193a8d7fc4aSZbigniew Bodek { 1194a8d7fc4aSZbigniew Bodek 1195a8d7fc4aSZbigniew Bodek if (error != 0) 1196a8d7fc4aSZbigniew Bodek return; 1197a8d7fc4aSZbigniew Bodek *(bus_addr_t *)arg = segs->ds_addr; 1198a8d7fc4aSZbigniew Bodek } 1199a8d7fc4aSZbigniew Bodek 1200a8d7fc4aSZbigniew Bodek STATIC int 1201a8d7fc4aSZbigniew Bodek mvneta_ring_alloc_rx_queue(struct mvneta_softc *sc, int q) 1202a8d7fc4aSZbigniew Bodek { 1203a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1204a8d7fc4aSZbigniew Bodek struct mvneta_buf *rxbuf; 1205a8d7fc4aSZbigniew Bodek bus_dmamap_t dmap; 1206a8d7fc4aSZbigniew Bodek int i, error; 1207a8d7fc4aSZbigniew Bodek 1208a8d7fc4aSZbigniew Bodek if (q >= MVNETA_RX_QNUM_MAX) 1209a8d7fc4aSZbigniew Bodek return (EINVAL); 1210a8d7fc4aSZbigniew Bodek 1211a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1212a8d7fc4aSZbigniew Bodek mtx_init(&rx->ring_mtx, "mvneta_rx", NULL, MTX_DEF); 1213a8d7fc4aSZbigniew Bodek /* Allocate DMA memory for Rx descriptors */ 1214a8d7fc4aSZbigniew Bodek error = bus_dmamem_alloc(sc->rx_dtag, 1215a8d7fc4aSZbigniew Bodek (void**)&(rx->desc), 1216a8d7fc4aSZbigniew Bodek BUS_DMA_NOWAIT | BUS_DMA_ZERO, 1217a8d7fc4aSZbigniew Bodek &rx->desc_map); 1218a8d7fc4aSZbigniew Bodek if (error != 0 || rx->desc == NULL) 1219a8d7fc4aSZbigniew Bodek goto fail; 1220a8d7fc4aSZbigniew Bodek error = bus_dmamap_load(sc->rx_dtag, rx->desc_map, 1221a8d7fc4aSZbigniew Bodek rx->desc, 1222a8d7fc4aSZbigniew Bodek sizeof(struct mvneta_rx_desc) * MVNETA_RX_RING_CNT, 1223a8d7fc4aSZbigniew Bodek mvneta_dmamap_cb, &rx->desc_pa, BUS_DMA_NOWAIT); 1224a8d7fc4aSZbigniew Bodek if (error != 0) 1225a8d7fc4aSZbigniew Bodek goto fail; 1226a8d7fc4aSZbigniew Bodek 1227a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_RX_RING_CNT; i++) { 1228a8d7fc4aSZbigniew Bodek error = bus_dmamap_create(sc->rxbuf_dtag, 0, &dmap); 1229a8d7fc4aSZbigniew Bodek if (error != 0) { 1230a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 1231a8d7fc4aSZbigniew Bodek "Failed to create DMA map for Rx buffer num: %d\n", i); 1232a8d7fc4aSZbigniew Bodek goto fail; 1233a8d7fc4aSZbigniew Bodek } 1234a8d7fc4aSZbigniew Bodek rxbuf = &rx->rxbuf[i]; 1235a8d7fc4aSZbigniew Bodek rxbuf->dmap = dmap; 1236a8d7fc4aSZbigniew Bodek rxbuf->m = NULL; 1237a8d7fc4aSZbigniew Bodek } 1238a8d7fc4aSZbigniew Bodek 1239a8d7fc4aSZbigniew Bodek return (0); 1240a8d7fc4aSZbigniew Bodek fail: 1241b831f9ceSHubert Mazur mvneta_rx_lockq(sc, q); 1242b831f9ceSHubert Mazur mvneta_ring_flush_rx_queue(sc, q); 1243b831f9ceSHubert Mazur mvneta_rx_unlockq(sc, q); 1244a8d7fc4aSZbigniew Bodek mvneta_ring_dealloc_rx_queue(sc, q); 1245a8d7fc4aSZbigniew Bodek device_printf(sc->dev, "DMA Ring buffer allocation failure.\n"); 1246a8d7fc4aSZbigniew Bodek return (error); 1247a8d7fc4aSZbigniew Bodek } 1248a8d7fc4aSZbigniew Bodek 1249a8d7fc4aSZbigniew Bodek STATIC int 1250a8d7fc4aSZbigniew Bodek mvneta_ring_alloc_tx_queue(struct mvneta_softc *sc, int q) 1251a8d7fc4aSZbigniew Bodek { 1252a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1253a8d7fc4aSZbigniew Bodek int error; 1254a8d7fc4aSZbigniew Bodek 1255a8d7fc4aSZbigniew Bodek if (q >= MVNETA_TX_QNUM_MAX) 1256a8d7fc4aSZbigniew Bodek return (EINVAL); 1257a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1258a8d7fc4aSZbigniew Bodek mtx_init(&tx->ring_mtx, "mvneta_tx", NULL, MTX_DEF); 1259a8d7fc4aSZbigniew Bodek error = bus_dmamem_alloc(sc->tx_dtag, 1260a8d7fc4aSZbigniew Bodek (void**)&(tx->desc), 1261a8d7fc4aSZbigniew Bodek BUS_DMA_NOWAIT | BUS_DMA_ZERO, 1262a8d7fc4aSZbigniew Bodek &tx->desc_map); 1263a8d7fc4aSZbigniew Bodek if (error != 0 || tx->desc == NULL) 1264a8d7fc4aSZbigniew Bodek goto fail; 1265a8d7fc4aSZbigniew Bodek error = bus_dmamap_load(sc->tx_dtag, tx->desc_map, 1266a8d7fc4aSZbigniew Bodek tx->desc, 1267a8d7fc4aSZbigniew Bodek sizeof(struct mvneta_tx_desc) * MVNETA_TX_RING_CNT, 1268a8d7fc4aSZbigniew Bodek mvneta_dmamap_cb, &tx->desc_pa, BUS_DMA_NOWAIT); 1269a8d7fc4aSZbigniew Bodek if (error != 0) 1270a8d7fc4aSZbigniew Bodek goto fail; 1271a8d7fc4aSZbigniew Bodek 1272a8d7fc4aSZbigniew Bodek #ifdef MVNETA_MULTIQUEUE 1273a8d7fc4aSZbigniew Bodek tx->br = buf_ring_alloc(MVNETA_BUFRING_SIZE, M_DEVBUF, M_NOWAIT, 1274a8d7fc4aSZbigniew Bodek &tx->ring_mtx); 1275a8d7fc4aSZbigniew Bodek if (tx->br == NULL) { 1276a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 1277a8d7fc4aSZbigniew Bodek "Could not setup buffer ring for TxQ(%d)\n", q); 1278a8d7fc4aSZbigniew Bodek error = ENOMEM; 1279a8d7fc4aSZbigniew Bodek goto fail; 1280a8d7fc4aSZbigniew Bodek } 1281a8d7fc4aSZbigniew Bodek #endif 1282a8d7fc4aSZbigniew Bodek 1283a8d7fc4aSZbigniew Bodek return (0); 1284a8d7fc4aSZbigniew Bodek fail: 1285b831f9ceSHubert Mazur mvneta_tx_lockq(sc, q); 1286b831f9ceSHubert Mazur mvneta_ring_flush_tx_queue(sc, q); 1287b831f9ceSHubert Mazur mvneta_tx_unlockq(sc, q); 1288a8d7fc4aSZbigniew Bodek mvneta_ring_dealloc_tx_queue(sc, q); 1289a8d7fc4aSZbigniew Bodek device_printf(sc->dev, "DMA Ring buffer allocation failure.\n"); 1290a8d7fc4aSZbigniew Bodek return (error); 1291a8d7fc4aSZbigniew Bodek } 1292a8d7fc4aSZbigniew Bodek 1293a8d7fc4aSZbigniew Bodek STATIC void 1294a8d7fc4aSZbigniew Bodek mvneta_ring_dealloc_tx_queue(struct mvneta_softc *sc, int q) 1295a8d7fc4aSZbigniew Bodek { 1296a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1297a8d7fc4aSZbigniew Bodek struct mvneta_buf *txbuf; 1298a8d7fc4aSZbigniew Bodek void *kva; 1299a8d7fc4aSZbigniew Bodek int error; 1300a8d7fc4aSZbigniew Bodek int i; 1301a8d7fc4aSZbigniew Bodek 1302a8d7fc4aSZbigniew Bodek if (q >= MVNETA_TX_QNUM_MAX) 1303a8d7fc4aSZbigniew Bodek return; 1304a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1305a8d7fc4aSZbigniew Bodek 1306a8d7fc4aSZbigniew Bodek if (tx->taskq != NULL) { 1307a8d7fc4aSZbigniew Bodek /* Remove task */ 1308a8d7fc4aSZbigniew Bodek while (taskqueue_cancel(tx->taskq, &tx->task, NULL) != 0) 1309a8d7fc4aSZbigniew Bodek taskqueue_drain(tx->taskq, &tx->task); 1310a8d7fc4aSZbigniew Bodek } 1311a8d7fc4aSZbigniew Bodek #ifdef MVNETA_MULTIQUEUE 1312a8d7fc4aSZbigniew Bodek if (tx->br != NULL) 1313a8d7fc4aSZbigniew Bodek drbr_free(tx->br, M_DEVBUF); 1314a8d7fc4aSZbigniew Bodek #endif 1315a8d7fc4aSZbigniew Bodek 1316a8d7fc4aSZbigniew Bodek if (sc->txmbuf_dtag != NULL) { 1317a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_TX_RING_CNT; i++) { 1318a8d7fc4aSZbigniew Bodek txbuf = &tx->txbuf[i]; 1319a8d7fc4aSZbigniew Bodek if (txbuf->dmap != NULL) { 1320a8d7fc4aSZbigniew Bodek error = bus_dmamap_destroy(sc->txmbuf_dtag, 1321a8d7fc4aSZbigniew Bodek txbuf->dmap); 1322a8d7fc4aSZbigniew Bodek if (error != 0) { 1323a8d7fc4aSZbigniew Bodek panic("%s: map busy for Tx descriptor (Q%d, %d)", 1324a8d7fc4aSZbigniew Bodek __func__, q, i); 1325a8d7fc4aSZbigniew Bodek } 1326a8d7fc4aSZbigniew Bodek } 1327a8d7fc4aSZbigniew Bodek } 1328a8d7fc4aSZbigniew Bodek } 1329a8d7fc4aSZbigniew Bodek 1330a8d7fc4aSZbigniew Bodek if (tx->desc_pa != 0) 1331a8d7fc4aSZbigniew Bodek bus_dmamap_unload(sc->tx_dtag, tx->desc_map); 1332a8d7fc4aSZbigniew Bodek 1333a8d7fc4aSZbigniew Bodek kva = (void *)tx->desc; 1334a8d7fc4aSZbigniew Bodek if (kva != NULL) 1335a8d7fc4aSZbigniew Bodek bus_dmamem_free(sc->tx_dtag, tx->desc, tx->desc_map); 1336a8d7fc4aSZbigniew Bodek 1337a8d7fc4aSZbigniew Bodek if (mtx_name(&tx->ring_mtx) != NULL) 1338a8d7fc4aSZbigniew Bodek mtx_destroy(&tx->ring_mtx); 1339a8d7fc4aSZbigniew Bodek 1340a8d7fc4aSZbigniew Bodek memset(tx, 0, sizeof(*tx)); 1341a8d7fc4aSZbigniew Bodek } 1342a8d7fc4aSZbigniew Bodek 1343a8d7fc4aSZbigniew Bodek STATIC void 1344a8d7fc4aSZbigniew Bodek mvneta_ring_dealloc_rx_queue(struct mvneta_softc *sc, int q) 1345a8d7fc4aSZbigniew Bodek { 1346a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1347a8d7fc4aSZbigniew Bodek struct lro_ctrl *lro; 1348a8d7fc4aSZbigniew Bodek void *kva; 1349a8d7fc4aSZbigniew Bodek 1350a8d7fc4aSZbigniew Bodek if (q >= MVNETA_RX_QNUM_MAX) 1351a8d7fc4aSZbigniew Bodek return; 1352a8d7fc4aSZbigniew Bodek 1353a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1354a8d7fc4aSZbigniew Bodek 1355a8d7fc4aSZbigniew Bodek if (rx->desc_pa != 0) 1356a8d7fc4aSZbigniew Bodek bus_dmamap_unload(sc->rx_dtag, rx->desc_map); 1357a8d7fc4aSZbigniew Bodek 1358a8d7fc4aSZbigniew Bodek kva = (void *)rx->desc; 1359a8d7fc4aSZbigniew Bodek if (kva != NULL) 1360a8d7fc4aSZbigniew Bodek bus_dmamem_free(sc->rx_dtag, rx->desc, rx->desc_map); 1361a8d7fc4aSZbigniew Bodek 1362a8d7fc4aSZbigniew Bodek lro = &rx->lro; 1363a8d7fc4aSZbigniew Bodek tcp_lro_free(lro); 1364a8d7fc4aSZbigniew Bodek 1365a8d7fc4aSZbigniew Bodek if (mtx_name(&rx->ring_mtx) != NULL) 1366a8d7fc4aSZbigniew Bodek mtx_destroy(&rx->ring_mtx); 1367a8d7fc4aSZbigniew Bodek 1368a8d7fc4aSZbigniew Bodek memset(rx, 0, sizeof(*rx)); 1369a8d7fc4aSZbigniew Bodek } 1370a8d7fc4aSZbigniew Bodek 1371a8d7fc4aSZbigniew Bodek STATIC int 1372a8d7fc4aSZbigniew Bodek mvneta_ring_init_rx_queue(struct mvneta_softc *sc, int q) 1373a8d7fc4aSZbigniew Bodek { 1374a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1375a8d7fc4aSZbigniew Bodek struct lro_ctrl *lro; 1376a8d7fc4aSZbigniew Bodek int error; 1377a8d7fc4aSZbigniew Bodek 1378a8d7fc4aSZbigniew Bodek if (q >= MVNETA_RX_QNUM_MAX) 1379a8d7fc4aSZbigniew Bodek return (0); 1380a8d7fc4aSZbigniew Bodek 1381a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1382a8d7fc4aSZbigniew Bodek rx->dma = rx->cpu = 0; 1383a8d7fc4aSZbigniew Bodek rx->queue_th_received = MVNETA_RXTH_COUNT; 13844885d6f3SHubert Mazur rx->queue_th_time = (sc->clk_freq / 1000) / 10; /* 0.1 [ms] */ 1385a8d7fc4aSZbigniew Bodek 1386a8d7fc4aSZbigniew Bodek /* Initialize LRO */ 1387a8d7fc4aSZbigniew Bodek rx->lro_enabled = FALSE; 1388992fa62bSJustin Hibbits if ((if_getcapenable(sc->ifp) & IFCAP_LRO) != 0) { 1389a8d7fc4aSZbigniew Bodek lro = &rx->lro; 1390a8d7fc4aSZbigniew Bodek error = tcp_lro_init(lro); 1391a8d7fc4aSZbigniew Bodek if (error != 0) 1392a8d7fc4aSZbigniew Bodek device_printf(sc->dev, "LRO Initialization failed!\n"); 1393a8d7fc4aSZbigniew Bodek else { 1394a8d7fc4aSZbigniew Bodek rx->lro_enabled = TRUE; 1395a8d7fc4aSZbigniew Bodek lro->ifp = sc->ifp; 1396a8d7fc4aSZbigniew Bodek } 1397a8d7fc4aSZbigniew Bodek } 1398a8d7fc4aSZbigniew Bodek 1399a8d7fc4aSZbigniew Bodek return (0); 1400a8d7fc4aSZbigniew Bodek } 1401a8d7fc4aSZbigniew Bodek 1402a8d7fc4aSZbigniew Bodek STATIC int 1403a8d7fc4aSZbigniew Bodek mvneta_ring_init_tx_queue(struct mvneta_softc *sc, int q) 1404a8d7fc4aSZbigniew Bodek { 1405a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1406a8d7fc4aSZbigniew Bodek struct mvneta_buf *txbuf; 1407a8d7fc4aSZbigniew Bodek int i, error; 1408a8d7fc4aSZbigniew Bodek 1409a8d7fc4aSZbigniew Bodek if (q >= MVNETA_TX_QNUM_MAX) 1410a8d7fc4aSZbigniew Bodek return (0); 1411a8d7fc4aSZbigniew Bodek 1412a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1413a8d7fc4aSZbigniew Bodek 1414a8d7fc4aSZbigniew Bodek /* Tx handle */ 1415a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_TX_RING_CNT; i++) { 1416a8d7fc4aSZbigniew Bodek txbuf = &tx->txbuf[i]; 1417a8d7fc4aSZbigniew Bodek txbuf->m = NULL; 1418a8d7fc4aSZbigniew Bodek /* Tx handle needs DMA map for busdma_load_mbuf() */ 1419a8d7fc4aSZbigniew Bodek error = bus_dmamap_create(sc->txmbuf_dtag, 0, 1420a8d7fc4aSZbigniew Bodek &txbuf->dmap); 1421a8d7fc4aSZbigniew Bodek if (error != 0) { 1422a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 1423a8d7fc4aSZbigniew Bodek "can't create dma map (tx ring %d)\n", i); 1424a8d7fc4aSZbigniew Bodek return (error); 1425a8d7fc4aSZbigniew Bodek } 1426a8d7fc4aSZbigniew Bodek } 1427a8d7fc4aSZbigniew Bodek tx->dma = tx->cpu = 0; 1428a8d7fc4aSZbigniew Bodek tx->used = 0; 1429a8d7fc4aSZbigniew Bodek tx->drv_error = 0; 1430a8d7fc4aSZbigniew Bodek tx->queue_status = MVNETA_QUEUE_DISABLED; 1431a8d7fc4aSZbigniew Bodek tx->queue_hung = FALSE; 1432a8d7fc4aSZbigniew Bodek 1433a8d7fc4aSZbigniew Bodek tx->ifp = sc->ifp; 1434a8d7fc4aSZbigniew Bodek tx->qidx = q; 1435a8d7fc4aSZbigniew Bodek TASK_INIT(&tx->task, 0, mvneta_tx_task, tx); 1436a8d7fc4aSZbigniew Bodek tx->taskq = taskqueue_create_fast("mvneta_tx_taskq", M_WAITOK, 1437a8d7fc4aSZbigniew Bodek taskqueue_thread_enqueue, &tx->taskq); 1438a8d7fc4aSZbigniew Bodek taskqueue_start_threads(&tx->taskq, 1, PI_NET, "%s: tx_taskq(%d)", 1439a8d7fc4aSZbigniew Bodek device_get_nameunit(sc->dev), q); 1440a8d7fc4aSZbigniew Bodek 1441a8d7fc4aSZbigniew Bodek return (0); 1442a8d7fc4aSZbigniew Bodek } 1443a8d7fc4aSZbigniew Bodek 1444a8d7fc4aSZbigniew Bodek STATIC void 1445a8d7fc4aSZbigniew Bodek mvneta_ring_flush_tx_queue(struct mvneta_softc *sc, int q) 1446a8d7fc4aSZbigniew Bodek { 1447a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1448a8d7fc4aSZbigniew Bodek struct mvneta_buf *txbuf; 1449a8d7fc4aSZbigniew Bodek int i; 1450a8d7fc4aSZbigniew Bodek 1451a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1452a8d7fc4aSZbigniew Bodek KASSERT_TX_MTX(sc, q); 1453a8d7fc4aSZbigniew Bodek 1454a8d7fc4aSZbigniew Bodek /* Tx handle */ 1455a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_TX_RING_CNT; i++) { 1456a8d7fc4aSZbigniew Bodek txbuf = &tx->txbuf[i]; 1457a8d7fc4aSZbigniew Bodek bus_dmamap_unload(sc->txmbuf_dtag, txbuf->dmap); 1458a8d7fc4aSZbigniew Bodek if (txbuf->m != NULL) { 1459a8d7fc4aSZbigniew Bodek m_freem(txbuf->m); 1460a8d7fc4aSZbigniew Bodek txbuf->m = NULL; 1461a8d7fc4aSZbigniew Bodek } 1462a8d7fc4aSZbigniew Bodek } 1463a8d7fc4aSZbigniew Bodek tx->dma = tx->cpu = 0; 1464a8d7fc4aSZbigniew Bodek tx->used = 0; 1465a8d7fc4aSZbigniew Bodek } 1466a8d7fc4aSZbigniew Bodek 1467a8d7fc4aSZbigniew Bodek STATIC void 1468a8d7fc4aSZbigniew Bodek mvneta_ring_flush_rx_queue(struct mvneta_softc *sc, int q) 1469a8d7fc4aSZbigniew Bodek { 1470a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1471a8d7fc4aSZbigniew Bodek struct mvneta_buf *rxbuf; 1472a8d7fc4aSZbigniew Bodek int i; 1473a8d7fc4aSZbigniew Bodek 1474a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1475a8d7fc4aSZbigniew Bodek KASSERT_RX_MTX(sc, q); 1476a8d7fc4aSZbigniew Bodek 1477a8d7fc4aSZbigniew Bodek /* Rx handle */ 1478a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_RX_RING_CNT; i++) { 1479a8d7fc4aSZbigniew Bodek rxbuf = &rx->rxbuf[i]; 1480a8d7fc4aSZbigniew Bodek mvneta_rx_buf_free(sc, rxbuf); 1481a8d7fc4aSZbigniew Bodek } 1482a8d7fc4aSZbigniew Bodek rx->dma = rx->cpu = 0; 1483a8d7fc4aSZbigniew Bodek } 1484a8d7fc4aSZbigniew Bodek 1485a8d7fc4aSZbigniew Bodek /* 1486a8d7fc4aSZbigniew Bodek * Rx/Tx Queue Control 1487a8d7fc4aSZbigniew Bodek */ 1488a8d7fc4aSZbigniew Bodek STATIC int 1489992fa62bSJustin Hibbits mvneta_rx_queue_init(if_t ifp, int q) 1490a8d7fc4aSZbigniew Bodek { 1491a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1492a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1493a8d7fc4aSZbigniew Bodek uint32_t reg; 1494a8d7fc4aSZbigniew Bodek 1495992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1496a8d7fc4aSZbigniew Bodek KASSERT_RX_MTX(sc, q); 1497a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1498a8d7fc4aSZbigniew Bodek DASSERT(rx->desc_pa != 0); 1499a8d7fc4aSZbigniew Bodek 1500a8d7fc4aSZbigniew Bodek /* descriptor address */ 1501a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXDQA(q), rx->desc_pa); 1502a8d7fc4aSZbigniew Bodek 1503a8d7fc4aSZbigniew Bodek /* Rx buffer size and descriptor ring size */ 150473f20bb3SMarcin Wojtas reg = MVNETA_PRXDQS_BUFFERSIZE(sc->rx_frame_size >> 3); 1505a8d7fc4aSZbigniew Bodek reg |= MVNETA_PRXDQS_DESCRIPTORSQUEUESIZE(MVNETA_RX_RING_CNT); 1506a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXDQS(q), reg); 1507a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 1508992fa62bSJustin Hibbits CTR3(KTR_SPARE2, "%s PRXDQS(%d): %#x", if_name(ifp), q, 1509a8d7fc4aSZbigniew Bodek MVNETA_READ(sc, MVNETA_PRXDQS(q))); 1510a8d7fc4aSZbigniew Bodek #endif 1511a8d7fc4aSZbigniew Bodek /* Rx packet offset address */ 1512a8d7fc4aSZbigniew Bodek reg = MVNETA_PRXC_PACKETOFFSET(MVNETA_PACKET_OFFSET >> 3); 1513a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXC(q), reg); 1514a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 1515992fa62bSJustin Hibbits CTR3(KTR_SPARE2, "%s PRXC(%d): %#x", if_name(ifp), q, 1516a8d7fc4aSZbigniew Bodek MVNETA_READ(sc, MVNETA_PRXC(q))); 1517a8d7fc4aSZbigniew Bodek #endif 1518a8d7fc4aSZbigniew Bodek 1519a8d7fc4aSZbigniew Bodek /* if DMA is not working, register is not updated */ 1520a8d7fc4aSZbigniew Bodek DASSERT(MVNETA_READ(sc, MVNETA_PRXDQA(q)) == rx->desc_pa); 1521a8d7fc4aSZbigniew Bodek return (0); 1522a8d7fc4aSZbigniew Bodek } 1523a8d7fc4aSZbigniew Bodek 1524a8d7fc4aSZbigniew Bodek STATIC int 1525992fa62bSJustin Hibbits mvneta_tx_queue_init(if_t ifp, int q) 1526a8d7fc4aSZbigniew Bodek { 1527a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1528a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1529a8d7fc4aSZbigniew Bodek uint32_t reg; 1530a8d7fc4aSZbigniew Bodek 1531992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1532a8d7fc4aSZbigniew Bodek KASSERT_TX_MTX(sc, q); 1533a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1534a8d7fc4aSZbigniew Bodek DASSERT(tx->desc_pa != 0); 1535a8d7fc4aSZbigniew Bodek 1536a8d7fc4aSZbigniew Bodek /* descriptor address */ 1537a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXDQA(q), tx->desc_pa); 1538a8d7fc4aSZbigniew Bodek 1539a8d7fc4aSZbigniew Bodek /* descriptor ring size */ 1540a8d7fc4aSZbigniew Bodek reg = MVNETA_PTXDQS_DQS(MVNETA_TX_RING_CNT); 1541a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXDQS(q), reg); 1542a8d7fc4aSZbigniew Bodek 1543a8d7fc4aSZbigniew Bodek /* if DMA is not working, register is not updated */ 1544a8d7fc4aSZbigniew Bodek DASSERT(MVNETA_READ(sc, MVNETA_PTXDQA(q)) == tx->desc_pa); 1545a8d7fc4aSZbigniew Bodek return (0); 1546a8d7fc4aSZbigniew Bodek } 1547a8d7fc4aSZbigniew Bodek 1548a8d7fc4aSZbigniew Bodek STATIC int 1549992fa62bSJustin Hibbits mvneta_rx_queue_enable(if_t ifp, int q) 1550a8d7fc4aSZbigniew Bodek { 1551a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1552a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1553a8d7fc4aSZbigniew Bodek uint32_t reg; 1554a8d7fc4aSZbigniew Bodek 1555992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1556a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1557a8d7fc4aSZbigniew Bodek KASSERT_RX_MTX(sc, q); 1558a8d7fc4aSZbigniew Bodek 1559a8d7fc4aSZbigniew Bodek /* Set Rx interrupt threshold */ 1560a8d7fc4aSZbigniew Bodek reg = MVNETA_PRXDQTH_ODT(rx->queue_th_received); 1561a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXDQTH(q), reg); 1562a8d7fc4aSZbigniew Bodek 1563a8d7fc4aSZbigniew Bodek reg = MVNETA_PRXITTH_RITT(rx->queue_th_time); 1564a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXITTH(q), reg); 1565a8d7fc4aSZbigniew Bodek 1566a8d7fc4aSZbigniew Bodek /* Unmask RXTX_TH Intr. */ 1567a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PRXTXTIM); 1568a8d7fc4aSZbigniew Bodek reg |= MVNETA_PRXTXTI_RBICTAPQ(q); /* Rx Buffer Interrupt Coalese */ 1569a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXTIM, reg); 1570a8d7fc4aSZbigniew Bodek 1571a8d7fc4aSZbigniew Bodek /* Enable Rx queue */ 1572a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_RQC) & MVNETA_RQC_EN_MASK; 1573a8d7fc4aSZbigniew Bodek reg |= MVNETA_RQC_ENQ(q); 1574a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_RQC, reg); 1575a8d7fc4aSZbigniew Bodek 1576a8d7fc4aSZbigniew Bodek rx->queue_status = MVNETA_QUEUE_WORKING; 1577a8d7fc4aSZbigniew Bodek return (0); 1578a8d7fc4aSZbigniew Bodek } 1579a8d7fc4aSZbigniew Bodek 1580a8d7fc4aSZbigniew Bodek STATIC int 1581992fa62bSJustin Hibbits mvneta_tx_queue_enable(if_t ifp, int q) 1582a8d7fc4aSZbigniew Bodek { 1583a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1584a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1585a8d7fc4aSZbigniew Bodek 1586992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1587a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1588a8d7fc4aSZbigniew Bodek KASSERT_TX_MTX(sc, q); 1589a8d7fc4aSZbigniew Bodek 1590a8d7fc4aSZbigniew Bodek /* Enable Tx queue */ 1591a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_TQC, MVNETA_TQC_ENQ(q)); 1592a8d7fc4aSZbigniew Bodek 1593a8d7fc4aSZbigniew Bodek tx->queue_status = MVNETA_QUEUE_IDLE; 1594a8d7fc4aSZbigniew Bodek tx->queue_hung = FALSE; 1595a8d7fc4aSZbigniew Bodek return (0); 1596a8d7fc4aSZbigniew Bodek } 1597a8d7fc4aSZbigniew Bodek 1598a8d7fc4aSZbigniew Bodek STATIC __inline void 1599a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(struct mvneta_softc *sc, int q) 1600a8d7fc4aSZbigniew Bodek { 1601a8d7fc4aSZbigniew Bodek 1602a8d7fc4aSZbigniew Bodek DASSERT(q >= 0); 1603a8d7fc4aSZbigniew Bodek DASSERT(q < MVNETA_RX_QNUM_MAX); 1604a8d7fc4aSZbigniew Bodek mtx_lock(&sc->rx_ring[q].ring_mtx); 1605a8d7fc4aSZbigniew Bodek } 1606a8d7fc4aSZbigniew Bodek 1607a8d7fc4aSZbigniew Bodek STATIC __inline void 1608a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(struct mvneta_softc *sc, int q) 1609a8d7fc4aSZbigniew Bodek { 1610a8d7fc4aSZbigniew Bodek 1611a8d7fc4aSZbigniew Bodek DASSERT(q >= 0); 1612a8d7fc4aSZbigniew Bodek DASSERT(q < MVNETA_RX_QNUM_MAX); 1613a8d7fc4aSZbigniew Bodek mtx_unlock(&sc->rx_ring[q].ring_mtx); 1614a8d7fc4aSZbigniew Bodek } 1615a8d7fc4aSZbigniew Bodek 1616a8d7fc4aSZbigniew Bodek STATIC __inline int __unused 1617a8d7fc4aSZbigniew Bodek mvneta_tx_trylockq(struct mvneta_softc *sc, int q) 1618a8d7fc4aSZbigniew Bodek { 1619a8d7fc4aSZbigniew Bodek 1620a8d7fc4aSZbigniew Bodek DASSERT(q >= 0); 1621a8d7fc4aSZbigniew Bodek DASSERT(q < MVNETA_TX_QNUM_MAX); 1622a8d7fc4aSZbigniew Bodek return (mtx_trylock(&sc->tx_ring[q].ring_mtx)); 1623a8d7fc4aSZbigniew Bodek } 1624a8d7fc4aSZbigniew Bodek 1625a8d7fc4aSZbigniew Bodek STATIC __inline void 1626a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(struct mvneta_softc *sc, int q) 1627a8d7fc4aSZbigniew Bodek { 1628a8d7fc4aSZbigniew Bodek 1629a8d7fc4aSZbigniew Bodek DASSERT(q >= 0); 1630a8d7fc4aSZbigniew Bodek DASSERT(q < MVNETA_TX_QNUM_MAX); 1631a8d7fc4aSZbigniew Bodek mtx_lock(&sc->tx_ring[q].ring_mtx); 1632a8d7fc4aSZbigniew Bodek } 1633a8d7fc4aSZbigniew Bodek 1634a8d7fc4aSZbigniew Bodek STATIC __inline void 1635a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(struct mvneta_softc *sc, int q) 1636a8d7fc4aSZbigniew Bodek { 1637a8d7fc4aSZbigniew Bodek 1638a8d7fc4aSZbigniew Bodek DASSERT(q >= 0); 1639a8d7fc4aSZbigniew Bodek DASSERT(q < MVNETA_TX_QNUM_MAX); 1640a8d7fc4aSZbigniew Bodek mtx_unlock(&sc->tx_ring[q].ring_mtx); 1641a8d7fc4aSZbigniew Bodek } 1642a8d7fc4aSZbigniew Bodek 1643a8d7fc4aSZbigniew Bodek /* 1644a8d7fc4aSZbigniew Bodek * Interrupt Handlers 1645a8d7fc4aSZbigniew Bodek */ 1646a8d7fc4aSZbigniew Bodek STATIC void 1647a8d7fc4aSZbigniew Bodek mvneta_disable_intr(struct mvneta_softc *sc) 1648a8d7fc4aSZbigniew Bodek { 1649a8d7fc4aSZbigniew Bodek 1650a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_EUIM, 0); 1651a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_EUIC, 0); 1652a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXTIM, 0); 1653a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXTIC, 0); 1654a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXIM, 0); 1655a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXIC, 0); 1656a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMIM, 0); 1657a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMIC, 0); 1658a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PIE, 0); 1659a8d7fc4aSZbigniew Bodek } 1660a8d7fc4aSZbigniew Bodek 1661a8d7fc4aSZbigniew Bodek STATIC void 1662a8d7fc4aSZbigniew Bodek mvneta_enable_intr(struct mvneta_softc *sc) 1663a8d7fc4aSZbigniew Bodek { 1664a8d7fc4aSZbigniew Bodek uint32_t reg; 1665a8d7fc4aSZbigniew Bodek 1666a8d7fc4aSZbigniew Bodek /* Enable Summary Bit to check all interrupt cause. */ 1667a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PRXTXTIM); 1668a8d7fc4aSZbigniew Bodek reg |= MVNETA_PRXTXTI_PMISCICSUMMARY; 1669a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXTIM, reg); 1670a8d7fc4aSZbigniew Bodek 1671231237bbSSebastien Bini if (!sc->phy_attached || sc->use_inband_status) { 1672a8d7fc4aSZbigniew Bodek /* Enable Port MISC Intr. (via RXTX_TH_Summary bit) */ 1673a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMIM, MVNETA_PMI_PHYSTATUSCHNG | 1674a8d7fc4aSZbigniew Bodek MVNETA_PMI_LINKCHANGE | MVNETA_PMI_PSCSYNCCHANGE); 1675a8d7fc4aSZbigniew Bodek } 1676a8d7fc4aSZbigniew Bodek 1677a8d7fc4aSZbigniew Bodek /* Enable All Queue Interrupt */ 1678a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PIE); 1679a8d7fc4aSZbigniew Bodek reg |= MVNETA_PIE_RXPKTINTRPTENB_MASK; 1680a8d7fc4aSZbigniew Bodek reg |= MVNETA_PIE_TXPKTINTRPTENB_MASK; 1681a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PIE, reg); 1682a8d7fc4aSZbigniew Bodek } 1683a8d7fc4aSZbigniew Bodek 1684a8d7fc4aSZbigniew Bodek STATIC void 1685a8d7fc4aSZbigniew Bodek mvneta_rxtxth_intr(void *arg) 1686a8d7fc4aSZbigniew Bodek { 1687a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1688992fa62bSJustin Hibbits if_t ifp; 1689a8d7fc4aSZbigniew Bodek uint32_t ic, queues; 1690a8d7fc4aSZbigniew Bodek 1691a8d7fc4aSZbigniew Bodek sc = arg; 1692a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 1693a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 1694992fa62bSJustin Hibbits CTR1(KTR_SPARE2, "%s got RXTX_TH_Intr", if_name(ifp)); 1695a8d7fc4aSZbigniew Bodek #endif 1696a8d7fc4aSZbigniew Bodek ic = MVNETA_READ(sc, MVNETA_PRXTXTIC); 1697a8d7fc4aSZbigniew Bodek if (ic == 0) 1698a8d7fc4aSZbigniew Bodek return; 1699a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXTXTIC, ~ic); 1700a8d7fc4aSZbigniew Bodek 170119ae05aaSGordon Bergling /* Ack maintenance interrupt first */ 1702a8d7fc4aSZbigniew Bodek if (__predict_false((ic & MVNETA_PRXTXTI_PMISCICSUMMARY) && 1703231237bbSSebastien Bini (!sc->phy_attached || sc->use_inband_status))) { 1704a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 1705a8d7fc4aSZbigniew Bodek mvneta_misc_intr(sc); 1706a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 1707a8d7fc4aSZbigniew Bodek } 1708992fa62bSJustin Hibbits if (__predict_false(!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))) 1709a8d7fc4aSZbigniew Bodek return; 1710a8d7fc4aSZbigniew Bodek /* RxTxTH interrupt */ 1711a8d7fc4aSZbigniew Bodek queues = MVNETA_PRXTXTI_GET_RBICTAPQ(ic); 1712a8d7fc4aSZbigniew Bodek if (__predict_true(queues)) { 1713a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 1714992fa62bSJustin Hibbits CTR1(KTR_SPARE2, "%s got PRXTXTIC: +RXEOF", if_name(ifp)); 1715a8d7fc4aSZbigniew Bodek #endif 1716a8d7fc4aSZbigniew Bodek /* At the moment the driver support only one RX queue. */ 1717a8d7fc4aSZbigniew Bodek DASSERT(MVNETA_IS_QUEUE_SET(queues, 0)); 1718a8d7fc4aSZbigniew Bodek mvneta_rx(sc, 0, 0); 1719a8d7fc4aSZbigniew Bodek } 1720a8d7fc4aSZbigniew Bodek } 1721a8d7fc4aSZbigniew Bodek 1722a8d7fc4aSZbigniew Bodek STATIC int 1723a8d7fc4aSZbigniew Bodek mvneta_misc_intr(struct mvneta_softc *sc) 1724a8d7fc4aSZbigniew Bodek { 1725a8d7fc4aSZbigniew Bodek uint32_t ic; 1726a8d7fc4aSZbigniew Bodek int claimed = 0; 1727a8d7fc4aSZbigniew Bodek 1728a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 1729992fa62bSJustin Hibbits CTR1(KTR_SPARE2, "%s got MISC_INTR", if_name(sc->ifp)); 1730a8d7fc4aSZbigniew Bodek #endif 1731a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 1732a8d7fc4aSZbigniew Bodek 1733a8d7fc4aSZbigniew Bodek for (;;) { 1734a8d7fc4aSZbigniew Bodek ic = MVNETA_READ(sc, MVNETA_PMIC); 1735a8d7fc4aSZbigniew Bodek ic &= MVNETA_READ(sc, MVNETA_PMIM); 1736a8d7fc4aSZbigniew Bodek if (ic == 0) 1737a8d7fc4aSZbigniew Bodek break; 1738a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMIC, ~ic); 1739a8d7fc4aSZbigniew Bodek claimed = 1; 1740a8d7fc4aSZbigniew Bodek 1741a8d7fc4aSZbigniew Bodek if (ic & (MVNETA_PMI_PHYSTATUSCHNG | 1742a8d7fc4aSZbigniew Bodek MVNETA_PMI_LINKCHANGE | MVNETA_PMI_PSCSYNCCHANGE)) 1743a8d7fc4aSZbigniew Bodek mvneta_link_isr(sc); 1744a8d7fc4aSZbigniew Bodek } 1745a8d7fc4aSZbigniew Bodek return (claimed); 1746a8d7fc4aSZbigniew Bodek } 1747a8d7fc4aSZbigniew Bodek 1748a8d7fc4aSZbigniew Bodek STATIC void 1749a8d7fc4aSZbigniew Bodek mvneta_tick(void *arg) 1750a8d7fc4aSZbigniew Bodek { 1751a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1752a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1753a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 1754a8d7fc4aSZbigniew Bodek int q; 1755a8d7fc4aSZbigniew Bodek uint32_t fc_prev, fc_curr; 1756a8d7fc4aSZbigniew Bodek 1757a8d7fc4aSZbigniew Bodek sc = arg; 1758a8d7fc4aSZbigniew Bodek 1759a8d7fc4aSZbigniew Bodek /* 1760a8d7fc4aSZbigniew Bodek * This is done before mib update to get the right stats 1761a8d7fc4aSZbigniew Bodek * for this tick. 1762a8d7fc4aSZbigniew Bodek */ 1763a8d7fc4aSZbigniew Bodek mvneta_tx_drain(sc); 1764a8d7fc4aSZbigniew Bodek 1765a8d7fc4aSZbigniew Bodek /* Extract previous flow-control frame received counter. */ 1766a8d7fc4aSZbigniew Bodek fc_prev = sc->sysctl_mib[MVNETA_MIB_FC_GOOD_IDX].counter; 1767a8d7fc4aSZbigniew Bodek /* Read mib registers (clear by read). */ 1768a8d7fc4aSZbigniew Bodek mvneta_update_mib(sc); 1769a8d7fc4aSZbigniew Bodek /* Extract current flow-control frame received counter. */ 1770a8d7fc4aSZbigniew Bodek fc_curr = sc->sysctl_mib[MVNETA_MIB_FC_GOOD_IDX].counter; 1771a8d7fc4aSZbigniew Bodek 1772a8d7fc4aSZbigniew Bodek 1773992fa62bSJustin Hibbits if (sc->phy_attached && if_getflags(sc->ifp) & IFF_UP) { 1774a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 1775a8d7fc4aSZbigniew Bodek mii_tick(sc->mii); 1776a8d7fc4aSZbigniew Bodek 1777a8d7fc4aSZbigniew Bodek /* Adjust MAC settings */ 1778a8d7fc4aSZbigniew Bodek mvneta_adjust_link(sc); 1779a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 1780a8d7fc4aSZbigniew Bodek } 1781a8d7fc4aSZbigniew Bodek 1782a8d7fc4aSZbigniew Bodek /* 1783a8d7fc4aSZbigniew Bodek * We were unable to refill the rx queue and left the rx func, leaving 1784a8d7fc4aSZbigniew Bodek * the ring without mbuf and no way to call the refill func. 1785a8d7fc4aSZbigniew Bodek */ 1786a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 1787a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 1788a8d7fc4aSZbigniew Bodek if (rx->needs_refill == TRUE) { 1789a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 1790a8d7fc4aSZbigniew Bodek mvneta_rx_queue_refill(sc, q); 1791a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 1792a8d7fc4aSZbigniew Bodek } 1793a8d7fc4aSZbigniew Bodek } 1794a8d7fc4aSZbigniew Bodek 1795a8d7fc4aSZbigniew Bodek /* 1796a8d7fc4aSZbigniew Bodek * Watchdog: 1797a8d7fc4aSZbigniew Bodek * - check if queue is mark as hung. 1798a8d7fc4aSZbigniew Bodek * - ignore hung status if we received some pause frame 1799a8d7fc4aSZbigniew Bodek * as hardware may have paused packet transmit. 1800a8d7fc4aSZbigniew Bodek */ 1801a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 1802a8d7fc4aSZbigniew Bodek /* 1803a8d7fc4aSZbigniew Bodek * We should take queue lock, but as we only read 1804a8d7fc4aSZbigniew Bodek * queue status we can do it without lock, we may 1805a8d7fc4aSZbigniew Bodek * only missdetect queue status for one tick. 1806a8d7fc4aSZbigniew Bodek */ 1807a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1808a8d7fc4aSZbigniew Bodek 1809a8d7fc4aSZbigniew Bodek if (tx->queue_hung && (fc_curr - fc_prev) == 0) 1810a8d7fc4aSZbigniew Bodek goto timeout; 1811a8d7fc4aSZbigniew Bodek } 1812a8d7fc4aSZbigniew Bodek 1813a8d7fc4aSZbigniew Bodek callout_schedule(&sc->tick_ch, hz); 1814a8d7fc4aSZbigniew Bodek return; 1815a8d7fc4aSZbigniew Bodek 1816a8d7fc4aSZbigniew Bodek timeout: 1817a8d7fc4aSZbigniew Bodek if_printf(sc->ifp, "watchdog timeout\n"); 1818a8d7fc4aSZbigniew Bodek 1819a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 1820a8d7fc4aSZbigniew Bodek sc->counter_watchdog++; 1821a8d7fc4aSZbigniew Bodek sc->counter_watchdog_mib++; 1822a8d7fc4aSZbigniew Bodek /* Trigger reinitialize sequence. */ 1823a8d7fc4aSZbigniew Bodek mvneta_stop_locked(sc); 1824a8d7fc4aSZbigniew Bodek mvneta_init_locked(sc); 1825a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 1826a8d7fc4aSZbigniew Bodek } 1827a8d7fc4aSZbigniew Bodek 1828a8d7fc4aSZbigniew Bodek STATIC void 1829992fa62bSJustin Hibbits mvneta_qflush(if_t ifp) 1830a8d7fc4aSZbigniew Bodek { 1831a8d7fc4aSZbigniew Bodek #ifdef MVNETA_MULTIQUEUE 1832a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1833a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1834a8d7fc4aSZbigniew Bodek struct mbuf *m; 1835a8d7fc4aSZbigniew Bodek size_t q; 1836a8d7fc4aSZbigniew Bodek 1837992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1838a8d7fc4aSZbigniew Bodek 1839a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 1840a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1841a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, q); 1842a8d7fc4aSZbigniew Bodek while ((m = buf_ring_dequeue_sc(tx->br)) != NULL) 1843a8d7fc4aSZbigniew Bodek m_freem(m); 1844a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 1845a8d7fc4aSZbigniew Bodek } 1846a8d7fc4aSZbigniew Bodek #endif 1847a8d7fc4aSZbigniew Bodek if_qflush(ifp); 1848a8d7fc4aSZbigniew Bodek } 1849a8d7fc4aSZbigniew Bodek 1850a8d7fc4aSZbigniew Bodek STATIC void 1851a8d7fc4aSZbigniew Bodek mvneta_tx_task(void *arg, int pending) 1852a8d7fc4aSZbigniew Bodek { 1853a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1854a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1855992fa62bSJustin Hibbits if_t ifp; 1856a8d7fc4aSZbigniew Bodek int error; 1857a8d7fc4aSZbigniew Bodek 1858a8d7fc4aSZbigniew Bodek tx = arg; 1859a8d7fc4aSZbigniew Bodek ifp = tx->ifp; 1860992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1861a8d7fc4aSZbigniew Bodek 1862a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, tx->qidx); 1863a8d7fc4aSZbigniew Bodek error = mvneta_xmit_locked(sc, tx->qidx); 1864a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, tx->qidx); 1865a8d7fc4aSZbigniew Bodek 1866a8d7fc4aSZbigniew Bodek /* Try again */ 1867a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0 && error != ENETDOWN)) { 1868a8d7fc4aSZbigniew Bodek pause("mvneta_tx_task_sleep", 1); 1869a8d7fc4aSZbigniew Bodek taskqueue_enqueue(tx->taskq, &tx->task); 1870a8d7fc4aSZbigniew Bodek } 1871a8d7fc4aSZbigniew Bodek } 1872a8d7fc4aSZbigniew Bodek 1873a8d7fc4aSZbigniew Bodek STATIC int 1874a8d7fc4aSZbigniew Bodek mvneta_xmitfast_locked(struct mvneta_softc *sc, int q, struct mbuf **m) 1875a8d7fc4aSZbigniew Bodek { 1876a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1877992fa62bSJustin Hibbits if_t ifp; 1878a8d7fc4aSZbigniew Bodek int error; 1879a8d7fc4aSZbigniew Bodek 1880a8d7fc4aSZbigniew Bodek KASSERT_TX_MTX(sc, q); 1881a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1882a8d7fc4aSZbigniew Bodek error = 0; 1883a8d7fc4aSZbigniew Bodek 1884a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 1885a8d7fc4aSZbigniew Bodek 1886a8d7fc4aSZbigniew Bodek /* Dont enqueue packet if the queue is disabled. */ 1887a8d7fc4aSZbigniew Bodek if (__predict_false(tx->queue_status == MVNETA_QUEUE_DISABLED)) { 1888a8d7fc4aSZbigniew Bodek m_freem(*m); 1889a8d7fc4aSZbigniew Bodek *m = NULL; 1890a8d7fc4aSZbigniew Bodek return (ENETDOWN); 1891a8d7fc4aSZbigniew Bodek } 1892a8d7fc4aSZbigniew Bodek 1893a8d7fc4aSZbigniew Bodek /* Reclaim mbuf if above threshold. */ 1894a8d7fc4aSZbigniew Bodek if (__predict_true(tx->used > MVNETA_TX_RECLAIM_COUNT)) 1895a8d7fc4aSZbigniew Bodek mvneta_tx_queue_complete(sc, q); 1896a8d7fc4aSZbigniew Bodek 1897a8d7fc4aSZbigniew Bodek /* Do not call transmit path if queue is already too full. */ 1898a8d7fc4aSZbigniew Bodek if (__predict_false(tx->used > 1899a8d7fc4aSZbigniew Bodek MVNETA_TX_RING_CNT - MVNETA_TX_SEGLIMIT)) 1900a8d7fc4aSZbigniew Bodek return (ENOBUFS); 1901a8d7fc4aSZbigniew Bodek 1902a8d7fc4aSZbigniew Bodek error = mvneta_tx_queue(sc, m, q); 1903a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0)) 1904a8d7fc4aSZbigniew Bodek return (error); 1905a8d7fc4aSZbigniew Bodek 1906a8d7fc4aSZbigniew Bodek /* Send a copy of the frame to the BPF listener */ 1907a8d7fc4aSZbigniew Bodek ETHER_BPF_MTAP(ifp, *m); 1908a8d7fc4aSZbigniew Bodek 1909a8d7fc4aSZbigniew Bodek /* Set watchdog on */ 1910a8d7fc4aSZbigniew Bodek tx->watchdog_time = ticks; 1911a8d7fc4aSZbigniew Bodek tx->queue_status = MVNETA_QUEUE_WORKING; 1912a8d7fc4aSZbigniew Bodek 1913a8d7fc4aSZbigniew Bodek return (error); 1914a8d7fc4aSZbigniew Bodek } 1915a8d7fc4aSZbigniew Bodek 1916a8d7fc4aSZbigniew Bodek #ifdef MVNETA_MULTIQUEUE 1917a8d7fc4aSZbigniew Bodek STATIC int 1918992fa62bSJustin Hibbits mvneta_transmit(if_t ifp, struct mbuf *m) 1919a8d7fc4aSZbigniew Bodek { 1920a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1921a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1922a8d7fc4aSZbigniew Bodek int error; 1923a8d7fc4aSZbigniew Bodek int q; 1924a8d7fc4aSZbigniew Bodek 1925992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 1926a8d7fc4aSZbigniew Bodek 1927a8d7fc4aSZbigniew Bodek /* Use default queue if there is no flow id as thread can migrate. */ 1928a8d7fc4aSZbigniew Bodek if (__predict_true(M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)) 1929a8d7fc4aSZbigniew Bodek q = m->m_pkthdr.flowid % MVNETA_TX_QNUM_MAX; 1930a8d7fc4aSZbigniew Bodek else 1931a8d7fc4aSZbigniew Bodek q = 0; 1932a8d7fc4aSZbigniew Bodek 1933a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1934a8d7fc4aSZbigniew Bodek 1935592fcf6cSGordon Bergling /* If buf_ring is full start transmit immediately. */ 1936a8d7fc4aSZbigniew Bodek if (buf_ring_full(tx->br)) { 1937a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, q); 1938a8d7fc4aSZbigniew Bodek mvneta_xmit_locked(sc, q); 1939a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 1940a8d7fc4aSZbigniew Bodek } 1941a8d7fc4aSZbigniew Bodek 1942a8d7fc4aSZbigniew Bodek /* 1943a8d7fc4aSZbigniew Bodek * If the buf_ring is empty we will not reorder packets. 1944a8d7fc4aSZbigniew Bodek * If the lock is available transmit without using buf_ring. 1945a8d7fc4aSZbigniew Bodek */ 1946a8d7fc4aSZbigniew Bodek if (buf_ring_empty(tx->br) && mvneta_tx_trylockq(sc, q) != 0) { 1947a8d7fc4aSZbigniew Bodek error = mvneta_xmitfast_locked(sc, q, &m); 1948a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 1949a8d7fc4aSZbigniew Bodek if (__predict_true(error == 0)) 1950a8d7fc4aSZbigniew Bodek return (0); 1951a8d7fc4aSZbigniew Bodek 1952a8d7fc4aSZbigniew Bodek /* Transmit can fail in fastpath. */ 1953a8d7fc4aSZbigniew Bodek if (__predict_false(m == NULL)) 1954a8d7fc4aSZbigniew Bodek return (error); 1955a8d7fc4aSZbigniew Bodek } 1956a8d7fc4aSZbigniew Bodek 1957a8d7fc4aSZbigniew Bodek /* Enqueue then schedule taskqueue. */ 1958a8d7fc4aSZbigniew Bodek error = drbr_enqueue(ifp, tx->br, m); 1959a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0)) 1960a8d7fc4aSZbigniew Bodek return (error); 1961a8d7fc4aSZbigniew Bodek 1962a8d7fc4aSZbigniew Bodek taskqueue_enqueue(tx->taskq, &tx->task); 1963a8d7fc4aSZbigniew Bodek return (0); 1964a8d7fc4aSZbigniew Bodek } 1965a8d7fc4aSZbigniew Bodek 1966a8d7fc4aSZbigniew Bodek STATIC int 1967a8d7fc4aSZbigniew Bodek mvneta_xmit_locked(struct mvneta_softc *sc, int q) 1968a8d7fc4aSZbigniew Bodek { 1969992fa62bSJustin Hibbits if_t ifp; 1970a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1971a8d7fc4aSZbigniew Bodek struct mbuf *m; 1972a8d7fc4aSZbigniew Bodek int error; 1973a8d7fc4aSZbigniew Bodek 1974a8d7fc4aSZbigniew Bodek KASSERT_TX_MTX(sc, q); 1975a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 1976a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 1977a8d7fc4aSZbigniew Bodek error = 0; 1978a8d7fc4aSZbigniew Bodek 1979a8d7fc4aSZbigniew Bodek while ((m = drbr_peek(ifp, tx->br)) != NULL) { 1980a8d7fc4aSZbigniew Bodek error = mvneta_xmitfast_locked(sc, q, &m); 1981a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0)) { 1982a8d7fc4aSZbigniew Bodek if (m != NULL) 1983a8d7fc4aSZbigniew Bodek drbr_putback(ifp, tx->br, m); 1984a8d7fc4aSZbigniew Bodek else 1985a8d7fc4aSZbigniew Bodek drbr_advance(ifp, tx->br); 1986a8d7fc4aSZbigniew Bodek break; 1987a8d7fc4aSZbigniew Bodek } 1988a8d7fc4aSZbigniew Bodek drbr_advance(ifp, tx->br); 1989a8d7fc4aSZbigniew Bodek } 1990a8d7fc4aSZbigniew Bodek 1991a8d7fc4aSZbigniew Bodek return (error); 1992a8d7fc4aSZbigniew Bodek } 1993a8d7fc4aSZbigniew Bodek #else /* !MVNETA_MULTIQUEUE */ 1994a8d7fc4aSZbigniew Bodek STATIC void 1995992fa62bSJustin Hibbits mvneta_start(if_t ifp) 1996a8d7fc4aSZbigniew Bodek { 1997a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 1998a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 1999a8d7fc4aSZbigniew Bodek int error; 2000a8d7fc4aSZbigniew Bodek 2001992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 2002a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, 0); 2003a8d7fc4aSZbigniew Bodek 2004a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, 0); 2005a8d7fc4aSZbigniew Bodek error = mvneta_xmit_locked(sc, 0); 2006a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, 0); 2007a8d7fc4aSZbigniew Bodek /* Handle retransmit in the background taskq. */ 2008a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0 && error != ENETDOWN)) 2009a8d7fc4aSZbigniew Bodek taskqueue_enqueue(tx->taskq, &tx->task); 2010a8d7fc4aSZbigniew Bodek } 2011a8d7fc4aSZbigniew Bodek 2012a8d7fc4aSZbigniew Bodek STATIC int 2013a8d7fc4aSZbigniew Bodek mvneta_xmit_locked(struct mvneta_softc *sc, int q) 2014a8d7fc4aSZbigniew Bodek { 2015992fa62bSJustin Hibbits if_t ifp; 2016a8d7fc4aSZbigniew Bodek struct mbuf *m; 2017a8d7fc4aSZbigniew Bodek int error; 2018a8d7fc4aSZbigniew Bodek 2019a8d7fc4aSZbigniew Bodek KASSERT_TX_MTX(sc, q); 2020a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 2021a8d7fc4aSZbigniew Bodek error = 0; 2022a8d7fc4aSZbigniew Bodek 2023992fa62bSJustin Hibbits while (!if_sendq_empty(ifp)) { 2024992fa62bSJustin Hibbits m = if_dequeue(ifp); 2025a8d7fc4aSZbigniew Bodek if (m == NULL) 2026a8d7fc4aSZbigniew Bodek break; 2027a8d7fc4aSZbigniew Bodek 2028a8d7fc4aSZbigniew Bodek error = mvneta_xmitfast_locked(sc, q, &m); 2029a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0)) { 2030a8d7fc4aSZbigniew Bodek if (m != NULL) 2031992fa62bSJustin Hibbits if_sendq_prepend(ifp, m); 2032a8d7fc4aSZbigniew Bodek break; 2033a8d7fc4aSZbigniew Bodek } 2034a8d7fc4aSZbigniew Bodek } 2035a8d7fc4aSZbigniew Bodek 2036a8d7fc4aSZbigniew Bodek return (error); 2037a8d7fc4aSZbigniew Bodek } 2038a8d7fc4aSZbigniew Bodek #endif 2039a8d7fc4aSZbigniew Bodek 2040a8d7fc4aSZbigniew Bodek STATIC int 2041992fa62bSJustin Hibbits mvneta_ioctl(if_t ifp, u_long cmd, caddr_t data) 2042a8d7fc4aSZbigniew Bodek { 2043a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 2044a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 2045a8d7fc4aSZbigniew Bodek struct ifreq *ifr; 2046a8d7fc4aSZbigniew Bodek int error, mask; 2047a8d7fc4aSZbigniew Bodek uint32_t flags; 204897ecdc00SKornel Dulęba bool reinit; 2049a8d7fc4aSZbigniew Bodek int q; 2050a8d7fc4aSZbigniew Bodek 2051a8d7fc4aSZbigniew Bodek error = 0; 205297ecdc00SKornel Dulęba reinit = false; 2053992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 2054a8d7fc4aSZbigniew Bodek ifr = (struct ifreq *)data; 2055a8d7fc4aSZbigniew Bodek switch (cmd) { 2056a8d7fc4aSZbigniew Bodek case SIOCSIFFLAGS: 2057a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2058992fa62bSJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 2059992fa62bSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 2060992fa62bSJustin Hibbits flags = if_getflags(ifp) ^ sc->mvneta_if_flags; 2061a8d7fc4aSZbigniew Bodek 2062a8d7fc4aSZbigniew Bodek if (flags != 0) 2063992fa62bSJustin Hibbits sc->mvneta_if_flags = if_getflags(ifp); 2064a8d7fc4aSZbigniew Bodek 2065a8d7fc4aSZbigniew Bodek if ((flags & IFF_PROMISC) != 0) 2066a8d7fc4aSZbigniew Bodek mvneta_filter_setup(sc); 2067a8d7fc4aSZbigniew Bodek } else { 2068a8d7fc4aSZbigniew Bodek mvneta_init_locked(sc); 2069992fa62bSJustin Hibbits sc->mvneta_if_flags = if_getflags(ifp); 2070a8d7fc4aSZbigniew Bodek if (sc->phy_attached) 2071a8d7fc4aSZbigniew Bodek mii_mediachg(sc->mii); 2072a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2073a8d7fc4aSZbigniew Bodek break; 2074a8d7fc4aSZbigniew Bodek } 2075992fa62bSJustin Hibbits } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 2076a8d7fc4aSZbigniew Bodek mvneta_stop_locked(sc); 2077a8d7fc4aSZbigniew Bodek 2078992fa62bSJustin Hibbits sc->mvneta_if_flags = if_getflags(ifp); 2079a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2080a8d7fc4aSZbigniew Bodek break; 2081a8d7fc4aSZbigniew Bodek case SIOCSIFCAP: 2082992fa62bSJustin Hibbits if (if_getmtu(ifp) > sc->tx_csum_limit && 2083a8d7fc4aSZbigniew Bodek ifr->ifr_reqcap & IFCAP_TXCSUM) 2084a8d7fc4aSZbigniew Bodek ifr->ifr_reqcap &= ~IFCAP_TXCSUM; 2085992fa62bSJustin Hibbits mask = if_getcapenable(ifp) ^ ifr->ifr_reqcap; 2086a8d7fc4aSZbigniew Bodek if (mask & IFCAP_HWCSUM) { 2087992fa62bSJustin Hibbits if_setcapenablebit(ifp, IFCAP_HWCSUM & ifr->ifr_reqcap, 2088992fa62bSJustin Hibbits IFCAP_HWCSUM); 2089992fa62bSJustin Hibbits if (if_getcapenable(ifp) & IFCAP_TXCSUM) 2090992fa62bSJustin Hibbits if_sethwassist(ifp, CSUM_IP | CSUM_TCP | 2091992fa62bSJustin Hibbits CSUM_UDP); 2092a8d7fc4aSZbigniew Bodek else 2093992fa62bSJustin Hibbits if_sethwassist(ifp, 0); 2094a8d7fc4aSZbigniew Bodek } 2095a8d7fc4aSZbigniew Bodek if (mask & IFCAP_LRO) { 2096a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2097992fa62bSJustin Hibbits if_togglecapenable(ifp, IFCAP_LRO); 2098992fa62bSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) { 2099a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 2100a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 2101a8d7fc4aSZbigniew Bodek rx->lro_enabled = !rx->lro_enabled; 2102a8d7fc4aSZbigniew Bodek } 2103a8d7fc4aSZbigniew Bodek } 2104a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2105a8d7fc4aSZbigniew Bodek } 2106a8d7fc4aSZbigniew Bodek VLAN_CAPABILITIES(ifp); 2107a8d7fc4aSZbigniew Bodek break; 2108a8d7fc4aSZbigniew Bodek case SIOCSIFMEDIA: 2109a8d7fc4aSZbigniew Bodek if ((IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T || 2110a8d7fc4aSZbigniew Bodek IFM_SUBTYPE(ifr->ifr_media) == IFM_2500_T) && 2111a8d7fc4aSZbigniew Bodek (ifr->ifr_media & IFM_FDX) == 0) { 2112a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 2113a8d7fc4aSZbigniew Bodek "%s half-duplex unsupported\n", 2114a8d7fc4aSZbigniew Bodek IFM_SUBTYPE(ifr->ifr_media) == IFM_1000_T ? 2115a8d7fc4aSZbigniew Bodek "1000Base-T" : 2116a8d7fc4aSZbigniew Bodek "2500Base-T"); 2117a8d7fc4aSZbigniew Bodek error = EINVAL; 2118a8d7fc4aSZbigniew Bodek break; 2119a8d7fc4aSZbigniew Bodek } 2120a8d7fc4aSZbigniew Bodek case SIOCGIFMEDIA: /* FALLTHROUGH */ 2121db79a5f9SLuiz Otavio O Souza case SIOCGIFXMEDIA: 2122a8d7fc4aSZbigniew Bodek if (!sc->phy_attached) 2123a8d7fc4aSZbigniew Bodek error = ifmedia_ioctl(ifp, ifr, &sc->mvneta_ifmedia, 2124a8d7fc4aSZbigniew Bodek cmd); 2125a8d7fc4aSZbigniew Bodek else 2126a8d7fc4aSZbigniew Bodek error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, 2127a8d7fc4aSZbigniew Bodek cmd); 2128a8d7fc4aSZbigniew Bodek break; 2129a8d7fc4aSZbigniew Bodek case SIOCSIFMTU: 2130a8d7fc4aSZbigniew Bodek if (ifr->ifr_mtu < 68 || ifr->ifr_mtu > MVNETA_MAX_FRAME - 2131a8d7fc4aSZbigniew Bodek MVNETA_ETHER_SIZE) { 2132a8d7fc4aSZbigniew Bodek error = EINVAL; 2133a8d7fc4aSZbigniew Bodek } else { 2134992fa62bSJustin Hibbits if_setmtu(ifp, ifr->ifr_mtu); 2135a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2136992fa62bSJustin Hibbits if (if_getmtu(ifp) + MVNETA_ETHER_SIZE <= MCLBYTES) { 213773f20bb3SMarcin Wojtas sc->rx_frame_size = MCLBYTES; 213873f20bb3SMarcin Wojtas } else { 213973f20bb3SMarcin Wojtas sc->rx_frame_size = MJUM9BYTES; 214073f20bb3SMarcin Wojtas } 2141992fa62bSJustin Hibbits if (if_getmtu(ifp) > sc->tx_csum_limit) { 2142992fa62bSJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_TXCSUM); 2143992fa62bSJustin Hibbits if_sethwassist(ifp, 0); 2144a8d7fc4aSZbigniew Bodek } else { 2145992fa62bSJustin Hibbits if_setcapenablebit(ifp, IFCAP_TXCSUM, 0); 2146992fa62bSJustin Hibbits if_sethwassist(ifp, CSUM_IP | CSUM_TCP | 2147992fa62bSJustin Hibbits CSUM_UDP); 2148a8d7fc4aSZbigniew Bodek } 214973f20bb3SMarcin Wojtas /* 215073f20bb3SMarcin Wojtas * Reinitialize RX queues. 215173f20bb3SMarcin Wojtas * We need to update RX descriptor size. 215273f20bb3SMarcin Wojtas */ 2153992fa62bSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 215497ecdc00SKornel Dulęba reinit = true; 21555438ef47SKornel Duleba mvneta_stop_locked(sc); 215697ecdc00SKornel Dulęba } 21575438ef47SKornel Duleba 215873f20bb3SMarcin Wojtas for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 215973f20bb3SMarcin Wojtas mvneta_rx_lockq(sc, q); 216073f20bb3SMarcin Wojtas if (mvneta_rx_queue_init(ifp, q) != 0) { 216173f20bb3SMarcin Wojtas device_printf(sc->dev, 216273f20bb3SMarcin Wojtas "initialization failed:" 216373f20bb3SMarcin Wojtas " cannot initialize queue\n"); 216473f20bb3SMarcin Wojtas mvneta_rx_unlockq(sc, q); 216573f20bb3SMarcin Wojtas error = ENOBUFS; 216673f20bb3SMarcin Wojtas break; 216773f20bb3SMarcin Wojtas } 216873f20bb3SMarcin Wojtas mvneta_rx_unlockq(sc, q); 216973f20bb3SMarcin Wojtas } 217097ecdc00SKornel Dulęba if (reinit) 2171a8d7fc4aSZbigniew Bodek mvneta_init_locked(sc); 21725438ef47SKornel Duleba 2173a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2174a8d7fc4aSZbigniew Bodek } 2175a8d7fc4aSZbigniew Bodek break; 2176a8d7fc4aSZbigniew Bodek 2177a8d7fc4aSZbigniew Bodek default: 2178a8d7fc4aSZbigniew Bodek error = ether_ioctl(ifp, cmd, data); 2179a8d7fc4aSZbigniew Bodek break; 2180a8d7fc4aSZbigniew Bodek } 2181a8d7fc4aSZbigniew Bodek 2182a8d7fc4aSZbigniew Bodek return (error); 2183a8d7fc4aSZbigniew Bodek } 2184a8d7fc4aSZbigniew Bodek 2185a8d7fc4aSZbigniew Bodek STATIC void 2186a8d7fc4aSZbigniew Bodek mvneta_init_locked(void *arg) 2187a8d7fc4aSZbigniew Bodek { 2188a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 2189992fa62bSJustin Hibbits if_t ifp; 2190a8d7fc4aSZbigniew Bodek uint32_t reg; 2191a8d7fc4aSZbigniew Bodek int q, cpu; 2192a8d7fc4aSZbigniew Bodek 2193a8d7fc4aSZbigniew Bodek sc = arg; 2194a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 2195a8d7fc4aSZbigniew Bodek 2196a8d7fc4aSZbigniew Bodek if (!device_is_attached(sc->dev) || 2197992fa62bSJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) 2198a8d7fc4aSZbigniew Bodek return; 2199a8d7fc4aSZbigniew Bodek 2200a8d7fc4aSZbigniew Bodek mvneta_disable_intr(sc); 2201a8d7fc4aSZbigniew Bodek callout_stop(&sc->tick_ch); 2202a8d7fc4aSZbigniew Bodek 2203a8d7fc4aSZbigniew Bodek /* Get the latest mac address */ 2204992fa62bSJustin Hibbits bcopy(if_getlladdr(ifp), sc->enaddr, ETHER_ADDR_LEN); 2205a8d7fc4aSZbigniew Bodek mvneta_set_mac_address(sc, sc->enaddr); 2206a8d7fc4aSZbigniew Bodek mvneta_filter_setup(sc); 2207a8d7fc4aSZbigniew Bodek 2208a8d7fc4aSZbigniew Bodek /* Start DMA Engine */ 2209a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXINIT, 0x00000000); 2210a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXINIT, 0x00000000); 2211a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PACC, MVNETA_PACC_ACCELERATIONMODE_EDM); 2212a8d7fc4aSZbigniew Bodek 2213a8d7fc4aSZbigniew Bodek /* Enable port */ 2214a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PMACC0); 2215a8d7fc4aSZbigniew Bodek reg |= MVNETA_PMACC0_PORTEN; 221673f20bb3SMarcin Wojtas reg &= ~MVNETA_PMACC0_FRAMESIZELIMIT_MASK; 2217992fa62bSJustin Hibbits reg |= MVNETA_PMACC0_FRAMESIZELIMIT(if_getmtu(ifp) + MVNETA_ETHER_SIZE); 2218a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMACC0, reg); 2219a8d7fc4aSZbigniew Bodek 2220a8d7fc4aSZbigniew Bodek /* Allow access to each TXQ/RXQ from both CPU's */ 2221a8d7fc4aSZbigniew Bodek for (cpu = 0; cpu < mp_ncpus; ++cpu) 2222a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PCP2Q(cpu), 2223a8d7fc4aSZbigniew Bodek MVNETA_PCP2Q_TXQEN_MASK | MVNETA_PCP2Q_RXQEN_MASK); 2224a8d7fc4aSZbigniew Bodek 2225a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 2226a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 2227a8d7fc4aSZbigniew Bodek mvneta_rx_queue_refill(sc, q); 2228a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 2229a8d7fc4aSZbigniew Bodek } 2230a8d7fc4aSZbigniew Bodek 2231a8d7fc4aSZbigniew Bodek if (!sc->phy_attached) 2232a8d7fc4aSZbigniew Bodek mvneta_linkup(sc); 2233a8d7fc4aSZbigniew Bodek 2234a8d7fc4aSZbigniew Bodek /* Enable interrupt */ 2235a8d7fc4aSZbigniew Bodek mvneta_enable_intr(sc); 2236a8d7fc4aSZbigniew Bodek 2237a8d7fc4aSZbigniew Bodek /* Set Counter */ 2238a8d7fc4aSZbigniew Bodek callout_schedule(&sc->tick_ch, hz); 2239a8d7fc4aSZbigniew Bodek 2240992fa62bSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 2241a8d7fc4aSZbigniew Bodek } 2242a8d7fc4aSZbigniew Bodek 2243a8d7fc4aSZbigniew Bodek STATIC void 2244a8d7fc4aSZbigniew Bodek mvneta_init(void *arg) 2245a8d7fc4aSZbigniew Bodek { 2246a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 2247a8d7fc4aSZbigniew Bodek 2248a8d7fc4aSZbigniew Bodek sc = arg; 2249a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2250a8d7fc4aSZbigniew Bodek mvneta_init_locked(sc); 2251a8d7fc4aSZbigniew Bodek if (sc->phy_attached) 2252a8d7fc4aSZbigniew Bodek mii_mediachg(sc->mii); 2253a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2254a8d7fc4aSZbigniew Bodek } 2255a8d7fc4aSZbigniew Bodek 2256a8d7fc4aSZbigniew Bodek /* ARGSUSED */ 2257a8d7fc4aSZbigniew Bodek STATIC void 2258a8d7fc4aSZbigniew Bodek mvneta_stop_locked(struct mvneta_softc *sc) 2259a8d7fc4aSZbigniew Bodek { 2260992fa62bSJustin Hibbits if_t ifp; 2261a8d7fc4aSZbigniew Bodek uint32_t reg; 2262a8d7fc4aSZbigniew Bodek int q; 2263a8d7fc4aSZbigniew Bodek 2264a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 2265992fa62bSJustin Hibbits if (ifp == NULL || (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 2266a8d7fc4aSZbigniew Bodek return; 2267a8d7fc4aSZbigniew Bodek 2268a8d7fc4aSZbigniew Bodek mvneta_disable_intr(sc); 2269a8d7fc4aSZbigniew Bodek 2270a8d7fc4aSZbigniew Bodek callout_stop(&sc->tick_ch); 2271a8d7fc4aSZbigniew Bodek 2272992fa62bSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 2273a8d7fc4aSZbigniew Bodek 2274a8d7fc4aSZbigniew Bodek /* Link down */ 2275a8d7fc4aSZbigniew Bodek if (sc->linkup == TRUE) 2276a8d7fc4aSZbigniew Bodek mvneta_linkdown(sc); 2277a8d7fc4aSZbigniew Bodek 2278a8d7fc4aSZbigniew Bodek /* Reset the MAC Port Enable bit */ 2279a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PMACC0); 2280a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PMACC0_PORTEN; 2281a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMACC0, reg); 2282a8d7fc4aSZbigniew Bodek 2283a8d7fc4aSZbigniew Bodek /* Disable each of queue */ 2284a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 2285a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 2286a8d7fc4aSZbigniew Bodek mvneta_ring_flush_rx_queue(sc, q); 2287a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 2288a8d7fc4aSZbigniew Bodek } 2289a8d7fc4aSZbigniew Bodek 2290a8d7fc4aSZbigniew Bodek /* 2291a8d7fc4aSZbigniew Bodek * Hold Reset state of DMA Engine 2292a8d7fc4aSZbigniew Bodek * (must write 0x0 to restart it) 2293a8d7fc4aSZbigniew Bodek */ 2294a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXINIT, 0x00000001); 2295a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXINIT, 0x00000001); 2296a8d7fc4aSZbigniew Bodek 2297a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 2298a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, q); 2299a8d7fc4aSZbigniew Bodek mvneta_ring_flush_tx_queue(sc, q); 2300a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 2301a8d7fc4aSZbigniew Bodek } 2302a8d7fc4aSZbigniew Bodek } 2303a8d7fc4aSZbigniew Bodek 2304a8d7fc4aSZbigniew Bodek STATIC void 2305a8d7fc4aSZbigniew Bodek mvneta_stop(struct mvneta_softc *sc) 2306a8d7fc4aSZbigniew Bodek { 2307a8d7fc4aSZbigniew Bodek 2308a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2309a8d7fc4aSZbigniew Bodek mvneta_stop_locked(sc); 2310a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2311a8d7fc4aSZbigniew Bodek } 2312a8d7fc4aSZbigniew Bodek 2313a8d7fc4aSZbigniew Bodek STATIC int 2314992fa62bSJustin Hibbits mvneta_mediachange(if_t ifp) 2315a8d7fc4aSZbigniew Bodek { 2316a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 2317a8d7fc4aSZbigniew Bodek 2318992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 2319a8d7fc4aSZbigniew Bodek 2320a8d7fc4aSZbigniew Bodek if (!sc->phy_attached && !sc->use_inband_status) { 2321a8d7fc4aSZbigniew Bodek /* We shouldn't be here */ 2322a8d7fc4aSZbigniew Bodek if_printf(ifp, "Cannot change media in fixed-link mode!\n"); 2323a8d7fc4aSZbigniew Bodek return (0); 2324a8d7fc4aSZbigniew Bodek } 2325a8d7fc4aSZbigniew Bodek 2326a8d7fc4aSZbigniew Bodek if (sc->use_inband_status) { 2327a8d7fc4aSZbigniew Bodek mvneta_update_media(sc, sc->mvneta_ifmedia.ifm_media); 2328a8d7fc4aSZbigniew Bodek return (0); 2329a8d7fc4aSZbigniew Bodek } 2330a8d7fc4aSZbigniew Bodek 2331a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2332a8d7fc4aSZbigniew Bodek 2333a8d7fc4aSZbigniew Bodek /* Update PHY */ 2334a8d7fc4aSZbigniew Bodek mii_mediachg(sc->mii); 2335a8d7fc4aSZbigniew Bodek 2336a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2337a8d7fc4aSZbigniew Bodek 2338a8d7fc4aSZbigniew Bodek return (0); 2339a8d7fc4aSZbigniew Bodek } 2340a8d7fc4aSZbigniew Bodek 2341a8d7fc4aSZbigniew Bodek STATIC void 2342a8d7fc4aSZbigniew Bodek mvneta_get_media(struct mvneta_softc *sc, struct ifmediareq *ifmr) 2343a8d7fc4aSZbigniew Bodek { 2344a8d7fc4aSZbigniew Bodek uint32_t psr; 2345a8d7fc4aSZbigniew Bodek 2346a8d7fc4aSZbigniew Bodek psr = MVNETA_READ(sc, MVNETA_PSR); 2347a8d7fc4aSZbigniew Bodek 2348a8d7fc4aSZbigniew Bodek /* Speed */ 2349a8d7fc4aSZbigniew Bodek if (psr & MVNETA_PSR_GMIISPEED) 2350a8d7fc4aSZbigniew Bodek ifmr->ifm_active = IFM_ETHER_SUBTYPE_SET(IFM_1000_T); 2351a8d7fc4aSZbigniew Bodek else if (psr & MVNETA_PSR_MIISPEED) 2352a8d7fc4aSZbigniew Bodek ifmr->ifm_active = IFM_ETHER_SUBTYPE_SET(IFM_100_TX); 2353a8d7fc4aSZbigniew Bodek else if (psr & MVNETA_PSR_LINKUP) 2354a8d7fc4aSZbigniew Bodek ifmr->ifm_active = IFM_ETHER_SUBTYPE_SET(IFM_10_T); 2355a8d7fc4aSZbigniew Bodek 2356a8d7fc4aSZbigniew Bodek /* Duplex */ 2357a8d7fc4aSZbigniew Bodek if (psr & MVNETA_PSR_FULLDX) 2358a8d7fc4aSZbigniew Bodek ifmr->ifm_active |= IFM_FDX; 2359a8d7fc4aSZbigniew Bodek 2360a8d7fc4aSZbigniew Bodek /* Link */ 2361a8d7fc4aSZbigniew Bodek ifmr->ifm_status = IFM_AVALID; 2362a8d7fc4aSZbigniew Bodek if (psr & MVNETA_PSR_LINKUP) 2363a8d7fc4aSZbigniew Bodek ifmr->ifm_status |= IFM_ACTIVE; 2364a8d7fc4aSZbigniew Bodek } 2365a8d7fc4aSZbigniew Bodek 2366a8d7fc4aSZbigniew Bodek STATIC void 2367992fa62bSJustin Hibbits mvneta_mediastatus(if_t ifp, struct ifmediareq *ifmr) 2368a8d7fc4aSZbigniew Bodek { 2369a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 2370a8d7fc4aSZbigniew Bodek struct mii_data *mii; 2371a8d7fc4aSZbigniew Bodek 2372992fa62bSJustin Hibbits sc = if_getsoftc(ifp); 2373a8d7fc4aSZbigniew Bodek 2374a8d7fc4aSZbigniew Bodek if (!sc->phy_attached && !sc->use_inband_status) { 2375a8d7fc4aSZbigniew Bodek ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; 2376a8d7fc4aSZbigniew Bodek return; 2377a8d7fc4aSZbigniew Bodek } 2378a8d7fc4aSZbigniew Bodek 2379a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2380a8d7fc4aSZbigniew Bodek 2381a8d7fc4aSZbigniew Bodek if (sc->use_inband_status) { 2382a8d7fc4aSZbigniew Bodek mvneta_get_media(sc, ifmr); 2383a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2384a8d7fc4aSZbigniew Bodek return; 2385a8d7fc4aSZbigniew Bodek } 2386a8d7fc4aSZbigniew Bodek 2387a8d7fc4aSZbigniew Bodek mii = sc->mii; 2388a8d7fc4aSZbigniew Bodek mii_pollstat(mii); 2389a8d7fc4aSZbigniew Bodek 2390a8d7fc4aSZbigniew Bodek ifmr->ifm_active = mii->mii_media_active; 2391a8d7fc4aSZbigniew Bodek ifmr->ifm_status = mii->mii_media_status; 2392a8d7fc4aSZbigniew Bodek 2393a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2394a8d7fc4aSZbigniew Bodek } 2395a8d7fc4aSZbigniew Bodek 2396a8d7fc4aSZbigniew Bodek /* 2397a8d7fc4aSZbigniew Bodek * Link State Notify 2398a8d7fc4aSZbigniew Bodek */ 2399a8d7fc4aSZbigniew Bodek STATIC void 2400a8d7fc4aSZbigniew Bodek mvneta_update_autoneg(struct mvneta_softc *sc, int enable) 2401a8d7fc4aSZbigniew Bodek { 2402a8d7fc4aSZbigniew Bodek int reg; 2403a8d7fc4aSZbigniew Bodek 2404a8d7fc4aSZbigniew Bodek if (enable) { 2405a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PANC); 2406a8d7fc4aSZbigniew Bodek reg &= ~(MVNETA_PANC_FORCELINKFAIL | MVNETA_PANC_FORCELINKPASS | 2407a8d7fc4aSZbigniew Bodek MVNETA_PANC_ANFCEN); 2408a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_ANDUPLEXEN | MVNETA_PANC_ANSPEEDEN | 2409a8d7fc4aSZbigniew Bodek MVNETA_PANC_INBANDANEN; 2410a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PANC, reg); 2411a8d7fc4aSZbigniew Bodek 2412a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PMACC2); 2413a8d7fc4aSZbigniew Bodek reg |= MVNETA_PMACC2_INBANDANMODE; 2414a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMACC2, reg); 2415a8d7fc4aSZbigniew Bodek 2416a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PSOMSCD); 2417a8d7fc4aSZbigniew Bodek reg |= MVNETA_PSOMSCD_ENABLE; 2418a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PSOMSCD, reg); 2419a8d7fc4aSZbigniew Bodek } else { 2420a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PANC); 2421a8d7fc4aSZbigniew Bodek reg &= ~(MVNETA_PANC_FORCELINKFAIL | MVNETA_PANC_FORCELINKPASS | 2422a8d7fc4aSZbigniew Bodek MVNETA_PANC_ANDUPLEXEN | MVNETA_PANC_ANSPEEDEN | 2423a8d7fc4aSZbigniew Bodek MVNETA_PANC_INBANDANEN); 2424a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PANC, reg); 2425a8d7fc4aSZbigniew Bodek 2426a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PMACC2); 2427a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PMACC2_INBANDANMODE; 2428a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PMACC2, reg); 2429a8d7fc4aSZbigniew Bodek 2430a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PSOMSCD); 2431a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PSOMSCD_ENABLE; 2432a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PSOMSCD, reg); 2433a8d7fc4aSZbigniew Bodek } 2434a8d7fc4aSZbigniew Bodek } 2435a8d7fc4aSZbigniew Bodek 2436a8d7fc4aSZbigniew Bodek STATIC int 2437a8d7fc4aSZbigniew Bodek mvneta_update_media(struct mvneta_softc *sc, int media) 2438a8d7fc4aSZbigniew Bodek { 2439a8d7fc4aSZbigniew Bodek int reg, err; 2440a8d7fc4aSZbigniew Bodek boolean_t running; 2441a8d7fc4aSZbigniew Bodek 2442a8d7fc4aSZbigniew Bodek err = 0; 2443a8d7fc4aSZbigniew Bodek 2444a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 2445a8d7fc4aSZbigniew Bodek 2446a8d7fc4aSZbigniew Bodek mvneta_linkreset(sc); 2447a8d7fc4aSZbigniew Bodek 2448992fa62bSJustin Hibbits running = (if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) != 0; 2449a8d7fc4aSZbigniew Bodek if (running) 2450a8d7fc4aSZbigniew Bodek mvneta_stop_locked(sc); 2451a8d7fc4aSZbigniew Bodek 2452a8d7fc4aSZbigniew Bodek sc->autoneg = (IFM_SUBTYPE(media) == IFM_AUTO); 2453a8d7fc4aSZbigniew Bodek 2454231237bbSSebastien Bini if (!sc->phy_attached || sc->use_inband_status) 2455a8d7fc4aSZbigniew Bodek mvneta_update_autoneg(sc, IFM_SUBTYPE(media) == IFM_AUTO); 2456a8d7fc4aSZbigniew Bodek 2457a8d7fc4aSZbigniew Bodek mvneta_update_eee(sc); 2458a8d7fc4aSZbigniew Bodek mvneta_update_fc(sc); 2459a8d7fc4aSZbigniew Bodek 2460a8d7fc4aSZbigniew Bodek if (IFM_SUBTYPE(media) != IFM_AUTO) { 2461a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PANC); 2462a8d7fc4aSZbigniew Bodek reg &= ~(MVNETA_PANC_SETGMIISPEED | 2463a8d7fc4aSZbigniew Bodek MVNETA_PANC_SETMIISPEED | 2464a8d7fc4aSZbigniew Bodek MVNETA_PANC_SETFULLDX); 2465a8d7fc4aSZbigniew Bodek if (IFM_SUBTYPE(media) == IFM_1000_T || 2466a8d7fc4aSZbigniew Bodek IFM_SUBTYPE(media) == IFM_2500_T) { 2467a8d7fc4aSZbigniew Bodek if ((media & IFM_FDX) == 0) { 2468a8d7fc4aSZbigniew Bodek device_printf(sc->dev, 2469a8d7fc4aSZbigniew Bodek "%s half-duplex unsupported\n", 2470a8d7fc4aSZbigniew Bodek IFM_SUBTYPE(media) == IFM_1000_T ? 2471a8d7fc4aSZbigniew Bodek "1000Base-T" : 2472a8d7fc4aSZbigniew Bodek "2500Base-T"); 2473a8d7fc4aSZbigniew Bodek err = EINVAL; 2474a8d7fc4aSZbigniew Bodek goto out; 2475a8d7fc4aSZbigniew Bodek } 2476a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_SETGMIISPEED; 2477a8d7fc4aSZbigniew Bodek } else if (IFM_SUBTYPE(media) == IFM_100_TX) 2478a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_SETMIISPEED; 2479a8d7fc4aSZbigniew Bodek 2480a8d7fc4aSZbigniew Bodek if (media & IFM_FDX) 2481a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_SETFULLDX; 2482a8d7fc4aSZbigniew Bodek 2483a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PANC, reg); 2484a8d7fc4aSZbigniew Bodek } 2485a8d7fc4aSZbigniew Bodek out: 2486a8d7fc4aSZbigniew Bodek if (running) 2487a8d7fc4aSZbigniew Bodek mvneta_init_locked(sc); 2488a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 2489a8d7fc4aSZbigniew Bodek return (err); 2490a8d7fc4aSZbigniew Bodek } 2491a8d7fc4aSZbigniew Bodek 2492a8d7fc4aSZbigniew Bodek STATIC void 2493a8d7fc4aSZbigniew Bodek mvneta_adjust_link(struct mvneta_softc *sc) 2494a8d7fc4aSZbigniew Bodek { 2495a8d7fc4aSZbigniew Bodek boolean_t phy_linkup; 2496a8d7fc4aSZbigniew Bodek int reg; 2497a8d7fc4aSZbigniew Bodek 2498a8d7fc4aSZbigniew Bodek /* Update eee/fc */ 2499a8d7fc4aSZbigniew Bodek mvneta_update_eee(sc); 2500a8d7fc4aSZbigniew Bodek mvneta_update_fc(sc); 2501a8d7fc4aSZbigniew Bodek 2502a8d7fc4aSZbigniew Bodek /* Check for link change */ 2503a8d7fc4aSZbigniew Bodek phy_linkup = (sc->mii->mii_media_status & 2504a8d7fc4aSZbigniew Bodek (IFM_AVALID | IFM_ACTIVE)) == (IFM_AVALID | IFM_ACTIVE); 2505a8d7fc4aSZbigniew Bodek 2506a8d7fc4aSZbigniew Bodek if (sc->linkup != phy_linkup) 2507a8d7fc4aSZbigniew Bodek mvneta_linkupdate(sc, phy_linkup); 2508a8d7fc4aSZbigniew Bodek 2509a8d7fc4aSZbigniew Bodek /* Don't update media on disabled link */ 2510a8d7fc4aSZbigniew Bodek if (!phy_linkup) 2511a8d7fc4aSZbigniew Bodek return; 2512a8d7fc4aSZbigniew Bodek 2513a8d7fc4aSZbigniew Bodek /* Check for media type change */ 2514a8d7fc4aSZbigniew Bodek if (sc->mvneta_media != sc->mii->mii_media_active) { 2515a8d7fc4aSZbigniew Bodek sc->mvneta_media = sc->mii->mii_media_active; 2516a8d7fc4aSZbigniew Bodek 2517a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PANC); 2518a8d7fc4aSZbigniew Bodek reg &= ~(MVNETA_PANC_SETGMIISPEED | 2519a8d7fc4aSZbigniew Bodek MVNETA_PANC_SETMIISPEED | 2520a8d7fc4aSZbigniew Bodek MVNETA_PANC_SETFULLDX); 2521a8d7fc4aSZbigniew Bodek if (IFM_SUBTYPE(sc->mvneta_media) == IFM_1000_T || 2522a8d7fc4aSZbigniew Bodek IFM_SUBTYPE(sc->mvneta_media) == IFM_2500_T) { 2523a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_SETGMIISPEED; 2524a8d7fc4aSZbigniew Bodek } else if (IFM_SUBTYPE(sc->mvneta_media) == IFM_100_TX) 2525a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_SETMIISPEED; 2526a8d7fc4aSZbigniew Bodek 2527a8d7fc4aSZbigniew Bodek if (sc->mvneta_media & IFM_FDX) 2528a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_SETFULLDX; 2529a8d7fc4aSZbigniew Bodek 2530a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PANC, reg); 2531a8d7fc4aSZbigniew Bodek } 2532a8d7fc4aSZbigniew Bodek } 2533a8d7fc4aSZbigniew Bodek 2534a8d7fc4aSZbigniew Bodek STATIC void 2535a8d7fc4aSZbigniew Bodek mvneta_link_isr(struct mvneta_softc *sc) 2536a8d7fc4aSZbigniew Bodek { 2537a8d7fc4aSZbigniew Bodek int linkup; 2538a8d7fc4aSZbigniew Bodek 2539a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 2540a8d7fc4aSZbigniew Bodek 2541a8d7fc4aSZbigniew Bodek linkup = MVNETA_IS_LINKUP(sc) ? TRUE : FALSE; 2542a8d7fc4aSZbigniew Bodek if (sc->linkup == linkup) 2543a8d7fc4aSZbigniew Bodek return; 2544a8d7fc4aSZbigniew Bodek 2545a8d7fc4aSZbigniew Bodek if (linkup == TRUE) 2546a8d7fc4aSZbigniew Bodek mvneta_linkup(sc); 2547a8d7fc4aSZbigniew Bodek else 2548a8d7fc4aSZbigniew Bodek mvneta_linkdown(sc); 2549a8d7fc4aSZbigniew Bodek 2550a8d7fc4aSZbigniew Bodek #ifdef DEBUG 2551b831f9ceSHubert Mazur device_printf(sc->dev, 2552992fa62bSJustin Hibbits "%s: link %s\n", if_name(sc->ifp), linkup ? "up" : "down"); 2553a8d7fc4aSZbigniew Bodek #endif 2554a8d7fc4aSZbigniew Bodek } 2555a8d7fc4aSZbigniew Bodek 2556a8d7fc4aSZbigniew Bodek STATIC void 2557a8d7fc4aSZbigniew Bodek mvneta_linkupdate(struct mvneta_softc *sc, boolean_t linkup) 2558a8d7fc4aSZbigniew Bodek { 2559a8d7fc4aSZbigniew Bodek 2560a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 2561a8d7fc4aSZbigniew Bodek 2562a8d7fc4aSZbigniew Bodek if (linkup == TRUE) 2563a8d7fc4aSZbigniew Bodek mvneta_linkup(sc); 2564a8d7fc4aSZbigniew Bodek else 2565a8d7fc4aSZbigniew Bodek mvneta_linkdown(sc); 2566a8d7fc4aSZbigniew Bodek 2567a8d7fc4aSZbigniew Bodek #ifdef DEBUG 2568b831f9ceSHubert Mazur device_printf(sc->dev, 2569992fa62bSJustin Hibbits "%s: link %s\n", if_name(sc->ifp), linkup ? "up" : "down"); 2570a8d7fc4aSZbigniew Bodek #endif 2571a8d7fc4aSZbigniew Bodek } 2572a8d7fc4aSZbigniew Bodek 2573a8d7fc4aSZbigniew Bodek STATIC void 2574a8d7fc4aSZbigniew Bodek mvneta_update_eee(struct mvneta_softc *sc) 2575a8d7fc4aSZbigniew Bodek { 2576a8d7fc4aSZbigniew Bodek uint32_t reg; 2577a8d7fc4aSZbigniew Bodek 2578a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 2579a8d7fc4aSZbigniew Bodek 2580a8d7fc4aSZbigniew Bodek /* set EEE parameters */ 2581a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_LPIC1); 2582a8d7fc4aSZbigniew Bodek if (sc->cf_lpi) 2583a8d7fc4aSZbigniew Bodek reg |= MVNETA_LPIC1_LPIRE; 2584a8d7fc4aSZbigniew Bodek else 2585a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_LPIC1_LPIRE; 2586a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_LPIC1, reg); 2587a8d7fc4aSZbigniew Bodek } 2588a8d7fc4aSZbigniew Bodek 2589a8d7fc4aSZbigniew Bodek STATIC void 2590a8d7fc4aSZbigniew Bodek mvneta_update_fc(struct mvneta_softc *sc) 2591a8d7fc4aSZbigniew Bodek { 2592a8d7fc4aSZbigniew Bodek uint32_t reg; 2593a8d7fc4aSZbigniew Bodek 2594a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 2595a8d7fc4aSZbigniew Bodek 2596a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PANC); 2597a8d7fc4aSZbigniew Bodek if (sc->cf_fc) { 2598a8d7fc4aSZbigniew Bodek /* Flow control negotiation */ 2599a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_PAUSEADV; 2600a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_ANFCEN; 2601a8d7fc4aSZbigniew Bodek } else { 2602a8d7fc4aSZbigniew Bodek /* Disable flow control negotiation */ 2603a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PANC_PAUSEADV; 2604a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PANC_ANFCEN; 2605a8d7fc4aSZbigniew Bodek } 2606a8d7fc4aSZbigniew Bodek 2607a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PANC, reg); 2608a8d7fc4aSZbigniew Bodek } 2609a8d7fc4aSZbigniew Bodek 2610a8d7fc4aSZbigniew Bodek STATIC void 2611a8d7fc4aSZbigniew Bodek mvneta_linkup(struct mvneta_softc *sc) 2612a8d7fc4aSZbigniew Bodek { 2613a8d7fc4aSZbigniew Bodek uint32_t reg; 2614a8d7fc4aSZbigniew Bodek 2615a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 2616a8d7fc4aSZbigniew Bodek 2617231237bbSSebastien Bini if (!sc->phy_attached || !sc->use_inband_status) { 2618a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PANC); 2619a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_FORCELINKPASS; 2620a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PANC_FORCELINKFAIL; 2621a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PANC, reg); 2622a8d7fc4aSZbigniew Bodek } 2623a8d7fc4aSZbigniew Bodek 2624a8d7fc4aSZbigniew Bodek mvneta_qflush(sc->ifp); 2625a8d7fc4aSZbigniew Bodek mvneta_portup(sc); 2626a8d7fc4aSZbigniew Bodek sc->linkup = TRUE; 2627a8d7fc4aSZbigniew Bodek if_link_state_change(sc->ifp, LINK_STATE_UP); 2628a8d7fc4aSZbigniew Bodek } 2629a8d7fc4aSZbigniew Bodek 2630a8d7fc4aSZbigniew Bodek STATIC void 2631a8d7fc4aSZbigniew Bodek mvneta_linkdown(struct mvneta_softc *sc) 2632a8d7fc4aSZbigniew Bodek { 2633a8d7fc4aSZbigniew Bodek uint32_t reg; 2634a8d7fc4aSZbigniew Bodek 2635a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 2636a8d7fc4aSZbigniew Bodek 2637231237bbSSebastien Bini if (!sc->phy_attached || !sc->use_inband_status) { 2638a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PANC); 2639a8d7fc4aSZbigniew Bodek reg &= ~MVNETA_PANC_FORCELINKPASS; 2640a8d7fc4aSZbigniew Bodek reg |= MVNETA_PANC_FORCELINKFAIL; 2641a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PANC, reg); 2642a8d7fc4aSZbigniew Bodek } 2643a8d7fc4aSZbigniew Bodek 2644a8d7fc4aSZbigniew Bodek mvneta_portdown(sc); 2645a8d7fc4aSZbigniew Bodek mvneta_qflush(sc->ifp); 2646a8d7fc4aSZbigniew Bodek sc->linkup = FALSE; 2647a8d7fc4aSZbigniew Bodek if_link_state_change(sc->ifp, LINK_STATE_DOWN); 2648a8d7fc4aSZbigniew Bodek } 2649a8d7fc4aSZbigniew Bodek 2650a8d7fc4aSZbigniew Bodek STATIC void 2651a8d7fc4aSZbigniew Bodek mvneta_linkreset(struct mvneta_softc *sc) 2652a8d7fc4aSZbigniew Bodek { 2653a8d7fc4aSZbigniew Bodek struct mii_softc *mii; 2654a8d7fc4aSZbigniew Bodek 2655a8d7fc4aSZbigniew Bodek if (sc->phy_attached) { 2656a8d7fc4aSZbigniew Bodek /* Force reset PHY */ 2657a8d7fc4aSZbigniew Bodek mii = LIST_FIRST(&sc->mii->mii_phys); 2658a8d7fc4aSZbigniew Bodek if (mii) 2659a8d7fc4aSZbigniew Bodek mii_phy_reset(mii); 2660a8d7fc4aSZbigniew Bodek } 2661a8d7fc4aSZbigniew Bodek } 2662a8d7fc4aSZbigniew Bodek 2663a8d7fc4aSZbigniew Bodek /* 2664a8d7fc4aSZbigniew Bodek * Tx Subroutines 2665a8d7fc4aSZbigniew Bodek */ 2666a8d7fc4aSZbigniew Bodek STATIC int 2667a8d7fc4aSZbigniew Bodek mvneta_tx_queue(struct mvneta_softc *sc, struct mbuf **mbufp, int q) 2668a8d7fc4aSZbigniew Bodek { 2669992fa62bSJustin Hibbits if_t ifp; 2670a8d7fc4aSZbigniew Bodek bus_dma_segment_t txsegs[MVNETA_TX_SEGLIMIT]; 2671a8d7fc4aSZbigniew Bodek struct mbuf *mtmp, *mbuf; 2672a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 2673a8d7fc4aSZbigniew Bodek struct mvneta_buf *txbuf; 2674a8d7fc4aSZbigniew Bodek struct mvneta_tx_desc *t; 2675a8d7fc4aSZbigniew Bodek uint32_t ptxsu; 267627f889cfSJohn Baldwin int used, error, i, txnsegs; 2677a8d7fc4aSZbigniew Bodek 2678a8d7fc4aSZbigniew Bodek mbuf = *mbufp; 2679a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 2680a8d7fc4aSZbigniew Bodek DASSERT(tx->used >= 0); 2681a8d7fc4aSZbigniew Bodek DASSERT(tx->used <= MVNETA_TX_RING_CNT); 2682a8d7fc4aSZbigniew Bodek t = NULL; 2683a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 2684a8d7fc4aSZbigniew Bodek 2685a8d7fc4aSZbigniew Bodek if (__predict_false(mbuf->m_flags & M_VLANTAG)) { 2686a8d7fc4aSZbigniew Bodek mbuf = ether_vlanencap(mbuf, mbuf->m_pkthdr.ether_vtag); 2687a8d7fc4aSZbigniew Bodek if (mbuf == NULL) { 2688a8d7fc4aSZbigniew Bodek tx->drv_error++; 2689a8d7fc4aSZbigniew Bodek *mbufp = NULL; 2690a8d7fc4aSZbigniew Bodek return (ENOBUFS); 2691a8d7fc4aSZbigniew Bodek } 2692a8d7fc4aSZbigniew Bodek mbuf->m_flags &= ~M_VLANTAG; 2693a8d7fc4aSZbigniew Bodek *mbufp = mbuf; 2694a8d7fc4aSZbigniew Bodek } 2695a8d7fc4aSZbigniew Bodek 2696a8d7fc4aSZbigniew Bodek if (__predict_false(mbuf->m_next != NULL && 2697a8d7fc4aSZbigniew Bodek (mbuf->m_pkthdr.csum_flags & 2698a8d7fc4aSZbigniew Bodek (CSUM_IP | CSUM_TCP | CSUM_UDP)) != 0)) { 2699a8d7fc4aSZbigniew Bodek if (M_WRITABLE(mbuf) == 0) { 2700a8d7fc4aSZbigniew Bodek mtmp = m_dup(mbuf, M_NOWAIT); 2701a8d7fc4aSZbigniew Bodek m_freem(mbuf); 2702a8d7fc4aSZbigniew Bodek if (mtmp == NULL) { 2703a8d7fc4aSZbigniew Bodek tx->drv_error++; 2704a8d7fc4aSZbigniew Bodek *mbufp = NULL; 2705a8d7fc4aSZbigniew Bodek return (ENOBUFS); 2706a8d7fc4aSZbigniew Bodek } 2707a8d7fc4aSZbigniew Bodek *mbufp = mbuf = mtmp; 2708a8d7fc4aSZbigniew Bodek } 2709a8d7fc4aSZbigniew Bodek } 2710a8d7fc4aSZbigniew Bodek 2711a8d7fc4aSZbigniew Bodek /* load mbuf using dmamap of 1st descriptor */ 2712a8d7fc4aSZbigniew Bodek txbuf = &tx->txbuf[tx->cpu]; 2713a8d7fc4aSZbigniew Bodek error = bus_dmamap_load_mbuf_sg(sc->txmbuf_dtag, 2714a8d7fc4aSZbigniew Bodek txbuf->dmap, mbuf, txsegs, &txnsegs, 2715a8d7fc4aSZbigniew Bodek BUS_DMA_NOWAIT); 2716a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0)) { 2717a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 2718992fa62bSJustin Hibbits CTR3(KTR_SPARE2, "%s:%u bus_dmamap_load_mbuf_sg error=%d", if_name(ifp), q, error); 2719a8d7fc4aSZbigniew Bodek #endif 2720a8d7fc4aSZbigniew Bodek /* This is the only recoverable error (except EFBIG). */ 2721a8d7fc4aSZbigniew Bodek if (error != ENOMEM) { 2722a8d7fc4aSZbigniew Bodek tx->drv_error++; 2723a8d7fc4aSZbigniew Bodek m_freem(mbuf); 2724a8d7fc4aSZbigniew Bodek *mbufp = NULL; 2725a8d7fc4aSZbigniew Bodek return (ENOBUFS); 2726a8d7fc4aSZbigniew Bodek } 2727a8d7fc4aSZbigniew Bodek return (error); 2728a8d7fc4aSZbigniew Bodek } 2729a8d7fc4aSZbigniew Bodek 2730a8d7fc4aSZbigniew Bodek if (__predict_false(txnsegs <= 0 2731a8d7fc4aSZbigniew Bodek || (txnsegs + tx->used) > MVNETA_TX_RING_CNT)) { 2732a8d7fc4aSZbigniew Bodek /* we have no enough descriptors or mbuf is broken */ 2733a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 2734a8d7fc4aSZbigniew Bodek CTR3(KTR_SPARE2, "%s:%u not enough descriptors txnsegs=%d", 2735992fa62bSJustin Hibbits if_name(ifp), q, txnsegs); 2736a8d7fc4aSZbigniew Bodek #endif 2737a8d7fc4aSZbigniew Bodek bus_dmamap_unload(sc->txmbuf_dtag, txbuf->dmap); 2738a8d7fc4aSZbigniew Bodek return (ENOBUFS); 2739a8d7fc4aSZbigniew Bodek } 2740a8d7fc4aSZbigniew Bodek DASSERT(txbuf->m == NULL); 2741a8d7fc4aSZbigniew Bodek 2742a8d7fc4aSZbigniew Bodek /* remember mbuf using 1st descriptor */ 2743a8d7fc4aSZbigniew Bodek txbuf->m = mbuf; 2744a8d7fc4aSZbigniew Bodek bus_dmamap_sync(sc->txmbuf_dtag, txbuf->dmap, 2745a8d7fc4aSZbigniew Bodek BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 2746a8d7fc4aSZbigniew Bodek 2747a8d7fc4aSZbigniew Bodek /* load to tx descriptors */ 2748a8d7fc4aSZbigniew Bodek used = 0; 2749a8d7fc4aSZbigniew Bodek for (i = 0; i < txnsegs; i++) { 2750a8d7fc4aSZbigniew Bodek t = &tx->desc[tx->cpu]; 2751a8d7fc4aSZbigniew Bodek t->command = 0; 2752a8d7fc4aSZbigniew Bodek t->l4ichk = 0; 2753a8d7fc4aSZbigniew Bodek t->flags = 0; 2754a8d7fc4aSZbigniew Bodek if (__predict_true(i == 0)) { 2755a8d7fc4aSZbigniew Bodek /* 1st descriptor */ 2756a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_W_PACKET_OFFSET(0); 2757a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_F; 2758a8d7fc4aSZbigniew Bodek mvneta_tx_set_csumflag(ifp, t, mbuf); 2759a8d7fc4aSZbigniew Bodek } 2760a8d7fc4aSZbigniew Bodek t->bufptr_pa = txsegs[i].ds_addr; 2761a8d7fc4aSZbigniew Bodek t->bytecnt = txsegs[i].ds_len; 2762a8d7fc4aSZbigniew Bodek tx->cpu = tx_counter_adv(tx->cpu, 1); 2763a8d7fc4aSZbigniew Bodek 2764a8d7fc4aSZbigniew Bodek tx->used++; 2765a8d7fc4aSZbigniew Bodek used++; 2766a8d7fc4aSZbigniew Bodek } 2767a8d7fc4aSZbigniew Bodek /* t is last descriptor here */ 2768a8d7fc4aSZbigniew Bodek DASSERT(t != NULL); 2769a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L|MVNETA_TX_CMD_PADDING; 2770a8d7fc4aSZbigniew Bodek 2771a8d7fc4aSZbigniew Bodek bus_dmamap_sync(sc->tx_dtag, tx->desc_map, 2772a8d7fc4aSZbigniew Bodek BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 2773a8d7fc4aSZbigniew Bodek 2774a8d7fc4aSZbigniew Bodek while (__predict_false(used > 255)) { 2775a8d7fc4aSZbigniew Bodek ptxsu = MVNETA_PTXSU_NOWD(255); 2776a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXSU(q), ptxsu); 2777a8d7fc4aSZbigniew Bodek used -= 255; 2778a8d7fc4aSZbigniew Bodek } 2779a8d7fc4aSZbigniew Bodek if (__predict_true(used > 0)) { 2780a8d7fc4aSZbigniew Bodek ptxsu = MVNETA_PTXSU_NOWD(used); 2781a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXSU(q), ptxsu); 2782a8d7fc4aSZbigniew Bodek } 2783a8d7fc4aSZbigniew Bodek return (0); 2784a8d7fc4aSZbigniew Bodek } 2785a8d7fc4aSZbigniew Bodek 2786a8d7fc4aSZbigniew Bodek STATIC void 2787992fa62bSJustin Hibbits mvneta_tx_set_csumflag(if_t ifp, 2788a8d7fc4aSZbigniew Bodek struct mvneta_tx_desc *t, struct mbuf *m) 2789a8d7fc4aSZbigniew Bodek { 2790a8d7fc4aSZbigniew Bodek struct ether_header *eh; 2791ea68079fSArnaud Ysmal struct ether_vlan_header *evh; 2792a8d7fc4aSZbigniew Bodek int csum_flags; 2793a8d7fc4aSZbigniew Bodek uint32_t iphl, ipoff; 2794a8d7fc4aSZbigniew Bodek struct ip *ip; 2795a8d7fc4aSZbigniew Bodek 2796a8d7fc4aSZbigniew Bodek iphl = ipoff = 0; 2797992fa62bSJustin Hibbits csum_flags = if_gethwassist(ifp) & m->m_pkthdr.csum_flags; 2798a8d7fc4aSZbigniew Bodek eh = mtod(m, struct ether_header *); 279973f20bb3SMarcin Wojtas 2800a8d7fc4aSZbigniew Bodek switch (ntohs(eh->ether_type)) { 2801a8d7fc4aSZbigniew Bodek case ETHERTYPE_IP: 2802a8d7fc4aSZbigniew Bodek ipoff = ETHER_HDR_LEN; 2803a8d7fc4aSZbigniew Bodek break; 2804a8d7fc4aSZbigniew Bodek case ETHERTYPE_VLAN: 2805a8d7fc4aSZbigniew Bodek ipoff = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 2806ea68079fSArnaud Ysmal evh = mtod(m, struct ether_vlan_header *); 2807ea68079fSArnaud Ysmal if (ntohs(evh->evl_proto) == ETHERTYPE_VLAN) 2808ea68079fSArnaud Ysmal ipoff += ETHER_VLAN_ENCAP_LEN; 2809a8d7fc4aSZbigniew Bodek break; 2810acdc9154SMarcin Wojtas default: 2811acdc9154SMarcin Wojtas csum_flags = 0; 2812a8d7fc4aSZbigniew Bodek } 2813a8d7fc4aSZbigniew Bodek 2814a8d7fc4aSZbigniew Bodek if (__predict_true(csum_flags & (CSUM_IP|CSUM_IP_TCP|CSUM_IP_UDP))) { 2815a8d7fc4aSZbigniew Bodek ip = (struct ip *)(m->m_data + ipoff); 2816a8d7fc4aSZbigniew Bodek iphl = ip->ip_hl<<2; 2817a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L3_IP4; 2818a8d7fc4aSZbigniew Bodek } else { 2819a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L4_CHECKSUM_NONE; 2820a8d7fc4aSZbigniew Bodek return; 2821a8d7fc4aSZbigniew Bodek } 2822a8d7fc4aSZbigniew Bodek 2823a8d7fc4aSZbigniew Bodek 2824a8d7fc4aSZbigniew Bodek /* L3 */ 2825a8d7fc4aSZbigniew Bodek if (csum_flags & CSUM_IP) { 2826a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_IP4_CHECKSUM; 2827a8d7fc4aSZbigniew Bodek } 2828a8d7fc4aSZbigniew Bodek 2829a8d7fc4aSZbigniew Bodek /* L4 */ 2830a8d7fc4aSZbigniew Bodek if (csum_flags & CSUM_IP_TCP) { 2831a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L4_CHECKSUM_NOFRAG; 2832a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L4_TCP; 2833a8d7fc4aSZbigniew Bodek } else if (csum_flags & CSUM_IP_UDP) { 2834a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L4_CHECKSUM_NOFRAG; 2835a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L4_UDP; 2836a8d7fc4aSZbigniew Bodek } else 2837a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L4_CHECKSUM_NONE; 2838a8d7fc4aSZbigniew Bodek 2839a8d7fc4aSZbigniew Bodek t->l4ichk = 0; 2840a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_IP_HEADER_LEN(iphl >> 2); 2841a8d7fc4aSZbigniew Bodek t->command |= MVNETA_TX_CMD_L3_OFFSET(ipoff); 2842a8d7fc4aSZbigniew Bodek } 2843a8d7fc4aSZbigniew Bodek 2844a8d7fc4aSZbigniew Bodek STATIC void 2845a8d7fc4aSZbigniew Bodek mvneta_tx_queue_complete(struct mvneta_softc *sc, int q) 2846a8d7fc4aSZbigniew Bodek { 2847a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 2848a8d7fc4aSZbigniew Bodek struct mvneta_buf *txbuf; 2849fcd0ea3aSJohn Baldwin struct mvneta_tx_desc *t __diagused; 2850a8d7fc4aSZbigniew Bodek uint32_t ptxs, ptxsu, ndesc; 2851a8d7fc4aSZbigniew Bodek int i; 2852a8d7fc4aSZbigniew Bodek 2853a8d7fc4aSZbigniew Bodek KASSERT_TX_MTX(sc, q); 2854a8d7fc4aSZbigniew Bodek 2855a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 2856a8d7fc4aSZbigniew Bodek if (__predict_false(tx->queue_status == MVNETA_QUEUE_DISABLED)) 2857a8d7fc4aSZbigniew Bodek return; 2858a8d7fc4aSZbigniew Bodek 2859a8d7fc4aSZbigniew Bodek ptxs = MVNETA_READ(sc, MVNETA_PTXS(q)); 2860a8d7fc4aSZbigniew Bodek ndesc = MVNETA_PTXS_GET_TBC(ptxs); 2861a8d7fc4aSZbigniew Bodek 2862a8d7fc4aSZbigniew Bodek if (__predict_false(ndesc == 0)) { 2863a8d7fc4aSZbigniew Bodek if (tx->used == 0) 2864a8d7fc4aSZbigniew Bodek tx->queue_status = MVNETA_QUEUE_IDLE; 2865a8d7fc4aSZbigniew Bodek else if (tx->queue_status == MVNETA_QUEUE_WORKING && 2866a8d7fc4aSZbigniew Bodek ((ticks - tx->watchdog_time) > MVNETA_WATCHDOG)) 2867a8d7fc4aSZbigniew Bodek tx->queue_hung = TRUE; 2868a8d7fc4aSZbigniew Bodek return; 2869a8d7fc4aSZbigniew Bodek } 2870a8d7fc4aSZbigniew Bodek 2871a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 2872a8d7fc4aSZbigniew Bodek CTR3(KTR_SPARE2, "%s:%u tx_complete begin ndesc=%u", 2873992fa62bSJustin Hibbits if_name(sc->ifp), q, ndesc); 2874a8d7fc4aSZbigniew Bodek #endif 2875a8d7fc4aSZbigniew Bodek 2876a8d7fc4aSZbigniew Bodek bus_dmamap_sync(sc->tx_dtag, tx->desc_map, 2877a8d7fc4aSZbigniew Bodek BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 2878a8d7fc4aSZbigniew Bodek 2879a8d7fc4aSZbigniew Bodek for (i = 0; i < ndesc; i++) { 2880a8d7fc4aSZbigniew Bodek t = &tx->desc[tx->dma]; 2881a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 2882a8d7fc4aSZbigniew Bodek if (t->flags & MVNETA_TX_F_ES) 2883a8d7fc4aSZbigniew Bodek CTR3(KTR_SPARE2, "%s tx error queue %d desc %d", 2884992fa62bSJustin Hibbits if_name(sc->ifp), q, tx->dma); 2885a8d7fc4aSZbigniew Bodek #endif 2886a8d7fc4aSZbigniew Bodek txbuf = &tx->txbuf[tx->dma]; 2887a8d7fc4aSZbigniew Bodek if (__predict_true(txbuf->m != NULL)) { 2888a8d7fc4aSZbigniew Bodek DASSERT((t->command & MVNETA_TX_CMD_F) != 0); 2889a8d7fc4aSZbigniew Bodek bus_dmamap_unload(sc->txmbuf_dtag, txbuf->dmap); 2890a8d7fc4aSZbigniew Bodek m_freem(txbuf->m); 2891a8d7fc4aSZbigniew Bodek txbuf->m = NULL; 2892a8d7fc4aSZbigniew Bodek } 2893a8d7fc4aSZbigniew Bodek else 2894a8d7fc4aSZbigniew Bodek DASSERT((t->flags & MVNETA_TX_CMD_F) == 0); 2895a8d7fc4aSZbigniew Bodek tx->dma = tx_counter_adv(tx->dma, 1); 2896a8d7fc4aSZbigniew Bodek tx->used--; 2897a8d7fc4aSZbigniew Bodek } 2898a8d7fc4aSZbigniew Bodek DASSERT(tx->used >= 0); 2899a8d7fc4aSZbigniew Bodek DASSERT(tx->used <= MVNETA_TX_RING_CNT); 2900a8d7fc4aSZbigniew Bodek while (__predict_false(ndesc > 255)) { 2901a8d7fc4aSZbigniew Bodek ptxsu = MVNETA_PTXSU_NORB(255); 2902a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXSU(q), ptxsu); 2903a8d7fc4aSZbigniew Bodek ndesc -= 255; 2904a8d7fc4aSZbigniew Bodek } 2905a8d7fc4aSZbigniew Bodek if (__predict_true(ndesc > 0)) { 2906a8d7fc4aSZbigniew Bodek ptxsu = MVNETA_PTXSU_NORB(ndesc); 2907a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PTXSU(q), ptxsu); 2908a8d7fc4aSZbigniew Bodek } 2909a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 2910a8d7fc4aSZbigniew Bodek CTR5(KTR_SPARE2, "%s:%u tx_complete tx_cpu=%d tx_dma=%d tx_used=%d", 2911992fa62bSJustin Hibbits if_name(sc->ifp), q, tx->cpu, tx->dma, tx->used); 2912a8d7fc4aSZbigniew Bodek #endif 2913a8d7fc4aSZbigniew Bodek 2914a8d7fc4aSZbigniew Bodek tx->watchdog_time = ticks; 2915a8d7fc4aSZbigniew Bodek 2916a8d7fc4aSZbigniew Bodek if (tx->used == 0) 2917a8d7fc4aSZbigniew Bodek tx->queue_status = MVNETA_QUEUE_IDLE; 2918a8d7fc4aSZbigniew Bodek } 2919a8d7fc4aSZbigniew Bodek 2920a8d7fc4aSZbigniew Bodek /* 2921a8d7fc4aSZbigniew Bodek * Do a final TX complete when TX is idle. 2922a8d7fc4aSZbigniew Bodek */ 2923a8d7fc4aSZbigniew Bodek STATIC void 2924a8d7fc4aSZbigniew Bodek mvneta_tx_drain(struct mvneta_softc *sc) 2925a8d7fc4aSZbigniew Bodek { 2926a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 2927a8d7fc4aSZbigniew Bodek int q; 2928a8d7fc4aSZbigniew Bodek 2929a8d7fc4aSZbigniew Bodek /* 2930a8d7fc4aSZbigniew Bodek * Handle trailing mbuf on TX queue. 2931a8d7fc4aSZbigniew Bodek * Check is done lockess to avoid TX path contention. 2932a8d7fc4aSZbigniew Bodek */ 2933a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_TX_QNUM_MAX; q++) { 2934a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, q); 2935a8d7fc4aSZbigniew Bodek if ((ticks - tx->watchdog_time) > MVNETA_WATCHDOG_TXCOMP && 2936a8d7fc4aSZbigniew Bodek tx->used > 0) { 2937a8d7fc4aSZbigniew Bodek mvneta_tx_lockq(sc, q); 2938a8d7fc4aSZbigniew Bodek mvneta_tx_queue_complete(sc, q); 2939a8d7fc4aSZbigniew Bodek mvneta_tx_unlockq(sc, q); 2940a8d7fc4aSZbigniew Bodek } 2941a8d7fc4aSZbigniew Bodek } 2942a8d7fc4aSZbigniew Bodek } 2943a8d7fc4aSZbigniew Bodek 2944a8d7fc4aSZbigniew Bodek /* 2945a8d7fc4aSZbigniew Bodek * Rx Subroutines 2946a8d7fc4aSZbigniew Bodek */ 2947a8d7fc4aSZbigniew Bodek STATIC int 2948a8d7fc4aSZbigniew Bodek mvneta_rx(struct mvneta_softc *sc, int q, int count) 2949a8d7fc4aSZbigniew Bodek { 2950a8d7fc4aSZbigniew Bodek uint32_t prxs, npkt; 2951a8d7fc4aSZbigniew Bodek int more; 2952a8d7fc4aSZbigniew Bodek 2953a8d7fc4aSZbigniew Bodek more = 0; 2954a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 2955a8d7fc4aSZbigniew Bodek prxs = MVNETA_READ(sc, MVNETA_PRXS(q)); 2956a8d7fc4aSZbigniew Bodek npkt = MVNETA_PRXS_GET_ODC(prxs); 2957a8d7fc4aSZbigniew Bodek if (__predict_false(npkt == 0)) 2958a8d7fc4aSZbigniew Bodek goto out; 2959a8d7fc4aSZbigniew Bodek 2960a8d7fc4aSZbigniew Bodek if (count > 0 && npkt > count) { 2961a8d7fc4aSZbigniew Bodek more = 1; 2962a8d7fc4aSZbigniew Bodek npkt = count; 2963a8d7fc4aSZbigniew Bodek } 2964a8d7fc4aSZbigniew Bodek mvneta_rx_queue(sc, q, npkt); 2965a8d7fc4aSZbigniew Bodek out: 2966a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 2967a8d7fc4aSZbigniew Bodek return more; 2968a8d7fc4aSZbigniew Bodek } 2969a8d7fc4aSZbigniew Bodek 2970a8d7fc4aSZbigniew Bodek /* 2971a8d7fc4aSZbigniew Bodek * Helper routine for updating PRXSU register of a given queue. 2972a8d7fc4aSZbigniew Bodek * Handles number of processed descriptors bigger than maximum acceptable value. 2973a8d7fc4aSZbigniew Bodek */ 2974a8d7fc4aSZbigniew Bodek STATIC __inline void 2975a8d7fc4aSZbigniew Bodek mvneta_prxsu_update(struct mvneta_softc *sc, int q, int processed) 2976a8d7fc4aSZbigniew Bodek { 2977a8d7fc4aSZbigniew Bodek uint32_t prxsu; 2978a8d7fc4aSZbigniew Bodek 2979a8d7fc4aSZbigniew Bodek while (__predict_false(processed > 255)) { 2980a8d7fc4aSZbigniew Bodek prxsu = MVNETA_PRXSU_NOOFPROCESSEDDESCRIPTORS(255); 2981a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXSU(q), prxsu); 2982a8d7fc4aSZbigniew Bodek processed -= 255; 2983a8d7fc4aSZbigniew Bodek } 2984a8d7fc4aSZbigniew Bodek prxsu = MVNETA_PRXSU_NOOFPROCESSEDDESCRIPTORS(processed); 2985a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXSU(q), prxsu); 2986a8d7fc4aSZbigniew Bodek } 2987a8d7fc4aSZbigniew Bodek 2988a8d7fc4aSZbigniew Bodek static __inline void 2989a8d7fc4aSZbigniew Bodek mvneta_prefetch(void *p) 2990a8d7fc4aSZbigniew Bodek { 2991a8d7fc4aSZbigniew Bodek 2992a8d7fc4aSZbigniew Bodek __builtin_prefetch(p); 2993a8d7fc4aSZbigniew Bodek } 2994a8d7fc4aSZbigniew Bodek 2995a8d7fc4aSZbigniew Bodek STATIC void 2996a8d7fc4aSZbigniew Bodek mvneta_rx_queue(struct mvneta_softc *sc, int q, int npkt) 2997a8d7fc4aSZbigniew Bodek { 2998992fa62bSJustin Hibbits if_t ifp; 2999a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 3000a8d7fc4aSZbigniew Bodek struct mvneta_rx_desc *r; 3001a8d7fc4aSZbigniew Bodek struct mvneta_buf *rxbuf; 3002a8d7fc4aSZbigniew Bodek struct mbuf *m; 3003a8d7fc4aSZbigniew Bodek void *pktbuf; 3004a8d7fc4aSZbigniew Bodek int i, pktlen, processed, ndma; 3005a8d7fc4aSZbigniew Bodek 3006a8d7fc4aSZbigniew Bodek KASSERT_RX_MTX(sc, q); 3007a8d7fc4aSZbigniew Bodek 3008a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 3009a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 3010a8d7fc4aSZbigniew Bodek processed = 0; 3011a8d7fc4aSZbigniew Bodek 3012a8d7fc4aSZbigniew Bodek if (__predict_false(rx->queue_status == MVNETA_QUEUE_DISABLED)) 3013a8d7fc4aSZbigniew Bodek return; 3014a8d7fc4aSZbigniew Bodek 3015a8d7fc4aSZbigniew Bodek bus_dmamap_sync(sc->rx_dtag, rx->desc_map, 3016a8d7fc4aSZbigniew Bodek BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 3017a8d7fc4aSZbigniew Bodek 3018a8d7fc4aSZbigniew Bodek for (i = 0; i < npkt; i++) { 3019a8d7fc4aSZbigniew Bodek /* Prefetch next desc, rxbuf. */ 3020a8d7fc4aSZbigniew Bodek ndma = rx_counter_adv(rx->dma, 1); 3021a8d7fc4aSZbigniew Bodek mvneta_prefetch(&rx->desc[ndma]); 3022a8d7fc4aSZbigniew Bodek mvneta_prefetch(&rx->rxbuf[ndma]); 3023a8d7fc4aSZbigniew Bodek 3024a8d7fc4aSZbigniew Bodek /* get descriptor and packet */ 3025a8d7fc4aSZbigniew Bodek r = &rx->desc[rx->dma]; 3026a8d7fc4aSZbigniew Bodek rxbuf = &rx->rxbuf[rx->dma]; 3027a8d7fc4aSZbigniew Bodek m = rxbuf->m; 3028a8d7fc4aSZbigniew Bodek rxbuf->m = NULL; 3029a8d7fc4aSZbigniew Bodek DASSERT(m != NULL); 3030a8d7fc4aSZbigniew Bodek bus_dmamap_sync(sc->rxbuf_dtag, rxbuf->dmap, 3031a8d7fc4aSZbigniew Bodek BUS_DMASYNC_POSTREAD); 3032a8d7fc4aSZbigniew Bodek bus_dmamap_unload(sc->rxbuf_dtag, rxbuf->dmap); 3033a8d7fc4aSZbigniew Bodek /* Prefetch mbuf header. */ 3034a8d7fc4aSZbigniew Bodek mvneta_prefetch(m); 3035a8d7fc4aSZbigniew Bodek 3036a8d7fc4aSZbigniew Bodek processed++; 3037a8d7fc4aSZbigniew Bodek /* Drop desc with error status or not in a single buffer. */ 3038a8d7fc4aSZbigniew Bodek DASSERT((r->status & (MVNETA_RX_F|MVNETA_RX_L)) == 3039a8d7fc4aSZbigniew Bodek (MVNETA_RX_F|MVNETA_RX_L)); 3040a8d7fc4aSZbigniew Bodek if (__predict_false((r->status & MVNETA_RX_ES) || 3041a8d7fc4aSZbigniew Bodek (r->status & (MVNETA_RX_F|MVNETA_RX_L)) != 3042a8d7fc4aSZbigniew Bodek (MVNETA_RX_F|MVNETA_RX_L))) 3043a8d7fc4aSZbigniew Bodek goto rx_error; 3044a8d7fc4aSZbigniew Bodek 3045a8d7fc4aSZbigniew Bodek /* 3046a8d7fc4aSZbigniew Bodek * [ OFF | MH | PKT | CRC ] 3047a8d7fc4aSZbigniew Bodek * bytecnt cover MH, PKT, CRC 3048a8d7fc4aSZbigniew Bodek */ 3049a8d7fc4aSZbigniew Bodek pktlen = r->bytecnt - ETHER_CRC_LEN - MVNETA_HWHEADER_SIZE; 3050e7843f1dSMarcin Wojtas pktbuf = (uint8_t *)rx->rxbuf_virt_addr[rx->dma] + MVNETA_PACKET_OFFSET + 3051a8d7fc4aSZbigniew Bodek MVNETA_HWHEADER_SIZE; 3052a8d7fc4aSZbigniew Bodek 3053a8d7fc4aSZbigniew Bodek /* Prefetch mbuf data. */ 3054a8d7fc4aSZbigniew Bodek mvneta_prefetch(pktbuf); 3055a8d7fc4aSZbigniew Bodek 3056a8d7fc4aSZbigniew Bodek /* Write value to mbuf (avoid read). */ 3057a8d7fc4aSZbigniew Bodek m->m_data = pktbuf; 3058a8d7fc4aSZbigniew Bodek m->m_len = m->m_pkthdr.len = pktlen; 3059a8d7fc4aSZbigniew Bodek m->m_pkthdr.rcvif = ifp; 3060a8d7fc4aSZbigniew Bodek mvneta_rx_set_csumflag(ifp, r, m); 3061a8d7fc4aSZbigniew Bodek 3062a8d7fc4aSZbigniew Bodek /* Increase rx_dma before releasing the lock. */ 3063a8d7fc4aSZbigniew Bodek rx->dma = ndma; 3064a8d7fc4aSZbigniew Bodek 3065a8d7fc4aSZbigniew Bodek if (__predict_false(rx->lro_enabled && 3066a8d7fc4aSZbigniew Bodek ((r->status & MVNETA_RX_L3_IP) != 0) && 3067a8d7fc4aSZbigniew Bodek ((r->status & MVNETA_RX_L4_MASK) == MVNETA_RX_L4_TCP) && 3068a8d7fc4aSZbigniew Bodek (m->m_pkthdr.csum_flags & 3069a8d7fc4aSZbigniew Bodek (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == 3070a8d7fc4aSZbigniew Bodek (CSUM_DATA_VALID | CSUM_PSEUDO_HDR))) { 3071a8d7fc4aSZbigniew Bodek if (rx->lro.lro_cnt != 0) { 3072a8d7fc4aSZbigniew Bodek if (tcp_lro_rx(&rx->lro, m, 0) == 0) 3073a8d7fc4aSZbigniew Bodek goto rx_done; 3074a8d7fc4aSZbigniew Bodek } 3075a8d7fc4aSZbigniew Bodek } 3076a8d7fc4aSZbigniew Bodek 3077a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, q); 3078992fa62bSJustin Hibbits if_input(ifp, m); 3079a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, q); 3080a8d7fc4aSZbigniew Bodek /* 3081a8d7fc4aSZbigniew Bodek * Check whether this queue has been disabled in the 3082a8d7fc4aSZbigniew Bodek * meantime. If yes, then clear LRO and exit. 3083a8d7fc4aSZbigniew Bodek */ 3084a8d7fc4aSZbigniew Bodek if(__predict_false(rx->queue_status == MVNETA_QUEUE_DISABLED)) 3085a8d7fc4aSZbigniew Bodek goto rx_lro; 3086a8d7fc4aSZbigniew Bodek rx_done: 3087a8d7fc4aSZbigniew Bodek /* Refresh receive ring to avoid stall and minimize jitter. */ 3088a8d7fc4aSZbigniew Bodek if (processed >= MVNETA_RX_REFILL_COUNT) { 3089a8d7fc4aSZbigniew Bodek mvneta_prxsu_update(sc, q, processed); 3090a8d7fc4aSZbigniew Bodek mvneta_rx_queue_refill(sc, q); 3091a8d7fc4aSZbigniew Bodek processed = 0; 3092a8d7fc4aSZbigniew Bodek } 3093a8d7fc4aSZbigniew Bodek continue; 3094a8d7fc4aSZbigniew Bodek rx_error: 3095a8d7fc4aSZbigniew Bodek m_freem(m); 3096a8d7fc4aSZbigniew Bodek rx->dma = ndma; 3097a8d7fc4aSZbigniew Bodek /* Refresh receive ring to avoid stall and minimize jitter. */ 3098a8d7fc4aSZbigniew Bodek if (processed >= MVNETA_RX_REFILL_COUNT) { 3099a8d7fc4aSZbigniew Bodek mvneta_prxsu_update(sc, q, processed); 3100a8d7fc4aSZbigniew Bodek mvneta_rx_queue_refill(sc, q); 3101a8d7fc4aSZbigniew Bodek processed = 0; 3102a8d7fc4aSZbigniew Bodek } 3103a8d7fc4aSZbigniew Bodek } 3104a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 3105992fa62bSJustin Hibbits CTR3(KTR_SPARE2, "%s:%u %u packets received", if_name(ifp), q, npkt); 3106a8d7fc4aSZbigniew Bodek #endif 3107a8d7fc4aSZbigniew Bodek /* DMA status update */ 3108a8d7fc4aSZbigniew Bodek mvneta_prxsu_update(sc, q, processed); 3109a8d7fc4aSZbigniew Bodek /* Refill the rest of buffers if there are any to refill */ 3110a8d7fc4aSZbigniew Bodek mvneta_rx_queue_refill(sc, q); 3111a8d7fc4aSZbigniew Bodek 3112a8d7fc4aSZbigniew Bodek rx_lro: 3113a8d7fc4aSZbigniew Bodek /* 3114a8d7fc4aSZbigniew Bodek * Flush any outstanding LRO work 3115a8d7fc4aSZbigniew Bodek */ 31165203dcceSMichael Tuexen tcp_lro_flush_all(&rx->lro); 3117a8d7fc4aSZbigniew Bodek } 3118a8d7fc4aSZbigniew Bodek 3119a8d7fc4aSZbigniew Bodek STATIC void 3120a8d7fc4aSZbigniew Bodek mvneta_rx_buf_free(struct mvneta_softc *sc, struct mvneta_buf *rxbuf) 3121a8d7fc4aSZbigniew Bodek { 3122a8d7fc4aSZbigniew Bodek 3123a8d7fc4aSZbigniew Bodek bus_dmamap_unload(sc->rxbuf_dtag, rxbuf->dmap); 3124a8d7fc4aSZbigniew Bodek /* This will remove all data at once */ 3125a8d7fc4aSZbigniew Bodek m_freem(rxbuf->m); 3126a8d7fc4aSZbigniew Bodek } 3127a8d7fc4aSZbigniew Bodek 3128a8d7fc4aSZbigniew Bodek STATIC void 3129a8d7fc4aSZbigniew Bodek mvneta_rx_queue_refill(struct mvneta_softc *sc, int q) 3130a8d7fc4aSZbigniew Bodek { 3131a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 3132a8d7fc4aSZbigniew Bodek struct mvneta_rx_desc *r; 3133a8d7fc4aSZbigniew Bodek struct mvneta_buf *rxbuf; 3134a8d7fc4aSZbigniew Bodek bus_dma_segment_t segs; 3135a8d7fc4aSZbigniew Bodek struct mbuf *m; 3136a8d7fc4aSZbigniew Bodek uint32_t prxs, prxsu, ndesc; 3137a8d7fc4aSZbigniew Bodek int npkt, refill, nsegs, error; 3138a8d7fc4aSZbigniew Bodek 3139a8d7fc4aSZbigniew Bodek KASSERT_RX_MTX(sc, q); 3140a8d7fc4aSZbigniew Bodek 3141a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, q); 3142a8d7fc4aSZbigniew Bodek prxs = MVNETA_READ(sc, MVNETA_PRXS(q)); 3143a8d7fc4aSZbigniew Bodek ndesc = MVNETA_PRXS_GET_NODC(prxs) + MVNETA_PRXS_GET_ODC(prxs); 3144a8d7fc4aSZbigniew Bodek refill = MVNETA_RX_RING_CNT - ndesc; 3145a8d7fc4aSZbigniew Bodek #ifdef MVNETA_KTR 3146992fa62bSJustin Hibbits CTR3(KTR_SPARE2, "%s:%u refill %u packets", if_name(sc->ifp), q, 3147a8d7fc4aSZbigniew Bodek refill); 3148a8d7fc4aSZbigniew Bodek #endif 3149a8d7fc4aSZbigniew Bodek if (__predict_false(refill <= 0)) 3150a8d7fc4aSZbigniew Bodek return; 3151a8d7fc4aSZbigniew Bodek 3152a8d7fc4aSZbigniew Bodek for (npkt = 0; npkt < refill; npkt++) { 3153a8d7fc4aSZbigniew Bodek rxbuf = &rx->rxbuf[rx->cpu]; 315473f20bb3SMarcin Wojtas m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, sc->rx_frame_size); 3155a8d7fc4aSZbigniew Bodek if (__predict_false(m == NULL)) { 3156a8d7fc4aSZbigniew Bodek error = ENOBUFS; 3157a8d7fc4aSZbigniew Bodek break; 3158a8d7fc4aSZbigniew Bodek } 3159a8d7fc4aSZbigniew Bodek m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; 3160a8d7fc4aSZbigniew Bodek 3161a8d7fc4aSZbigniew Bodek error = bus_dmamap_load_mbuf_sg(sc->rxbuf_dtag, rxbuf->dmap, 3162a8d7fc4aSZbigniew Bodek m, &segs, &nsegs, BUS_DMA_NOWAIT); 3163a8d7fc4aSZbigniew Bodek if (__predict_false(error != 0 || nsegs != 1)) { 3164a8d7fc4aSZbigniew Bodek KASSERT(1, ("Failed to load Rx mbuf DMA map")); 3165a8d7fc4aSZbigniew Bodek m_freem(m); 3166a8d7fc4aSZbigniew Bodek break; 3167a8d7fc4aSZbigniew Bodek } 3168a8d7fc4aSZbigniew Bodek 3169a8d7fc4aSZbigniew Bodek /* Add the packet to the ring */ 3170a8d7fc4aSZbigniew Bodek rxbuf->m = m; 3171a8d7fc4aSZbigniew Bodek r = &rx->desc[rx->cpu]; 3172a8d7fc4aSZbigniew Bodek r->bufptr_pa = segs.ds_addr; 3173e7843f1dSMarcin Wojtas rx->rxbuf_virt_addr[rx->cpu] = m->m_data; 3174a8d7fc4aSZbigniew Bodek 3175a8d7fc4aSZbigniew Bodek rx->cpu = rx_counter_adv(rx->cpu, 1); 3176a8d7fc4aSZbigniew Bodek } 3177a8d7fc4aSZbigniew Bodek if (npkt == 0) { 3178a8d7fc4aSZbigniew Bodek if (refill == MVNETA_RX_RING_CNT) 3179a8d7fc4aSZbigniew Bodek rx->needs_refill = TRUE; 3180a8d7fc4aSZbigniew Bodek return; 3181a8d7fc4aSZbigniew Bodek } 3182a8d7fc4aSZbigniew Bodek 3183a8d7fc4aSZbigniew Bodek rx->needs_refill = FALSE; 3184a8d7fc4aSZbigniew Bodek bus_dmamap_sync(sc->rx_dtag, rx->desc_map, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 3185a8d7fc4aSZbigniew Bodek 3186a8d7fc4aSZbigniew Bodek while (__predict_false(npkt > 255)) { 3187a8d7fc4aSZbigniew Bodek prxsu = MVNETA_PRXSU_NOOFNEWDESCRIPTORS(255); 3188a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXSU(q), prxsu); 3189a8d7fc4aSZbigniew Bodek npkt -= 255; 3190a8d7fc4aSZbigniew Bodek } 3191a8d7fc4aSZbigniew Bodek if (__predict_true(npkt > 0)) { 3192a8d7fc4aSZbigniew Bodek prxsu = MVNETA_PRXSU_NOOFNEWDESCRIPTORS(npkt); 3193a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXSU(q), prxsu); 3194a8d7fc4aSZbigniew Bodek } 3195a8d7fc4aSZbigniew Bodek } 3196a8d7fc4aSZbigniew Bodek 3197a8d7fc4aSZbigniew Bodek STATIC __inline void 3198992fa62bSJustin Hibbits mvneta_rx_set_csumflag(if_t ifp, 3199a8d7fc4aSZbigniew Bodek struct mvneta_rx_desc *r, struct mbuf *m) 3200a8d7fc4aSZbigniew Bodek { 3201a8d7fc4aSZbigniew Bodek uint32_t csum_flags; 3202a8d7fc4aSZbigniew Bodek 3203a8d7fc4aSZbigniew Bodek csum_flags = 0; 3204a8d7fc4aSZbigniew Bodek if (__predict_false((r->status & 3205a8d7fc4aSZbigniew Bodek (MVNETA_RX_IP_HEADER_OK|MVNETA_RX_L3_IP)) == 0)) 3206a8d7fc4aSZbigniew Bodek return; /* not a IP packet */ 3207a8d7fc4aSZbigniew Bodek 3208a8d7fc4aSZbigniew Bodek /* L3 */ 3209a8d7fc4aSZbigniew Bodek if (__predict_true((r->status & MVNETA_RX_IP_HEADER_OK) == 3210a8d7fc4aSZbigniew Bodek MVNETA_RX_IP_HEADER_OK)) 3211a8d7fc4aSZbigniew Bodek csum_flags |= CSUM_L3_CALC|CSUM_L3_VALID; 3212a8d7fc4aSZbigniew Bodek 3213a8d7fc4aSZbigniew Bodek if (__predict_true((r->status & (MVNETA_RX_IP_HEADER_OK|MVNETA_RX_L3_IP)) == 3214a8d7fc4aSZbigniew Bodek (MVNETA_RX_IP_HEADER_OK|MVNETA_RX_L3_IP))) { 3215a8d7fc4aSZbigniew Bodek /* L4 */ 3216a8d7fc4aSZbigniew Bodek switch (r->status & MVNETA_RX_L4_MASK) { 3217a8d7fc4aSZbigniew Bodek case MVNETA_RX_L4_TCP: 3218a8d7fc4aSZbigniew Bodek case MVNETA_RX_L4_UDP: 3219a8d7fc4aSZbigniew Bodek csum_flags |= CSUM_L4_CALC; 3220a8d7fc4aSZbigniew Bodek if (__predict_true((r->status & 3221a8d7fc4aSZbigniew Bodek MVNETA_RX_L4_CHECKSUM_OK) == MVNETA_RX_L4_CHECKSUM_OK)) { 3222a8d7fc4aSZbigniew Bodek csum_flags |= CSUM_L4_VALID; 3223a8d7fc4aSZbigniew Bodek m->m_pkthdr.csum_data = htons(0xffff); 3224a8d7fc4aSZbigniew Bodek } 3225a8d7fc4aSZbigniew Bodek break; 3226a8d7fc4aSZbigniew Bodek case MVNETA_RX_L4_OTH: 3227a8d7fc4aSZbigniew Bodek default: 3228a8d7fc4aSZbigniew Bodek break; 3229a8d7fc4aSZbigniew Bodek } 3230a8d7fc4aSZbigniew Bodek } 3231a8d7fc4aSZbigniew Bodek m->m_pkthdr.csum_flags = csum_flags; 3232a8d7fc4aSZbigniew Bodek } 3233a8d7fc4aSZbigniew Bodek 3234a8d7fc4aSZbigniew Bodek /* 3235a8d7fc4aSZbigniew Bodek * MAC address filter 3236a8d7fc4aSZbigniew Bodek */ 3237a8d7fc4aSZbigniew Bodek STATIC void 3238a8d7fc4aSZbigniew Bodek mvneta_filter_setup(struct mvneta_softc *sc) 3239a8d7fc4aSZbigniew Bodek { 3240992fa62bSJustin Hibbits if_t ifp; 3241a8d7fc4aSZbigniew Bodek uint32_t dfut[MVNETA_NDFUT], dfsmt[MVNETA_NDFSMT], dfomt[MVNETA_NDFOMT]; 3242a8d7fc4aSZbigniew Bodek uint32_t pxc; 3243a8d7fc4aSZbigniew Bodek int i; 3244a8d7fc4aSZbigniew Bodek 3245a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 3246a8d7fc4aSZbigniew Bodek 3247a8d7fc4aSZbigniew Bodek memset(dfut, 0, sizeof(dfut)); 3248a8d7fc4aSZbigniew Bodek memset(dfsmt, 0, sizeof(dfsmt)); 3249a8d7fc4aSZbigniew Bodek memset(dfomt, 0, sizeof(dfomt)); 3250a8d7fc4aSZbigniew Bodek 3251a8d7fc4aSZbigniew Bodek ifp = sc->ifp; 3252992fa62bSJustin Hibbits if_setflagbits(ifp, IFF_ALLMULTI, 0); 3253992fa62bSJustin Hibbits if (if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) { 3254a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_NDFSMT; i++) { 3255a8d7fc4aSZbigniew Bodek dfsmt[i] = dfomt[i] = 3256a8d7fc4aSZbigniew Bodek MVNETA_DF(0, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS) | 3257a8d7fc4aSZbigniew Bodek MVNETA_DF(1, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS) | 3258a8d7fc4aSZbigniew Bodek MVNETA_DF(2, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS) | 3259a8d7fc4aSZbigniew Bodek MVNETA_DF(3, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS); 3260a8d7fc4aSZbigniew Bodek } 3261a8d7fc4aSZbigniew Bodek } 3262a8d7fc4aSZbigniew Bodek 3263a8d7fc4aSZbigniew Bodek pxc = MVNETA_READ(sc, MVNETA_PXC); 3264a8d7fc4aSZbigniew Bodek pxc &= ~(MVNETA_PXC_UPM | MVNETA_PXC_RXQ_MASK | MVNETA_PXC_RXQARP_MASK | 3265a8d7fc4aSZbigniew Bodek MVNETA_PXC_TCPQ_MASK | MVNETA_PXC_UDPQ_MASK | MVNETA_PXC_BPDUQ_MASK); 3266a8d7fc4aSZbigniew Bodek pxc |= MVNETA_PXC_RXQ(MVNETA_RX_QNUM_MAX-1); 3267a8d7fc4aSZbigniew Bodek pxc |= MVNETA_PXC_RXQARP(MVNETA_RX_QNUM_MAX-1); 3268a8d7fc4aSZbigniew Bodek pxc |= MVNETA_PXC_TCPQ(MVNETA_RX_QNUM_MAX-1); 3269a8d7fc4aSZbigniew Bodek pxc |= MVNETA_PXC_UDPQ(MVNETA_RX_QNUM_MAX-1); 3270a8d7fc4aSZbigniew Bodek pxc |= MVNETA_PXC_BPDUQ(MVNETA_RX_QNUM_MAX-1); 3271a8d7fc4aSZbigniew Bodek pxc |= MVNETA_PXC_RB | MVNETA_PXC_RBIP | MVNETA_PXC_RBARP; 3272992fa62bSJustin Hibbits if (if_getflags(ifp) & IFF_BROADCAST) { 3273a8d7fc4aSZbigniew Bodek pxc &= ~(MVNETA_PXC_RB | MVNETA_PXC_RBIP | MVNETA_PXC_RBARP); 3274a8d7fc4aSZbigniew Bodek } 3275992fa62bSJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC) { 3276a8d7fc4aSZbigniew Bodek pxc |= MVNETA_PXC_UPM; 3277a8d7fc4aSZbigniew Bodek } 3278a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PXC, pxc); 3279a8d7fc4aSZbigniew Bodek 3280a8d7fc4aSZbigniew Bodek /* Set Destination Address Filter Unicast Table */ 3281992fa62bSJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC) { 3282a8d7fc4aSZbigniew Bodek /* pass all unicast addresses */ 3283a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_NDFUT; i++) { 3284a8d7fc4aSZbigniew Bodek dfut[i] = 3285a8d7fc4aSZbigniew Bodek MVNETA_DF(0, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS) | 3286a8d7fc4aSZbigniew Bodek MVNETA_DF(1, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS) | 3287a8d7fc4aSZbigniew Bodek MVNETA_DF(2, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS) | 3288a8d7fc4aSZbigniew Bodek MVNETA_DF(3, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS); 3289a8d7fc4aSZbigniew Bodek } 3290a8d7fc4aSZbigniew Bodek } else { 3291a8d7fc4aSZbigniew Bodek i = sc->enaddr[5] & 0xf; /* last nibble */ 3292a8d7fc4aSZbigniew Bodek dfut[i>>2] = MVNETA_DF(i&3, MVNETA_DF_QUEUE(0) | MVNETA_DF_PASS); 3293a8d7fc4aSZbigniew Bodek } 3294a8d7fc4aSZbigniew Bodek MVNETA_WRITE_REGION(sc, MVNETA_DFUT(0), dfut, MVNETA_NDFUT); 3295a8d7fc4aSZbigniew Bodek 3296a8d7fc4aSZbigniew Bodek /* Set Destination Address Filter Multicast Tables */ 3297a8d7fc4aSZbigniew Bodek MVNETA_WRITE_REGION(sc, MVNETA_DFSMT(0), dfsmt, MVNETA_NDFSMT); 3298a8d7fc4aSZbigniew Bodek MVNETA_WRITE_REGION(sc, MVNETA_DFOMT(0), dfomt, MVNETA_NDFOMT); 3299a8d7fc4aSZbigniew Bodek } 3300a8d7fc4aSZbigniew Bodek 3301a8d7fc4aSZbigniew Bodek /* 3302a8d7fc4aSZbigniew Bodek * sysctl(9) 3303a8d7fc4aSZbigniew Bodek */ 3304a8d7fc4aSZbigniew Bodek STATIC int 3305a8d7fc4aSZbigniew Bodek sysctl_read_mib(SYSCTL_HANDLER_ARGS) 3306a8d7fc4aSZbigniew Bodek { 3307a8d7fc4aSZbigniew Bodek struct mvneta_sysctl_mib *arg; 3308a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 3309a8d7fc4aSZbigniew Bodek uint64_t val; 3310a8d7fc4aSZbigniew Bodek 3311a8d7fc4aSZbigniew Bodek arg = (struct mvneta_sysctl_mib *)arg1; 3312a8d7fc4aSZbigniew Bodek if (arg == NULL) 3313a8d7fc4aSZbigniew Bodek return (EINVAL); 3314a8d7fc4aSZbigniew Bodek 3315a8d7fc4aSZbigniew Bodek sc = arg->sc; 3316a8d7fc4aSZbigniew Bodek if (sc == NULL) 3317a8d7fc4aSZbigniew Bodek return (EINVAL); 3318a8d7fc4aSZbigniew Bodek if (arg->index < 0 || arg->index > MVNETA_PORTMIB_NOCOUNTER) 3319a8d7fc4aSZbigniew Bodek return (EINVAL); 3320a8d7fc4aSZbigniew Bodek 3321a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 3322a8d7fc4aSZbigniew Bodek val = arg->counter; 3323a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 3324a8d7fc4aSZbigniew Bodek return sysctl_handle_64(oidp, &val, 0, req); 3325a8d7fc4aSZbigniew Bodek } 3326a8d7fc4aSZbigniew Bodek 3327a8d7fc4aSZbigniew Bodek 3328a8d7fc4aSZbigniew Bodek STATIC int 3329a8d7fc4aSZbigniew Bodek sysctl_clear_mib(SYSCTL_HANDLER_ARGS) 3330a8d7fc4aSZbigniew Bodek { 3331a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 3332a8d7fc4aSZbigniew Bodek int err, val; 3333a8d7fc4aSZbigniew Bodek 3334a8d7fc4aSZbigniew Bodek val = 0; 3335a8d7fc4aSZbigniew Bodek sc = (struct mvneta_softc *)arg1; 3336a8d7fc4aSZbigniew Bodek if (sc == NULL) 3337a8d7fc4aSZbigniew Bodek return (EINVAL); 3338a8d7fc4aSZbigniew Bodek 3339a8d7fc4aSZbigniew Bodek err = sysctl_handle_int(oidp, &val, 0, req); 3340a8d7fc4aSZbigniew Bodek if (err != 0) 3341a8d7fc4aSZbigniew Bodek return (err); 3342a8d7fc4aSZbigniew Bodek 3343a8d7fc4aSZbigniew Bodek if (val < 0 || val > 1) 3344a8d7fc4aSZbigniew Bodek return (EINVAL); 3345a8d7fc4aSZbigniew Bodek 3346a8d7fc4aSZbigniew Bodek if (val == 1) { 3347a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 3348a8d7fc4aSZbigniew Bodek mvneta_clear_mib(sc); 3349a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 3350a8d7fc4aSZbigniew Bodek } 3351a8d7fc4aSZbigniew Bodek 3352a8d7fc4aSZbigniew Bodek return (0); 3353a8d7fc4aSZbigniew Bodek } 3354a8d7fc4aSZbigniew Bodek 3355a8d7fc4aSZbigniew Bodek STATIC int 3356a8d7fc4aSZbigniew Bodek sysctl_set_queue_rxthtime(SYSCTL_HANDLER_ARGS) 3357a8d7fc4aSZbigniew Bodek { 3358a8d7fc4aSZbigniew Bodek struct mvneta_sysctl_queue *arg; 3359a8d7fc4aSZbigniew Bodek struct mvneta_rx_ring *rx; 3360a8d7fc4aSZbigniew Bodek struct mvneta_softc *sc; 3361a8d7fc4aSZbigniew Bodek uint32_t reg, time_mvtclk; 3362a8d7fc4aSZbigniew Bodek int err, time_us; 3363a8d7fc4aSZbigniew Bodek 3364a8d7fc4aSZbigniew Bodek rx = NULL; 3365a8d7fc4aSZbigniew Bodek arg = (struct mvneta_sysctl_queue *)arg1; 3366a8d7fc4aSZbigniew Bodek if (arg == NULL) 3367a8d7fc4aSZbigniew Bodek return (EINVAL); 3368a8d7fc4aSZbigniew Bodek if (arg->queue < 0 || arg->queue > MVNETA_RX_RING_CNT) 3369a8d7fc4aSZbigniew Bodek return (EINVAL); 3370a8d7fc4aSZbigniew Bodek if (arg->rxtx != MVNETA_SYSCTL_RX) 3371a8d7fc4aSZbigniew Bodek return (EINVAL); 3372a8d7fc4aSZbigniew Bodek 3373a8d7fc4aSZbigniew Bodek sc = arg->sc; 3374a8d7fc4aSZbigniew Bodek if (sc == NULL) 3375a8d7fc4aSZbigniew Bodek return (EINVAL); 3376a8d7fc4aSZbigniew Bodek 3377a8d7fc4aSZbigniew Bodek /* read queue length */ 3378a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 3379a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, arg->queue); 3380a8d7fc4aSZbigniew Bodek rx = MVNETA_RX_RING(sc, arg->queue); 3381a8d7fc4aSZbigniew Bodek time_mvtclk = rx->queue_th_time; 33824885d6f3SHubert Mazur time_us = ((uint64_t)time_mvtclk * 1000ULL * 1000ULL) / sc->clk_freq; 3383a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, arg->queue); 3384a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 3385a8d7fc4aSZbigniew Bodek 3386a8d7fc4aSZbigniew Bodek err = sysctl_handle_int(oidp, &time_us, 0, req); 3387a8d7fc4aSZbigniew Bodek if (err != 0) 3388a8d7fc4aSZbigniew Bodek return (err); 3389a8d7fc4aSZbigniew Bodek 3390a8d7fc4aSZbigniew Bodek mvneta_sc_lock(sc); 3391a8d7fc4aSZbigniew Bodek mvneta_rx_lockq(sc, arg->queue); 3392a8d7fc4aSZbigniew Bodek 3393a8d7fc4aSZbigniew Bodek /* update queue length (0[sec] - 1[sec]) */ 3394a8d7fc4aSZbigniew Bodek if (time_us < 0 || time_us > (1000 * 1000)) { 3395a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, arg->queue); 3396a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 3397a8d7fc4aSZbigniew Bodek return (EINVAL); 3398a8d7fc4aSZbigniew Bodek } 33994885d6f3SHubert Mazur time_mvtclk = sc->clk_freq * (uint64_t)time_us / (1000ULL * 1000ULL); 3400a8d7fc4aSZbigniew Bodek rx->queue_th_time = time_mvtclk; 3401a8d7fc4aSZbigniew Bodek reg = MVNETA_PRXITTH_RITT(rx->queue_th_time); 3402a8d7fc4aSZbigniew Bodek MVNETA_WRITE(sc, MVNETA_PRXITTH(arg->queue), reg); 3403a8d7fc4aSZbigniew Bodek mvneta_rx_unlockq(sc, arg->queue); 3404a8d7fc4aSZbigniew Bodek mvneta_sc_unlock(sc); 3405a8d7fc4aSZbigniew Bodek 3406a8d7fc4aSZbigniew Bodek return (0); 3407a8d7fc4aSZbigniew Bodek } 3408a8d7fc4aSZbigniew Bodek 3409a8d7fc4aSZbigniew Bodek STATIC void 3410a8d7fc4aSZbigniew Bodek sysctl_mvneta_init(struct mvneta_softc *sc) 3411a8d7fc4aSZbigniew Bodek { 3412a8d7fc4aSZbigniew Bodek struct sysctl_ctx_list *ctx; 3413a8d7fc4aSZbigniew Bodek struct sysctl_oid_list *children; 3414a8d7fc4aSZbigniew Bodek struct sysctl_oid_list *rxchildren; 3415a8d7fc4aSZbigniew Bodek struct sysctl_oid_list *qchildren, *mchildren; 3416a8d7fc4aSZbigniew Bodek struct sysctl_oid *tree; 3417a8d7fc4aSZbigniew Bodek int i, q; 3418a8d7fc4aSZbigniew Bodek struct mvneta_sysctl_queue *rxarg; 3419a8d7fc4aSZbigniew Bodek #define MVNETA_SYSCTL_NAME(num) "queue" # num 3420a8d7fc4aSZbigniew Bodek static const char *sysctl_queue_names[] = { 3421a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_NAME(0), MVNETA_SYSCTL_NAME(1), 3422a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_NAME(2), MVNETA_SYSCTL_NAME(3), 3423a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_NAME(4), MVNETA_SYSCTL_NAME(5), 3424a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_NAME(6), MVNETA_SYSCTL_NAME(7), 3425a8d7fc4aSZbigniew Bodek }; 3426a8d7fc4aSZbigniew Bodek #undef MVNETA_SYSCTL_NAME 3427a8d7fc4aSZbigniew Bodek 34283bc4bd5eSNick Hibma #ifndef NO_SYSCTL_DESCR 3429a8d7fc4aSZbigniew Bodek #define MVNETA_SYSCTL_DESCR(num) "configuration parameters for queue " # num 3430a8d7fc4aSZbigniew Bodek static const char *sysctl_queue_descrs[] = { 3431a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_DESCR(0), MVNETA_SYSCTL_DESCR(1), 3432a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_DESCR(2), MVNETA_SYSCTL_DESCR(3), 3433a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_DESCR(4), MVNETA_SYSCTL_DESCR(5), 3434a8d7fc4aSZbigniew Bodek MVNETA_SYSCTL_DESCR(6), MVNETA_SYSCTL_DESCR(7), 3435a8d7fc4aSZbigniew Bodek }; 3436a8d7fc4aSZbigniew Bodek #undef MVNETA_SYSCTL_DESCR 34373bc4bd5eSNick Hibma #endif 3438a8d7fc4aSZbigniew Bodek 3439a8d7fc4aSZbigniew Bodek 3440a8d7fc4aSZbigniew Bodek ctx = device_get_sysctl_ctx(sc->dev); 3441a8d7fc4aSZbigniew Bodek children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); 3442a8d7fc4aSZbigniew Bodek 3443a8d7fc4aSZbigniew Bodek tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "rx", 34447029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "NETA RX"); 3445a8d7fc4aSZbigniew Bodek rxchildren = SYSCTL_CHILDREN(tree); 3446a8d7fc4aSZbigniew Bodek tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "mib", 34477029da5cSPawel Biernacki CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "NETA MIB"); 3448a8d7fc4aSZbigniew Bodek mchildren = SYSCTL_CHILDREN(tree); 3449a8d7fc4aSZbigniew Bodek 3450a8d7fc4aSZbigniew Bodek 3451a8d7fc4aSZbigniew Bodek SYSCTL_ADD_INT(ctx, children, OID_AUTO, "flow_control", 3452a8d7fc4aSZbigniew Bodek CTLFLAG_RW, &sc->cf_fc, 0, "flow control"); 3453a8d7fc4aSZbigniew Bodek SYSCTL_ADD_INT(ctx, children, OID_AUTO, "lpi", 3454a8d7fc4aSZbigniew Bodek CTLFLAG_RW, &sc->cf_lpi, 0, "Low Power Idle"); 3455a8d7fc4aSZbigniew Bodek 3456a8d7fc4aSZbigniew Bodek /* 3457a8d7fc4aSZbigniew Bodek * MIB access 3458a8d7fc4aSZbigniew Bodek */ 3459a8d7fc4aSZbigniew Bodek /* dev.mvneta.[unit].mib.<mibs> */ 3460a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_PORTMIB_NOCOUNTER; i++) { 3461a8d7fc4aSZbigniew Bodek struct mvneta_sysctl_mib *mib_arg = &sc->sysctl_mib[i]; 3462a8d7fc4aSZbigniew Bodek 3463a8d7fc4aSZbigniew Bodek mib_arg->sc = sc; 3464a8d7fc4aSZbigniew Bodek mib_arg->index = i; 34653bc4bd5eSNick Hibma SYSCTL_ADD_PROC(ctx, mchildren, OID_AUTO, 34663bc4bd5eSNick Hibma mvneta_mib_list[i].sysctl_name, 34677029da5cSPawel Biernacki CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 34687029da5cSPawel Biernacki (void *)mib_arg, 0, sysctl_read_mib, "I", 34697029da5cSPawel Biernacki mvneta_mib_list[i].desc); 3470a8d7fc4aSZbigniew Bodek } 3471a8d7fc4aSZbigniew Bodek SYSCTL_ADD_UQUAD(ctx, mchildren, OID_AUTO, "rx_discard", 3472a8d7fc4aSZbigniew Bodek CTLFLAG_RD, &sc->counter_pdfc, "Port Rx Discard Frame Counter"); 3473a8d7fc4aSZbigniew Bodek SYSCTL_ADD_UQUAD(ctx, mchildren, OID_AUTO, "overrun", 3474a8d7fc4aSZbigniew Bodek CTLFLAG_RD, &sc->counter_pofc, "Port Overrun Frame Counter"); 3475a8d7fc4aSZbigniew Bodek SYSCTL_ADD_UINT(ctx, mchildren, OID_AUTO, "watchdog", 3476a8d7fc4aSZbigniew Bodek CTLFLAG_RD, &sc->counter_watchdog, 0, "TX Watchdog Counter"); 3477a8d7fc4aSZbigniew Bodek 3478a8d7fc4aSZbigniew Bodek SYSCTL_ADD_PROC(ctx, mchildren, OID_AUTO, "reset", 34797029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 34807029da5cSPawel Biernacki (void *)sc, 0, sysctl_clear_mib, "I", "Reset MIB counters"); 3481a8d7fc4aSZbigniew Bodek 3482a8d7fc4aSZbigniew Bodek for (q = 0; q < MVNETA_RX_QNUM_MAX; q++) { 3483a8d7fc4aSZbigniew Bodek rxarg = &sc->sysctl_rx_queue[q]; 3484a8d7fc4aSZbigniew Bodek 3485a8d7fc4aSZbigniew Bodek rxarg->sc = sc; 3486a8d7fc4aSZbigniew Bodek rxarg->queue = q; 3487a8d7fc4aSZbigniew Bodek rxarg->rxtx = MVNETA_SYSCTL_RX; 3488a8d7fc4aSZbigniew Bodek 3489a8d7fc4aSZbigniew Bodek /* hw.mvneta.mvneta[unit].rx.[queue] */ 3490a8d7fc4aSZbigniew Bodek tree = SYSCTL_ADD_NODE(ctx, rxchildren, OID_AUTO, 34917029da5cSPawel Biernacki sysctl_queue_names[q], CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 3492a8d7fc4aSZbigniew Bodek sysctl_queue_descrs[q]); 3493a8d7fc4aSZbigniew Bodek qchildren = SYSCTL_CHILDREN(tree); 3494a8d7fc4aSZbigniew Bodek 3495a8d7fc4aSZbigniew Bodek /* hw.mvneta.mvneta[unit].rx.[queue].threshold_timer_us */ 3496a8d7fc4aSZbigniew Bodek SYSCTL_ADD_PROC(ctx, qchildren, OID_AUTO, "threshold_timer_us", 34977029da5cSPawel Biernacki CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, rxarg, 0, 3498a8d7fc4aSZbigniew Bodek sysctl_set_queue_rxthtime, "I", 3499a8d7fc4aSZbigniew Bodek "interrupt coalescing threshold timer [us]"); 3500a8d7fc4aSZbigniew Bodek } 3501a8d7fc4aSZbigniew Bodek } 3502a8d7fc4aSZbigniew Bodek 3503a8d7fc4aSZbigniew Bodek /* 3504a8d7fc4aSZbigniew Bodek * MIB 3505a8d7fc4aSZbigniew Bodek */ 3506caf552a6SMark Johnston STATIC uint64_t 3507caf552a6SMark Johnston mvneta_read_mib(struct mvneta_softc *sc, int index) 3508caf552a6SMark Johnston { 3509caf552a6SMark Johnston struct mvneta_mib_def *mib; 3510caf552a6SMark Johnston uint64_t val; 3511caf552a6SMark Johnston 3512caf552a6SMark Johnston mib = &mvneta_mib_list[index]; 3513caf552a6SMark Johnston val = MVNETA_READ_MIB(sc, mib->regnum); 3514caf552a6SMark Johnston if (mib->reg64) 3515caf552a6SMark Johnston val |= (uint64_t)MVNETA_READ_MIB(sc, mib->regnum + 4) << 32; 3516caf552a6SMark Johnston return (val); 3517caf552a6SMark Johnston } 3518caf552a6SMark Johnston 3519a8d7fc4aSZbigniew Bodek STATIC void 3520a8d7fc4aSZbigniew Bodek mvneta_clear_mib(struct mvneta_softc *sc) 3521a8d7fc4aSZbigniew Bodek { 3522a8d7fc4aSZbigniew Bodek int i; 3523a8d7fc4aSZbigniew Bodek 3524a8d7fc4aSZbigniew Bodek KASSERT_SC_MTX(sc); 3525a8d7fc4aSZbigniew Bodek 3526a8d7fc4aSZbigniew Bodek for (i = 0; i < nitems(mvneta_mib_list); i++) { 3527caf552a6SMark Johnston (void)mvneta_read_mib(sc, i); 3528a8d7fc4aSZbigniew Bodek sc->sysctl_mib[i].counter = 0; 3529a8d7fc4aSZbigniew Bodek } 3530a8d7fc4aSZbigniew Bodek MVNETA_READ(sc, MVNETA_PDFC); 3531a8d7fc4aSZbigniew Bodek sc->counter_pdfc = 0; 3532a8d7fc4aSZbigniew Bodek MVNETA_READ(sc, MVNETA_POFC); 3533a8d7fc4aSZbigniew Bodek sc->counter_pofc = 0; 3534a8d7fc4aSZbigniew Bodek sc->counter_watchdog = 0; 3535a8d7fc4aSZbigniew Bodek } 3536a8d7fc4aSZbigniew Bodek 3537a8d7fc4aSZbigniew Bodek STATIC void 3538a8d7fc4aSZbigniew Bodek mvneta_update_mib(struct mvneta_softc *sc) 3539a8d7fc4aSZbigniew Bodek { 3540a8d7fc4aSZbigniew Bodek struct mvneta_tx_ring *tx; 3541a8d7fc4aSZbigniew Bodek int i; 3542a8d7fc4aSZbigniew Bodek uint64_t val; 3543a8d7fc4aSZbigniew Bodek uint32_t reg; 3544a8d7fc4aSZbigniew Bodek 3545a8d7fc4aSZbigniew Bodek for (i = 0; i < nitems(mvneta_mib_list); i++) { 3546a8d7fc4aSZbigniew Bodek 3547caf552a6SMark Johnston val = mvneta_read_mib(sc, i); 3548a8d7fc4aSZbigniew Bodek if (val == 0) 3549a8d7fc4aSZbigniew Bodek continue; 3550a8d7fc4aSZbigniew Bodek 3551a8d7fc4aSZbigniew Bodek sc->sysctl_mib[i].counter += val; 3552a8d7fc4aSZbigniew Bodek switch (mvneta_mib_list[i].regnum) { 3553a8d7fc4aSZbigniew Bodek case MVNETA_MIB_RX_GOOD_OCT: 3554a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_IBYTES, val); 3555a8d7fc4aSZbigniew Bodek break; 3556a8d7fc4aSZbigniew Bodek case MVNETA_MIB_RX_BAD_FRAME: 3557a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, val); 3558a8d7fc4aSZbigniew Bodek break; 3559a8d7fc4aSZbigniew Bodek case MVNETA_MIB_RX_GOOD_FRAME: 3560a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, val); 3561a8d7fc4aSZbigniew Bodek break; 3562a8d7fc4aSZbigniew Bodek case MVNETA_MIB_RX_MCAST_FRAME: 3563a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_IMCASTS, val); 3564a8d7fc4aSZbigniew Bodek break; 3565a8d7fc4aSZbigniew Bodek case MVNETA_MIB_TX_GOOD_OCT: 3566a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_OBYTES, val); 3567a8d7fc4aSZbigniew Bodek break; 3568a8d7fc4aSZbigniew Bodek case MVNETA_MIB_TX_GOOD_FRAME: 3569a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, val); 3570a8d7fc4aSZbigniew Bodek break; 3571a8d7fc4aSZbigniew Bodek case MVNETA_MIB_TX_MCAST_FRAME: 3572a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_OMCASTS, val); 3573a8d7fc4aSZbigniew Bodek break; 3574a8d7fc4aSZbigniew Bodek case MVNETA_MIB_MAC_COL: 3575a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_COLLISIONS, val); 3576a8d7fc4aSZbigniew Bodek break; 3577a8d7fc4aSZbigniew Bodek case MVNETA_MIB_TX_MAC_TRNS_ERR: 3578a8d7fc4aSZbigniew Bodek case MVNETA_MIB_TX_EXCES_COL: 3579a8d7fc4aSZbigniew Bodek case MVNETA_MIB_MAC_LATE_COL: 3580a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, val); 3581a8d7fc4aSZbigniew Bodek break; 3582a8d7fc4aSZbigniew Bodek } 3583a8d7fc4aSZbigniew Bodek } 3584a8d7fc4aSZbigniew Bodek 3585a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_PDFC); 3586a8d7fc4aSZbigniew Bodek sc->counter_pdfc += reg; 3587a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, reg); 3588a8d7fc4aSZbigniew Bodek reg = MVNETA_READ(sc, MVNETA_POFC); 3589a8d7fc4aSZbigniew Bodek sc->counter_pofc += reg; 3590a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, reg); 3591a8d7fc4aSZbigniew Bodek 3592a8d7fc4aSZbigniew Bodek /* TX watchdog. */ 3593a8d7fc4aSZbigniew Bodek if (sc->counter_watchdog_mib > 0) { 3594a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, sc->counter_watchdog_mib); 3595a8d7fc4aSZbigniew Bodek sc->counter_watchdog_mib = 0; 3596a8d7fc4aSZbigniew Bodek } 3597a8d7fc4aSZbigniew Bodek /* 3598a8d7fc4aSZbigniew Bodek * TX driver errors: 3599a8d7fc4aSZbigniew Bodek * We do not take queue locks to not disrupt TX path. 3600a8d7fc4aSZbigniew Bodek * We may only miss one drv error which will be fixed at 3601a8d7fc4aSZbigniew Bodek * next mib update. We may also clear counter when TX path 3602a8d7fc4aSZbigniew Bodek * is incrementing it but we only do it if counter was not zero 3603a8d7fc4aSZbigniew Bodek * thus we may only loose one error. 3604a8d7fc4aSZbigniew Bodek */ 3605a8d7fc4aSZbigniew Bodek for (i = 0; i < MVNETA_TX_QNUM_MAX; i++) { 3606a8d7fc4aSZbigniew Bodek tx = MVNETA_TX_RING(sc, i); 3607a8d7fc4aSZbigniew Bodek 3608a8d7fc4aSZbigniew Bodek if (tx->drv_error > 0) { 3609a8d7fc4aSZbigniew Bodek if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, tx->drv_error); 3610a8d7fc4aSZbigniew Bodek tx->drv_error = 0; 3611a8d7fc4aSZbigniew Bodek } 3612a8d7fc4aSZbigniew Bodek } 3613a8d7fc4aSZbigniew Bodek } 3614