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/cdefs.h> 3485ae89f4SRuslan Bukin __FBSDID("$FreeBSD$"); 3585ae89f4SRuslan Bukin 3685ae89f4SRuslan Bukin #include <sys/param.h> 3785ae89f4SRuslan Bukin #include <sys/systm.h> 3885ae89f4SRuslan Bukin #include <sys/bus.h> 3985ae89f4SRuslan Bukin #include <sys/kernel.h> 4085ae89f4SRuslan Bukin #include <sys/lock.h> 4185ae89f4SRuslan Bukin #include <sys/malloc.h> 4285ae89f4SRuslan Bukin #include <sys/mbuf.h> 4385ae89f4SRuslan Bukin #include <sys/module.h> 4485ae89f4SRuslan Bukin #include <sys/mutex.h> 4585ae89f4SRuslan Bukin #include <sys/rman.h> 4685ae89f4SRuslan Bukin #include <sys/socket.h> 4785ae89f4SRuslan Bukin #include <sys/sockio.h> 4885ae89f4SRuslan Bukin 4985ae89f4SRuslan Bukin #include <net/bpf.h> 5085ae89f4SRuslan Bukin #include <net/if.h> 5185ae89f4SRuslan Bukin #include <net/ethernet.h> 5285ae89f4SRuslan Bukin #include <net/if_dl.h> 5385ae89f4SRuslan Bukin #include <net/if_media.h> 5485ae89f4SRuslan Bukin #include <net/if_types.h> 5585ae89f4SRuslan Bukin #include <net/if_var.h> 5685ae89f4SRuslan Bukin 5785ae89f4SRuslan Bukin #include <machine/bus.h> 5885ae89f4SRuslan Bukin 5985ae89f4SRuslan Bukin #include <dev/mii/mii.h> 6085ae89f4SRuslan Bukin #include <dev/mii/miivar.h> 6185ae89f4SRuslan Bukin #include <dev/mii/tiphy.h> 6285ae89f4SRuslan Bukin #include <dev/ofw/ofw_bus.h> 6385ae89f4SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 6485ae89f4SRuslan Bukin #include <dev/xilinx/if_xaereg.h> 6585ae89f4SRuslan Bukin #include <dev/xilinx/if_xaevar.h> 6685ae89f4SRuslan Bukin 67a8692c16SRuslan Bukin #include <dev/xilinx/axidma.h> 68a8692c16SRuslan Bukin 6985ae89f4SRuslan Bukin #include "miibus_if.h" 7085ae89f4SRuslan Bukin 7185ae89f4SRuslan Bukin #define READ4(_sc, _reg) \ 7285ae89f4SRuslan Bukin bus_read_4((_sc)->res[0], _reg) 7385ae89f4SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 7485ae89f4SRuslan Bukin bus_write_4((_sc)->res[0], _reg, _val) 7585ae89f4SRuslan Bukin 7685ae89f4SRuslan Bukin #define READ8(_sc, _reg) \ 7785ae89f4SRuslan Bukin bus_read_8((_sc)->res[0], _reg) 7885ae89f4SRuslan Bukin #define WRITE8(_sc, _reg, _val) \ 7985ae89f4SRuslan Bukin bus_write_8((_sc)->res[0], _reg, _val) 8085ae89f4SRuslan Bukin 8185ae89f4SRuslan Bukin #define XAE_LOCK(sc) mtx_lock(&(sc)->mtx) 8285ae89f4SRuslan Bukin #define XAE_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 8385ae89f4SRuslan Bukin #define XAE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) 8485ae89f4SRuslan Bukin #define XAE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) 8585ae89f4SRuslan Bukin 8685ae89f4SRuslan Bukin #define XAE_DEBUG 8785ae89f4SRuslan Bukin #undef XAE_DEBUG 8885ae89f4SRuslan Bukin 8985ae89f4SRuslan Bukin #ifdef XAE_DEBUG 9085ae89f4SRuslan Bukin #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) 9185ae89f4SRuslan Bukin #else 9285ae89f4SRuslan Bukin #define dprintf(fmt, ...) 9385ae89f4SRuslan Bukin #endif 9485ae89f4SRuslan Bukin 9585ae89f4SRuslan Bukin #define RX_QUEUE_SIZE 64 9685ae89f4SRuslan Bukin #define TX_QUEUE_SIZE 64 9785ae89f4SRuslan Bukin #define NUM_RX_MBUF 16 9885ae89f4SRuslan Bukin #define BUFRING_SIZE 8192 9985ae89f4SRuslan Bukin #define MDIO_CLK_DIV_DEFAULT 29 10085ae89f4SRuslan Bukin 10185ae89f4SRuslan Bukin #define PHY1_RD(sc, _r) \ 10285ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, 1, _r) 10385ae89f4SRuslan Bukin #define PHY1_WR(sc, _r, _v) \ 10485ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, 1, _r, _v) 10585ae89f4SRuslan Bukin 10685ae89f4SRuslan Bukin #define PHY_RD(sc, _r) \ 10785ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, sc->phy_addr, _r) 10885ae89f4SRuslan Bukin #define PHY_WR(sc, _r, _v) \ 10985ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, sc->phy_addr, _r, _v) 11085ae89f4SRuslan Bukin 11185ae89f4SRuslan Bukin /* Use this macro to access regs > 0x1f */ 11285ae89f4SRuslan Bukin #define WRITE_TI_EREG(sc, reg, data) { \ 11385ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK); \ 11485ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, reg); \ 11585ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK | MMDACR_FN_DATANPI); \ 11685ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, data); \ 11785ae89f4SRuslan Bukin } 11885ae89f4SRuslan Bukin 11985ae89f4SRuslan Bukin /* Not documented, Xilinx VCU118 workaround */ 12085ae89f4SRuslan Bukin #define CFG4_SGMII_TMR 0x160 /* bits 8:7 MUST be '10' */ 12185ae89f4SRuslan Bukin #define DP83867_SGMIICTL1 0xD3 /* not documented register */ 12285ae89f4SRuslan Bukin #define SGMIICTL1_SGMII_6W (1 << 14) /* no idea what it is */ 12385ae89f4SRuslan Bukin 12485ae89f4SRuslan Bukin static struct resource_spec xae_spec[] = { 12585ae89f4SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 12685ae89f4SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 12785ae89f4SRuslan Bukin { -1, 0 } 12885ae89f4SRuslan Bukin }; 12985ae89f4SRuslan Bukin 13085ae89f4SRuslan Bukin static void xae_stop_locked(struct xae_softc *sc); 13185ae89f4SRuslan Bukin static void xae_setup_rxfilter(struct xae_softc *sc); 13285ae89f4SRuslan Bukin 13385ae89f4SRuslan Bukin static int 13485ae89f4SRuslan Bukin xae_rx_enqueue(struct xae_softc *sc, uint32_t n) 13585ae89f4SRuslan Bukin { 13685ae89f4SRuslan Bukin struct mbuf *m; 13785ae89f4SRuslan Bukin int i; 13885ae89f4SRuslan Bukin 13985ae89f4SRuslan Bukin for (i = 0; i < n; i++) { 14085ae89f4SRuslan Bukin m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 14185ae89f4SRuslan Bukin if (m == NULL) { 14285ae89f4SRuslan Bukin device_printf(sc->dev, 14385ae89f4SRuslan Bukin "%s: Can't alloc rx mbuf\n", __func__); 14485ae89f4SRuslan Bukin return (-1); 14585ae89f4SRuslan Bukin } 14685ae89f4SRuslan Bukin 14785ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 14885ae89f4SRuslan Bukin xdma_enqueue_mbuf(sc->xchan_rx, &m, 0, 4, 4, XDMA_DEV_TO_MEM); 14985ae89f4SRuslan Bukin } 15085ae89f4SRuslan Bukin 15185ae89f4SRuslan Bukin return (0); 15285ae89f4SRuslan Bukin } 15385ae89f4SRuslan Bukin 15485ae89f4SRuslan Bukin static int 15585ae89f4SRuslan Bukin xae_get_phyaddr(phandle_t node, int *phy_addr) 15685ae89f4SRuslan Bukin { 15785ae89f4SRuslan Bukin phandle_t phy_node; 15885ae89f4SRuslan Bukin pcell_t phy_handle, phy_reg; 15985ae89f4SRuslan Bukin 16085ae89f4SRuslan Bukin if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, 16185ae89f4SRuslan Bukin sizeof(phy_handle)) <= 0) 16285ae89f4SRuslan Bukin return (ENXIO); 16385ae89f4SRuslan Bukin 16485ae89f4SRuslan Bukin phy_node = OF_node_from_xref(phy_handle); 16585ae89f4SRuslan Bukin 16685ae89f4SRuslan Bukin if (OF_getencprop(phy_node, "reg", (void *)&phy_reg, 16785ae89f4SRuslan Bukin sizeof(phy_reg)) <= 0) 16885ae89f4SRuslan Bukin return (ENXIO); 16985ae89f4SRuslan Bukin 17085ae89f4SRuslan Bukin *phy_addr = phy_reg; 17185ae89f4SRuslan Bukin 17285ae89f4SRuslan Bukin return (0); 17385ae89f4SRuslan Bukin } 17485ae89f4SRuslan Bukin 17585ae89f4SRuslan Bukin static int 17685ae89f4SRuslan Bukin xae_xdma_tx_intr(void *arg, xdma_transfer_status_t *status) 17785ae89f4SRuslan Bukin { 17885ae89f4SRuslan Bukin xdma_transfer_status_t st; 17985ae89f4SRuslan Bukin struct xae_softc *sc; 180*dba12f75SJustin Hibbits if_t ifp; 18185ae89f4SRuslan Bukin struct mbuf *m; 18285ae89f4SRuslan Bukin int err; 18385ae89f4SRuslan Bukin 18485ae89f4SRuslan Bukin sc = arg; 18585ae89f4SRuslan Bukin 18685ae89f4SRuslan Bukin XAE_LOCK(sc); 18785ae89f4SRuslan Bukin 18885ae89f4SRuslan Bukin ifp = sc->ifp; 18985ae89f4SRuslan Bukin 19085ae89f4SRuslan Bukin for (;;) { 19185ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_tx, &m, &st); 19285ae89f4SRuslan Bukin if (err != 0) { 19385ae89f4SRuslan Bukin break; 19485ae89f4SRuslan Bukin } 19585ae89f4SRuslan Bukin 19685ae89f4SRuslan Bukin if (st.error != 0) { 19785ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 19885ae89f4SRuslan Bukin } 19985ae89f4SRuslan Bukin 20085ae89f4SRuslan Bukin m_freem(m); 20185ae89f4SRuslan Bukin } 20285ae89f4SRuslan Bukin 203*dba12f75SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 20485ae89f4SRuslan Bukin 20585ae89f4SRuslan Bukin XAE_UNLOCK(sc); 20685ae89f4SRuslan Bukin 20785ae89f4SRuslan Bukin return (0); 20885ae89f4SRuslan Bukin } 20985ae89f4SRuslan Bukin 21085ae89f4SRuslan Bukin static int 21185ae89f4SRuslan Bukin xae_xdma_rx_intr(void *arg, xdma_transfer_status_t *status) 21285ae89f4SRuslan Bukin { 21385ae89f4SRuslan Bukin xdma_transfer_status_t st; 21485ae89f4SRuslan Bukin struct xae_softc *sc; 215*dba12f75SJustin Hibbits if_t ifp; 21685ae89f4SRuslan Bukin struct mbuf *m; 21785ae89f4SRuslan Bukin int err; 21885ae89f4SRuslan Bukin uint32_t cnt_processed; 21985ae89f4SRuslan Bukin 22085ae89f4SRuslan Bukin sc = arg; 22185ae89f4SRuslan Bukin 22285ae89f4SRuslan Bukin dprintf("%s\n", __func__); 22385ae89f4SRuslan Bukin 22485ae89f4SRuslan Bukin XAE_LOCK(sc); 22585ae89f4SRuslan Bukin 22685ae89f4SRuslan Bukin ifp = sc->ifp; 22785ae89f4SRuslan Bukin 22885ae89f4SRuslan Bukin cnt_processed = 0; 22985ae89f4SRuslan Bukin for (;;) { 23085ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_rx, &m, &st); 23185ae89f4SRuslan Bukin if (err != 0) { 23285ae89f4SRuslan Bukin break; 23385ae89f4SRuslan Bukin } 23485ae89f4SRuslan Bukin cnt_processed++; 23585ae89f4SRuslan Bukin 23685ae89f4SRuslan Bukin if (st.error != 0) { 23785ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 23885ae89f4SRuslan Bukin m_freem(m); 23985ae89f4SRuslan Bukin continue; 24085ae89f4SRuslan Bukin } 24185ae89f4SRuslan Bukin 24285ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = st.transferred; 24385ae89f4SRuslan Bukin m->m_pkthdr.rcvif = ifp; 24485ae89f4SRuslan Bukin XAE_UNLOCK(sc); 245*dba12f75SJustin Hibbits if_input(ifp, m); 24685ae89f4SRuslan Bukin XAE_LOCK(sc); 24785ae89f4SRuslan Bukin } 24885ae89f4SRuslan Bukin 24985ae89f4SRuslan Bukin xae_rx_enqueue(sc, cnt_processed); 25085ae89f4SRuslan Bukin 25185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 25285ae89f4SRuslan Bukin 25385ae89f4SRuslan Bukin return (0); 25485ae89f4SRuslan Bukin } 25585ae89f4SRuslan Bukin 25685ae89f4SRuslan Bukin static void 257*dba12f75SJustin Hibbits xae_qflush(if_t ifp) 25885ae89f4SRuslan Bukin { 25985ae89f4SRuslan Bukin } 26085ae89f4SRuslan Bukin 26185ae89f4SRuslan Bukin static int 262*dba12f75SJustin Hibbits xae_transmit_locked(if_t ifp) 26385ae89f4SRuslan Bukin { 26485ae89f4SRuslan Bukin struct xae_softc *sc; 26585ae89f4SRuslan Bukin struct mbuf *m; 26685ae89f4SRuslan Bukin struct buf_ring *br; 26785ae89f4SRuslan Bukin int error; 26885ae89f4SRuslan Bukin int enq; 26985ae89f4SRuslan Bukin 27085ae89f4SRuslan Bukin dprintf("%s\n", __func__); 27185ae89f4SRuslan Bukin 272*dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 27385ae89f4SRuslan Bukin br = sc->br; 27485ae89f4SRuslan Bukin 27585ae89f4SRuslan Bukin enq = 0; 27685ae89f4SRuslan Bukin 27785ae89f4SRuslan Bukin while ((m = drbr_peek(ifp, br)) != NULL) { 27885ae89f4SRuslan Bukin error = xdma_enqueue_mbuf(sc->xchan_tx, 27985ae89f4SRuslan Bukin &m, 0, 4, 4, XDMA_MEM_TO_DEV); 28085ae89f4SRuslan Bukin if (error != 0) { 28185ae89f4SRuslan Bukin /* No space in request queue available yet. */ 28285ae89f4SRuslan Bukin drbr_putback(ifp, br, m); 28385ae89f4SRuslan Bukin break; 28485ae89f4SRuslan Bukin } 28585ae89f4SRuslan Bukin 28685ae89f4SRuslan Bukin drbr_advance(ifp, br); 28785ae89f4SRuslan Bukin 28885ae89f4SRuslan Bukin enq++; 28985ae89f4SRuslan Bukin 29085ae89f4SRuslan Bukin /* If anyone is interested give them a copy. */ 29185ae89f4SRuslan Bukin ETHER_BPF_MTAP(ifp, m); 29285ae89f4SRuslan Bukin } 29385ae89f4SRuslan Bukin 29485ae89f4SRuslan Bukin if (enq > 0) 29585ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_tx); 29685ae89f4SRuslan Bukin 29785ae89f4SRuslan Bukin return (0); 29885ae89f4SRuslan Bukin } 29985ae89f4SRuslan Bukin 30085ae89f4SRuslan Bukin static int 301*dba12f75SJustin Hibbits xae_transmit(if_t ifp, struct mbuf *m) 30285ae89f4SRuslan Bukin { 30385ae89f4SRuslan Bukin struct xae_softc *sc; 30485ae89f4SRuslan Bukin int error; 30585ae89f4SRuslan Bukin 30685ae89f4SRuslan Bukin dprintf("%s\n", __func__); 30785ae89f4SRuslan Bukin 308*dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 30985ae89f4SRuslan Bukin 31085ae89f4SRuslan Bukin XAE_LOCK(sc); 31185ae89f4SRuslan Bukin 31285ae89f4SRuslan Bukin error = drbr_enqueue(ifp, sc->br, m); 31385ae89f4SRuslan Bukin if (error) { 31485ae89f4SRuslan Bukin XAE_UNLOCK(sc); 31585ae89f4SRuslan Bukin return (error); 31685ae89f4SRuslan Bukin } 31785ae89f4SRuslan Bukin 318*dba12f75SJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 31985ae89f4SRuslan Bukin IFF_DRV_RUNNING) { 32085ae89f4SRuslan Bukin XAE_UNLOCK(sc); 32185ae89f4SRuslan Bukin return (0); 32285ae89f4SRuslan Bukin } 32385ae89f4SRuslan Bukin 32485ae89f4SRuslan Bukin if (!sc->link_is_up) { 32585ae89f4SRuslan Bukin XAE_UNLOCK(sc); 32685ae89f4SRuslan Bukin return (0); 32785ae89f4SRuslan Bukin } 32885ae89f4SRuslan Bukin 32985ae89f4SRuslan Bukin error = xae_transmit_locked(ifp); 33085ae89f4SRuslan Bukin 33185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 33285ae89f4SRuslan Bukin 33385ae89f4SRuslan Bukin return (error); 33485ae89f4SRuslan Bukin } 33585ae89f4SRuslan Bukin 33685ae89f4SRuslan Bukin static void 33785ae89f4SRuslan Bukin xae_stop_locked(struct xae_softc *sc) 33885ae89f4SRuslan Bukin { 339*dba12f75SJustin Hibbits if_t ifp; 34085ae89f4SRuslan Bukin uint32_t reg; 34185ae89f4SRuslan Bukin 34285ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 34385ae89f4SRuslan Bukin 34485ae89f4SRuslan Bukin ifp = sc->ifp; 345*dba12f75SJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 34685ae89f4SRuslan Bukin 34785ae89f4SRuslan Bukin callout_stop(&sc->xae_callout); 34885ae89f4SRuslan Bukin 34985ae89f4SRuslan Bukin /* Stop the transmitter */ 35085ae89f4SRuslan Bukin reg = READ4(sc, XAE_TC); 35185ae89f4SRuslan Bukin reg &= ~TC_TX; 35285ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, reg); 35385ae89f4SRuslan Bukin 35485ae89f4SRuslan Bukin /* Stop the receiver. */ 35585ae89f4SRuslan Bukin reg = READ4(sc, XAE_RCW1); 35685ae89f4SRuslan Bukin reg &= ~RCW1_RX; 35785ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, reg); 35885ae89f4SRuslan Bukin } 35985ae89f4SRuslan Bukin 36085ae89f4SRuslan Bukin static uint64_t 36185ae89f4SRuslan Bukin xae_stat(struct xae_softc *sc, int counter_id) 36285ae89f4SRuslan Bukin { 36385ae89f4SRuslan Bukin uint64_t new, old; 36485ae89f4SRuslan Bukin uint64_t delta; 36585ae89f4SRuslan Bukin 36685ae89f4SRuslan Bukin KASSERT(counter_id < XAE_MAX_COUNTERS, 36785ae89f4SRuslan Bukin ("counter %d is out of range", counter_id)); 36885ae89f4SRuslan Bukin 36985ae89f4SRuslan Bukin new = READ8(sc, XAE_STATCNT(counter_id)); 37085ae89f4SRuslan Bukin old = sc->counters[counter_id]; 37185ae89f4SRuslan Bukin 37285ae89f4SRuslan Bukin if (new >= old) 37385ae89f4SRuslan Bukin delta = new - old; 37485ae89f4SRuslan Bukin else 37585ae89f4SRuslan Bukin delta = UINT64_MAX - old + new; 37685ae89f4SRuslan Bukin sc->counters[counter_id] = new; 37785ae89f4SRuslan Bukin 37885ae89f4SRuslan Bukin return (delta); 37985ae89f4SRuslan Bukin } 38085ae89f4SRuslan Bukin 38185ae89f4SRuslan Bukin static void 38285ae89f4SRuslan Bukin xae_harvest_stats(struct xae_softc *sc) 38385ae89f4SRuslan Bukin { 384*dba12f75SJustin Hibbits if_t ifp; 38585ae89f4SRuslan Bukin 38685ae89f4SRuslan Bukin ifp = sc->ifp; 38785ae89f4SRuslan Bukin 38885ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IPACKETS, xae_stat(sc, RX_GOOD_FRAMES)); 38985ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IMCASTS, xae_stat(sc, RX_GOOD_MCASTS)); 39085ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 39185ae89f4SRuslan Bukin xae_stat(sc, RX_FRAME_CHECK_SEQ_ERROR) + 39285ae89f4SRuslan Bukin xae_stat(sc, RX_LEN_OUT_OF_RANGE) + 39385ae89f4SRuslan Bukin xae_stat(sc, RX_ALIGNMENT_ERRORS)); 39485ae89f4SRuslan Bukin 39585ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OBYTES, xae_stat(sc, TX_BYTES)); 39685ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OPACKETS, xae_stat(sc, TX_GOOD_FRAMES)); 39785ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OMCASTS, xae_stat(sc, TX_GOOD_MCASTS)); 39885ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 39985ae89f4SRuslan Bukin xae_stat(sc, TX_GOOD_UNDERRUN_ERRORS)); 40085ae89f4SRuslan Bukin 40185ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 40285ae89f4SRuslan Bukin xae_stat(sc, TX_SINGLE_COLLISION_FRAMES) + 40385ae89f4SRuslan Bukin xae_stat(sc, TX_MULTI_COLLISION_FRAMES) + 40485ae89f4SRuslan Bukin xae_stat(sc, TX_LATE_COLLISIONS) + 40585ae89f4SRuslan Bukin xae_stat(sc, TX_EXCESS_COLLISIONS)); 40685ae89f4SRuslan Bukin } 40785ae89f4SRuslan Bukin 40885ae89f4SRuslan Bukin static void 40985ae89f4SRuslan Bukin xae_tick(void *arg) 41085ae89f4SRuslan Bukin { 41185ae89f4SRuslan Bukin struct xae_softc *sc; 412*dba12f75SJustin Hibbits if_t ifp; 41385ae89f4SRuslan Bukin int link_was_up; 41485ae89f4SRuslan Bukin 41585ae89f4SRuslan Bukin sc = arg; 41685ae89f4SRuslan Bukin 41785ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 41885ae89f4SRuslan Bukin 41985ae89f4SRuslan Bukin ifp = sc->ifp; 42085ae89f4SRuslan Bukin 421*dba12f75SJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) 42285ae89f4SRuslan Bukin return; 42385ae89f4SRuslan Bukin 42485ae89f4SRuslan Bukin /* Gather stats from hardware counters. */ 42585ae89f4SRuslan Bukin xae_harvest_stats(sc); 42685ae89f4SRuslan Bukin 42785ae89f4SRuslan Bukin /* Check the media status. */ 42885ae89f4SRuslan Bukin link_was_up = sc->link_is_up; 42985ae89f4SRuslan Bukin mii_tick(sc->mii_softc); 43085ae89f4SRuslan Bukin if (sc->link_is_up && !link_was_up) 43185ae89f4SRuslan Bukin xae_transmit_locked(sc->ifp); 43285ae89f4SRuslan Bukin 43385ae89f4SRuslan Bukin /* Schedule another check one second from now. */ 43485ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 43585ae89f4SRuslan Bukin } 43685ae89f4SRuslan Bukin 43785ae89f4SRuslan Bukin static void 43885ae89f4SRuslan Bukin xae_init_locked(struct xae_softc *sc) 43985ae89f4SRuslan Bukin { 440*dba12f75SJustin Hibbits if_t ifp; 44185ae89f4SRuslan Bukin 44285ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 44385ae89f4SRuslan Bukin 44485ae89f4SRuslan Bukin ifp = sc->ifp; 445*dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 44685ae89f4SRuslan Bukin return; 44785ae89f4SRuslan Bukin 448*dba12f75SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 44985ae89f4SRuslan Bukin 45085ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 45185ae89f4SRuslan Bukin 45285ae89f4SRuslan Bukin /* Enable the transmitter */ 45385ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, TC_TX); 45485ae89f4SRuslan Bukin 45585ae89f4SRuslan Bukin /* Enable the receiver. */ 45685ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, RCW1_RX); 45785ae89f4SRuslan Bukin 45885ae89f4SRuslan Bukin /* 45985ae89f4SRuslan Bukin * Call mii_mediachg() which will call back into xae_miibus_statchg() 46085ae89f4SRuslan Bukin * to set up the remaining config registers based on current media. 46185ae89f4SRuslan Bukin */ 46285ae89f4SRuslan Bukin mii_mediachg(sc->mii_softc); 46385ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 46485ae89f4SRuslan Bukin } 46585ae89f4SRuslan Bukin 46685ae89f4SRuslan Bukin static void 46785ae89f4SRuslan Bukin xae_init(void *arg) 46885ae89f4SRuslan Bukin { 46985ae89f4SRuslan Bukin struct xae_softc *sc; 47085ae89f4SRuslan Bukin 47185ae89f4SRuslan Bukin sc = arg; 47285ae89f4SRuslan Bukin 47385ae89f4SRuslan Bukin XAE_LOCK(sc); 47485ae89f4SRuslan Bukin xae_init_locked(sc); 47585ae89f4SRuslan Bukin XAE_UNLOCK(sc); 47685ae89f4SRuslan Bukin } 47785ae89f4SRuslan Bukin 47885ae89f4SRuslan Bukin static void 479*dba12f75SJustin Hibbits xae_media_status(if_t ifp, struct ifmediareq *ifmr) 48085ae89f4SRuslan Bukin { 48185ae89f4SRuslan Bukin struct xae_softc *sc; 48285ae89f4SRuslan Bukin struct mii_data *mii; 48385ae89f4SRuslan Bukin 484*dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 48585ae89f4SRuslan Bukin mii = sc->mii_softc; 48685ae89f4SRuslan Bukin 48785ae89f4SRuslan Bukin XAE_LOCK(sc); 48885ae89f4SRuslan Bukin mii_pollstat(mii); 48985ae89f4SRuslan Bukin ifmr->ifm_active = mii->mii_media_active; 49085ae89f4SRuslan Bukin ifmr->ifm_status = mii->mii_media_status; 49185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 49285ae89f4SRuslan Bukin } 49385ae89f4SRuslan Bukin 49485ae89f4SRuslan Bukin static int 49585ae89f4SRuslan Bukin xae_media_change_locked(struct xae_softc *sc) 49685ae89f4SRuslan Bukin { 49785ae89f4SRuslan Bukin 49885ae89f4SRuslan Bukin return (mii_mediachg(sc->mii_softc)); 49985ae89f4SRuslan Bukin } 50085ae89f4SRuslan Bukin 50185ae89f4SRuslan Bukin static int 502*dba12f75SJustin Hibbits xae_media_change(if_t ifp) 50385ae89f4SRuslan Bukin { 50485ae89f4SRuslan Bukin struct xae_softc *sc; 50585ae89f4SRuslan Bukin int error; 50685ae89f4SRuslan Bukin 507*dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 50885ae89f4SRuslan Bukin 50985ae89f4SRuslan Bukin XAE_LOCK(sc); 51085ae89f4SRuslan Bukin error = xae_media_change_locked(sc); 51185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 51285ae89f4SRuslan Bukin 51385ae89f4SRuslan Bukin return (error); 51485ae89f4SRuslan Bukin } 51585ae89f4SRuslan Bukin 5164d50c26aSGleb Smirnoff static u_int 5174d50c26aSGleb Smirnoff xae_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 5184d50c26aSGleb Smirnoff { 5194d50c26aSGleb Smirnoff struct xae_softc *sc = arg; 5204d50c26aSGleb Smirnoff uint32_t reg; 5214d50c26aSGleb Smirnoff uint8_t *ma; 5224d50c26aSGleb Smirnoff 5234d50c26aSGleb Smirnoff if (cnt >= XAE_MULTICAST_TABLE_SIZE) 5244d50c26aSGleb Smirnoff return (1); 5254d50c26aSGleb Smirnoff 5264d50c26aSGleb Smirnoff ma = LLADDR(sdl); 5274d50c26aSGleb Smirnoff 5284d50c26aSGleb Smirnoff reg = READ4(sc, XAE_FFC) & 0xffffff00; 5294d50c26aSGleb Smirnoff reg |= cnt; 5304d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFC, reg); 5314d50c26aSGleb Smirnoff 5324d50c26aSGleb Smirnoff reg = (ma[0]); 5334d50c26aSGleb Smirnoff reg |= (ma[1] << 8); 5344d50c26aSGleb Smirnoff reg |= (ma[2] << 16); 5354d50c26aSGleb Smirnoff reg |= (ma[3] << 24); 5364d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFV(0), reg); 5374d50c26aSGleb Smirnoff 5384d50c26aSGleb Smirnoff reg = ma[4]; 5394d50c26aSGleb Smirnoff reg |= ma[5] << 8; 5404d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFV(1), reg); 5414d50c26aSGleb Smirnoff 5424d50c26aSGleb Smirnoff return (1); 5434d50c26aSGleb Smirnoff } 5444d50c26aSGleb Smirnoff 54585ae89f4SRuslan Bukin static void 54685ae89f4SRuslan Bukin xae_setup_rxfilter(struct xae_softc *sc) 54785ae89f4SRuslan Bukin { 548*dba12f75SJustin Hibbits if_t ifp; 54985ae89f4SRuslan Bukin uint32_t reg; 55085ae89f4SRuslan Bukin 55185ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 55285ae89f4SRuslan Bukin 55385ae89f4SRuslan Bukin ifp = sc->ifp; 55485ae89f4SRuslan Bukin 55585ae89f4SRuslan Bukin /* 55685ae89f4SRuslan Bukin * Set the multicast (group) filter hash. 55785ae89f4SRuslan Bukin */ 558*dba12f75SJustin Hibbits if ((if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 55985ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 56085ae89f4SRuslan Bukin reg |= FFC_PM; 56185ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 56285ae89f4SRuslan Bukin } else { 56385ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 56485ae89f4SRuslan Bukin reg &= ~FFC_PM; 56585ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 56685ae89f4SRuslan Bukin 5674d50c26aSGleb Smirnoff if_foreach_llmaddr(ifp, xae_write_maddr, sc); 56885ae89f4SRuslan Bukin } 56985ae89f4SRuslan Bukin 57085ae89f4SRuslan Bukin /* 57185ae89f4SRuslan Bukin * Set the primary address. 57285ae89f4SRuslan Bukin */ 57385ae89f4SRuslan Bukin reg = sc->macaddr[0]; 57485ae89f4SRuslan Bukin reg |= (sc->macaddr[1] << 8); 57585ae89f4SRuslan Bukin reg |= (sc->macaddr[2] << 16); 57685ae89f4SRuslan Bukin reg |= (sc->macaddr[3] << 24); 57785ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW0, reg); 57885ae89f4SRuslan Bukin 57985ae89f4SRuslan Bukin reg = sc->macaddr[4]; 58085ae89f4SRuslan Bukin reg |= (sc->macaddr[5] << 8); 58185ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW1, reg); 58285ae89f4SRuslan Bukin } 58385ae89f4SRuslan Bukin 58485ae89f4SRuslan Bukin static int 585*dba12f75SJustin Hibbits xae_ioctl(if_t ifp, u_long cmd, caddr_t data) 58685ae89f4SRuslan Bukin { 58785ae89f4SRuslan Bukin struct xae_softc *sc; 58885ae89f4SRuslan Bukin struct mii_data *mii; 58985ae89f4SRuslan Bukin struct ifreq *ifr; 59085ae89f4SRuslan Bukin int mask, error; 59185ae89f4SRuslan Bukin 592*dba12f75SJustin Hibbits sc = if_getsoftc(ifp); 59385ae89f4SRuslan Bukin ifr = (struct ifreq *)data; 59485ae89f4SRuslan Bukin 59585ae89f4SRuslan Bukin error = 0; 59685ae89f4SRuslan Bukin switch (cmd) { 59785ae89f4SRuslan Bukin case SIOCSIFFLAGS: 59885ae89f4SRuslan Bukin XAE_LOCK(sc); 599*dba12f75SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 600*dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 601*dba12f75SJustin Hibbits if ((if_getflags(ifp) ^ sc->if_flags) & 60285ae89f4SRuslan Bukin (IFF_PROMISC | IFF_ALLMULTI)) 60385ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 60485ae89f4SRuslan Bukin } else { 60585ae89f4SRuslan Bukin if (!sc->is_detaching) 60685ae89f4SRuslan Bukin xae_init_locked(sc); 60785ae89f4SRuslan Bukin } 60885ae89f4SRuslan Bukin } else { 609*dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 61085ae89f4SRuslan Bukin xae_stop_locked(sc); 61185ae89f4SRuslan Bukin } 612*dba12f75SJustin Hibbits sc->if_flags = if_getflags(ifp); 61385ae89f4SRuslan Bukin XAE_UNLOCK(sc); 61485ae89f4SRuslan Bukin break; 61585ae89f4SRuslan Bukin case SIOCADDMULTI: 61685ae89f4SRuslan Bukin case SIOCDELMULTI: 617*dba12f75SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 61885ae89f4SRuslan Bukin XAE_LOCK(sc); 61985ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 62085ae89f4SRuslan Bukin XAE_UNLOCK(sc); 62185ae89f4SRuslan Bukin } 62285ae89f4SRuslan Bukin break; 62385ae89f4SRuslan Bukin case SIOCSIFMEDIA: 62485ae89f4SRuslan Bukin case SIOCGIFMEDIA: 62585ae89f4SRuslan Bukin mii = sc->mii_softc; 62685ae89f4SRuslan Bukin error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 62785ae89f4SRuslan Bukin break; 62885ae89f4SRuslan Bukin case SIOCSIFCAP: 629*dba12f75SJustin Hibbits mask = if_getcapenable(ifp) ^ ifr->ifr_reqcap; 63085ae89f4SRuslan Bukin if (mask & IFCAP_VLAN_MTU) { 63185ae89f4SRuslan Bukin /* No work to do except acknowledge the change took */ 632*dba12f75SJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_MTU); 63385ae89f4SRuslan Bukin } 63485ae89f4SRuslan Bukin break; 63585ae89f4SRuslan Bukin 63685ae89f4SRuslan Bukin default: 63785ae89f4SRuslan Bukin error = ether_ioctl(ifp, cmd, data); 63885ae89f4SRuslan Bukin break; 63985ae89f4SRuslan Bukin } 64085ae89f4SRuslan Bukin 64185ae89f4SRuslan Bukin return (error); 64285ae89f4SRuslan Bukin } 64385ae89f4SRuslan Bukin 64485ae89f4SRuslan Bukin static void 64585ae89f4SRuslan Bukin xae_intr(void *arg) 64685ae89f4SRuslan Bukin { 64785ae89f4SRuslan Bukin 64885ae89f4SRuslan Bukin } 64985ae89f4SRuslan Bukin 65085ae89f4SRuslan Bukin static int 65185ae89f4SRuslan Bukin xae_get_hwaddr(struct xae_softc *sc, uint8_t *hwaddr) 65285ae89f4SRuslan Bukin { 65385ae89f4SRuslan Bukin phandle_t node; 65485ae89f4SRuslan Bukin int len; 65585ae89f4SRuslan Bukin 65685ae89f4SRuslan Bukin node = ofw_bus_get_node(sc->dev); 65785ae89f4SRuslan Bukin 65885ae89f4SRuslan Bukin /* Check if there is property */ 65985ae89f4SRuslan Bukin if ((len = OF_getproplen(node, "local-mac-address")) <= 0) 66085ae89f4SRuslan Bukin return (EINVAL); 66185ae89f4SRuslan Bukin 66285ae89f4SRuslan Bukin if (len != ETHER_ADDR_LEN) 66385ae89f4SRuslan Bukin return (EINVAL); 66485ae89f4SRuslan Bukin 66585ae89f4SRuslan Bukin OF_getprop(node, "local-mac-address", hwaddr, 66685ae89f4SRuslan Bukin ETHER_ADDR_LEN); 66785ae89f4SRuslan Bukin 66885ae89f4SRuslan Bukin return (0); 66985ae89f4SRuslan Bukin } 67085ae89f4SRuslan Bukin 67185ae89f4SRuslan Bukin static int 67285ae89f4SRuslan Bukin mdio_wait(struct xae_softc *sc) 67385ae89f4SRuslan Bukin { 67485ae89f4SRuslan Bukin uint32_t reg; 67585ae89f4SRuslan Bukin int timeout; 67685ae89f4SRuslan Bukin 67785ae89f4SRuslan Bukin timeout = 200; 67885ae89f4SRuslan Bukin 67985ae89f4SRuslan Bukin do { 68085ae89f4SRuslan Bukin reg = READ4(sc, XAE_MDIO_CTRL); 68185ae89f4SRuslan Bukin if (reg & MDIO_CTRL_READY) 68285ae89f4SRuslan Bukin break; 68385ae89f4SRuslan Bukin DELAY(1); 68485ae89f4SRuslan Bukin } while (timeout--); 68585ae89f4SRuslan Bukin 68685ae89f4SRuslan Bukin if (timeout <= 0) { 68785ae89f4SRuslan Bukin printf("Failed to get MDIO ready\n"); 68885ae89f4SRuslan Bukin return (1); 68985ae89f4SRuslan Bukin } 69085ae89f4SRuslan Bukin 69185ae89f4SRuslan Bukin return (0); 69285ae89f4SRuslan Bukin } 69385ae89f4SRuslan Bukin 69485ae89f4SRuslan Bukin static int 69585ae89f4SRuslan Bukin xae_miibus_read_reg(device_t dev, int phy, int reg) 69685ae89f4SRuslan Bukin { 69785ae89f4SRuslan Bukin struct xae_softc *sc; 69885ae89f4SRuslan Bukin uint32_t mii; 69985ae89f4SRuslan Bukin int rv; 70085ae89f4SRuslan Bukin 70185ae89f4SRuslan Bukin sc = device_get_softc(dev); 70285ae89f4SRuslan Bukin 70385ae89f4SRuslan Bukin if (mdio_wait(sc)) 70485ae89f4SRuslan Bukin return (0); 70585ae89f4SRuslan Bukin 70685ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_READ | MDIO_CTRL_INITIATE; 70785ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 70885ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 70985ae89f4SRuslan Bukin 71085ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 71185ae89f4SRuslan Bukin 71285ae89f4SRuslan Bukin if (mdio_wait(sc)) 71385ae89f4SRuslan Bukin return (0); 71485ae89f4SRuslan Bukin 71585ae89f4SRuslan Bukin rv = READ4(sc, XAE_MDIO_READ); 71685ae89f4SRuslan Bukin 71785ae89f4SRuslan Bukin return (rv); 71885ae89f4SRuslan Bukin } 71985ae89f4SRuslan Bukin 72085ae89f4SRuslan Bukin static int 72185ae89f4SRuslan Bukin xae_miibus_write_reg(device_t dev, int phy, int reg, int val) 72285ae89f4SRuslan Bukin { 72385ae89f4SRuslan Bukin struct xae_softc *sc; 72485ae89f4SRuslan Bukin uint32_t mii; 72585ae89f4SRuslan Bukin 72685ae89f4SRuslan Bukin sc = device_get_softc(dev); 72785ae89f4SRuslan Bukin 72885ae89f4SRuslan Bukin if (mdio_wait(sc)) 72985ae89f4SRuslan Bukin return (1); 73085ae89f4SRuslan Bukin 73185ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_WRITE | MDIO_CTRL_INITIATE; 73285ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 73385ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 73485ae89f4SRuslan Bukin 73585ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_WRITE, val); 73685ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 73785ae89f4SRuslan Bukin 73885ae89f4SRuslan Bukin if (mdio_wait(sc)) 73985ae89f4SRuslan Bukin return (1); 74085ae89f4SRuslan Bukin 74185ae89f4SRuslan Bukin return (0); 74285ae89f4SRuslan Bukin } 74385ae89f4SRuslan Bukin 74485ae89f4SRuslan Bukin static void 74585ae89f4SRuslan Bukin xae_phy_fixup(struct xae_softc *sc) 74685ae89f4SRuslan Bukin { 74785ae89f4SRuslan Bukin uint32_t reg; 74885ae89f4SRuslan Bukin 74985ae89f4SRuslan Bukin do { 75085ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_SGMIICTL1, SGMIICTL1_SGMII_6W); 75185ae89f4SRuslan Bukin PHY_WR(sc, DP83867_PHYCR, PHYCR_SGMII_EN); 75285ae89f4SRuslan Bukin 75385ae89f4SRuslan Bukin reg = PHY_RD(sc, DP83867_CFG2); 75485ae89f4SRuslan Bukin reg &= ~CFG2_SPEED_OPT_ATTEMPT_CNT_M; 75585ae89f4SRuslan Bukin reg |= (CFG2_SPEED_OPT_ATTEMPT_CNT_4); 75685ae89f4SRuslan Bukin reg |= CFG2_INTERRUPT_POLARITY; 75785ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_ENHANCED_EN; 75885ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_10M_EN; 75985ae89f4SRuslan Bukin PHY_WR(sc, DP83867_CFG2, reg); 76085ae89f4SRuslan Bukin 76185ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_CFG4, CFG4_SGMII_TMR); 76285ae89f4SRuslan Bukin PHY_WR(sc, MII_BMCR, 76385ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_RESET); 76485ae89f4SRuslan Bukin } while (PHY1_RD(sc, MII_BMCR) == 0x0ffff); 76585ae89f4SRuslan Bukin 76685ae89f4SRuslan Bukin do { 76785ae89f4SRuslan Bukin PHY1_WR(sc, MII_BMCR, 76885ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_STARTNEG); 76985ae89f4SRuslan Bukin DELAY(40000); 77085ae89f4SRuslan Bukin } while ((PHY1_RD(sc, MII_BMSR) & BMSR_ACOMP) == 0); 77185ae89f4SRuslan Bukin } 77285ae89f4SRuslan Bukin 77385ae89f4SRuslan Bukin static int 774a8692c16SRuslan Bukin get_xdma_std(struct xae_softc *sc) 775a8692c16SRuslan Bukin { 776a8692c16SRuslan Bukin 777a8692c16SRuslan Bukin sc->xdma_tx = xdma_ofw_get(sc->dev, "tx"); 778a8692c16SRuslan Bukin if (sc->xdma_tx == NULL) 779a8692c16SRuslan Bukin return (ENXIO); 780a8692c16SRuslan Bukin 781a8692c16SRuslan Bukin sc->xdma_rx = xdma_ofw_get(sc->dev, "rx"); 782a8692c16SRuslan Bukin if (sc->xdma_rx == NULL) { 783a8692c16SRuslan Bukin xdma_put(sc->xdma_tx); 784a8692c16SRuslan Bukin return (ENXIO); 785a8692c16SRuslan Bukin } 786a8692c16SRuslan Bukin 787a8692c16SRuslan Bukin return (0); 788a8692c16SRuslan Bukin } 789a8692c16SRuslan Bukin 790a8692c16SRuslan Bukin static int 791a8692c16SRuslan Bukin get_xdma_axistream(struct xae_softc *sc) 792a8692c16SRuslan Bukin { 793a8692c16SRuslan Bukin struct axidma_fdt_data *data; 794a8692c16SRuslan Bukin device_t dma_dev; 795a8692c16SRuslan Bukin phandle_t node; 796a8692c16SRuslan Bukin pcell_t prop; 797a8692c16SRuslan Bukin size_t len; 798a8692c16SRuslan Bukin 799a8692c16SRuslan Bukin node = ofw_bus_get_node(sc->dev); 800a8692c16SRuslan Bukin len = OF_getencprop(node, "axistream-connected", &prop, sizeof(prop)); 801a8692c16SRuslan Bukin if (len != sizeof(prop)) { 802a8692c16SRuslan Bukin device_printf(sc->dev, 803a8692c16SRuslan Bukin "%s: Couldn't get axistream-connected prop.\n", __func__); 804a8692c16SRuslan Bukin return (ENXIO); 805a8692c16SRuslan Bukin } 806a8692c16SRuslan Bukin dma_dev = OF_device_from_xref(prop); 807a8692c16SRuslan Bukin if (dma_dev == NULL) { 808a8692c16SRuslan Bukin device_printf(sc->dev, "Could not get DMA device by xref.\n"); 809a8692c16SRuslan Bukin return (ENXIO); 810a8692c16SRuslan Bukin } 811a8692c16SRuslan Bukin 812a8692c16SRuslan Bukin sc->xdma_tx = xdma_get(sc->dev, dma_dev); 813a8692c16SRuslan Bukin if (sc->xdma_tx == NULL) { 814a8692c16SRuslan Bukin device_printf(sc->dev, "Could not find DMA controller.\n"); 815a8692c16SRuslan Bukin return (ENXIO); 816a8692c16SRuslan Bukin } 817a8692c16SRuslan Bukin data = malloc(sizeof(struct axidma_fdt_data), 818a8692c16SRuslan Bukin M_DEVBUF, (M_WAITOK | M_ZERO)); 819a8692c16SRuslan Bukin data->id = AXIDMA_TX_CHAN; 820a8692c16SRuslan Bukin sc->xdma_tx->data = data; 821a8692c16SRuslan Bukin 822a8692c16SRuslan Bukin sc->xdma_rx = xdma_get(sc->dev, dma_dev); 823a8692c16SRuslan Bukin if (sc->xdma_rx == NULL) { 824a8692c16SRuslan Bukin device_printf(sc->dev, "Could not find DMA controller.\n"); 825a8692c16SRuslan Bukin return (ENXIO); 826a8692c16SRuslan Bukin } 827a8692c16SRuslan Bukin data = malloc(sizeof(struct axidma_fdt_data), 828a8692c16SRuslan Bukin M_DEVBUF, (M_WAITOK | M_ZERO)); 829a8692c16SRuslan Bukin data->id = AXIDMA_RX_CHAN; 830a8692c16SRuslan Bukin sc->xdma_rx->data = data; 831a8692c16SRuslan Bukin 832a8692c16SRuslan Bukin return (0); 833a8692c16SRuslan Bukin } 834a8692c16SRuslan Bukin 835a8692c16SRuslan Bukin static int 83685ae89f4SRuslan Bukin setup_xdma(struct xae_softc *sc) 83785ae89f4SRuslan Bukin { 83885ae89f4SRuslan Bukin device_t dev; 83985ae89f4SRuslan Bukin vmem_t *vmem; 84085ae89f4SRuslan Bukin int error; 84185ae89f4SRuslan Bukin 84285ae89f4SRuslan Bukin dev = sc->dev; 84385ae89f4SRuslan Bukin 84485ae89f4SRuslan Bukin /* Get xDMA controller */ 845a8692c16SRuslan Bukin error = get_xdma_std(sc); 846a8692c16SRuslan Bukin 847a8692c16SRuslan Bukin if (error) { 848a8692c16SRuslan Bukin device_printf(sc->dev, 849a8692c16SRuslan Bukin "Fallback to axistream-connected property\n"); 850a8692c16SRuslan Bukin error = get_xdma_axistream(sc); 85185ae89f4SRuslan Bukin } 85285ae89f4SRuslan Bukin 853a8692c16SRuslan Bukin if (error) { 854a8692c16SRuslan Bukin device_printf(dev, "Could not find xDMA controllers.\n"); 85585ae89f4SRuslan Bukin return (ENXIO); 85685ae89f4SRuslan Bukin } 85785ae89f4SRuslan Bukin 85885ae89f4SRuslan Bukin /* Alloc xDMA TX virtual channel. */ 85985ae89f4SRuslan Bukin sc->xchan_tx = xdma_channel_alloc(sc->xdma_tx, 0); 86085ae89f4SRuslan Bukin if (sc->xchan_tx == NULL) { 86185ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA TX channel.\n"); 86285ae89f4SRuslan Bukin return (ENXIO); 86385ae89f4SRuslan Bukin } 86485ae89f4SRuslan Bukin 86585ae89f4SRuslan Bukin /* Setup interrupt handler. */ 866d987842dSRuslan Bukin error = xdma_setup_intr(sc->xchan_tx, 0, 86785ae89f4SRuslan Bukin xae_xdma_tx_intr, sc, &sc->ih_tx); 86885ae89f4SRuslan Bukin if (error) { 86985ae89f4SRuslan Bukin device_printf(sc->dev, 87085ae89f4SRuslan Bukin "Can't setup xDMA TX interrupt handler.\n"); 87185ae89f4SRuslan Bukin return (ENXIO); 87285ae89f4SRuslan Bukin } 87385ae89f4SRuslan Bukin 87485ae89f4SRuslan Bukin /* Alloc xDMA RX virtual channel. */ 87585ae89f4SRuslan Bukin sc->xchan_rx = xdma_channel_alloc(sc->xdma_rx, 0); 87685ae89f4SRuslan Bukin if (sc->xchan_rx == NULL) { 87785ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA RX channel.\n"); 87885ae89f4SRuslan Bukin return (ENXIO); 87985ae89f4SRuslan Bukin } 88085ae89f4SRuslan Bukin 88185ae89f4SRuslan Bukin /* Setup interrupt handler. */ 882d987842dSRuslan Bukin error = xdma_setup_intr(sc->xchan_rx, XDMA_INTR_NET, 88385ae89f4SRuslan Bukin xae_xdma_rx_intr, sc, &sc->ih_rx); 88485ae89f4SRuslan Bukin if (error) { 88585ae89f4SRuslan Bukin device_printf(sc->dev, 88685ae89f4SRuslan Bukin "Can't setup xDMA RX interrupt handler.\n"); 88785ae89f4SRuslan Bukin return (ENXIO); 88885ae89f4SRuslan Bukin } 88985ae89f4SRuslan Bukin 89085ae89f4SRuslan Bukin /* Setup bounce buffer */ 89185ae89f4SRuslan Bukin vmem = xdma_get_memory(dev); 89285ae89f4SRuslan Bukin if (vmem) { 89385ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_tx, vmem); 89485ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_rx, vmem); 89585ae89f4SRuslan Bukin } 89685ae89f4SRuslan Bukin 89785ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_tx, 89885ae89f4SRuslan Bukin TX_QUEUE_SIZE, /* xchan requests queue size */ 89985ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 90085ae89f4SRuslan Bukin 8, /* maxnsegs */ 90185ae89f4SRuslan Bukin 16, /* alignment */ 90285ae89f4SRuslan Bukin 0, /* boundary */ 90385ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 90485ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 90585ae89f4SRuslan Bukin 90685ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_rx, 90785ae89f4SRuslan Bukin RX_QUEUE_SIZE, /* xchan requests queue size */ 90885ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 90985ae89f4SRuslan Bukin 1, /* maxnsegs */ 91085ae89f4SRuslan Bukin 16, /* alignment */ 91185ae89f4SRuslan Bukin 0, /* boundary */ 91285ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 91385ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 91485ae89f4SRuslan Bukin 91585ae89f4SRuslan Bukin return (0); 91685ae89f4SRuslan Bukin } 91785ae89f4SRuslan Bukin 91885ae89f4SRuslan Bukin static int 91985ae89f4SRuslan Bukin xae_probe(device_t dev) 92085ae89f4SRuslan Bukin { 92185ae89f4SRuslan Bukin 92285ae89f4SRuslan Bukin if (!ofw_bus_status_okay(dev)) 92385ae89f4SRuslan Bukin return (ENXIO); 92485ae89f4SRuslan Bukin 92585ae89f4SRuslan Bukin if (!ofw_bus_is_compatible(dev, "xlnx,axi-ethernet-1.00.a")) 92685ae89f4SRuslan Bukin return (ENXIO); 92785ae89f4SRuslan Bukin 92885ae89f4SRuslan Bukin device_set_desc(dev, "Xilinx AXI Ethernet"); 92985ae89f4SRuslan Bukin 93085ae89f4SRuslan Bukin return (BUS_PROBE_DEFAULT); 93185ae89f4SRuslan Bukin } 93285ae89f4SRuslan Bukin 93385ae89f4SRuslan Bukin static int 93485ae89f4SRuslan Bukin xae_attach(device_t dev) 93585ae89f4SRuslan Bukin { 93685ae89f4SRuslan Bukin struct xae_softc *sc; 937*dba12f75SJustin Hibbits if_t ifp; 93885ae89f4SRuslan Bukin phandle_t node; 93985ae89f4SRuslan Bukin uint32_t reg; 94085ae89f4SRuslan Bukin int error; 94185ae89f4SRuslan Bukin 94285ae89f4SRuslan Bukin sc = device_get_softc(dev); 94385ae89f4SRuslan Bukin sc->dev = dev; 94485ae89f4SRuslan Bukin node = ofw_bus_get_node(dev); 94585ae89f4SRuslan Bukin 94685ae89f4SRuslan Bukin if (setup_xdma(sc) != 0) { 94785ae89f4SRuslan Bukin device_printf(dev, "Could not setup xDMA.\n"); 94885ae89f4SRuslan Bukin return (ENXIO); 94985ae89f4SRuslan Bukin } 95085ae89f4SRuslan Bukin 95185ae89f4SRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 95285ae89f4SRuslan Bukin MTX_NETWORK_LOCK, MTX_DEF); 95385ae89f4SRuslan Bukin 95485ae89f4SRuslan Bukin sc->br = buf_ring_alloc(BUFRING_SIZE, M_DEVBUF, 95585ae89f4SRuslan Bukin M_NOWAIT, &sc->mtx); 95685ae89f4SRuslan Bukin if (sc->br == NULL) 95785ae89f4SRuslan Bukin return (ENOMEM); 95885ae89f4SRuslan Bukin 95985ae89f4SRuslan Bukin if (bus_alloc_resources(dev, xae_spec, sc->res)) { 96085ae89f4SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 96185ae89f4SRuslan Bukin return (ENXIO); 96285ae89f4SRuslan Bukin } 96385ae89f4SRuslan Bukin 96485ae89f4SRuslan Bukin /* Memory interface */ 96585ae89f4SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 96685ae89f4SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 96785ae89f4SRuslan Bukin 96885ae89f4SRuslan Bukin device_printf(sc->dev, "Identification: %x\n", 96985ae89f4SRuslan Bukin READ4(sc, XAE_IDENT)); 97085ae89f4SRuslan Bukin 97185ae89f4SRuslan Bukin /* Get MAC addr */ 97285ae89f4SRuslan Bukin if (xae_get_hwaddr(sc, sc->macaddr)) { 97385ae89f4SRuslan Bukin device_printf(sc->dev, "can't get mac\n"); 97485ae89f4SRuslan Bukin return (ENXIO); 97585ae89f4SRuslan Bukin } 97685ae89f4SRuslan Bukin 97785ae89f4SRuslan Bukin /* Enable MII clock */ 97885ae89f4SRuslan Bukin reg = (MDIO_CLK_DIV_DEFAULT << MDIO_SETUP_CLK_DIV_S); 97985ae89f4SRuslan Bukin reg |= MDIO_SETUP_ENABLE; 98085ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_SETUP, reg); 98185ae89f4SRuslan Bukin if (mdio_wait(sc)) 98285ae89f4SRuslan Bukin return (ENXIO); 98385ae89f4SRuslan Bukin 98485ae89f4SRuslan Bukin callout_init_mtx(&sc->xae_callout, &sc->mtx, 0); 98585ae89f4SRuslan Bukin 98685ae89f4SRuslan Bukin /* Setup interrupt handler. */ 98785ae89f4SRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 98885ae89f4SRuslan Bukin NULL, xae_intr, sc, &sc->intr_cookie); 98985ae89f4SRuslan Bukin if (error != 0) { 99085ae89f4SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 99185ae89f4SRuslan Bukin return (ENXIO); 99285ae89f4SRuslan Bukin } 99385ae89f4SRuslan Bukin 99485ae89f4SRuslan Bukin /* Set up the ethernet interface. */ 99585ae89f4SRuslan Bukin sc->ifp = ifp = if_alloc(IFT_ETHER); 99685ae89f4SRuslan Bukin if (ifp == NULL) { 99785ae89f4SRuslan Bukin device_printf(dev, "could not allocate ifp.\n"); 99885ae89f4SRuslan Bukin return (ENXIO); 99985ae89f4SRuslan Bukin } 100085ae89f4SRuslan Bukin 1001*dba12f75SJustin Hibbits if_setsoftc(ifp, sc); 100285ae89f4SRuslan Bukin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1003*dba12f75SJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 1004*dba12f75SJustin Hibbits if_setcapabilities(ifp, IFCAP_VLAN_MTU); 1005*dba12f75SJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 1006*dba12f75SJustin Hibbits if_settransmitfn(ifp, xae_transmit); 1007*dba12f75SJustin Hibbits if_setqflushfn(ifp, xae_qflush); 1008*dba12f75SJustin Hibbits if_setioctlfn(ifp, xae_ioctl); 1009*dba12f75SJustin Hibbits if_setinitfn(ifp, xae_init); 1010*dba12f75SJustin Hibbits if_setsendqlen(ifp, TX_DESC_COUNT - 1); 1011*dba12f75SJustin Hibbits if_setsendqready(ifp); 101285ae89f4SRuslan Bukin 101385ae89f4SRuslan Bukin if (xae_get_phyaddr(node, &sc->phy_addr) != 0) 101485ae89f4SRuslan Bukin return (ENXIO); 101585ae89f4SRuslan Bukin 101685ae89f4SRuslan Bukin /* Attach the mii driver. */ 101785ae89f4SRuslan Bukin error = mii_attach(dev, &sc->miibus, ifp, xae_media_change, 101885ae89f4SRuslan Bukin xae_media_status, BMSR_DEFCAPMASK, sc->phy_addr, 101985ae89f4SRuslan Bukin MII_OFFSET_ANY, 0); 102085ae89f4SRuslan Bukin 102185ae89f4SRuslan Bukin if (error != 0) { 102285ae89f4SRuslan Bukin device_printf(dev, "PHY attach failed\n"); 102385ae89f4SRuslan Bukin return (ENXIO); 102485ae89f4SRuslan Bukin } 102585ae89f4SRuslan Bukin sc->mii_softc = device_get_softc(sc->miibus); 102685ae89f4SRuslan Bukin 102785ae89f4SRuslan Bukin /* Apply vcu118 workaround. */ 102885ae89f4SRuslan Bukin if (OF_getproplen(node, "xlnx,vcu118") >= 0) 102985ae89f4SRuslan Bukin xae_phy_fixup(sc); 103085ae89f4SRuslan Bukin 103185ae89f4SRuslan Bukin /* All ready to run, attach the ethernet interface. */ 103285ae89f4SRuslan Bukin ether_ifattach(ifp, sc->macaddr); 103385ae89f4SRuslan Bukin sc->is_attached = true; 103485ae89f4SRuslan Bukin 103585ae89f4SRuslan Bukin xae_rx_enqueue(sc, NUM_RX_MBUF); 103685ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_rx); 103785ae89f4SRuslan Bukin 103885ae89f4SRuslan Bukin return (0); 103985ae89f4SRuslan Bukin } 104085ae89f4SRuslan Bukin 104185ae89f4SRuslan Bukin static int 104285ae89f4SRuslan Bukin xae_detach(device_t dev) 104385ae89f4SRuslan Bukin { 104485ae89f4SRuslan Bukin struct xae_softc *sc; 1045*dba12f75SJustin Hibbits if_t ifp; 104685ae89f4SRuslan Bukin 104785ae89f4SRuslan Bukin sc = device_get_softc(dev); 104885ae89f4SRuslan Bukin 104985ae89f4SRuslan Bukin KASSERT(mtx_initialized(&sc->mtx), ("%s: mutex not initialized", 105085ae89f4SRuslan Bukin device_get_nameunit(dev))); 105185ae89f4SRuslan Bukin 105285ae89f4SRuslan Bukin ifp = sc->ifp; 105385ae89f4SRuslan Bukin 105485ae89f4SRuslan Bukin /* Only cleanup if attach succeeded. */ 105585ae89f4SRuslan Bukin if (device_is_attached(dev)) { 105685ae89f4SRuslan Bukin XAE_LOCK(sc); 105785ae89f4SRuslan Bukin xae_stop_locked(sc); 105885ae89f4SRuslan Bukin XAE_UNLOCK(sc); 105985ae89f4SRuslan Bukin callout_drain(&sc->xae_callout); 106085ae89f4SRuslan Bukin ether_ifdetach(ifp); 106185ae89f4SRuslan Bukin } 106285ae89f4SRuslan Bukin 106385ae89f4SRuslan Bukin if (sc->miibus != NULL) 106485ae89f4SRuslan Bukin device_delete_child(dev, sc->miibus); 106585ae89f4SRuslan Bukin 106685ae89f4SRuslan Bukin if (ifp != NULL) 106785ae89f4SRuslan Bukin if_free(ifp); 106885ae89f4SRuslan Bukin 106985ae89f4SRuslan Bukin mtx_destroy(&sc->mtx); 107085ae89f4SRuslan Bukin 107185ae89f4SRuslan Bukin bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 107285ae89f4SRuslan Bukin 107385ae89f4SRuslan Bukin bus_release_resources(dev, xae_spec, sc->res); 107485ae89f4SRuslan Bukin 107585ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_tx); 107685ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_rx); 107785ae89f4SRuslan Bukin xdma_put(sc->xdma_tx); 107885ae89f4SRuslan Bukin xdma_put(sc->xdma_rx); 107985ae89f4SRuslan Bukin 108085ae89f4SRuslan Bukin return (0); 108185ae89f4SRuslan Bukin } 108285ae89f4SRuslan Bukin 108385ae89f4SRuslan Bukin static void 108485ae89f4SRuslan Bukin xae_miibus_statchg(device_t dev) 108585ae89f4SRuslan Bukin { 108685ae89f4SRuslan Bukin struct xae_softc *sc; 108785ae89f4SRuslan Bukin struct mii_data *mii; 108885ae89f4SRuslan Bukin uint32_t reg; 108985ae89f4SRuslan Bukin 109085ae89f4SRuslan Bukin /* 109185ae89f4SRuslan Bukin * Called by the MII bus driver when the PHY establishes 109285ae89f4SRuslan Bukin * link to set the MAC interface registers. 109385ae89f4SRuslan Bukin */ 109485ae89f4SRuslan Bukin 109585ae89f4SRuslan Bukin sc = device_get_softc(dev); 109685ae89f4SRuslan Bukin 109785ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 109885ae89f4SRuslan Bukin 109985ae89f4SRuslan Bukin mii = sc->mii_softc; 110085ae89f4SRuslan Bukin 110185ae89f4SRuslan Bukin if (mii->mii_media_status & IFM_ACTIVE) 110285ae89f4SRuslan Bukin sc->link_is_up = true; 110385ae89f4SRuslan Bukin else 110485ae89f4SRuslan Bukin sc->link_is_up = false; 110585ae89f4SRuslan Bukin 110685ae89f4SRuslan Bukin switch (IFM_SUBTYPE(mii->mii_media_active)) { 110785ae89f4SRuslan Bukin case IFM_1000_T: 110885ae89f4SRuslan Bukin case IFM_1000_SX: 110985ae89f4SRuslan Bukin reg = SPEED_1000; 111085ae89f4SRuslan Bukin break; 111185ae89f4SRuslan Bukin case IFM_100_TX: 111285ae89f4SRuslan Bukin reg = SPEED_100; 111385ae89f4SRuslan Bukin break; 111485ae89f4SRuslan Bukin case IFM_10_T: 111585ae89f4SRuslan Bukin reg = SPEED_10; 111685ae89f4SRuslan Bukin break; 111785ae89f4SRuslan Bukin case IFM_NONE: 111885ae89f4SRuslan Bukin sc->link_is_up = false; 111985ae89f4SRuslan Bukin return; 112085ae89f4SRuslan Bukin default: 112185ae89f4SRuslan Bukin sc->link_is_up = false; 112285ae89f4SRuslan Bukin device_printf(dev, "Unsupported media %u\n", 112385ae89f4SRuslan Bukin IFM_SUBTYPE(mii->mii_media_active)); 112485ae89f4SRuslan Bukin return; 112585ae89f4SRuslan Bukin } 112685ae89f4SRuslan Bukin 112785ae89f4SRuslan Bukin WRITE4(sc, XAE_SPEED, reg); 112885ae89f4SRuslan Bukin } 112985ae89f4SRuslan Bukin 113085ae89f4SRuslan Bukin static device_method_t xae_methods[] = { 113185ae89f4SRuslan Bukin DEVMETHOD(device_probe, xae_probe), 113285ae89f4SRuslan Bukin DEVMETHOD(device_attach, xae_attach), 113385ae89f4SRuslan Bukin DEVMETHOD(device_detach, xae_detach), 113485ae89f4SRuslan Bukin 113585ae89f4SRuslan Bukin /* MII Interface */ 113685ae89f4SRuslan Bukin DEVMETHOD(miibus_readreg, xae_miibus_read_reg), 113785ae89f4SRuslan Bukin DEVMETHOD(miibus_writereg, xae_miibus_write_reg), 113885ae89f4SRuslan Bukin DEVMETHOD(miibus_statchg, xae_miibus_statchg), 113985ae89f4SRuslan Bukin { 0, 0 } 114085ae89f4SRuslan Bukin }; 114185ae89f4SRuslan Bukin 114285ae89f4SRuslan Bukin driver_t xae_driver = { 114385ae89f4SRuslan Bukin "xae", 114485ae89f4SRuslan Bukin xae_methods, 114585ae89f4SRuslan Bukin sizeof(struct xae_softc), 114685ae89f4SRuslan Bukin }; 114785ae89f4SRuslan Bukin 114890b8b224SJohn Baldwin DRIVER_MODULE(xae, simplebus, xae_driver, 0, 0); 11493e38757dSJohn Baldwin DRIVER_MODULE(miibus, xae, miibus_driver, 0, 0); 115085ae89f4SRuslan Bukin 115185ae89f4SRuslan Bukin MODULE_DEPEND(xae, ether, 1, 1, 1); 115285ae89f4SRuslan Bukin MODULE_DEPEND(xae, miibus, 1, 1, 1); 1153