/* * Inform the PHYs that the interface is down. */ void mii_down(struct mii_data *mii) { struct mii_softc *child; for (child = LIST_FIRST(&mii->mii_phys); child != NULL; child = LIST_NEXT(child, mii_list)) (void) PHY_SERVICE(child, mii, MII_DOWN); }
/* * Get media status from PHYs. */ void mii_pollstat(struct mii_data *mii) { struct mii_softc *child; mii->mii_media_status = 0; mii->mii_media_active = IFM_NONE; for (child = LIST_FIRST(&mii->mii_phys); child != NULL; child = LIST_NEXT(child, mii_list)) (void) PHY_SERVICE(child, mii, MII_POLLSTAT); }
/* * Media changed; notify all PHYs. */ int mii_mediachg(struct mii_data *mii) { struct mii_softc *child; int rv; mii->mii_media_status = 0; mii->mii_media_active = IFM_NONE; for (child = LIST_FIRST(&mii->mii_phys); child != NULL; child = LIST_NEXT(child, mii_list)) { rv = PHY_SERVICE(child, mii, MII_MEDIACHG); if (rv) return (rv); } return (0); }
int mlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; struct mii_softc *other = NULL; struct mlphy_softc *msc = (struct mlphy_softc *)sc; int other_inst, reg; LIST_FOREACH(other, &mii->mii_phys, mii_list) if (other != sc) break; if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) return (ENXIO); 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 interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: msc->ml_state = ML_STATE_AUTO_SELF; if (other != NULL) { mii_phy_reset(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } (void)mii_phy_auto(sc, 0); msc->ml_linked = 0; break; case IFM_10_T: /* * For 10baseT modes, reset and program the * companion PHY (of any), then setup ourselves * to match. This will put us in pass-through * mode and let the companion PHY do all the * work. * BMCR data is stored in the ifmedia entry. */ if (other != NULL) { mii_phy_reset(other); PHY_WRITE(other, MII_BMCR, ife->ifm_data); } mii_phy_setmedia(sc); msc->ml_state = 0; break; case IFM_100_TX: /* * For 100baseTX modes, reset and isolate the * companion PHY (if any), then setup ourselves * accordingly. * * BMCR data is stored in the ifmedia entry. */ if (other != NULL) { mii_phy_reset(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } mii_phy_setmedia(sc); msc->ml_state = 0; break; default: return (EINVAL); } break; case MII_TICK: /* * If interface is not up, don't do anything */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 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 we're in a 10Mbps mode, check the link of the * 10Mbps PHY. Sometimes the Micro Linear PHY's * linkstat bit will clear while the linkstat bit of * the companion PHY will remain set. */ if (msc->ml_state == ML_STATE_AUTO_OTHER) { reg = PHY_READ(other, MII_BMSR) | PHY_READ(other, MII_BMSR); } else { reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); } if (reg & BMSR_LINK) { if (!msc->ml_linked) { msc->ml_linked = 1; mlphy_status(sc); } sc->mii_ticks = 0; break; } /* * Only retry autonegotiation every 5 seconds. */ if (++sc->mii_ticks <= MII_ANEGTICKS) break; sc->mii_ticks = 0; msc->ml_linked = 0; mii->mii_media_active = IFM_NONE; mii_phy_reset(sc); msc->ml_state = ML_STATE_AUTO_SELF; if (other != NULL) { mii_phy_reset(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } mii_phy_auto(sc, 0); break; case MII_DOWN: mii_phy_down(sc); return (0); } /* Update the media status. */ if (msc->ml_state == ML_STATE_AUTO_OTHER && other != NULL) { other_inst = other->mii_inst; other->mii_inst = sc->mii_inst; if (IFM_INST(ife->ifm_media) == other->mii_inst) (void) PHY_SERVICE(other, mii, MII_POLLSTAT); other->mii_inst = other_inst; sc->mii_media_active = other->mii_media_active; sc->mii_media_status = other->mii_media_status; } else ukphy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }