1  /*
2  
3  	mii.c: MII interface library
4  
5  	Maintained by Jeff Garzik <jgarzik@pobox.com>
6  	Copyright 2001,2002 Jeff Garzik
7  
8  	Various code came from myson803.c and other files by
9  	Donald Becker.  Copyright:
10  
11  		Written 1998-2002 by Donald Becker.
12  
13  		This software may be used and distributed according
14  		to the terms of the GNU General Public License (GPL),
15  		incorporated herein by reference.  Drivers based on
16  		or derived from this code fall under the GPL and must
17  		retain the authorship, copyright and license notice.
18  		This file is not a complete program and may only be
19  		used when the entire operating system is licensed
20  		under the GPL.
21  
22  		The author may be reached as becker@scyld.com, or C/O
23  		Scyld Computing Corporation
24  		410 Severn Ave., Suite 210
25  		Annapolis MD 21403
26  
27  
28   */
29  
30  #include <linux/kernel.h>
31  #include <linux/module.h>
32  #include <linux/netdevice.h>
33  #include <linux/ethtool.h>
34  #include <linux/mii.h>
35  
mii_get_an(struct mii_if_info * mii,u16 addr)36  static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
37  {
38  	int advert;
39  
40  	advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
41  
42  	return mii_lpa_to_ethtool_lpa_t(advert);
43  }
44  
45  /**
46   * mii_ethtool_gset - get settings that are specified in @ecmd
47   * @mii: MII interface
48   * @ecmd: requested ethtool_cmd
49   *
50   * The @ecmd parameter is expected to have been cleared before calling
51   * mii_ethtool_gset().
52   */
mii_ethtool_gset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)53  void mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
54  {
55  	struct net_device *dev = mii->dev;
56  	u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
57  	u32 nego;
58  
59  	ecmd->supported =
60  	    (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
61  	     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
62  	     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
63  	if (mii->supports_gmii)
64  		ecmd->supported |= SUPPORTED_1000baseT_Half |
65  			SUPPORTED_1000baseT_Full;
66  
67  	/* only supports twisted-pair */
68  	ecmd->port = PORT_MII;
69  
70  	/* only supports internal transceiver */
71  	ecmd->transceiver = XCVR_INTERNAL;
72  
73  	/* this isn't fully supported at higher layers */
74  	ecmd->phy_address = mii->phy_id;
75  	ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22;
76  
77  	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
78  
79  	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
80  	bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
81  	if (mii->supports_gmii) {
82  		ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
83  		stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
84  	}
85  
86  	ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
87  	if (mii->supports_gmii)
88  		ecmd->advertising |=
89  			mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
90  
91  	if (bmcr & BMCR_ANENABLE) {
92  		ecmd->advertising |= ADVERTISED_Autoneg;
93  		ecmd->autoneg = AUTONEG_ENABLE;
94  
95  		if (bmsr & BMSR_ANEGCOMPLETE) {
96  			ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
97  			ecmd->lp_advertising |=
98  					mii_stat1000_to_ethtool_lpa_t(stat1000);
99  		} else {
100  			ecmd->lp_advertising = 0;
101  		}
102  
103  		nego = ecmd->advertising & ecmd->lp_advertising;
104  
105  		if (nego & (ADVERTISED_1000baseT_Full |
106  			    ADVERTISED_1000baseT_Half)) {
107  			ethtool_cmd_speed_set(ecmd, SPEED_1000);
108  			ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
109  		} else if (nego & (ADVERTISED_100baseT_Full |
110  				   ADVERTISED_100baseT_Half)) {
111  			ethtool_cmd_speed_set(ecmd, SPEED_100);
112  			ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
113  		} else {
114  			ethtool_cmd_speed_set(ecmd, SPEED_10);
115  			ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
116  		}
117  	} else {
118  		ecmd->autoneg = AUTONEG_DISABLE;
119  
120  		ethtool_cmd_speed_set(ecmd,
121  				      ((bmcr & BMCR_SPEED1000 &&
122  					(bmcr & BMCR_SPEED100) == 0) ?
123  				       SPEED_1000 :
124  				       ((bmcr & BMCR_SPEED100) ?
125  					SPEED_100 : SPEED_10)));
126  		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
127  	}
128  
129  	mii->full_duplex = ecmd->duplex;
130  
131  	/* ignore maxtxpkt, maxrxpkt for now */
132  }
133  
134  /**
135   * mii_ethtool_get_link_ksettings - get settings that are specified in @cmd
136   * @mii: MII interface
137   * @cmd: requested ethtool_link_ksettings
138   *
139   * The @cmd parameter is expected to have been cleared before calling
140   * mii_ethtool_get_link_ksettings().
141   */
mii_ethtool_get_link_ksettings(struct mii_if_info * mii,struct ethtool_link_ksettings * cmd)142  void mii_ethtool_get_link_ksettings(struct mii_if_info *mii,
143  				    struct ethtool_link_ksettings *cmd)
144  {
145  	struct net_device *dev = mii->dev;
146  	u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
147  	u32 nego, supported, advertising, lp_advertising;
148  
149  	supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
150  		     SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
151  		     SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
152  	if (mii->supports_gmii)
153  		supported |= SUPPORTED_1000baseT_Half |
154  			SUPPORTED_1000baseT_Full;
155  
156  	/* only supports twisted-pair */
157  	cmd->base.port = PORT_MII;
158  
159  	/* this isn't fully supported at higher layers */
160  	cmd->base.phy_address = mii->phy_id;
161  	cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
162  
163  	advertising = ADVERTISED_TP | ADVERTISED_MII;
164  
165  	bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
166  	bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
167  	if (mii->supports_gmii) {
168  		ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
169  		stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
170  	}
171  
172  	advertising |= mii_get_an(mii, MII_ADVERTISE);
173  	if (mii->supports_gmii)
174  		advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
175  
176  	if (bmcr & BMCR_ANENABLE) {
177  		advertising |= ADVERTISED_Autoneg;
178  		cmd->base.autoneg = AUTONEG_ENABLE;
179  
180  		if (bmsr & BMSR_ANEGCOMPLETE) {
181  			lp_advertising = mii_get_an(mii, MII_LPA);
182  			lp_advertising |=
183  					mii_stat1000_to_ethtool_lpa_t(stat1000);
184  		} else {
185  			lp_advertising = 0;
186  		}
187  
188  		nego = advertising & lp_advertising;
189  
190  		if (nego & (ADVERTISED_1000baseT_Full |
191  			    ADVERTISED_1000baseT_Half)) {
192  			cmd->base.speed = SPEED_1000;
193  			cmd->base.duplex = !!(nego & ADVERTISED_1000baseT_Full);
194  		} else if (nego & (ADVERTISED_100baseT_Full |
195  				   ADVERTISED_100baseT_Half)) {
196  			cmd->base.speed = SPEED_100;
197  			cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full);
198  		} else {
199  			cmd->base.speed = SPEED_10;
200  			cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full);
201  		}
202  	} else {
203  		cmd->base.autoneg = AUTONEG_DISABLE;
204  
205  		cmd->base.speed = ((bmcr & BMCR_SPEED1000 &&
206  				    (bmcr & BMCR_SPEED100) == 0) ?
207  				   SPEED_1000 :
208  				   ((bmcr & BMCR_SPEED100) ?
209  				    SPEED_100 : SPEED_10));
210  		cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
211  			DUPLEX_FULL : DUPLEX_HALF;
212  
213  		lp_advertising = 0;
214  	}
215  
216  	mii->full_duplex = cmd->base.duplex;
217  
218  	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
219  						supported);
220  	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
221  						advertising);
222  	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
223  						lp_advertising);
224  
225  	/* ignore maxtxpkt, maxrxpkt for now */
226  }
227  
228  /**
229   * mii_ethtool_sset - set settings that are specified in @ecmd
230   * @mii: MII interface
231   * @ecmd: requested ethtool_cmd
232   *
233   * Returns 0 for success, negative on error.
234   */
mii_ethtool_sset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)235  int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
236  {
237  	struct net_device *dev = mii->dev;
238  	u32 speed = ethtool_cmd_speed(ecmd);
239  
240  	if (speed != SPEED_10 &&
241  	    speed != SPEED_100 &&
242  	    speed != SPEED_1000)
243  		return -EINVAL;
244  	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
245  		return -EINVAL;
246  	if (ecmd->port != PORT_MII)
247  		return -EINVAL;
248  	if (ecmd->transceiver != XCVR_INTERNAL)
249  		return -EINVAL;
250  	if (ecmd->phy_address != mii->phy_id)
251  		return -EINVAL;
252  	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
253  		return -EINVAL;
254  	if ((speed == SPEED_1000) && (!mii->supports_gmii))
255  		return -EINVAL;
256  
257  	/* ignore supported, maxtxpkt, maxrxpkt */
258  
259  	if (ecmd->autoneg == AUTONEG_ENABLE) {
260  		u32 bmcr, advert, tmp;
261  		u32 advert2 = 0, tmp2 = 0;
262  
263  		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
264  					  ADVERTISED_10baseT_Full |
265  					  ADVERTISED_100baseT_Half |
266  					  ADVERTISED_100baseT_Full |
267  					  ADVERTISED_1000baseT_Half |
268  					  ADVERTISED_1000baseT_Full)) == 0)
269  			return -EINVAL;
270  
271  		/* advertise only what has been requested */
272  		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
273  		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
274  		if (mii->supports_gmii) {
275  			advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
276  			tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
277  		}
278  		tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
279  
280  		if (mii->supports_gmii)
281  			tmp2 |=
282  			      ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
283  		if (advert != tmp) {
284  			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
285  			mii->advertising = tmp;
286  		}
287  		if ((mii->supports_gmii) && (advert2 != tmp2))
288  			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
289  
290  		/* turn on autonegotiation, and force a renegotiate */
291  		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
292  		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
293  		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
294  
295  		mii->force_media = 0;
296  	} else {
297  		u32 bmcr, tmp;
298  
299  		/* turn off auto negotiation, set speed and duplexity */
300  		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
301  		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
302  			       BMCR_SPEED1000 | BMCR_FULLDPLX);
303  		if (speed == SPEED_1000)
304  			tmp |= BMCR_SPEED1000;
305  		else if (speed == SPEED_100)
306  			tmp |= BMCR_SPEED100;
307  		if (ecmd->duplex == DUPLEX_FULL) {
308  			tmp |= BMCR_FULLDPLX;
309  			mii->full_duplex = 1;
310  		} else
311  			mii->full_duplex = 0;
312  		if (bmcr != tmp)
313  			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
314  
315  		mii->force_media = 1;
316  	}
317  	return 0;
318  }
319  
320  /**
321   * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
322   * @mii: MII interfaces
323   * @cmd: requested ethtool_link_ksettings
324   *
325   * Returns 0 for success, negative on error.
326   */
mii_ethtool_set_link_ksettings(struct mii_if_info * mii,const struct ethtool_link_ksettings * cmd)327  int mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
328  				   const struct ethtool_link_ksettings *cmd)
329  {
330  	struct net_device *dev = mii->dev;
331  	u32 speed = cmd->base.speed;
332  
333  	if (speed != SPEED_10 &&
334  	    speed != SPEED_100 &&
335  	    speed != SPEED_1000)
336  		return -EINVAL;
337  	if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
338  		return -EINVAL;
339  	if (cmd->base.port != PORT_MII)
340  		return -EINVAL;
341  	if (cmd->base.phy_address != mii->phy_id)
342  		return -EINVAL;
343  	if (cmd->base.autoneg != AUTONEG_DISABLE &&
344  	    cmd->base.autoneg != AUTONEG_ENABLE)
345  		return -EINVAL;
346  	if ((speed == SPEED_1000) && (!mii->supports_gmii))
347  		return -EINVAL;
348  
349  	/* ignore supported, maxtxpkt, maxrxpkt */
350  
351  	if (cmd->base.autoneg == AUTONEG_ENABLE) {
352  		u32 bmcr, advert, tmp;
353  		u32 advert2 = 0, tmp2 = 0;
354  		u32 advertising;
355  
356  		ethtool_convert_link_mode_to_legacy_u32(
357  			&advertising, cmd->link_modes.advertising);
358  
359  		if ((advertising & (ADVERTISED_10baseT_Half |
360  				    ADVERTISED_10baseT_Full |
361  				    ADVERTISED_100baseT_Half |
362  				    ADVERTISED_100baseT_Full |
363  				    ADVERTISED_1000baseT_Half |
364  				    ADVERTISED_1000baseT_Full)) == 0)
365  			return -EINVAL;
366  
367  		/* advertise only what has been requested */
368  		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
369  		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
370  		if (mii->supports_gmii) {
371  			advert2 = mii->mdio_read(dev, mii->phy_id,
372  						 MII_CTRL1000);
373  			tmp2 = advert2 &
374  				~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
375  		}
376  		tmp |= ethtool_adv_to_mii_adv_t(advertising);
377  
378  		if (mii->supports_gmii)
379  			tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
380  		if (advert != tmp) {
381  			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
382  			mii->advertising = tmp;
383  		}
384  		if ((mii->supports_gmii) && (advert2 != tmp2))
385  			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
386  
387  		/* turn on autonegotiation, and force a renegotiate */
388  		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
389  		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
390  		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
391  
392  		mii->force_media = 0;
393  	} else {
394  		u32 bmcr, tmp;
395  
396  		/* turn off auto negotiation, set speed and duplexity */
397  		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
398  		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
399  			       BMCR_SPEED1000 | BMCR_FULLDPLX);
400  		if (speed == SPEED_1000)
401  			tmp |= BMCR_SPEED1000;
402  		else if (speed == SPEED_100)
403  			tmp |= BMCR_SPEED100;
404  		if (cmd->base.duplex == DUPLEX_FULL) {
405  			tmp |= BMCR_FULLDPLX;
406  			mii->full_duplex = 1;
407  		} else {
408  			mii->full_duplex = 0;
409  		}
410  		if (bmcr != tmp)
411  			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
412  
413  		mii->force_media = 1;
414  	}
415  	return 0;
416  }
417  
418  /**
419   * mii_check_gmii_support - check if the MII supports Gb interfaces
420   * @mii: the MII interface
421   */
mii_check_gmii_support(struct mii_if_info * mii)422  int mii_check_gmii_support(struct mii_if_info *mii)
423  {
424  	int reg;
425  
426  	reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
427  	if (reg & BMSR_ESTATEN) {
428  		reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
429  		if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
430  			return 1;
431  	}
432  
433  	return 0;
434  }
435  
436  /**
437   * mii_link_ok - is link status up/ok
438   * @mii: the MII interface
439   *
440   * Returns 1 if the MII reports link status up/ok, 0 otherwise.
441   */
mii_link_ok(struct mii_if_info * mii)442  int mii_link_ok (struct mii_if_info *mii)
443  {
444  	/* first, a dummy read, needed to latch some MII phys */
445  	mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
446  	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
447  		return 1;
448  	return 0;
449  }
450  
451  /**
452   * mii_nway_restart - restart NWay (autonegotiation) for this interface
453   * @mii: the MII interface
454   *
455   * Returns 0 on success, negative on error.
456   */
mii_nway_restart(struct mii_if_info * mii)457  int mii_nway_restart (struct mii_if_info *mii)
458  {
459  	int bmcr;
460  	int r = -EINVAL;
461  
462  	/* if autoneg is off, it's an error */
463  	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
464  
465  	if (bmcr & BMCR_ANENABLE) {
466  		bmcr |= BMCR_ANRESTART;
467  		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
468  		r = 0;
469  	}
470  
471  	return r;
472  }
473  
474  /**
475   * mii_check_link - check MII link status
476   * @mii: MII interface
477   *
478   * If the link status changed (previous != current), call
479   * netif_carrier_on() if current link status is Up or call
480   * netif_carrier_off() if current link status is Down.
481   */
mii_check_link(struct mii_if_info * mii)482  void mii_check_link (struct mii_if_info *mii)
483  {
484  	int cur_link = mii_link_ok(mii);
485  	int prev_link = netif_carrier_ok(mii->dev);
486  
487  	if (cur_link && !prev_link)
488  		netif_carrier_on(mii->dev);
489  	else if (prev_link && !cur_link)
490  		netif_carrier_off(mii->dev);
491  }
492  
493  /**
494   * mii_check_media - check the MII interface for a carrier/speed/duplex change
495   * @mii: the MII interface
496   * @ok_to_print: OK to print link up/down messages
497   * @init_media: OK to save duplex mode in @mii
498   *
499   * Returns 1 if the duplex mode changed, 0 if not.
500   * If the media type is forced, always returns 0.
501   */
mii_check_media(struct mii_if_info * mii,unsigned int ok_to_print,unsigned int init_media)502  unsigned int mii_check_media (struct mii_if_info *mii,
503  			      unsigned int ok_to_print,
504  			      unsigned int init_media)
505  {
506  	unsigned int old_carrier, new_carrier;
507  	int advertise, lpa, media, duplex;
508  	int lpa2 = 0;
509  
510  	/* check current and old link status */
511  	old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
512  	new_carrier = (unsigned int) mii_link_ok(mii);
513  
514  	/* if carrier state did not change, this is a "bounce",
515  	 * just exit as everything is already set correctly
516  	 */
517  	if ((!init_media) && (old_carrier == new_carrier))
518  		return 0; /* duplex did not change */
519  
520  	/* no carrier, nothing much to do */
521  	if (!new_carrier) {
522  		netif_carrier_off(mii->dev);
523  		if (ok_to_print)
524  			netdev_info(mii->dev, "link down\n");
525  		return 0; /* duplex did not change */
526  	}
527  
528  	/*
529  	 * we have carrier, see who's on the other end
530  	 */
531  	netif_carrier_on(mii->dev);
532  
533  	if (mii->force_media) {
534  		if (ok_to_print)
535  			netdev_info(mii->dev, "link up\n");
536  		return 0; /* duplex did not change */
537  	}
538  
539  	/* get MII advertise and LPA values */
540  	if ((!init_media) && (mii->advertising))
541  		advertise = mii->advertising;
542  	else {
543  		advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
544  		mii->advertising = advertise;
545  	}
546  	lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
547  	if (mii->supports_gmii)
548  		lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
549  
550  	/* figure out media and duplex from advertise and LPA values */
551  	media = mii_nway_result(lpa & advertise);
552  	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
553  	if (lpa2 & LPA_1000FULL)
554  		duplex = 1;
555  
556  	if (ok_to_print)
557  		netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
558  			    lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
559  			    media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
560  			    100 : 10,
561  			    duplex ? "full" : "half",
562  			    lpa);
563  
564  	if ((init_media) || (mii->full_duplex != duplex)) {
565  		mii->full_duplex = duplex;
566  		return 1; /* duplex changed */
567  	}
568  
569  	return 0; /* duplex did not change */
570  }
571  
572  /**
573   * generic_mii_ioctl - main MII ioctl interface
574   * @mii_if: the MII interface
575   * @mii_data: MII ioctl data structure
576   * @cmd: MII ioctl command
577   * @duplex_chg_out: pointer to @duplex_changed status if there was no
578   *	ioctl error
579   *
580   * Returns 0 on success, negative on error.
581   */
generic_mii_ioctl(struct mii_if_info * mii_if,struct mii_ioctl_data * mii_data,int cmd,unsigned int * duplex_chg_out)582  int generic_mii_ioctl(struct mii_if_info *mii_if,
583  		      struct mii_ioctl_data *mii_data, int cmd,
584  		      unsigned int *duplex_chg_out)
585  {
586  	int rc = 0;
587  	unsigned int duplex_changed = 0;
588  
589  	if (duplex_chg_out)
590  		*duplex_chg_out = 0;
591  
592  	mii_data->phy_id &= mii_if->phy_id_mask;
593  	mii_data->reg_num &= mii_if->reg_num_mask;
594  
595  	switch(cmd) {
596  	case SIOCGMIIPHY:
597  		mii_data->phy_id = mii_if->phy_id;
598  		fallthrough;
599  
600  	case SIOCGMIIREG:
601  		mii_data->val_out =
602  			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
603  					  mii_data->reg_num);
604  		break;
605  
606  	case SIOCSMIIREG: {
607  		u16 val = mii_data->val_in;
608  
609  		if (mii_data->phy_id == mii_if->phy_id) {
610  			switch(mii_data->reg_num) {
611  			case MII_BMCR: {
612  				unsigned int new_duplex = 0;
613  				if (val & (BMCR_RESET|BMCR_ANENABLE))
614  					mii_if->force_media = 0;
615  				else
616  					mii_if->force_media = 1;
617  				if (mii_if->force_media &&
618  				    (val & BMCR_FULLDPLX))
619  					new_duplex = 1;
620  				if (mii_if->full_duplex != new_duplex) {
621  					duplex_changed = 1;
622  					mii_if->full_duplex = new_duplex;
623  				}
624  				break;
625  			}
626  			case MII_ADVERTISE:
627  				mii_if->advertising = val;
628  				break;
629  			default:
630  				/* do nothing */
631  				break;
632  			}
633  		}
634  
635  		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
636  				   mii_data->reg_num, val);
637  		break;
638  	}
639  
640  	default:
641  		rc = -EOPNOTSUPP;
642  		break;
643  	}
644  
645  	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
646  		*duplex_chg_out = 1;
647  
648  	return rc;
649  }
650  
651  MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
652  MODULE_DESCRIPTION ("MII hardware support library");
653  MODULE_LICENSE("GPL");
654  
655  EXPORT_SYMBOL(mii_link_ok);
656  EXPORT_SYMBOL(mii_nway_restart);
657  EXPORT_SYMBOL(mii_ethtool_gset);
658  EXPORT_SYMBOL(mii_ethtool_get_link_ksettings);
659  EXPORT_SYMBOL(mii_ethtool_sset);
660  EXPORT_SYMBOL(mii_ethtool_set_link_ksettings);
661  EXPORT_SYMBOL(mii_check_link);
662  EXPORT_SYMBOL(mii_check_media);
663  EXPORT_SYMBOL(mii_check_gmii_support);
664  EXPORT_SYMBOL(generic_mii_ioctl);
665  
666