174131Sjlemon/*- 274131Sjlemon * Copyright (c) 2001 Jonathan Lemon 374131Sjlemon * All rights reserved. 474131Sjlemon * 574131Sjlemon * Redistribution and use in source and binary forms, with or without 674131Sjlemon * modification, are permitted provided that the following conditions 774131Sjlemon * are met: 874131Sjlemon * 1. Redistributions of source code must retain the above copyright 974131Sjlemon * notice, this list of conditions and the following disclaimer. 1074131Sjlemon * 2. Redistributions in binary form must reproduce the above copyright 1174131Sjlemon * notice, this list of conditions and the following disclaimer in the 1274131Sjlemon * documentation and/or other materials provided with the distribution. 1374131Sjlemon * 3. Neither the name of the author nor the names of any co-contributors 1474131Sjlemon * may be used to endorse or promote products derived from this software 1574131Sjlemon * without specific prior written permission. 1674131Sjlemon * 1774131Sjlemon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1874131Sjlemon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1974131Sjlemon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2074131Sjlemon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2174131Sjlemon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2274131Sjlemon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2374131Sjlemon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2474131Sjlemon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2574131Sjlemon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2674131Sjlemon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2774131Sjlemon * SUCH DAMAGE. 2874131Sjlemon * 2974131Sjlemon */ 3074131Sjlemon 31119418Sobrien#include <sys/cdefs.h> 32119418Sobrien__FBSDID("$FreeBSD$"); 33119418Sobrien 3474131Sjlemon/* 3574131Sjlemon * driver for Intel 82553 and 82555 PHYs 3674131Sjlemon */ 3774131Sjlemon 3874131Sjlemon#include <sys/param.h> 3974131Sjlemon#include <sys/systm.h> 4074131Sjlemon#include <sys/kernel.h> 41129876Sphk#include <sys/module.h> 4274131Sjlemon#include <sys/socket.h> 4374131Sjlemon#include <sys/bus.h> 4474131Sjlemon 4574131Sjlemon#include <net/if.h> 46257176Sglebius#include <net/if_var.h> 4774131Sjlemon#include <net/if_media.h> 4874131Sjlemon 4974131Sjlemon#include <dev/mii/mii.h> 5074131Sjlemon#include <dev/mii/miivar.h> 51109514Sobrien#include "miidevs.h" 5274131Sjlemon 53226154Smarius#include <dev/fxp/inphyreg.h> 5474131Sjlemon 5574131Sjlemon#include "miibus_if.h" 5674131Sjlemon 5774131Sjlemonstatic int inphy_probe(device_t dev); 5874131Sjlemonstatic int inphy_attach(device_t dev); 5974131Sjlemon 6074131Sjlemonstatic device_method_t inphy_methods[] = { 6174131Sjlemon /* device interface */ 6274131Sjlemon DEVMETHOD(device_probe, inphy_probe), 6374131Sjlemon DEVMETHOD(device_attach, inphy_attach), 6495722Sphk DEVMETHOD(device_detach, mii_phy_detach), 6574131Sjlemon DEVMETHOD(device_shutdown, bus_generic_shutdown), 6674131Sjlemon { 0, 0 } 6774131Sjlemon}; 6874131Sjlemon 6974131Sjlemonstatic devclass_t inphy_devclass; 7074131Sjlemon 7174131Sjlemonstatic driver_t inphy_driver = { 7274131Sjlemon "inphy", 7374131Sjlemon inphy_methods, 7474131Sjlemon sizeof(struct mii_softc) 7574131Sjlemon}; 7674131Sjlemon 7774131SjlemonDRIVER_MODULE(inphy, miibus, inphy_driver, inphy_devclass, 0, 0); 7874131Sjlemon 7984145Sjlemonstatic int inphy_service(struct mii_softc *, struct mii_data *, int); 8084145Sjlemonstatic void inphy_status(struct mii_softc *); 81215905Smariusstatic void inphy_reset(struct mii_softc *); 8274131Sjlemon 83164827Smariusstatic const struct mii_phydesc inphys[] = { 84221407Smarius MII_PHY_DESC(xxINTEL, I82553), 85221407Smarius MII_PHY_DESC(yyINTEL, I82553), 86221407Smarius MII_PHY_DESC(yyINTEL, I82555), 87221407Smarius MII_PHY_DESC(yyINTEL, I82562EM), 88221407Smarius MII_PHY_DESC(yyINTEL, I82562ET), 89164827Smarius MII_PHY_END 90164827Smarius}; 91164827Smarius 92221407Smariusstatic const struct mii_phy_funcs inphy_funcs = { 93221407Smarius inphy_service, 94221407Smarius inphy_status, 95221407Smarius inphy_reset 96221407Smarius}; 97221407Smarius 9874131Sjlemonstatic int 9974131Sjlemoninphy_probe(device_t dev) 10074131Sjlemon{ 10174131Sjlemon 102164827Smarius return (mii_phy_dev_probe(dev, inphys, BUS_PROBE_DEFAULT)); 10374131Sjlemon} 10474131Sjlemon 10574131Sjlemonstatic int 10674131Sjlemoninphy_attach(device_t dev) 10774131Sjlemon{ 10874131Sjlemon 109221407Smarius mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &inphy_funcs, 1); 11074131Sjlemon return (0); 11174131Sjlemon} 11274131Sjlemon 11374131Sjlemonstatic int 11474131Sjlemoninphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 11574131Sjlemon{ 11674131Sjlemon 11774131Sjlemon switch (cmd) { 11874131Sjlemon case MII_POLLSTAT: 11974131Sjlemon break; 12074131Sjlemon 12174131Sjlemon case MII_MEDIACHG: 12274131Sjlemon /* 12374131Sjlemon * If the interface is not up, don't do anything. 12474131Sjlemon */ 125266974Smarcel if ((if_getflags(mii->mii_ifp) & IFF_UP) == 0) 12674131Sjlemon break; 12774131Sjlemon 12895718Sphk mii_phy_setmedia(sc); 12974131Sjlemon break; 13074131Sjlemon 13174131Sjlemon case MII_TICK: 13284145Sjlemon if (mii_phy_tick(sc) == EJUSTRETURN) 13374131Sjlemon return (0); 13474131Sjlemon break; 13574131Sjlemon } 13674131Sjlemon 13774131Sjlemon /* Update the media status. */ 138221407Smarius PHY_STATUS(sc); 13974131Sjlemon 14074131Sjlemon /* Callback if something changed. */ 14184145Sjlemon mii_phy_update(sc, cmd); 14274131Sjlemon return (0); 14374131Sjlemon} 14474131Sjlemon 14584145Sjlemonstatic void 14674131Sjlemoninphy_status(struct mii_softc *sc) 14774131Sjlemon{ 14874131Sjlemon struct mii_data *mii = sc->mii_pdata; 14995718Sphk struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 15074131Sjlemon int bmsr, bmcr, scr; 15174131Sjlemon 15274131Sjlemon mii->mii_media_status = IFM_AVALID; 15374131Sjlemon mii->mii_media_active = IFM_ETHER; 15474131Sjlemon 15574131Sjlemon bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 15674131Sjlemon if (bmsr & BMSR_LINK) 15774131Sjlemon mii->mii_media_status |= IFM_ACTIVE; 15874131Sjlemon 15974131Sjlemon bmcr = PHY_READ(sc, MII_BMCR); 16074131Sjlemon if (bmcr & BMCR_ISO) { 16174131Sjlemon mii->mii_media_active |= IFM_NONE; 16274131Sjlemon mii->mii_media_status = 0; 16374131Sjlemon return; 16474131Sjlemon } 16574131Sjlemon 16674131Sjlemon if (bmcr & BMCR_LOOP) 16774131Sjlemon mii->mii_media_active |= IFM_LOOP; 16874131Sjlemon 16974131Sjlemon if (bmcr & BMCR_AUTOEN) { 17074131Sjlemon if ((bmsr & BMSR_ACOMP) == 0) { 17174131Sjlemon mii->mii_media_active |= IFM_NONE; 17274131Sjlemon return; 17374131Sjlemon } 17474131Sjlemon 17574131Sjlemon scr = PHY_READ(sc, MII_INPHY_SCR); 17674131Sjlemon if (scr & SCR_S100) 17774131Sjlemon mii->mii_media_active |= IFM_100_TX; 17874131Sjlemon else 17974131Sjlemon mii->mii_media_active |= IFM_10_T; 18074131Sjlemon if (scr & SCR_FDX) 181215716Smarius mii->mii_media_active |= 182215716Smarius IFM_FDX | mii_phy_flowstatus(sc); 183213384Smarius else 184213384Smarius mii->mii_media_active |= IFM_HDX; 18574131Sjlemon } else 18695718Sphk mii->mii_media_active = ife->ifm_media; 18774131Sjlemon} 188215905Smarius 189215905Smariusstatic void 190215905Smariusinphy_reset(struct mii_softc *sc) 191215905Smarius{ 192215905Smarius 193215905Smarius mii_phy_reset(sc); 194215905Smarius 195215905Smarius /* Ensure Bay flow control is disabled. */ 196215905Smarius PHY_WRITE(sc, MII_INPHY_SCR, 197215905Smarius PHY_READ(sc, MII_INPHY_SCR) & ~SCR_FLOWCTL); 198215905Smarius} 199