diff options
Diffstat (limited to 'sys/dev/mii/brgphy.c')
-rw-r--r-- | sys/dev/mii/brgphy.c | 73 |
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); } |