summaryrefslogtreecommitdiff
path: root/sys/dev/mii
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2004-10-09 02:06:57 +0000
committerBrad Smith <brad@cvs.openbsd.org>2004-10-09 02:06:57 +0000
commit74566017b8f9543b54823bb0600c54d58d505ee7 (patch)
treee421a866bad788c93c6ea9da3f9392d18bd9ee03 /sys/dev/mii
parentbdac2703a436f20c001f057abff80c170d555c65 (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.c65
-rw-r--r--sys/dev/mii/ukphy_subr.c23
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;
}