static int atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t anar, bmcr, bmsr; 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) { bmcr = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); return (0); } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { atphy_auto(sc); break; } bmcr = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_100_TX: bmcr = BMCR_S100; break; case IFM_10_T: bmcr = BMCR_S10; break; case IFM_NONE: bmcr = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO | BMCR_PDOWN); goto done; default: return (EINVAL); } anar = atphy_anar(ife); if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { bmcr |= BMCR_FDX; /* Enable pause. */ anar |= (3 << 10); } PHY_WRITE(sc, MII_100T2CR, 0); PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); /* * Reset the PHY so all changes take effect. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET); done: 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 for link. * Read the status register twice; BMSR_LINK is latch-low. */ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; if (sc->mii_ticks <= sc->mii_anegticks) return (0); sc->mii_ticks = 0; atphy_auto(sc); break; } /* Update the media status. */ atphy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static int atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t anar, bmcr, bmsr; 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) { bmcr = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); return 0; } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { atphy_auto(sc); break; } bmcr = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_100_TX: bmcr = BMCR_S100; break; case IFM_10_T: bmcr = BMCR_S10; break; case IFM_NONE: bmcr = PHY_READ(sc, MII_BMCR); /* * XXX * Due to an unknown reason powering down PHY resulted * in unexpected results such as inaccessbility of * hardware of freshly rebooted system. Disable * powering down PHY until I got more information for * Attansic/Atheros PHY hardwares. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); goto done; default: return EINVAL; } anar = atphy_anar(ife); if ((ife->ifm_media & IFM_GMASK) & IFM_FDX) { bmcr |= BMCR_FDX; /* Enable pause. */ anar |= (3 << 10); } if (sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) PHY_WRITE(sc, MII_100T2CR, 0); PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); /* * Reset the PHY so all changes take effect. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); done: 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 for link. * Read the status register twice; BMSR_LINK is latch-low. */ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; if (sc->mii_ticks <= sc->mii_anegticks) return 0; sc->mii_ticks = 0; atphy_auto(sc); break; } /* Update the media status. */ atphy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return 0; }
static int atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t anar, bmcr, bmsr; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO || IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { atphy_setmedia(sc, ife->ifm_media); break; } bmcr = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_100_TX: bmcr = BMCR_S100; break; case IFM_10_T: bmcr = BMCR_S10; break; case IFM_NONE: bmcr = PHY_READ(sc, MII_BMCR); /* * XXX * Due to an unknown reason powering down PHY resulted * in unexpected results such as inaccessibility of * hardware of freshly rebooted system. Disable * powering down PHY until I got more information for * Attansic/Atheros PHY hardwares. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); goto done; default: return (EINVAL); } anar = atphy_anar(ife); if ((ife->ifm_media & IFM_FDX) != 0) { bmcr |= BMCR_FDX; if ((ife->ifm_media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= ANAR_PAUSE_TOWARDS; } if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, MII_100T2CR, 0); PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA); /* * Reset the PHY so all changes take effect. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); done: break; case MII_TICK: /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check for link. * Read the status register twice; BMSR_LINK is latch-low. */ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; if (sc->mii_ticks <= sc->mii_anegticks) return (0); sc->mii_ticks = 0; atphy_setmedia(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }