aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorTrent Piepho <tpiepho@freescale.com>2008-09-24 06:55:46 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-08 18:43:54 -0400
commit51e2a3846eab18711f4eb59cd0a4c33054e2980a (patch)
treea9abbddd407ce2205218148ebdcf8f54709f6a1c /drivers/net/phy
parent7bf6bf4803df1adc927f585168d2135fb019c698 (diff)
PHY: Avoid unnecessary aneg restarts
The PHY's aneg is configured and restarted whenever the link is brought up, e.g. when DHCP is started after the kernel has booted. This can take the link down for several seconds while auto-negotiation is redone. If the advertised features haven't changed, then it shouldn't be necessary to bring down the link and start auto-negotiation over again. genphy_config_advert() is enhanced to return 0 when the advertised features haven't been changed and >0 when they have been. genphy_config_aneg() then uses this information to not call genphy_restart_aneg() if there has been no change. Signed-off-by: Trent Piepho <tpiepho@freescale.com> Acked-by: Andy Fleming <afleming@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/phy_device.c49
1 files changed, 30 insertions, 19 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 16a0e7de5888..171627480058 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -419,13 +419,14 @@ EXPORT_SYMBOL(phy_detach);
419 * 419 *
420 * Description: Writes MII_ADVERTISE with the appropriate values, 420 * Description: Writes MII_ADVERTISE with the appropriate values,
421 * after sanitizing the values to make sure we only advertise 421 * after sanitizing the values to make sure we only advertise
422 * what is supported. 422 * what is supported. Returns < 0 on error, 0 if the PHY's advertisement
423 * hasn't changed, and > 0 if it has changed.
423 */ 424 */
424int genphy_config_advert(struct phy_device *phydev) 425int genphy_config_advert(struct phy_device *phydev)
425{ 426{
426 u32 advertise; 427 u32 advertise;
427 int adv; 428 int oldadv, adv;
428 int err; 429 int err, changed = 0;
429 430
430 /* Only allow advertising what 431 /* Only allow advertising what
431 * this PHY supports */ 432 * this PHY supports */
@@ -433,7 +434,7 @@ int genphy_config_advert(struct phy_device *phydev)
433 advertise = phydev->advertising; 434 advertise = phydev->advertising;
434 435
435 /* Setup standard advertisement */ 436 /* Setup standard advertisement */
436 adv = phy_read(phydev, MII_ADVERTISE); 437 oldadv = adv = phy_read(phydev, MII_ADVERTISE);
437 438
438 if (adv < 0) 439 if (adv < 0)
439 return adv; 440 return adv;
@@ -453,15 +454,18 @@ int genphy_config_advert(struct phy_device *phydev)
453 if (advertise & ADVERTISED_Asym_Pause) 454 if (advertise & ADVERTISED_Asym_Pause)
454 adv |= ADVERTISE_PAUSE_ASYM; 455 adv |= ADVERTISE_PAUSE_ASYM;
455 456
456 err = phy_write(phydev, MII_ADVERTISE, adv); 457 if (adv != oldadv) {
458 err = phy_write(phydev, MII_ADVERTISE, adv);
457 459
458 if (err < 0) 460 if (err < 0)
459 return err; 461 return err;
462 changed = 1;
463 }
460 464
461 /* Configure gigabit if it's supported */ 465 /* Configure gigabit if it's supported */
462 if (phydev->supported & (SUPPORTED_1000baseT_Half | 466 if (phydev->supported & (SUPPORTED_1000baseT_Half |
463 SUPPORTED_1000baseT_Full)) { 467 SUPPORTED_1000baseT_Full)) {
464 adv = phy_read(phydev, MII_CTRL1000); 468 oldadv = adv = phy_read(phydev, MII_CTRL1000);
465 469
466 if (adv < 0) 470 if (adv < 0)
467 return adv; 471 return adv;
@@ -471,13 +475,17 @@ int genphy_config_advert(struct phy_device *phydev)
471 adv |= ADVERTISE_1000HALF; 475 adv |= ADVERTISE_1000HALF;
472 if (advertise & SUPPORTED_1000baseT_Full) 476 if (advertise & SUPPORTED_1000baseT_Full)
473 adv |= ADVERTISE_1000FULL; 477 adv |= ADVERTISE_1000FULL;
474 err = phy_write(phydev, MII_CTRL1000, adv);
475 478
476 if (err < 0) 479 if (adv != oldadv) {
477 return err; 480 err = phy_write(phydev, MII_CTRL1000, adv);
481
482 if (err < 0)
483 return err;
484 changed = 1;
485 }
478 } 486 }
479 487
480 return adv; 488 return changed;
481} 489}
482EXPORT_SYMBOL(genphy_config_advert); 490EXPORT_SYMBOL(genphy_config_advert);
483 491
@@ -561,19 +569,22 @@ int genphy_restart_aneg(struct phy_device *phydev)
561 */ 569 */
562int genphy_config_aneg(struct phy_device *phydev) 570int genphy_config_aneg(struct phy_device *phydev)
563{ 571{
564 int err = 0; 572 int result = 0;
565 573
566 if (AUTONEG_ENABLE == phydev->autoneg) { 574 if (AUTONEG_ENABLE == phydev->autoneg) {
567 err = genphy_config_advert(phydev); 575 int result = genphy_config_advert(phydev);
568 576
569 if (err < 0) 577 if (result < 0) /* error */
570 return err; 578 return result;
571 579
572 err = genphy_restart_aneg(phydev); 580 /* Only restart aneg if we are advertising something different
581 * than we were before. */
582 if (result > 0)
583 result = genphy_restart_aneg(phydev);
573 } else 584 } else
574 err = genphy_setup_forced(phydev); 585 result = genphy_setup_forced(phydev);
575 586
576 return err; 587 return result;
577} 588}
578EXPORT_SYMBOL(genphy_config_aneg); 589EXPORT_SYMBOL(genphy_config_aneg);
579 590