diff options
Diffstat (limited to 'drivers/net/phy/phy_device.c')
-rw-r--r-- | drivers/net/phy/phy_device.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8fb1faca883a..25acbbde4a60 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -227,8 +227,17 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) | |||
227 | if (r) | 227 | if (r) |
228 | return ERR_PTR(r); | 228 | return ERR_PTR(r); |
229 | 229 | ||
230 | /* If the phy_id is all Fs or all 0s, there is no device there */ | 230 | /* If the phy_id is mostly Fs, there is no device there */ |
231 | if ((0xffff == phy_id) || (0x00 == phy_id)) | 231 | if ((phy_id & 0x1fffffff) == 0x1fffffff) |
232 | return NULL; | ||
233 | |||
234 | /* | ||
235 | * Broken hardware is sometimes missing the pull down resistor on the | ||
236 | * MDIO line, which results in reads to non-existent devices returning | ||
237 | * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent | ||
238 | * device as well. | ||
239 | */ | ||
240 | if (phy_id == 0) | ||
232 | return NULL; | 241 | return NULL; |
233 | 242 | ||
234 | dev = phy_device_create(bus, addr, phy_id); | 243 | dev = phy_device_create(bus, addr, phy_id); |
@@ -564,20 +573,32 @@ EXPORT_SYMBOL(genphy_restart_aneg); | |||
564 | */ | 573 | */ |
565 | int genphy_config_aneg(struct phy_device *phydev) | 574 | int genphy_config_aneg(struct phy_device *phydev) |
566 | { | 575 | { |
567 | int result = 0; | 576 | int result; |
568 | 577 | ||
569 | if (AUTONEG_ENABLE == phydev->autoneg) { | 578 | if (AUTONEG_ENABLE != phydev->autoneg) |
570 | int result = genphy_config_advert(phydev); | 579 | return genphy_setup_forced(phydev); |
571 | 580 | ||
572 | if (result < 0) /* error */ | 581 | result = genphy_config_advert(phydev); |
573 | return result; | 582 | |
583 | if (result < 0) /* error */ | ||
584 | return result; | ||
585 | |||
586 | if (result == 0) { | ||
587 | /* Advertisment hasn't changed, but maybe aneg was never on to | ||
588 | * begin with? Or maybe phy was isolated? */ | ||
589 | int ctl = phy_read(phydev, MII_BMCR); | ||
590 | |||
591 | if (ctl < 0) | ||
592 | return ctl; | ||
593 | |||
594 | if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) | ||
595 | result = 1; /* do restart aneg */ | ||
596 | } | ||
574 | 597 | ||
575 | /* Only restart aneg if we are advertising something different | 598 | /* Only restart aneg if we are advertising something different |
576 | * than we were before. */ | 599 | * than we were before. */ |
577 | if (result > 0) | 600 | if (result > 0) |
578 | result = genphy_restart_aneg(phydev); | 601 | result = genphy_restart_aneg(phydev); |
579 | } else | ||
580 | result = genphy_setup_forced(phydev); | ||
581 | 602 | ||
582 | return result; | 603 | return result; |
583 | } | 604 | } |