1441d6780SZbigniew Bodek /*- 2441d6780SZbigniew Bodek * Copyright (c) 2015 The FreeBSD Foundation 3441d6780SZbigniew Bodek * 4441d6780SZbigniew Bodek * This software was developed by Semihalf under 5441d6780SZbigniew Bodek * the sponsorship of the FreeBSD Foundation. 6441d6780SZbigniew Bodek * 7441d6780SZbigniew Bodek * Redistribution and use in source and binary forms, with or without 8441d6780SZbigniew Bodek * modification, are permitted provided that the following conditions 9441d6780SZbigniew Bodek * are met: 10441d6780SZbigniew Bodek * 1. Redistributions of source code must retain the above copyright 11441d6780SZbigniew Bodek * notice, this list of conditions and the following disclaimer. 12441d6780SZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright 13441d6780SZbigniew Bodek * notice, this list of conditions and the following disclaimer in the 14441d6780SZbigniew Bodek * documentation and/or other materials provided with the distribution. 15441d6780SZbigniew Bodek * 16441d6780SZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17441d6780SZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18441d6780SZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19441d6780SZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20441d6780SZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21441d6780SZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22441d6780SZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23441d6780SZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24441d6780SZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25441d6780SZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26441d6780SZbigniew Bodek * SUCH DAMAGE. 27441d6780SZbigniew Bodek */ 28441d6780SZbigniew Bodek 29441d6780SZbigniew Bodek #include <sys/param.h> 30441d6780SZbigniew Bodek #include <sys/systm.h> 31441d6780SZbigniew Bodek #include <sys/bus.h> 32441d6780SZbigniew Bodek #include <sys/kernel.h> 33441d6780SZbigniew Bodek #include <sys/module.h> 34441d6780SZbigniew Bodek #include <sys/resource.h> 35441d6780SZbigniew Bodek #include <sys/rman.h> 36441d6780SZbigniew Bodek #include <sys/socket.h> 37441d6780SZbigniew Bodek #include <sys/queue.h> 38441d6780SZbigniew Bodek 39441d6780SZbigniew Bodek #include <machine/bus.h> 40441d6780SZbigniew Bodek #include <machine/resource.h> 41441d6780SZbigniew Bodek 42441d6780SZbigniew Bodek #include <net/if.h> 43441d6780SZbigniew Bodek #include <net/if_media.h> 44441d6780SZbigniew Bodek #include <net/if_types.h> 45441d6780SZbigniew Bodek #include <net/if_var.h> 46441d6780SZbigniew Bodek 47441d6780SZbigniew Bodek #include <dev/mii/mii.h> 48441d6780SZbigniew Bodek #include <dev/mii/miivar.h> 49441d6780SZbigniew Bodek 50441d6780SZbigniew Bodek #include "thunder_mdio_var.h" 51441d6780SZbigniew Bodek 52441d6780SZbigniew Bodek #include "lmac_if.h" 53441d6780SZbigniew Bodek #include "miibus_if.h" 54441d6780SZbigniew Bodek 55441d6780SZbigniew Bodek #define REG_BASE_RID 0 56441d6780SZbigniew Bodek 57441d6780SZbigniew Bodek #define SMI_CMD 0x00 58441d6780SZbigniew Bodek #define SMI_CMD_PHY_REG_ADR_SHIFT (0) 59441d6780SZbigniew Bodek #define SMI_CMD_PHY_REG_ADR_MASK (0x1FUL << SMI_CMD_PHY_REG_ADR_SHIFT) 60441d6780SZbigniew Bodek #define SMI_CMD_PHY_ADR_SHIFT (8) 61441d6780SZbigniew Bodek #define SMI_CMD_PHY_ADR_MASK (0x1FUL << SMI_CMD_PHY_ADR_SHIFT) 62441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_MASK (0x3UL << 16) 63441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C22_READ (0x1UL << 16) 64441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C22_WRITE (0x0UL << 16) 65441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C45_READ (0x3UL << 16) 66441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C45_WRITE (0x1UL << 16) 67441d6780SZbigniew Bodek #define SMI_CMD_PHY_OP_C45_ADDR (0x0UL << 16) 68441d6780SZbigniew Bodek 69441d6780SZbigniew Bodek #define SMI_WR_DAT 0x08 70441d6780SZbigniew Bodek #define SMI_WR_DAT_PENDING (1UL << 17) 71441d6780SZbigniew Bodek #define SMI_WR_DAT_VAL (1UL << 16) 72441d6780SZbigniew Bodek #define SMI_WR_DAT_DAT_MASK (0xFFFFUL << 0) 73441d6780SZbigniew Bodek 74441d6780SZbigniew Bodek #define SMI_RD_DAT 0x10 75441d6780SZbigniew Bodek #define SMI_RD_DAT_PENDING (1UL << 17) 76441d6780SZbigniew Bodek #define SMI_RD_DAT_VAL (1UL << 16) 77441d6780SZbigniew Bodek #define SMI_RD_DAT_DAT_MASK (0xFFFFUL << 0) 78441d6780SZbigniew Bodek 79441d6780SZbigniew Bodek #define SMI_CLK 0x18 80441d6780SZbigniew Bodek #define SMI_CLK_PREAMBLE (1UL << 12) 81441d6780SZbigniew Bodek #define SMI_CLK_MODE (1UL << 24) 82441d6780SZbigniew Bodek 83441d6780SZbigniew Bodek #define SMI_EN 0x20 84*b73763fcSGordon Bergling #define SMI_EN_EN (1UL << 0) /* Enable interface */ 85441d6780SZbigniew Bodek 86441d6780SZbigniew Bodek #define SMI_DRV_CTL 0x28 87441d6780SZbigniew Bodek 88441d6780SZbigniew Bodek static int thunder_mdio_detach(device_t); 89441d6780SZbigniew Bodek 90441d6780SZbigniew Bodek static int thunder_mdio_read(device_t, int, int); 91441d6780SZbigniew Bodek static int thunder_mdio_write(device_t, int, int, int); 92441d6780SZbigniew Bodek 93b9545c57SJustin Hibbits static int thunder_ifmedia_change_stub(if_t); 94b9545c57SJustin Hibbits static void thunder_ifmedia_status_stub(if_t, struct ifmediareq *); 95441d6780SZbigniew Bodek 96441d6780SZbigniew Bodek static int thunder_mdio_media_status(device_t, int, int *, int *, int *); 97441d6780SZbigniew Bodek static int thunder_mdio_media_change(device_t, int, int, int, int); 98441d6780SZbigniew Bodek static int thunder_mdio_phy_connect(device_t, int, int); 99441d6780SZbigniew Bodek static int thunder_mdio_phy_disconnect(device_t, int, int); 100441d6780SZbigniew Bodek 101441d6780SZbigniew Bodek static device_method_t thunder_mdio_methods[] = { 102441d6780SZbigniew Bodek /* Device interface */ 103441d6780SZbigniew Bodek DEVMETHOD(device_detach, thunder_mdio_detach), 104441d6780SZbigniew Bodek /* LMAC interface */ 105441d6780SZbigniew Bodek DEVMETHOD(lmac_media_status, thunder_mdio_media_status), 106441d6780SZbigniew Bodek DEVMETHOD(lmac_media_change, thunder_mdio_media_change), 107441d6780SZbigniew Bodek DEVMETHOD(lmac_phy_connect, thunder_mdio_phy_connect), 108441d6780SZbigniew Bodek DEVMETHOD(lmac_phy_disconnect, thunder_mdio_phy_disconnect), 109441d6780SZbigniew Bodek /* MII interface */ 110441d6780SZbigniew Bodek DEVMETHOD(miibus_readreg, thunder_mdio_read), 111441d6780SZbigniew Bodek DEVMETHOD(miibus_writereg, thunder_mdio_write), 112441d6780SZbigniew Bodek 113441d6780SZbigniew Bodek /* End */ 114441d6780SZbigniew Bodek DEVMETHOD_END 115441d6780SZbigniew Bodek }; 116441d6780SZbigniew Bodek 117441d6780SZbigniew Bodek DEFINE_CLASS_0(thunder_mdio, thunder_mdio_driver, thunder_mdio_methods, 118441d6780SZbigniew Bodek sizeof(struct thunder_mdio_softc)); 119441d6780SZbigniew Bodek 1203e38757dSJohn Baldwin DRIVER_MODULE(miibus, thunder_mdio, miibus_driver, 0, 0); 121f4aafb9eSWojciech Macek MODULE_VERSION(thunder_mdio, 1); 122441d6780SZbigniew Bodek MODULE_DEPEND(thunder_mdio, ether, 1, 1, 1); 123441d6780SZbigniew Bodek MODULE_DEPEND(thunder_mdio, miibus, 1, 1, 1); 124f4aafb9eSWojciech Macek MODULE_DEPEND(thunder_mdio, mrmlbus, 1, 1, 1); 125441d6780SZbigniew Bodek 126441d6780SZbigniew Bodek MALLOC_DEFINE(M_THUNDER_MDIO, "ThunderX MDIO", 127441d6780SZbigniew Bodek "Cavium ThunderX MDIO dynamic memory"); 128441d6780SZbigniew Bodek 129441d6780SZbigniew Bodek #define MDIO_LOCK_INIT(sc, name) \ 130441d6780SZbigniew Bodek mtx_init(&(sc)->mtx, name, NULL, MTX_DEF) 131441d6780SZbigniew Bodek 132441d6780SZbigniew Bodek #define MDIO_LOCK_DESTROY(sc) \ 133441d6780SZbigniew Bodek mtx_destroy(&(sc)->mtx) 134441d6780SZbigniew Bodek 135441d6780SZbigniew Bodek #define MDIO_LOCK(sc) mtx_lock(&(sc)->mtx) 136441d6780SZbigniew Bodek #define MDIO_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 137441d6780SZbigniew Bodek 138441d6780SZbigniew Bodek #define MDIO_LOCK_ASSERT(sc) \ 139441d6780SZbigniew Bodek mtx_assert(&(sc)->mtx, MA_OWNED) 140441d6780SZbigniew Bodek 141441d6780SZbigniew Bodek #define mdio_reg_read(sc, reg) \ 142441d6780SZbigniew Bodek bus_read_8((sc)->reg_base, (reg)) 143441d6780SZbigniew Bodek 144441d6780SZbigniew Bodek #define mdio_reg_write(sc, reg, val) \ 145441d6780SZbigniew Bodek bus_write_8((sc)->reg_base, (reg), (val)) 146441d6780SZbigniew Bodek 147441d6780SZbigniew Bodek int 148441d6780SZbigniew Bodek thunder_mdio_attach(device_t dev) 149441d6780SZbigniew Bodek { 150441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 151441d6780SZbigniew Bodek int rid; 152441d6780SZbigniew Bodek 153441d6780SZbigniew Bodek sc = device_get_softc(dev); 154441d6780SZbigniew Bodek sc->dev = dev; 155441d6780SZbigniew Bodek 156441d6780SZbigniew Bodek /* Allocate memory resources */ 157441d6780SZbigniew Bodek rid = REG_BASE_RID; 158441d6780SZbigniew Bodek sc->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 159441d6780SZbigniew Bodek RF_ACTIVE); 160441d6780SZbigniew Bodek if (sc->reg_base == NULL) { 161441d6780SZbigniew Bodek device_printf(dev, "Could not allocate memory\n"); 162441d6780SZbigniew Bodek return (ENXIO); 163441d6780SZbigniew Bodek } 164441d6780SZbigniew Bodek 165441d6780SZbigniew Bodek TAILQ_INIT(&sc->phy_desc_head); 166441d6780SZbigniew Bodek MDIO_LOCK_INIT(sc, "ThunderX MDIO lock"); 167441d6780SZbigniew Bodek 168441d6780SZbigniew Bodek /* Enable SMI/MDIO interface */ 169441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_EN, SMI_EN_EN); 170441d6780SZbigniew Bodek 171441d6780SZbigniew Bodek return (0); 172441d6780SZbigniew Bodek } 173441d6780SZbigniew Bodek 174441d6780SZbigniew Bodek static int 175441d6780SZbigniew Bodek thunder_mdio_detach(device_t dev) 176441d6780SZbigniew Bodek { 177441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 178441d6780SZbigniew Bodek 179441d6780SZbigniew Bodek sc = device_get_softc(dev); 180441d6780SZbigniew Bodek 181441d6780SZbigniew Bodek if (sc->reg_base != NULL) { 182441d6780SZbigniew Bodek bus_release_resource(dev, SYS_RES_MEMORY, REG_BASE_RID, 183441d6780SZbigniew Bodek sc->reg_base); 184441d6780SZbigniew Bodek } 185441d6780SZbigniew Bodek 186441d6780SZbigniew Bodek return (0); 187441d6780SZbigniew Bodek } 188441d6780SZbigniew Bodek 189441d6780SZbigniew Bodek static __inline void 190441d6780SZbigniew Bodek thunder_mdio_set_mode(struct thunder_mdio_softc *sc, 191441d6780SZbigniew Bodek enum thunder_mdio_mode mode) 192441d6780SZbigniew Bodek { 193441d6780SZbigniew Bodek uint64_t smi_clk; 194441d6780SZbigniew Bodek 195441d6780SZbigniew Bodek if (sc->mode == mode) 196441d6780SZbigniew Bodek return; 197441d6780SZbigniew Bodek 198441d6780SZbigniew Bodek /* Set mode, IEEE CLAUSE 22 or IEEE CAUSE 45 */ 199441d6780SZbigniew Bodek smi_clk = mdio_reg_read(sc, SMI_CLK); 200441d6780SZbigniew Bodek if (mode == MODE_IEEE_C22) 201441d6780SZbigniew Bodek smi_clk &= ~SMI_CLK_MODE; 202441d6780SZbigniew Bodek else 203441d6780SZbigniew Bodek smi_clk |= SMI_CLK_MODE; 204441d6780SZbigniew Bodek /* Enable sending 32 bit preable on SMI transactions */ 205441d6780SZbigniew Bodek smi_clk |= SMI_CLK_PREAMBLE; 206fafb1c57SGordon Bergling /* Saved settings */ 207441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CLK, smi_clk); 208441d6780SZbigniew Bodek sc->mode = mode; 209441d6780SZbigniew Bodek } 210441d6780SZbigniew Bodek 211441d6780SZbigniew Bodek static int 212441d6780SZbigniew Bodek thunder_mdio_c45_addr(struct thunder_mdio_softc *sc, int phy, int reg) 213441d6780SZbigniew Bodek { 214441d6780SZbigniew Bodek uint64_t smi_cmd, smi_wr_dat; 215441d6780SZbigniew Bodek ssize_t timeout; 216441d6780SZbigniew Bodek 217441d6780SZbigniew Bodek thunder_mdio_set_mode(sc, MODE_IEEE_C45); 218441d6780SZbigniew Bodek 219441d6780SZbigniew Bodek /* Prepare data for transmission */ 220441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_WR_DAT, reg & SMI_WR_DAT_DAT_MASK); 221441d6780SZbigniew Bodek /* 222441d6780SZbigniew Bodek * Assemble command 223441d6780SZbigniew Bodek */ 224441d6780SZbigniew Bodek smi_cmd = 0; 225441d6780SZbigniew Bodek /* Set opcode */ 226441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C45_WRITE; 227441d6780SZbigniew Bodek 228441d6780SZbigniew Bodek /* Set PHY address */ 229441d6780SZbigniew Bodek smi_cmd |= ((phy << SMI_CMD_PHY_ADR_SHIFT) & SMI_CMD_PHY_ADR_MASK); 230441d6780SZbigniew Bodek /* Set PHY register offset */ 231441d6780SZbigniew Bodek smi_cmd |= ((reg << SMI_CMD_PHY_REG_ADR_SHIFT) & 232441d6780SZbigniew Bodek SMI_CMD_PHY_REG_ADR_MASK); 233441d6780SZbigniew Bodek 234441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CMD, smi_cmd); 235441d6780SZbigniew Bodek for (timeout = 1000; timeout > 0; timeout--) { 236441d6780SZbigniew Bodek smi_wr_dat = mdio_reg_read(sc, SMI_WR_DAT); 237441d6780SZbigniew Bodek if (smi_wr_dat & SMI_WR_DAT_PENDING) 238441d6780SZbigniew Bodek DELAY(1000); 239441d6780SZbigniew Bodek else 240441d6780SZbigniew Bodek break; 241441d6780SZbigniew Bodek } 242441d6780SZbigniew Bodek 243441d6780SZbigniew Bodek if (timeout <= 0) 244441d6780SZbigniew Bodek return (EIO); 245441d6780SZbigniew Bodek else { 246441d6780SZbigniew Bodek /* Return 0 on success */ 247441d6780SZbigniew Bodek return (0); 248441d6780SZbigniew Bodek } 249441d6780SZbigniew Bodek } 250441d6780SZbigniew Bodek 251441d6780SZbigniew Bodek static int 252441d6780SZbigniew Bodek thunder_mdio_read(device_t dev, int phy, int reg) 253441d6780SZbigniew Bodek { 254441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 255441d6780SZbigniew Bodek uint64_t smi_cmd, smi_rd_dat; 256441d6780SZbigniew Bodek ssize_t timeout; 257441d6780SZbigniew Bodek int err; 258441d6780SZbigniew Bodek 259441d6780SZbigniew Bodek sc = device_get_softc(dev); 260441d6780SZbigniew Bodek 261441d6780SZbigniew Bodek /* XXX Always C22 - for <= 1Gbps only */ 262441d6780SZbigniew Bodek thunder_mdio_set_mode(sc, MODE_IEEE_C22); 263441d6780SZbigniew Bodek 264441d6780SZbigniew Bodek /* 265441d6780SZbigniew Bodek * Assemble command 266441d6780SZbigniew Bodek */ 267441d6780SZbigniew Bodek smi_cmd = 0; 268441d6780SZbigniew Bodek /* Set opcode */ 269441d6780SZbigniew Bodek if (sc->mode == MODE_IEEE_C22) 270441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C22_READ; 271441d6780SZbigniew Bodek else { 272441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C45_READ; 273441d6780SZbigniew Bodek err = thunder_mdio_c45_addr(sc, phy, reg); 274441d6780SZbigniew Bodek if (err != 0) 275441d6780SZbigniew Bodek return (err); 276441d6780SZbigniew Bodek 277441d6780SZbigniew Bodek reg = (reg >> 16) & 0x1F; 278441d6780SZbigniew Bodek } 279441d6780SZbigniew Bodek 280441d6780SZbigniew Bodek /* Set PHY address */ 281441d6780SZbigniew Bodek smi_cmd |= ((phy << SMI_CMD_PHY_ADR_SHIFT) & SMI_CMD_PHY_ADR_MASK); 282441d6780SZbigniew Bodek /* Set PHY register offset */ 283441d6780SZbigniew Bodek smi_cmd |= ((reg << SMI_CMD_PHY_REG_ADR_SHIFT) & 284441d6780SZbigniew Bodek SMI_CMD_PHY_REG_ADR_MASK); 285441d6780SZbigniew Bodek 286441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CMD, smi_cmd); 287441d6780SZbigniew Bodek for (timeout = 1000; timeout > 0; timeout--) { 288441d6780SZbigniew Bodek smi_rd_dat = mdio_reg_read(sc, SMI_RD_DAT); 289441d6780SZbigniew Bodek if (smi_rd_dat & SMI_RD_DAT_PENDING) 290441d6780SZbigniew Bodek DELAY(1000); 291441d6780SZbigniew Bodek else 292441d6780SZbigniew Bodek break; 293441d6780SZbigniew Bodek } 294441d6780SZbigniew Bodek 295441d6780SZbigniew Bodek if (smi_rd_dat & SMI_RD_DAT_VAL) 296441d6780SZbigniew Bodek return (smi_rd_dat & SMI_RD_DAT_DAT_MASK); 297441d6780SZbigniew Bodek else { 298441d6780SZbigniew Bodek /* Return 0 on error */ 299441d6780SZbigniew Bodek return (0); 300441d6780SZbigniew Bodek } 301441d6780SZbigniew Bodek } 302441d6780SZbigniew Bodek 303441d6780SZbigniew Bodek static int 304441d6780SZbigniew Bodek thunder_mdio_write(device_t dev, int phy, int reg, int data) 305441d6780SZbigniew Bodek { 306441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 307441d6780SZbigniew Bodek uint64_t smi_cmd, smi_wr_dat; 308441d6780SZbigniew Bodek ssize_t timeout; 309441d6780SZbigniew Bodek 310441d6780SZbigniew Bodek sc = device_get_softc(dev); 311441d6780SZbigniew Bodek 312441d6780SZbigniew Bodek /* XXX Always C22 - for <= 1Gbps only */ 313441d6780SZbigniew Bodek thunder_mdio_set_mode(sc, MODE_IEEE_C22); 314441d6780SZbigniew Bodek 315441d6780SZbigniew Bodek /* Prepare data for transmission */ 316441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_WR_DAT, data & SMI_WR_DAT_DAT_MASK); 317441d6780SZbigniew Bodek /* 318441d6780SZbigniew Bodek * Assemble command 319441d6780SZbigniew Bodek */ 320441d6780SZbigniew Bodek smi_cmd = 0; 321441d6780SZbigniew Bodek /* Set opcode */ 322441d6780SZbigniew Bodek if (sc->mode == MODE_IEEE_C22) 323441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C22_WRITE; 324441d6780SZbigniew Bodek else 325441d6780SZbigniew Bodek smi_cmd |= SMI_CMD_PHY_OP_C45_WRITE; 326441d6780SZbigniew Bodek 327441d6780SZbigniew Bodek /* Set PHY address */ 328441d6780SZbigniew Bodek smi_cmd |= ((phy << SMI_CMD_PHY_ADR_SHIFT) & SMI_CMD_PHY_ADR_MASK); 329441d6780SZbigniew Bodek /* Set PHY register offset */ 330441d6780SZbigniew Bodek smi_cmd |= ((reg << SMI_CMD_PHY_REG_ADR_SHIFT) & 331441d6780SZbigniew Bodek SMI_CMD_PHY_REG_ADR_MASK); 332441d6780SZbigniew Bodek 333441d6780SZbigniew Bodek mdio_reg_write(sc, SMI_CMD, smi_cmd); 334441d6780SZbigniew Bodek for (timeout = 1000; timeout > 0; timeout--) { 335441d6780SZbigniew Bodek smi_wr_dat = mdio_reg_read(sc, SMI_WR_DAT); 336441d6780SZbigniew Bodek if (smi_wr_dat & SMI_WR_DAT_PENDING) 337441d6780SZbigniew Bodek DELAY(1000); 338441d6780SZbigniew Bodek else 339441d6780SZbigniew Bodek break; 340441d6780SZbigniew Bodek } 341441d6780SZbigniew Bodek 342441d6780SZbigniew Bodek if (timeout <= 0) 343441d6780SZbigniew Bodek return (EIO); 344441d6780SZbigniew Bodek else { 345441d6780SZbigniew Bodek /* Return 0 on success */ 346441d6780SZbigniew Bodek return (0); 347441d6780SZbigniew Bodek } 348441d6780SZbigniew Bodek } 349441d6780SZbigniew Bodek 350441d6780SZbigniew Bodek static int 351b9545c57SJustin Hibbits thunder_ifmedia_change_stub(if_t ifp __unused) 352441d6780SZbigniew Bodek { 353441d6780SZbigniew Bodek /* Will never be called by if_media */ 354441d6780SZbigniew Bodek return (0); 355441d6780SZbigniew Bodek } 356441d6780SZbigniew Bodek 357441d6780SZbigniew Bodek static void 358b9545c57SJustin Hibbits thunder_ifmedia_status_stub(if_t ifp __unused, struct ifmediareq 359441d6780SZbigniew Bodek *ifmr __unused) 360441d6780SZbigniew Bodek { 361441d6780SZbigniew Bodek /* Will never be called by if_media */ 362441d6780SZbigniew Bodek } 363441d6780SZbigniew Bodek 364441d6780SZbigniew Bodek static __inline struct phy_desc * 365441d6780SZbigniew Bodek get_phy_desc(struct thunder_mdio_softc *sc, int lmacid) 366441d6780SZbigniew Bodek { 367441d6780SZbigniew Bodek struct phy_desc *pd = NULL; 368441d6780SZbigniew Bodek 369441d6780SZbigniew Bodek MDIO_LOCK_ASSERT(sc); 370441d6780SZbigniew Bodek TAILQ_FOREACH(pd, &sc->phy_desc_head, phy_desc_list) { 371441d6780SZbigniew Bodek if (pd->lmacid == lmacid) 372441d6780SZbigniew Bodek break; 373441d6780SZbigniew Bodek } 374441d6780SZbigniew Bodek 375441d6780SZbigniew Bodek return (pd); 376441d6780SZbigniew Bodek } 377441d6780SZbigniew Bodek static int 378441d6780SZbigniew Bodek thunder_mdio_media_status(device_t dev, int lmacid, int *link, int *duplex, 379441d6780SZbigniew Bodek int *speed) 380441d6780SZbigniew Bodek { 381441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 382441d6780SZbigniew Bodek struct mii_data *mii_sc; 383441d6780SZbigniew Bodek struct phy_desc *pd; 384441d6780SZbigniew Bodek 385441d6780SZbigniew Bodek sc = device_get_softc(dev); 386441d6780SZbigniew Bodek 387441d6780SZbigniew Bodek MDIO_LOCK(sc); 388441d6780SZbigniew Bodek pd = get_phy_desc(sc, lmacid); 389441d6780SZbigniew Bodek if (pd == NULL) { 390441d6780SZbigniew Bodek /* Panic when invariants are enabled, fail otherwise. */ 391441d6780SZbigniew Bodek KASSERT(0, ("%s: no PHY descriptor for LMAC%d", 392441d6780SZbigniew Bodek __func__, lmacid)); 393441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 394441d6780SZbigniew Bodek return (ENXIO); 395441d6780SZbigniew Bodek } 396441d6780SZbigniew Bodek mii_sc = device_get_softc(pd->miibus); 397441d6780SZbigniew Bodek 398441d6780SZbigniew Bodek mii_tick(mii_sc); 399441d6780SZbigniew Bodek if ((mii_sc->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 400441d6780SZbigniew Bodek (IFM_ACTIVE | IFM_AVALID)) { 401441d6780SZbigniew Bodek /* Link is up */ 402441d6780SZbigniew Bodek *link = 1; 403441d6780SZbigniew Bodek } else 404441d6780SZbigniew Bodek *link = 0; 405441d6780SZbigniew Bodek 406441d6780SZbigniew Bodek switch (IFM_SUBTYPE(mii_sc->mii_media_active)) { 407441d6780SZbigniew Bodek case IFM_10_T: 408441d6780SZbigniew Bodek *speed = 10; 409441d6780SZbigniew Bodek break; 410441d6780SZbigniew Bodek case IFM_100_TX: 411441d6780SZbigniew Bodek *speed = 100; 412441d6780SZbigniew Bodek break; 413441d6780SZbigniew Bodek case IFM_1000_T: 414441d6780SZbigniew Bodek *speed = 1000; 415441d6780SZbigniew Bodek break; 416441d6780SZbigniew Bodek default: 417441d6780SZbigniew Bodek /* IFM_NONE */ 418441d6780SZbigniew Bodek *speed = 0; 419441d6780SZbigniew Bodek } 420441d6780SZbigniew Bodek 421441d6780SZbigniew Bodek if ((IFM_OPTIONS(mii_sc->mii_media_active) & IFM_FDX) != 0) 422441d6780SZbigniew Bodek *duplex = 1; 423441d6780SZbigniew Bodek else 424441d6780SZbigniew Bodek *duplex = 0; 425441d6780SZbigniew Bodek 426441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 427441d6780SZbigniew Bodek 428441d6780SZbigniew Bodek return (0); 429441d6780SZbigniew Bodek } 430441d6780SZbigniew Bodek 431441d6780SZbigniew Bodek static int 432441d6780SZbigniew Bodek thunder_mdio_media_change(device_t dev, int lmacid, int link, int duplex, 433441d6780SZbigniew Bodek int speed) 434441d6780SZbigniew Bodek { 435441d6780SZbigniew Bodek 436441d6780SZbigniew Bodek return (EIO); 437441d6780SZbigniew Bodek } 438441d6780SZbigniew Bodek 439441d6780SZbigniew Bodek static int 440441d6780SZbigniew Bodek thunder_mdio_phy_connect(device_t dev, int lmacid, int phy) 441441d6780SZbigniew Bodek { 442441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 443441d6780SZbigniew Bodek struct phy_desc *pd; 444441d6780SZbigniew Bodek int err; 445441d6780SZbigniew Bodek 446441d6780SZbigniew Bodek sc = device_get_softc(dev); 447441d6780SZbigniew Bodek 448441d6780SZbigniew Bodek MDIO_LOCK(sc); 449441d6780SZbigniew Bodek pd = get_phy_desc(sc, lmacid); 450441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 451441d6780SZbigniew Bodek if (pd == NULL) { 452441d6780SZbigniew Bodek pd = malloc(sizeof(*pd), M_THUNDER_MDIO, (M_NOWAIT | M_ZERO)); 453441d6780SZbigniew Bodek if (pd == NULL) 454441d6780SZbigniew Bodek return (ENOMEM); 455441d6780SZbigniew Bodek pd->ifp = if_alloc(IFT_ETHER); 456441d6780SZbigniew Bodek pd->lmacid = lmacid; 457441d6780SZbigniew Bodek } 458441d6780SZbigniew Bodek 459441d6780SZbigniew Bodek err = mii_attach(dev, &pd->miibus, pd->ifp, 460441d6780SZbigniew Bodek thunder_ifmedia_change_stub, thunder_ifmedia_status_stub, 461441d6780SZbigniew Bodek BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 462441d6780SZbigniew Bodek 463441d6780SZbigniew Bodek if (err != 0) { 464441d6780SZbigniew Bodek device_printf(dev, "Could not attach PHY%d\n", phy); 465441d6780SZbigniew Bodek if_free(pd->ifp); 466441d6780SZbigniew Bodek free(pd, M_THUNDER_MDIO); 467441d6780SZbigniew Bodek return (ENXIO); 468441d6780SZbigniew Bodek } 469441d6780SZbigniew Bodek 470441d6780SZbigniew Bodek MDIO_LOCK(sc); 471441d6780SZbigniew Bodek TAILQ_INSERT_TAIL(&sc->phy_desc_head, pd, phy_desc_list); 472441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 473441d6780SZbigniew Bodek 474441d6780SZbigniew Bodek return (0); 475441d6780SZbigniew Bodek } 476441d6780SZbigniew Bodek 477441d6780SZbigniew Bodek static int 478441d6780SZbigniew Bodek thunder_mdio_phy_disconnect(device_t dev, int lmacid, int phy) 479441d6780SZbigniew Bodek { 480441d6780SZbigniew Bodek struct thunder_mdio_softc *sc; 481441d6780SZbigniew Bodek struct phy_desc *pd; 482441d6780SZbigniew Bodek 483441d6780SZbigniew Bodek sc = device_get_softc(dev); 484441d6780SZbigniew Bodek MDIO_LOCK(sc); 485441d6780SZbigniew Bodek 486441d6780SZbigniew Bodek pd = get_phy_desc(sc, lmacid); 487441d6780SZbigniew Bodek if (pd == NULL) { 488441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 489441d6780SZbigniew Bodek return (EINVAL); 490441d6780SZbigniew Bodek } 491441d6780SZbigniew Bodek 492441d6780SZbigniew Bodek /* Remove this PHY descriptor from the list */ 493441d6780SZbigniew Bodek TAILQ_REMOVE(&sc->phy_desc_head, pd, phy_desc_list); 494441d6780SZbigniew Bodek 495441d6780SZbigniew Bodek /* Detach miibus */ 496441d6780SZbigniew Bodek bus_generic_detach(dev); 497441d6780SZbigniew Bodek /* Free fake ifnet */ 498441d6780SZbigniew Bodek if_free(pd->ifp); 499441d6780SZbigniew Bodek /* Free memory under phy descriptor */ 500441d6780SZbigniew Bodek free(pd, M_THUNDER_MDIO); 501441d6780SZbigniew Bodek MDIO_UNLOCK(sc); 502441d6780SZbigniew Bodek 503441d6780SZbigniew Bodek return (0); 504441d6780SZbigniew Bodek } 505