1112a855dSMarius Strobl /*- 2112a855dSMarius Strobl * Copyright (c) 2001 Jonathan Lemon 3112a855dSMarius Strobl * All rights reserved. 4112a855dSMarius Strobl * 5112a855dSMarius Strobl * Redistribution and use in source and binary forms, with or without 6112a855dSMarius Strobl * modification, are permitted provided that the following conditions 7112a855dSMarius Strobl * are met: 8112a855dSMarius Strobl * 1. Redistributions of source code must retain the above copyright 9112a855dSMarius Strobl * notice, this list of conditions and the following disclaimer. 10112a855dSMarius Strobl * 2. Redistributions in binary form must reproduce the above copyright 11112a855dSMarius Strobl * notice, this list of conditions and the following disclaimer in the 12112a855dSMarius Strobl * documentation and/or other materials provided with the distribution. 13112a855dSMarius Strobl * 3. Neither the name of the author nor the names of any co-contributors 14112a855dSMarius Strobl * may be used to endorse or promote products derived from this software 15112a855dSMarius Strobl * without specific prior written permission. 16112a855dSMarius Strobl * 17112a855dSMarius Strobl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18112a855dSMarius Strobl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19112a855dSMarius Strobl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20112a855dSMarius Strobl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21112a855dSMarius Strobl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22112a855dSMarius Strobl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23112a855dSMarius Strobl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24112a855dSMarius Strobl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25112a855dSMarius Strobl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26112a855dSMarius Strobl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27112a855dSMarius Strobl * SUCH DAMAGE. 28112a855dSMarius Strobl * 29112a855dSMarius Strobl */ 30112a855dSMarius Strobl 31112a855dSMarius Strobl #include <sys/cdefs.h> 32112a855dSMarius Strobl __FBSDID("$FreeBSD$"); 33112a855dSMarius Strobl 34112a855dSMarius Strobl /* 35112a855dSMarius Strobl * driver for Intel 82553 and 82555 PHYs 36112a855dSMarius Strobl */ 37112a855dSMarius Strobl 38112a855dSMarius Strobl #include <sys/param.h> 39112a855dSMarius Strobl #include <sys/systm.h> 40112a855dSMarius Strobl #include <sys/kernel.h> 41112a855dSMarius Strobl #include <sys/module.h> 42112a855dSMarius Strobl #include <sys/socket.h> 43112a855dSMarius Strobl #include <sys/bus.h> 44112a855dSMarius Strobl 45112a855dSMarius Strobl #include <net/if.h> 4676039bc8SGleb Smirnoff #include <net/if_var.h> 47112a855dSMarius Strobl #include <net/if_media.h> 48112a855dSMarius Strobl 49112a855dSMarius Strobl #include <dev/mii/mii.h> 50112a855dSMarius Strobl #include <dev/mii/miivar.h> 51112a855dSMarius Strobl #include "miidevs.h" 52112a855dSMarius Strobl 53112a855dSMarius Strobl #include <dev/fxp/inphyreg.h> 54112a855dSMarius Strobl 55112a855dSMarius Strobl #include "miibus_if.h" 56112a855dSMarius Strobl 57112a855dSMarius Strobl static int inphy_probe(device_t dev); 58112a855dSMarius Strobl static int inphy_attach(device_t dev); 59112a855dSMarius Strobl 60112a855dSMarius Strobl static device_method_t inphy_methods[] = { 61112a855dSMarius Strobl /* device interface */ 62112a855dSMarius Strobl DEVMETHOD(device_probe, inphy_probe), 63112a855dSMarius Strobl DEVMETHOD(device_attach, inphy_attach), 64112a855dSMarius Strobl DEVMETHOD(device_detach, mii_phy_detach), 65112a855dSMarius Strobl DEVMETHOD(device_shutdown, bus_generic_shutdown), 66112a855dSMarius Strobl { 0, 0 } 67112a855dSMarius Strobl }; 68112a855dSMarius Strobl 69112a855dSMarius Strobl static devclass_t inphy_devclass; 70112a855dSMarius Strobl 71112a855dSMarius Strobl static driver_t inphy_driver = { 72112a855dSMarius Strobl "inphy", 73112a855dSMarius Strobl inphy_methods, 74112a855dSMarius Strobl sizeof(struct mii_softc) 75112a855dSMarius Strobl }; 76112a855dSMarius Strobl 77112a855dSMarius Strobl DRIVER_MODULE(inphy, miibus, inphy_driver, inphy_devclass, 0, 0); 78112a855dSMarius Strobl 79112a855dSMarius Strobl static int inphy_service(struct mii_softc *, struct mii_data *, int); 80112a855dSMarius Strobl static void inphy_status(struct mii_softc *); 81112a855dSMarius Strobl static void inphy_reset(struct mii_softc *); 82112a855dSMarius Strobl 83112a855dSMarius Strobl static const struct mii_phydesc inphys[] = { 84112a855dSMarius Strobl MII_PHY_DESC(xxINTEL, I82553), 85112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82553), 86112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82555), 87112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82562EM), 88112a855dSMarius Strobl MII_PHY_DESC(yyINTEL, I82562ET), 89112a855dSMarius Strobl MII_PHY_END 90112a855dSMarius Strobl }; 91112a855dSMarius Strobl 92112a855dSMarius Strobl static const struct mii_phy_funcs inphy_funcs = { 93112a855dSMarius Strobl inphy_service, 94112a855dSMarius Strobl inphy_status, 95112a855dSMarius Strobl inphy_reset 96112a855dSMarius Strobl }; 97112a855dSMarius Strobl 98112a855dSMarius Strobl static int 99112a855dSMarius Strobl inphy_probe(device_t dev) 100112a855dSMarius Strobl { 101112a855dSMarius Strobl 102112a855dSMarius Strobl return (mii_phy_dev_probe(dev, inphys, BUS_PROBE_DEFAULT)); 103112a855dSMarius Strobl } 104112a855dSMarius Strobl 105112a855dSMarius Strobl static int 106112a855dSMarius Strobl inphy_attach(device_t dev) 107112a855dSMarius Strobl { 108112a855dSMarius Strobl 109112a855dSMarius Strobl mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &inphy_funcs, 1); 110112a855dSMarius Strobl return (0); 111112a855dSMarius Strobl } 112112a855dSMarius Strobl 113112a855dSMarius Strobl static int 114112a855dSMarius Strobl inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 115112a855dSMarius Strobl { 116112a855dSMarius Strobl 117112a855dSMarius Strobl switch (cmd) { 118112a855dSMarius Strobl case MII_POLLSTAT: 119112a855dSMarius Strobl break; 120112a855dSMarius Strobl 121112a855dSMarius Strobl case MII_MEDIACHG: 122112a855dSMarius Strobl /* 123112a855dSMarius Strobl * If the interface is not up, don't do anything. 124112a855dSMarius Strobl */ 125*62d76917SMarcel Moolenaar if ((if_getflags(mii->mii_ifp) & IFF_UP) == 0) 126112a855dSMarius Strobl break; 127112a855dSMarius Strobl 128112a855dSMarius Strobl mii_phy_setmedia(sc); 129112a855dSMarius Strobl break; 130112a855dSMarius Strobl 131112a855dSMarius Strobl case MII_TICK: 132112a855dSMarius Strobl if (mii_phy_tick(sc) == EJUSTRETURN) 133112a855dSMarius Strobl return (0); 134112a855dSMarius Strobl break; 135112a855dSMarius Strobl } 136112a855dSMarius Strobl 137112a855dSMarius Strobl /* Update the media status. */ 138112a855dSMarius Strobl PHY_STATUS(sc); 139112a855dSMarius Strobl 140112a855dSMarius Strobl /* Callback if something changed. */ 141112a855dSMarius Strobl mii_phy_update(sc, cmd); 142112a855dSMarius Strobl return (0); 143112a855dSMarius Strobl } 144112a855dSMarius Strobl 145112a855dSMarius Strobl static void 146112a855dSMarius Strobl inphy_status(struct mii_softc *sc) 147112a855dSMarius Strobl { 148112a855dSMarius Strobl struct mii_data *mii = sc->mii_pdata; 149112a855dSMarius Strobl struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 150112a855dSMarius Strobl int bmsr, bmcr, scr; 151112a855dSMarius Strobl 152112a855dSMarius Strobl mii->mii_media_status = IFM_AVALID; 153112a855dSMarius Strobl mii->mii_media_active = IFM_ETHER; 154112a855dSMarius Strobl 155112a855dSMarius Strobl bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 156112a855dSMarius Strobl if (bmsr & BMSR_LINK) 157112a855dSMarius Strobl mii->mii_media_status |= IFM_ACTIVE; 158112a855dSMarius Strobl 159112a855dSMarius Strobl bmcr = PHY_READ(sc, MII_BMCR); 160112a855dSMarius Strobl if (bmcr & BMCR_ISO) { 161112a855dSMarius Strobl mii->mii_media_active |= IFM_NONE; 162112a855dSMarius Strobl mii->mii_media_status = 0; 163112a855dSMarius Strobl return; 164112a855dSMarius Strobl } 165112a855dSMarius Strobl 166112a855dSMarius Strobl if (bmcr & BMCR_LOOP) 167112a855dSMarius Strobl mii->mii_media_active |= IFM_LOOP; 168112a855dSMarius Strobl 169112a855dSMarius Strobl if (bmcr & BMCR_AUTOEN) { 170112a855dSMarius Strobl if ((bmsr & BMSR_ACOMP) == 0) { 171112a855dSMarius Strobl mii->mii_media_active |= IFM_NONE; 172112a855dSMarius Strobl return; 173112a855dSMarius Strobl } 174112a855dSMarius Strobl 175112a855dSMarius Strobl scr = PHY_READ(sc, MII_INPHY_SCR); 176112a855dSMarius Strobl if (scr & SCR_S100) 177112a855dSMarius Strobl mii->mii_media_active |= IFM_100_TX; 178112a855dSMarius Strobl else 179112a855dSMarius Strobl mii->mii_media_active |= IFM_10_T; 180112a855dSMarius Strobl if (scr & SCR_FDX) 181112a855dSMarius Strobl mii->mii_media_active |= 182112a855dSMarius Strobl IFM_FDX | mii_phy_flowstatus(sc); 183112a855dSMarius Strobl else 184112a855dSMarius Strobl mii->mii_media_active |= IFM_HDX; 185112a855dSMarius Strobl } else 186112a855dSMarius Strobl mii->mii_media_active = ife->ifm_media; 187112a855dSMarius Strobl } 188112a855dSMarius Strobl 189112a855dSMarius Strobl static void 190112a855dSMarius Strobl inphy_reset(struct mii_softc *sc) 191112a855dSMarius Strobl { 192112a855dSMarius Strobl 193112a855dSMarius Strobl mii_phy_reset(sc); 194112a855dSMarius Strobl 195112a855dSMarius Strobl /* Ensure Bay flow control is disabled. */ 196112a855dSMarius Strobl PHY_WRITE(sc, MII_INPHY_SCR, 197112a855dSMarius Strobl PHY_READ(sc, MII_INPHY_SCR) & ~SCR_FLOWCTL); 198112a855dSMarius Strobl } 199