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 6785ae89f4SRuslan Bukin #include "miibus_if.h" 6885ae89f4SRuslan Bukin 6985ae89f4SRuslan Bukin #define READ4(_sc, _reg) \ 7085ae89f4SRuslan Bukin bus_read_4((_sc)->res[0], _reg) 7185ae89f4SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 7285ae89f4SRuslan Bukin bus_write_4((_sc)->res[0], _reg, _val) 7385ae89f4SRuslan Bukin 7485ae89f4SRuslan Bukin #define READ8(_sc, _reg) \ 7585ae89f4SRuslan Bukin bus_read_8((_sc)->res[0], _reg) 7685ae89f4SRuslan Bukin #define WRITE8(_sc, _reg, _val) \ 7785ae89f4SRuslan Bukin bus_write_8((_sc)->res[0], _reg, _val) 7885ae89f4SRuslan Bukin 7985ae89f4SRuslan Bukin #define XAE_LOCK(sc) mtx_lock(&(sc)->mtx) 8085ae89f4SRuslan Bukin #define XAE_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 8185ae89f4SRuslan Bukin #define XAE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) 8285ae89f4SRuslan Bukin #define XAE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) 8385ae89f4SRuslan Bukin 8485ae89f4SRuslan Bukin #define XAE_DEBUG 8585ae89f4SRuslan Bukin #undef XAE_DEBUG 8685ae89f4SRuslan Bukin 8785ae89f4SRuslan Bukin #ifdef XAE_DEBUG 8885ae89f4SRuslan Bukin #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) 8985ae89f4SRuslan Bukin #else 9085ae89f4SRuslan Bukin #define dprintf(fmt, ...) 9185ae89f4SRuslan Bukin #endif 9285ae89f4SRuslan Bukin 9385ae89f4SRuslan Bukin #define RX_QUEUE_SIZE 64 9485ae89f4SRuslan Bukin #define TX_QUEUE_SIZE 64 9585ae89f4SRuslan Bukin #define NUM_RX_MBUF 16 9685ae89f4SRuslan Bukin #define BUFRING_SIZE 8192 9785ae89f4SRuslan Bukin #define MDIO_CLK_DIV_DEFAULT 29 9885ae89f4SRuslan Bukin 9985ae89f4SRuslan Bukin #define PHY1_RD(sc, _r) \ 10085ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, 1, _r) 10185ae89f4SRuslan Bukin #define PHY1_WR(sc, _r, _v) \ 10285ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, 1, _r, _v) 10385ae89f4SRuslan Bukin 10485ae89f4SRuslan Bukin #define PHY_RD(sc, _r) \ 10585ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, sc->phy_addr, _r) 10685ae89f4SRuslan Bukin #define PHY_WR(sc, _r, _v) \ 10785ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, sc->phy_addr, _r, _v) 10885ae89f4SRuslan Bukin 10985ae89f4SRuslan Bukin /* Use this macro to access regs > 0x1f */ 11085ae89f4SRuslan Bukin #define WRITE_TI_EREG(sc, reg, data) { \ 11185ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK); \ 11285ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, reg); \ 11385ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK | MMDACR_FN_DATANPI); \ 11485ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, data); \ 11585ae89f4SRuslan Bukin } 11685ae89f4SRuslan Bukin 11785ae89f4SRuslan Bukin /* Not documented, Xilinx VCU118 workaround */ 11885ae89f4SRuslan Bukin #define CFG4_SGMII_TMR 0x160 /* bits 8:7 MUST be '10' */ 11985ae89f4SRuslan Bukin #define DP83867_SGMIICTL1 0xD3 /* not documented register */ 12085ae89f4SRuslan Bukin #define SGMIICTL1_SGMII_6W (1 << 14) /* no idea what it is */ 12185ae89f4SRuslan Bukin 12285ae89f4SRuslan Bukin static struct resource_spec xae_spec[] = { 12385ae89f4SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 12485ae89f4SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 12585ae89f4SRuslan Bukin { -1, 0 } 12685ae89f4SRuslan Bukin }; 12785ae89f4SRuslan Bukin 12885ae89f4SRuslan Bukin static void xae_stop_locked(struct xae_softc *sc); 12985ae89f4SRuslan Bukin static void xae_setup_rxfilter(struct xae_softc *sc); 13085ae89f4SRuslan Bukin 13185ae89f4SRuslan Bukin static int 13285ae89f4SRuslan Bukin xae_rx_enqueue(struct xae_softc *sc, uint32_t n) 13385ae89f4SRuslan Bukin { 13485ae89f4SRuslan Bukin struct mbuf *m; 13585ae89f4SRuslan Bukin int i; 13685ae89f4SRuslan Bukin 13785ae89f4SRuslan Bukin for (i = 0; i < n; i++) { 13885ae89f4SRuslan Bukin m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 13985ae89f4SRuslan Bukin if (m == NULL) { 14085ae89f4SRuslan Bukin device_printf(sc->dev, 14185ae89f4SRuslan Bukin "%s: Can't alloc rx mbuf\n", __func__); 14285ae89f4SRuslan Bukin return (-1); 14385ae89f4SRuslan Bukin } 14485ae89f4SRuslan Bukin 14585ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 14685ae89f4SRuslan Bukin xdma_enqueue_mbuf(sc->xchan_rx, &m, 0, 4, 4, XDMA_DEV_TO_MEM); 14785ae89f4SRuslan Bukin } 14885ae89f4SRuslan Bukin 14985ae89f4SRuslan Bukin return (0); 15085ae89f4SRuslan Bukin } 15185ae89f4SRuslan Bukin 15285ae89f4SRuslan Bukin static int 15385ae89f4SRuslan Bukin xae_get_phyaddr(phandle_t node, int *phy_addr) 15485ae89f4SRuslan Bukin { 15585ae89f4SRuslan Bukin phandle_t phy_node; 15685ae89f4SRuslan Bukin pcell_t phy_handle, phy_reg; 15785ae89f4SRuslan Bukin 15885ae89f4SRuslan Bukin if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, 15985ae89f4SRuslan Bukin sizeof(phy_handle)) <= 0) 16085ae89f4SRuslan Bukin return (ENXIO); 16185ae89f4SRuslan Bukin 16285ae89f4SRuslan Bukin phy_node = OF_node_from_xref(phy_handle); 16385ae89f4SRuslan Bukin 16485ae89f4SRuslan Bukin if (OF_getencprop(phy_node, "reg", (void *)&phy_reg, 16585ae89f4SRuslan Bukin sizeof(phy_reg)) <= 0) 16685ae89f4SRuslan Bukin return (ENXIO); 16785ae89f4SRuslan Bukin 16885ae89f4SRuslan Bukin *phy_addr = phy_reg; 16985ae89f4SRuslan Bukin 17085ae89f4SRuslan Bukin return (0); 17185ae89f4SRuslan Bukin } 17285ae89f4SRuslan Bukin 17385ae89f4SRuslan Bukin static int 17485ae89f4SRuslan Bukin xae_xdma_tx_intr(void *arg, xdma_transfer_status_t *status) 17585ae89f4SRuslan Bukin { 17685ae89f4SRuslan Bukin xdma_transfer_status_t st; 17785ae89f4SRuslan Bukin struct xae_softc *sc; 17885ae89f4SRuslan Bukin struct ifnet *ifp; 17985ae89f4SRuslan Bukin struct mbuf *m; 18085ae89f4SRuslan Bukin int err; 18185ae89f4SRuslan Bukin 18285ae89f4SRuslan Bukin sc = arg; 18385ae89f4SRuslan Bukin 18485ae89f4SRuslan Bukin XAE_LOCK(sc); 18585ae89f4SRuslan Bukin 18685ae89f4SRuslan Bukin ifp = sc->ifp; 18785ae89f4SRuslan Bukin 18885ae89f4SRuslan Bukin for (;;) { 18985ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_tx, &m, &st); 19085ae89f4SRuslan Bukin if (err != 0) { 19185ae89f4SRuslan Bukin break; 19285ae89f4SRuslan Bukin } 19385ae89f4SRuslan Bukin 19485ae89f4SRuslan Bukin if (st.error != 0) { 19585ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 19685ae89f4SRuslan Bukin } 19785ae89f4SRuslan Bukin 19885ae89f4SRuslan Bukin m_freem(m); 19985ae89f4SRuslan Bukin } 20085ae89f4SRuslan Bukin 20185ae89f4SRuslan Bukin ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 20285ae89f4SRuslan Bukin 20385ae89f4SRuslan Bukin XAE_UNLOCK(sc); 20485ae89f4SRuslan Bukin 20585ae89f4SRuslan Bukin return (0); 20685ae89f4SRuslan Bukin } 20785ae89f4SRuslan Bukin 20885ae89f4SRuslan Bukin static int 20985ae89f4SRuslan Bukin xae_xdma_rx_intr(void *arg, xdma_transfer_status_t *status) 21085ae89f4SRuslan Bukin { 21185ae89f4SRuslan Bukin xdma_transfer_status_t st; 21285ae89f4SRuslan Bukin struct xae_softc *sc; 21385ae89f4SRuslan Bukin struct ifnet *ifp; 21485ae89f4SRuslan Bukin struct mbuf *m; 21585ae89f4SRuslan Bukin int err; 21685ae89f4SRuslan Bukin uint32_t cnt_processed; 21785ae89f4SRuslan Bukin 21885ae89f4SRuslan Bukin sc = arg; 21985ae89f4SRuslan Bukin 22085ae89f4SRuslan Bukin dprintf("%s\n", __func__); 22185ae89f4SRuslan Bukin 22285ae89f4SRuslan Bukin XAE_LOCK(sc); 22385ae89f4SRuslan Bukin 22485ae89f4SRuslan Bukin ifp = sc->ifp; 22585ae89f4SRuslan Bukin 22685ae89f4SRuslan Bukin cnt_processed = 0; 22785ae89f4SRuslan Bukin for (;;) { 22885ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_rx, &m, &st); 22985ae89f4SRuslan Bukin if (err != 0) { 23085ae89f4SRuslan Bukin break; 23185ae89f4SRuslan Bukin } 23285ae89f4SRuslan Bukin cnt_processed++; 23385ae89f4SRuslan Bukin 23485ae89f4SRuslan Bukin if (st.error != 0) { 23585ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 23685ae89f4SRuslan Bukin m_freem(m); 23785ae89f4SRuslan Bukin continue; 23885ae89f4SRuslan Bukin } 23985ae89f4SRuslan Bukin 24085ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = st.transferred; 24185ae89f4SRuslan Bukin m->m_pkthdr.rcvif = ifp; 24285ae89f4SRuslan Bukin XAE_UNLOCK(sc); 24385ae89f4SRuslan Bukin (*ifp->if_input)(ifp, m); 24485ae89f4SRuslan Bukin XAE_LOCK(sc); 24585ae89f4SRuslan Bukin } 24685ae89f4SRuslan Bukin 24785ae89f4SRuslan Bukin xae_rx_enqueue(sc, cnt_processed); 24885ae89f4SRuslan Bukin 24985ae89f4SRuslan Bukin XAE_UNLOCK(sc); 25085ae89f4SRuslan Bukin 25185ae89f4SRuslan Bukin return (0); 25285ae89f4SRuslan Bukin } 25385ae89f4SRuslan Bukin 25485ae89f4SRuslan Bukin static void 25585ae89f4SRuslan Bukin xae_qflush(struct ifnet *ifp) 25685ae89f4SRuslan Bukin { 25785ae89f4SRuslan Bukin struct xae_softc *sc; 25885ae89f4SRuslan Bukin 25985ae89f4SRuslan Bukin sc = ifp->if_softc; 26085ae89f4SRuslan Bukin } 26185ae89f4SRuslan Bukin 26285ae89f4SRuslan Bukin static int 26385ae89f4SRuslan Bukin xae_transmit_locked(struct ifnet *ifp) 26485ae89f4SRuslan Bukin { 26585ae89f4SRuslan Bukin struct xae_softc *sc; 26685ae89f4SRuslan Bukin struct mbuf *m; 26785ae89f4SRuslan Bukin struct buf_ring *br; 26885ae89f4SRuslan Bukin int error; 26985ae89f4SRuslan Bukin int enq; 27085ae89f4SRuslan Bukin 27185ae89f4SRuslan Bukin dprintf("%s\n", __func__); 27285ae89f4SRuslan Bukin 27385ae89f4SRuslan Bukin sc = ifp->if_softc; 27485ae89f4SRuslan Bukin br = sc->br; 27585ae89f4SRuslan Bukin 27685ae89f4SRuslan Bukin enq = 0; 27785ae89f4SRuslan Bukin 27885ae89f4SRuslan Bukin while ((m = drbr_peek(ifp, br)) != NULL) { 27985ae89f4SRuslan Bukin error = xdma_enqueue_mbuf(sc->xchan_tx, 28085ae89f4SRuslan Bukin &m, 0, 4, 4, XDMA_MEM_TO_DEV); 28185ae89f4SRuslan Bukin if (error != 0) { 28285ae89f4SRuslan Bukin /* No space in request queue available yet. */ 28385ae89f4SRuslan Bukin drbr_putback(ifp, br, m); 28485ae89f4SRuslan Bukin break; 28585ae89f4SRuslan Bukin } 28685ae89f4SRuslan Bukin 28785ae89f4SRuslan Bukin drbr_advance(ifp, br); 28885ae89f4SRuslan Bukin 28985ae89f4SRuslan Bukin enq++; 29085ae89f4SRuslan Bukin 29185ae89f4SRuslan Bukin /* If anyone is interested give them a copy. */ 29285ae89f4SRuslan Bukin ETHER_BPF_MTAP(ifp, m); 29385ae89f4SRuslan Bukin } 29485ae89f4SRuslan Bukin 29585ae89f4SRuslan Bukin if (enq > 0) 29685ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_tx); 29785ae89f4SRuslan Bukin 29885ae89f4SRuslan Bukin return (0); 29985ae89f4SRuslan Bukin } 30085ae89f4SRuslan Bukin 30185ae89f4SRuslan Bukin static int 30285ae89f4SRuslan Bukin xae_transmit(struct ifnet *ifp, struct mbuf *m) 30385ae89f4SRuslan Bukin { 30485ae89f4SRuslan Bukin struct xae_softc *sc; 30585ae89f4SRuslan Bukin int error; 30685ae89f4SRuslan Bukin 30785ae89f4SRuslan Bukin dprintf("%s\n", __func__); 30885ae89f4SRuslan Bukin 30985ae89f4SRuslan Bukin sc = ifp->if_softc; 31085ae89f4SRuslan Bukin 31185ae89f4SRuslan Bukin XAE_LOCK(sc); 31285ae89f4SRuslan Bukin 31385ae89f4SRuslan Bukin error = drbr_enqueue(ifp, sc->br, m); 31485ae89f4SRuslan Bukin if (error) { 31585ae89f4SRuslan Bukin XAE_UNLOCK(sc); 31685ae89f4SRuslan Bukin return (error); 31785ae89f4SRuslan Bukin } 31885ae89f4SRuslan Bukin 31985ae89f4SRuslan Bukin if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 32085ae89f4SRuslan Bukin IFF_DRV_RUNNING) { 32185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 32285ae89f4SRuslan Bukin return (0); 32385ae89f4SRuslan Bukin } 32485ae89f4SRuslan Bukin 32585ae89f4SRuslan Bukin if (!sc->link_is_up) { 32685ae89f4SRuslan Bukin XAE_UNLOCK(sc); 32785ae89f4SRuslan Bukin return (0); 32885ae89f4SRuslan Bukin } 32985ae89f4SRuslan Bukin 33085ae89f4SRuslan Bukin error = xae_transmit_locked(ifp); 33185ae89f4SRuslan Bukin 33285ae89f4SRuslan Bukin XAE_UNLOCK(sc); 33385ae89f4SRuslan Bukin 33485ae89f4SRuslan Bukin return (error); 33585ae89f4SRuslan Bukin } 33685ae89f4SRuslan Bukin 33785ae89f4SRuslan Bukin static void 33885ae89f4SRuslan Bukin xae_stop_locked(struct xae_softc *sc) 33985ae89f4SRuslan Bukin { 34085ae89f4SRuslan Bukin struct ifnet *ifp; 34185ae89f4SRuslan Bukin uint32_t reg; 34285ae89f4SRuslan Bukin 34385ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 34485ae89f4SRuslan Bukin 34585ae89f4SRuslan Bukin ifp = sc->ifp; 34685ae89f4SRuslan Bukin ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 34785ae89f4SRuslan Bukin 34885ae89f4SRuslan Bukin callout_stop(&sc->xae_callout); 34985ae89f4SRuslan Bukin 35085ae89f4SRuslan Bukin /* Stop the transmitter */ 35185ae89f4SRuslan Bukin reg = READ4(sc, XAE_TC); 35285ae89f4SRuslan Bukin reg &= ~TC_TX; 35385ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, reg); 35485ae89f4SRuslan Bukin 35585ae89f4SRuslan Bukin /* Stop the receiver. */ 35685ae89f4SRuslan Bukin reg = READ4(sc, XAE_RCW1); 35785ae89f4SRuslan Bukin reg &= ~RCW1_RX; 35885ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, reg); 35985ae89f4SRuslan Bukin } 36085ae89f4SRuslan Bukin 36185ae89f4SRuslan Bukin static uint64_t 36285ae89f4SRuslan Bukin xae_stat(struct xae_softc *sc, int counter_id) 36385ae89f4SRuslan Bukin { 36485ae89f4SRuslan Bukin uint64_t new, old; 36585ae89f4SRuslan Bukin uint64_t delta; 36685ae89f4SRuslan Bukin 36785ae89f4SRuslan Bukin KASSERT(counter_id < XAE_MAX_COUNTERS, 36885ae89f4SRuslan Bukin ("counter %d is out of range", counter_id)); 36985ae89f4SRuslan Bukin 37085ae89f4SRuslan Bukin new = READ8(sc, XAE_STATCNT(counter_id)); 37185ae89f4SRuslan Bukin old = sc->counters[counter_id]; 37285ae89f4SRuslan Bukin 37385ae89f4SRuslan Bukin if (new >= old) 37485ae89f4SRuslan Bukin delta = new - old; 37585ae89f4SRuslan Bukin else 37685ae89f4SRuslan Bukin delta = UINT64_MAX - old + new; 37785ae89f4SRuslan Bukin sc->counters[counter_id] = new; 37885ae89f4SRuslan Bukin 37985ae89f4SRuslan Bukin return (delta); 38085ae89f4SRuslan Bukin } 38185ae89f4SRuslan Bukin 38285ae89f4SRuslan Bukin static void 38385ae89f4SRuslan Bukin xae_harvest_stats(struct xae_softc *sc) 38485ae89f4SRuslan Bukin { 38585ae89f4SRuslan Bukin struct ifnet *ifp; 38685ae89f4SRuslan Bukin 38785ae89f4SRuslan Bukin ifp = sc->ifp; 38885ae89f4SRuslan Bukin 38985ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IPACKETS, xae_stat(sc, RX_GOOD_FRAMES)); 39085ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IMCASTS, xae_stat(sc, RX_GOOD_MCASTS)); 39185ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 39285ae89f4SRuslan Bukin xae_stat(sc, RX_FRAME_CHECK_SEQ_ERROR) + 39385ae89f4SRuslan Bukin xae_stat(sc, RX_LEN_OUT_OF_RANGE) + 39485ae89f4SRuslan Bukin xae_stat(sc, RX_ALIGNMENT_ERRORS)); 39585ae89f4SRuslan Bukin 39685ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OBYTES, xae_stat(sc, TX_BYTES)); 39785ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OPACKETS, xae_stat(sc, TX_GOOD_FRAMES)); 39885ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OMCASTS, xae_stat(sc, TX_GOOD_MCASTS)); 39985ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 40085ae89f4SRuslan Bukin xae_stat(sc, TX_GOOD_UNDERRUN_ERRORS)); 40185ae89f4SRuslan Bukin 40285ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 40385ae89f4SRuslan Bukin xae_stat(sc, TX_SINGLE_COLLISION_FRAMES) + 40485ae89f4SRuslan Bukin xae_stat(sc, TX_MULTI_COLLISION_FRAMES) + 40585ae89f4SRuslan Bukin xae_stat(sc, TX_LATE_COLLISIONS) + 40685ae89f4SRuslan Bukin xae_stat(sc, TX_EXCESS_COLLISIONS)); 40785ae89f4SRuslan Bukin } 40885ae89f4SRuslan Bukin 40985ae89f4SRuslan Bukin static void 41085ae89f4SRuslan Bukin xae_tick(void *arg) 41185ae89f4SRuslan Bukin { 41285ae89f4SRuslan Bukin struct xae_softc *sc; 41385ae89f4SRuslan Bukin struct ifnet *ifp; 41485ae89f4SRuslan Bukin int link_was_up; 41585ae89f4SRuslan Bukin 41685ae89f4SRuslan Bukin sc = arg; 41785ae89f4SRuslan Bukin 41885ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 41985ae89f4SRuslan Bukin 42085ae89f4SRuslan Bukin ifp = sc->ifp; 42185ae89f4SRuslan Bukin 42285ae89f4SRuslan Bukin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 42385ae89f4SRuslan Bukin return; 42485ae89f4SRuslan Bukin 42585ae89f4SRuslan Bukin /* Gather stats from hardware counters. */ 42685ae89f4SRuslan Bukin xae_harvest_stats(sc); 42785ae89f4SRuslan Bukin 42885ae89f4SRuslan Bukin /* Check the media status. */ 42985ae89f4SRuslan Bukin link_was_up = sc->link_is_up; 43085ae89f4SRuslan Bukin mii_tick(sc->mii_softc); 43185ae89f4SRuslan Bukin if (sc->link_is_up && !link_was_up) 43285ae89f4SRuslan Bukin xae_transmit_locked(sc->ifp); 43385ae89f4SRuslan Bukin 43485ae89f4SRuslan Bukin /* Schedule another check one second from now. */ 43585ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 43685ae89f4SRuslan Bukin } 43785ae89f4SRuslan Bukin 43885ae89f4SRuslan Bukin static void 43985ae89f4SRuslan Bukin xae_init_locked(struct xae_softc *sc) 44085ae89f4SRuslan Bukin { 44185ae89f4SRuslan Bukin struct ifnet *ifp; 44285ae89f4SRuslan Bukin 44385ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 44485ae89f4SRuslan Bukin 44585ae89f4SRuslan Bukin ifp = sc->ifp; 44685ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 44785ae89f4SRuslan Bukin return; 44885ae89f4SRuslan Bukin 44985ae89f4SRuslan Bukin ifp->if_drv_flags |= IFF_DRV_RUNNING; 45085ae89f4SRuslan Bukin 45185ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 45285ae89f4SRuslan Bukin 45385ae89f4SRuslan Bukin /* Enable the transmitter */ 45485ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, TC_TX); 45585ae89f4SRuslan Bukin 45685ae89f4SRuslan Bukin /* Enable the receiver. */ 45785ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, RCW1_RX); 45885ae89f4SRuslan Bukin 45985ae89f4SRuslan Bukin /* 46085ae89f4SRuslan Bukin * Call mii_mediachg() which will call back into xae_miibus_statchg() 46185ae89f4SRuslan Bukin * to set up the remaining config registers based on current media. 46285ae89f4SRuslan Bukin */ 46385ae89f4SRuslan Bukin mii_mediachg(sc->mii_softc); 46485ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 46585ae89f4SRuslan Bukin } 46685ae89f4SRuslan Bukin 46785ae89f4SRuslan Bukin static void 46885ae89f4SRuslan Bukin xae_init(void *arg) 46985ae89f4SRuslan Bukin { 47085ae89f4SRuslan Bukin struct xae_softc *sc; 47185ae89f4SRuslan Bukin 47285ae89f4SRuslan Bukin sc = arg; 47385ae89f4SRuslan Bukin 47485ae89f4SRuslan Bukin XAE_LOCK(sc); 47585ae89f4SRuslan Bukin xae_init_locked(sc); 47685ae89f4SRuslan Bukin XAE_UNLOCK(sc); 47785ae89f4SRuslan Bukin } 47885ae89f4SRuslan Bukin 47985ae89f4SRuslan Bukin static void 48085ae89f4SRuslan Bukin xae_media_status(struct ifnet * ifp, struct ifmediareq *ifmr) 48185ae89f4SRuslan Bukin { 48285ae89f4SRuslan Bukin struct xae_softc *sc; 48385ae89f4SRuslan Bukin struct mii_data *mii; 48485ae89f4SRuslan Bukin 48585ae89f4SRuslan Bukin sc = ifp->if_softc; 48685ae89f4SRuslan Bukin mii = sc->mii_softc; 48785ae89f4SRuslan Bukin 48885ae89f4SRuslan Bukin XAE_LOCK(sc); 48985ae89f4SRuslan Bukin mii_pollstat(mii); 49085ae89f4SRuslan Bukin ifmr->ifm_active = mii->mii_media_active; 49185ae89f4SRuslan Bukin ifmr->ifm_status = mii->mii_media_status; 49285ae89f4SRuslan Bukin XAE_UNLOCK(sc); 49385ae89f4SRuslan Bukin } 49485ae89f4SRuslan Bukin 49585ae89f4SRuslan Bukin static int 49685ae89f4SRuslan Bukin xae_media_change_locked(struct xae_softc *sc) 49785ae89f4SRuslan Bukin { 49885ae89f4SRuslan Bukin 49985ae89f4SRuslan Bukin return (mii_mediachg(sc->mii_softc)); 50085ae89f4SRuslan Bukin } 50185ae89f4SRuslan Bukin 50285ae89f4SRuslan Bukin static int 50385ae89f4SRuslan Bukin xae_media_change(struct ifnet * ifp) 50485ae89f4SRuslan Bukin { 50585ae89f4SRuslan Bukin struct xae_softc *sc; 50685ae89f4SRuslan Bukin int error; 50785ae89f4SRuslan Bukin 50885ae89f4SRuslan Bukin sc = ifp->if_softc; 50985ae89f4SRuslan Bukin 51085ae89f4SRuslan Bukin XAE_LOCK(sc); 51185ae89f4SRuslan Bukin error = xae_media_change_locked(sc); 51285ae89f4SRuslan Bukin XAE_UNLOCK(sc); 51385ae89f4SRuslan Bukin 51485ae89f4SRuslan Bukin return (error); 51585ae89f4SRuslan Bukin } 51685ae89f4SRuslan Bukin 517*4d50c26aSGleb Smirnoff static u_int 518*4d50c26aSGleb Smirnoff xae_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 519*4d50c26aSGleb Smirnoff { 520*4d50c26aSGleb Smirnoff struct xae_softc *sc = arg; 521*4d50c26aSGleb Smirnoff uint32_t reg; 522*4d50c26aSGleb Smirnoff uint8_t *ma; 523*4d50c26aSGleb Smirnoff 524*4d50c26aSGleb Smirnoff if (cnt >= XAE_MULTICAST_TABLE_SIZE) 525*4d50c26aSGleb Smirnoff return (1); 526*4d50c26aSGleb Smirnoff 527*4d50c26aSGleb Smirnoff ma = LLADDR(sdl); 528*4d50c26aSGleb Smirnoff 529*4d50c26aSGleb Smirnoff reg = READ4(sc, XAE_FFC) & 0xffffff00; 530*4d50c26aSGleb Smirnoff reg |= cnt; 531*4d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFC, reg); 532*4d50c26aSGleb Smirnoff 533*4d50c26aSGleb Smirnoff reg = (ma[0]); 534*4d50c26aSGleb Smirnoff reg |= (ma[1] << 8); 535*4d50c26aSGleb Smirnoff reg |= (ma[2] << 16); 536*4d50c26aSGleb Smirnoff reg |= (ma[3] << 24); 537*4d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFV(0), reg); 538*4d50c26aSGleb Smirnoff 539*4d50c26aSGleb Smirnoff reg = ma[4]; 540*4d50c26aSGleb Smirnoff reg |= ma[5] << 8; 541*4d50c26aSGleb Smirnoff WRITE4(sc, XAE_FFV(1), reg); 542*4d50c26aSGleb Smirnoff 543*4d50c26aSGleb Smirnoff return (1); 544*4d50c26aSGleb Smirnoff } 545*4d50c26aSGleb Smirnoff 54685ae89f4SRuslan Bukin static void 54785ae89f4SRuslan Bukin xae_setup_rxfilter(struct xae_softc *sc) 54885ae89f4SRuslan Bukin { 54985ae89f4SRuslan Bukin struct ifnet *ifp; 55085ae89f4SRuslan Bukin uint32_t reg; 55185ae89f4SRuslan Bukin 55285ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 55385ae89f4SRuslan Bukin 55485ae89f4SRuslan Bukin ifp = sc->ifp; 55585ae89f4SRuslan Bukin 55685ae89f4SRuslan Bukin /* 55785ae89f4SRuslan Bukin * Set the multicast (group) filter hash. 55885ae89f4SRuslan Bukin */ 55985ae89f4SRuslan Bukin if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 56085ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 56185ae89f4SRuslan Bukin reg |= FFC_PM; 56285ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 56385ae89f4SRuslan Bukin } else { 56485ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 56585ae89f4SRuslan Bukin reg &= ~FFC_PM; 56685ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 56785ae89f4SRuslan Bukin 568*4d50c26aSGleb Smirnoff if_foreach_llmaddr(ifp, xae_write_maddr, sc); 56985ae89f4SRuslan Bukin } 57085ae89f4SRuslan Bukin 57185ae89f4SRuslan Bukin /* 57285ae89f4SRuslan Bukin * Set the primary address. 57385ae89f4SRuslan Bukin */ 57485ae89f4SRuslan Bukin reg = sc->macaddr[0]; 57585ae89f4SRuslan Bukin reg |= (sc->macaddr[1] << 8); 57685ae89f4SRuslan Bukin reg |= (sc->macaddr[2] << 16); 57785ae89f4SRuslan Bukin reg |= (sc->macaddr[3] << 24); 57885ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW0, reg); 57985ae89f4SRuslan Bukin 58085ae89f4SRuslan Bukin reg = sc->macaddr[4]; 58185ae89f4SRuslan Bukin reg |= (sc->macaddr[5] << 8); 58285ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW1, reg); 58385ae89f4SRuslan Bukin } 58485ae89f4SRuslan Bukin 58585ae89f4SRuslan Bukin static int 58685ae89f4SRuslan Bukin xae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 58785ae89f4SRuslan Bukin { 58885ae89f4SRuslan Bukin struct xae_softc *sc; 58985ae89f4SRuslan Bukin struct mii_data *mii; 59085ae89f4SRuslan Bukin struct ifreq *ifr; 59185ae89f4SRuslan Bukin int mask, error; 59285ae89f4SRuslan Bukin 59385ae89f4SRuslan Bukin sc = ifp->if_softc; 59485ae89f4SRuslan Bukin ifr = (struct ifreq *)data; 59585ae89f4SRuslan Bukin 59685ae89f4SRuslan Bukin error = 0; 59785ae89f4SRuslan Bukin switch (cmd) { 59885ae89f4SRuslan Bukin case SIOCSIFFLAGS: 59985ae89f4SRuslan Bukin XAE_LOCK(sc); 60085ae89f4SRuslan Bukin if (ifp->if_flags & IFF_UP) { 60185ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 60285ae89f4SRuslan Bukin if ((ifp->if_flags ^ sc->if_flags) & 60385ae89f4SRuslan Bukin (IFF_PROMISC | IFF_ALLMULTI)) 60485ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 60585ae89f4SRuslan Bukin } else { 60685ae89f4SRuslan Bukin if (!sc->is_detaching) 60785ae89f4SRuslan Bukin xae_init_locked(sc); 60885ae89f4SRuslan Bukin } 60985ae89f4SRuslan Bukin } else { 61085ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 61185ae89f4SRuslan Bukin xae_stop_locked(sc); 61285ae89f4SRuslan Bukin } 61385ae89f4SRuslan Bukin sc->if_flags = ifp->if_flags; 61485ae89f4SRuslan Bukin XAE_UNLOCK(sc); 61585ae89f4SRuslan Bukin break; 61685ae89f4SRuslan Bukin case SIOCADDMULTI: 61785ae89f4SRuslan Bukin case SIOCDELMULTI: 61885ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 61985ae89f4SRuslan Bukin XAE_LOCK(sc); 62085ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 62185ae89f4SRuslan Bukin XAE_UNLOCK(sc); 62285ae89f4SRuslan Bukin } 62385ae89f4SRuslan Bukin break; 62485ae89f4SRuslan Bukin case SIOCSIFMEDIA: 62585ae89f4SRuslan Bukin case SIOCGIFMEDIA: 62685ae89f4SRuslan Bukin mii = sc->mii_softc; 62785ae89f4SRuslan Bukin error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 62885ae89f4SRuslan Bukin break; 62985ae89f4SRuslan Bukin case SIOCSIFCAP: 63085ae89f4SRuslan Bukin mask = ifp->if_capenable ^ ifr->ifr_reqcap; 63185ae89f4SRuslan Bukin if (mask & IFCAP_VLAN_MTU) { 63285ae89f4SRuslan Bukin /* No work to do except acknowledge the change took */ 63385ae89f4SRuslan Bukin ifp->if_capenable ^= IFCAP_VLAN_MTU; 63485ae89f4SRuslan Bukin } 63585ae89f4SRuslan Bukin break; 63685ae89f4SRuslan Bukin 63785ae89f4SRuslan Bukin default: 63885ae89f4SRuslan Bukin error = ether_ioctl(ifp, cmd, data); 63985ae89f4SRuslan Bukin break; 64085ae89f4SRuslan Bukin } 64185ae89f4SRuslan Bukin 64285ae89f4SRuslan Bukin return (error); 64385ae89f4SRuslan Bukin } 64485ae89f4SRuslan Bukin 64585ae89f4SRuslan Bukin static void 64685ae89f4SRuslan Bukin xae_intr(void *arg) 64785ae89f4SRuslan Bukin { 64885ae89f4SRuslan Bukin 64985ae89f4SRuslan Bukin } 65085ae89f4SRuslan Bukin 65185ae89f4SRuslan Bukin static int 65285ae89f4SRuslan Bukin xae_get_hwaddr(struct xae_softc *sc, uint8_t *hwaddr) 65385ae89f4SRuslan Bukin { 65485ae89f4SRuslan Bukin phandle_t node; 65585ae89f4SRuslan Bukin int len; 65685ae89f4SRuslan Bukin 65785ae89f4SRuslan Bukin node = ofw_bus_get_node(sc->dev); 65885ae89f4SRuslan Bukin 65985ae89f4SRuslan Bukin /* Check if there is property */ 66085ae89f4SRuslan Bukin if ((len = OF_getproplen(node, "local-mac-address")) <= 0) 66185ae89f4SRuslan Bukin return (EINVAL); 66285ae89f4SRuslan Bukin 66385ae89f4SRuslan Bukin if (len != ETHER_ADDR_LEN) 66485ae89f4SRuslan Bukin return (EINVAL); 66585ae89f4SRuslan Bukin 66685ae89f4SRuslan Bukin OF_getprop(node, "local-mac-address", hwaddr, 66785ae89f4SRuslan Bukin ETHER_ADDR_LEN); 66885ae89f4SRuslan Bukin 66985ae89f4SRuslan Bukin return (0); 67085ae89f4SRuslan Bukin } 67185ae89f4SRuslan Bukin 67285ae89f4SRuslan Bukin static int 67385ae89f4SRuslan Bukin mdio_wait(struct xae_softc *sc) 67485ae89f4SRuslan Bukin { 67585ae89f4SRuslan Bukin uint32_t reg; 67685ae89f4SRuslan Bukin int timeout; 67785ae89f4SRuslan Bukin 67885ae89f4SRuslan Bukin timeout = 200; 67985ae89f4SRuslan Bukin 68085ae89f4SRuslan Bukin do { 68185ae89f4SRuslan Bukin reg = READ4(sc, XAE_MDIO_CTRL); 68285ae89f4SRuslan Bukin if (reg & MDIO_CTRL_READY) 68385ae89f4SRuslan Bukin break; 68485ae89f4SRuslan Bukin DELAY(1); 68585ae89f4SRuslan Bukin } while (timeout--); 68685ae89f4SRuslan Bukin 68785ae89f4SRuslan Bukin if (timeout <= 0) { 68885ae89f4SRuslan Bukin printf("Failed to get MDIO ready\n"); 68985ae89f4SRuslan Bukin return (1); 69085ae89f4SRuslan Bukin } 69185ae89f4SRuslan Bukin 69285ae89f4SRuslan Bukin return (0); 69385ae89f4SRuslan Bukin } 69485ae89f4SRuslan Bukin 69585ae89f4SRuslan Bukin static int 69685ae89f4SRuslan Bukin xae_miibus_read_reg(device_t dev, int phy, int reg) 69785ae89f4SRuslan Bukin { 69885ae89f4SRuslan Bukin struct xae_softc *sc; 69985ae89f4SRuslan Bukin uint32_t mii; 70085ae89f4SRuslan Bukin int rv; 70185ae89f4SRuslan Bukin 70285ae89f4SRuslan Bukin sc = device_get_softc(dev); 70385ae89f4SRuslan Bukin 70485ae89f4SRuslan Bukin if (mdio_wait(sc)) 70585ae89f4SRuslan Bukin return (0); 70685ae89f4SRuslan Bukin 70785ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_READ | MDIO_CTRL_INITIATE; 70885ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 70985ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 71085ae89f4SRuslan Bukin 71185ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 71285ae89f4SRuslan Bukin 71385ae89f4SRuslan Bukin if (mdio_wait(sc)) 71485ae89f4SRuslan Bukin return (0); 71585ae89f4SRuslan Bukin 71685ae89f4SRuslan Bukin rv = READ4(sc, XAE_MDIO_READ); 71785ae89f4SRuslan Bukin 71885ae89f4SRuslan Bukin return (rv); 71985ae89f4SRuslan Bukin } 72085ae89f4SRuslan Bukin 72185ae89f4SRuslan Bukin static int 72285ae89f4SRuslan Bukin xae_miibus_write_reg(device_t dev, int phy, int reg, int val) 72385ae89f4SRuslan Bukin { 72485ae89f4SRuslan Bukin struct xae_softc *sc; 72585ae89f4SRuslan Bukin uint32_t mii; 72685ae89f4SRuslan Bukin 72785ae89f4SRuslan Bukin sc = device_get_softc(dev); 72885ae89f4SRuslan Bukin 72985ae89f4SRuslan Bukin if (mdio_wait(sc)) 73085ae89f4SRuslan Bukin return (1); 73185ae89f4SRuslan Bukin 73285ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_WRITE | MDIO_CTRL_INITIATE; 73385ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 73485ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 73585ae89f4SRuslan Bukin 73685ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_WRITE, val); 73785ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 73885ae89f4SRuslan Bukin 73985ae89f4SRuslan Bukin if (mdio_wait(sc)) 74085ae89f4SRuslan Bukin return (1); 74185ae89f4SRuslan Bukin 74285ae89f4SRuslan Bukin return (0); 74385ae89f4SRuslan Bukin } 74485ae89f4SRuslan Bukin 74585ae89f4SRuslan Bukin static void 74685ae89f4SRuslan Bukin xae_phy_fixup(struct xae_softc *sc) 74785ae89f4SRuslan Bukin { 74885ae89f4SRuslan Bukin uint32_t reg; 74985ae89f4SRuslan Bukin device_t dev; 75085ae89f4SRuslan Bukin 75185ae89f4SRuslan Bukin dev = sc->dev; 75285ae89f4SRuslan Bukin 75385ae89f4SRuslan Bukin do { 75485ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_SGMIICTL1, SGMIICTL1_SGMII_6W); 75585ae89f4SRuslan Bukin PHY_WR(sc, DP83867_PHYCR, PHYCR_SGMII_EN); 75685ae89f4SRuslan Bukin 75785ae89f4SRuslan Bukin reg = PHY_RD(sc, DP83867_CFG2); 75885ae89f4SRuslan Bukin reg &= ~CFG2_SPEED_OPT_ATTEMPT_CNT_M; 75985ae89f4SRuslan Bukin reg |= (CFG2_SPEED_OPT_ATTEMPT_CNT_4); 76085ae89f4SRuslan Bukin reg |= CFG2_INTERRUPT_POLARITY; 76185ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_ENHANCED_EN; 76285ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_10M_EN; 76385ae89f4SRuslan Bukin PHY_WR(sc, DP83867_CFG2, reg); 76485ae89f4SRuslan Bukin 76585ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_CFG4, CFG4_SGMII_TMR); 76685ae89f4SRuslan Bukin PHY_WR(sc, MII_BMCR, 76785ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_RESET); 76885ae89f4SRuslan Bukin } while (PHY1_RD(sc, MII_BMCR) == 0x0ffff); 76985ae89f4SRuslan Bukin 77085ae89f4SRuslan Bukin do { 77185ae89f4SRuslan Bukin PHY1_WR(sc, MII_BMCR, 77285ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_STARTNEG); 77385ae89f4SRuslan Bukin DELAY(40000); 77485ae89f4SRuslan Bukin } while ((PHY1_RD(sc, MII_BMSR) & BMSR_ACOMP) == 0); 77585ae89f4SRuslan Bukin } 77685ae89f4SRuslan Bukin 77785ae89f4SRuslan Bukin static int 77885ae89f4SRuslan Bukin setup_xdma(struct xae_softc *sc) 77985ae89f4SRuslan Bukin { 78085ae89f4SRuslan Bukin device_t dev; 78185ae89f4SRuslan Bukin vmem_t *vmem; 78285ae89f4SRuslan Bukin int error; 78385ae89f4SRuslan Bukin 78485ae89f4SRuslan Bukin dev = sc->dev; 78585ae89f4SRuslan Bukin 78685ae89f4SRuslan Bukin /* Get xDMA controller */ 78785ae89f4SRuslan Bukin sc->xdma_tx = xdma_ofw_get(sc->dev, "tx"); 78885ae89f4SRuslan Bukin if (sc->xdma_tx == NULL) { 78985ae89f4SRuslan Bukin device_printf(dev, "Could not find DMA controller.\n"); 79085ae89f4SRuslan Bukin return (ENXIO); 79185ae89f4SRuslan Bukin } 79285ae89f4SRuslan Bukin 79385ae89f4SRuslan Bukin sc->xdma_rx = xdma_ofw_get(sc->dev, "rx"); 79485ae89f4SRuslan Bukin if (sc->xdma_rx == NULL) { 79585ae89f4SRuslan Bukin device_printf(dev, "Could not find DMA controller.\n"); 79685ae89f4SRuslan Bukin return (ENXIO); 79785ae89f4SRuslan Bukin } 79885ae89f4SRuslan Bukin 79985ae89f4SRuslan Bukin /* Alloc xDMA TX virtual channel. */ 80085ae89f4SRuslan Bukin sc->xchan_tx = xdma_channel_alloc(sc->xdma_tx, 0); 80185ae89f4SRuslan Bukin if (sc->xchan_tx == NULL) { 80285ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA TX channel.\n"); 80385ae89f4SRuslan Bukin return (ENXIO); 80485ae89f4SRuslan Bukin } 80585ae89f4SRuslan Bukin 80685ae89f4SRuslan Bukin /* Setup interrupt handler. */ 80785ae89f4SRuslan Bukin error = xdma_setup_intr(sc->xchan_tx, 80885ae89f4SRuslan Bukin xae_xdma_tx_intr, sc, &sc->ih_tx); 80985ae89f4SRuslan Bukin if (error) { 81085ae89f4SRuslan Bukin device_printf(sc->dev, 81185ae89f4SRuslan Bukin "Can't setup xDMA TX interrupt handler.\n"); 81285ae89f4SRuslan Bukin return (ENXIO); 81385ae89f4SRuslan Bukin } 81485ae89f4SRuslan Bukin 81585ae89f4SRuslan Bukin /* Alloc xDMA RX virtual channel. */ 81685ae89f4SRuslan Bukin sc->xchan_rx = xdma_channel_alloc(sc->xdma_rx, 0); 81785ae89f4SRuslan Bukin if (sc->xchan_rx == NULL) { 81885ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA RX channel.\n"); 81985ae89f4SRuslan Bukin return (ENXIO); 82085ae89f4SRuslan Bukin } 82185ae89f4SRuslan Bukin 82285ae89f4SRuslan Bukin /* Setup interrupt handler. */ 82385ae89f4SRuslan Bukin error = xdma_setup_intr(sc->xchan_rx, 82485ae89f4SRuslan Bukin xae_xdma_rx_intr, sc, &sc->ih_rx); 82585ae89f4SRuslan Bukin if (error) { 82685ae89f4SRuslan Bukin device_printf(sc->dev, 82785ae89f4SRuslan Bukin "Can't setup xDMA RX interrupt handler.\n"); 82885ae89f4SRuslan Bukin return (ENXIO); 82985ae89f4SRuslan Bukin } 83085ae89f4SRuslan Bukin 83185ae89f4SRuslan Bukin /* Setup bounce buffer */ 83285ae89f4SRuslan Bukin vmem = xdma_get_memory(dev); 83385ae89f4SRuslan Bukin if (vmem) { 83485ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_tx, vmem); 83585ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_rx, vmem); 83685ae89f4SRuslan Bukin } 83785ae89f4SRuslan Bukin 83885ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_tx, 83985ae89f4SRuslan Bukin TX_QUEUE_SIZE, /* xchan requests queue size */ 84085ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 84185ae89f4SRuslan Bukin 8, /* maxnsegs */ 84285ae89f4SRuslan Bukin 16, /* alignment */ 84385ae89f4SRuslan Bukin 0, /* boundary */ 84485ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 84585ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 84685ae89f4SRuslan Bukin 84785ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_rx, 84885ae89f4SRuslan Bukin RX_QUEUE_SIZE, /* xchan requests queue size */ 84985ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 85085ae89f4SRuslan Bukin 1, /* maxnsegs */ 85185ae89f4SRuslan Bukin 16, /* alignment */ 85285ae89f4SRuslan Bukin 0, /* boundary */ 85385ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 85485ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 85585ae89f4SRuslan Bukin 85685ae89f4SRuslan Bukin return (0); 85785ae89f4SRuslan Bukin } 85885ae89f4SRuslan Bukin 85985ae89f4SRuslan Bukin static int 86085ae89f4SRuslan Bukin xae_probe(device_t dev) 86185ae89f4SRuslan Bukin { 86285ae89f4SRuslan Bukin 86385ae89f4SRuslan Bukin if (!ofw_bus_status_okay(dev)) 86485ae89f4SRuslan Bukin return (ENXIO); 86585ae89f4SRuslan Bukin 86685ae89f4SRuslan Bukin if (!ofw_bus_is_compatible(dev, "xlnx,axi-ethernet-1.00.a")) 86785ae89f4SRuslan Bukin return (ENXIO); 86885ae89f4SRuslan Bukin 86985ae89f4SRuslan Bukin device_set_desc(dev, "Xilinx AXI Ethernet"); 87085ae89f4SRuslan Bukin 87185ae89f4SRuslan Bukin return (BUS_PROBE_DEFAULT); 87285ae89f4SRuslan Bukin } 87385ae89f4SRuslan Bukin 87485ae89f4SRuslan Bukin static int 87585ae89f4SRuslan Bukin xae_attach(device_t dev) 87685ae89f4SRuslan Bukin { 87785ae89f4SRuslan Bukin struct xae_softc *sc; 87885ae89f4SRuslan Bukin struct ifnet *ifp; 87985ae89f4SRuslan Bukin phandle_t node; 88085ae89f4SRuslan Bukin uint32_t reg; 88185ae89f4SRuslan Bukin int error; 88285ae89f4SRuslan Bukin 88385ae89f4SRuslan Bukin sc = device_get_softc(dev); 88485ae89f4SRuslan Bukin sc->dev = dev; 88585ae89f4SRuslan Bukin node = ofw_bus_get_node(dev); 88685ae89f4SRuslan Bukin 88785ae89f4SRuslan Bukin if (setup_xdma(sc) != 0) { 88885ae89f4SRuslan Bukin device_printf(dev, "Could not setup xDMA.\n"); 88985ae89f4SRuslan Bukin return (ENXIO); 89085ae89f4SRuslan Bukin } 89185ae89f4SRuslan Bukin 89285ae89f4SRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 89385ae89f4SRuslan Bukin MTX_NETWORK_LOCK, MTX_DEF); 89485ae89f4SRuslan Bukin 89585ae89f4SRuslan Bukin sc->br = buf_ring_alloc(BUFRING_SIZE, M_DEVBUF, 89685ae89f4SRuslan Bukin M_NOWAIT, &sc->mtx); 89785ae89f4SRuslan Bukin if (sc->br == NULL) 89885ae89f4SRuslan Bukin return (ENOMEM); 89985ae89f4SRuslan Bukin 90085ae89f4SRuslan Bukin if (bus_alloc_resources(dev, xae_spec, sc->res)) { 90185ae89f4SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 90285ae89f4SRuslan Bukin return (ENXIO); 90385ae89f4SRuslan Bukin } 90485ae89f4SRuslan Bukin 90585ae89f4SRuslan Bukin /* Memory interface */ 90685ae89f4SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 90785ae89f4SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 90885ae89f4SRuslan Bukin 90985ae89f4SRuslan Bukin device_printf(sc->dev, "Identification: %x\n", 91085ae89f4SRuslan Bukin READ4(sc, XAE_IDENT)); 91185ae89f4SRuslan Bukin 91285ae89f4SRuslan Bukin /* Get MAC addr */ 91385ae89f4SRuslan Bukin if (xae_get_hwaddr(sc, sc->macaddr)) { 91485ae89f4SRuslan Bukin device_printf(sc->dev, "can't get mac\n"); 91585ae89f4SRuslan Bukin return (ENXIO); 91685ae89f4SRuslan Bukin } 91785ae89f4SRuslan Bukin 91885ae89f4SRuslan Bukin /* Enable MII clock */ 91985ae89f4SRuslan Bukin reg = (MDIO_CLK_DIV_DEFAULT << MDIO_SETUP_CLK_DIV_S); 92085ae89f4SRuslan Bukin reg |= MDIO_SETUP_ENABLE; 92185ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_SETUP, reg); 92285ae89f4SRuslan Bukin if (mdio_wait(sc)) 92385ae89f4SRuslan Bukin return (ENXIO); 92485ae89f4SRuslan Bukin 92585ae89f4SRuslan Bukin callout_init_mtx(&sc->xae_callout, &sc->mtx, 0); 92685ae89f4SRuslan Bukin 92785ae89f4SRuslan Bukin /* Setup interrupt handler. */ 92885ae89f4SRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 92985ae89f4SRuslan Bukin NULL, xae_intr, sc, &sc->intr_cookie); 93085ae89f4SRuslan Bukin if (error != 0) { 93185ae89f4SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 93285ae89f4SRuslan Bukin return (ENXIO); 93385ae89f4SRuslan Bukin } 93485ae89f4SRuslan Bukin 93585ae89f4SRuslan Bukin /* Set up the ethernet interface. */ 93685ae89f4SRuslan Bukin sc->ifp = ifp = if_alloc(IFT_ETHER); 93785ae89f4SRuslan Bukin if (ifp == NULL) { 93885ae89f4SRuslan Bukin device_printf(dev, "could not allocate ifp.\n"); 93985ae89f4SRuslan Bukin return (ENXIO); 94085ae89f4SRuslan Bukin } 94185ae89f4SRuslan Bukin 94285ae89f4SRuslan Bukin ifp->if_softc = sc; 94385ae89f4SRuslan Bukin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 94485ae89f4SRuslan Bukin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 94585ae89f4SRuslan Bukin ifp->if_capabilities = IFCAP_VLAN_MTU; 94685ae89f4SRuslan Bukin ifp->if_capenable = ifp->if_capabilities; 94785ae89f4SRuslan Bukin ifp->if_transmit = xae_transmit; 94885ae89f4SRuslan Bukin ifp->if_qflush = xae_qflush; 94985ae89f4SRuslan Bukin ifp->if_ioctl = xae_ioctl; 95085ae89f4SRuslan Bukin ifp->if_init = xae_init; 95185ae89f4SRuslan Bukin IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1); 95285ae89f4SRuslan Bukin ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1; 95385ae89f4SRuslan Bukin IFQ_SET_READY(&ifp->if_snd); 95485ae89f4SRuslan Bukin 95585ae89f4SRuslan Bukin if (xae_get_phyaddr(node, &sc->phy_addr) != 0) 95685ae89f4SRuslan Bukin return (ENXIO); 95785ae89f4SRuslan Bukin 95885ae89f4SRuslan Bukin /* Attach the mii driver. */ 95985ae89f4SRuslan Bukin error = mii_attach(dev, &sc->miibus, ifp, xae_media_change, 96085ae89f4SRuslan Bukin xae_media_status, BMSR_DEFCAPMASK, sc->phy_addr, 96185ae89f4SRuslan Bukin MII_OFFSET_ANY, 0); 96285ae89f4SRuslan Bukin 96385ae89f4SRuslan Bukin if (error != 0) { 96485ae89f4SRuslan Bukin device_printf(dev, "PHY attach failed\n"); 96585ae89f4SRuslan Bukin return (ENXIO); 96685ae89f4SRuslan Bukin } 96785ae89f4SRuslan Bukin sc->mii_softc = device_get_softc(sc->miibus); 96885ae89f4SRuslan Bukin 96985ae89f4SRuslan Bukin /* Apply vcu118 workaround. */ 97085ae89f4SRuslan Bukin if (OF_getproplen(node, "xlnx,vcu118") >= 0) 97185ae89f4SRuslan Bukin xae_phy_fixup(sc); 97285ae89f4SRuslan Bukin 97385ae89f4SRuslan Bukin /* All ready to run, attach the ethernet interface. */ 97485ae89f4SRuslan Bukin ether_ifattach(ifp, sc->macaddr); 97585ae89f4SRuslan Bukin sc->is_attached = true; 97685ae89f4SRuslan Bukin 97785ae89f4SRuslan Bukin xae_rx_enqueue(sc, NUM_RX_MBUF); 97885ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_rx); 97985ae89f4SRuslan Bukin 98085ae89f4SRuslan Bukin return (0); 98185ae89f4SRuslan Bukin } 98285ae89f4SRuslan Bukin 98385ae89f4SRuslan Bukin static int 98485ae89f4SRuslan Bukin xae_detach(device_t dev) 98585ae89f4SRuslan Bukin { 98685ae89f4SRuslan Bukin struct xae_softc *sc; 98785ae89f4SRuslan Bukin struct ifnet *ifp; 98885ae89f4SRuslan Bukin 98985ae89f4SRuslan Bukin sc = device_get_softc(dev); 99085ae89f4SRuslan Bukin 99185ae89f4SRuslan Bukin KASSERT(mtx_initialized(&sc->mtx), ("%s: mutex not initialized", 99285ae89f4SRuslan Bukin device_get_nameunit(dev))); 99385ae89f4SRuslan Bukin 99485ae89f4SRuslan Bukin ifp = sc->ifp; 99585ae89f4SRuslan Bukin 99685ae89f4SRuslan Bukin /* Only cleanup if attach succeeded. */ 99785ae89f4SRuslan Bukin if (device_is_attached(dev)) { 99885ae89f4SRuslan Bukin XAE_LOCK(sc); 99985ae89f4SRuslan Bukin xae_stop_locked(sc); 100085ae89f4SRuslan Bukin XAE_UNLOCK(sc); 100185ae89f4SRuslan Bukin callout_drain(&sc->xae_callout); 100285ae89f4SRuslan Bukin ether_ifdetach(ifp); 100385ae89f4SRuslan Bukin } 100485ae89f4SRuslan Bukin 100585ae89f4SRuslan Bukin if (sc->miibus != NULL) 100685ae89f4SRuslan Bukin device_delete_child(dev, sc->miibus); 100785ae89f4SRuslan Bukin 100885ae89f4SRuslan Bukin if (ifp != NULL) 100985ae89f4SRuslan Bukin if_free(ifp); 101085ae89f4SRuslan Bukin 101185ae89f4SRuslan Bukin mtx_destroy(&sc->mtx); 101285ae89f4SRuslan Bukin 101385ae89f4SRuslan Bukin bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 101485ae89f4SRuslan Bukin 101585ae89f4SRuslan Bukin bus_release_resources(dev, xae_spec, sc->res); 101685ae89f4SRuslan Bukin 101785ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_tx); 101885ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_rx); 101985ae89f4SRuslan Bukin xdma_put(sc->xdma_tx); 102085ae89f4SRuslan Bukin xdma_put(sc->xdma_rx); 102185ae89f4SRuslan Bukin 102285ae89f4SRuslan Bukin return (0); 102385ae89f4SRuslan Bukin } 102485ae89f4SRuslan Bukin 102585ae89f4SRuslan Bukin static void 102685ae89f4SRuslan Bukin xae_miibus_statchg(device_t dev) 102785ae89f4SRuslan Bukin { 102885ae89f4SRuslan Bukin struct xae_softc *sc; 102985ae89f4SRuslan Bukin struct mii_data *mii; 103085ae89f4SRuslan Bukin uint32_t reg; 103185ae89f4SRuslan Bukin 103285ae89f4SRuslan Bukin /* 103385ae89f4SRuslan Bukin * Called by the MII bus driver when the PHY establishes 103485ae89f4SRuslan Bukin * link to set the MAC interface registers. 103585ae89f4SRuslan Bukin */ 103685ae89f4SRuslan Bukin 103785ae89f4SRuslan Bukin sc = device_get_softc(dev); 103885ae89f4SRuslan Bukin 103985ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 104085ae89f4SRuslan Bukin 104185ae89f4SRuslan Bukin mii = sc->mii_softc; 104285ae89f4SRuslan Bukin 104385ae89f4SRuslan Bukin if (mii->mii_media_status & IFM_ACTIVE) 104485ae89f4SRuslan Bukin sc->link_is_up = true; 104585ae89f4SRuslan Bukin else 104685ae89f4SRuslan Bukin sc->link_is_up = false; 104785ae89f4SRuslan Bukin 104885ae89f4SRuslan Bukin switch (IFM_SUBTYPE(mii->mii_media_active)) { 104985ae89f4SRuslan Bukin case IFM_1000_T: 105085ae89f4SRuslan Bukin case IFM_1000_SX: 105185ae89f4SRuslan Bukin reg = SPEED_1000; 105285ae89f4SRuslan Bukin break; 105385ae89f4SRuslan Bukin case IFM_100_TX: 105485ae89f4SRuslan Bukin reg = SPEED_100; 105585ae89f4SRuslan Bukin break; 105685ae89f4SRuslan Bukin case IFM_10_T: 105785ae89f4SRuslan Bukin reg = SPEED_10; 105885ae89f4SRuslan Bukin break; 105985ae89f4SRuslan Bukin case IFM_NONE: 106085ae89f4SRuslan Bukin sc->link_is_up = false; 106185ae89f4SRuslan Bukin return; 106285ae89f4SRuslan Bukin default: 106385ae89f4SRuslan Bukin sc->link_is_up = false; 106485ae89f4SRuslan Bukin device_printf(dev, "Unsupported media %u\n", 106585ae89f4SRuslan Bukin IFM_SUBTYPE(mii->mii_media_active)); 106685ae89f4SRuslan Bukin return; 106785ae89f4SRuslan Bukin } 106885ae89f4SRuslan Bukin 106985ae89f4SRuslan Bukin WRITE4(sc, XAE_SPEED, reg); 107085ae89f4SRuslan Bukin } 107185ae89f4SRuslan Bukin 107285ae89f4SRuslan Bukin static device_method_t xae_methods[] = { 107385ae89f4SRuslan Bukin DEVMETHOD(device_probe, xae_probe), 107485ae89f4SRuslan Bukin DEVMETHOD(device_attach, xae_attach), 107585ae89f4SRuslan Bukin DEVMETHOD(device_detach, xae_detach), 107685ae89f4SRuslan Bukin 107785ae89f4SRuslan Bukin /* MII Interface */ 107885ae89f4SRuslan Bukin DEVMETHOD(miibus_readreg, xae_miibus_read_reg), 107985ae89f4SRuslan Bukin DEVMETHOD(miibus_writereg, xae_miibus_write_reg), 108085ae89f4SRuslan Bukin DEVMETHOD(miibus_statchg, xae_miibus_statchg), 108185ae89f4SRuslan Bukin 108285ae89f4SRuslan Bukin { 0, 0 } 108385ae89f4SRuslan Bukin }; 108485ae89f4SRuslan Bukin 108585ae89f4SRuslan Bukin driver_t xae_driver = { 108685ae89f4SRuslan Bukin "xae", 108785ae89f4SRuslan Bukin xae_methods, 108885ae89f4SRuslan Bukin sizeof(struct xae_softc), 108985ae89f4SRuslan Bukin }; 109085ae89f4SRuslan Bukin 109185ae89f4SRuslan Bukin static devclass_t xae_devclass; 109285ae89f4SRuslan Bukin 109385ae89f4SRuslan Bukin DRIVER_MODULE(xae, simplebus, xae_driver, xae_devclass, 0, 0); 109485ae89f4SRuslan Bukin DRIVER_MODULE(miibus, xae, miibus_driver, miibus_devclass, 0, 0); 109585ae89f4SRuslan Bukin 109685ae89f4SRuslan Bukin MODULE_DEPEND(xae, ether, 1, 1, 1); 109785ae89f4SRuslan Bukin MODULE_DEPEND(xae, miibus, 1, 1, 1); 1098