static int e1000phy_attach(device_t dev) { struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; getenv_int("e1000phy_debug", &e1000phy_debug); sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); mii = device_get_softc(sc->mii_dev); LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); sc->mii_inst = mii->mii_instance; sc->mii_phy = ma->mii_phyno; sc->mii_service = e1000phy_service; sc->mii_pdata = mii; sc->mii_flags |= MIIF_NOISOLATE; mii->mii_instance++; e1000phy_reset(sc); device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) /* ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), E1000_CR_ISOLATE); */ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), E1000_CR_SPEED_10); printf("10baseT, "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); printf("10baseT-FDX, "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), E1000_CR_SPEED_100); printf("100baseTX, "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); printf("100baseTX-FDX, "); /* * 1000BT-simplex not supported; driver must ignore this entry, * but it must be present in order to manually set full-duplex. */ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), E1000_CR_SPEED_1000); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); printf("1000baseTX-FDX, "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); printf("auto\n"); #undef ADD MIIBUS_MEDIAINIT(sc->mii_dev); return(0); }
static int e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t speed, gig; int reg; 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, E1000_CR); PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); 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) { e1000phy_mii_phy_auto(sc); break; } speed = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_1000_T: if (sc->mii_model == MII_MODEL_MARVELL_E3082) return (EINVAL); speed = E1000_CR_SPEED_1000; break; case IFM_1000_SX: if (sc->mii_model == MII_MODEL_MARVELL_E3082) return (EINVAL); speed = E1000_CR_SPEED_1000; break; case IFM_100_TX: speed = E1000_CR_SPEED_100; break; case IFM_10_T: speed = E1000_CR_SPEED_10; break; case IFM_NONE: reg = PHY_READ(sc, E1000_CR); PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE | E1000_CR_POWER_DOWN); goto done; default: return (EINVAL); } if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { speed |= E1000_CR_FULL_DUPLEX; gig = E1000_1GCR_1000T_FD; } else { gig = E1000_1GCR_1000T; } reg = PHY_READ(sc, E1000_CR); reg &= ~E1000_CR_AUTO_NEG_ENABLE; PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET); /* * 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 (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T || IFM_SUBTYPE(ife->ifm_media) == IFM_1000_SX) { if (mii->mii_ifp->if_flags & IFF_LINK0) { PHY_WRITE(sc, E1000_1GCR, gig | E1000_1GCR_MS_ENABLE | E1000_1GCR_MS_VALUE); } else { PHY_WRITE(sc, E1000_1GCR, gig | E1000_1GCR_MS_ENABLE); } } else { if (sc->mii_model != MII_MODEL_MARVELL_E3082) PHY_WRITE(sc, E1000_1GCR, 0); } PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); PHY_WRITE(sc, E1000_CR, speed | E1000_CR_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) 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. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) { 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; e1000phy_reset(sc); e1000phy_mii_phy_auto(sc); break; } /* Update the media status. */ e1000phy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static int e1000phy_attach(device_t dev) { struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; const char *sep = ""; int fast_ether = 0; sc = device_get_softc(dev); ma = device_get_ivars(dev); mii_softc_init(sc, ma); sc->mii_dev = device_get_parent(dev); mii = device_get_softc(sc->mii_dev); LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); sc->mii_inst = mii->mii_instance; sc->mii_service = e1000phy_service; sc->mii_reset = e1000phy_reset; sc->mii_anegticks = MII_ANEGTICKS_GIGE; sc->mii_pdata = mii; sc->mii_flags |= MIIF_NOISOLATE; switch (sc->mii_model) { case MII_MODEL_MARVELL_E1011: case MII_MODEL_MARVELL_E1112: if (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK) sc->mii_flags |= MIIF_HAVEFIBER; break; case MII_MODEL_MARVELL_E3082: /* 88E3082 10/100 Fast Ethernet PHY. */ sc->mii_anegticks = MII_ANEGTICKS; fast_ether = 1; break; } mii->mii_instance++; e1000phy_reset(sc); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) #define PRINT(s) kprintf("%s%s", sep, s); sep = ", " device_printf(dev, "%s", ""); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), E1000_CR_ISOLATE); if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { if (!fast_ether) { /* * 1000T-simplex not supported; driver must ignore * this entry, but it must be present in order to * manually set full-duplex. */ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), E1000_CR_SPEED_1000); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); PRINT("1000baseT-FDX"); } ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); PRINT("100baseTX-FDX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), E1000_CR_SPEED_100); PRINT("100baseTX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); PRINT("10baseTX-FDX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), E1000_CR_SPEED_10); PRINT("10baseTX"); } else { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); PRINT("1000baseSX-FDX"); } ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); PRINT("auto\n"); #undef ADD #undef PRINT MIIBUS_MEDIAINIT(sc->mii_dev); return(0); }
int e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; 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, E1000_CR); PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); return (0); } /* * 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: /* * If we're already in auto mode, just return. */ if (sc->mii_flags & MIIF_DOINGAUTO) { return (0); } e1000phy_reset(sc); (void)e1000phy_mii_phy_auto(sc, 1); break; case IFM_1000_TX: if (sc->mii_flags & MIIF_DOINGAUTO) return (0); e1000phy_reset(sc); /* TODO - any other way to force 1000BT? */ (void)e1000phy_mii_phy_auto(sc, 1); break; case IFM_100_TX: e1000phy_reset(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { PHY_WRITE(sc, E1000_CR, E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_100); PHY_WRITE(sc, E1000_AR, E1000_AR_100TX_FD); } else { PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_100); PHY_WRITE(sc, E1000_AR, E1000_AR_100TX); } break; case IFM_10_T: e1000phy_reset(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { PHY_WRITE(sc, E1000_CR, E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_10); PHY_WRITE(sc, E1000_AR, E1000_AR_10T_FD); } else { PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_10); PHY_WRITE(sc, E1000_AR, E1000_AR_10T); } break; 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); } /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { return (0); } /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { return (0); } /* * Only retry autonegotiation every 5 seconds. */ if (++(sc->mii_ticks) != 5) { return (0); } sc->mii_ticks = 0; /* * 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. */ reg = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR); if (reg & E1000_SR_LINK_STATUS) break; e1000phy_reset(sc); if (e1000phy_mii_phy_auto(sc, 0) == EJUSTRETURN) { return(0); } break; } /* Update the media status. */ e1000phy_status(sc); /* Callback if something changed. */ if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { MIIBUS_STATCHG(sc->mii_dev); sc->mii_active = mii->mii_media_active; } return (0); }
static int e1000phy_attach(device_t dev) { struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; const char *sep = ""; getenv_int("e1000phy_debug", &e1000phy_debug); sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); mii = device_get_softc(sc->mii_dev); LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); sc->mii_inst = mii->mii_instance; sc->mii_phy = ma->mii_phyno; sc->mii_service = e1000phy_service; sc->mii_pdata = mii; sc->mii_flags |= MIIF_NOISOLATE; mii->mii_instance++; e1000phy_reset(sc); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) #define PRINT(s) printf("%s%s", sep, s); sep = ", " #if 0 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), E1000_CR_ISOLATE); #endif device_printf(dev, " "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX); PRINT("1000baseTX-FDX"); /* TODO - apparently 1000BT-simplex not supported? ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_TX, 0, sc->mii_inst), E1000_CR_SPEED_1000); PRINT("1000baseTX"); */ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX); PRINT("100baseTX-FDX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), E1000_CR_SPEED_100); PRINT("100baseTX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX); PRINT("10baseTX-FDX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), E1000_CR_SPEED_10); PRINT("10baseTX"); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); PRINT("auto"); printf("\n"); #undef ADD #undef PRINT MIIBUS_MEDIAINIT(sc->mii_dev); return(0); }
static int e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; 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, E1000_CR); PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); return (0); } /* * 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: e1000phy_reset(sc); (void)e1000phy_mii_phy_auto(sc); break; case IFM_1000_T: e1000phy_reset(sc); /* TODO - any other way to force 1000BT? */ (void)e1000phy_mii_phy_auto(sc); break; case IFM_100_TX: e1000phy_reset(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { PHY_WRITE(sc, E1000_CR, E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_100); PHY_WRITE(sc, E1000_AR, E1000_AR_100TX_FD); } else { PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_100); PHY_WRITE(sc, E1000_AR, E1000_AR_100TX); } break; case IFM_10_T: e1000phy_reset(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { PHY_WRITE(sc, E1000_CR, E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_10); PHY_WRITE(sc, E1000_AR, E1000_AR_10T_FD); } else { PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_10); PHY_WRITE(sc, E1000_AR, E1000_AR_10T); } break; 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) break; /* * check for link. * Read the status register twice; BMSR_LINK is latch-low. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) break; /* * Only retry autonegotiation every 5 seconds. */ if (++sc->mii_ticks != 5) return (0); sc->mii_ticks = 0; e1000phy_reset(sc); e1000phy_mii_phy_auto(sc); return (0); } /* Update the media status. */ e1000phy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }