diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2006-08-28 01:54:25 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2006-08-28 01:54:25 +0000 |
commit | f28d443b8308de361467163828fbc840ee0d5c06 (patch) | |
tree | 3ca97d49a02868698f0c701563a331c227b1b1c1 /sys/dev/mii/rgephy.c | |
parent | b0901da970d1df2483f5b089537ebd118aeeffcf (diff) |
Fix manual media types by always leaving the PHY in autoneg mode but adjusting
the ANAR as appropriate.
Derived from a diff for FreeBSD; same technique used by the Linux r8169 driver.
Diffstat (limited to 'sys/dev/mii/rgephy.c')
-rw-r--r-- | sys/dev/mii/rgephy.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c index c6a317c41fa..5e2b4780409 100644 --- a/sys/dev/mii/rgephy.c +++ b/sys/dev/mii/rgephy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rgephy.c,v 1.14 2006/08/11 19:50:48 brad Exp $ */ +/* $OpenBSD: rgephy.c,v 1.15 2006/08/28 01:54:24 brad Exp $ */ /* * Copyright (c) 2003 * Bill Paul <wpaul@windriver.com>. All rights reserved. @@ -147,7 +147,7 @@ int rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg, speed, gig; + int anar, reg, speed, gig = 0; switch (cmd) { case MII_POLLSTAT: @@ -177,6 +177,10 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) PHY_RESET(sc); /* XXX hardware bug work-around */ + anar = PHY_READ(sc, RGEPHY_MII_ANAR); + anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | + RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10); + switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: #ifdef foo @@ -190,32 +194,30 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case IFM_1000_T: speed = RGEPHY_S1000; + anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | + RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10; goto setit; case IFM_100_TX: speed = RGEPHY_S100; + anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX; goto setit; case IFM_10_T: speed = RGEPHY_S10; + anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10; setit: rgephy_loop(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { speed |= RGEPHY_BMCR_FDX; - gig = RGEPHY_1000CTL_AFD; + if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) + gig = RGEPHY_1000CTL_AFD; + anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10); } else { - gig = RGEPHY_1000CTL_AHD; + if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) + gig = RGEPHY_1000CTL_AHD; + anar &= + ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD); } - PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0); - PHY_WRITE(sc, RGEPHY_MII_BMCR, speed); - PHY_WRITE(sc, RGEPHY_MII_ANAR, RGEPHY_SEL_TYPE); - - if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) - break; - - PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); - PHY_WRITE(sc, RGEPHY_MII_BMCR, - speed|RGEPHY_BMCR_AUTOEN|RGEPHY_BMCR_STARTNEG); - /* * When setting the link manually, one side must * be the master and the other the slave. However @@ -224,13 +226,16 @@ setit: * flags. If LINK0 is set, we program the PHY to * be a master, otherwise it's a slave. */ - if ((mii->mii_ifp->if_flags & IFF_LINK0)) { - PHY_WRITE(sc, RGEPHY_MII_1000CTL, - gig|RGEPHY_1000CTL_MSE|RGEPHY_1000CTL_MSC); - } else { - PHY_WRITE(sc, RGEPHY_MII_1000CTL, - gig|RGEPHY_1000CTL_MSE); + if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { + gig |= RGEPHY_1000CTL_MSE; + if (mii->mii_ifp->if_flags & IFF_LINK0) + gig |= RGEPHY_1000CTL_MSC; } + + PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); + PHY_WRITE(sc, RGEPHY_MII_BMCR, speed | + RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); + PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); break; #ifdef foo case IFM_NONE: @@ -292,10 +297,12 @@ setit: */ if (sc->mii_media_active != mii->mii_media_active || sc->mii_media_status != mii->mii_media_status || - cmd == MII_MEDIACHG) { + cmd == MII_MEDIACHG) rgephy_load_dspcode(sc); - } + + /* Callback if something changed. */ mii_phy_update(sc, cmd); + return (0); } |