diff options
author | yongari <yongari@FreeBSD.org> | 2006-08-12 01:38:49 +0000 |
---|---|---|
committer | yongari <yongari@FreeBSD.org> | 2006-08-12 01:38:49 +0000 |
commit | 38e27927c91701f256654a22f2341b7197f00cee (patch) | |
tree | 779e0b364581a248fd01af3dac3a0fd515cecdfe | |
parent | 36aa6705100b69cc3c482c73a8b095f0c1e404d2 (diff) | |
download | FreeBSD-src-38e27927c91701f256654a22f2341b7197f00cee.zip FreeBSD-src-38e27927c91701f256654a22f2341b7197f00cee.tar.gz |
Due to the poor PHY documentation from RealTek I can't sure but I
think the RealTek PHY needs driver to set RGEPHY_BMCR_AUTOEN bit of
RGEPHY_MII_BMCR register and proper ANAR register setting for manual
media type selection.
This fixes long standing manual media type selection bug in rgephy(4).
Reported by: Jelte Jansen <jelte AT NLnetLabs DOT nl>
Tested by: Jelte Jansen <jelte AT NLnetLabs DOT nl>
-rw-r--r-- | sys/dev/mii/rgephy.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c index 3d36865..ffee835 100644 --- a/sys/dev/mii/rgephy.c +++ b/sys/dev/mii/rgephy.c @@ -166,7 +166,7 @@ static 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 reg, speed, gig, anar; switch (cmd) { case MII_POLLSTAT: @@ -196,6 +196,10 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) rgephy_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 @@ -212,28 +216,30 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) 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; + anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10); } else { 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) + if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) { + PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0); + PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); + PHY_WRITE(sc, RGEPHY_MII_BMCR, speed | + RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); break; - - PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); - PHY_WRITE(sc, RGEPHY_MII_BMCR, - speed|RGEPHY_BMCR_AUTOEN|RGEPHY_BMCR_STARTNEG); + } /* * When settning the link manually, one side must @@ -250,6 +256,8 @@ setit: PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig|RGEPHY_1000CTL_MSE); } + PHY_WRITE(sc, RGEPHY_MII_BMCR, speed | + RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); break; #ifdef foo case IFM_NONE: |