summaryrefslogtreecommitdiff
path: root/sys/dev/mii
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mii')
-rw-r--r--sys/dev/mii/brgphy.c73
1 files changed, 52 insertions, 21 deletions
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c
index 6122a882c90..4d22d1c1309 100644
--- a/sys/dev/mii/brgphy.c
+++ b/sys/dev/mii/brgphy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: brgphy.c,v 1.39 2005/11/06 03:49:28 brad Exp $ */
+/* $OpenBSD: brgphy.c,v 1.40 2005/11/06 07:25:05 brad Exp $ */
/*
* Copyright (c) 2000
@@ -80,7 +80,7 @@ struct cfdriver brgphy_cd = {
int brgphy_service(struct mii_softc *, struct mii_data *, int);
void brgphy_status(struct mii_softc *);
-int brgphy_mii_phy_auto(struct mii_softc *);
+int brgphy_mii_phy_auto(struct mii_softc *, int);
void brgphy_loop(struct mii_softc *);
void brgphy_reset(struct mii_softc *);
void brgphy_load_dspcode(struct mii_softc *);
@@ -217,7 +217,7 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN)
return (0);
#endif
- (void) brgphy_mii_phy_auto(sc);
+ (void) brgphy_mii_phy_auto(sc, 1);
break;
case IFM_1000_T:
speed = BRGPHY_S1000;
@@ -309,8 +309,9 @@ setit:
break;
sc->mii_ticks = 0;
- brgphy_mii_phy_auto(sc);
- return (0);
+ if (brgphy_mii_phy_auto(sc, 0) == EJUSTRETURN)
+ return (0);
+ break;
}
/* Update the media status. */
@@ -397,24 +398,54 @@ brgphy_status(struct mii_softc *sc)
int
-brgphy_mii_phy_auto(struct mii_softc *sc)
+brgphy_mii_phy_auto(struct mii_softc *sc, int waitfor)
{
- int ktcr = 0;
+ int bmsr, ktcr = 0, i;
+
+ if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
+ brgphy_loop(sc);
+ PHY_RESET(sc);
+ ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD;
+ if (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701)
+ ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC;
+ PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr);
+ ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL);
+ DELAY(1000);
+ PHY_WRITE(sc, BRGPHY_MII_ANAR,
+ BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA);
+ DELAY(1000);
+ PHY_WRITE(sc, BRGPHY_MII_BMCR,
+ BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
+ PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
+ }
- brgphy_loop(sc);
- PHY_RESET(sc);
- ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD;
- if (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701)
- ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC;
- PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr);
- ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL);
- DELAY(1000);
- PHY_WRITE(sc, BRGPHY_MII_ANAR,
- BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA);
- DELAY(1000);
- PHY_WRITE(sc, BRGPHY_MII_BMCR,
- BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
- PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
+ if (waitfor) {
+ /* Wait 500ms for it to complete. */
+ for (i = 0; i < 500; i++) {
+ if ((bmsr = PHY_READ(sc, BRGPHY_MII_BMSR)) &
+ BRGPHY_BMSR_ACOMP)
+ return (0);
+ DELAY(1000);
+ }
+
+ /*
+ * Don't need to worry about clearing MIIF_DOINGAUTO.
+ * If that's set, a timeout is pending, and it will
+ * clear the flag.
+ */
+ return (EIO);
+ }
+
+ /*
+ * Just let it finish asynchronously. This is for the benefit of
+ * the tick handler driving autonegotiation. Don't want 500ms
+ * delays all the time while the system is running!
+ */
+ if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
+ sc->mii_flags |= MIIF_DOINGAUTO;
+ timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc);
+ timeout_add(&sc->mii_phy_timo, hz / 2);
+ }
return (EJUSTRETURN);
}