예제 #1
0
static int
truephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int bmcr;

	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) {
			bmcr = PHY_READ(sc, MII_BMCR) & ~BMCR_AUTOEN;
			PHY_WRITE(sc, MII_BMCR, bmcr);
			PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_PDOWN);
		}

		mii_phy_set_media(sc);

		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
			bmcr = PHY_READ(sc, MII_BMCR) & ~BMCR_PDOWN;
			PHY_WRITE(sc, MII_BMCR, bmcr);

			if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
				PHY_WRITE(sc, MII_BMCR,
					  bmcr | BMCR_AUTOEN | BMCR_STARTNEG);
			}
		}
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return 0;

		if (mii_phy_tick(sc) == EJUSTRETURN)
			return 0;
		break;
	}

	/* Update the media status. */
	truephy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return 0;
}
예제 #2
0
int
ipgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	uint32_t gig, reg, speed;

	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, IPGPHY_MII_BMCR);
			PHY_WRITE(sc, IPGPHY_MII_BMCR,
			    reg | IPGPHY_BMCR_ISO);
			return (0);
		}

		/*
		 * If the interface is not up, don't do anything.
		 */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			break;

		PHY_RESET(sc);

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			(void)ipgphy_mii_phy_auto(sc);
			goto done;
			break;

		case IFM_1000_T:
			/*
			 * XXX
			 * Manual 1000baseT setting doesn't seem to work.
			 */
			speed = IPGPHY_BMCR_1000;
			break;

		case IFM_100_TX:
			speed = IPGPHY_BMCR_100;
			break;

		case IFM_10_T:
			speed = IPGPHY_BMCR_10;
			break;

		default:
			return (EINVAL);
		}

		if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) {
			speed |= IPGPHY_BMCR_FDX;
			gig = IPGPHY_1000CR_1000T_FDX;
		} else
			gig = IPGPHY_1000CR_1000T;

		PHY_WRITE(sc, IPGPHY_MII_1000CR, 0);
		PHY_WRITE(sc, IPGPHY_MII_BMCR, speed);

		if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
			break;

		PHY_WRITE(sc, IPGPHY_MII_1000CR, gig);
		PHY_WRITE(sc, IPGPHY_MII_BMCR, speed);

		if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
			gig |= IPGPHY_1000CR_MASTER | IPGPHY_1000CR_MANUAL;

		PHY_WRITE(sc, IPGPHY_MII_1000CR, gig);

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.
		 */
		reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
		if (reg & BMSR_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;
		ipgphy_mii_phy_auto(sc);
		break;
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #3
0
static int
tlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct tlphy_softc *tsc = (struct tlphy_softc *)sc;
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg;

	if ((sc->mii_flags & MIIF_DOINGAUTO) == 0 && tsc->sc_need_acomp)
		tlphy_acomp(tsc);

	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;

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			/*
			 * The ThunderLAN PHY doesn't self-configure after
			 * an autonegotiation cycle, so there's no such
			 * thing as "already in auto mode".
			 */
			(void) tlphy_auto(tsc, 1);
			break;
		case IFM_10_2:
		case IFM_10_5:
			PHY_WRITE(sc, MII_BMCR, 0);
			PHY_WRITE(sc, MII_TLPHY_CTRL, CTRL_AUISEL);
			delay(100000);
			break;
		default:
			PHY_WRITE(sc, MII_TLPHY_CTRL, 0);
			delay(100000);
			mii_phy_setmedia(sc);
		}
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		/*
		 * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?!
		 */

		if (mii_phy_tick(sc) == EJUSTRETURN)
			return (0);
		break;

	case MII_DOWN:
		mii_phy_down(sc);
		return (0);
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #4
0
파일: atphy.c 프로젝트: ajinkya93/OpenBSD
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;

		bmcr = 0;
		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
		case IFM_1000_T:
			atphy_mii_phy_auto(sc);
			goto done;
		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 = mii_anar(ife->ifm_media);
		if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) {
			bmcr |= BMCR_FDX;
			/* Enable pause. */
			if (sc->mii_flags & MIIF_DOPAUSE)
				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);

		/*
		 * 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;

		/*
		 * Only retry autonegotiation every mii_anegticks seconds.
		 */
		if (sc->mii_ticks <= sc->mii_anegticks)
			return (0);

		sc->mii_ticks = 0;
		atphy_mii_phy_auto(sc);
		break;
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #5
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);
}
예제 #6
0
static int
mlphy_service(struct mii_softc *xsc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry	*ife = mii->mii_media.ifm_cur;
	int			reg;
	struct mii_softc	*other = NULL;
	struct mlphy_softc	*msc = (struct mlphy_softc *)xsc;
	struct mii_softc	*sc = &msc->ml_mii;
	device_t		*devlist;
	int			devs, i;
	const struct mii_media	*mm;

	/*
	 * See if there's another PHY on this bus with us.
	 * If so, we may need it for 10Mbps modes.
	 */
	device_get_children(msc->ml_mii.mii_dev, &devlist, &devs);
	for (i = 0; i < devs; i++) {
		if (strcmp(device_get_name(devlist[i]), "mlphy")) {
			other = device_get_softc(devlist[i]);
			break;
		}
	}
	kfree(devlist, M_TEMP);

	KKASSERT(ife->ifm_data >= 0 && ife->ifm_data < MII_NMEDIA);
	mm = &mii_media_table[ife->ifm_data];

	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;

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			/*
			 * For autonegotiation, reset and isolate the
			 * companion PHY (if any) and then do NWAY
			 * autonegotiation ourselves.
			 */
			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, 1);
			msc->ml_linked = 0;
			return(0);

		case IFM_10_T:
			/*
			 * For 10baseT modes, reset and program the
			 * companion PHY (of any), then program ourselves
			 * to match. This will put us in pass-through
			 * mode and let the companion PHY do all the
			 * work.
			 */
			if (other != NULL) {
				mii_phy_reset(other);
				PHY_WRITE(other, MII_BMCR, mm->mm_bmcr);
			}
			PHY_WRITE(sc, MII_ANAR, mm->mm_anar);
			PHY_WRITE(sc, MII_BMCR, mm->mm_bmcr);
			msc->ml_state = 0;
			break;

		case IFM_100_TX:
			/*
			 * For 100baseTX modes, reset and isolate the
			 * companion PHY (if any), then program ourselves
			 * accordingly.
			 */
			if (other != NULL) {
				mii_phy_reset(other);
				PHY_WRITE(other, MII_BMCR, BMCR_ISO);
			}
			PHY_WRITE(sc, MII_ANAR, mm->mm_anar);
			PHY_WRITE(sc, MII_BMCR, mm->mm_bmcr);
			msc->ml_state = 0;
			break;

		case IFM_100_T4:
			/*
			 * XXX Not supported as a manual setting right now.
			 */
			return (EINVAL);
		default:
			break;
		}
		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.
		 * 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 <= sc->mii_anegticks)
			return (0);
		
		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);
		}
		if (mii_phy_auto(sc, 0) == EJUSTRETURN)
			return(0);
		break;
	}

	/* Update the media status. */
	if (msc->ml_state == ML_STATE_AUTO_OTHER) {
		int other_inst;

		other_inst = other->mii_inst;
		other->mii_inst = sc->mii_inst;
		other->mii_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);
}
예제 #7
0
static int
brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct brgphy_softc *bsc = (struct brgphy_softc *)sc;
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int error = 0;
	int val;

	switch (cmd) {
	case MII_POLLSTAT:
		/* If we're not polling our PHY instance, just return. */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			goto brgphy_service_exit;
		break;
	case MII_MEDIACHG:
		/*
		 * If the media indicates a different PHY instance,
		 * isolate ourselves.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
			PHY_WRITE(sc, MII_BMCR,
			    PHY_READ(sc, MII_BMCR) | BMCR_ISO);
			goto brgphy_service_exit;
		}

		/* If the interface is not up, don't do anything. */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			break;

		/* Todo: Why is this here?  Is it really needed? */
		brgphy_reset(sc);	/* XXX hardware bug work-around */

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			brgphy_mii_phy_auto(sc);
			break;
		case IFM_2500_SX:
		case IFM_1000_SX:
		case IFM_1000_T:
		case IFM_100_TX:
		case IFM_10_T:
			brgphy_setmedia(sc, ife->ifm_media,
			    mii->mii_ifp->if_flags & IFF_LINK0);
			break;
		default:
			error = EINVAL;
			goto brgphy_service_exit;
		}
		break;
	case MII_TICK:
		/* Bail if we're not currently selected. */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			goto brgphy_service_exit;

		/* Bail if the interface isn't up. */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			goto brgphy_service_exit;


		/* Bail if autoneg isn't in process. */
		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.
		 */
		val	= PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
		if (val & BMSR_LINK) {
			sc->mii_ticks = 0;	/* Reset autoneg timer. */
			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)
			break;


		/* Retry autonegotiation */
		sc->mii_ticks = 0;
		brgphy_mii_phy_auto(sc);
		break;
	}

	/* Update the media status. */
	brgphy_status(sc);

	/*
	 * Callback if something changed. Note that we need to poke
	 * the DSP on the Broadcom 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) {
		switch (bsc->mii_oui) {
		case MII_OUI_BROADCOM:
			break;
		case MII_OUI_xxBROADCOM:
			switch (bsc->mii_model) {
			case MII_MODEL_xxBROADCOM_BCM5400:
				bcm5401_load_dspcode(sc);
				break;
			case MII_MODEL_xxBROADCOM_BCM5401:
				if (bsc->mii_rev == 1 || bsc->mii_rev == 3)
					bcm5401_load_dspcode(sc);
				break;
			case MII_MODEL_xxBROADCOM_BCM5411:
				bcm5411_load_dspcode(sc);
				break;
			}
			break;
		case MII_OUI_xxBROADCOM_ALT1:
			break;
		}
	}
	mii_phy_update(sc, cmd);
brgphy_service_exit:
	return (error);
}
예제 #8
0
static int
pnaphy_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, 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;

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
		case IFM_10_T:
		case IFM_100_TX:
		case IFM_100_T4:
			return (EINVAL);
		default:
			mii_phy_set_media(sc);
		}
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		if (mii_phy_tick(sc) == EJUSTRETURN)
			return (0);
		break;
	}

	/* Update the media status. */
	ukphy_status(sc);
	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T)
		mii->mii_media_active = IFM_ETHER | IFM_HPNA_1;

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #9
0
파일: e1000phy.c 프로젝트: MarginC/kame
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);
}
예제 #10
0
static int
ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	uint32_t gig, reg, speed;

	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, IP1000PHY_MII_BMCR);
			PHY_WRITE(sc, IP1000PHY_MII_BMCR,
			    reg | IP1000PHY_BMCR_ISO);
			return (0);
		}

		/*
		 * If the interface is not up, don't do anything.
		 */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			break;

		ip1000phy_reset(sc);
		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			ip1000phy_mii_phy_auto(sc);
			goto done;

		case IFM_1000_T:
			/*
			 * XXX
			 * Manual 1000baseT setting doesn't seem to work.
			 */
			speed = IP1000PHY_BMCR_1000;
			break;

		case IFM_100_TX:
			speed = IP1000PHY_BMCR_100;
			break;

		case IFM_10_T:
			speed = IP1000PHY_BMCR_10;
			break;

		default:
			return (EINVAL);
		}

		if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) {
			speed |= IP1000PHY_BMCR_FDX;
			gig = IP1000PHY_1000CR_1000T_FDX;
		} else {
			gig = IP1000PHY_1000CR_1000T;
		}

		PHY_WRITE(sc, IP1000PHY_MII_1000CR, 0);
		PHY_WRITE(sc, IP1000PHY_MII_BMCR, speed);

		if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
			break;

		PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig);
		PHY_WRITE(sc, IP1000PHY_MII_BMCR, speed);

		/*
		 * When settning 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, IP1000PHY_MII_1000CR, gig |
			    IP1000PHY_1000CR_MASTER |
			    IP1000PHY_1000CR_MMASTER |
			    IP1000PHY_1000CR_MANUAL);
		} else {
			PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig |
			    IP1000PHY_1000CR_MASTER |
			    IP1000PHY_1000CR_MANUAL);
		}

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 for link.
		 */
		reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
		if (reg & BMSR_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;
		ip1000phy_mii_phy_auto(sc);
		break;
	}

	/* Update the media status. */
	ip1000phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #11
0
int
urlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg;

	DPRINTF(("%s: %s: enter\n", sc->mii_dev.dv_xname, __func__));

	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 we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		/* If the interface is not up, don't do anything. */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			break;

		mii_phy_setmedia(sc);
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		/* Just bail now if the interface is down. */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			return (0);

		/*
		 * If we're not doing autonegotiation, we don't need to do
		 * any extra work here.  However, we need to check the link
		 * status so we can generate an announcement if the status
		 * changes.
		 */
		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
			return (0);

		/* Read the status register twice; MSR_LINK is latch-low. */
		reg = PHY_READ(sc, URLPHY_MSR) | PHY_READ(sc, URLPHY_MSR);
		if (reg & URLPHY_MSR_LINK)
			return (0);

		/*
	 	 * Only retry autonegotiation every mii_anegticks seconds.
		 */
		if (++sc->mii_ticks <= sc->mii_anegticks)
			return (0);

		sc->mii_ticks = 0;
		PHY_RESET(sc);

		if (mii_phy_auto(sc, 0) == EJUSTRETURN)
			return (0);

		break;

	case MII_DOWN:
		mii_phy_down(sc);
		return (0);
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);

	return (0);
}
예제 #12
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);
}
예제 #13
0
/*
 * Callback from ifmedia to request new media setting.
 */
int
epic_mediachange(struct ifnet *ifp)
{
	struct epic_softc *sc = ifp->if_softc;
	struct mii_data *mii = &sc->sc_mii;
	struct ifmedia *ifm = &mii->mii_media;
	uint64_t media = ifm->ifm_cur->ifm_media;
	u_int32_t miicfg;
	struct mii_softc *miisc;
	int cfg;

	if (!(ifp->if_flags & IFF_UP))
		return (0);

	if (IFM_INST(media) != sc->sc_serinst) {
		/* If we're not selecting serial interface, select MII mode */
#ifdef EPICMEDIADEBUG
		printf("%s: parallel mode\n", ifp->if_xname);
#endif
		miicfg = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG);
		miicfg &= ~MIICFG_SERMODEENA;
		bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG, miicfg);
	}

	mii_mediachg(mii);

	if (IFM_INST(media) == sc->sc_serinst) {
		/* select serial interface */
#ifdef EPICMEDIADEBUG
		printf("%s: serial mode\n", ifp->if_xname);
#endif
		miicfg = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG);
		miicfg |= (MIICFG_SERMODEENA | MIICFG_ENABLE);
		bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG, miicfg);

		/* There is no driver to fill this */
		mii->mii_media_active = media;
		mii->mii_media_status = 0;

		epic_statchg(&sc->sc_dev);
		return (0);
	}

	/* Lookup selected PHY */
	for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
	     miisc = LIST_NEXT(miisc, mii_list)) {
		if (IFM_INST(media) == miisc->mii_inst)
			break;
	}
	if (!miisc) {
		printf("epic_mediachange: can't happen\n"); /* ??? panic */
		return (0);
	}
#ifdef EPICMEDIADEBUG
	printf("%s: using phy %s\n", ifp->if_xname,
	       miisc->mii_dev.dv_xname);
#endif

	if (miisc->mii_flags & MIIF_HAVEFIBER) {
		/* XXX XXX assume it's a Level1 - should check */

		/* We have to powerup fiber transceivers */
		cfg = PHY_READ(miisc, MII_LXTPHY_CONFIG);
		if (IFM_SUBTYPE(media) == IFM_100_FX) {
#ifdef EPICMEDIADEBUG
			printf("%s: power up fiber\n", ifp->if_xname);
#endif
			cfg |= (CONFIG_LEDC1 | CONFIG_LEDC0);
		} else {
#ifdef EPICMEDIADEBUG
			printf("%s: power down fiber\n", ifp->if_xname);
#endif
			cfg &= ~(CONFIG_LEDC1 | CONFIG_LEDC0);
		}
		PHY_WRITE(miisc, MII_LXTPHY_CONFIG, cfg);
	}

	return (0);
}
예제 #14
0
static int
urlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg;

	DPRINTF(("%s: %s: enter\n", device_xname(sc->mii_dev), __func__));

	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 we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		/* If the interface is not up, don't do anything. */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			break;

		mii_phy_setmedia(sc);
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		/* Just bail now if the interface is down. */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			return (0);

		/*
		 * If we're not doing autonegotiation, we don't need to do
		 * any extra work here.  However, we need to check the link
		 * status so we can generate an announcement if the status
		 * changes.
		 */
		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
			break;

		/* Read the status register twice; MSR_LINK is latch-low. */
		reg = PHY_READ(sc, URLPHY_MSR) | PHY_READ(sc, URLPHY_MSR);
		if (reg & URLPHY_MSR_LINK) {
			/*
			 * Reset autonegotiation timer to 0 in case the link
			 * goes down in the next tick.
			 */
			sc->mii_ticks = 0;
			/* See above. */
			break;
		}

		/*
		 * mii_ticks == 0 means it's the first tick after changing the
		 * media or the link became down since the last tick (see
		 * above), so break to update the status.
		 */
		if (sc->mii_ticks++ == 0)
			break;

		/*
		 * Only retry autonegotiation every N seconds.
		 */
		KASSERT(sc->mii_anegticks != 0);
		if (sc->mii_ticks <= sc->mii_anegticks)
			return (0);

		PHY_RESET(sc);

		if (mii_phy_auto(sc, 0) == EJUSTRETURN)
			return (0);

		break;

	case MII_DOWN:
		mii_phy_down(sc);
		return (0);
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);

	return (0);
}
예제 #15
0
파일: tlphy.c 프로젝트: kusumi/DragonFlyBSD
static int
tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd)
{
	struct tlphy_softc *sc = (struct tlphy_softc *)self;
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg;

	if (sc->sc_need_acomp)
		tlphy_acomp(sc);

	switch (cmd) {
	case MII_POLLSTAT:
		/*
		 * If we're not polling our PHY instance, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->sc_mii.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->sc_mii.mii_inst) {
			reg = PHY_READ(&sc->sc_mii, MII_BMCR);
			PHY_WRITE(&sc->sc_mii, 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;

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			/*
			 * The ThunderLAN PHY doesn't self-configure after
			 * an autonegotiation cycle, so there's no such
			 * thing as "already in auto mode".
			 */
			tlphy_auto(sc, 1);
			break;
		case IFM_10_2:
		case IFM_10_5:
			PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
			PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL);
			DELAY(100000);
			break;
		default:
			PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0);
			DELAY(100000);
			mii_phy_set_media(&sc->sc_mii);
			break;
		}
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->sc_mii.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.
		 *
		 * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?!
		 */
		reg = PHY_READ(&sc->sc_mii, MII_BMSR) |
		    PHY_READ(&sc->sc_mii, MII_BMSR);
		if (reg & BMSR_LINK) {
			sc->sc_mii.mii_ticks = 0;
			break;
		}

		/*
		 * Only retry autonegotiation every mii_anegticks seconds.
		 */
		if (++sc->sc_mii.mii_ticks <= sc->sc_mii.mii_anegticks)
			return (0);

		sc->sc_mii.mii_ticks = 0;
		mii_phy_reset(&sc->sc_mii);
		if (tlphy_auto(sc, 0) == EJUSTRETURN)
			return (0);
		break;
	}

	/* Update the media status. */
	tlphy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(&sc->sc_mii, cmd);
	return (0);
}
예제 #16
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);
}
예제 #17
0
static int
pnphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;

	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)
			return (0);

		/*
		 * If the interface is not up, don't do anything.
		 */
		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
			break;

		sc->mii_flags = 0;

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			/* NWAY is busted on this chip */
		case IFM_100_T4:
			/*
			 * XXX Not supported as a manual setting right now.
			 */
			return (EINVAL);
		case IFM_100_TX:
			mii->mii_media_active = IFM_ETHER | IFM_100_TX;
			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
				mii->mii_media_active |= IFM_FDX;
			MIIBUS_STATCHG(sc->mii_dev);
			return (0);
		case IFM_10_T:
			mii->mii_media_active = IFM_ETHER | IFM_10_T;
			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
				mii->mii_media_active |= IFM_FDX;
			MIIBUS_STATCHG(sc->mii_dev);
			return (0);
		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);

		break;
	}

	/* Update the media status. */
	pnphy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #18
0
static int
nsphy_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, 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;

		reg = PHY_READ(sc, MII_NSPHY_PCR);

		/*
		 * Set up the PCR to use LED4 to indicate full-duplex
		 * in both 10baseT and 100baseTX modes.
		 */
		reg |= PCR_LED4MODE;

		/*
		 * Make sure Carrier Intgrity Monitor function is
		 * disabled (normal for Node operation, but sometimes
		 * it's not set?!)
		 */
		reg |= PCR_CIMDIS;

		/*
		 * Make sure "force link good" is set to normal mode.
		 * It's only intended for debugging.
		 */
		reg |= PCR_FLINK100;

		/*
		 * Mystery bits which are supposedly `reserved',
		 * but we seem to need to set them when the PHY
		 * is connected to some interfaces:
		 *
		 * 0x0400 is needed for fxp
		 *        (Intel EtherExpress Pro 10+/100B, 82557 chip)
		 *        (nsphy with a DP83840 chip)
		 * 0x0100 may be needed for some other card
		 */
		reg |= PCR_CONGCTRL | PCR_TXREADYSEL;

		if (strcmp(device_get_name(device_get_parent(sc->mii_dev)),
		    "fxp") == 0)
			PHY_WRITE(sc, MII_NSPHY_PCR, reg);

		mii_phy_set_media(sc);
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		if (mii_phy_tick(sc) == EJUSTRETURN)
			return (0);
		break;
	}

	/* Update the media status. */
	nsphy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #19
0
int
xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg;

	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 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;

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			(void) xmphy_mii_phy_auto(sc);
			break;
		case IFM_1000_SX:
			PHY_RESET(sc);
			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
				PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX);
				PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX);
			} else {
				PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX);
				PHY_WRITE(sc, XMPHY_MII_BMCR, 0);
			}
			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 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)
			break;

		sc->mii_ticks = 0;
		PHY_RESET(sc);

		xmphy_mii_phy_auto(sc);
		break;
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #20
0
파일: media.c 프로젝트: muhammadn/nsh
int
intmedia(char *ifname, int ifs, int argc, char **argv)
{
	const char *errmsg = NULL;
	uint64_t set, media_current, type, subtype, inst;

	if (NO_ARG(argv[0])) {
		set = 0;
		argc--;
		argv++;
	} else
		set = 1;

	argv++;
	argc--;

	if ((set && (argc < 1 || argc > 2)) || (!set && argc > 2)) {
		printf("%% media <type> [instance]\n");
		printf("%% no media [type] [instance]\n");
		media_supported(ifs, ifname, "% ", "%   ");
		return(0);
	}

	media_current = init_current_media(ifs, ifname);

	if (media_current == -1) {
		if (errno == EINVAL)
			printf("%% This device does not support "
			    "media commands.\n");
		else
			printf("%% Failed to initialize media: %s\n",
			    strerror(errno));
		return(0);
	}

	if (argc == 2) {
		inst = strtonum(argv[1], 0, IFM_INST_MAX, &errmsg);
		if (errmsg) {
			printf("%% Invalid media instance: %s: %s\n", argv[1],
			    errmsg);
			return(0);
		}
	} else {
		inst = IFM_INST(media_current);
	}

	type = IFM_TYPE(media_current);
	/* Look up the subtype */
	if (set)
		subtype = get_media_subtype(type, argv[0]);
	else
		subtype = get_media_subtype(type, DEFAULT_MEDIA_TYPE);

	if (subtype == -1)
		return(0);

	/* Build the new media_current word */
	media_current = IFM_MAKEWORD(type, subtype, 0, inst);

	process_media_commands(ifs, ifname, media_current);

	return(0);
}
예제 #21
0
int
rlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;

	int rv;

	/*
	 * Can't isolate the RTL8139 phy, so it has to be the only one.
	 */
	if (IFM_INST(ife->ifm_media) != sc->mii_inst)
		panic("rlphy_service: attempt to isolate phy");

	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;

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			/*
			 * If we're already in auto mode, just return.
			 */
			if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
				return (0);
			(void) mii_phy_auto(sc, 0);
			break;
		case IFM_100_T4:
			/*
			 * XXX Not supported as a manual setting right now.
			 */
			return (EINVAL);
		default:
			/*
			 * BMCR data is stored in the ifmedia entry.
			 */
			switch (ife->ifm_media &
			    (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
				case IFM_ETHER|IFM_10_T:
					rv = ANAR_10|ANAR_CSMA;
					break;
				case IFM_ETHER|IFM_10_T|IFM_FDX:
					rv = ANAR_10_FD|ANAR_CSMA;
					break;
				case IFM_ETHER|IFM_100_TX:
					rv = ANAR_TX|ANAR_CSMA;
					break;
				case IFM_ETHER|IFM_100_TX|IFM_FDX:
					rv = ANAR_TX_FD|ANAR_CSMA;
					break;
				case IFM_ETHER|IFM_100_T4:
					rv = ANAR_T4|ANAR_CSMA;
					break;
				default:
					rv = 0;
					break;
			}

			PHY_WRITE(sc, MII_ANAR, rv);
			PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
		}
		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)
			break;

		/*
		 * The RealTek PHY's autonegotiation doesn't need to be
		 * kicked; it continues in the background.
		 */
		break;

	case MII_DOWN:
		mii_phy_down(sc);
		return (0);
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #22
0
파일: qsphy.c 프로젝트: SylvestreG/bitrig
int
qsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg;

	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 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;

		mii_phy_setmedia(sc);
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		if (mii_phy_tick(sc) == EJUSTRETURN)
			return (0);
		break;

	case MII_DOWN:
		mii_phy_down(sc);
		return (0);
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #23
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);
}
예제 #24
0
static int
brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg, speed, gig;

	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;

		PHY_RESET(sc); /* XXX hardware bug work-around */

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			(void) brgphy_mii_phy_auto(sc);
			break;
		case IFM_1000_T:
			speed = BMCR_S1000;
			goto setit;
		case IFM_100_TX:
			speed = BMCR_S100;
			goto setit;
		case IFM_10_T:
			speed = BMCR_S10;
setit:
			brgphy_loop(sc);
			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
				speed |= BMCR_FDX;
				gig = GTCR_ADV_1000TFDX;
			} else {
				gig = GTCR_ADV_1000THDX;
			}

			PHY_WRITE(sc, MII_100T2CR, 0);
			PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
			PHY_WRITE(sc, MII_BMCR, speed);

			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
				break;

			PHY_WRITE(sc, MII_100T2CR, gig);
			PHY_WRITE(sc, MII_BMCR,
			    speed | BMCR_AUTOEN | BMCR_STARTNEG);

			if ((sc->mii_mpd_oui != MII_OUI_BROADCOM)
			    || (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701))
				break;

			if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
				gig |= GTCR_MAN_MS | GTCR_ADV_MS;
			PHY_WRITE(sc, MII_100T2CR, gig);
			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) &&
		    (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)) {
			sc->mii_ticks = 0;
			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) {
			sc->mii_ticks = 0;
			break;
		}

		/*
		 * mii_ticks == 0 means it's the first tick after changing the
		 * media or the link became down since the last tick
		 * (see above), so break to update the status.
		 */
		if (sc->mii_ticks++ == 0)
			break;

		/*
		 * Only retry autonegotiation every mii_anegticks seconds.
		 */
		KASSERT(sc->mii_anegticks != 0);
		if (sc->mii_ticks <= sc->mii_anegticks)
			break;

		brgphy_mii_phy_auto(sc);
		break;

	case MII_DOWN:
		mii_phy_down(sc);
		return (0);
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/*
	 * Callback if something changed. Note that we need to poke the DSP on
	 * the Broadcom 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) {
		switch (sc->mii_mpd_oui) {
		case MII_OUI_BROADCOM:
			switch (sc->mii_mpd_model) {
			case MII_MODEL_BROADCOM_BCM5400:
				brgphy_bcm5401_dspcode(sc);
				break;
			case MII_MODEL_BROADCOM_BCM5401:
				if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
					brgphy_bcm5401_dspcode(sc);
				break;
			case MII_MODEL_BROADCOM_BCM5411:
				brgphy_bcm5411_dspcode(sc);
				break;
			}
			break;
		}
	}

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #25
0
파일: brgphy.c 프로젝트: sofuture/bitrig
int
brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg, speed = 0, gig;

	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 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;

		PHY_RESET(sc); /* XXX hardware bug work-around */

		switch (IFM_SUBTYPE(ife->ifm_media)) {
		case IFM_AUTO:
			(void) brgphy_mii_phy_auto(sc);
			break;
		case IFM_2500_SX:
			speed = BRGPHY_5708S_BMCR_2500;
			goto setit;
		case IFM_1000_T:
			speed = BRGPHY_S1000;
			goto setit;
		case IFM_100_TX:
			speed = BRGPHY_S100;
			goto setit;
		case IFM_10_T:
			speed = BRGPHY_S10;
setit:
			brgphy_loop(sc);
			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
				speed |= BRGPHY_BMCR_FDX;
				gig = BRGPHY_1000CTL_AFD;
			} else {
				gig = BRGPHY_1000CTL_AHD;
			}

			PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0);
			PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE);
			PHY_WRITE(sc, BRGPHY_MII_BMCR, speed);

			if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) &&
			    (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) &&
			    (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX))
				break;

			PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig);
			PHY_WRITE(sc, BRGPHY_MII_BMCR,
			    speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG);

			if (sc->mii_model != MII_MODEL_xxBROADCOM_BCM5701)
 				break;

			if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
				gig |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC;
			PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig);
			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 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)
			break;

		/*
		 * Only retry autonegotiation every mii_anegticks seconds.
		 */
		if (++sc->mii_ticks <= sc->mii_anegticks)
			break;

		sc->mii_ticks = 0;
		brgphy_mii_phy_auto(sc);
		break;
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/*
	 * Callback if something changed. Note that we need to poke the DSP on
	 * the Broadcom 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) {
		switch (sc->mii_model) {
		case MII_MODEL_BROADCOM_BCM5400:
			brgphy_bcm5401_dspcode(sc);
			break;
		case MII_MODEL_xxBROADCOM_BCM5401:
			if (sc->mii_rev == 1 || sc->mii_rev == 3)
				brgphy_bcm5401_dspcode(sc);
			break;
		case MII_MODEL_xxBROADCOM_BCM5411:
			brgphy_bcm5411_dspcode(sc);
			break;
		}
	}

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);

	return (0);
}
예제 #26
0
static int
ciphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
    struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    int reg, speed, gig;

    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;

        ciphy_fixup(sc);	/* XXX hardware bug work-around */

        switch (IFM_SUBTYPE(ife->ifm_media)) {
        case IFM_AUTO:
#ifdef foo
            /*
             * If we're already in auto mode, just return.
             */
            if (PHY_READ(sc, CIPHY_MII_BMCR) & CIPHY_BMCR_AUTOEN)
                return (0);
#endif
            (void) mii_phy_auto(sc);
            break;
        case IFM_1000_T:
            speed = CIPHY_S1000;
            goto setit;
        case IFM_100_TX:
            speed = CIPHY_S100;
            goto setit;
        case IFM_10_T:
            speed = CIPHY_S10;
setit:
            if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
                speed |= CIPHY_BMCR_FDX;
                gig = CIPHY_1000CTL_AFD;
            } else {
                gig = CIPHY_1000CTL_AHD;
            }

            PHY_WRITE(sc, CIPHY_MII_1000CTL, 0);
            PHY_WRITE(sc, CIPHY_MII_BMCR, speed);
            PHY_WRITE(sc, CIPHY_MII_ANAR, CIPHY_SEL_TYPE);

            if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
                break;

            PHY_WRITE(sc, CIPHY_MII_1000CTL, gig);
            PHY_WRITE(sc, CIPHY_MII_BMCR,
                      speed|CIPHY_BMCR_AUTOEN|CIPHY_BMCR_STARTNEG);

            /*
             * 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, CIPHY_MII_1000CTL,
                          gig|CIPHY_1000CTL_MSE|CIPHY_1000CTL_MSC);
            } else {
                PHY_WRITE(sc, CIPHY_MII_1000CTL,
                          gig|CIPHY_1000CTL_MSE);
            }
            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)
            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)
            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)
            break;

        sc->mii_ticks = 0;
        mii_phy_auto(sc);
        break;
    }

    /* Update the media status. */
    ciphy_status(sc);

    /*
     * Callback if something changed. Note that we need to poke
     * apply fixups for certain PHY revs.
     */
    if (sc->mii_media_active != mii->mii_media_active ||
            sc->mii_media_status != mii->mii_media_status ||
            cmd == MII_MEDIACHG) {
        ciphy_fixup(sc);
    }
    mii_phy_update(sc, cmd);
    return (0);
}
예제 #27
0
static int
jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	uint16_t bmcr;

	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 (jmphy_auto(sc, ife) != EJUSTRETURN)
			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. */
		if (PHY_READ(sc, JMPHY_SSR) & JMPHY_SSR_LINK_UP) {
			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;
		jmphy_auto(sc, ife);
		break;
	}

	/* Update the media status. */
	jmphy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #28
0
int
eephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int bmcr;

	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 media indicates a different PHY instance,
		 * isolate ourselves.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
			bmcr = PHY_READ(sc, E1000_CR);
			PHY_WRITE(sc, E1000_CR, bmcr | 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;

		mii_phy_setmedia(sc);

		/*
		 * If autonegitation is not enabled, we need a
		 * software reset for the settings to take effect.
		 */
		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
			bmcr = PHY_READ(sc, E1000_CR);
			PHY_WRITE(sc, E1000_CR, bmcr | E1000_CR_RESET);
		}
		break;

	case MII_TICK:
		/*
		 * If we're not currently selected, just return.
		 */
		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
			return (0);

		if (mii_phy_tick(sc) == EJUSTRETURN)
                        return (0);
		break;

	case MII_DOWN:
		mii_phy_down(sc);
                return (0);
	}

	/* Update the media status. */
	mii_phy_status(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
예제 #29
0
int
eephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
	int reg;

	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 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);
			}
			eephy_reset(sc);
			(void)eephy_mii_phy_auto(sc, 1);
			break;

		case IFM_1000_TX:
			if (sc->mii_flags & MIIF_DOINGAUTO)
				return (0);

			eephy_reset(sc);

			/* TODO - any other way to force 1000BT? */
			(void)eephy_mii_phy_auto(sc, 1);
			break;

		case IFM_100_TX:
			eephy_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:
			eephy_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.
		 */
#ifndef PMON
		if (++(sc->mii_ticks) != sc->mii_anegticks) {
#else
		if (++(sc->mii_ticks) != 5) {
#endif
			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;

		eephy_reset(sc);

		if (eephy_mii_phy_auto(sc, 0) == EJUSTRETURN) {
			return(0);
		}

		break;
	}

	/* Update the media status. */
	eephy_status(sc);

	/* Callback if something changed. */
#ifndef PMON
	mii_phy_update(sc, cmd);
#else
	if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
		(*mii->mii_statchg)(sc->mii_dev.dv_parent);
		sc->mii_active = mii->mii_media_active;
	}
#endif

	return (0);
}

void
eephy_status(struct mii_softc *sc)
{
	struct mii_data *mii = sc->mii_pdata;
	int bmsr, bmcr, esr, ssr, isr, ar, lpar;

	if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
		return;

	mii->mii_media_status = IFM_AVALID;
	mii->mii_media_active = IFM_ETHER;

	bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR);
	esr = PHY_READ(sc, E1000_ESR);
	bmcr = PHY_READ(sc, E1000_CR);
	ssr = PHY_READ(sc, E1000_SSR);
	isr = PHY_READ(sc, E1000_ISR);
	ar = PHY_READ(sc, E1000_AR);
	lpar = PHY_READ(sc, E1000_LPAR);

	if (bmsr & E1000_SR_LINK_STATUS)
		mii->mii_media_status |= IFM_ACTIVE;

	if (bmcr & E1000_CR_LOOPBACK)
		mii->mii_media_active |= IFM_LOOP;

	if ((sc->mii_flags & MIIF_DOINGAUTO) &&
	    (!(bmsr & E1000_SR_AUTO_NEG_COMPLETE) || !(ssr & E1000_SSR_LINK) ||
	    !(ssr & E1000_SSR_SPD_DPLX_RESOLVED))) {
		/* Erg, still trying, I guess... */
		mii->mii_media_active |= IFM_NONE;
		return;
	}

	if (ssr & E1000_SSR_1000MBS)
		mii->mii_media_active |= IFM_1000_TX;
	else if (ssr & E1000_SSR_100MBS)
		mii->mii_media_active |= IFM_100_TX;
	else
		mii->mii_media_active |= IFM_10_T;

	if (ssr & E1000_SSR_DUPLEX)
		mii->mii_media_active |= IFM_FDX;
	else
		mii->mii_media_active |= IFM_HDX;

	/* FLAG0==rx-flow-control FLAG1==tx-flow-control */
	if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) {
		mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1;
	} else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
	    (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
		mii->mii_media_active |= IFM_FLAG1;
	} else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
	    !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
		mii->mii_media_active |= IFM_FLAG0;
	}
}

static int
eephy_mii_phy_auto(struct mii_softc *sc, int waitfor)
{
	int bmsr, i;

	if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) {
		PHY_WRITE(sc, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD |
		    E1000_AR_100TX | E1000_AR_100TX_FD | 
		    E1000_AR_PAUSE | E1000_AR_ASM_DIR);
		PHY_WRITE(sc, E1000_1GCR, E1000_1GCR_1000T_FD);
		PHY_WRITE(sc, E1000_CR,
		    E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG);
	}

	if (waitfor) {
		/* Wait 500ms for it to complete. */
		for (i = 0; i < 500; i++) {
			bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR);

			if (bmsr & E1000_SR_AUTO_NEG_COMPLETE) {
				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. [do it anyway]
		 */
		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;
		sc->mii_ticks = 0;
#ifndef PMON
		timeout_set(&sc->mii_phy_timo, mii_phy_auto_timeout, sc);
		timeout_add(&sc->mii_phy_timo, hz >> 1);
#else
		timeout(mii_phy_auto_timeout, sc, hz >> 1);
#endif
	}