1*441d6780SZbigniew Bodek /*- 2*441d6780SZbigniew Bodek * Copyright (c) 2015 The FreeBSD Foundation 3*441d6780SZbigniew Bodek * All rights reserved. 4*441d6780SZbigniew Bodek * 5*441d6780SZbigniew Bodek * This software was developed by Semihalf under 6*441d6780SZbigniew Bodek * the sponsorship of the FreeBSD Foundation. 7*441d6780SZbigniew Bodek * 8*441d6780SZbigniew Bodek * Redistribution and use in source and binary forms, with or without 9*441d6780SZbigniew Bodek * modification, are permitted provided that the following conditions 10*441d6780SZbigniew Bodek * are met: 11*441d6780SZbigniew Bodek * 1. Redistributions of source code must retain the above copyright 12*441d6780SZbigniew Bodek * notice, this list of conditions and the following disclaimer. 13*441d6780SZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright 14*441d6780SZbigniew Bodek * notice, this list of conditions and the following disclaimer in the 15*441d6780SZbigniew Bodek * documentation and/or other materials provided with the distribution. 16*441d6780SZbigniew Bodek * 17*441d6780SZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*441d6780SZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*441d6780SZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*441d6780SZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*441d6780SZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*441d6780SZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*441d6780SZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*441d6780SZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*441d6780SZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*441d6780SZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*441d6780SZbigniew Bodek * SUCH DAMAGE. 28*441d6780SZbigniew Bodek */ 29*441d6780SZbigniew Bodek 30*441d6780SZbigniew Bodek #include <sys/cdefs.h> 31*441d6780SZbigniew Bodek __FBSDID("$FreeBSD$"); 32*441d6780SZbigniew Bodek 33*441d6780SZbigniew Bodek #include <sys/param.h> 34*441d6780SZbigniew Bodek #include <sys/systm.h> 35*441d6780SZbigniew Bodek #include <sys/bus.h> 36*441d6780SZbigniew Bodek #include <sys/kernel.h> 37*441d6780SZbigniew Bodek #include <sys/module.h> 38*441d6780SZbigniew Bodek #include <sys/resource.h> 39*441d6780SZbigniew Bodek #include <sys/rman.h> 40*441d6780SZbigniew Bodek #include <sys/socket.h> 41*441d6780SZbigniew Bodek #include <sys/queue.h> 42*441d6780SZbigniew Bodek 43*441d6780SZbigniew Bodek #include <machine/bus.h> 44*441d6780SZbigniew Bodek #include <machine/resource.h> 45*441d6780SZbigniew Bodek 46*441d6780SZbigniew Bodek #include <net/if.h> 47*441d6780SZbigniew Bodek #include <net/if_media.h> 48*441d6780SZbigniew Bodek #include <net/if_types.h> 49*441d6780SZbigniew Bodek #include <net/if_var.h> 50*441d6780SZbigniew Bodek 51*441d6780SZbigniew Bodek #include <dev/mii/mii.h> 52*441d6780SZbigniew Bodek #include <dev/mii/miivar.h> 53*441d6780SZbigniew Bodek 54*441d6780SZbigniew Bodek #include "thunder_mdio_var.h" 55*441d6780SZbigniew Bodek 56*441d6780SZbigniew Bodek #include "lmac_if.h" 57*441d6780SZbigniew Bodek #include "miibus_if.h" 58*441d6780SZbigniew Bodek 59*441d6780SZbigniew Bodek #define REG_BASE_RID 0 60*441d6780SZbigniew Bodek 61*441d6780SZbigniew Bodek #define SMI_CMD 0x00 62*441d6780SZbigniew Bodek #define SMI_CMD_PHY_REG_ADR_SHIFT (0) 63*441d6780SZbigniew Bodek #define SMI_CMD_PHY_REG_ADR_MASK (0x1FUL << SMI_CMD_PHY_REG_ADR_SHIFT) 64*441d6780SZbigniew Bodek #define SMI_CMD_PHY_ADR_SHIFT (8) 65*441d6780SZbigniew Bodek #define SMI_CMD_PHY_ADR_MASK (0x1FUL << SMI_CMD_PHY_ADR_SHIFT) 66*441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_MASK (0x3UL << 16) 67*441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C22_READ (0x1UL << 16) 68*441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C22_WRITE (0x0UL << 16) 69*441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C45_READ (0x3UL << 16) 70*441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C45_WRITE (0x1UL << 16) 71*441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C45_ADDR (0x0UL << 16) 72*441d6780SZbigniew Bodek 73*441d6780SZbigniew Bodek #define SMI_WR_DAT 0x08 74*441d6780SZbigniew Bodek #define SMI_WR_DAT_PENDING (1UL << 17) 75*441d6780SZbigniew Bodek #define SMI_WR_DAT_VAL (1UL << 16) 76*441d6780SZbigniew Bodek #define SMI_WR_DAT_DAT_MASK (0xFFFFUL << 0) 77*441d6780SZbigniew Bodek 78*441d6780SZbigniew Bodek #define SMI_RD_DAT 0x10 79*441d6780SZbigniew Bodek #define SMI_RD_DAT_PENDING (1UL << 17) 80*441d6780SZbigniew Bodek #define SMI_RD_DAT_VAL (1UL << 16) 81*441d6780SZbigniew Bodek #define SMI_RD_DAT_DAT_MASK (0xFFFFUL << 0) 82*441d6780SZbigniew Bodek 83*441d6780SZbigniew Bodek #define SMI_CLK 0x18 84*441d6780SZbigniew Bodek #define SMI_CLK_PREAMBLE (1UL << 12) 85*441d6780SZbigniew Bodek #define SMI_CLK_MODE (1UL << 24) 86*441d6780SZbigniew Bodek 87*441d6780SZbigniew Bodek #define SMI_EN 0x20 88*441d6780SZbigniew Bodek #define SMI_EN_EN (1UL << 0) /* Enabele interface */ 89*441d6780SZbigniew Bodek 90*441d6780SZbigniew Bodek #define SMI_DRV_CTL 0x28 91*441d6780SZbigniew Bodek 92*441d6780SZbigniew Bodek static int thunder_mdio_detach(device_t); 93*441d6780SZbigniew Bodek 94*441d6780SZbigniew Bodek static int thunder_mdio_read(device_t, int, int); 95*441d6780SZbigniew Bodek static int thunder_mdio_write(device_t, int, int, int); 96*441d6780SZbigniew Bodek 97*441d6780SZbigniew Bodek static int thunder_ifmedia_change_stub(struct ifnet *); 98*441d6780SZbigniew Bodek static void thunder_ifmedia_status_stub(struct ifnet *, struct ifmediareq *); 99*441d6780SZbigniew Bodek 100*441d6780SZbigniew Bodek static int thunder_mdio_media_status(device_t, int, int *, int *, int *); 101*441d6780SZbigniew Bodek static int thunder_mdio_media_change(device_t, int, int, int, int); 102*441d6780SZbigniew Bodek static int thunder_mdio_phy_connect(device_t, int, int); 103*441d6780SZbigniew Bodek static int thunder_mdio_phy_disconnect(device_t, int, int); 104*441d6780SZbigniew Bodek 105*441d6780SZbigniew Bodek static device_method_t thunder_mdio_methods[] = { 106*441d6780SZbigniew Bodek /* Device interface */ 107*441d6780SZbigniew Bodek DEVMETHOD(device_detach, thunder_mdio_detach), 108*441d6780SZbigniew Bodek /* LMAC interface */ 109*441d6780SZbigniew Bodek DEVMETHOD(lmac_media_status, thunder_mdio_media_status), 110*441d6780SZbigniew Bodek DEVMETHOD(lmac_media_change, thunder_mdio_media_change), 111*441d6780SZbigniew Bodek DEVMETHOD(lmac_phy_connect, thunder_mdio_phy_connect), 112*441d6780SZbigniew Bodek DEVMETHOD(lmac_phy_disconnect, thunder_mdio_phy_disconnect), 113*441d6780SZbigniew Bodek /* MII interface */ 114*441d6780SZbigniew Bodek DEVMETHOD(miibus_readreg, thunder_mdio_read), 115*441d6780SZbigniew Bodek DEVMETHOD(miibus_writereg, thunder_mdio_write), 116*441d6780SZbigniew Bodek 117*441d6780SZbigniew Bodek /* End */ 118*441d6780SZbigniew Bodek DEVMETHOD_END 119*441d6780SZbigniew Bodek }; 120*441d6780SZbigniew Bodek 121*441d6780SZbigniew Bodek DEFINE_CLASS_0(thunder_mdio, thunder_mdio_driver, thunder_mdio_methods, 122*441d6780SZbigniew Bodek sizeof(struct thunder_mdio_softc)); 123*441d6780SZbigniew Bodek 124*441d6780SZbigniew Bodek DRIVER_MODULE(miibus, thunder_mdio, miibus_driver, miibus_devclass, 0, 0); 125*441d6780SZbigniew Bodek MODULE_DEPEND(thunder_mdio, ether, 1, 1, 1); 126*441d6780SZbigniew Bodek MODULE_DEPEND(thunder_mdio, miibus, 1, 1, 1); 127*441d6780SZbigniew Bodek 128*441d6780SZbigniew Bodek MALLOC_DEFINE(M_THUNDER_MDIO, "ThunderX MDIO", 129*441d6780SZbigniew Bodek "Cavium ThunderX MDIO dynamic memory"); 130*441d6780SZbigniew Bodek 131*441d6780SZbigniew Bodek #define MDIO_LOCK_INIT(sc, name) \ 132*441d6780SZbigniew Bodek mtx_init(&(sc)->mtx, name, NULL, MTX_DEF) 133*441d6780SZbigniew Bodek 134*441d6780SZbigniew Bodek #define MDIO_LOCK_DESTROY(sc) \ 135*441d6780SZbigniew Bodek mtx_destroy(&(sc)->mtx) 136*441d6780SZbigniew Bodek 137*441d6780SZbigniew Bodek #define MDIO_LOCK(sc) mtx_lock(&(sc)->mtx) 138*441d6780SZbigniew Bodek #define MDIO_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 139*441d6780SZbigniew Bodek 140*441d6780SZbigniew Bodek #define MDIO_LOCK_ASSERT(sc) \ 141*441d6780SZbigniew Bodek mtx_assert(&(sc)->mtx, MA_OWNED) 142*441d6780SZbigniew Bodek 143*441d6780SZbigniew Bodek 144*441d6780SZbigniew Bodek #define mdio_reg_read(sc, reg) \ 145*441d6780SZbigniew Bodek bus_read_8((sc)->reg_base, (reg)) 146*441d6780SZbigniew Bodek 147*441d6780SZbigniew Bodek #define mdio_reg_write(sc, reg, val) \ 148*441d6780SZbigniew Bodek bus_write_8((sc)->reg_base, (reg), (val)) 149*441d6780SZbigniew Bodek 150*441d6780SZbigniew Bodek int 151*441d6780SZbigniew Bodek thunder_mdio_attach(device_t dev) 152*441d6780SZbigniew Bodek { 153*441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 154*441d6780SZbigniew Bodek int rid; 155*441d6780SZbigniew Bodek 156*441d6780SZbigniew Bodek sc = device_get_softc(dev); 157*441d6780SZbigniew Bodek sc->dev = dev; 158*441d6780SZbigniew Bodek 159*441d6780SZbigniew Bodek /* Allocate memory resources */ 160*441d6780SZbigniew Bodek rid = REG_BASE_RID; 161*441d6780SZbigniew Bodek sc->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 162*441d6780SZbigniew Bodek RF_ACTIVE); 163*441d6780SZbigniew Bodek if (sc->reg_base == NULL) { 164*441d6780SZbigniew Bodek device_printf(dev, "Could not allocate memory\n"); 165*441d6780SZbigniew Bodek return (ENXIO); 166*441d6780SZbigniew Bodek } 167*441d6780SZbigniew Bodek 168*441d6780SZbigniew Bodek TAILQ_INIT(&sc->phy_desc_head); 169*441d6780SZbigniew Bodek MDIO_LOCK_INIT(sc, "ThunderX MDIO lock"); 170*441d6780SZbigniew Bodek 171*441d6780SZbigniew Bodek /* Enable SMI/MDIO interface */ 172*441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_EN, SMI_EN_EN); 173*441d6780SZbigniew Bodek 174*441d6780SZbigniew Bodek return (0); 175*441d6780SZbigniew Bodek } 176*441d6780SZbigniew Bodek 177*441d6780SZbigniew Bodek static int 178*441d6780SZbigniew Bodek thunder_mdio_detach(device_t dev) 179*441d6780SZbigniew Bodek { 180*441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 181*441d6780SZbigniew Bodek 182*441d6780SZbigniew Bodek sc = device_get_softc(dev); 183*441d6780SZbigniew Bodek 184*441d6780SZbigniew Bodek if (sc->reg_base != NULL) { 185*441d6780SZbigniew Bodek bus_release_resource(dev, SYS_RES_MEMORY, REG_BASE_RID, 186*441d6780SZbigniew Bodek sc->reg_base); 187*441d6780SZbigniew Bodek } 188*441d6780SZbigniew Bodek 189*441d6780SZbigniew Bodek return (0); 190*441d6780SZbigniew Bodek } 191*441d6780SZbigniew Bodek 192*441d6780SZbigniew Bodek static __inline void 193*441d6780SZbigniew Bodek thunder_mdio_set_mode(struct thunder_mdio_softc *sc, 194*441d6780SZbigniew Bodek enum thunder_mdio_mode mode) 195*441d6780SZbigniew Bodek { 196*441d6780SZbigniew Bodek uint64_t smi_clk; 197*441d6780SZbigniew Bodek 198*441d6780SZbigniew Bodek if (sc->mode == mode) 199*441d6780SZbigniew Bodek return; 200*441d6780SZbigniew Bodek 201*441d6780SZbigniew Bodek /* Set mode, IEEE CLAUSE 22 or IEEE CAUSE 45 */ 202*441d6780SZbigniew Bodek smi_clk = mdio_reg_read(sc, SMI_CLK); 203*441d6780SZbigniew Bodek if (mode == MODE_IEEE_C22) 204*441d6780SZbigniew Bodek smi_clk &= ~SMI_CLK_MODE; 205*441d6780SZbigniew Bodek else 206*441d6780SZbigniew Bodek smi_clk |= SMI_CLK_MODE; 207*441d6780SZbigniew Bodek /* Enable sending 32 bit preable on SMI transactions */ 208*441d6780SZbigniew Bodek smi_clk |= SMI_CLK_PREAMBLE; 209*441d6780SZbigniew Bodek /* Saved setings */ 210*441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CLK, smi_clk); 211*441d6780SZbigniew Bodek sc->mode = mode; 212*441d6780SZbigniew Bodek } 213*441d6780SZbigniew Bodek 214*441d6780SZbigniew Bodek static int 215*441d6780SZbigniew Bodek thunder_mdio_c45_addr(struct thunder_mdio_softc *sc, int phy, int reg) 216*441d6780SZbigniew Bodek { 217*441d6780SZbigniew Bodek uint64_t smi_cmd, smi_wr_dat; 218*441d6780SZbigniew Bodek ssize_t timeout; 219*441d6780SZbigniew Bodek 220*441d6780SZbigniew Bodek thunder_mdio_set_mode(sc, MODE_IEEE_C45); 221*441d6780SZbigniew Bodek 222*441d6780SZbigniew Bodek /* Prepare data for transmission */ 223*441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_WR_DAT, reg & SMI_WR_DAT_DAT_MASK); 224*441d6780SZbigniew Bodek /* 225*441d6780SZbigniew Bodek * Assemble command 226*441d6780SZbigniew Bodek */ 227*441d6780SZbigniew Bodek smi_cmd = 0; 228*441d6780SZbigniew Bodek /* Set opcode */ 229*441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C45_WRITE; 230*441d6780SZbigniew Bodek 231*441d6780SZbigniew Bodek /* Set PHY address */ 232*441d6780SZbigniew Bodek smi_cmd |= ((phy << SMI_CMD_PHY_ADR_SHIFT) & SMI_CMD_PHY_ADR_MASK); 233*441d6780SZbigniew Bodek /* Set PHY register offset */ 234*441d6780SZbigniew Bodek smi_cmd |= ((reg << SMI_CMD_PHY_REG_ADR_SHIFT) & 235*441d6780SZbigniew Bodek SMI_CMD_PHY_REG_ADR_MASK); 236*441d6780SZbigniew Bodek 237*441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CMD, smi_cmd); 238*441d6780SZbigniew Bodek for (timeout = 1000; timeout > 0; timeout--) { 239*441d6780SZbigniew Bodek smi_wr_dat = mdio_reg_read(sc, SMI_WR_DAT); 240*441d6780SZbigniew Bodek if (smi_wr_dat & SMI_WR_DAT_PENDING) 241*441d6780SZbigniew Bodek DELAY(1000); 242*441d6780SZbigniew Bodek else 243*441d6780SZbigniew Bodek break; 244*441d6780SZbigniew Bodek } 245*441d6780SZbigniew Bodek 246*441d6780SZbigniew Bodek if (timeout <= 0) 247*441d6780SZbigniew Bodek return (EIO); 248*441d6780SZbigniew Bodek else { 249*441d6780SZbigniew Bodek /* Return 0 on success */ 250*441d6780SZbigniew Bodek return (0); 251*441d6780SZbigniew Bodek } 252*441d6780SZbigniew Bodek } 253*441d6780SZbigniew Bodek 254*441d6780SZbigniew Bodek static int 255*441d6780SZbigniew Bodek thunder_mdio_read(device_t dev, int phy, int reg) 256*441d6780SZbigniew Bodek { 257*441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 258*441d6780SZbigniew Bodek uint64_t smi_cmd, smi_rd_dat; 259*441d6780SZbigniew Bodek ssize_t timeout; 260*441d6780SZbigniew Bodek int err; 261*441d6780SZbigniew Bodek 262*441d6780SZbigniew Bodek sc = device_get_softc(dev); 263*441d6780SZbigniew Bodek 264*441d6780SZbigniew Bodek /* XXX Always C22 - for <= 1Gbps only */ 265*441d6780SZbigniew Bodek thunder_mdio_set_mode(sc, MODE_IEEE_C22); 266*441d6780SZbigniew Bodek 267*441d6780SZbigniew Bodek /* 268*441d6780SZbigniew Bodek * Assemble command 269*441d6780SZbigniew Bodek */ 270*441d6780SZbigniew Bodek smi_cmd = 0; 271*441d6780SZbigniew Bodek /* Set opcode */ 272*441d6780SZbigniew Bodek if (sc->mode == MODE_IEEE_C22) 273*441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C22_READ; 274*441d6780SZbigniew Bodek else { 275*441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C45_READ; 276*441d6780SZbigniew Bodek err = thunder_mdio_c45_addr(sc, phy, reg); 277*441d6780SZbigniew Bodek if (err != 0) 278*441d6780SZbigniew Bodek return (err); 279*441d6780SZbigniew Bodek 280*441d6780SZbigniew Bodek reg = (reg >> 16) & 0x1F; 281*441d6780SZbigniew Bodek } 282*441d6780SZbigniew Bodek 283*441d6780SZbigniew Bodek /* Set PHY address */ 284*441d6780SZbigniew Bodek smi_cmd |= ((phy << SMI_CMD_PHY_ADR_SHIFT) & SMI_CMD_PHY_ADR_MASK); 285*441d6780SZbigniew Bodek /* Set PHY register offset */ 286*441d6780SZbigniew Bodek smi_cmd |= ((reg << SMI_CMD_PHY_REG_ADR_SHIFT) & 287*441d6780SZbigniew Bodek SMI_CMD_PHY_REG_ADR_MASK); 288*441d6780SZbigniew Bodek 289*441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CMD, smi_cmd); 290*441d6780SZbigniew Bodek for (timeout = 1000; timeout > 0; timeout--) { 291*441d6780SZbigniew Bodek smi_rd_dat = mdio_reg_read(sc, SMI_RD_DAT); 292*441d6780SZbigniew Bodek if (smi_rd_dat & SMI_RD_DAT_PENDING) 293*441d6780SZbigniew Bodek DELAY(1000); 294*441d6780SZbigniew Bodek else 295*441d6780SZbigniew Bodek break; 296*441d6780SZbigniew Bodek } 297*441d6780SZbigniew Bodek 298*441d6780SZbigniew Bodek if (smi_rd_dat & SMI_RD_DAT_VAL) 299*441d6780SZbigniew Bodek return (smi_rd_dat & SMI_RD_DAT_DAT_MASK); 300*441d6780SZbigniew Bodek else { 301*441d6780SZbigniew Bodek /* Return 0 on error */ 302*441d6780SZbigniew Bodek return (0); 303*441d6780SZbigniew Bodek } 304*441d6780SZbigniew Bodek } 305*441d6780SZbigniew Bodek 306*441d6780SZbigniew Bodek static int 307*441d6780SZbigniew Bodek thunder_mdio_write(device_t dev, int phy, int reg, int data) 308*441d6780SZbigniew Bodek { 309*441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 310*441d6780SZbigniew Bodek uint64_t smi_cmd, smi_wr_dat; 311*441d6780SZbigniew Bodek ssize_t timeout; 312*441d6780SZbigniew Bodek 313*441d6780SZbigniew Bodek sc = device_get_softc(dev); 314*441d6780SZbigniew Bodek 315*441d6780SZbigniew Bodek /* XXX Always C22 - for <= 1Gbps only */ 316*441d6780SZbigniew Bodek thunder_mdio_set_mode(sc, MODE_IEEE_C22); 317*441d6780SZbigniew Bodek 318*441d6780SZbigniew Bodek /* Prepare data for transmission */ 319*441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_WR_DAT, data & SMI_WR_DAT_DAT_MASK); 320*441d6780SZbigniew Bodek /* 321*441d6780SZbigniew Bodek * Assemble command 322*441d6780SZbigniew Bodek */ 323*441d6780SZbigniew Bodek smi_cmd = 0; 324*441d6780SZbigniew Bodek /* Set opcode */ 325*441d6780SZbigniew Bodek if (sc->mode == MODE_IEEE_C22) 326*441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C22_WRITE; 327*441d6780SZbigniew Bodek else 328*441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C45_WRITE; 329*441d6780SZbigniew Bodek 330*441d6780SZbigniew Bodek /* Set PHY address */ 331*441d6780SZbigniew Bodek smi_cmd |= ((phy << SMI_CMD_PHY_ADR_SHIFT) & SMI_CMD_PHY_ADR_MASK); 332*441d6780SZbigniew Bodek /* Set PHY register offset */ 333*441d6780SZbigniew Bodek smi_cmd |= ((reg << SMI_CMD_PHY_REG_ADR_SHIFT) & 334*441d6780SZbigniew Bodek SMI_CMD_PHY_REG_ADR_MASK); 335*441d6780SZbigniew Bodek 336*441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CMD, smi_cmd); 337*441d6780SZbigniew Bodek for (timeout = 1000; timeout > 0; timeout--) { 338*441d6780SZbigniew Bodek smi_wr_dat = mdio_reg_read(sc, SMI_WR_DAT); 339*441d6780SZbigniew Bodek if (smi_wr_dat & SMI_WR_DAT_PENDING) 340*441d6780SZbigniew Bodek DELAY(1000); 341*441d6780SZbigniew Bodek else 342*441d6780SZbigniew Bodek break; 343*441d6780SZbigniew Bodek } 344*441d6780SZbigniew Bodek 345*441d6780SZbigniew Bodek if (timeout <= 0) 346*441d6780SZbigniew Bodek return (EIO); 347*441d6780SZbigniew Bodek else { 348*441d6780SZbigniew Bodek /* Return 0 on success */ 349*441d6780SZbigniew Bodek return (0); 350*441d6780SZbigniew Bodek } 351*441d6780SZbigniew Bodek } 352*441d6780SZbigniew Bodek 353*441d6780SZbigniew Bodek static int 354*441d6780SZbigniew Bodek thunder_ifmedia_change_stub(struct ifnet *ifp __unused) 355*441d6780SZbigniew Bodek { 356*441d6780SZbigniew Bodek /* Will never be called by if_media */ 357*441d6780SZbigniew Bodek return (0); 358*441d6780SZbigniew Bodek } 359*441d6780SZbigniew Bodek 360*441d6780SZbigniew Bodek static void 361*441d6780SZbigniew Bodek thunder_ifmedia_status_stub(struct ifnet *ifp __unused, struct ifmediareq 362*441d6780SZbigniew Bodek *ifmr __unused) 363*441d6780SZbigniew Bodek { 364*441d6780SZbigniew Bodek /* Will never be called by if_media */ 365*441d6780SZbigniew Bodek } 366*441d6780SZbigniew Bodek 367*441d6780SZbigniew Bodek static __inline struct phy_desc * 368*441d6780SZbigniew Bodek get_phy_desc(struct thunder_mdio_softc *sc, int lmacid) 369*441d6780SZbigniew Bodek { 370*441d6780SZbigniew Bodek struct phy_desc *pd = NULL; 371*441d6780SZbigniew Bodek 372*441d6780SZbigniew Bodek MDIO_LOCK_ASSERT(sc); 373*441d6780SZbigniew Bodek TAILQ_FOREACH(pd, &sc->phy_desc_head, phy_desc_list) { 374*441d6780SZbigniew Bodek if (pd->lmacid == lmacid) 375*441d6780SZbigniew Bodek break; 376*441d6780SZbigniew Bodek } 377*441d6780SZbigniew Bodek 378*441d6780SZbigniew Bodek return (pd); 379*441d6780SZbigniew Bodek } 380*441d6780SZbigniew Bodek static int 381*441d6780SZbigniew Bodek thunder_mdio_media_status(device_t dev, int lmacid, int *link, int *duplex, 382*441d6780SZbigniew Bodek int *speed) 383*441d6780SZbigniew Bodek { 384*441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 385*441d6780SZbigniew Bodek struct mii_data *mii_sc; 386*441d6780SZbigniew Bodek struct phy_desc *pd; 387*441d6780SZbigniew Bodek 388*441d6780SZbigniew Bodek sc = device_get_softc(dev); 389*441d6780SZbigniew Bodek 390*441d6780SZbigniew Bodek MDIO_LOCK(sc); 391*441d6780SZbigniew Bodek pd = get_phy_desc(sc, lmacid); 392*441d6780SZbigniew Bodek if (pd == NULL) { 393*441d6780SZbigniew Bodek /* Panic when invariants are enabled, fail otherwise. */ 394*441d6780SZbigniew Bodek KASSERT(0, ("%s: no PHY descriptor for LMAC%d", 395*441d6780SZbigniew Bodek __func__, lmacid)); 396*441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 397*441d6780SZbigniew Bodek return (ENXIO); 398*441d6780SZbigniew Bodek } 399*441d6780SZbigniew Bodek mii_sc = device_get_softc(pd->miibus); 400*441d6780SZbigniew Bodek 401*441d6780SZbigniew Bodek mii_tick(mii_sc); 402*441d6780SZbigniew Bodek if ((mii_sc->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 403*441d6780SZbigniew Bodek (IFM_ACTIVE | IFM_AVALID)) { 404*441d6780SZbigniew Bodek /* Link is up */ 405*441d6780SZbigniew Bodek *link = 1; 406*441d6780SZbigniew Bodek } else 407*441d6780SZbigniew Bodek *link = 0; 408*441d6780SZbigniew Bodek 409*441d6780SZbigniew Bodek switch (IFM_SUBTYPE(mii_sc->mii_media_active)) { 410*441d6780SZbigniew Bodek case IFM_10_T: 411*441d6780SZbigniew Bodek *speed = 10; 412*441d6780SZbigniew Bodek break; 413*441d6780SZbigniew Bodek case IFM_100_TX: 414*441d6780SZbigniew Bodek *speed = 100; 415*441d6780SZbigniew Bodek break; 416*441d6780SZbigniew Bodek case IFM_1000_T: 417*441d6780SZbigniew Bodek *speed = 1000; 418*441d6780SZbigniew Bodek break; 419*441d6780SZbigniew Bodek default: 420*441d6780SZbigniew Bodek /* IFM_NONE */ 421*441d6780SZbigniew Bodek *speed = 0; 422*441d6780SZbigniew Bodek } 423*441d6780SZbigniew Bodek 424*441d6780SZbigniew Bodek if ((IFM_OPTIONS(mii_sc->mii_media_active) & IFM_FDX) != 0) 425*441d6780SZbigniew Bodek *duplex = 1; 426*441d6780SZbigniew Bodek else 427*441d6780SZbigniew Bodek *duplex = 0; 428*441d6780SZbigniew Bodek 429*441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 430*441d6780SZbigniew Bodek 431*441d6780SZbigniew Bodek return (0); 432*441d6780SZbigniew Bodek } 433*441d6780SZbigniew Bodek 434*441d6780SZbigniew Bodek static int 435*441d6780SZbigniew Bodek thunder_mdio_media_change(device_t dev, int lmacid, int link, int duplex, 436*441d6780SZbigniew Bodek int speed) 437*441d6780SZbigniew Bodek { 438*441d6780SZbigniew Bodek 439*441d6780SZbigniew Bodek return (EIO); 440*441d6780SZbigniew Bodek } 441*441d6780SZbigniew Bodek 442*441d6780SZbigniew Bodek static int 443*441d6780SZbigniew Bodek thunder_mdio_phy_connect(device_t dev, int lmacid, int phy) 444*441d6780SZbigniew Bodek { 445*441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 446*441d6780SZbigniew Bodek struct phy_desc *pd; 447*441d6780SZbigniew Bodek int err; 448*441d6780SZbigniew Bodek 449*441d6780SZbigniew Bodek sc = device_get_softc(dev); 450*441d6780SZbigniew Bodek 451*441d6780SZbigniew Bodek MDIO_LOCK(sc); 452*441d6780SZbigniew Bodek pd = get_phy_desc(sc, lmacid); 453*441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 454*441d6780SZbigniew Bodek if (pd == NULL) { 455*441d6780SZbigniew Bodek pd = malloc(sizeof(*pd), M_THUNDER_MDIO, (M_NOWAIT | M_ZERO)); 456*441d6780SZbigniew Bodek if (pd == NULL) 457*441d6780SZbigniew Bodek return (ENOMEM); 458*441d6780SZbigniew Bodek pd->ifp = if_alloc(IFT_ETHER); 459*441d6780SZbigniew Bodek if (pd->ifp == NULL) { 460*441d6780SZbigniew Bodek free(pd, M_THUNDER_MDIO); 461*441d6780SZbigniew Bodek return (ENOMEM); 462*441d6780SZbigniew Bodek } 463*441d6780SZbigniew Bodek pd->lmacid = lmacid; 464*441d6780SZbigniew Bodek } 465*441d6780SZbigniew Bodek 466*441d6780SZbigniew Bodek err = mii_attach(dev, &pd->miibus, pd->ifp, 467*441d6780SZbigniew Bodek thunder_ifmedia_change_stub, thunder_ifmedia_status_stub, 468*441d6780SZbigniew Bodek BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 469*441d6780SZbigniew Bodek 470*441d6780SZbigniew Bodek if (err != 0) { 471*441d6780SZbigniew Bodek device_printf(dev, "Could not attach PHY%d\n", phy); 472*441d6780SZbigniew Bodek if_free(pd->ifp); 473*441d6780SZbigniew Bodek free(pd, M_THUNDER_MDIO); 474*441d6780SZbigniew Bodek return (ENXIO); 475*441d6780SZbigniew Bodek } 476*441d6780SZbigniew Bodek 477*441d6780SZbigniew Bodek MDIO_LOCK(sc); 478*441d6780SZbigniew Bodek TAILQ_INSERT_TAIL(&sc->phy_desc_head, pd, phy_desc_list); 479*441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 480*441d6780SZbigniew Bodek 481*441d6780SZbigniew Bodek return (0); 482*441d6780SZbigniew Bodek } 483*441d6780SZbigniew Bodek 484*441d6780SZbigniew Bodek static int 485*441d6780SZbigniew Bodek thunder_mdio_phy_disconnect(device_t dev, int lmacid, int phy) 486*441d6780SZbigniew Bodek { 487*441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 488*441d6780SZbigniew Bodek struct phy_desc *pd; 489*441d6780SZbigniew Bodek 490*441d6780SZbigniew Bodek sc = device_get_softc(dev); 491*441d6780SZbigniew Bodek MDIO_LOCK(sc); 492*441d6780SZbigniew Bodek 493*441d6780SZbigniew Bodek pd = get_phy_desc(sc, lmacid); 494*441d6780SZbigniew Bodek if (pd == NULL) { 495*441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 496*441d6780SZbigniew Bodek return (EINVAL); 497*441d6780SZbigniew Bodek } 498*441d6780SZbigniew Bodek 499*441d6780SZbigniew Bodek /* Remove this PHY descriptor from the list */ 500*441d6780SZbigniew Bodek TAILQ_REMOVE(&sc->phy_desc_head, pd, phy_desc_list); 501*441d6780SZbigniew Bodek 502*441d6780SZbigniew Bodek /* Detach miibus */ 503*441d6780SZbigniew Bodek bus_generic_detach(dev); 504*441d6780SZbigniew Bodek device_delete_child(dev, pd->miibus); 505*441d6780SZbigniew Bodek /* Free fake ifnet */ 506*441d6780SZbigniew Bodek if_free(pd->ifp); 507*441d6780SZbigniew Bodek /* Free memory under phy descriptor */ 508*441d6780SZbigniew Bodek free(pd, M_THUNDER_MDIO); 509*441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 510*441d6780SZbigniew Bodek 511*441d6780SZbigniew Bodek return (0); 512*441d6780SZbigniew Bodek } 513