1 /*
2 
3 	mii.c: MII interface library
4 
5 	Maintained by Jeff Garzik <[email protected]>
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 [email protected], 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 	if (!(bmsr & BMSR_LSTATUS))
217 		cmd->base.speed = SPEED_UNKNOWN;
218 
219 	mii->full_duplex = cmd->base.duplex;
220 
221 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
222 						supported);
223 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
224 						advertising);
225 	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
226 						lp_advertising);
227 
228 	/* ignore maxtxpkt, maxrxpkt for now */
229 }
230 
231 /**
232  * mii_ethtool_sset - set settings that are specified in @ecmd
233  * @mii: MII interface
234  * @ecmd: requested ethtool_cmd
235  *
236  * Returns 0 for success, negative on error.
237  */
mii_ethtool_sset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)238 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
239 {
240 	struct net_device *dev = mii->dev;
241 	u32 speed = ethtool_cmd_speed(ecmd);
242 
243 	if (speed != SPEED_10 &&
244 	    speed != SPEED_100 &&
245 	    speed != SPEED_1000)
246 		return -EINVAL;
247 	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
248 		return -EINVAL;
249 	if (ecmd->port != PORT_MII)
250 		return -EINVAL;
251 	if (ecmd->transceiver != XCVR_INTERNAL)
252 		return -EINVAL;
253 	if (ecmd->phy_address != mii->phy_id)
254 		return -EINVAL;
255 	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
256 		return -EINVAL;
257 	if ((speed == SPEED_1000) && (!mii->supports_gmii))
258 		return -EINVAL;
259 
260 	/* ignore supported, maxtxpkt, maxrxpkt */
261 
262 	if (ecmd->autoneg == AUTONEG_ENABLE) {
263 		u32 bmcr, advert, tmp;
264 		u32 advert2 = 0, tmp2 = 0;
265 
266 		if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
267 					  ADVERTISED_10baseT_Full |
268 					  ADVERTISED_100baseT_Half |
269 					  ADVERTISED_100baseT_Full |
270 					  ADVERTISED_1000baseT_Half |
271 					  ADVERTISED_1000baseT_Full)) == 0)
272 			return -EINVAL;
273 
274 		/* advertise only what has been requested */
275 		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
276 		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
277 		if (mii->supports_gmii) {
278 			advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
279 			tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
280 		}
281 		tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
282 
283 		if (mii->supports_gmii)
284 			tmp2 |=
285 			      ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
286 		if (advert != tmp) {
287 			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
288 			mii->advertising = tmp;
289 		}
290 		if ((mii->supports_gmii) && (advert2 != tmp2))
291 			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
292 
293 		/* turn on autonegotiation, and force a renegotiate */
294 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
295 		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
296 		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
297 
298 		mii->force_media = 0;
299 	} else {
300 		u32 bmcr, tmp;
301 
302 		/* turn off auto negotiation, set speed and duplexity */
303 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
304 		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
305 			       BMCR_SPEED1000 | BMCR_FULLDPLX);
306 		if (speed == SPEED_1000)
307 			tmp |= BMCR_SPEED1000;
308 		else if (speed == SPEED_100)
309 			tmp |= BMCR_SPEED100;
310 		if (ecmd->duplex == DUPLEX_FULL) {
311 			tmp |= BMCR_FULLDPLX;
312 			mii->full_duplex = 1;
313 		} else
314 			mii->full_duplex = 0;
315 		if (bmcr != tmp)
316 			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
317 
318 		mii->force_media = 1;
319 	}
320 	return 0;
321 }
322 
323 /**
324  * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd
325  * @mii: MII interfaces
326  * @cmd: requested ethtool_link_ksettings
327  *
328  * Returns 0 for success, negative on error.
329  */
mii_ethtool_set_link_ksettings(struct mii_if_info * mii,const struct ethtool_link_ksettings * cmd)330 int mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
331 				   const struct ethtool_link_ksettings *cmd)
332 {
333 	struct net_device *dev = mii->dev;
334 	u32 speed = cmd->base.speed;
335 
336 	if (speed != SPEED_10 &&
337 	    speed != SPEED_100 &&
338 	    speed != SPEED_1000)
339 		return -EINVAL;
340 	if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
341 		return -EINVAL;
342 	if (cmd->base.port != PORT_MII)
343 		return -EINVAL;
344 	if (cmd->base.phy_address != mii->phy_id)
345 		return -EINVAL;
346 	if (cmd->base.autoneg != AUTONEG_DISABLE &&
347 	    cmd->base.autoneg != AUTONEG_ENABLE)
348 		return -EINVAL;
349 	if ((speed == SPEED_1000) && (!mii->supports_gmii))
350 		return -EINVAL;
351 
352 	/* ignore supported, maxtxpkt, maxrxpkt */
353 
354 	if (cmd->base.autoneg == AUTONEG_ENABLE) {
355 		u32 bmcr, advert, tmp;
356 		u32 advert2 = 0, tmp2 = 0;
357 		u32 advertising;
358 
359 		ethtool_convert_link_mode_to_legacy_u32(
360 			&advertising, cmd->link_modes.advertising);
361 
362 		if ((advertising & (ADVERTISED_10baseT_Half |
363 				    ADVERTISED_10baseT_Full |
364 				    ADVERTISED_100baseT_Half |
365 				    ADVERTISED_100baseT_Full |
366 				    ADVERTISED_1000baseT_Half |
367 				    ADVERTISED_1000baseT_Full)) == 0)
368 			return -EINVAL;
369 
370 		/* advertise only what has been requested */
371 		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
372 		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
373 		if (mii->supports_gmii) {
374 			advert2 = mii->mdio_read(dev, mii->phy_id,
375 						 MII_CTRL1000);
376 			tmp2 = advert2 &
377 				~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
378 		}
379 		tmp |= ethtool_adv_to_mii_adv_t(advertising);
380 
381 		if (mii->supports_gmii)
382 			tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
383 		if (advert != tmp) {
384 			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
385 			mii->advertising = tmp;
386 		}
387 		if ((mii->supports_gmii) && (advert2 != tmp2))
388 			mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
389 
390 		/* turn on autonegotiation, and force a renegotiate */
391 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
392 		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
393 		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
394 
395 		mii->force_media = 0;
396 	} else {
397 		u32 bmcr, tmp;
398 
399 		/* turn off auto negotiation, set speed and duplexity */
400 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
401 		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
402 			       BMCR_SPEED1000 | BMCR_FULLDPLX);
403 		if (speed == SPEED_1000)
404 			tmp |= BMCR_SPEED1000;
405 		else if (speed == SPEED_100)
406 			tmp |= BMCR_SPEED100;
407 		if (cmd->base.duplex == DUPLEX_FULL) {
408 			tmp |= BMCR_FULLDPLX;
409 			mii->full_duplex = 1;
410 		} else {
411 			mii->full_duplex = 0;
412 		}
413 		if (bmcr != tmp)
414 			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
415 
416 		mii->force_media = 1;
417 	}
418 	return 0;
419 }
420 
421 /**
422  * mii_check_gmii_support - check if the MII supports Gb interfaces
423  * @mii: the MII interface
424  */
mii_check_gmii_support(struct mii_if_info * mii)425 int mii_check_gmii_support(struct mii_if_info *mii)
426 {
427 	int reg;
428 
429 	reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
430 	if (reg & BMSR_ESTATEN) {
431 		reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
432 		if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
433 			return 1;
434 	}
435 
436 	return 0;
437 }
438 
439 /**
440  * mii_link_ok - is link status up/ok
441  * @mii: the MII interface
442  *
443  * Returns 1 if the MII reports link status up/ok, 0 otherwise.
444  */
mii_link_ok(struct mii_if_info * mii)445 int mii_link_ok (struct mii_if_info *mii)
446 {
447 	/* first, a dummy read, needed to latch some MII phys */
448 	mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
449 	if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
450 		return 1;
451 	return 0;
452 }
453 
454 /**
455  * mii_nway_restart - restart NWay (autonegotiation) for this interface
456  * @mii: the MII interface
457  *
458  * Returns 0 on success, negative on error.
459  */
mii_nway_restart(struct mii_if_info * mii)460 int mii_nway_restart (struct mii_if_info *mii)
461 {
462 	int bmcr;
463 	int r = -EINVAL;
464 
465 	/* if autoneg is off, it's an error */
466 	bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
467 
468 	if (bmcr & BMCR_ANENABLE) {
469 		bmcr |= BMCR_ANRESTART;
470 		mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
471 		r = 0;
472 	}
473 
474 	return r;
475 }
476 
477 /**
478  * mii_check_link - check MII link status
479  * @mii: MII interface
480  *
481  * If the link status changed (previous != current), call
482  * netif_carrier_on() if current link status is Up or call
483  * netif_carrier_off() if current link status is Down.
484  */
mii_check_link(struct mii_if_info * mii)485 void mii_check_link (struct mii_if_info *mii)
486 {
487 	int cur_link = mii_link_ok(mii);
488 	int prev_link = netif_carrier_ok(mii->dev);
489 
490 	if (cur_link && !prev_link)
491 		netif_carrier_on(mii->dev);
492 	else if (prev_link && !cur_link)
493 		netif_carrier_off(mii->dev);
494 }
495 
496 /**
497  * mii_check_media - check the MII interface for a carrier/speed/duplex change
498  * @mii: the MII interface
499  * @ok_to_print: OK to print link up/down messages
500  * @init_media: OK to save duplex mode in @mii
501  *
502  * Returns 1 if the duplex mode changed, 0 if not.
503  * If the media type is forced, always returns 0.
504  */
mii_check_media(struct mii_if_info * mii,unsigned int ok_to_print,unsigned int init_media)505 unsigned int mii_check_media (struct mii_if_info *mii,
506 			      unsigned int ok_to_print,
507 			      unsigned int init_media)
508 {
509 	unsigned int old_carrier, new_carrier;
510 	int advertise, lpa, media, duplex;
511 	int lpa2 = 0;
512 
513 	/* check current and old link status */
514 	old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
515 	new_carrier = (unsigned int) mii_link_ok(mii);
516 
517 	/* if carrier state did not change, this is a "bounce",
518 	 * just exit as everything is already set correctly
519 	 */
520 	if ((!init_media) && (old_carrier == new_carrier))
521 		return 0; /* duplex did not change */
522 
523 	/* no carrier, nothing much to do */
524 	if (!new_carrier) {
525 		netif_carrier_off(mii->dev);
526 		if (ok_to_print)
527 			netdev_info(mii->dev, "link down\n");
528 		return 0; /* duplex did not change */
529 	}
530 
531 	/*
532 	 * we have carrier, see who's on the other end
533 	 */
534 	netif_carrier_on(mii->dev);
535 
536 	if (mii->force_media) {
537 		if (ok_to_print)
538 			netdev_info(mii->dev, "link up\n");
539 		return 0; /* duplex did not change */
540 	}
541 
542 	/* get MII advertise and LPA values */
543 	if ((!init_media) && (mii->advertising))
544 		advertise = mii->advertising;
545 	else {
546 		advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
547 		mii->advertising = advertise;
548 	}
549 	lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
550 	if (mii->supports_gmii)
551 		lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
552 
553 	/* figure out media and duplex from advertise and LPA values */
554 	media = mii_nway_result(lpa & advertise);
555 	duplex = (media & ADVERTISE_FULL) ? 1 : 0;
556 	if (lpa2 & LPA_1000FULL)
557 		duplex = 1;
558 
559 	if (ok_to_print)
560 		netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
561 			    lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
562 			    media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
563 			    100 : 10,
564 			    duplex ? "full" : "half",
565 			    lpa);
566 
567 	if ((init_media) || (mii->full_duplex != duplex)) {
568 		mii->full_duplex = duplex;
569 		return 1; /* duplex changed */
570 	}
571 
572 	return 0; /* duplex did not change */
573 }
574 
575 /**
576  * generic_mii_ioctl - main MII ioctl interface
577  * @mii_if: the MII interface
578  * @mii_data: MII ioctl data structure
579  * @cmd: MII ioctl command
580  * @duplex_chg_out: pointer to @duplex_changed status if there was no
581  *	ioctl error
582  *
583  * Returns 0 on success, negative on error.
584  */
generic_mii_ioctl(struct mii_if_info * mii_if,struct mii_ioctl_data * mii_data,int cmd,unsigned int * duplex_chg_out)585 int generic_mii_ioctl(struct mii_if_info *mii_if,
586 		      struct mii_ioctl_data *mii_data, int cmd,
587 		      unsigned int *duplex_chg_out)
588 {
589 	int rc = 0;
590 	unsigned int duplex_changed = 0;
591 
592 	if (duplex_chg_out)
593 		*duplex_chg_out = 0;
594 
595 	mii_data->phy_id &= mii_if->phy_id_mask;
596 	mii_data->reg_num &= mii_if->reg_num_mask;
597 
598 	switch(cmd) {
599 	case SIOCGMIIPHY:
600 		mii_data->phy_id = mii_if->phy_id;
601 		fallthrough;
602 
603 	case SIOCGMIIREG:
604 		mii_data->val_out =
605 			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
606 					  mii_data->reg_num);
607 		break;
608 
609 	case SIOCSMIIREG: {
610 		u16 val = mii_data->val_in;
611 
612 		if (mii_data->phy_id == mii_if->phy_id) {
613 			switch(mii_data->reg_num) {
614 			case MII_BMCR: {
615 				unsigned int new_duplex = 0;
616 				if (val & (BMCR_RESET|BMCR_ANENABLE))
617 					mii_if->force_media = 0;
618 				else
619 					mii_if->force_media = 1;
620 				if (mii_if->force_media &&
621 				    (val & BMCR_FULLDPLX))
622 					new_duplex = 1;
623 				if (mii_if->full_duplex != new_duplex) {
624 					duplex_changed = 1;
625 					mii_if->full_duplex = new_duplex;
626 				}
627 				break;
628 			}
629 			case MII_ADVERTISE:
630 				mii_if->advertising = val;
631 				break;
632 			default:
633 				/* do nothing */
634 				break;
635 			}
636 		}
637 
638 		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
639 				   mii_data->reg_num, val);
640 		break;
641 	}
642 
643 	default:
644 		rc = -EOPNOTSUPP;
645 		break;
646 	}
647 
648 	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
649 		*duplex_chg_out = 1;
650 
651 	return rc;
652 }
653 
654 MODULE_AUTHOR ("Jeff Garzik <[email protected]>");
655 MODULE_DESCRIPTION ("MII hardware support library");
656 MODULE_LICENSE("GPL");
657 
658 EXPORT_SYMBOL(mii_link_ok);
659 EXPORT_SYMBOL(mii_nway_restart);
660 EXPORT_SYMBOL(mii_ethtool_gset);
661 EXPORT_SYMBOL(mii_ethtool_get_link_ksettings);
662 EXPORT_SYMBOL(mii_ethtool_sset);
663 EXPORT_SYMBOL(mii_ethtool_set_link_ksettings);
664 EXPORT_SYMBOL(mii_check_link);
665 EXPORT_SYMBOL(mii_check_media);
666 EXPORT_SYMBOL(mii_check_gmii_support);
667 EXPORT_SYMBOL(generic_mii_ioctl);
668 
669