1*85ae89f4SRuslan Bukin /*- 2*85ae89f4SRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause 3*85ae89f4SRuslan Bukin * 4*85ae89f4SRuslan Bukin * Copyright (c) 2019 Ruslan Bukin <br@bsdpad.com> 5*85ae89f4SRuslan Bukin * 6*85ae89f4SRuslan Bukin * This software was developed by SRI International and the University of 7*85ae89f4SRuslan Bukin * Cambridge Computer Laboratory (Department of Computer Science and 8*85ae89f4SRuslan Bukin * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the 9*85ae89f4SRuslan Bukin * DARPA SSITH research programme. 10*85ae89f4SRuslan Bukin * 11*85ae89f4SRuslan Bukin * Redistribution and use in source and binary forms, with or without 12*85ae89f4SRuslan Bukin * modification, are permitted provided that the following conditions 13*85ae89f4SRuslan Bukin * are met: 14*85ae89f4SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 15*85ae89f4SRuslan Bukin * notice, this list of conditions and the following disclaimer. 16*85ae89f4SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 17*85ae89f4SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 18*85ae89f4SRuslan Bukin * documentation and/or other materials provided with the distribution. 19*85ae89f4SRuslan Bukin * 20*85ae89f4SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21*85ae89f4SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*85ae89f4SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*85ae89f4SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24*85ae89f4SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25*85ae89f4SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26*85ae89f4SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27*85ae89f4SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28*85ae89f4SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29*85ae89f4SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30*85ae89f4SRuslan Bukin * SUCH DAMAGE. 31*85ae89f4SRuslan Bukin */ 32*85ae89f4SRuslan Bukin 33*85ae89f4SRuslan Bukin #include <sys/cdefs.h> 34*85ae89f4SRuslan Bukin __FBSDID("$FreeBSD$"); 35*85ae89f4SRuslan Bukin 36*85ae89f4SRuslan Bukin #include <sys/param.h> 37*85ae89f4SRuslan Bukin #include <sys/systm.h> 38*85ae89f4SRuslan Bukin #include <sys/bus.h> 39*85ae89f4SRuslan Bukin #include <sys/kernel.h> 40*85ae89f4SRuslan Bukin #include <sys/lock.h> 41*85ae89f4SRuslan Bukin #include <sys/malloc.h> 42*85ae89f4SRuslan Bukin #include <sys/mbuf.h> 43*85ae89f4SRuslan Bukin #include <sys/module.h> 44*85ae89f4SRuslan Bukin #include <sys/mutex.h> 45*85ae89f4SRuslan Bukin #include <sys/rman.h> 46*85ae89f4SRuslan Bukin #include <sys/socket.h> 47*85ae89f4SRuslan Bukin #include <sys/sockio.h> 48*85ae89f4SRuslan Bukin 49*85ae89f4SRuslan Bukin #include <net/bpf.h> 50*85ae89f4SRuslan Bukin #include <net/if.h> 51*85ae89f4SRuslan Bukin #include <net/ethernet.h> 52*85ae89f4SRuslan Bukin #include <net/if_dl.h> 53*85ae89f4SRuslan Bukin #include <net/if_media.h> 54*85ae89f4SRuslan Bukin #include <net/if_types.h> 55*85ae89f4SRuslan Bukin #include <net/if_var.h> 56*85ae89f4SRuslan Bukin 57*85ae89f4SRuslan Bukin #include <machine/bus.h> 58*85ae89f4SRuslan Bukin 59*85ae89f4SRuslan Bukin #include <dev/mii/mii.h> 60*85ae89f4SRuslan Bukin #include <dev/mii/miivar.h> 61*85ae89f4SRuslan Bukin #include <dev/mii/tiphy.h> 62*85ae89f4SRuslan Bukin #include <dev/ofw/ofw_bus.h> 63*85ae89f4SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 64*85ae89f4SRuslan Bukin #include <dev/xilinx/if_xaereg.h> 65*85ae89f4SRuslan Bukin #include <dev/xilinx/if_xaevar.h> 66*85ae89f4SRuslan Bukin 67*85ae89f4SRuslan Bukin #include "miibus_if.h" 68*85ae89f4SRuslan Bukin 69*85ae89f4SRuslan Bukin #define READ4(_sc, _reg) \ 70*85ae89f4SRuslan Bukin bus_read_4((_sc)->res[0], _reg) 71*85ae89f4SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 72*85ae89f4SRuslan Bukin bus_write_4((_sc)->res[0], _reg, _val) 73*85ae89f4SRuslan Bukin 74*85ae89f4SRuslan Bukin #define READ8(_sc, _reg) \ 75*85ae89f4SRuslan Bukin bus_read_8((_sc)->res[0], _reg) 76*85ae89f4SRuslan Bukin #define WRITE8(_sc, _reg, _val) \ 77*85ae89f4SRuslan Bukin bus_write_8((_sc)->res[0], _reg, _val) 78*85ae89f4SRuslan Bukin 79*85ae89f4SRuslan Bukin #define XAE_LOCK(sc) mtx_lock(&(sc)->mtx) 80*85ae89f4SRuslan Bukin #define XAE_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 81*85ae89f4SRuslan Bukin #define XAE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) 82*85ae89f4SRuslan Bukin #define XAE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) 83*85ae89f4SRuslan Bukin 84*85ae89f4SRuslan Bukin #define XAE_DEBUG 85*85ae89f4SRuslan Bukin #undef XAE_DEBUG 86*85ae89f4SRuslan Bukin 87*85ae89f4SRuslan Bukin #ifdef XAE_DEBUG 88*85ae89f4SRuslan Bukin #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) 89*85ae89f4SRuslan Bukin #else 90*85ae89f4SRuslan Bukin #define dprintf(fmt, ...) 91*85ae89f4SRuslan Bukin #endif 92*85ae89f4SRuslan Bukin 93*85ae89f4SRuslan Bukin #define RX_QUEUE_SIZE 64 94*85ae89f4SRuslan Bukin #define TX_QUEUE_SIZE 64 95*85ae89f4SRuslan Bukin #define NUM_RX_MBUF 16 96*85ae89f4SRuslan Bukin #define BUFRING_SIZE 8192 97*85ae89f4SRuslan Bukin #define MDIO_CLK_DIV_DEFAULT 29 98*85ae89f4SRuslan Bukin 99*85ae89f4SRuslan Bukin #define PHY1_RD(sc, _r) \ 100*85ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, 1, _r) 101*85ae89f4SRuslan Bukin #define PHY1_WR(sc, _r, _v) \ 102*85ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, 1, _r, _v) 103*85ae89f4SRuslan Bukin 104*85ae89f4SRuslan Bukin #define PHY_RD(sc, _r) \ 105*85ae89f4SRuslan Bukin xae_miibus_read_reg(sc->dev, sc->phy_addr, _r) 106*85ae89f4SRuslan Bukin #define PHY_WR(sc, _r, _v) \ 107*85ae89f4SRuslan Bukin xae_miibus_write_reg(sc->dev, sc->phy_addr, _r, _v) 108*85ae89f4SRuslan Bukin 109*85ae89f4SRuslan Bukin /* Use this macro to access regs > 0x1f */ 110*85ae89f4SRuslan Bukin #define WRITE_TI_EREG(sc, reg, data) { \ 111*85ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK); \ 112*85ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, reg); \ 113*85ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDACR, MMDACR_DADDRMASK | MMDACR_FN_DATANPI); \ 114*85ae89f4SRuslan Bukin PHY_WR(sc, MII_MMDAADR, data); \ 115*85ae89f4SRuslan Bukin } 116*85ae89f4SRuslan Bukin 117*85ae89f4SRuslan Bukin /* Not documented, Xilinx VCU118 workaround */ 118*85ae89f4SRuslan Bukin #define CFG4_SGMII_TMR 0x160 /* bits 8:7 MUST be '10' */ 119*85ae89f4SRuslan Bukin #define DP83867_SGMIICTL1 0xD3 /* not documented register */ 120*85ae89f4SRuslan Bukin #define SGMIICTL1_SGMII_6W (1 << 14) /* no idea what it is */ 121*85ae89f4SRuslan Bukin 122*85ae89f4SRuslan Bukin static struct resource_spec xae_spec[] = { 123*85ae89f4SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 124*85ae89f4SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 125*85ae89f4SRuslan Bukin { -1, 0 } 126*85ae89f4SRuslan Bukin }; 127*85ae89f4SRuslan Bukin 128*85ae89f4SRuslan Bukin static void xae_stop_locked(struct xae_softc *sc); 129*85ae89f4SRuslan Bukin static void xae_setup_rxfilter(struct xae_softc *sc); 130*85ae89f4SRuslan Bukin 131*85ae89f4SRuslan Bukin static int 132*85ae89f4SRuslan Bukin xae_rx_enqueue(struct xae_softc *sc, uint32_t n) 133*85ae89f4SRuslan Bukin { 134*85ae89f4SRuslan Bukin struct mbuf *m; 135*85ae89f4SRuslan Bukin int i; 136*85ae89f4SRuslan Bukin 137*85ae89f4SRuslan Bukin for (i = 0; i < n; i++) { 138*85ae89f4SRuslan Bukin m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 139*85ae89f4SRuslan Bukin if (m == NULL) { 140*85ae89f4SRuslan Bukin device_printf(sc->dev, 141*85ae89f4SRuslan Bukin "%s: Can't alloc rx mbuf\n", __func__); 142*85ae89f4SRuslan Bukin return (-1); 143*85ae89f4SRuslan Bukin } 144*85ae89f4SRuslan Bukin 145*85ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 146*85ae89f4SRuslan Bukin xdma_enqueue_mbuf(sc->xchan_rx, &m, 0, 4, 4, XDMA_DEV_TO_MEM); 147*85ae89f4SRuslan Bukin } 148*85ae89f4SRuslan Bukin 149*85ae89f4SRuslan Bukin return (0); 150*85ae89f4SRuslan Bukin } 151*85ae89f4SRuslan Bukin 152*85ae89f4SRuslan Bukin static int 153*85ae89f4SRuslan Bukin xae_get_phyaddr(phandle_t node, int *phy_addr) 154*85ae89f4SRuslan Bukin { 155*85ae89f4SRuslan Bukin phandle_t phy_node; 156*85ae89f4SRuslan Bukin pcell_t phy_handle, phy_reg; 157*85ae89f4SRuslan Bukin 158*85ae89f4SRuslan Bukin if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, 159*85ae89f4SRuslan Bukin sizeof(phy_handle)) <= 0) 160*85ae89f4SRuslan Bukin return (ENXIO); 161*85ae89f4SRuslan Bukin 162*85ae89f4SRuslan Bukin phy_node = OF_node_from_xref(phy_handle); 163*85ae89f4SRuslan Bukin 164*85ae89f4SRuslan Bukin if (OF_getencprop(phy_node, "reg", (void *)&phy_reg, 165*85ae89f4SRuslan Bukin sizeof(phy_reg)) <= 0) 166*85ae89f4SRuslan Bukin return (ENXIO); 167*85ae89f4SRuslan Bukin 168*85ae89f4SRuslan Bukin *phy_addr = phy_reg; 169*85ae89f4SRuslan Bukin 170*85ae89f4SRuslan Bukin return (0); 171*85ae89f4SRuslan Bukin } 172*85ae89f4SRuslan Bukin 173*85ae89f4SRuslan Bukin static int 174*85ae89f4SRuslan Bukin xae_xdma_tx_intr(void *arg, xdma_transfer_status_t *status) 175*85ae89f4SRuslan Bukin { 176*85ae89f4SRuslan Bukin xdma_transfer_status_t st; 177*85ae89f4SRuslan Bukin struct xae_softc *sc; 178*85ae89f4SRuslan Bukin struct ifnet *ifp; 179*85ae89f4SRuslan Bukin struct mbuf *m; 180*85ae89f4SRuslan Bukin int err; 181*85ae89f4SRuslan Bukin 182*85ae89f4SRuslan Bukin sc = arg; 183*85ae89f4SRuslan Bukin 184*85ae89f4SRuslan Bukin XAE_LOCK(sc); 185*85ae89f4SRuslan Bukin 186*85ae89f4SRuslan Bukin ifp = sc->ifp; 187*85ae89f4SRuslan Bukin 188*85ae89f4SRuslan Bukin for (;;) { 189*85ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_tx, &m, &st); 190*85ae89f4SRuslan Bukin if (err != 0) { 191*85ae89f4SRuslan Bukin break; 192*85ae89f4SRuslan Bukin } 193*85ae89f4SRuslan Bukin 194*85ae89f4SRuslan Bukin if (st.error != 0) { 195*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 196*85ae89f4SRuslan Bukin } 197*85ae89f4SRuslan Bukin 198*85ae89f4SRuslan Bukin m_freem(m); 199*85ae89f4SRuslan Bukin } 200*85ae89f4SRuslan Bukin 201*85ae89f4SRuslan Bukin ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 202*85ae89f4SRuslan Bukin 203*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 204*85ae89f4SRuslan Bukin 205*85ae89f4SRuslan Bukin return (0); 206*85ae89f4SRuslan Bukin } 207*85ae89f4SRuslan Bukin 208*85ae89f4SRuslan Bukin static int 209*85ae89f4SRuslan Bukin xae_xdma_rx_intr(void *arg, xdma_transfer_status_t *status) 210*85ae89f4SRuslan Bukin { 211*85ae89f4SRuslan Bukin xdma_transfer_status_t st; 212*85ae89f4SRuslan Bukin struct xae_softc *sc; 213*85ae89f4SRuslan Bukin struct ifnet *ifp; 214*85ae89f4SRuslan Bukin struct mbuf *m; 215*85ae89f4SRuslan Bukin int err; 216*85ae89f4SRuslan Bukin uint32_t cnt_processed; 217*85ae89f4SRuslan Bukin 218*85ae89f4SRuslan Bukin sc = arg; 219*85ae89f4SRuslan Bukin 220*85ae89f4SRuslan Bukin dprintf("%s\n", __func__); 221*85ae89f4SRuslan Bukin 222*85ae89f4SRuslan Bukin XAE_LOCK(sc); 223*85ae89f4SRuslan Bukin 224*85ae89f4SRuslan Bukin ifp = sc->ifp; 225*85ae89f4SRuslan Bukin 226*85ae89f4SRuslan Bukin cnt_processed = 0; 227*85ae89f4SRuslan Bukin for (;;) { 228*85ae89f4SRuslan Bukin err = xdma_dequeue_mbuf(sc->xchan_rx, &m, &st); 229*85ae89f4SRuslan Bukin if (err != 0) { 230*85ae89f4SRuslan Bukin break; 231*85ae89f4SRuslan Bukin } 232*85ae89f4SRuslan Bukin cnt_processed++; 233*85ae89f4SRuslan Bukin 234*85ae89f4SRuslan Bukin if (st.error != 0) { 235*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 236*85ae89f4SRuslan Bukin m_freem(m); 237*85ae89f4SRuslan Bukin continue; 238*85ae89f4SRuslan Bukin } 239*85ae89f4SRuslan Bukin 240*85ae89f4SRuslan Bukin m->m_pkthdr.len = m->m_len = st.transferred; 241*85ae89f4SRuslan Bukin m->m_pkthdr.rcvif = ifp; 242*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 243*85ae89f4SRuslan Bukin (*ifp->if_input)(ifp, m); 244*85ae89f4SRuslan Bukin XAE_LOCK(sc); 245*85ae89f4SRuslan Bukin } 246*85ae89f4SRuslan Bukin 247*85ae89f4SRuslan Bukin xae_rx_enqueue(sc, cnt_processed); 248*85ae89f4SRuslan Bukin 249*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 250*85ae89f4SRuslan Bukin 251*85ae89f4SRuslan Bukin return (0); 252*85ae89f4SRuslan Bukin } 253*85ae89f4SRuslan Bukin 254*85ae89f4SRuslan Bukin static void 255*85ae89f4SRuslan Bukin xae_qflush(struct ifnet *ifp) 256*85ae89f4SRuslan Bukin { 257*85ae89f4SRuslan Bukin struct xae_softc *sc; 258*85ae89f4SRuslan Bukin 259*85ae89f4SRuslan Bukin sc = ifp->if_softc; 260*85ae89f4SRuslan Bukin } 261*85ae89f4SRuslan Bukin 262*85ae89f4SRuslan Bukin static int 263*85ae89f4SRuslan Bukin xae_transmit_locked(struct ifnet *ifp) 264*85ae89f4SRuslan Bukin { 265*85ae89f4SRuslan Bukin struct xae_softc *sc; 266*85ae89f4SRuslan Bukin struct mbuf *m; 267*85ae89f4SRuslan Bukin struct buf_ring *br; 268*85ae89f4SRuslan Bukin int error; 269*85ae89f4SRuslan Bukin int enq; 270*85ae89f4SRuslan Bukin 271*85ae89f4SRuslan Bukin dprintf("%s\n", __func__); 272*85ae89f4SRuslan Bukin 273*85ae89f4SRuslan Bukin sc = ifp->if_softc; 274*85ae89f4SRuslan Bukin br = sc->br; 275*85ae89f4SRuslan Bukin 276*85ae89f4SRuslan Bukin enq = 0; 277*85ae89f4SRuslan Bukin 278*85ae89f4SRuslan Bukin while ((m = drbr_peek(ifp, br)) != NULL) { 279*85ae89f4SRuslan Bukin error = xdma_enqueue_mbuf(sc->xchan_tx, 280*85ae89f4SRuslan Bukin &m, 0, 4, 4, XDMA_MEM_TO_DEV); 281*85ae89f4SRuslan Bukin if (error != 0) { 282*85ae89f4SRuslan Bukin /* No space in request queue available yet. */ 283*85ae89f4SRuslan Bukin drbr_putback(ifp, br, m); 284*85ae89f4SRuslan Bukin break; 285*85ae89f4SRuslan Bukin } 286*85ae89f4SRuslan Bukin 287*85ae89f4SRuslan Bukin drbr_advance(ifp, br); 288*85ae89f4SRuslan Bukin 289*85ae89f4SRuslan Bukin enq++; 290*85ae89f4SRuslan Bukin 291*85ae89f4SRuslan Bukin /* If anyone is interested give them a copy. */ 292*85ae89f4SRuslan Bukin ETHER_BPF_MTAP(ifp, m); 293*85ae89f4SRuslan Bukin } 294*85ae89f4SRuslan Bukin 295*85ae89f4SRuslan Bukin if (enq > 0) 296*85ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_tx); 297*85ae89f4SRuslan Bukin 298*85ae89f4SRuslan Bukin return (0); 299*85ae89f4SRuslan Bukin } 300*85ae89f4SRuslan Bukin 301*85ae89f4SRuslan Bukin static int 302*85ae89f4SRuslan Bukin xae_transmit(struct ifnet *ifp, struct mbuf *m) 303*85ae89f4SRuslan Bukin { 304*85ae89f4SRuslan Bukin struct xae_softc *sc; 305*85ae89f4SRuslan Bukin int error; 306*85ae89f4SRuslan Bukin 307*85ae89f4SRuslan Bukin dprintf("%s\n", __func__); 308*85ae89f4SRuslan Bukin 309*85ae89f4SRuslan Bukin sc = ifp->if_softc; 310*85ae89f4SRuslan Bukin 311*85ae89f4SRuslan Bukin XAE_LOCK(sc); 312*85ae89f4SRuslan Bukin 313*85ae89f4SRuslan Bukin error = drbr_enqueue(ifp, sc->br, m); 314*85ae89f4SRuslan Bukin if (error) { 315*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 316*85ae89f4SRuslan Bukin return (error); 317*85ae89f4SRuslan Bukin } 318*85ae89f4SRuslan Bukin 319*85ae89f4SRuslan Bukin if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 320*85ae89f4SRuslan Bukin IFF_DRV_RUNNING) { 321*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 322*85ae89f4SRuslan Bukin return (0); 323*85ae89f4SRuslan Bukin } 324*85ae89f4SRuslan Bukin 325*85ae89f4SRuslan Bukin if (!sc->link_is_up) { 326*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 327*85ae89f4SRuslan Bukin return (0); 328*85ae89f4SRuslan Bukin } 329*85ae89f4SRuslan Bukin 330*85ae89f4SRuslan Bukin error = xae_transmit_locked(ifp); 331*85ae89f4SRuslan Bukin 332*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 333*85ae89f4SRuslan Bukin 334*85ae89f4SRuslan Bukin return (error); 335*85ae89f4SRuslan Bukin } 336*85ae89f4SRuslan Bukin 337*85ae89f4SRuslan Bukin static void 338*85ae89f4SRuslan Bukin xae_stop_locked(struct xae_softc *sc) 339*85ae89f4SRuslan Bukin { 340*85ae89f4SRuslan Bukin struct ifnet *ifp; 341*85ae89f4SRuslan Bukin uint32_t reg; 342*85ae89f4SRuslan Bukin 343*85ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 344*85ae89f4SRuslan Bukin 345*85ae89f4SRuslan Bukin ifp = sc->ifp; 346*85ae89f4SRuslan Bukin ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 347*85ae89f4SRuslan Bukin 348*85ae89f4SRuslan Bukin callout_stop(&sc->xae_callout); 349*85ae89f4SRuslan Bukin 350*85ae89f4SRuslan Bukin /* Stop the transmitter */ 351*85ae89f4SRuslan Bukin reg = READ4(sc, XAE_TC); 352*85ae89f4SRuslan Bukin reg &= ~TC_TX; 353*85ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, reg); 354*85ae89f4SRuslan Bukin 355*85ae89f4SRuslan Bukin /* Stop the receiver. */ 356*85ae89f4SRuslan Bukin reg = READ4(sc, XAE_RCW1); 357*85ae89f4SRuslan Bukin reg &= ~RCW1_RX; 358*85ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, reg); 359*85ae89f4SRuslan Bukin } 360*85ae89f4SRuslan Bukin 361*85ae89f4SRuslan Bukin static uint64_t 362*85ae89f4SRuslan Bukin xae_stat(struct xae_softc *sc, int counter_id) 363*85ae89f4SRuslan Bukin { 364*85ae89f4SRuslan Bukin uint64_t new, old; 365*85ae89f4SRuslan Bukin uint64_t delta; 366*85ae89f4SRuslan Bukin 367*85ae89f4SRuslan Bukin KASSERT(counter_id < XAE_MAX_COUNTERS, 368*85ae89f4SRuslan Bukin ("counter %d is out of range", counter_id)); 369*85ae89f4SRuslan Bukin 370*85ae89f4SRuslan Bukin new = READ8(sc, XAE_STATCNT(counter_id)); 371*85ae89f4SRuslan Bukin old = sc->counters[counter_id]; 372*85ae89f4SRuslan Bukin 373*85ae89f4SRuslan Bukin if (new >= old) 374*85ae89f4SRuslan Bukin delta = new - old; 375*85ae89f4SRuslan Bukin else 376*85ae89f4SRuslan Bukin delta = UINT64_MAX - old + new; 377*85ae89f4SRuslan Bukin sc->counters[counter_id] = new; 378*85ae89f4SRuslan Bukin 379*85ae89f4SRuslan Bukin return (delta); 380*85ae89f4SRuslan Bukin } 381*85ae89f4SRuslan Bukin 382*85ae89f4SRuslan Bukin static void 383*85ae89f4SRuslan Bukin xae_harvest_stats(struct xae_softc *sc) 384*85ae89f4SRuslan Bukin { 385*85ae89f4SRuslan Bukin struct ifnet *ifp; 386*85ae89f4SRuslan Bukin 387*85ae89f4SRuslan Bukin ifp = sc->ifp; 388*85ae89f4SRuslan Bukin 389*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IPACKETS, xae_stat(sc, RX_GOOD_FRAMES)); 390*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IMCASTS, xae_stat(sc, RX_GOOD_MCASTS)); 391*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 392*85ae89f4SRuslan Bukin xae_stat(sc, RX_FRAME_CHECK_SEQ_ERROR) + 393*85ae89f4SRuslan Bukin xae_stat(sc, RX_LEN_OUT_OF_RANGE) + 394*85ae89f4SRuslan Bukin xae_stat(sc, RX_ALIGNMENT_ERRORS)); 395*85ae89f4SRuslan Bukin 396*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OBYTES, xae_stat(sc, TX_BYTES)); 397*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OPACKETS, xae_stat(sc, TX_GOOD_FRAMES)); 398*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OMCASTS, xae_stat(sc, TX_GOOD_MCASTS)); 399*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 400*85ae89f4SRuslan Bukin xae_stat(sc, TX_GOOD_UNDERRUN_ERRORS)); 401*85ae89f4SRuslan Bukin 402*85ae89f4SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 403*85ae89f4SRuslan Bukin xae_stat(sc, TX_SINGLE_COLLISION_FRAMES) + 404*85ae89f4SRuslan Bukin xae_stat(sc, TX_MULTI_COLLISION_FRAMES) + 405*85ae89f4SRuslan Bukin xae_stat(sc, TX_LATE_COLLISIONS) + 406*85ae89f4SRuslan Bukin xae_stat(sc, TX_EXCESS_COLLISIONS)); 407*85ae89f4SRuslan Bukin } 408*85ae89f4SRuslan Bukin 409*85ae89f4SRuslan Bukin static void 410*85ae89f4SRuslan Bukin xae_tick(void *arg) 411*85ae89f4SRuslan Bukin { 412*85ae89f4SRuslan Bukin struct xae_softc *sc; 413*85ae89f4SRuslan Bukin struct ifnet *ifp; 414*85ae89f4SRuslan Bukin int link_was_up; 415*85ae89f4SRuslan Bukin 416*85ae89f4SRuslan Bukin sc = arg; 417*85ae89f4SRuslan Bukin 418*85ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 419*85ae89f4SRuslan Bukin 420*85ae89f4SRuslan Bukin ifp = sc->ifp; 421*85ae89f4SRuslan Bukin 422*85ae89f4SRuslan Bukin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 423*85ae89f4SRuslan Bukin return; 424*85ae89f4SRuslan Bukin 425*85ae89f4SRuslan Bukin /* Gather stats from hardware counters. */ 426*85ae89f4SRuslan Bukin xae_harvest_stats(sc); 427*85ae89f4SRuslan Bukin 428*85ae89f4SRuslan Bukin /* Check the media status. */ 429*85ae89f4SRuslan Bukin link_was_up = sc->link_is_up; 430*85ae89f4SRuslan Bukin mii_tick(sc->mii_softc); 431*85ae89f4SRuslan Bukin if (sc->link_is_up && !link_was_up) 432*85ae89f4SRuslan Bukin xae_transmit_locked(sc->ifp); 433*85ae89f4SRuslan Bukin 434*85ae89f4SRuslan Bukin /* Schedule another check one second from now. */ 435*85ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 436*85ae89f4SRuslan Bukin } 437*85ae89f4SRuslan Bukin 438*85ae89f4SRuslan Bukin static void 439*85ae89f4SRuslan Bukin xae_init_locked(struct xae_softc *sc) 440*85ae89f4SRuslan Bukin { 441*85ae89f4SRuslan Bukin struct ifnet *ifp; 442*85ae89f4SRuslan Bukin 443*85ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 444*85ae89f4SRuslan Bukin 445*85ae89f4SRuslan Bukin ifp = sc->ifp; 446*85ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 447*85ae89f4SRuslan Bukin return; 448*85ae89f4SRuslan Bukin 449*85ae89f4SRuslan Bukin ifp->if_drv_flags |= IFF_DRV_RUNNING; 450*85ae89f4SRuslan Bukin 451*85ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 452*85ae89f4SRuslan Bukin 453*85ae89f4SRuslan Bukin /* Enable the transmitter */ 454*85ae89f4SRuslan Bukin WRITE4(sc, XAE_TC, TC_TX); 455*85ae89f4SRuslan Bukin 456*85ae89f4SRuslan Bukin /* Enable the receiver. */ 457*85ae89f4SRuslan Bukin WRITE4(sc, XAE_RCW1, RCW1_RX); 458*85ae89f4SRuslan Bukin 459*85ae89f4SRuslan Bukin /* 460*85ae89f4SRuslan Bukin * Call mii_mediachg() which will call back into xae_miibus_statchg() 461*85ae89f4SRuslan Bukin * to set up the remaining config registers based on current media. 462*85ae89f4SRuslan Bukin */ 463*85ae89f4SRuslan Bukin mii_mediachg(sc->mii_softc); 464*85ae89f4SRuslan Bukin callout_reset(&sc->xae_callout, hz, xae_tick, sc); 465*85ae89f4SRuslan Bukin } 466*85ae89f4SRuslan Bukin 467*85ae89f4SRuslan Bukin static void 468*85ae89f4SRuslan Bukin xae_init(void *arg) 469*85ae89f4SRuslan Bukin { 470*85ae89f4SRuslan Bukin struct xae_softc *sc; 471*85ae89f4SRuslan Bukin 472*85ae89f4SRuslan Bukin sc = arg; 473*85ae89f4SRuslan Bukin 474*85ae89f4SRuslan Bukin XAE_LOCK(sc); 475*85ae89f4SRuslan Bukin xae_init_locked(sc); 476*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 477*85ae89f4SRuslan Bukin } 478*85ae89f4SRuslan Bukin 479*85ae89f4SRuslan Bukin static void 480*85ae89f4SRuslan Bukin xae_media_status(struct ifnet * ifp, struct ifmediareq *ifmr) 481*85ae89f4SRuslan Bukin { 482*85ae89f4SRuslan Bukin struct xae_softc *sc; 483*85ae89f4SRuslan Bukin struct mii_data *mii; 484*85ae89f4SRuslan Bukin 485*85ae89f4SRuslan Bukin sc = ifp->if_softc; 486*85ae89f4SRuslan Bukin mii = sc->mii_softc; 487*85ae89f4SRuslan Bukin 488*85ae89f4SRuslan Bukin XAE_LOCK(sc); 489*85ae89f4SRuslan Bukin mii_pollstat(mii); 490*85ae89f4SRuslan Bukin ifmr->ifm_active = mii->mii_media_active; 491*85ae89f4SRuslan Bukin ifmr->ifm_status = mii->mii_media_status; 492*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 493*85ae89f4SRuslan Bukin } 494*85ae89f4SRuslan Bukin 495*85ae89f4SRuslan Bukin static int 496*85ae89f4SRuslan Bukin xae_media_change_locked(struct xae_softc *sc) 497*85ae89f4SRuslan Bukin { 498*85ae89f4SRuslan Bukin 499*85ae89f4SRuslan Bukin return (mii_mediachg(sc->mii_softc)); 500*85ae89f4SRuslan Bukin } 501*85ae89f4SRuslan Bukin 502*85ae89f4SRuslan Bukin static int 503*85ae89f4SRuslan Bukin xae_media_change(struct ifnet * ifp) 504*85ae89f4SRuslan Bukin { 505*85ae89f4SRuslan Bukin struct xae_softc *sc; 506*85ae89f4SRuslan Bukin int error; 507*85ae89f4SRuslan Bukin 508*85ae89f4SRuslan Bukin sc = ifp->if_softc; 509*85ae89f4SRuslan Bukin 510*85ae89f4SRuslan Bukin XAE_LOCK(sc); 511*85ae89f4SRuslan Bukin error = xae_media_change_locked(sc); 512*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 513*85ae89f4SRuslan Bukin 514*85ae89f4SRuslan Bukin return (error); 515*85ae89f4SRuslan Bukin } 516*85ae89f4SRuslan Bukin 517*85ae89f4SRuslan Bukin static void 518*85ae89f4SRuslan Bukin xae_setup_rxfilter(struct xae_softc *sc) 519*85ae89f4SRuslan Bukin { 520*85ae89f4SRuslan Bukin struct ifmultiaddr *ifma; 521*85ae89f4SRuslan Bukin struct ifnet *ifp; 522*85ae89f4SRuslan Bukin uint32_t reg; 523*85ae89f4SRuslan Bukin uint8_t *ma; 524*85ae89f4SRuslan Bukin int i; 525*85ae89f4SRuslan Bukin 526*85ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 527*85ae89f4SRuslan Bukin 528*85ae89f4SRuslan Bukin ifp = sc->ifp; 529*85ae89f4SRuslan Bukin 530*85ae89f4SRuslan Bukin /* 531*85ae89f4SRuslan Bukin * Set the multicast (group) filter hash. 532*85ae89f4SRuslan Bukin */ 533*85ae89f4SRuslan Bukin if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { 534*85ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 535*85ae89f4SRuslan Bukin reg |= FFC_PM; 536*85ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 537*85ae89f4SRuslan Bukin } else { 538*85ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC); 539*85ae89f4SRuslan Bukin reg &= ~FFC_PM; 540*85ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 541*85ae89f4SRuslan Bukin 542*85ae89f4SRuslan Bukin if_maddr_rlock(ifp); 543*85ae89f4SRuslan Bukin 544*85ae89f4SRuslan Bukin i = 0; 545*85ae89f4SRuslan Bukin CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { 546*85ae89f4SRuslan Bukin if (ifma->ifma_addr->sa_family != AF_LINK) 547*85ae89f4SRuslan Bukin continue; 548*85ae89f4SRuslan Bukin 549*85ae89f4SRuslan Bukin if (i >= XAE_MULTICAST_TABLE_SIZE) 550*85ae89f4SRuslan Bukin break; 551*85ae89f4SRuslan Bukin 552*85ae89f4SRuslan Bukin ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 553*85ae89f4SRuslan Bukin 554*85ae89f4SRuslan Bukin reg = READ4(sc, XAE_FFC) & 0xffffff00; 555*85ae89f4SRuslan Bukin reg |= i++; 556*85ae89f4SRuslan Bukin WRITE4(sc, XAE_FFC, reg); 557*85ae89f4SRuslan Bukin 558*85ae89f4SRuslan Bukin reg = (ma[0]); 559*85ae89f4SRuslan Bukin reg |= (ma[1] << 8); 560*85ae89f4SRuslan Bukin reg |= (ma[2] << 16); 561*85ae89f4SRuslan Bukin reg |= (ma[3] << 24); 562*85ae89f4SRuslan Bukin WRITE4(sc, XAE_FFV(0), reg); 563*85ae89f4SRuslan Bukin 564*85ae89f4SRuslan Bukin reg = ma[4]; 565*85ae89f4SRuslan Bukin reg |= ma[5] << 8; 566*85ae89f4SRuslan Bukin WRITE4(sc, XAE_FFV(1), reg); 567*85ae89f4SRuslan Bukin } 568*85ae89f4SRuslan Bukin if_maddr_runlock(ifp); 569*85ae89f4SRuslan Bukin } 570*85ae89f4SRuslan Bukin 571*85ae89f4SRuslan Bukin /* 572*85ae89f4SRuslan Bukin * Set the primary address. 573*85ae89f4SRuslan Bukin */ 574*85ae89f4SRuslan Bukin reg = sc->macaddr[0]; 575*85ae89f4SRuslan Bukin reg |= (sc->macaddr[1] << 8); 576*85ae89f4SRuslan Bukin reg |= (sc->macaddr[2] << 16); 577*85ae89f4SRuslan Bukin reg |= (sc->macaddr[3] << 24); 578*85ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW0, reg); 579*85ae89f4SRuslan Bukin 580*85ae89f4SRuslan Bukin reg = sc->macaddr[4]; 581*85ae89f4SRuslan Bukin reg |= (sc->macaddr[5] << 8); 582*85ae89f4SRuslan Bukin WRITE4(sc, XAE_UAW1, reg); 583*85ae89f4SRuslan Bukin } 584*85ae89f4SRuslan Bukin 585*85ae89f4SRuslan Bukin static int 586*85ae89f4SRuslan Bukin xae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 587*85ae89f4SRuslan Bukin { 588*85ae89f4SRuslan Bukin struct xae_softc *sc; 589*85ae89f4SRuslan Bukin struct mii_data *mii; 590*85ae89f4SRuslan Bukin struct ifreq *ifr; 591*85ae89f4SRuslan Bukin int mask, error; 592*85ae89f4SRuslan Bukin 593*85ae89f4SRuslan Bukin sc = ifp->if_softc; 594*85ae89f4SRuslan Bukin ifr = (struct ifreq *)data; 595*85ae89f4SRuslan Bukin 596*85ae89f4SRuslan Bukin error = 0; 597*85ae89f4SRuslan Bukin switch (cmd) { 598*85ae89f4SRuslan Bukin case SIOCSIFFLAGS: 599*85ae89f4SRuslan Bukin XAE_LOCK(sc); 600*85ae89f4SRuslan Bukin if (ifp->if_flags & IFF_UP) { 601*85ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 602*85ae89f4SRuslan Bukin if ((ifp->if_flags ^ sc->if_flags) & 603*85ae89f4SRuslan Bukin (IFF_PROMISC | IFF_ALLMULTI)) 604*85ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 605*85ae89f4SRuslan Bukin } else { 606*85ae89f4SRuslan Bukin if (!sc->is_detaching) 607*85ae89f4SRuslan Bukin xae_init_locked(sc); 608*85ae89f4SRuslan Bukin } 609*85ae89f4SRuslan Bukin } else { 610*85ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 611*85ae89f4SRuslan Bukin xae_stop_locked(sc); 612*85ae89f4SRuslan Bukin } 613*85ae89f4SRuslan Bukin sc->if_flags = ifp->if_flags; 614*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 615*85ae89f4SRuslan Bukin break; 616*85ae89f4SRuslan Bukin case SIOCADDMULTI: 617*85ae89f4SRuslan Bukin case SIOCDELMULTI: 618*85ae89f4SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 619*85ae89f4SRuslan Bukin XAE_LOCK(sc); 620*85ae89f4SRuslan Bukin xae_setup_rxfilter(sc); 621*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 622*85ae89f4SRuslan Bukin } 623*85ae89f4SRuslan Bukin break; 624*85ae89f4SRuslan Bukin case SIOCSIFMEDIA: 625*85ae89f4SRuslan Bukin case SIOCGIFMEDIA: 626*85ae89f4SRuslan Bukin mii = sc->mii_softc; 627*85ae89f4SRuslan Bukin error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 628*85ae89f4SRuslan Bukin break; 629*85ae89f4SRuslan Bukin case SIOCSIFCAP: 630*85ae89f4SRuslan Bukin mask = ifp->if_capenable ^ ifr->ifr_reqcap; 631*85ae89f4SRuslan Bukin if (mask & IFCAP_VLAN_MTU) { 632*85ae89f4SRuslan Bukin /* No work to do except acknowledge the change took */ 633*85ae89f4SRuslan Bukin ifp->if_capenable ^= IFCAP_VLAN_MTU; 634*85ae89f4SRuslan Bukin } 635*85ae89f4SRuslan Bukin break; 636*85ae89f4SRuslan Bukin 637*85ae89f4SRuslan Bukin default: 638*85ae89f4SRuslan Bukin error = ether_ioctl(ifp, cmd, data); 639*85ae89f4SRuslan Bukin break; 640*85ae89f4SRuslan Bukin } 641*85ae89f4SRuslan Bukin 642*85ae89f4SRuslan Bukin return (error); 643*85ae89f4SRuslan Bukin } 644*85ae89f4SRuslan Bukin 645*85ae89f4SRuslan Bukin static void 646*85ae89f4SRuslan Bukin xae_intr(void *arg) 647*85ae89f4SRuslan Bukin { 648*85ae89f4SRuslan Bukin 649*85ae89f4SRuslan Bukin } 650*85ae89f4SRuslan Bukin 651*85ae89f4SRuslan Bukin static int 652*85ae89f4SRuslan Bukin xae_get_hwaddr(struct xae_softc *sc, uint8_t *hwaddr) 653*85ae89f4SRuslan Bukin { 654*85ae89f4SRuslan Bukin phandle_t node; 655*85ae89f4SRuslan Bukin int len; 656*85ae89f4SRuslan Bukin 657*85ae89f4SRuslan Bukin node = ofw_bus_get_node(sc->dev); 658*85ae89f4SRuslan Bukin 659*85ae89f4SRuslan Bukin /* Check if there is property */ 660*85ae89f4SRuslan Bukin if ((len = OF_getproplen(node, "local-mac-address")) <= 0) 661*85ae89f4SRuslan Bukin return (EINVAL); 662*85ae89f4SRuslan Bukin 663*85ae89f4SRuslan Bukin if (len != ETHER_ADDR_LEN) 664*85ae89f4SRuslan Bukin return (EINVAL); 665*85ae89f4SRuslan Bukin 666*85ae89f4SRuslan Bukin OF_getprop(node, "local-mac-address", hwaddr, 667*85ae89f4SRuslan Bukin ETHER_ADDR_LEN); 668*85ae89f4SRuslan Bukin 669*85ae89f4SRuslan Bukin return (0); 670*85ae89f4SRuslan Bukin } 671*85ae89f4SRuslan Bukin 672*85ae89f4SRuslan Bukin static int 673*85ae89f4SRuslan Bukin mdio_wait(struct xae_softc *sc) 674*85ae89f4SRuslan Bukin { 675*85ae89f4SRuslan Bukin uint32_t reg; 676*85ae89f4SRuslan Bukin int timeout; 677*85ae89f4SRuslan Bukin 678*85ae89f4SRuslan Bukin timeout = 200; 679*85ae89f4SRuslan Bukin 680*85ae89f4SRuslan Bukin do { 681*85ae89f4SRuslan Bukin reg = READ4(sc, XAE_MDIO_CTRL); 682*85ae89f4SRuslan Bukin if (reg & MDIO_CTRL_READY) 683*85ae89f4SRuslan Bukin break; 684*85ae89f4SRuslan Bukin DELAY(1); 685*85ae89f4SRuslan Bukin } while (timeout--); 686*85ae89f4SRuslan Bukin 687*85ae89f4SRuslan Bukin if (timeout <= 0) { 688*85ae89f4SRuslan Bukin printf("Failed to get MDIO ready\n"); 689*85ae89f4SRuslan Bukin return (1); 690*85ae89f4SRuslan Bukin } 691*85ae89f4SRuslan Bukin 692*85ae89f4SRuslan Bukin return (0); 693*85ae89f4SRuslan Bukin } 694*85ae89f4SRuslan Bukin 695*85ae89f4SRuslan Bukin static int 696*85ae89f4SRuslan Bukin xae_miibus_read_reg(device_t dev, int phy, int reg) 697*85ae89f4SRuslan Bukin { 698*85ae89f4SRuslan Bukin struct xae_softc *sc; 699*85ae89f4SRuslan Bukin uint32_t mii; 700*85ae89f4SRuslan Bukin int rv; 701*85ae89f4SRuslan Bukin 702*85ae89f4SRuslan Bukin sc = device_get_softc(dev); 703*85ae89f4SRuslan Bukin 704*85ae89f4SRuslan Bukin if (mdio_wait(sc)) 705*85ae89f4SRuslan Bukin return (0); 706*85ae89f4SRuslan Bukin 707*85ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_READ | MDIO_CTRL_INITIATE; 708*85ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 709*85ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 710*85ae89f4SRuslan Bukin 711*85ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 712*85ae89f4SRuslan Bukin 713*85ae89f4SRuslan Bukin if (mdio_wait(sc)) 714*85ae89f4SRuslan Bukin return (0); 715*85ae89f4SRuslan Bukin 716*85ae89f4SRuslan Bukin rv = READ4(sc, XAE_MDIO_READ); 717*85ae89f4SRuslan Bukin 718*85ae89f4SRuslan Bukin return (rv); 719*85ae89f4SRuslan Bukin } 720*85ae89f4SRuslan Bukin 721*85ae89f4SRuslan Bukin static int 722*85ae89f4SRuslan Bukin xae_miibus_write_reg(device_t dev, int phy, int reg, int val) 723*85ae89f4SRuslan Bukin { 724*85ae89f4SRuslan Bukin struct xae_softc *sc; 725*85ae89f4SRuslan Bukin uint32_t mii; 726*85ae89f4SRuslan Bukin 727*85ae89f4SRuslan Bukin sc = device_get_softc(dev); 728*85ae89f4SRuslan Bukin 729*85ae89f4SRuslan Bukin if (mdio_wait(sc)) 730*85ae89f4SRuslan Bukin return (1); 731*85ae89f4SRuslan Bukin 732*85ae89f4SRuslan Bukin mii = MDIO_CTRL_TX_OP_WRITE | MDIO_CTRL_INITIATE; 733*85ae89f4SRuslan Bukin mii |= (reg << MDIO_TX_REGAD_S); 734*85ae89f4SRuslan Bukin mii |= (phy << MDIO_TX_PHYAD_S); 735*85ae89f4SRuslan Bukin 736*85ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_WRITE, val); 737*85ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_CTRL, mii); 738*85ae89f4SRuslan Bukin 739*85ae89f4SRuslan Bukin if (mdio_wait(sc)) 740*85ae89f4SRuslan Bukin return (1); 741*85ae89f4SRuslan Bukin 742*85ae89f4SRuslan Bukin return (0); 743*85ae89f4SRuslan Bukin } 744*85ae89f4SRuslan Bukin 745*85ae89f4SRuslan Bukin static void 746*85ae89f4SRuslan Bukin xae_phy_fixup(struct xae_softc *sc) 747*85ae89f4SRuslan Bukin { 748*85ae89f4SRuslan Bukin uint32_t reg; 749*85ae89f4SRuslan Bukin device_t dev; 750*85ae89f4SRuslan Bukin 751*85ae89f4SRuslan Bukin dev = sc->dev; 752*85ae89f4SRuslan Bukin 753*85ae89f4SRuslan Bukin do { 754*85ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_SGMIICTL1, SGMIICTL1_SGMII_6W); 755*85ae89f4SRuslan Bukin PHY_WR(sc, DP83867_PHYCR, PHYCR_SGMII_EN); 756*85ae89f4SRuslan Bukin 757*85ae89f4SRuslan Bukin reg = PHY_RD(sc, DP83867_CFG2); 758*85ae89f4SRuslan Bukin reg &= ~CFG2_SPEED_OPT_ATTEMPT_CNT_M; 759*85ae89f4SRuslan Bukin reg |= (CFG2_SPEED_OPT_ATTEMPT_CNT_4); 760*85ae89f4SRuslan Bukin reg |= CFG2_INTERRUPT_POLARITY; 761*85ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_ENHANCED_EN; 762*85ae89f4SRuslan Bukin reg |= CFG2_SPEED_OPT_10M_EN; 763*85ae89f4SRuslan Bukin PHY_WR(sc, DP83867_CFG2, reg); 764*85ae89f4SRuslan Bukin 765*85ae89f4SRuslan Bukin WRITE_TI_EREG(sc, DP83867_CFG4, CFG4_SGMII_TMR); 766*85ae89f4SRuslan Bukin PHY_WR(sc, MII_BMCR, 767*85ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_RESET); 768*85ae89f4SRuslan Bukin } while (PHY1_RD(sc, MII_BMCR) == 0x0ffff); 769*85ae89f4SRuslan Bukin 770*85ae89f4SRuslan Bukin do { 771*85ae89f4SRuslan Bukin PHY1_WR(sc, MII_BMCR, 772*85ae89f4SRuslan Bukin BMCR_AUTOEN | BMCR_FDX | BMCR_SPEED1 | BMCR_STARTNEG); 773*85ae89f4SRuslan Bukin DELAY(40000); 774*85ae89f4SRuslan Bukin } while ((PHY1_RD(sc, MII_BMSR) & BMSR_ACOMP) == 0); 775*85ae89f4SRuslan Bukin } 776*85ae89f4SRuslan Bukin 777*85ae89f4SRuslan Bukin static int 778*85ae89f4SRuslan Bukin setup_xdma(struct xae_softc *sc) 779*85ae89f4SRuslan Bukin { 780*85ae89f4SRuslan Bukin device_t dev; 781*85ae89f4SRuslan Bukin vmem_t *vmem; 782*85ae89f4SRuslan Bukin int error; 783*85ae89f4SRuslan Bukin 784*85ae89f4SRuslan Bukin dev = sc->dev; 785*85ae89f4SRuslan Bukin 786*85ae89f4SRuslan Bukin /* Get xDMA controller */ 787*85ae89f4SRuslan Bukin sc->xdma_tx = xdma_ofw_get(sc->dev, "tx"); 788*85ae89f4SRuslan Bukin if (sc->xdma_tx == NULL) { 789*85ae89f4SRuslan Bukin device_printf(dev, "Could not find DMA controller.\n"); 790*85ae89f4SRuslan Bukin return (ENXIO); 791*85ae89f4SRuslan Bukin } 792*85ae89f4SRuslan Bukin 793*85ae89f4SRuslan Bukin sc->xdma_rx = xdma_ofw_get(sc->dev, "rx"); 794*85ae89f4SRuslan Bukin if (sc->xdma_rx == NULL) { 795*85ae89f4SRuslan Bukin device_printf(dev, "Could not find DMA controller.\n"); 796*85ae89f4SRuslan Bukin return (ENXIO); 797*85ae89f4SRuslan Bukin } 798*85ae89f4SRuslan Bukin 799*85ae89f4SRuslan Bukin /* Alloc xDMA TX virtual channel. */ 800*85ae89f4SRuslan Bukin sc->xchan_tx = xdma_channel_alloc(sc->xdma_tx, 0); 801*85ae89f4SRuslan Bukin if (sc->xchan_tx == NULL) { 802*85ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA TX channel.\n"); 803*85ae89f4SRuslan Bukin return (ENXIO); 804*85ae89f4SRuslan Bukin } 805*85ae89f4SRuslan Bukin 806*85ae89f4SRuslan Bukin /* Setup interrupt handler. */ 807*85ae89f4SRuslan Bukin error = xdma_setup_intr(sc->xchan_tx, 808*85ae89f4SRuslan Bukin xae_xdma_tx_intr, sc, &sc->ih_tx); 809*85ae89f4SRuslan Bukin if (error) { 810*85ae89f4SRuslan Bukin device_printf(sc->dev, 811*85ae89f4SRuslan Bukin "Can't setup xDMA TX interrupt handler.\n"); 812*85ae89f4SRuslan Bukin return (ENXIO); 813*85ae89f4SRuslan Bukin } 814*85ae89f4SRuslan Bukin 815*85ae89f4SRuslan Bukin /* Alloc xDMA RX virtual channel. */ 816*85ae89f4SRuslan Bukin sc->xchan_rx = xdma_channel_alloc(sc->xdma_rx, 0); 817*85ae89f4SRuslan Bukin if (sc->xchan_rx == NULL) { 818*85ae89f4SRuslan Bukin device_printf(dev, "Can't alloc virtual DMA RX channel.\n"); 819*85ae89f4SRuslan Bukin return (ENXIO); 820*85ae89f4SRuslan Bukin } 821*85ae89f4SRuslan Bukin 822*85ae89f4SRuslan Bukin /* Setup interrupt handler. */ 823*85ae89f4SRuslan Bukin error = xdma_setup_intr(sc->xchan_rx, 824*85ae89f4SRuslan Bukin xae_xdma_rx_intr, sc, &sc->ih_rx); 825*85ae89f4SRuslan Bukin if (error) { 826*85ae89f4SRuslan Bukin device_printf(sc->dev, 827*85ae89f4SRuslan Bukin "Can't setup xDMA RX interrupt handler.\n"); 828*85ae89f4SRuslan Bukin return (ENXIO); 829*85ae89f4SRuslan Bukin } 830*85ae89f4SRuslan Bukin 831*85ae89f4SRuslan Bukin /* Setup bounce buffer */ 832*85ae89f4SRuslan Bukin vmem = xdma_get_memory(dev); 833*85ae89f4SRuslan Bukin if (vmem) { 834*85ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_tx, vmem); 835*85ae89f4SRuslan Bukin xchan_set_memory(sc->xchan_rx, vmem); 836*85ae89f4SRuslan Bukin } 837*85ae89f4SRuslan Bukin 838*85ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_tx, 839*85ae89f4SRuslan Bukin TX_QUEUE_SIZE, /* xchan requests queue size */ 840*85ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 841*85ae89f4SRuslan Bukin 8, /* maxnsegs */ 842*85ae89f4SRuslan Bukin 16, /* alignment */ 843*85ae89f4SRuslan Bukin 0, /* boundary */ 844*85ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 845*85ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 846*85ae89f4SRuslan Bukin 847*85ae89f4SRuslan Bukin xdma_prep_sg(sc->xchan_rx, 848*85ae89f4SRuslan Bukin RX_QUEUE_SIZE, /* xchan requests queue size */ 849*85ae89f4SRuslan Bukin MCLBYTES, /* maxsegsize */ 850*85ae89f4SRuslan Bukin 1, /* maxnsegs */ 851*85ae89f4SRuslan Bukin 16, /* alignment */ 852*85ae89f4SRuslan Bukin 0, /* boundary */ 853*85ae89f4SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, 854*85ae89f4SRuslan Bukin BUS_SPACE_MAXADDR); 855*85ae89f4SRuslan Bukin 856*85ae89f4SRuslan Bukin return (0); 857*85ae89f4SRuslan Bukin } 858*85ae89f4SRuslan Bukin 859*85ae89f4SRuslan Bukin static int 860*85ae89f4SRuslan Bukin xae_probe(device_t dev) 861*85ae89f4SRuslan Bukin { 862*85ae89f4SRuslan Bukin 863*85ae89f4SRuslan Bukin if (!ofw_bus_status_okay(dev)) 864*85ae89f4SRuslan Bukin return (ENXIO); 865*85ae89f4SRuslan Bukin 866*85ae89f4SRuslan Bukin if (!ofw_bus_is_compatible(dev, "xlnx,axi-ethernet-1.00.a")) 867*85ae89f4SRuslan Bukin return (ENXIO); 868*85ae89f4SRuslan Bukin 869*85ae89f4SRuslan Bukin device_set_desc(dev, "Xilinx AXI Ethernet"); 870*85ae89f4SRuslan Bukin 871*85ae89f4SRuslan Bukin return (BUS_PROBE_DEFAULT); 872*85ae89f4SRuslan Bukin } 873*85ae89f4SRuslan Bukin 874*85ae89f4SRuslan Bukin static int 875*85ae89f4SRuslan Bukin xae_attach(device_t dev) 876*85ae89f4SRuslan Bukin { 877*85ae89f4SRuslan Bukin struct xae_softc *sc; 878*85ae89f4SRuslan Bukin struct ifnet *ifp; 879*85ae89f4SRuslan Bukin phandle_t node; 880*85ae89f4SRuslan Bukin uint32_t reg; 881*85ae89f4SRuslan Bukin int error; 882*85ae89f4SRuslan Bukin 883*85ae89f4SRuslan Bukin sc = device_get_softc(dev); 884*85ae89f4SRuslan Bukin sc->dev = dev; 885*85ae89f4SRuslan Bukin node = ofw_bus_get_node(dev); 886*85ae89f4SRuslan Bukin 887*85ae89f4SRuslan Bukin if (setup_xdma(sc) != 0) { 888*85ae89f4SRuslan Bukin device_printf(dev, "Could not setup xDMA.\n"); 889*85ae89f4SRuslan Bukin return (ENXIO); 890*85ae89f4SRuslan Bukin } 891*85ae89f4SRuslan Bukin 892*85ae89f4SRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 893*85ae89f4SRuslan Bukin MTX_NETWORK_LOCK, MTX_DEF); 894*85ae89f4SRuslan Bukin 895*85ae89f4SRuslan Bukin sc->br = buf_ring_alloc(BUFRING_SIZE, M_DEVBUF, 896*85ae89f4SRuslan Bukin M_NOWAIT, &sc->mtx); 897*85ae89f4SRuslan Bukin if (sc->br == NULL) 898*85ae89f4SRuslan Bukin return (ENOMEM); 899*85ae89f4SRuslan Bukin 900*85ae89f4SRuslan Bukin if (bus_alloc_resources(dev, xae_spec, sc->res)) { 901*85ae89f4SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 902*85ae89f4SRuslan Bukin return (ENXIO); 903*85ae89f4SRuslan Bukin } 904*85ae89f4SRuslan Bukin 905*85ae89f4SRuslan Bukin /* Memory interface */ 906*85ae89f4SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 907*85ae89f4SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 908*85ae89f4SRuslan Bukin 909*85ae89f4SRuslan Bukin device_printf(sc->dev, "Identification: %x\n", 910*85ae89f4SRuslan Bukin READ4(sc, XAE_IDENT)); 911*85ae89f4SRuslan Bukin 912*85ae89f4SRuslan Bukin /* Get MAC addr */ 913*85ae89f4SRuslan Bukin if (xae_get_hwaddr(sc, sc->macaddr)) { 914*85ae89f4SRuslan Bukin device_printf(sc->dev, "can't get mac\n"); 915*85ae89f4SRuslan Bukin return (ENXIO); 916*85ae89f4SRuslan Bukin } 917*85ae89f4SRuslan Bukin 918*85ae89f4SRuslan Bukin /* Enable MII clock */ 919*85ae89f4SRuslan Bukin reg = (MDIO_CLK_DIV_DEFAULT << MDIO_SETUP_CLK_DIV_S); 920*85ae89f4SRuslan Bukin reg |= MDIO_SETUP_ENABLE; 921*85ae89f4SRuslan Bukin WRITE4(sc, XAE_MDIO_SETUP, reg); 922*85ae89f4SRuslan Bukin if (mdio_wait(sc)) 923*85ae89f4SRuslan Bukin return (ENXIO); 924*85ae89f4SRuslan Bukin 925*85ae89f4SRuslan Bukin callout_init_mtx(&sc->xae_callout, &sc->mtx, 0); 926*85ae89f4SRuslan Bukin 927*85ae89f4SRuslan Bukin /* Setup interrupt handler. */ 928*85ae89f4SRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 929*85ae89f4SRuslan Bukin NULL, xae_intr, sc, &sc->intr_cookie); 930*85ae89f4SRuslan Bukin if (error != 0) { 931*85ae89f4SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 932*85ae89f4SRuslan Bukin return (ENXIO); 933*85ae89f4SRuslan Bukin } 934*85ae89f4SRuslan Bukin 935*85ae89f4SRuslan Bukin /* Set up the ethernet interface. */ 936*85ae89f4SRuslan Bukin sc->ifp = ifp = if_alloc(IFT_ETHER); 937*85ae89f4SRuslan Bukin if (ifp == NULL) { 938*85ae89f4SRuslan Bukin device_printf(dev, "could not allocate ifp.\n"); 939*85ae89f4SRuslan Bukin return (ENXIO); 940*85ae89f4SRuslan Bukin } 941*85ae89f4SRuslan Bukin 942*85ae89f4SRuslan Bukin ifp->if_softc = sc; 943*85ae89f4SRuslan Bukin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 944*85ae89f4SRuslan Bukin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 945*85ae89f4SRuslan Bukin ifp->if_capabilities = IFCAP_VLAN_MTU; 946*85ae89f4SRuslan Bukin ifp->if_capenable = ifp->if_capabilities; 947*85ae89f4SRuslan Bukin ifp->if_transmit = xae_transmit; 948*85ae89f4SRuslan Bukin ifp->if_qflush = xae_qflush; 949*85ae89f4SRuslan Bukin ifp->if_ioctl = xae_ioctl; 950*85ae89f4SRuslan Bukin ifp->if_init = xae_init; 951*85ae89f4SRuslan Bukin IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1); 952*85ae89f4SRuslan Bukin ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1; 953*85ae89f4SRuslan Bukin IFQ_SET_READY(&ifp->if_snd); 954*85ae89f4SRuslan Bukin 955*85ae89f4SRuslan Bukin if (xae_get_phyaddr(node, &sc->phy_addr) != 0) 956*85ae89f4SRuslan Bukin return (ENXIO); 957*85ae89f4SRuslan Bukin 958*85ae89f4SRuslan Bukin /* Attach the mii driver. */ 959*85ae89f4SRuslan Bukin error = mii_attach(dev, &sc->miibus, ifp, xae_media_change, 960*85ae89f4SRuslan Bukin xae_media_status, BMSR_DEFCAPMASK, sc->phy_addr, 961*85ae89f4SRuslan Bukin MII_OFFSET_ANY, 0); 962*85ae89f4SRuslan Bukin 963*85ae89f4SRuslan Bukin if (error != 0) { 964*85ae89f4SRuslan Bukin device_printf(dev, "PHY attach failed\n"); 965*85ae89f4SRuslan Bukin return (ENXIO); 966*85ae89f4SRuslan Bukin } 967*85ae89f4SRuslan Bukin sc->mii_softc = device_get_softc(sc->miibus); 968*85ae89f4SRuslan Bukin 969*85ae89f4SRuslan Bukin /* Apply vcu118 workaround. */ 970*85ae89f4SRuslan Bukin if (OF_getproplen(node, "xlnx,vcu118") >= 0) 971*85ae89f4SRuslan Bukin xae_phy_fixup(sc); 972*85ae89f4SRuslan Bukin 973*85ae89f4SRuslan Bukin /* All ready to run, attach the ethernet interface. */ 974*85ae89f4SRuslan Bukin ether_ifattach(ifp, sc->macaddr); 975*85ae89f4SRuslan Bukin sc->is_attached = true; 976*85ae89f4SRuslan Bukin 977*85ae89f4SRuslan Bukin xae_rx_enqueue(sc, NUM_RX_MBUF); 978*85ae89f4SRuslan Bukin xdma_queue_submit(sc->xchan_rx); 979*85ae89f4SRuslan Bukin 980*85ae89f4SRuslan Bukin return (0); 981*85ae89f4SRuslan Bukin } 982*85ae89f4SRuslan Bukin 983*85ae89f4SRuslan Bukin static int 984*85ae89f4SRuslan Bukin xae_detach(device_t dev) 985*85ae89f4SRuslan Bukin { 986*85ae89f4SRuslan Bukin struct xae_softc *sc; 987*85ae89f4SRuslan Bukin struct ifnet *ifp; 988*85ae89f4SRuslan Bukin 989*85ae89f4SRuslan Bukin sc = device_get_softc(dev); 990*85ae89f4SRuslan Bukin 991*85ae89f4SRuslan Bukin KASSERT(mtx_initialized(&sc->mtx), ("%s: mutex not initialized", 992*85ae89f4SRuslan Bukin device_get_nameunit(dev))); 993*85ae89f4SRuslan Bukin 994*85ae89f4SRuslan Bukin ifp = sc->ifp; 995*85ae89f4SRuslan Bukin 996*85ae89f4SRuslan Bukin /* Only cleanup if attach succeeded. */ 997*85ae89f4SRuslan Bukin if (device_is_attached(dev)) { 998*85ae89f4SRuslan Bukin XAE_LOCK(sc); 999*85ae89f4SRuslan Bukin xae_stop_locked(sc); 1000*85ae89f4SRuslan Bukin XAE_UNLOCK(sc); 1001*85ae89f4SRuslan Bukin callout_drain(&sc->xae_callout); 1002*85ae89f4SRuslan Bukin ether_ifdetach(ifp); 1003*85ae89f4SRuslan Bukin } 1004*85ae89f4SRuslan Bukin 1005*85ae89f4SRuslan Bukin if (sc->miibus != NULL) 1006*85ae89f4SRuslan Bukin device_delete_child(dev, sc->miibus); 1007*85ae89f4SRuslan Bukin 1008*85ae89f4SRuslan Bukin if (ifp != NULL) 1009*85ae89f4SRuslan Bukin if_free(ifp); 1010*85ae89f4SRuslan Bukin 1011*85ae89f4SRuslan Bukin mtx_destroy(&sc->mtx); 1012*85ae89f4SRuslan Bukin 1013*85ae89f4SRuslan Bukin bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 1014*85ae89f4SRuslan Bukin 1015*85ae89f4SRuslan Bukin bus_release_resources(dev, xae_spec, sc->res); 1016*85ae89f4SRuslan Bukin 1017*85ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_tx); 1018*85ae89f4SRuslan Bukin xdma_channel_free(sc->xchan_rx); 1019*85ae89f4SRuslan Bukin xdma_put(sc->xdma_tx); 1020*85ae89f4SRuslan Bukin xdma_put(sc->xdma_rx); 1021*85ae89f4SRuslan Bukin 1022*85ae89f4SRuslan Bukin return (0); 1023*85ae89f4SRuslan Bukin } 1024*85ae89f4SRuslan Bukin 1025*85ae89f4SRuslan Bukin static void 1026*85ae89f4SRuslan Bukin xae_miibus_statchg(device_t dev) 1027*85ae89f4SRuslan Bukin { 1028*85ae89f4SRuslan Bukin struct xae_softc *sc; 1029*85ae89f4SRuslan Bukin struct mii_data *mii; 1030*85ae89f4SRuslan Bukin uint32_t reg; 1031*85ae89f4SRuslan Bukin 1032*85ae89f4SRuslan Bukin /* 1033*85ae89f4SRuslan Bukin * Called by the MII bus driver when the PHY establishes 1034*85ae89f4SRuslan Bukin * link to set the MAC interface registers. 1035*85ae89f4SRuslan Bukin */ 1036*85ae89f4SRuslan Bukin 1037*85ae89f4SRuslan Bukin sc = device_get_softc(dev); 1038*85ae89f4SRuslan Bukin 1039*85ae89f4SRuslan Bukin XAE_ASSERT_LOCKED(sc); 1040*85ae89f4SRuslan Bukin 1041*85ae89f4SRuslan Bukin mii = sc->mii_softc; 1042*85ae89f4SRuslan Bukin 1043*85ae89f4SRuslan Bukin if (mii->mii_media_status & IFM_ACTIVE) 1044*85ae89f4SRuslan Bukin sc->link_is_up = true; 1045*85ae89f4SRuslan Bukin else 1046*85ae89f4SRuslan Bukin sc->link_is_up = false; 1047*85ae89f4SRuslan Bukin 1048*85ae89f4SRuslan Bukin switch (IFM_SUBTYPE(mii->mii_media_active)) { 1049*85ae89f4SRuslan Bukin case IFM_1000_T: 1050*85ae89f4SRuslan Bukin case IFM_1000_SX: 1051*85ae89f4SRuslan Bukin reg = SPEED_1000; 1052*85ae89f4SRuslan Bukin break; 1053*85ae89f4SRuslan Bukin case IFM_100_TX: 1054*85ae89f4SRuslan Bukin reg = SPEED_100; 1055*85ae89f4SRuslan Bukin break; 1056*85ae89f4SRuslan Bukin case IFM_10_T: 1057*85ae89f4SRuslan Bukin reg = SPEED_10; 1058*85ae89f4SRuslan Bukin break; 1059*85ae89f4SRuslan Bukin case IFM_NONE: 1060*85ae89f4SRuslan Bukin sc->link_is_up = false; 1061*85ae89f4SRuslan Bukin return; 1062*85ae89f4SRuslan Bukin default: 1063*85ae89f4SRuslan Bukin sc->link_is_up = false; 1064*85ae89f4SRuslan Bukin device_printf(dev, "Unsupported media %u\n", 1065*85ae89f4SRuslan Bukin IFM_SUBTYPE(mii->mii_media_active)); 1066*85ae89f4SRuslan Bukin return; 1067*85ae89f4SRuslan Bukin } 1068*85ae89f4SRuslan Bukin 1069*85ae89f4SRuslan Bukin WRITE4(sc, XAE_SPEED, reg); 1070*85ae89f4SRuslan Bukin } 1071*85ae89f4SRuslan Bukin 1072*85ae89f4SRuslan Bukin static device_method_t xae_methods[] = { 1073*85ae89f4SRuslan Bukin DEVMETHOD(device_probe, xae_probe), 1074*85ae89f4SRuslan Bukin DEVMETHOD(device_attach, xae_attach), 1075*85ae89f4SRuslan Bukin DEVMETHOD(device_detach, xae_detach), 1076*85ae89f4SRuslan Bukin 1077*85ae89f4SRuslan Bukin /* MII Interface */ 1078*85ae89f4SRuslan Bukin DEVMETHOD(miibus_readreg, xae_miibus_read_reg), 1079*85ae89f4SRuslan Bukin DEVMETHOD(miibus_writereg, xae_miibus_write_reg), 1080*85ae89f4SRuslan Bukin DEVMETHOD(miibus_statchg, xae_miibus_statchg), 1081*85ae89f4SRuslan Bukin 1082*85ae89f4SRuslan Bukin { 0, 0 } 1083*85ae89f4SRuslan Bukin }; 1084*85ae89f4SRuslan Bukin 1085*85ae89f4SRuslan Bukin driver_t xae_driver = { 1086*85ae89f4SRuslan Bukin "xae", 1087*85ae89f4SRuslan Bukin xae_methods, 1088*85ae89f4SRuslan Bukin sizeof(struct xae_softc), 1089*85ae89f4SRuslan Bukin }; 1090*85ae89f4SRuslan Bukin 1091*85ae89f4SRuslan Bukin static devclass_t xae_devclass; 1092*85ae89f4SRuslan Bukin 1093*85ae89f4SRuslan Bukin DRIVER_MODULE(xae, simplebus, xae_driver, xae_devclass, 0, 0); 1094*85ae89f4SRuslan Bukin DRIVER_MODULE(miibus, xae, miibus_driver, miibus_devclass, 0, 0); 1095*85ae89f4SRuslan Bukin 1096*85ae89f4SRuslan Bukin MODULE_DEPEND(xae, ether, 1, 1, 1); 1097*85ae89f4SRuslan Bukin MODULE_DEPEND(xae, miibus, 1, 1, 1); 1098