static int rgephy_mii_phy_auto(struct mii_softc *mii) { rgephy_loop(mii); rgephy_reset(mii); PHY_WRITE(mii, RGEPHY_MII_ANAR, BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA); DELAY(1000); PHY_WRITE(mii, RGEPHY_MII_1000CTL, RGEPHY_1000CTL_AHD|RGEPHY_1000CTL_AFD); DELAY(1000); PHY_WRITE(mii, RGEPHY_MII_BMCR, RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); DELAY(100); return (EJUSTRETURN); }
static int rgephy_mii_phy_auto(struct mii_softc *sc, int media) { int anar; rgephy_loop(sc); PHY_RESET(sc); 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(sc, RGEPHY_MII_1000CTL, RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD); DELAY(1000); PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG); DELAY(100); return (EJUSTRETURN); }
static int rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg, speed, gig, anar; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; PHY_RESET(sc); /* XXX hardware bug work-around */ anar = PHY_READ(sc, RGEPHY_MII_ANAR); 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)) { case IFM_AUTO: #ifdef foo /* * If we're already in auto mode, just return. */ if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN) return (0); #endif (void)rgephy_mii_phy_auto(sc, ife->ifm_media); break; case IFM_1000_T: speed = RGEPHY_S1000; goto setit; case IFM_100_TX: speed = RGEPHY_S100; anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX; goto setit; case IFM_10_T: speed = RGEPHY_S10; anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10; setit: if ((ife->ifm_media & IFM_FLOW) != 0 && (mii->mii_media.ifm_media & IFM_FLAG0) != 0) return (EINVAL); if ((ife->ifm_media & IFM_FDX) != 0) { speed |= RGEPHY_BMCR_FDX; gig = RGEPHY_1000CTL_AFD; anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10); if ((ife->ifm_media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP; } else { gig = RGEPHY_1000CTL_AHD; anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD); } if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= RGEPHY_1000CTL_MSE; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= RGEPHY_1000CTL_MSC; } else { gig = 0; anar &= ~RGEPHY_ANAR_ASP; } if ((mii->mii_media.ifm_media & IFM_FLAG0) == 0) speed |= RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG; rgephy_loop(sc); PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig); PHY_WRITE(sc, RGEPHY_MII_ANAR, anar); PHY_WRITE(sc, RGEPHY_MII_BMCR, speed); break; case IFM_NONE: PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN); break; default: return (EINVAL); } break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. */ if ((sc->mii_flags & MIIF_PHYPRIV0) == 0 && sc->mii_mpd_rev >= 2) { /* RTL8211B(L) */ reg = PHY_READ(sc, RGEPHY_MII_SSR); if (reg & RGEPHY_SSR_LINK) { sc->mii_ticks = 0; break; } } else { reg = PHY_READ(sc, RL_GMEDIASTAT); if (reg & RL_GMEDIASTAT_LINK) { sc->mii_ticks = 0; break; } } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; /* Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) return (0); sc->mii_ticks = 0; rgephy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* * Callback if something changed. Note that we need to poke * the DSP on the RealTek PHYs if the media changes. * */ if (sc->mii_media_active != mii->mii_media_active || sc->mii_media_status != mii->mii_media_status || cmd == MII_MEDIACHG) { rgephy_load_dspcode(sc); } mii_phy_update(sc, cmd); return (0); }
static int rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct rgephy_softc *rsc; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg, speed, gig, anar; rsc = (struct rgephy_softc *)sc; switch (cmd) { case MII_POLLSTAT: /* * If we're not polling our PHY instance, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); break; case MII_MEDIACHG: /* * If the media indicates a different PHY instance, * isolate ourselves. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) { reg = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); return (0); } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; rgephy_reset(sc); /* XXX hardware bug work-around */ anar = PHY_READ(sc, RGEPHY_MII_ANAR); anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX | RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10); switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: #ifdef foo /* * If we're already in auto mode, just return. */ if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN) return (0); #endif (void) rgephy_mii_phy_auto(sc); break; case IFM_1000_T: speed = RGEPHY_S1000; goto setit; case IFM_100_TX: speed = RGEPHY_S100; anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX; goto setit; case IFM_10_T: speed = RGEPHY_S10; anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10; setit: rgephy_loop(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { speed |= RGEPHY_BMCR_FDX; gig = RGEPHY_1000CTL_AFD; anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10); } else { gig = RGEPHY_1000CTL_AHD; anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD); } if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) { 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); 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); } 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); break; case IFM_100_T4: default: return (EINVAL); } break; case MII_TICK: /* * If we're not currently selected, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. */ if (rsc->mii_revision >= 2) { /* RTL8211B(L) */ reg = PHY_READ(sc, RGEPHY_MII_SSR); if (reg & RGEPHY_SSR_LINK) { sc->mii_ticks = 0; break; } } else { reg = PHY_READ(sc, RL_GMEDIASTAT); if (reg & RL_GMEDIASTAT_LINK) { sc->mii_ticks = 0; break; } } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; /* Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) return (0); sc->mii_ticks = 0; rgephy_mii_phy_auto(sc); break; } /* Update the media status. */ rgephy_status(sc); /* * Callback if something changed. Note that we need to poke * the DSP on the RealTek PHYs if the media changes. * */ if (sc->mii_media_active != mii->mii_media_active || sc->mii_media_status != mii->mii_media_status || cmd == MII_MEDIACHG) { rgephy_load_dspcode(sc); } mii_phy_update(sc, cmd); return (0); }