diff options
author | marius <marius@FreeBSD.org> | 2010-11-14 13:31:01 +0000 |
---|---|---|
committer | marius <marius@FreeBSD.org> | 2010-11-14 13:31:01 +0000 |
commit | dd93d3c0fda933782c0813b9cf0b13c8c5f80054 (patch) | |
tree | 07cbc77f29c3ac4577e10c4a098c52dd7a62a657 | |
parent | 278d761d736b370c6ad85e2ff6593c0f73d10c6f (diff) | |
download | FreeBSD-src-dd93d3c0fda933782c0813b9cf0b13c8c5f80054.zip FreeBSD-src-dd93d3c0fda933782c0813b9cf0b13c8c5f80054.tar.gz |
- Change these drivers to take advantage and use the generic IEEE 802.3
annex 31B full duplex flow control as well as the IFM_1000_T master
support committed in r215297. For atphy(4) and jmphy(4) this includes
changing these PHY drivers to no longer unconditionally advertise
support for flow control but only if the selected media has IFM_FLOW
set (or MIIF_FORCEPAUSE is set).
- Rename {atphy,jmphy}_auto() to {atphy,jmphy}_setmedia() as these handle
other media types as well.
Reviewed by: yongari (plus additional testing)
Obtained from: NetBSD (partially), OpenBSD (partially)
MFC after: 2 weeks
-rw-r--r-- | sys/dev/mii/atphy.c | 36 | ||||
-rw-r--r-- | sys/dev/mii/gentbi.c | 3 | ||||
-rw-r--r-- | sys/dev/mii/jmphy.c | 37 | ||||
-rw-r--r-- | sys/dev/mii/nsgphy.c | 3 | ||||
-rw-r--r-- | sys/dev/mii/rgephy.c | 78 |
5 files changed, 82 insertions, 75 deletions
diff --git a/sys/dev/mii/atphy.c b/sys/dev/mii/atphy.c index 41cd72c..cfabd21 100644 --- a/sys/dev/mii/atphy.c +++ b/sys/dev/mii/atphy.c @@ -82,7 +82,7 @@ static int atphy_service(struct mii_softc *, struct mii_data *, int); static void atphy_status(struct mii_softc *); static void atphy_reset(struct mii_softc *); static uint16_t atphy_anar(struct ifmedia_entry *); -static int atphy_auto(struct mii_softc *); +static int atphy_setmedia(struct mii_softc *, int); static const struct mii_phydesc atphys[] = { MII_PHY_DESC(ATHEROS, F1), @@ -158,7 +158,7 @@ atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { - atphy_auto(sc); + atphy_setmedia(sc, ife->ifm_media); break; } @@ -175,7 +175,7 @@ atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) /* * XXX * Due to an unknown reason powering down PHY resulted - * in unexpected results such as inaccessbility of + * in unexpected results such as inaccessibility of * hardware of freshly rebooted system. Disable * powering down PHY until I got more information for * Attansic/Atheros PHY hardwares. @@ -189,8 +189,9 @@ atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) anar = atphy_anar(ife); if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { bmcr |= BMCR_FDX; - /* Enable pause. */ - anar |= (3 << 10); + if (((ife->ifm_media & IFM_GMASK) & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= ANAR_PAUSE_TOWARDS; } if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | @@ -222,7 +223,7 @@ done: } /* - * check for link. + * Check for link. * Read the status register twice; BMSR_LINK is latch-low. */ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); @@ -238,7 +239,7 @@ done: return (0); sc->mii_ticks = 0; - atphy_auto(sc); + atphy_setmedia(sc, ife->ifm_media); break; } @@ -284,7 +285,7 @@ atphy_status(struct mii_softc *sc) case ATPHY_SSR_1000MBS: mii->mii_media_active |= IFM_1000_T; /* - * atphy(4) got a valid link so reset mii_ticks. + * atphy(4) has a valid link so reset mii_ticks. * Resetting mii_ticks is needed in order to * detect link loss after auto-negotiation. */ @@ -304,11 +305,13 @@ atphy_status(struct mii_softc *sc) } if ((ssr & ATPHY_SSR_DUPLEX) != 0) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; - /* XXX Master/Slave, Flow-control */ + if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && + (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; } static void @@ -336,7 +339,7 @@ atphy_reset(struct mii_softc *sc) PHY_WRITE(sc, ATPHY_SCR, reg); /* Workaround F1 bug to reset phy. */ - atphy_auto(sc); + atphy_setmedia(sc, sc->mii_pdata->mii_media.ifm_cur->ifm_media); for (i = 0; i < 1000; i++) { DELAY(1); @@ -378,12 +381,17 @@ atphy_anar(struct ifmedia_entry *ife) } static int -atphy_auto(struct mii_softc *sc) +atphy_setmedia(struct mii_softc *sc, int media) { uint16_t anar; - anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities); - PHY_WRITE(sc, MII_ANAR, anar | (3 << 10) | ANAR_CSMA); + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; + if (((IFM_SUBTYPE(media) == IFM_AUTO || + ((media & IFM_GMASK) & IFM_FDX) != 0) && + ((media & IFM_GMASK) & IFM_FLOW) != 0) || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= ANAR_PAUSE_TOWARDS; + PHY_WRITE(sc, MII_ANAR, anar); if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX); diff --git a/sys/dev/mii/gentbi.c b/sys/dev/mii/gentbi.c index ee08efe..f5d3a8b 100644 --- a/sys/dev/mii/gentbi.c +++ b/sys/dev/mii/gentbi.c @@ -267,7 +267,8 @@ gentbi_status(struct mii_softc *sc) anlpar = PHY_READ(sc, MII_ANLPAR); if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0 && (anlpar & ANLPAR_X_FD) != 0) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= + IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else diff --git a/sys/dev/mii/jmphy.c b/sys/dev/mii/jmphy.c index 0b04d80..00611c4 100644 --- a/sys/dev/mii/jmphy.c +++ b/sys/dev/mii/jmphy.c @@ -50,11 +50,11 @@ __FBSDID("$FreeBSD$"); #include "miibus_if.h" -static int jmphy_probe(device_t); -static int jmphy_attach(device_t); +static int jmphy_probe(device_t); +static int jmphy_attach(device_t); static void jmphy_reset(struct mii_softc *); static uint16_t jmphy_anar(struct ifmedia_entry *); -static int jmphy_auto(struct mii_softc *, struct ifmedia_entry *); +static int jmphy_setmedia(struct mii_softc *, struct ifmedia_entry *); struct jmphy_softc { struct mii_softc mii_sc; @@ -154,7 +154,7 @@ jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; - if (jmphy_auto(sc, ife) != EJUSTRETURN) + if (jmphy_setmedia(sc, ife) != EJUSTRETURN) return (EINVAL); break; @@ -186,7 +186,7 @@ jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) return (0); sc->mii_ticks = 0; - jmphy_auto(sc, ife); + (void)jmphy_setmedia(sc, ife); break; } @@ -251,16 +251,14 @@ jmphy_status(struct mii_softc *sc) } if ((ssr & JMPHY_SSR_DUPLEX) != 0) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; - /* XXX Flow-control. */ -#ifdef notyet + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { if ((PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } -#endif } static void @@ -309,7 +307,7 @@ jmphy_anar(struct ifmedia_entry *ife) } static int -jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife) +jmphy_setmedia(struct mii_softc *sc, struct ifmedia_entry *ife) { uint16_t anar, bmcr, gig; @@ -336,17 +334,18 @@ jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife) bmcr |= BMCR_LOOP; anar = jmphy_anar(ife); - /* XXX Always advertise pause capability. */ - anar |= (3 << 10); + if (((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || + (ife->ifm_media & IFM_FDX) != 0) && + (ife->ifm_media & IFM_FLOW) != 0) || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= ANAR_PAUSE_TOWARDS; if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) { -#ifdef notyet - struct mii_data *mii; - - mii = sc->mii_pdata; - if ((mii->mii_media.ifm_media & IFM_ETH_MASTER) != 0) - gig |= GTCR_MAN_MS | GTCR_MAN_ADV; -#endif + if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { + gig |= GTCR_MAN_MS; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gig |= GTCR_ADV_MS; + } PHY_WRITE(sc, MII_100T2CR, gig); } PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); diff --git a/sys/dev/mii/nsgphy.c b/sys/dev/mii/nsgphy.c index b3df8a2..7cdee42 100644 --- a/sys/dev/mii/nsgphy.c +++ b/sys/dev/mii/nsgphy.c @@ -246,7 +246,8 @@ nsgphy_status(struct mii_softc *sc) } if (physup & PHY_SUP_DUPLEX) - mii->mii_media_active |= IFM_FDX; + mii->mii_media_active |= + IFM_FDX | mii_phy_flowstatus(sc); else mii->mii_media_active |= IFM_HDX; } else diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c index d1e0e51..aa4bff7 100644 --- a/sys/dev/mii/rgephy.c +++ b/sys/dev/mii/rgephy.c @@ -89,7 +89,7 @@ DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0); static int rgephy_service(struct mii_softc *, struct mii_data *, int); static void rgephy_status(struct mii_softc *); -static int rgephy_mii_phy_auto(struct mii_softc *); +static int rgephy_mii_phy_auto(struct mii_softc *, int); static void rgephy_reset(struct mii_softc *); static void rgephy_loop(struct mii_softc *); static void rgephy_load_dspcode(struct mii_softc *); @@ -113,7 +113,6 @@ rgephy_attach(device_t dev) struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - const char *sep = ""; rsc = device_get_softc(dev); sc = &rsc->mii_sc; @@ -132,27 +131,21 @@ rgephy_attach(device_t dev) rsc->mii_revision = MII_REV(ma->mii_id2); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) -#define PRINT(s) printf("%s%s", sep, s); sep = ", " #if 0 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), MII_MEDIA_100_TX); #endif - sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; - sc->mii_capabilities &= ~BMSR_ANEG; + /* RTL8169S do not report auto-sense; add manually. */ + sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_ANEG) & + ma->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); - device_printf(dev, " "); mii_phy_add_media(sc); - /* RTL8169S do not report auto-sense; add manually. */ - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA); - sep = ", "; - PRINT("auto"); printf("\n"); #undef ADD -#undef PRINT rgephy_reset(sc); MIIBUS_MEDIAINIT(sc->mii_dev); @@ -182,7 +175,8 @@ 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 | + anar &= ~(RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP | + RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10); switch (IFM_SUBTYPE(ife->ifm_media)) { @@ -194,7 +188,7 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN) return (0); #endif - (void) rgephy_mii_phy_auto(sc); + (void)rgephy_mii_phy_auto(sc, ife->ifm_media); break; case IFM_1000_T: speed = RGEPHY_S1000; @@ -222,32 +216,26 @@ setit: 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); + RGEPHY_BMCR_AUTOEN | + RGEPHY_BMCR_STARTNEG); break; } - /* - * When setting the link manually, one side must - * be the master and the other the slave. However - * ifmedia doesn't give us a good way to specify - * this, so we fake it by using one of the LINK - * 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 ((ife->ifm_media & IFM_FLOW) != 0 || + (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; + + gig |= RGEPHY_1000CTL_MSE; + if ((ife->ifm_media & IFM_ETH_MASTER) != 0) + gig |= RGEPHY_1000CTL_MSC; + PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); + PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); PHY_WRITE(sc, RGEPHY_MII_BMCR, speed | RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); break; case IFM_NONE: - PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN); + PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); break; - case IFM_100_T4: default: return (EINVAL); } @@ -297,7 +285,7 @@ setit: return (0); sc->mii_ticks = 0; - rgephy_mii_phy_auto(sc); + rgephy_mii_phy_auto(sc, ife->ifm_media); break; } @@ -395,22 +383,32 @@ rgephy_status(struct mii_softc *sc) else mii->mii_media_active |= IFM_HDX; } + + if ((mii->mii_media_active & IFM_FDX) != 0) + mii->mii_media_active |= mii_phy_flowstatus(sc); + + if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) && + (PHY_READ(sc, RGEPHY_MII_1000STS) & RGEPHY_1000STS_MSR) != 0) + mii->mii_media_active |= IFM_ETH_MASTER; } static int -rgephy_mii_phy_auto(struct mii_softc *mii) +rgephy_mii_phy_auto(struct mii_softc *sc, int media) { + int anar; - rgephy_loop(mii); - rgephy_reset(mii); + rgephy_loop(sc); + rgephy_reset(sc); - PHY_WRITE(mii, RGEPHY_MII_ANAR, - BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; + if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) + anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; + PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); DELAY(1000); - PHY_WRITE(mii, RGEPHY_MII_1000CTL, - RGEPHY_1000CTL_AHD|RGEPHY_1000CTL_AFD); + PHY_WRITE(sc, RGEPHY_MII_1000CTL, + RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD); DELAY(1000); - PHY_WRITE(mii, RGEPHY_MII_BMCR, + PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); DELAY(100); |