diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2004-10-09 02:06:57 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2004-10-09 02:06:57 +0000 |
commit | 74566017b8f9543b54823bb0600c54d58d505ee7 (patch) | |
tree | e421a866bad788c93c6ea9da3f9392d18bd9ee03 /sys/dev/mii | |
parent | bdac2703a436f20c001f057abff80c170d555c65 (diff) |
add master flag support for 1000baseT and autonegotiation support for 1000baseX.
From NetBSD
ok mcbride@
Diffstat (limited to 'sys/dev/mii')
-rw-r--r-- | sys/dev/mii/mii_physubr.c | 65 | ||||
-rw-r--r-- | sys/dev/mii/ukphy_subr.c | 23 |
2 files changed, 81 insertions, 7 deletions
diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c index 6ccd7c4da14..7f054369a42 100644 --- a/sys/dev/mii/mii_physubr.c +++ b/sys/dev/mii/mii_physubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mii_physubr.c,v 1.19 2004/09/27 18:25:48 brad Exp $ */ +/* $OpenBSD: mii_physubr.c,v 1.20 2004/10/09 02:06:56 brad Exp $ */ /* $NetBSD: mii_physubr.c,v 1.20 2001/04/13 23:30:09 thorpej Exp $ */ /*- @@ -98,7 +98,7 @@ mii_phy_setmedia(struct mii_softc *sc) { struct mii_data *mii = sc->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int bmcr, anar; + int bmcr, anar, gtcr; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 || @@ -117,12 +117,26 @@ mii_phy_setmedia(struct mii_softc *sc) anar = mii_media_table[ife->ifm_data].mm_anar; bmcr = mii_media_table[ife->ifm_data].mm_bmcr; + gtcr = mii_media_table[ife->ifm_data].mm_gtcr; + + if (mii->mii_media.ifm_media & IFM_ETH_MASTER) { + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_1000_T: + gtcr |= GTCR_MAN_MS|GTCR_ADV_MS; + break; + + default: + panic("mii_phy_setmedia: MASTER on wrong media"); + } + } if (ife->ifm_media & IFM_LOOP) bmcr |= BMCR_LOOP; PHY_WRITE(sc, MII_ANAR, anar); PHY_WRITE(sc, MII_BMCR, bmcr); + if (sc->mii_flags & MIIF_HAVE_GTCR) + PHY_WRITE(sc, MII_100T2CR, gtcr); } int @@ -131,8 +145,36 @@ mii_phy_auto(struct mii_softc *sc, int waitfor) int bmsr, i; if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { - PHY_WRITE(sc, MII_ANAR, - BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA); + /* + * Check for 1000BASE-X. Autonegotiation is a bit + * different on such devices. + */ + if (sc->mii_flags & MIIF_IS_1000X) { + uint16_t anar = 0; + + if (sc->mii_extcapabilities & EXTSR_1000XFDX) + anar |= ANAR_X_FD; + if (sc->mii_extcapabilities & EXTSR_1000XHDX) + anar |= ANAR_X_HD; + + PHY_WRITE(sc, MII_ANAR, anar); + } else { + uint16_t anar; + + anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | + ANAR_CSMA; + PHY_WRITE(sc, MII_ANAR, anar); + if (sc->mii_flags & MIIF_HAVE_GTCR) { + uint16_t gtcr = 0; + + if (sc->mii_extcapabilities & EXTSR_1000TFDX) + gtcr |= GTCR_ADV_1000TFDX; + if (sc->mii_extcapabilities & EXTSR_1000THDX) + gtcr |= GTCR_ADV_1000THDX; + + PHY_WRITE(sc, MII_100T2CR, gtcr); + } + } PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); } @@ -378,21 +420,36 @@ mii_phy_add_media(struct mii_softc *sc) */ if (sc->mii_extcapabilities & EXTSR_1000XHDX) { sc->mii_anegticks = 10; + sc->mii_flags |= MIIF_IS_1000X; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst), MII_MEDIA_1000_X); } if (sc->mii_extcapabilities & EXTSR_1000XFDX) { sc->mii_anegticks = 10; + sc->mii_flags |= MIIF_IS_1000X; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), MII_MEDIA_1000_X_FDX); } + + /* + * 1000baseT media needs to be able to manipulate + * master/slave mode. We set IFM_ETH_MASTER in + * the "don't care mask" and filter it out when + * the media is set. + * + * All 1000baseT PHYs have a 1000baseT control register. + */ if (sc->mii_extcapabilities & EXTSR_1000THDX) { sc->mii_anegticks = 10; + sc->mii_flags |= MIIF_HAVE_GTCR; + mii->mii_media.ifm_mask |= IFM_ETH_MASTER; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), MII_MEDIA_1000_T); } if (sc->mii_extcapabilities & EXTSR_1000TFDX) { sc->mii_anegticks = 10; + sc->mii_flags |= MIIF_HAVE_GTCR; + mii->mii_media.ifm_mask |= IFM_ETH_MASTER; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), MII_MEDIA_1000_T_FDX); } diff --git a/sys/dev/mii/ukphy_subr.c b/sys/dev/mii/ukphy_subr.c index 467e157f512..ae545bd33a7 100644 --- a/sys/dev/mii/ukphy_subr.c +++ b/sys/dev/mii/ukphy_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ukphy_subr.c,v 1.4 2004/09/27 18:25:48 brad Exp $ */ +/* $OpenBSD: ukphy_subr.c,v 1.5 2004/10/09 02:06:56 brad Exp $ */ /* $NetBSD: ukphy_subr.c,v 1.2 1998/11/05 04:08:02 thorpej Exp $ */ /*- @@ -63,7 +63,7 @@ ukphy_status(struct mii_softc *phy) { struct mii_data *mii = phy->mii_pdata; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int bmsr, bmcr, anlpar; + int bmsr, bmcr, anlpar, gtcr, gtsr; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; @@ -95,7 +95,20 @@ ukphy_status(struct mii_softc *phy) } anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR); - if (anlpar & ANLPAR_T4) + if ((phy->mii_flags & MIIF_HAVE_GTCR) != 0 && + (phy->mii_extcapabilities & + (EXTSR_1000THDX|EXTSR_1000TFDX)) != 0) { + gtcr = PHY_READ(phy, MII_100T2CR); + gtsr = PHY_READ(phy, MII_100T2SR); + } else + gtcr = gtsr = 0; + + if ((gtcr & GTCR_ADV_1000TFDX) && (gtsr & GTSR_LP_1000TFDX)) + mii->mii_media_active |= IFM_1000_T|IFM_FDX; + else if ((gtcr & GTCR_ADV_1000THDX) && + (gtsr & GTSR_LP_1000THDX)) + mii->mii_media_active |= IFM_1000_T; + else if (anlpar & ANLPAR_T4) mii->mii_media_active |= IFM_100_T4; else if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; @@ -107,6 +120,10 @@ ukphy_status(struct mii_softc *phy) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_NONE; + + if ((mii->mii_media_active & IFM_1000_T) && + (gtsr & GTSR_MS_RES)) + mii->mii_media_active |= IFM_ETH_MASTER; } else mii->mii_media_active = ife->ifm_media; } |