185ae89f4SRuslan Bukin /*- 285ae89f4SRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause 385ae89f4SRuslan Bukin * 485ae89f4SRuslan Bukin * Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com> 585ae89f4SRuslan Bukin * 685ae89f4SRuslan Bukin * This software was developed by SRI International and the University of 785ae89f4SRuslan Bukin * Cambridge Computer Laboratory (Department of Computer Science and 885ae89f4SRuslan Bukin * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 985ae89f4SRuslan Bukin * DARPA SSITH research programme. 1085ae89f4SRuslan Bukin * 1185ae89f4SRuslan Bukin * Redistribution and use in source and binary forms, with or without 1285ae89f4SRuslan Bukin * modification, are permitted provided that the following conditions 1385ae89f4SRuslan Bukin * are met: 1485ae89f4SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 1585ae89f4SRuslan Bukin * notice, this list of conditions and the following disclaimer. 1685ae89f4SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 1785ae89f4SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 1885ae89f4SRuslan Bukin * documentation and/or other materials provided with the distribution. 1985ae89f4SRuslan Bukin * 2085ae89f4SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2185ae89f4SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2285ae89f4SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2385ae89f4SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2485ae89f4SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2585ae89f4SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2685ae89f4SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2785ae89f4SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2885ae89f4SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2985ae89f4SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3085ae89f4SRuslan Bukin * SUCH DAMAGE. 3185ae89f4SRuslan Bukin */ 3285ae89f4SRuslan Bukin 3385ae89f4SRuslan Bukin #include <sys/param.h> 3485ae89f4SRuslan Bukin #include <sys/systm.h> 3585ae89f4SRuslan Bukin #include <sys/bus.h> 3685ae89f4SRuslan Bukin #include <sys/kernel.h> 3785ae89f4SRuslan Bukin #include <sys/lock.h> 3885ae89f4SRuslan Bukin #include <sys/malloc.h> 3985ae89f4SRuslan Bukin #include <sys/mbuf.h> 4085ae89f4SRuslan Bukin #include <sys/module.h> 4185ae89f4SRuslan Bukin #include <sys/mutex.h> 4285ae89f4SRuslan Bukin #include <sys/rman.h> 4385ae89f4SRuslan Bukin #include <sys/socket.h> 4485ae89f4SRuslan Bukin #include <sys/sockio.h> 4585ae89f4SRuslan Bukin 4685ae89f4SRuslan Bukin #include <net/bpf.h> 4785ae89f4SRuslan Bukin #include <net/if.h> 4885ae89f4SRuslan Bukin #include <net/ethernet.h> 4985ae89f4SRuslan Bukin #include <net/if_dl.h> 5085ae89f4SRuslan Bukin #include <net/if_media.h> 5185ae89f4SRuslan Bukin #include <net/if_types.h> 5285ae89f4SRuslan Bukin #include <net/if_var.h> 5385ae89f4SRuslan Bukin 5485ae89f4SRuslan Bukin #include <machine/bus.h> 5585ae89f4SRuslan Bukin 5685ae89f4SRuslan Bukin #include <dev/mii/mii.h> 5785ae89f4SRuslan Bukin #include <dev/mii/miivar.h> 5885ae89f4SRuslan Bukin #include <dev/mii/tiphy.h> 5985ae89f4SRuslan Bukin #include <dev/ofw/ofw_bus.h> 6085ae89f4SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 6185ae89f4SRuslan Bukin #include <dev/xilinx/if_xaereg.h> 6285ae89f4SRuslan Bukin #include <dev/xilinx/if_xaevar.h> 6385ae89f4SRuslan Bukin 64a8692c16SRuslan Bukin #include <dev/xilinx/axidma.h> 65a8692c16SRuslan Bukin 6685ae89f4SRuslan Bukin #include "miibus_if.h" 6785ae89f4SRuslan Bukin 6885ae89f4SRuslan Bukin #define READ4(_sc, _reg) \ 6985ae89f4SRuslan Bukin bus_read_4((_sc)->res[0], _reg) 7085ae89f4SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 7185ae89f4SRuslan Bukin bus_write_4((_sc)->res[0], _reg, _val) 7285ae89f4SRuslan Bukin 7385ae89f4SRuslan Bukin #define READ8(_sc, _reg) \ 7485ae89f4SRuslan Bukin bus_read_8((_sc)->res[0], _reg) 7585ae89f4SRuslan Bukin #define WRITE8(_sc, _reg, _val) \ 7685ae89f4SRuslan Bukin bus_write_8((_sc)->res[0], _reg, _val) 7785ae89f4SRuslan Bukin 7885ae89f4SRuslan Bukin #define XAE_LOCK(sc) mtx_lock(&(sc)->mtx) 7985ae89f4SRuslan Bukin #define XAE_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 8085ae89f4SRuslan Bukin #define XAE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) 8185ae89f4SRuslan Bukin #define XAE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) 8285ae89f4SRuslan Bukin 8385ae89f4SRuslan Bukin #define XAE_DEBUG 8485ae89f4SRuslan Bukin #undef XAE_DEBUG 8585ae89f4SRuslan Bukin 8685ae89f4SRuslan Bukin #ifdef XAE_DEBUG 8785ae89f4SRuslan Bukin #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) 8885ae89f4SRuslan Bukin #else 8985ae89f4SRuslan Bukin #define dprintf(fmt, ...) 9085ae89f4SRuslan Bukin #endif 9185ae89f4SRuslan Bukin 9285ae89f4SRuslan Bukin #define RX_QUEUE_SIZE 64 9385ae89f4SRuslan Bukin #define TX_QUEUE_SIZE 64 9485ae89f4SRuslan Bukin #define NUM_RX_MBUF 16 9585ae89f4SRuslan Bukin #define BUFRING_SIZE 8192 9685ae89f4SRuslan Bukin #define MDIO_CLK_DIV_DEFAULT 29 9785ae89f4SRuslan Bukin 9885ae89f4SRuslan Bukin #define PHY1_RD(sc, _r) \ 9985ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, 1, _r) 10085ae89f4SRuslan Bukin #define PHY1_WR(sc, _r, _v) \ 10185ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, 1, _r, _v) 10285ae89f4SRuslan Bukin 10385ae89f4SRuslan Bukin #define PHY_RD(sc, _r) \ 10485ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, sc->phy_addr, _r) 10585ae89f4SRuslan Bukin #define PHY_WR(sc, _r, _v) \ 10685ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, sc->phy_addr, _r, _v) 10785ae89f4SRuslan Bukin 10885ae89f4SRuslan Bukin /* Use this macro to access regs > 0x1f */ 10985ae89f4SRuslan Bukin #define WRITE_TI_EREG(sc, reg, data) { \ 11085ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK); \ 11185ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, reg); \ 11285ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK | MMDACR_FN_DATANPI); \ 11385ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, data); \ 11485ae89f4SRuslan Bukin } 11585ae89f4SRuslan Bukin 11685ae89f4SRuslan Bukin /* Not documented, Xilinx VCU118 workaround */ 11785ae89f4SRuslan Bukin #define CFG4_SGMII_TMR 0x160 /* bits 8:7 MUST be '10' */ 11885ae89f4SRuslan Bukin #define DP83867_SGMIICTL1 0xD3 /* not documented register */ 11985ae89f4SRuslan Bukin #define SGMIICTL1_SGMII_6W (1 << 14) /* no idea what it is */ 12085ae89f4SRuslan Bukin 12185ae89f4SRuslan Bukin static struct resource_spec xae_spec[] = { 12285ae89f4SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 12385ae89f4SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 12485ae89f4SRuslan Bukin { -1, 0 } 12585ae89f4SRuslan Bukin }; 12685ae89f4SRuslan Bukin 12785ae89f4SRuslan Bukin static void xae_stop_locked(struct xae_softc *sc); 12885ae89f4SRuslan Bukin static void xae_setup_rxfilter(struct xae_softc *sc); 12985ae89f4SRuslan Bukin 13085ae89f4SRuslan Bukin static int 13185ae89f4SRuslan Bukin xae_rx_enqueue(struct xae_softc *sc, uint32_t n) 13285ae89f4SRuslan Bukin { 13385ae89f4SRuslan Bukin struct mbuf *m; 13485ae89f4SRuslan Bukin int i; 13585ae89f4SRuslan Bukin 13685ae89f4SRuslan Bukin for (i = 0; i < n; i++) { 13785ae89f4SRuslan Bukin m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 13885ae89f4SRuslan Bukin if (m == NULL) { 13985ae89f4SRuslan Bukin device_printf(sc->dev, 14085ae89f4SRuslan Bukin "%s: Can't alloc rx mbuf\n", __func__); 14185ae89f4SRuslan Bukin return (-1); 14285ae89f4SRuslan Bukin } 14385ae89f4SRuslan Bukin 14485ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 14585ae89f4SRuslan Bukin xdma_enqueue_mbuf(sc->xchan_rx, &m, 0, 4, 4, XDMA_DEV_TO_MEM); 14685ae89f4SRuslan Bukin } 14785ae89f4SRuslan Bukin 14885ae89f4SRuslan Bukin return (0); 14985ae89f4SRuslan Bukin } 15085ae89f4SRuslan Bukin 15185ae89f4SRuslan Bukin static int 15285ae89f4SRuslan Bukin xae_get_phyaddr(phandle_t node, int *phy_addr) 15385ae89f4SRuslan Bukin { 15485ae89f4SRuslan Bukin phandle_t phy_node; 15585ae89f4SRuslan Bukin pcell_t phy_handle, phy_reg; 15685ae89f4SRuslan Bukin 15785ae89f4SRuslan Bukin if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, 15885ae89f4SRuslan Bukin sizeof(phy_handle)) <= 0) 15985ae89f4SRuslan Bukin return (ENXIO); 16085ae89f4SRuslan Bukin 16185ae89f4SRuslan Bukin phy_node = OF_node_from_xref(phy_handle); 16285ae89f4SRuslan Bukin 16385ae89f4SRuslan Bukin if (OF_getencprop(phy_node, "reg", (void *)&phy_reg, 16485ae89f4SRuslan Bukin sizeof(phy_reg)) <= 0) 16585ae89f4SRuslan Bukin return (ENXIO); 16685ae89f4SRuslan Bukin 16785ae89f4SRuslan Bukin *phy_addr = phy_reg; 16885ae89f4SRuslan Bukin 16985ae89f4SRuslan Bukin return (0); 17085ae89f4SRuslan Bukin } 17185ae89f4SRuslan Bukin 17285ae89f4SRuslan Bukin static int 17385ae89f4SRuslan Bukin xae_xdma_tx_intr(void *arg, xdma_transfer_status_t *status) 17485ae89f4SRuslan Bukin { 17585ae89f4SRuslan Bukin xdma_transfer_status_t st; 17685ae89f4SRuslan Bukin struct xae_softc *sc; 177dba12f75SJustin Hibbits if_t ifp; 17885ae89f4SRuslan Bukin struct mbuf *m; 17985ae89f4SRuslan Bukin int err; 18085ae89f4SRuslan Bukin 18185ae89f4SRuslan Bukin sc = arg; 18285ae89f4SRuslan Bukin 18385ae89f4SRuslan Bukin XAE_LOCK(sc); 18485ae89f4SRuslan Bukin 18585ae89f4SRuslan Bukin ifp = sc->ifp; 18685ae89f4SRuslan Bukin 18785ae89f4SRuslan Bukin for (;;) { 18885ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_tx, &m, &st); 18985ae89f4SRuslan Bukin if (err != 0) { 19085ae89f4SRuslan Bukin break; 19185ae89f4SRuslan Bukin } 19285ae89f4SRuslan Bukin 19385ae89f4SRuslan Bukin if (st.error != 0) { 19485ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 19585ae89f4SRuslan Bukin } 19685ae89f4SRuslan Bukin 19785ae89f4SRuslan Bukin m_freem(m); 19885ae89f4SRuslan Bukin } 19985ae89f4SRuslan Bukin 200dba12f75SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 20185ae89f4SRuslan Bukin 20285ae89f4SRuslan Bukin XAE_UNLOCK(sc); 20385ae89f4SRuslan Bukin 20485ae89f4SRuslan Bukin return (0); 20585ae89f4SRuslan Bukin } 20685ae89f4SRuslan Bukin 20785ae89f4SRuslan Bukin static int 20885ae89f4SRuslan Bukin xae_xdma_rx_intr(void *arg, xdma_transfer_status_t *status) 20985ae89f4SRuslan Bukin { 21085ae89f4SRuslan Bukin xdma_transfer_status_t st; 21185ae89f4SRuslan Bukin struct xae_softc *sc; 212dba12f75SJustin Hibbits if_t ifp; 21385ae89f4SRuslan Bukin struct mbuf *m; 21485ae89f4SRuslan Bukin int err; 21585ae89f4SRuslan Bukin uint32_t cnt_processed; 21685ae89f4SRuslan Bukin 21785ae89f4SRuslan Bukin sc = arg; 21885ae89f4SRuslan Bukin 21985ae89f4SRuslan Bukin dprintf("%s\n", __func__); 22085ae89f4SRuslan Bukin 22185ae89f4SRuslan Bukin XAE_LOCK(sc); 22285ae89f4SRuslan Bukin 22385ae89f4SRuslan Bukin ifp = sc->ifp; 22485ae89f4SRuslan Bukin 22585ae89f4SRuslan Bukin cnt_processed = 0; 22685ae89f4SRuslan Bukin for (;;) { 22785ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_rx, &m, &st); 22885ae89f4SRuslan Bukin if (err != 0) { 22985ae89f4SRuslan Bukin break; 23085ae89f4SRuslan Bukin } 23185ae89f4SRuslan Bukin cnt_processed++; 23285ae89f4SRuslan Bukin 23385ae89f4SRuslan Bukin if (st.error != 0) { 23485ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 23585ae89f4SRuslan Bukin m_freem(m); 23685ae89f4SRuslan Bukin continue; 23785ae89f4SRuslan Bukin } 23885ae89f4SRuslan Bukin 23985ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = st.transferred; 24085ae89f4SRuslan Bukin m->m_pkthdr.rcvif = ifp; 24185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 242dba12f75SJustin Hibbits if_input(ifp, m); 24385ae89f4SRuslan Bukin XAE_LOCK(sc); 24485ae89f4SRuslan Bukin } 24585ae89f4SRuslan Bukin 24685ae89f4SRuslan Bukin xae_rx_enqueue(sc, cnt_processed); 24785ae89f4SRuslan Bukin 24885ae89f4SRuslan Bukin XAE_UNLOCK(sc); 24985ae89f4SRuslan Bukin 25085ae89f4SRuslan Bukin return (0); 25185ae89f4SRuslan Bukin } 25285ae89f4SRuslan Bukin 25385ae89f4SRuslan Bukin static void 254dba12f75SJustin Hibbits xae_qflush(if_t ifp) 25585ae89f4SRuslan Bukin { 25685ae89f4SRuslan Bukin } 25785ae89f4SRuslan Bukin 25885ae89f4SRuslan Bukin static int 259dba12f75SJustin Hibbits xae_transmit_locked(if_t ifp) 26085ae89f4SRuslan Bukin { 26185ae89f4SRuslan Bukin struct xae_softc *sc; 26285ae89f4SRuslan Bukin struct mbuf *m; 26385ae89f4SRuslan Bukin struct buf_ring *br; 26485ae89f4SRuslan Bukin int error; 26585ae89f4SRuslan Bukin int enq; 26685ae89f4SRuslan Bukin 26785ae89f4SRuslan Bukin dprintf("%s\n", __func__); 26885ae89f4SRuslan Bukin 269dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 27085ae89f4SRuslan Bukin br = sc->br; 27185ae89f4SRuslan Bukin 27285ae89f4SRuslan Bukin enq = 0; 27385ae89f4SRuslan Bukin 27485ae89f4SRuslan Bukin while ((m = drbr_peek(ifp, br)) != NULL) { 27585ae89f4SRuslan Bukin error = xdma_enqueue_mbuf(sc->xchan_tx, 27685ae89f4SRuslan Bukin &m, 0, 4, 4, XDMA_MEM_TO_DEV); 27785ae89f4SRuslan Bukin if (error != 0) { 27885ae89f4SRuslan Bukin /* No space in request queue available yet. */ 27985ae89f4SRuslan Bukin drbr_putback(ifp, br, m); 28085ae89f4SRuslan Bukin break; 28185ae89f4SRuslan Bukin } 28285ae89f4SRuslan Bukin 28385ae89f4SRuslan Bukin drbr_advance(ifp, br); 28485ae89f4SRuslan Bukin 28585ae89f4SRuslan Bukin enq++; 28685ae89f4SRuslan Bukin 28785ae89f4SRuslan Bukin /* If anyone is interested give them a copy. */ 28885ae89f4SRuslan Bukin ETHER_BPF_MTAP(ifp, m); 28985ae89f4SRuslan Bukin } 29085ae89f4SRuslan Bukin 29185ae89f4SRuslan Bukin if (enq > 0) 29285ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_tx); 29385ae89f4SRuslan Bukin 29485ae89f4SRuslan Bukin return (0); 29585ae89f4SRuslan Bukin } 29685ae89f4SRuslan Bukin 29785ae89f4SRuslan Bukin static int 298dba12f75SJustin Hibbits xae_transmit(if_t ifp, struct mbuf *m) 29985ae89f4SRuslan Bukin { 30085ae89f4SRuslan Bukin struct xae_softc *sc; 30185ae89f4SRuslan Bukin int error; 30285ae89f4SRuslan Bukin 30385ae89f4SRuslan Bukin dprintf("%s\n", __func__); 30485ae89f4SRuslan Bukin 305dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 30685ae89f4SRuslan Bukin 30785ae89f4SRuslan Bukin XAE_LOCK(sc); 30885ae89f4SRuslan Bukin 30985ae89f4SRuslan Bukin error = drbr_enqueue(ifp, sc->br, m); 31085ae89f4SRuslan Bukin if (error) { 31185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 31285ae89f4SRuslan Bukin return (error); 31385ae89f4SRuslan Bukin } 31485ae89f4SRuslan Bukin 315dba12f75SJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 31685ae89f4SRuslan Bukin IFF_DRV_RUNNING) { 31785ae89f4SRuslan Bukin XAE_UNLOCK(sc); 31885ae89f4SRuslan Bukin return (0); 31985ae89f4SRuslan Bukin } 32085ae89f4SRuslan Bukin 32185ae89f4SRuslan Bukin if (!sc->link_is_up) { 32285ae89f4SRuslan Bukin XAE_UNLOCK(sc); 32385ae89f4SRuslan Bukin return (0); 32485ae89f4SRuslan Bukin } 32585ae89f4SRuslan Bukin 32685ae89f4SRuslan Bukin error = xae_transmit_locked(ifp); 32785ae89f4SRuslan Bukin 32885ae89f4SRuslan Bukin XAE_UNLOCK(sc); 32985ae89f4SRuslan Bukin 33085ae89f4SRuslan Bukin return (error); 33185ae89f4SRuslan Bukin } 33285ae89f4SRuslan Bukin 33385ae89f4SRuslan Bukin static void 33485ae89f4SRuslan Bukin xae_stop_locked(struct xae_softc *sc) 33585ae89f4SRuslan Bukin { 336dba12f75SJustin Hibbits if_t ifp; 33785ae89f4SRuslan Bukin uint32_t reg; 33885ae89f4SRuslan Bukin 33985ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 34085ae89f4SRuslan Bukin 34185ae89f4SRuslan Bukin ifp = sc->ifp; 342dba12f75SJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 34385ae89f4SRuslan Bukin 34485ae89f4SRuslan Bukin callout_stop(&sc->xae_callout); 34585ae89f4SRuslan Bukin 34685ae89f4SRuslan Bukin /* Stop the transmitter */ 34785ae89f4SRuslan Bukin reg = READ4(sc, XAE_TC); 34885ae89f4SRuslan Bukin reg &= ~TC_TX; 34985ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, reg); 35085ae89f4SRuslan Bukin 35185ae89f4SRuslan Bukin /* Stop the receiver. */ 35285ae89f4SRuslan Bukin reg = READ4(sc, XAE_RCW1); 35385ae89f4SRuslan Bukin reg &= ~RCW1_RX; 35485ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, reg); 35585ae89f4SRuslan Bukin } 35685ae89f4SRuslan Bukin 35785ae89f4SRuslan Bukin static uint64_t 35885ae89f4SRuslan Bukin xae_stat(struct xae_softc *sc, int counter_id) 35985ae89f4SRuslan Bukin { 36085ae89f4SRuslan Bukin uint64_t new, old; 36185ae89f4SRuslan Bukin uint64_t delta; 36285ae89f4SRuslan Bukin 36385ae89f4SRuslan Bukin KASSERT(counter_id < XAE_MAX_COUNTERS, 36485ae89f4SRuslan Bukin ("counter %d is out of range", counter_id)); 36585ae89f4SRuslan Bukin 36685ae89f4SRuslan Bukin new = READ8(sc, XAE_STATCNT(counter_id)); 36785ae89f4SRuslan Bukin old = sc->counters[counter_id]; 36885ae89f4SRuslan Bukin 36985ae89f4SRuslan Bukin if (new >= old) 37085ae89f4SRuslan Bukin delta = new - old; 37185ae89f4SRuslan Bukin else 37285ae89f4SRuslan Bukin delta = UINT64_MAX - old + new; 37385ae89f4SRuslan Bukin sc->counters[counter_id] = new; 37485ae89f4SRuslan Bukin 37585ae89f4SRuslan Bukin return (delta); 37685ae89f4SRuslan Bukin } 37785ae89f4SRuslan Bukin 37885ae89f4SRuslan Bukin static void 37985ae89f4SRuslan Bukin xae_harvest_stats(struct xae_softc *sc) 38085ae89f4SRuslan Bukin { 381dba12f75SJustin Hibbits if_t ifp; 38285ae89f4SRuslan Bukin 38385ae89f4SRuslan Bukin ifp = sc->ifp; 38485ae89f4SRuslan Bukin 38585ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IPACKETS, xae_stat(sc, RX_GOOD_FRAMES)); 38685ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IMCASTS, xae_stat(sc, RX_GOOD_MCASTS)); 38785ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 38885ae89f4SRuslan Bukin xae_stat(sc, RX_FRAME_CHECK_SEQ_ERROR) + 38985ae89f4SRuslan Bukin xae_stat(sc, RX_LEN_OUT_OF_RANGE) + 39085ae89f4SRuslan Bukin xae_stat(sc, RX_ALIGNMENT_ERRORS)); 39185ae89f4SRuslan Bukin 39285ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OBYTES, xae_stat(sc, TX_BYTES)); 39385ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OPACKETS, xae_stat(sc, TX_GOOD_FRAMES)); 39485ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OMCASTS, xae_stat(sc, TX_GOOD_MCASTS)); 39585ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 39685ae89f4SRuslan Bukin xae_stat(sc, TX_GOOD_UNDERRUN_ERRORS)); 39785ae89f4SRuslan Bukin 39885ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 39985ae89f4SRuslan Bukin xae_stat(sc, TX_SINGLE_COLLISION_FRAMES) + 40085ae89f4SRuslan Bukin xae_stat(sc, TX_MULTI_COLLISION_FRAMES) + 40185ae89f4SRuslan Bukin xae_stat(sc, TX_LATE_COLLISIONS) + 40285ae89f4SRuslan Bukin xae_stat(sc, TX_EXCESS_COLLISIONS)); 40385ae89f4SRuslan Bukin } 40485ae89f4SRuslan Bukin 40585ae89f4SRuslan Bukin static void 40685ae89f4SRuslan Bukin xae_tick(void *arg) 40785ae89f4SRuslan Bukin { 40885ae89f4SRuslan Bukin struct xae_softc *sc; 409dba12f75SJustin Hibbits if_t ifp; 41085ae89f4SRuslan Bukin int link_was_up; 41185ae89f4SRuslan Bukin 41285ae89f4SRuslan Bukin sc = arg; 41385ae89f4SRuslan Bukin 41485ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 41585ae89f4SRuslan Bukin 41685ae89f4SRuslan Bukin ifp = sc->ifp; 41785ae89f4SRuslan Bukin 418dba12f75SJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) 41985ae89f4SRuslan Bukin return; 42085ae89f4SRuslan Bukin 42185ae89f4SRuslan Bukin /* Gather stats from hardware counters. */ 42285ae89f4SRuslan Bukin xae_harvest_stats(sc); 42385ae89f4SRuslan Bukin 42485ae89f4SRuslan Bukin /* Check the media status. */ 42585ae89f4SRuslan Bukin link_was_up = sc->link_is_up; 42685ae89f4SRuslan Bukin mii_tick(sc->mii_softc); 42785ae89f4SRuslan Bukin if (sc->link_is_up && !link_was_up) 42885ae89f4SRuslan Bukin xae_transmit_locked(sc->ifp); 42985ae89f4SRuslan Bukin 43085ae89f4SRuslan Bukin /* Schedule another check one second from now. */ 43185ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 43285ae89f4SRuslan Bukin } 43385ae89f4SRuslan Bukin 43485ae89f4SRuslan Bukin static void 43585ae89f4SRuslan Bukin xae_init_locked(struct xae_softc *sc) 43685ae89f4SRuslan Bukin { 437dba12f75SJustin Hibbits if_t ifp; 43885ae89f4SRuslan Bukin 43985ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 44085ae89f4SRuslan Bukin 44185ae89f4SRuslan Bukin ifp = sc->ifp; 442dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 44385ae89f4SRuslan Bukin return; 44485ae89f4SRuslan Bukin 445dba12f75SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 44685ae89f4SRuslan Bukin 44785ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 44885ae89f4SRuslan Bukin 44985ae89f4SRuslan Bukin /* Enable the transmitter */ 45085ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, TC_TX); 45185ae89f4SRuslan Bukin 45285ae89f4SRuslan Bukin /* Enable the receiver. */ 45385ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, RCW1_RX); 45485ae89f4SRuslan Bukin 45585ae89f4SRuslan Bukin /* 45685ae89f4SRuslan Bukin * Call mii_mediachg() which will call back into xae_miibus_statchg() 45785ae89f4SRuslan Bukin * to set up the remaining config registers based on current media. 45885ae89f4SRuslan Bukin */ 45985ae89f4SRuslan Bukin mii_mediachg(sc->mii_softc); 46085ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 46185ae89f4SRuslan Bukin } 46285ae89f4SRuslan Bukin 46385ae89f4SRuslan Bukin static void 46485ae89f4SRuslan Bukin xae_init(void *arg) 46585ae89f4SRuslan Bukin { 46685ae89f4SRuslan Bukin struct xae_softc *sc; 46785ae89f4SRuslan Bukin 46885ae89f4SRuslan Bukin sc = arg; 46985ae89f4SRuslan Bukin 47085ae89f4SRuslan Bukin XAE_LOCK(sc); 47185ae89f4SRuslan Bukin xae_init_locked(sc); 47285ae89f4SRuslan Bukin XAE_UNLOCK(sc); 47385ae89f4SRuslan Bukin } 47485ae89f4SRuslan Bukin 47585ae89f4SRuslan Bukin static void 476dba12f75SJustin Hibbits xae_media_status(if_t ifp, struct ifmediareq *ifmr) 47785ae89f4SRuslan Bukin { 47885ae89f4SRuslan Bukin struct xae_softc *sc; 47985ae89f4SRuslan Bukin struct mii_data *mii; 48085ae89f4SRuslan Bukin 481dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 48285ae89f4SRuslan Bukin mii = sc->mii_softc; 48385ae89f4SRuslan Bukin 48485ae89f4SRuslan Bukin XAE_LOCK(sc); 48585ae89f4SRuslan Bukin mii_pollstat(mii); 48685ae89f4SRuslan Bukin ifmr->ifm_active = mii->mii_media_active; 48785ae89f4SRuslan Bukin ifmr->ifm_status = mii->mii_media_status; 48885ae89f4SRuslan Bukin XAE_UNLOCK(sc); 48985ae89f4SRuslan Bukin } 49085ae89f4SRuslan Bukin 49185ae89f4SRuslan Bukin static int 49285ae89f4SRuslan Bukin xae_media_change_locked(struct xae_softc *sc) 49385ae89f4SRuslan Bukin { 49485ae89f4SRuslan Bukin 49585ae89f4SRuslan Bukin return (mii_mediachg(sc->mii_softc)); 49685ae89f4SRuslan Bukin } 49785ae89f4SRuslan Bukin 49885ae89f4SRuslan Bukin static int 499dba12f75SJustin Hibbits xae_media_change(if_t ifp) 50085ae89f4SRuslan Bukin { 50185ae89f4SRuslan Bukin struct xae_softc *sc; 50285ae89f4SRuslan Bukin int error; 50385ae89f4SRuslan Bukin 504dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 50585ae89f4SRuslan Bukin 50685ae89f4SRuslan Bukin XAE_LOCK(sc); 50785ae89f4SRuslan Bukin error = xae_media_change_locked(sc); 50885ae89f4SRuslan Bukin XAE_UNLOCK(sc); 50985ae89f4SRuslan Bukin 51085ae89f4SRuslan Bukin return (error); 51185ae89f4SRuslan Bukin } 51285ae89f4SRuslan Bukin 5134d50c26aSGleb Smirnoff static u_int 5144d50c26aSGleb Smirnoff xae_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 5154d50c26aSGleb Smirnoff { 5164d50c26aSGleb Smirnoff struct xae_softc *sc = arg; 5174d50c26aSGleb Smirnoff uint32_t reg; 5184d50c26aSGleb Smirnoff uint8_t *ma; 5194d50c26aSGleb Smirnoff 5204d50c26aSGleb Smirnoff if (cnt >= XAE_MULTICAST_TABLE_SIZE) 5214d50c26aSGleb Smirnoff return (1); 5224d50c26aSGleb Smirnoff 5234d50c26aSGleb Smirnoff ma = LLADDR(sdl); 5244d50c26aSGleb Smirnoff 5254d50c26aSGleb Smirnoff reg = READ4(sc, XAE_FFC) & 0xffffff00; 5264d50c26aSGleb Smirnoff reg |= cnt; 5274d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFC, reg); 5284d50c26aSGleb Smirnoff 5294d50c26aSGleb Smirnoff reg = (ma[0]); 5304d50c26aSGleb Smirnoff reg |= (ma[1] << 8); 5314d50c26aSGleb Smirnoff reg |= (ma[2] << 16); 5324d50c26aSGleb Smirnoff reg |= (ma[3] << 24); 5334d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFV(0), reg); 5344d50c26aSGleb Smirnoff 5354d50c26aSGleb Smirnoff reg = ma[4]; 5364d50c26aSGleb Smirnoff reg |= ma[5] << 8; 5374d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFV(1), reg); 5384d50c26aSGleb Smirnoff 5394d50c26aSGleb Smirnoff return (1); 5404d50c26aSGleb Smirnoff } 5414d50c26aSGleb Smirnoff 54285ae89f4SRuslan Bukin static void 54385ae89f4SRuslan Bukin xae_setup_rxfilter(struct xae_softc *sc) 54485ae89f4SRuslan Bukin { 545dba12f75SJustin Hibbits if_t ifp; 54685ae89f4SRuslan Bukin uint32_t reg; 54785ae89f4SRuslan Bukin 54885ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 54985ae89f4SRuslan Bukin 55085ae89f4SRuslan Bukin ifp = sc->ifp; 55185ae89f4SRuslan Bukin 55285ae89f4SRuslan Bukin /* 55385ae89f4SRuslan Bukin * Set the multicast (group) filter hash. 55485ae89f4SRuslan Bukin */ 555dba12f75SJustin Hibbits if ((if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 55685ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 55785ae89f4SRuslan Bukin reg |= FFC_PM; 55885ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 55985ae89f4SRuslan Bukin } else { 56085ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 56185ae89f4SRuslan Bukin reg &= ~FFC_PM; 56285ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 56385ae89f4SRuslan Bukin 5644d50c26aSGleb Smirnoff if_foreach_llmaddr(ifp, xae_write_maddr, sc); 56585ae89f4SRuslan Bukin } 56685ae89f4SRuslan Bukin 56785ae89f4SRuslan Bukin /* 56885ae89f4SRuslan Bukin * Set the primary address. 56985ae89f4SRuslan Bukin */ 57085ae89f4SRuslan Bukin reg = sc->macaddr[0]; 57185ae89f4SRuslan Bukin reg |= (sc->macaddr[1] << 8); 57285ae89f4SRuslan Bukin reg |= (sc->macaddr[2] << 16); 57385ae89f4SRuslan Bukin reg |= (sc->macaddr[3] << 24); 57485ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW0, reg); 57585ae89f4SRuslan Bukin 57685ae89f4SRuslan Bukin reg = sc->macaddr[4]; 57785ae89f4SRuslan Bukin reg |= (sc->macaddr[5] << 8); 57885ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW1, reg); 57985ae89f4SRuslan Bukin } 58085ae89f4SRuslan Bukin 58185ae89f4SRuslan Bukin static int 582dba12f75SJustin Hibbits xae_ioctl(if_t ifp, u_long cmd, caddr_t data) 58385ae89f4SRuslan Bukin { 58485ae89f4SRuslan Bukin struct xae_softc *sc; 58585ae89f4SRuslan Bukin struct mii_data *mii; 58685ae89f4SRuslan Bukin struct ifreq *ifr; 58785ae89f4SRuslan Bukin int mask, error; 58885ae89f4SRuslan Bukin 589dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 59085ae89f4SRuslan Bukin ifr = (struct ifreq *)data; 59185ae89f4SRuslan Bukin 59285ae89f4SRuslan Bukin error = 0; 59385ae89f4SRuslan Bukin switch (cmd) { 59485ae89f4SRuslan Bukin case SIOCSIFFLAGS: 59585ae89f4SRuslan Bukin XAE_LOCK(sc); 596dba12f75SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 597dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 598dba12f75SJustin Hibbits if ((if_getflags(ifp) ^ sc->if_flags) & 59985ae89f4SRuslan Bukin (IFF_PROMISC | IFF_ALLMULTI)) 60085ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 60185ae89f4SRuslan Bukin } else { 60285ae89f4SRuslan Bukin if (!sc->is_detaching) 60385ae89f4SRuslan Bukin xae_init_locked(sc); 60485ae89f4SRuslan Bukin } 60585ae89f4SRuslan Bukin } else { 606dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 60785ae89f4SRuslan Bukin xae_stop_locked(sc); 60885ae89f4SRuslan Bukin } 609dba12f75SJustin Hibbits sc->if_flags = if_getflags(ifp); 61085ae89f4SRuslan Bukin XAE_UNLOCK(sc); 61185ae89f4SRuslan Bukin break; 61285ae89f4SRuslan Bukin case SIOCADDMULTI: 61385ae89f4SRuslan Bukin case SIOCDELMULTI: 614dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 61585ae89f4SRuslan Bukin XAE_LOCK(sc); 61685ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 61785ae89f4SRuslan Bukin XAE_UNLOCK(sc); 61885ae89f4SRuslan Bukin } 61985ae89f4SRuslan Bukin break; 62085ae89f4SRuslan Bukin case SIOCSIFMEDIA: 62185ae89f4SRuslan Bukin case SIOCGIFMEDIA: 62285ae89f4SRuslan Bukin mii = sc->mii_softc; 62385ae89f4SRuslan Bukin error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 62485ae89f4SRuslan Bukin break; 62585ae89f4SRuslan Bukin case SIOCSIFCAP: 626dba12f75SJustin Hibbits mask = if_getcapenable(ifp) ^ ifr->ifr_reqcap; 62785ae89f4SRuslan Bukin if (mask & IFCAP_VLAN_MTU) { 62885ae89f4SRuslan Bukin /* No work to do except acknowledge the change took */ 629dba12f75SJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_MTU); 63085ae89f4SRuslan Bukin } 63185ae89f4SRuslan Bukin break; 63285ae89f4SRuslan Bukin 63385ae89f4SRuslan Bukin default: 63485ae89f4SRuslan Bukin error = ether_ioctl(ifp, cmd, data); 63585ae89f4SRuslan Bukin break; 63685ae89f4SRuslan Bukin } 63785ae89f4SRuslan Bukin 63885ae89f4SRuslan Bukin return (error); 63985ae89f4SRuslan Bukin } 64085ae89f4SRuslan Bukin 64185ae89f4SRuslan Bukin static void 64285ae89f4SRuslan Bukin xae_intr(void *arg) 64385ae89f4SRuslan Bukin { 64485ae89f4SRuslan Bukin 64585ae89f4SRuslan Bukin } 64685ae89f4SRuslan Bukin 64785ae89f4SRuslan Bukin static int 64885ae89f4SRuslan Bukin xae_get_hwaddr(struct xae_softc *sc, uint8_t *hwaddr) 64985ae89f4SRuslan Bukin { 65085ae89f4SRuslan Bukin phandle_t node; 65185ae89f4SRuslan Bukin int len; 65285ae89f4SRuslan Bukin 65385ae89f4SRuslan Bukin node = ofw_bus_get_node(sc->dev); 65485ae89f4SRuslan Bukin 65585ae89f4SRuslan Bukin /* Check if there is property */ 65685ae89f4SRuslan Bukin if ((len = OF_getproplen(node, "local-mac-address")) <= 0) 65785ae89f4SRuslan Bukin return (EINVAL); 65885ae89f4SRuslan Bukin 65985ae89f4SRuslan Bukin if (len != ETHER_ADDR_LEN) 66085ae89f4SRuslan Bukin return (EINVAL); 66185ae89f4SRuslan Bukin 66285ae89f4SRuslan Bukin OF_getprop(node, "local-mac-address", hwaddr, 66385ae89f4SRuslan Bukin ETHER_ADDR_LEN); 66485ae89f4SRuslan Bukin 66585ae89f4SRuslan Bukin return (0); 66685ae89f4SRuslan Bukin } 66785ae89f4SRuslan Bukin 66885ae89f4SRuslan Bukin static int 66985ae89f4SRuslan Bukin mdio_wait(struct xae_softc *sc) 67085ae89f4SRuslan Bukin { 67185ae89f4SRuslan Bukin uint32_t reg; 67285ae89f4SRuslan Bukin int timeout; 67385ae89f4SRuslan Bukin 67485ae89f4SRuslan Bukin timeout = 200; 67585ae89f4SRuslan Bukin 67685ae89f4SRuslan Bukin do { 67785ae89f4SRuslan Bukin reg = READ4(sc, XAE_MDIO_CTRL); 67885ae89f4SRuslan Bukin if (reg & MDIO_CTRL_READY) 67985ae89f4SRuslan Bukin break; 68085ae89f4SRuslan Bukin DELAY(1); 68185ae89f4SRuslan Bukin } while (timeout--); 68285ae89f4SRuslan Bukin 68385ae89f4SRuslan Bukin if (timeout <= 0) { 68485ae89f4SRuslan Bukin printf("Failed to get MDIO ready\n"); 68585ae89f4SRuslan Bukin return (1); 68685ae89f4SRuslan Bukin } 68785ae89f4SRuslan Bukin 68885ae89f4SRuslan Bukin return (0); 68985ae89f4SRuslan Bukin } 69085ae89f4SRuslan Bukin 69185ae89f4SRuslan Bukin static int 69285ae89f4SRuslan Bukin xae_miibus_read_reg(device_t dev, int phy, int reg) 69385ae89f4SRuslan Bukin { 69485ae89f4SRuslan Bukin struct xae_softc *sc; 69585ae89f4SRuslan Bukin uint32_t mii; 69685ae89f4SRuslan Bukin int rv; 69785ae89f4SRuslan Bukin 69885ae89f4SRuslan Bukin sc = device_get_softc(dev); 69985ae89f4SRuslan Bukin 70085ae89f4SRuslan Bukin if (mdio_wait(sc)) 70185ae89f4SRuslan Bukin return (0); 70285ae89f4SRuslan Bukin 70385ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_READ | MDIO_CTRL_INITIATE; 70485ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 70585ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 70685ae89f4SRuslan Bukin 70785ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 70885ae89f4SRuslan Bukin 70985ae89f4SRuslan Bukin if (mdio_wait(sc)) 71085ae89f4SRuslan Bukin return (0); 71185ae89f4SRuslan Bukin 71285ae89f4SRuslan Bukin rv = READ4(sc, XAE_MDIO_READ); 71385ae89f4SRuslan Bukin 71485ae89f4SRuslan Bukin return (rv); 71585ae89f4SRuslan Bukin } 71685ae89f4SRuslan Bukin 71785ae89f4SRuslan Bukin static int 71885ae89f4SRuslan Bukin xae_miibus_write_reg(device_t dev, int phy, int reg, int val) 71985ae89f4SRuslan Bukin { 72085ae89f4SRuslan Bukin struct xae_softc *sc; 72185ae89f4SRuslan Bukin uint32_t mii; 72285ae89f4SRuslan Bukin 72385ae89f4SRuslan Bukin sc = device_get_softc(dev); 72485ae89f4SRuslan Bukin 72585ae89f4SRuslan Bukin if (mdio_wait(sc)) 72685ae89f4SRuslan Bukin return (1); 72785ae89f4SRuslan Bukin 72885ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_WRITE | MDIO_CTRL_INITIATE; 72985ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 73085ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 73185ae89f4SRuslan Bukin 73285ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_WRITE, val); 73385ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 73485ae89f4SRuslan Bukin 73585ae89f4SRuslan Bukin if (mdio_wait(sc)) 73685ae89f4SRuslan Bukin return (1); 73785ae89f4SRuslan Bukin 73885ae89f4SRuslan Bukin return (0); 73985ae89f4SRuslan Bukin } 74085ae89f4SRuslan Bukin 74185ae89f4SRuslan Bukin static void 74285ae89f4SRuslan Bukin xae_phy_fixup(struct xae_softc *sc) 74385ae89f4SRuslan Bukin { 74485ae89f4SRuslan Bukin uint32_t reg; 74585ae89f4SRuslan Bukin 74685ae89f4SRuslan Bukin do { 74785ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_SGMIICTL1, SGMIICTL1_SGMII_6W); 74885ae89f4SRuslan Bukin PHY_WR(sc, DP83867_PHYCR, PHYCR_SGMII_EN); 74985ae89f4SRuslan Bukin 75085ae89f4SRuslan Bukin reg = PHY_RD(sc, DP83867_CFG2); 75185ae89f4SRuslan Bukin reg &= ~CFG2_SPEED_OPT_ATTEMPT_CNT_M; 75285ae89f4SRuslan Bukin reg |= (CFG2_SPEED_OPT_ATTEMPT_CNT_4); 75385ae89f4SRuslan Bukin reg |= CFG2_INTERRUPT_POLARITY; 75485ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_ENHANCED_EN; 75585ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_10M_EN; 75685ae89f4SRuslan Bukin PHY_WR(sc, DP83867_CFG2, reg); 75785ae89f4SRuslan Bukin 75885ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_CFG4, CFG4_SGMII_TMR); 75985ae89f4SRuslan Bukin PHY_WR(sc, MII_BMCR, 76085ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_RESET); 76185ae89f4SRuslan Bukin } while (PHY1_RD(sc, MII_BMCR) == 0x0ffff); 76285ae89f4SRuslan Bukin 76385ae89f4SRuslan Bukin do { 76485ae89f4SRuslan Bukin PHY1_WR(sc, MII_BMCR, 76585ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_STARTNEG); 76685ae89f4SRuslan Bukin DELAY(40000); 76785ae89f4SRuslan Bukin } while ((PHY1_RD(sc, MII_BMSR) & BMSR_ACOMP) == 0); 76885ae89f4SRuslan Bukin } 76985ae89f4SRuslan Bukin 77085ae89f4SRuslan Bukin static int 771a8692c16SRuslan Bukin get_xdma_std(struct xae_softc *sc) 772a8692c16SRuslan Bukin { 773a8692c16SRuslan Bukin 774a8692c16SRuslan Bukin sc->xdma_tx = xdma_ofw_get(sc->dev, "tx"); 775a8692c16SRuslan Bukin if (sc->xdma_tx == NULL) 776a8692c16SRuslan Bukin return (ENXIO); 777a8692c16SRuslan Bukin 778a8692c16SRuslan Bukin sc->xdma_rx = xdma_ofw_get(sc->dev, "rx"); 779a8692c16SRuslan Bukin if (sc->xdma_rx == NULL) { 780a8692c16SRuslan Bukin xdma_put(sc->xdma_tx); 781a8692c16SRuslan Bukin return (ENXIO); 782a8692c16SRuslan Bukin } 783a8692c16SRuslan Bukin 784a8692c16SRuslan Bukin return (0); 785a8692c16SRuslan Bukin } 786a8692c16SRuslan Bukin 787a8692c16SRuslan Bukin static int 788a8692c16SRuslan Bukin get_xdma_axistream(struct xae_softc *sc) 789a8692c16SRuslan Bukin { 790a8692c16SRuslan Bukin struct axidma_fdt_data *data; 791a8692c16SRuslan Bukin device_t dma_dev; 792a8692c16SRuslan Bukin phandle_t node; 793a8692c16SRuslan Bukin pcell_t prop; 794a8692c16SRuslan Bukin size_t len; 795a8692c16SRuslan Bukin 796a8692c16SRuslan Bukin node = ofw_bus_get_node(sc->dev); 797a8692c16SRuslan Bukin len = OF_getencprop(node, "axistream-connected", &prop, sizeof(prop)); 798a8692c16SRuslan Bukin if (len != sizeof(prop)) { 799a8692c16SRuslan Bukin device_printf(sc->dev, 800a8692c16SRuslan Bukin "%s: Couldn't get axistream-connected prop.\n", __func__); 801a8692c16SRuslan Bukin return (ENXIO); 802a8692c16SRuslan Bukin } 803a8692c16SRuslan Bukin dma_dev = OF_device_from_xref(prop); 804a8692c16SRuslan Bukin if (dma_dev == NULL) { 805a8692c16SRuslan Bukin device_printf(sc->dev, "Could not get DMA device by xref.\n"); 806a8692c16SRuslan Bukin return (ENXIO); 807a8692c16SRuslan Bukin } 808a8692c16SRuslan Bukin 809a8692c16SRuslan Bukin sc->xdma_tx = xdma_get(sc->dev, dma_dev); 810a8692c16SRuslan Bukin if (sc->xdma_tx == NULL) { 811a8692c16SRuslan Bukin device_printf(sc->dev, "Could not find DMA controller.\n"); 812a8692c16SRuslan Bukin return (ENXIO); 813a8692c16SRuslan Bukin } 814a8692c16SRuslan Bukin data = malloc(sizeof(struct axidma_fdt_data), 815a8692c16SRuslan Bukin M_DEVBUF, (M_WAITOK | M_ZERO)); 816a8692c16SRuslan Bukin data->id = AXIDMA_TX_CHAN; 817a8692c16SRuslan Bukin sc->xdma_tx->data = data; 818a8692c16SRuslan Bukin 819a8692c16SRuslan Bukin sc->xdma_rx = xdma_get(sc->dev, dma_dev); 820a8692c16SRuslan Bukin if (sc->xdma_rx == NULL) { 821a8692c16SRuslan Bukin device_printf(sc->dev, "Could not find DMA controller.\n"); 822a8692c16SRuslan Bukin return (ENXIO); 823a8692c16SRuslan Bukin } 824a8692c16SRuslan Bukin data = malloc(sizeof(struct axidma_fdt_data), 825a8692c16SRuslan Bukin M_DEVBUF, (M_WAITOK | M_ZERO)); 826a8692c16SRuslan Bukin data->id = AXIDMA_RX_CHAN; 827a8692c16SRuslan Bukin sc->xdma_rx->data = data; 828a8692c16SRuslan Bukin 829a8692c16SRuslan Bukin return (0); 830a8692c16SRuslan Bukin } 831a8692c16SRuslan Bukin 832a8692c16SRuslan Bukin static int 83385ae89f4SRuslan Bukin setup_xdma(struct xae_softc *sc) 83485ae89f4SRuslan Bukin { 83585ae89f4SRuslan Bukin device_t dev; 83685ae89f4SRuslan Bukin vmem_t *vmem; 83785ae89f4SRuslan Bukin int error; 83885ae89f4SRuslan Bukin 83985ae89f4SRuslan Bukin dev = sc->dev; 84085ae89f4SRuslan Bukin 84185ae89f4SRuslan Bukin /* Get xDMA controller */ 842a8692c16SRuslan Bukin error = get_xdma_std(sc); 843a8692c16SRuslan Bukin 844a8692c16SRuslan Bukin if (error) { 845a8692c16SRuslan Bukin device_printf(sc->dev, 846a8692c16SRuslan Bukin "Fallback to axistream-connected property\n"); 847a8692c16SRuslan Bukin error = get_xdma_axistream(sc); 84885ae89f4SRuslan Bukin } 84985ae89f4SRuslan Bukin 850a8692c16SRuslan Bukin if (error) { 851a8692c16SRuslan Bukin device_printf(dev, "Could not find xDMA controllers.\n"); 85285ae89f4SRuslan Bukin return (ENXIO); 85385ae89f4SRuslan Bukin } 85485ae89f4SRuslan Bukin 85585ae89f4SRuslan Bukin /* Alloc xDMA TX virtual channel. */ 85685ae89f4SRuslan Bukin sc->xchan_tx = xdma_channel_alloc(sc->xdma_tx, 0); 85785ae89f4SRuslan Bukin if (sc->xchan_tx == NULL) { 85885ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA TX channel.\n"); 85985ae89f4SRuslan Bukin return (ENXIO); 86085ae89f4SRuslan Bukin } 86185ae89f4SRuslan Bukin 86285ae89f4SRuslan Bukin /* Setup interrupt handler. */ 863d987842dSRuslan Bukin error = xdma_setup_intr(sc->xchan_tx, 0, 86485ae89f4SRuslan Bukin xae_xdma_tx_intr, sc, &sc->ih_tx); 86585ae89f4SRuslan Bukin if (error) { 86685ae89f4SRuslan Bukin device_printf(sc->dev, 86785ae89f4SRuslan Bukin "Can't setup xDMA TX interrupt handler.\n"); 86885ae89f4SRuslan Bukin return (ENXIO); 86985ae89f4SRuslan Bukin } 87085ae89f4SRuslan Bukin 87185ae89f4SRuslan Bukin /* Alloc xDMA RX virtual channel. */ 87285ae89f4SRuslan Bukin sc->xchan_rx = xdma_channel_alloc(sc->xdma_rx, 0); 87385ae89f4SRuslan Bukin if (sc->xchan_rx == NULL) { 87485ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA RX channel.\n"); 87585ae89f4SRuslan Bukin return (ENXIO); 87685ae89f4SRuslan Bukin } 87785ae89f4SRuslan Bukin 87885ae89f4SRuslan Bukin /* Setup interrupt handler. */ 879d987842dSRuslan Bukin error = xdma_setup_intr(sc->xchan_rx, XDMA_INTR_NET, 88085ae89f4SRuslan Bukin xae_xdma_rx_intr, sc, &sc->ih_rx); 88185ae89f4SRuslan Bukin if (error) { 88285ae89f4SRuslan Bukin device_printf(sc->dev, 88385ae89f4SRuslan Bukin "Can't setup xDMA RX interrupt handler.\n"); 88485ae89f4SRuslan Bukin return (ENXIO); 88585ae89f4SRuslan Bukin } 88685ae89f4SRuslan Bukin 88785ae89f4SRuslan Bukin /* Setup bounce buffer */ 88885ae89f4SRuslan Bukin vmem = xdma_get_memory(dev); 88985ae89f4SRuslan Bukin if (vmem) { 89085ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_tx, vmem); 89185ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_rx, vmem); 89285ae89f4SRuslan Bukin } 89385ae89f4SRuslan Bukin 89485ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_tx, 89585ae89f4SRuslan Bukin TX_QUEUE_SIZE, /* xchan requests queue size */ 89685ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 89785ae89f4SRuslan Bukin 8, /* maxnsegs */ 89885ae89f4SRuslan Bukin 16, /* alignment */ 89985ae89f4SRuslan Bukin 0, /* boundary */ 90085ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 90185ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 90285ae89f4SRuslan Bukin 90385ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_rx, 90485ae89f4SRuslan Bukin RX_QUEUE_SIZE, /* xchan requests queue size */ 90585ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 90685ae89f4SRuslan Bukin 1, /* maxnsegs */ 90785ae89f4SRuslan Bukin 16, /* alignment */ 90885ae89f4SRuslan Bukin 0, /* boundary */ 90985ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 91085ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 91185ae89f4SRuslan Bukin 91285ae89f4SRuslan Bukin return (0); 91385ae89f4SRuslan Bukin } 91485ae89f4SRuslan Bukin 91585ae89f4SRuslan Bukin static int 91685ae89f4SRuslan Bukin xae_probe(device_t dev) 91785ae89f4SRuslan Bukin { 91885ae89f4SRuslan Bukin 91985ae89f4SRuslan Bukin if (!ofw_bus_status_okay(dev)) 92085ae89f4SRuslan Bukin return (ENXIO); 92185ae89f4SRuslan Bukin 92285ae89f4SRuslan Bukin if (!ofw_bus_is_compatible(dev, "xlnx,axi-ethernet-1.00.a")) 92385ae89f4SRuslan Bukin return (ENXIO); 92485ae89f4SRuslan Bukin 92585ae89f4SRuslan Bukin device_set_desc(dev, "Xilinx AXI Ethernet"); 92685ae89f4SRuslan Bukin 92785ae89f4SRuslan Bukin return (BUS_PROBE_DEFAULT); 92885ae89f4SRuslan Bukin } 92985ae89f4SRuslan Bukin 93085ae89f4SRuslan Bukin static int 93185ae89f4SRuslan Bukin xae_attach(device_t dev) 93285ae89f4SRuslan Bukin { 93385ae89f4SRuslan Bukin struct xae_softc *sc; 934dba12f75SJustin Hibbits if_t ifp; 93585ae89f4SRuslan Bukin phandle_t node; 93685ae89f4SRuslan Bukin uint32_t reg; 93785ae89f4SRuslan Bukin int error; 93885ae89f4SRuslan Bukin 93985ae89f4SRuslan Bukin sc = device_get_softc(dev); 94085ae89f4SRuslan Bukin sc->dev = dev; 94185ae89f4SRuslan Bukin node = ofw_bus_get_node(dev); 94285ae89f4SRuslan Bukin 94385ae89f4SRuslan Bukin if (setup_xdma(sc) != 0) { 94485ae89f4SRuslan Bukin device_printf(dev, "Could not setup xDMA.\n"); 94585ae89f4SRuslan Bukin return (ENXIO); 94685ae89f4SRuslan Bukin } 94785ae89f4SRuslan Bukin 94885ae89f4SRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 94985ae89f4SRuslan Bukin MTX_NETWORK_LOCK, MTX_DEF); 95085ae89f4SRuslan Bukin 95185ae89f4SRuslan Bukin sc->br = buf_ring_alloc(BUFRING_SIZE, M_DEVBUF, 95285ae89f4SRuslan Bukin M_NOWAIT, &sc->mtx); 95385ae89f4SRuslan Bukin if (sc->br == NULL) 95485ae89f4SRuslan Bukin return (ENOMEM); 95585ae89f4SRuslan Bukin 95685ae89f4SRuslan Bukin if (bus_alloc_resources(dev, xae_spec, sc->res)) { 95785ae89f4SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 95885ae89f4SRuslan Bukin return (ENXIO); 95985ae89f4SRuslan Bukin } 96085ae89f4SRuslan Bukin 96185ae89f4SRuslan Bukin /* Memory interface */ 96285ae89f4SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 96385ae89f4SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 96485ae89f4SRuslan Bukin 96585ae89f4SRuslan Bukin device_printf(sc->dev, "Identification: %x\n", 96685ae89f4SRuslan Bukin READ4(sc, XAE_IDENT)); 96785ae89f4SRuslan Bukin 96885ae89f4SRuslan Bukin /* Get MAC addr */ 96985ae89f4SRuslan Bukin if (xae_get_hwaddr(sc, sc->macaddr)) { 97085ae89f4SRuslan Bukin device_printf(sc->dev, "can't get mac\n"); 97185ae89f4SRuslan Bukin return (ENXIO); 97285ae89f4SRuslan Bukin } 97385ae89f4SRuslan Bukin 97485ae89f4SRuslan Bukin /* Enable MII clock */ 97585ae89f4SRuslan Bukin reg = (MDIO_CLK_DIV_DEFAULT << MDIO_SETUP_CLK_DIV_S); 97685ae89f4SRuslan Bukin reg |= MDIO_SETUP_ENABLE; 97785ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_SETUP, reg); 97885ae89f4SRuslan Bukin if (mdio_wait(sc)) 97985ae89f4SRuslan Bukin return (ENXIO); 98085ae89f4SRuslan Bukin 98185ae89f4SRuslan Bukin callout_init_mtx(&sc->xae_callout, &sc->mtx, 0); 98285ae89f4SRuslan Bukin 98385ae89f4SRuslan Bukin /* Setup interrupt handler. */ 98485ae89f4SRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 98585ae89f4SRuslan Bukin NULL, xae_intr, sc, &sc->intr_cookie); 98685ae89f4SRuslan Bukin if (error != 0) { 98785ae89f4SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 98885ae89f4SRuslan Bukin return (ENXIO); 98985ae89f4SRuslan Bukin } 99085ae89f4SRuslan Bukin 99185ae89f4SRuslan Bukin /* Set up the ethernet interface. */ 99285ae89f4SRuslan Bukin sc->ifp = ifp = if_alloc(IFT_ETHER); 993dba12f75SJustin Hibbits if_setsoftc(ifp, sc); 99485ae89f4SRuslan Bukin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 995dba12f75SJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 996dba12f75SJustin Hibbits if_setcapabilities(ifp, IFCAP_VLAN_MTU); 997dba12f75SJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 998dba12f75SJustin Hibbits if_settransmitfn(ifp, xae_transmit); 999dba12f75SJustin Hibbits if_setqflushfn(ifp, xae_qflush); 1000dba12f75SJustin Hibbits if_setioctlfn(ifp, xae_ioctl); 1001dba12f75SJustin Hibbits if_setinitfn(ifp, xae_init); 1002dba12f75SJustin Hibbits if_setsendqlen(ifp, TX_DESC_COUNT - 1); 1003dba12f75SJustin Hibbits if_setsendqready(ifp); 100485ae89f4SRuslan Bukin 100585ae89f4SRuslan Bukin if (xae_get_phyaddr(node, &sc->phy_addr) != 0) 100685ae89f4SRuslan Bukin return (ENXIO); 100785ae89f4SRuslan Bukin 100885ae89f4SRuslan Bukin /* Attach the mii driver. */ 100985ae89f4SRuslan Bukin error = mii_attach(dev, &sc->miibus, ifp, xae_media_change, 101085ae89f4SRuslan Bukin xae_media_status, BMSR_DEFCAPMASK, sc->phy_addr, 101185ae89f4SRuslan Bukin MII_OFFSET_ANY, 0); 101285ae89f4SRuslan Bukin 101385ae89f4SRuslan Bukin if (error != 0) { 101485ae89f4SRuslan Bukin device_printf(dev, "PHY attach failed\n"); 101585ae89f4SRuslan Bukin return (ENXIO); 101685ae89f4SRuslan Bukin } 101785ae89f4SRuslan Bukin sc->mii_softc = device_get_softc(sc->miibus); 101885ae89f4SRuslan Bukin 101985ae89f4SRuslan Bukin /* Apply vcu118 workaround. */ 102085ae89f4SRuslan Bukin if (OF_getproplen(node, "xlnx,vcu118") >= 0) 102185ae89f4SRuslan Bukin xae_phy_fixup(sc); 102285ae89f4SRuslan Bukin 102385ae89f4SRuslan Bukin /* All ready to run, attach the ethernet interface. */ 102485ae89f4SRuslan Bukin ether_ifattach(ifp, sc->macaddr); 102585ae89f4SRuslan Bukin sc->is_attached = true; 102685ae89f4SRuslan Bukin 102785ae89f4SRuslan Bukin xae_rx_enqueue(sc, NUM_RX_MBUF); 102885ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_rx); 102985ae89f4SRuslan Bukin 103085ae89f4SRuslan Bukin return (0); 103185ae89f4SRuslan Bukin } 103285ae89f4SRuslan Bukin 103385ae89f4SRuslan Bukin static int 103485ae89f4SRuslan Bukin xae_detach(device_t dev) 103585ae89f4SRuslan Bukin { 103685ae89f4SRuslan Bukin struct xae_softc *sc; 1037dba12f75SJustin Hibbits if_t ifp; 103885ae89f4SRuslan Bukin 103985ae89f4SRuslan Bukin sc = device_get_softc(dev); 104085ae89f4SRuslan Bukin 104185ae89f4SRuslan Bukin KASSERT(mtx_initialized(&sc->mtx), ("%s: mutex not initialized", 104285ae89f4SRuslan Bukin device_get_nameunit(dev))); 104385ae89f4SRuslan Bukin 104485ae89f4SRuslan Bukin ifp = sc->ifp; 104585ae89f4SRuslan Bukin 104685ae89f4SRuslan Bukin /* Only cleanup if attach succeeded. */ 104785ae89f4SRuslan Bukin if (device_is_attached(dev)) { 104885ae89f4SRuslan Bukin XAE_LOCK(sc); 104985ae89f4SRuslan Bukin xae_stop_locked(sc); 105085ae89f4SRuslan Bukin XAE_UNLOCK(sc); 105185ae89f4SRuslan Bukin callout_drain(&sc->xae_callout); 105285ae89f4SRuslan Bukin ether_ifdetach(ifp); 105385ae89f4SRuslan Bukin } 105485ae89f4SRuslan Bukin 1055*11a91178SJohn Baldwin bus_generic_detach(dev); 105685ae89f4SRuslan Bukin 105785ae89f4SRuslan Bukin if (ifp != NULL) 105885ae89f4SRuslan Bukin if_free(ifp); 105985ae89f4SRuslan Bukin 106085ae89f4SRuslan Bukin mtx_destroy(&sc->mtx); 106185ae89f4SRuslan Bukin 106285ae89f4SRuslan Bukin bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 106385ae89f4SRuslan Bukin 106485ae89f4SRuslan Bukin bus_release_resources(dev, xae_spec, sc->res); 106585ae89f4SRuslan Bukin 106685ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_tx); 106785ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_rx); 106885ae89f4SRuslan Bukin xdma_put(sc->xdma_tx); 106985ae89f4SRuslan Bukin xdma_put(sc->xdma_rx); 107085ae89f4SRuslan Bukin 107185ae89f4SRuslan Bukin return (0); 107285ae89f4SRuslan Bukin } 107385ae89f4SRuslan Bukin 107485ae89f4SRuslan Bukin static void 107585ae89f4SRuslan Bukin xae_miibus_statchg(device_t dev) 107685ae89f4SRuslan Bukin { 107785ae89f4SRuslan Bukin struct xae_softc *sc; 107885ae89f4SRuslan Bukin struct mii_data *mii; 107985ae89f4SRuslan Bukin uint32_t reg; 108085ae89f4SRuslan Bukin 108185ae89f4SRuslan Bukin /* 108285ae89f4SRuslan Bukin * Called by the MII bus driver when the PHY establishes 108385ae89f4SRuslan Bukin * link to set the MAC interface registers. 108485ae89f4SRuslan Bukin */ 108585ae89f4SRuslan Bukin 108685ae89f4SRuslan Bukin sc = device_get_softc(dev); 108785ae89f4SRuslan Bukin 108885ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 108985ae89f4SRuslan Bukin 109085ae89f4SRuslan Bukin mii = sc->mii_softc; 109185ae89f4SRuslan Bukin 109285ae89f4SRuslan Bukin if (mii->mii_media_status & IFM_ACTIVE) 109385ae89f4SRuslan Bukin sc->link_is_up = true; 109485ae89f4SRuslan Bukin else 109585ae89f4SRuslan Bukin sc->link_is_up = false; 109685ae89f4SRuslan Bukin 109785ae89f4SRuslan Bukin switch (IFM_SUBTYPE(mii->mii_media_active)) { 109885ae89f4SRuslan Bukin case IFM_1000_T: 109985ae89f4SRuslan Bukin case IFM_1000_SX: 110085ae89f4SRuslan Bukin reg = SPEED_1000; 110185ae89f4SRuslan Bukin break; 110285ae89f4SRuslan Bukin case IFM_100_TX: 110385ae89f4SRuslan Bukin reg = SPEED_100; 110485ae89f4SRuslan Bukin break; 110585ae89f4SRuslan Bukin case IFM_10_T: 110685ae89f4SRuslan Bukin reg = SPEED_10; 110785ae89f4SRuslan Bukin break; 110885ae89f4SRuslan Bukin case IFM_NONE: 110985ae89f4SRuslan Bukin sc->link_is_up = false; 111085ae89f4SRuslan Bukin return; 111185ae89f4SRuslan Bukin default: 111285ae89f4SRuslan Bukin sc->link_is_up = false; 111385ae89f4SRuslan Bukin device_printf(dev, "Unsupported media %u\n", 111485ae89f4SRuslan Bukin IFM_SUBTYPE(mii->mii_media_active)); 111585ae89f4SRuslan Bukin return; 111685ae89f4SRuslan Bukin } 111785ae89f4SRuslan Bukin 111885ae89f4SRuslan Bukin WRITE4(sc, XAE_SPEED, reg); 111985ae89f4SRuslan Bukin } 112085ae89f4SRuslan Bukin 112185ae89f4SRuslan Bukin static device_method_t xae_methods[] = { 112285ae89f4SRuslan Bukin DEVMETHOD(device_probe, xae_probe), 112385ae89f4SRuslan Bukin DEVMETHOD(device_attach, xae_attach), 112485ae89f4SRuslan Bukin DEVMETHOD(device_detach, xae_detach), 112585ae89f4SRuslan Bukin 112685ae89f4SRuslan Bukin /* MII Interface */ 112785ae89f4SRuslan Bukin DEVMETHOD(miibus_readreg, xae_miibus_read_reg), 112885ae89f4SRuslan Bukin DEVMETHOD(miibus_writereg, xae_miibus_write_reg), 112985ae89f4SRuslan Bukin DEVMETHOD(miibus_statchg, xae_miibus_statchg), 113085ae89f4SRuslan Bukin { 0, 0 } 113185ae89f4SRuslan Bukin }; 113285ae89f4SRuslan Bukin 113385ae89f4SRuslan Bukin driver_t xae_driver = { 113485ae89f4SRuslan Bukin "xae", 113585ae89f4SRuslan Bukin xae_methods, 113685ae89f4SRuslan Bukin sizeof(struct xae_softc), 113785ae89f4SRuslan Bukin }; 113885ae89f4SRuslan Bukin 113990b8b224SJohn Baldwin DRIVER_MODULE(xae, simplebus, xae_driver, 0, 0); 11403e38757dSJohn Baldwin DRIVER_MODULE(miibus, xae, miibus_driver, 0, 0); 114185ae89f4SRuslan Bukin 114285ae89f4SRuslan Bukin MODULE_DEPEND(xae, ether, 1, 1, 1); 114385ae89f4SRuslan Bukin MODULE_DEPEND(xae, miibus, 1, 1, 1); 1144