xref: /openbmc/linux/drivers/net/mii.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds 
31da177e4SLinus Torvalds 	mii.c: MII interface library
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds 	Maintained by Jeff Garzik <jgarzik@pobox.com>
61da177e4SLinus Torvalds 	Copyright 2001,2002 Jeff Garzik
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds 	Various code came from myson803.c and other files by
91da177e4SLinus Torvalds 	Donald Becker.  Copyright:
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds 		Written 1998-2002 by Donald Becker.
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds 		This software may be used and distributed according
141da177e4SLinus Torvalds 		to the terms of the GNU General Public License (GPL),
151da177e4SLinus Torvalds 		incorporated herein by reference.  Drivers based on
161da177e4SLinus Torvalds 		or derived from this code fall under the GPL and must
171da177e4SLinus Torvalds 		retain the authorship, copyright and license notice.
181da177e4SLinus Torvalds 		This file is not a complete program and may only be
191da177e4SLinus Torvalds 		used when the entire operating system is licensed
201da177e4SLinus Torvalds 		under the GPL.
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds 		The author may be reached as becker@scyld.com, or C/O
231da177e4SLinus Torvalds 		Scyld Computing Corporation
241da177e4SLinus Torvalds 		410 Severn Ave., Suite 210
251da177e4SLinus Torvalds 		Annapolis MD 21403
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds  */
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/kernel.h>
311da177e4SLinus Torvalds #include <linux/module.h>
321da177e4SLinus Torvalds #include <linux/netdevice.h>
331da177e4SLinus Torvalds #include <linux/ethtool.h>
349c4df53bSBen Hutchings #include <linux/mii.h>
355974700cSBen Hutchings 
mii_get_an(struct mii_if_info * mii,u16 addr)365974700cSBen Hutchings static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
375974700cSBen Hutchings {
385974700cSBen Hutchings 	int advert;
395974700cSBen Hutchings 
405974700cSBen Hutchings 	advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
415974700cSBen Hutchings 
4237f07023SMatt Carlson 	return mii_lpa_to_ethtool_lpa_t(advert);
435974700cSBen Hutchings }
441da177e4SLinus Torvalds 
4532684ec6SRandy Dunlap /**
4632684ec6SRandy Dunlap  * mii_ethtool_gset - get settings that are specified in @ecmd
4732684ec6SRandy Dunlap  * @mii: MII interface
4832684ec6SRandy Dunlap  * @ecmd: requested ethtool_cmd
4932684ec6SRandy Dunlap  *
508ae6dacaSDavid Decotigny  * The @ecmd parameter is expected to have been cleared before calling
518ae6dacaSDavid Decotigny  * mii_ethtool_gset().
5232684ec6SRandy Dunlap  */
mii_ethtool_gset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)53*2274af1dSPavel Skripkin void mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
541da177e4SLinus Torvalds {
551da177e4SLinus Torvalds 	struct net_device *dev = mii->dev;
565974700cSBen Hutchings 	u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
575974700cSBen Hutchings 	u32 nego;
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	ecmd->supported =
601da177e4SLinus Torvalds 	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
611da177e4SLinus Torvalds 	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
621da177e4SLinus Torvalds 	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
631da177e4SLinus Torvalds 	if (mii->supports_gmii)
641da177e4SLinus Torvalds 		ecmd->supported |= SUPPORTED_1000baseT_Half |
651da177e4SLinus Torvalds 			SUPPORTED_1000baseT_Full;
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 	/* only supports twisted-pair */
681da177e4SLinus Torvalds 	ecmd->port = PORT_MII;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	/* only supports internal transceiver */
711da177e4SLinus Torvalds 	ecmd->transceiver = XCVR_INTERNAL;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	/* this isn't fully supported at higher layers */
741da177e4SLinus Torvalds 	ecmd->phy_address = mii->phy_id;
759c4df53bSBen Hutchings 	ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22;
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
805974700cSBen Hutchings 	bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
811da177e4SLinus Torvalds 	if (mii->supports_gmii) {
825974700cSBen Hutchings 		ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
835974700cSBen Hutchings 		stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
841da177e4SLinus Torvalds 	}
851da177e4SLinus Torvalds 
865974700cSBen Hutchings 	ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
8728011cf1SMatt Carlson 	if (mii->supports_gmii)
8837f07023SMatt Carlson 		ecmd->advertising |=
8937f07023SMatt Carlson 			mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
905974700cSBen Hutchings 
918027c85cSŁukasz Stelmach 	if (bmcr & BMCR_ANENABLE) {
928027c85cSŁukasz Stelmach 		ecmd->advertising |= ADVERTISED_Autoneg;
938027c85cSŁukasz Stelmach 		ecmd->autoneg = AUTONEG_ENABLE;
948027c85cSŁukasz Stelmach 
955974700cSBen Hutchings 		if (bmsr & BMSR_ANEGCOMPLETE) {
965974700cSBen Hutchings 			ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
975974700cSBen Hutchings 			ecmd->lp_advertising |=
9837f07023SMatt Carlson 					mii_stat1000_to_ethtool_lpa_t(stat1000);
991da177e4SLinus Torvalds 		} else {
1005974700cSBen Hutchings 			ecmd->lp_advertising = 0;
1015974700cSBen Hutchings 		}
1025974700cSBen Hutchings 
1035974700cSBen Hutchings 		nego = ecmd->advertising & ecmd->lp_advertising;
1045974700cSBen Hutchings 
1055974700cSBen Hutchings 		if (nego & (ADVERTISED_1000baseT_Full |
1065974700cSBen Hutchings 			    ADVERTISED_1000baseT_Half)) {
10770739497SDavid Decotigny 			ethtool_cmd_speed_set(ecmd, SPEED_1000);
1085974700cSBen Hutchings 			ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
1095974700cSBen Hutchings 		} else if (nego & (ADVERTISED_100baseT_Full |
1105974700cSBen Hutchings 				   ADVERTISED_100baseT_Half)) {
11170739497SDavid Decotigny 			ethtool_cmd_speed_set(ecmd, SPEED_100);
1125974700cSBen Hutchings 			ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
1135974700cSBen Hutchings 		} else {
11470739497SDavid Decotigny 			ethtool_cmd_speed_set(ecmd, SPEED_10);
1155974700cSBen Hutchings 			ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
1161da177e4SLinus Torvalds 		}
1171da177e4SLinus Torvalds 	} else {
1181da177e4SLinus Torvalds 		ecmd->autoneg = AUTONEG_DISABLE;
1191da177e4SLinus Torvalds 
12070739497SDavid Decotigny 		ethtool_cmd_speed_set(ecmd,
12170739497SDavid Decotigny 				      ((bmcr & BMCR_SPEED1000 &&
12270739497SDavid Decotigny 					(bmcr & BMCR_SPEED100) == 0) ?
12370739497SDavid Decotigny 				       SPEED_1000 :
12470739497SDavid Decotigny 				       ((bmcr & BMCR_SPEED100) ?
12570739497SDavid Decotigny 					SPEED_100 : SPEED_10)));
1261da177e4SLinus Torvalds 		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
1271da177e4SLinus Torvalds 	}
1281da177e4SLinus Torvalds 
1295974700cSBen Hutchings 	mii->full_duplex = ecmd->duplex;
1305974700cSBen Hutchings 
1311da177e4SLinus Torvalds 	/* ignore maxtxpkt, maxrxpkt for now */
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds 
13432684ec6SRandy Dunlap /**
135bc8ee596SPhilippe Reynes  * mii_ethtool_get_link_ksettings - get settings that are specified in @cmd
136bc8ee596SPhilippe Reynes  * @mii: MII interface
137bc8ee596SPhilippe Reynes  * @cmd: requested ethtool_link_ksettings
138bc8ee596SPhilippe Reynes  *
139bc8ee596SPhilippe Reynes  * The @cmd parameter is expected to have been cleared before calling
140bc8ee596SPhilippe Reynes  * mii_ethtool_get_link_ksettings().
141bc8ee596SPhilippe Reynes  */
mii_ethtool_get_link_ksettings(struct mii_if_info * mii,struct ethtool_link_ksettings * cmd)14282c01a84Syuval.shaia@oracle.com void mii_ethtool_get_link_ksettings(struct mii_if_info *mii,
143bc8ee596SPhilippe Reynes 				    struct ethtool_link_ksettings *cmd)
144bc8ee596SPhilippe Reynes {
145bc8ee596SPhilippe Reynes 	struct net_device *dev = mii->dev;
146bc8ee596SPhilippe Reynes 	u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
147bc8ee596SPhilippe Reynes 	u32 nego, supported, advertising, lp_advertising;
148bc8ee596SPhilippe Reynes 
149bc8ee596SPhilippe Reynes 	supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
150bc8ee596SPhilippe Reynes 		     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
151bc8ee596SPhilippe Reynes 		     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
152bc8ee596SPhilippe Reynes 	if (mii->supports_gmii)
153bc8ee596SPhilippe Reynes 		supported |= SUPPORTED_1000baseT_Half |
154bc8ee596SPhilippe Reynes 			SUPPORTED_1000baseT_Full;
155bc8ee596SPhilippe Reynes 
156bc8ee596SPhilippe Reynes 	/* only supports twisted-pair */
157bc8ee596SPhilippe Reynes 	cmd->base.port = PORT_MII;
158bc8ee596SPhilippe Reynes 
159bc8ee596SPhilippe Reynes 	/* this isn't fully supported at higher layers */
160bc8ee596SPhilippe Reynes 	cmd->base.phy_address = mii->phy_id;
161bc8ee596SPhilippe Reynes 	cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
162bc8ee596SPhilippe Reynes 
163bc8ee596SPhilippe Reynes 	advertising = ADVERTISED_TP | ADVERTISED_MII;
164bc8ee596SPhilippe Reynes 
165bc8ee596SPhilippe Reynes 	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
166bc8ee596SPhilippe Reynes 	bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
167bc8ee596SPhilippe Reynes 	if (mii->supports_gmii) {
168bc8ee596SPhilippe Reynes 		ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
169bc8ee596SPhilippe Reynes 		stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
170bc8ee596SPhilippe Reynes 	}
171bc8ee596SPhilippe Reynes 
172bc8ee596SPhilippe Reynes 	advertising |= mii_get_an(mii, MII_ADVERTISE);
173bc8ee596SPhilippe Reynes 	if (mii->supports_gmii)
174bc8ee596SPhilippe Reynes 		advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
175bc8ee596SPhilippe Reynes 
1768027c85cSŁukasz Stelmach 	if (bmcr & BMCR_ANENABLE) {
1778027c85cSŁukasz Stelmach 		advertising |= ADVERTISED_Autoneg;
1788027c85cSŁukasz Stelmach 		cmd->base.autoneg = AUTONEG_ENABLE;
1798027c85cSŁukasz Stelmach 
180bc8ee596SPhilippe Reynes 		if (bmsr & BMSR_ANEGCOMPLETE) {
181bc8ee596SPhilippe Reynes 			lp_advertising = mii_get_an(mii, MII_LPA);
182bc8ee596SPhilippe Reynes 			lp_advertising |=
183bc8ee596SPhilippe Reynes 					mii_stat1000_to_ethtool_lpa_t(stat1000);
184bc8ee596SPhilippe Reynes 		} else {
185bc8ee596SPhilippe Reynes 			lp_advertising = 0;
186bc8ee596SPhilippe Reynes 		}
187bc8ee596SPhilippe Reynes 
188bc8ee596SPhilippe Reynes 		nego = advertising & lp_advertising;
189bc8ee596SPhilippe Reynes 
190bc8ee596SPhilippe Reynes 		if (nego & (ADVERTISED_1000baseT_Full |
191bc8ee596SPhilippe Reynes 			    ADVERTISED_1000baseT_Half)) {
192bc8ee596SPhilippe Reynes 			cmd->base.speed = SPEED_1000;
193bc8ee596SPhilippe Reynes 			cmd->base.duplex = !!(nego & ADVERTISED_1000baseT_Full);
194bc8ee596SPhilippe Reynes 		} else if (nego & (ADVERTISED_100baseT_Full |
195bc8ee596SPhilippe Reynes 				   ADVERTISED_100baseT_Half)) {
196bc8ee596SPhilippe Reynes 			cmd->base.speed = SPEED_100;
197bc8ee596SPhilippe Reynes 			cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full);
198bc8ee596SPhilippe Reynes 		} else {
199bc8ee596SPhilippe Reynes 			cmd->base.speed = SPEED_10;
200bc8ee596SPhilippe Reynes 			cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full);
201bc8ee596SPhilippe Reynes 		}
202bc8ee596SPhilippe Reynes 	} else {
203bc8ee596SPhilippe Reynes 		cmd->base.autoneg = AUTONEG_DISABLE;
204bc8ee596SPhilippe Reynes 
205bc8ee596SPhilippe Reynes 		cmd->base.speed = ((bmcr & BMCR_SPEED1000 &&
206bc8ee596SPhilippe Reynes 				    (bmcr & BMCR_SPEED100) == 0) ?
207bc8ee596SPhilippe Reynes 				   SPEED_1000 :
208bc8ee596SPhilippe Reynes 				   ((bmcr & BMCR_SPEED100) ?
209bc8ee596SPhilippe Reynes 				    SPEED_100 : SPEED_10));
210bc8ee596SPhilippe Reynes 		cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
211bc8ee596SPhilippe Reynes 			DUPLEX_FULL : DUPLEX_HALF;
212dc0b2c9cSArnd Bergmann 
213dc0b2c9cSArnd Bergmann 		lp_advertising = 0;
214bc8ee596SPhilippe Reynes 	}
215bc8ee596SPhilippe Reynes 
216bc8ee596SPhilippe Reynes 	mii->full_duplex = cmd->base.duplex;
217bc8ee596SPhilippe Reynes 
218bc8ee596SPhilippe Reynes 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
219bc8ee596SPhilippe Reynes 						supported);
220bc8ee596SPhilippe Reynes 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
221bc8ee596SPhilippe Reynes 						advertising);
222bc8ee596SPhilippe Reynes 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
223bc8ee596SPhilippe Reynes 						lp_advertising);
224bc8ee596SPhilippe Reynes 
225bc8ee596SPhilippe Reynes 	/* ignore maxtxpkt, maxrxpkt for now */
226bc8ee596SPhilippe Reynes }
227bc8ee596SPhilippe Reynes 
228bc8ee596SPhilippe Reynes /**
22932684ec6SRandy Dunlap  * mii_ethtool_sset - set settings that are specified in @ecmd
23032684ec6SRandy Dunlap  * @mii: MII interface
23132684ec6SRandy Dunlap  * @ecmd: requested ethtool_cmd
23232684ec6SRandy Dunlap  *
23332684ec6SRandy Dunlap  * Returns 0 for success, negative on error.
23432684ec6SRandy Dunlap  */
mii_ethtool_sset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)2351da177e4SLinus Torvalds int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
2361da177e4SLinus Torvalds {
2371da177e4SLinus Torvalds 	struct net_device *dev = mii->dev;
23825db0338SDavid Decotigny 	u32 speed = ethtool_cmd_speed(ecmd);
2391da177e4SLinus Torvalds 
24025db0338SDavid Decotigny 	if (speed != SPEED_10 &&
24125db0338SDavid Decotigny 	    speed != SPEED_100 &&
24225db0338SDavid Decotigny 	    speed != SPEED_1000)
2431da177e4SLinus Torvalds 		return -EINVAL;
2441da177e4SLinus Torvalds 	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
2451da177e4SLinus Torvalds 		return -EINVAL;
2461da177e4SLinus Torvalds 	if (ecmd->port != PORT_MII)
2471da177e4SLinus Torvalds 		return -EINVAL;
2481da177e4SLinus Torvalds 	if (ecmd->transceiver != XCVR_INTERNAL)
2491da177e4SLinus Torvalds 		return -EINVAL;
2501da177e4SLinus Torvalds 	if (ecmd->phy_address != mii->phy_id)
2511da177e4SLinus Torvalds 		return -EINVAL;
2521da177e4SLinus Torvalds 	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
2531da177e4SLinus Torvalds 		return -EINVAL;
25425db0338SDavid Decotigny 	if ((speed == SPEED_1000) && (!mii->supports_gmii))
2551da177e4SLinus Torvalds 		return -EINVAL;
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 	/* ignore supported, maxtxpkt, maxrxpkt */
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	if (ecmd->autoneg == AUTONEG_ENABLE) {
2601da177e4SLinus Torvalds 		u32 bmcr, advert, tmp;
2611da177e4SLinus Torvalds 		u32 advert2 = 0, tmp2 = 0;
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
2641da177e4SLinus Torvalds 					  ADVERTISED_10baseT_Full |
2651da177e4SLinus Torvalds 					  ADVERTISED_100baseT_Half |
2661da177e4SLinus Torvalds 					  ADVERTISED_100baseT_Full |
2671da177e4SLinus Torvalds 					  ADVERTISED_1000baseT_Half |
2681da177e4SLinus Torvalds 					  ADVERTISED_1000baseT_Full)) == 0)
2691da177e4SLinus Torvalds 			return -EINVAL;
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 		/* advertise only what has been requested */
2721da177e4SLinus Torvalds 		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
2731da177e4SLinus Torvalds 		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
2741da177e4SLinus Torvalds 		if (mii->supports_gmii) {
2751da177e4SLinus Torvalds 			advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
2761da177e4SLinus Torvalds 			tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
2771da177e4SLinus Torvalds 		}
27837f07023SMatt Carlson 		tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
27928011cf1SMatt Carlson 
28028011cf1SMatt Carlson 		if (mii->supports_gmii)
28137f07023SMatt Carlson 			tmp2 |=
28237f07023SMatt Carlson 			      ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
2831da177e4SLinus Torvalds 		if (advert != tmp) {
2841da177e4SLinus Torvalds 			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
2851da177e4SLinus Torvalds 			mii->advertising = tmp;
2861da177e4SLinus Torvalds 		}
2871da177e4SLinus Torvalds 		if ((mii->supports_gmii) && (advert2 != tmp2))
2881da177e4SLinus Torvalds 			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 		/* turn on autonegotiation, and force a renegotiate */
2911da177e4SLinus Torvalds 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
2921da177e4SLinus Torvalds 		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
2931da177e4SLinus Torvalds 		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 		mii->force_media = 0;
2961da177e4SLinus Torvalds 	} else {
2971da177e4SLinus Torvalds 		u32 bmcr, tmp;
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 		/* turn off auto negotiation, set speed and duplexity */
3001da177e4SLinus Torvalds 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
3011da177e4SLinus Torvalds 		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
3021da177e4SLinus Torvalds 			       BMCR_SPEED1000 | BMCR_FULLDPLX);
30325db0338SDavid Decotigny 		if (speed == SPEED_1000)
3041da177e4SLinus Torvalds 			tmp |= BMCR_SPEED1000;
30525db0338SDavid Decotigny 		else if (speed == SPEED_100)
3061da177e4SLinus Torvalds 			tmp |= BMCR_SPEED100;
3071da177e4SLinus Torvalds 		if (ecmd->duplex == DUPLEX_FULL) {
3081da177e4SLinus Torvalds 			tmp |= BMCR_FULLDPLX;
3091da177e4SLinus Torvalds 			mii->full_duplex = 1;
3101da177e4SLinus Torvalds 		} else
3111da177e4SLinus Torvalds 			mii->full_duplex = 0;
3121da177e4SLinus Torvalds 		if (bmcr != tmp)
3131da177e4SLinus Torvalds 			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 		mii->force_media = 1;
3161da177e4SLinus Torvalds 	}
3171da177e4SLinus Torvalds 	return 0;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
32032684ec6SRandy Dunlap /**
321bc8ee596SPhilippe Reynes  * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
322bc8ee596SPhilippe Reynes  * @mii: MII interfaces
323bc8ee596SPhilippe Reynes  * @cmd: requested ethtool_link_ksettings
324bc8ee596SPhilippe Reynes  *
325bc8ee596SPhilippe Reynes  * Returns 0 for success, negative on error.
326bc8ee596SPhilippe Reynes  */
mii_ethtool_set_link_ksettings(struct mii_if_info * mii,const struct ethtool_link_ksettings * cmd)327bc8ee596SPhilippe Reynes int mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
328bc8ee596SPhilippe Reynes 				   const struct ethtool_link_ksettings *cmd)
329bc8ee596SPhilippe Reynes {
330bc8ee596SPhilippe Reynes 	struct net_device *dev = mii->dev;
331bc8ee596SPhilippe Reynes 	u32 speed = cmd->base.speed;
332bc8ee596SPhilippe Reynes 
333bc8ee596SPhilippe Reynes 	if (speed != SPEED_10 &&
334bc8ee596SPhilippe Reynes 	    speed != SPEED_100 &&
335bc8ee596SPhilippe Reynes 	    speed != SPEED_1000)
336bc8ee596SPhilippe Reynes 		return -EINVAL;
337bc8ee596SPhilippe Reynes 	if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
338bc8ee596SPhilippe Reynes 		return -EINVAL;
339bc8ee596SPhilippe Reynes 	if (cmd->base.port != PORT_MII)
340bc8ee596SPhilippe Reynes 		return -EINVAL;
341bc8ee596SPhilippe Reynes 	if (cmd->base.phy_address != mii->phy_id)
342bc8ee596SPhilippe Reynes 		return -EINVAL;
343bc8ee596SPhilippe Reynes 	if (cmd->base.autoneg != AUTONEG_DISABLE &&
344bc8ee596SPhilippe Reynes 	    cmd->base.autoneg != AUTONEG_ENABLE)
345bc8ee596SPhilippe Reynes 		return -EINVAL;
346bc8ee596SPhilippe Reynes 	if ((speed == SPEED_1000) && (!mii->supports_gmii))
347bc8ee596SPhilippe Reynes 		return -EINVAL;
348bc8ee596SPhilippe Reynes 
349bc8ee596SPhilippe Reynes 	/* ignore supported, maxtxpkt, maxrxpkt */
350bc8ee596SPhilippe Reynes 
351bc8ee596SPhilippe Reynes 	if (cmd->base.autoneg == AUTONEG_ENABLE) {
352bc8ee596SPhilippe Reynes 		u32 bmcr, advert, tmp;
353bc8ee596SPhilippe Reynes 		u32 advert2 = 0, tmp2 = 0;
354bc8ee596SPhilippe Reynes 		u32 advertising;
355bc8ee596SPhilippe Reynes 
356bc8ee596SPhilippe Reynes 		ethtool_convert_link_mode_to_legacy_u32(
357bc8ee596SPhilippe Reynes 			&advertising, cmd->link_modes.advertising);
358bc8ee596SPhilippe Reynes 
359bc8ee596SPhilippe Reynes 		if ((advertising & (ADVERTISED_10baseT_Half |
360bc8ee596SPhilippe Reynes 				    ADVERTISED_10baseT_Full |
361bc8ee596SPhilippe Reynes 				    ADVERTISED_100baseT_Half |
362bc8ee596SPhilippe Reynes 				    ADVERTISED_100baseT_Full |
363bc8ee596SPhilippe Reynes 				    ADVERTISED_1000baseT_Half |
364bc8ee596SPhilippe Reynes 				    ADVERTISED_1000baseT_Full)) == 0)
365bc8ee596SPhilippe Reynes 			return -EINVAL;
366bc8ee596SPhilippe Reynes 
367bc8ee596SPhilippe Reynes 		/* advertise only what has been requested */
368bc8ee596SPhilippe Reynes 		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
369bc8ee596SPhilippe Reynes 		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
370bc8ee596SPhilippe Reynes 		if (mii->supports_gmii) {
371bc8ee596SPhilippe Reynes 			advert2 = mii->mdio_read(dev, mii->phy_id,
372bc8ee596SPhilippe Reynes 						 MII_CTRL1000);
373bc8ee596SPhilippe Reynes 			tmp2 = advert2 &
374bc8ee596SPhilippe Reynes 				~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
375bc8ee596SPhilippe Reynes 		}
376bc8ee596SPhilippe Reynes 		tmp |= ethtool_adv_to_mii_adv_t(advertising);
377bc8ee596SPhilippe Reynes 
378bc8ee596SPhilippe Reynes 		if (mii->supports_gmii)
379bc8ee596SPhilippe Reynes 			tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
380bc8ee596SPhilippe Reynes 		if (advert != tmp) {
381bc8ee596SPhilippe Reynes 			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
382bc8ee596SPhilippe Reynes 			mii->advertising = tmp;
383bc8ee596SPhilippe Reynes 		}
384bc8ee596SPhilippe Reynes 		if ((mii->supports_gmii) && (advert2 != tmp2))
385bc8ee596SPhilippe Reynes 			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
386bc8ee596SPhilippe Reynes 
387bc8ee596SPhilippe Reynes 		/* turn on autonegotiation, and force a renegotiate */
388bc8ee596SPhilippe Reynes 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
389bc8ee596SPhilippe Reynes 		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
390bc8ee596SPhilippe Reynes 		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
391bc8ee596SPhilippe Reynes 
392bc8ee596SPhilippe Reynes 		mii->force_media = 0;
393bc8ee596SPhilippe Reynes 	} else {
394bc8ee596SPhilippe Reynes 		u32 bmcr, tmp;
395bc8ee596SPhilippe Reynes 
396bc8ee596SPhilippe Reynes 		/* turn off auto negotiation, set speed and duplexity */
397bc8ee596SPhilippe Reynes 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
398bc8ee596SPhilippe Reynes 		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
399bc8ee596SPhilippe Reynes 			       BMCR_SPEED1000 | BMCR_FULLDPLX);
400bc8ee596SPhilippe Reynes 		if (speed == SPEED_1000)
401bc8ee596SPhilippe Reynes 			tmp |= BMCR_SPEED1000;
402bc8ee596SPhilippe Reynes 		else if (speed == SPEED_100)
403bc8ee596SPhilippe Reynes 			tmp |= BMCR_SPEED100;
404bc8ee596SPhilippe Reynes 		if (cmd->base.duplex == DUPLEX_FULL) {
405bc8ee596SPhilippe Reynes 			tmp |= BMCR_FULLDPLX;
406bc8ee596SPhilippe Reynes 			mii->full_duplex = 1;
407bc8ee596SPhilippe Reynes 		} else {
408bc8ee596SPhilippe Reynes 			mii->full_duplex = 0;
409bc8ee596SPhilippe Reynes 		}
410bc8ee596SPhilippe Reynes 		if (bmcr != tmp)
411bc8ee596SPhilippe Reynes 			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
412bc8ee596SPhilippe Reynes 
413bc8ee596SPhilippe Reynes 		mii->force_media = 1;
414bc8ee596SPhilippe Reynes 	}
415bc8ee596SPhilippe Reynes 	return 0;
416bc8ee596SPhilippe Reynes }
417bc8ee596SPhilippe Reynes 
418bc8ee596SPhilippe Reynes /**
41932684ec6SRandy Dunlap  * mii_check_gmii_support - check if the MII supports Gb interfaces
42032684ec6SRandy Dunlap  * @mii: the MII interface
42132684ec6SRandy Dunlap  */
mii_check_gmii_support(struct mii_if_info * mii)42243ec6e95SDale Farnsworth int mii_check_gmii_support(struct mii_if_info *mii)
42343ec6e95SDale Farnsworth {
42443ec6e95SDale Farnsworth 	int reg;
42543ec6e95SDale Farnsworth 
42643ec6e95SDale Farnsworth 	reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
42743ec6e95SDale Farnsworth 	if (reg & BMSR_ESTATEN) {
42843ec6e95SDale Farnsworth 		reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
42943ec6e95SDale Farnsworth 		if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
43043ec6e95SDale Farnsworth 			return 1;
43143ec6e95SDale Farnsworth 	}
43243ec6e95SDale Farnsworth 
43343ec6e95SDale Farnsworth 	return 0;
43443ec6e95SDale Farnsworth }
43543ec6e95SDale Farnsworth 
43632684ec6SRandy Dunlap /**
43732684ec6SRandy Dunlap  * mii_link_ok - is link status up/ok
43832684ec6SRandy Dunlap  * @mii: the MII interface
43932684ec6SRandy Dunlap  *
44032684ec6SRandy Dunlap  * Returns 1 if the MII reports link status up/ok, 0 otherwise.
44132684ec6SRandy Dunlap  */
mii_link_ok(struct mii_if_info * mii)4421da177e4SLinus Torvalds int mii_link_ok (struct mii_if_info *mii)
4431da177e4SLinus Torvalds {
4441da177e4SLinus Torvalds 	/* first, a dummy read, needed to latch some MII phys */
4451da177e4SLinus Torvalds 	mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
4461da177e4SLinus Torvalds 	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
4471da177e4SLinus Torvalds 		return 1;
4481da177e4SLinus Torvalds 	return 0;
4491da177e4SLinus Torvalds }
4501da177e4SLinus Torvalds 
45132684ec6SRandy Dunlap /**
45232684ec6SRandy Dunlap  * mii_nway_restart - restart NWay (autonegotiation) for this interface
45332684ec6SRandy Dunlap  * @mii: the MII interface
45432684ec6SRandy Dunlap  *
45532684ec6SRandy Dunlap  * Returns 0 on success, negative on error.
45632684ec6SRandy Dunlap  */
mii_nway_restart(struct mii_if_info * mii)4571da177e4SLinus Torvalds int mii_nway_restart (struct mii_if_info *mii)
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds 	int bmcr;
4601da177e4SLinus Torvalds 	int r = -EINVAL;
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	/* if autoneg is off, it's an error */
4631da177e4SLinus Torvalds 	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds 	if (bmcr & BMCR_ANENABLE) {
4661da177e4SLinus Torvalds 		bmcr |= BMCR_ANRESTART;
4671da177e4SLinus Torvalds 		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
4681da177e4SLinus Torvalds 		r = 0;
4691da177e4SLinus Torvalds 	}
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	return r;
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds 
47432684ec6SRandy Dunlap /**
47532684ec6SRandy Dunlap  * mii_check_link - check MII link status
47632684ec6SRandy Dunlap  * @mii: MII interface
47732684ec6SRandy Dunlap  *
47832684ec6SRandy Dunlap  * If the link status changed (previous != current), call
47932684ec6SRandy Dunlap  * netif_carrier_on() if current link status is Up or call
48032684ec6SRandy Dunlap  * netif_carrier_off() if current link status is Down.
48132684ec6SRandy Dunlap  */
mii_check_link(struct mii_if_info * mii)4821da177e4SLinus Torvalds void mii_check_link (struct mii_if_info *mii)
4831da177e4SLinus Torvalds {
4841da177e4SLinus Torvalds 	int cur_link = mii_link_ok(mii);
4851da177e4SLinus Torvalds 	int prev_link = netif_carrier_ok(mii->dev);
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	if (cur_link && !prev_link)
4881da177e4SLinus Torvalds 		netif_carrier_on(mii->dev);
4891da177e4SLinus Torvalds 	else if (prev_link && !cur_link)
4901da177e4SLinus Torvalds 		netif_carrier_off(mii->dev);
4911da177e4SLinus Torvalds }
4921da177e4SLinus Torvalds 
49332684ec6SRandy Dunlap /**
4945bdc7380SBen Hutchings  * mii_check_media - check the MII interface for a carrier/speed/duplex change
49532684ec6SRandy Dunlap  * @mii: the MII interface
49632684ec6SRandy Dunlap  * @ok_to_print: OK to print link up/down messages
49732684ec6SRandy Dunlap  * @init_media: OK to save duplex mode in @mii
49832684ec6SRandy Dunlap  *
49932684ec6SRandy Dunlap  * Returns 1 if the duplex mode changed, 0 if not.
50032684ec6SRandy Dunlap  * If the media type is forced, always returns 0.
50132684ec6SRandy Dunlap  */
mii_check_media(struct mii_if_info * mii,unsigned int ok_to_print,unsigned int init_media)5021da177e4SLinus Torvalds unsigned int mii_check_media (struct mii_if_info *mii,
5031da177e4SLinus Torvalds 			      unsigned int ok_to_print,
5041da177e4SLinus Torvalds 			      unsigned int init_media)
5051da177e4SLinus Torvalds {
5061da177e4SLinus Torvalds 	unsigned int old_carrier, new_carrier;
5071da177e4SLinus Torvalds 	int advertise, lpa, media, duplex;
5081da177e4SLinus Torvalds 	int lpa2 = 0;
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 	/* check current and old link status */
5111da177e4SLinus Torvalds 	old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
5121da177e4SLinus Torvalds 	new_carrier = (unsigned int) mii_link_ok(mii);
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	/* if carrier state did not change, this is a "bounce",
5151da177e4SLinus Torvalds 	 * just exit as everything is already set correctly
5161da177e4SLinus Torvalds 	 */
5171da177e4SLinus Torvalds 	if ((!init_media) && (old_carrier == new_carrier))
5181da177e4SLinus Torvalds 		return 0; /* duplex did not change */
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 	/* no carrier, nothing much to do */
5211da177e4SLinus Torvalds 	if (!new_carrier) {
5221da177e4SLinus Torvalds 		netif_carrier_off(mii->dev);
5231da177e4SLinus Torvalds 		if (ok_to_print)
524967faf3bSJoe Perches 			netdev_info(mii->dev, "link down\n");
5251da177e4SLinus Torvalds 		return 0; /* duplex did not change */
5261da177e4SLinus Torvalds 	}
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	/*
5291da177e4SLinus Torvalds 	 * we have carrier, see who's on the other end
5301da177e4SLinus Torvalds 	 */
5311da177e4SLinus Torvalds 	netif_carrier_on(mii->dev);
5321da177e4SLinus Torvalds 
5335bdc7380SBen Hutchings 	if (mii->force_media) {
5345bdc7380SBen Hutchings 		if (ok_to_print)
5355bdc7380SBen Hutchings 			netdev_info(mii->dev, "link up\n");
5365bdc7380SBen Hutchings 		return 0; /* duplex did not change */
5375bdc7380SBen Hutchings 	}
5385bdc7380SBen Hutchings 
5391da177e4SLinus Torvalds 	/* get MII advertise and LPA values */
5401da177e4SLinus Torvalds 	if ((!init_media) && (mii->advertising))
5411da177e4SLinus Torvalds 		advertise = mii->advertising;
5421da177e4SLinus Torvalds 	else {
5431da177e4SLinus Torvalds 		advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
5441da177e4SLinus Torvalds 		mii->advertising = advertise;
5451da177e4SLinus Torvalds 	}
5461da177e4SLinus Torvalds 	lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
5471da177e4SLinus Torvalds 	if (mii->supports_gmii)
5481da177e4SLinus Torvalds 		lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	/* figure out media and duplex from advertise and LPA values */
5511da177e4SLinus Torvalds 	media = mii_nway_result(lpa & advertise);
5521da177e4SLinus Torvalds 	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
5531da177e4SLinus Torvalds 	if (lpa2 & LPA_1000FULL)
5541da177e4SLinus Torvalds 		duplex = 1;
5551da177e4SLinus Torvalds 
5561da177e4SLinus Torvalds 	if (ok_to_print)
557967faf3bSJoe Perches 		netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
558967faf3bSJoe Perches 			    lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
559967faf3bSJoe Perches 			    media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
560967faf3bSJoe Perches 			    100 : 10,
5611da177e4SLinus Torvalds 			    duplex ? "full" : "half",
5621da177e4SLinus Torvalds 			    lpa);
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds 	if ((init_media) || (mii->full_duplex != duplex)) {
5651da177e4SLinus Torvalds 		mii->full_duplex = duplex;
5661da177e4SLinus Torvalds 		return 1; /* duplex changed */
5671da177e4SLinus Torvalds 	}
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	return 0; /* duplex did not change */
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds 
57232684ec6SRandy Dunlap /**
57332684ec6SRandy Dunlap  * generic_mii_ioctl - main MII ioctl interface
57432684ec6SRandy Dunlap  * @mii_if: the MII interface
57532684ec6SRandy Dunlap  * @mii_data: MII ioctl data structure
57632684ec6SRandy Dunlap  * @cmd: MII ioctl command
57732684ec6SRandy Dunlap  * @duplex_chg_out: pointer to @duplex_changed status if there was no
57832684ec6SRandy Dunlap  *	ioctl error
57932684ec6SRandy Dunlap  *
58032684ec6SRandy Dunlap  * Returns 0 on success, negative on error.
58132684ec6SRandy Dunlap  */
generic_mii_ioctl(struct mii_if_info * mii_if,struct mii_ioctl_data * mii_data,int cmd,unsigned int * duplex_chg_out)5821da177e4SLinus Torvalds int generic_mii_ioctl(struct mii_if_info *mii_if,
5831da177e4SLinus Torvalds 		      struct mii_ioctl_data *mii_data, int cmd,
5841da177e4SLinus Torvalds 		      unsigned int *duplex_chg_out)
5851da177e4SLinus Torvalds {
5861da177e4SLinus Torvalds 	int rc = 0;
5871da177e4SLinus Torvalds 	unsigned int duplex_changed = 0;
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds 	if (duplex_chg_out)
5901da177e4SLinus Torvalds 		*duplex_chg_out = 0;
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 	mii_data->phy_id &= mii_if->phy_id_mask;
5931da177e4SLinus Torvalds 	mii_data->reg_num &= mii_if->reg_num_mask;
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds 	switch(cmd) {
5961da177e4SLinus Torvalds 	case SIOCGMIIPHY:
5971da177e4SLinus Torvalds 		mii_data->phy_id = mii_if->phy_id;
598df561f66SGustavo A. R. Silva 		fallthrough;
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds 	case SIOCGMIIREG:
6011da177e4SLinus Torvalds 		mii_data->val_out =
6021da177e4SLinus Torvalds 			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
6031da177e4SLinus Torvalds 					  mii_data->reg_num);
6041da177e4SLinus Torvalds 		break;
6051da177e4SLinus Torvalds 
6061da177e4SLinus Torvalds 	case SIOCSMIIREG: {
6071da177e4SLinus Torvalds 		u16 val = mii_data->val_in;
6081da177e4SLinus Torvalds 
6091da177e4SLinus Torvalds 		if (mii_data->phy_id == mii_if->phy_id) {
6101da177e4SLinus Torvalds 			switch(mii_data->reg_num) {
6111da177e4SLinus Torvalds 			case MII_BMCR: {
6121da177e4SLinus Torvalds 				unsigned int new_duplex = 0;
6131da177e4SLinus Torvalds 				if (val & (BMCR_RESET|BMCR_ANENABLE))
6141da177e4SLinus Torvalds 					mii_if->force_media = 0;
6151da177e4SLinus Torvalds 				else
6161da177e4SLinus Torvalds 					mii_if->force_media = 1;
6171da177e4SLinus Torvalds 				if (mii_if->force_media &&
6181da177e4SLinus Torvalds 				    (val & BMCR_FULLDPLX))
6191da177e4SLinus Torvalds 					new_duplex = 1;
6201da177e4SLinus Torvalds 				if (mii_if->full_duplex != new_duplex) {
6211da177e4SLinus Torvalds 					duplex_changed = 1;
6221da177e4SLinus Torvalds 					mii_if->full_duplex = new_duplex;
6231da177e4SLinus Torvalds 				}
6241da177e4SLinus Torvalds 				break;
6251da177e4SLinus Torvalds 			}
6261da177e4SLinus Torvalds 			case MII_ADVERTISE:
6271da177e4SLinus Torvalds 				mii_if->advertising = val;
6281da177e4SLinus Torvalds 				break;
6291da177e4SLinus Torvalds 			default:
6301da177e4SLinus Torvalds 				/* do nothing */
6311da177e4SLinus Torvalds 				break;
6321da177e4SLinus Torvalds 			}
6331da177e4SLinus Torvalds 		}
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
6361da177e4SLinus Torvalds 				   mii_data->reg_num, val);
6371da177e4SLinus Torvalds 		break;
6381da177e4SLinus Torvalds 	}
6391da177e4SLinus Torvalds 
6401da177e4SLinus Torvalds 	default:
6411da177e4SLinus Torvalds 		rc = -EOPNOTSUPP;
6421da177e4SLinus Torvalds 		break;
6431da177e4SLinus Torvalds 	}
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
6461da177e4SLinus Torvalds 		*duplex_chg_out = 1;
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	return rc;
6491da177e4SLinus Torvalds }
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
6521da177e4SLinus Torvalds MODULE_DESCRIPTION ("MII hardware support library");
6531da177e4SLinus Torvalds MODULE_LICENSE("GPL");
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds EXPORT_SYMBOL(mii_link_ok);
6561da177e4SLinus Torvalds EXPORT_SYMBOL(mii_nway_restart);
6571da177e4SLinus Torvalds EXPORT_SYMBOL(mii_ethtool_gset);
658bc8ee596SPhilippe Reynes EXPORT_SYMBOL(mii_ethtool_get_link_ksettings);
6591da177e4SLinus Torvalds EXPORT_SYMBOL(mii_ethtool_sset);
660bc8ee596SPhilippe Reynes EXPORT_SYMBOL(mii_ethtool_set_link_ksettings);
6611da177e4SLinus Torvalds EXPORT_SYMBOL(mii_check_link);
6621da177e4SLinus Torvalds EXPORT_SYMBOL(mii_check_media);
66343ec6e95SDale Farnsworth EXPORT_SYMBOL(mii_check_gmii_support);
6641da177e4SLinus Torvalds EXPORT_SYMBOL(generic_mii_ioctl);
6651da177e4SLinus Torvalds 
666