diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2013-12-06 16:01:34 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-12-09 20:38:59 -0500 |
commit | 87aa9f9c61ad56d505641681812e92ad976f8608 (patch) | |
tree | f793d2ac5ed9680242a75fc363f1bee972f82f24 /drivers/net/phy/phy_device.c | |
parent | 06d87cec73d883690f690e72da498e7f0334f9bc (diff) |
net: phy: consolidate PHY reset in phy_init_hw()
There are quite a lot of drivers touching a PHY device MII_BMCR
register to reset the PHY without taking care of:
1) ensuring that BMCR_RESET is cleared after a given timeout
2) the PHY state machine resuming to the proper state and re-applying
potentially changed settings such as auto-negotiation
Introduce phy_poll_reset() which will take care of polling the MII_BMCR
for the BMCR_RESET bit to be cleared after a given timeout or return a
timeout error code.
In order to make sure the PHY is in a correct state, phy_init_hw() first
issues a software reset through MII_BMCR and then applies any fixups.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/phy_device.c')
-rw-r--r-- | drivers/net/phy/phy_device.c | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 6db36595eac9..5a619f0dcf73 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -364,7 +364,11 @@ int phy_device_register(struct phy_device *phydev) | |||
364 | phydev->bus->phy_map[phydev->addr] = phydev; | 364 | phydev->bus->phy_map[phydev->addr] = phydev; |
365 | 365 | ||
366 | /* Run all of the fixups for this PHY */ | 366 | /* Run all of the fixups for this PHY */ |
367 | phy_scan_fixups(phydev); | 367 | err = phy_init_hw(phydev); |
368 | if (err) { | ||
369 | pr_err("PHY %d failed to initialize\n", phydev->addr); | ||
370 | goto out; | ||
371 | } | ||
368 | 372 | ||
369 | err = device_add(&phydev->dev); | 373 | err = device_add(&phydev->dev); |
370 | if (err) { | 374 | if (err) { |
@@ -497,6 +501,47 @@ void phy_disconnect(struct phy_device *phydev) | |||
497 | } | 501 | } |
498 | EXPORT_SYMBOL(phy_disconnect); | 502 | EXPORT_SYMBOL(phy_disconnect); |
499 | 503 | ||
504 | /** | ||
505 | * phy_poll_reset - Safely wait until a PHY reset has properly completed | ||
506 | * @phydev: The PHY device to poll | ||
507 | * | ||
508 | * Description: According to IEEE 802.3, Section 2, Subsection 22.2.4.1.1, as | ||
509 | * published in 2008, a PHY reset may take up to 0.5 seconds. The MII BMCR | ||
510 | * register must be polled until the BMCR_RESET bit clears. | ||
511 | * | ||
512 | * Furthermore, any attempts to write to PHY registers may have no effect | ||
513 | * or even generate MDIO bus errors until this is complete. | ||
514 | * | ||
515 | * Some PHYs (such as the Marvell 88E1111) don't entirely conform to the | ||
516 | * standard and do not fully reset after the BMCR_RESET bit is set, and may | ||
517 | * even *REQUIRE* a soft-reset to properly restart autonegotiation. In an | ||
518 | * effort to support such broken PHYs, this function is separate from the | ||
519 | * standard phy_init_hw() which will zero all the other bits in the BMCR | ||
520 | * and reapply all driver-specific and board-specific fixups. | ||
521 | */ | ||
522 | static int phy_poll_reset(struct phy_device *phydev) | ||
523 | { | ||
524 | /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ | ||
525 | unsigned int retries = 12; | ||
526 | int ret; | ||
527 | |||
528 | do { | ||
529 | msleep(50); | ||
530 | ret = phy_read(phydev, MII_BMCR); | ||
531 | if (ret < 0) | ||
532 | return ret; | ||
533 | } while (ret & BMCR_RESET && --retries); | ||
534 | if (ret & BMCR_RESET) | ||
535 | return -ETIMEDOUT; | ||
536 | |||
537 | /* | ||
538 | * Some chips (smsc911x) may still need up to another 1ms after the | ||
539 | * BMCR_RESET bit is cleared before they are usable. | ||
540 | */ | ||
541 | msleep(1); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
500 | int phy_init_hw(struct phy_device *phydev) | 545 | int phy_init_hw(struct phy_device *phydev) |
501 | { | 546 | { |
502 | int ret; | 547 | int ret; |
@@ -504,12 +549,21 @@ int phy_init_hw(struct phy_device *phydev) | |||
504 | if (!phydev->drv || !phydev->drv->config_init) | 549 | if (!phydev->drv || !phydev->drv->config_init) |
505 | return 0; | 550 | return 0; |
506 | 551 | ||
552 | ret = phy_write(phydev, MII_BMCR, BMCR_RESET); | ||
553 | if (ret < 0) | ||
554 | return ret; | ||
555 | |||
556 | ret = phy_poll_reset(phydev); | ||
557 | if (ret < 0) | ||
558 | return ret; | ||
559 | |||
507 | ret = phy_scan_fixups(phydev); | 560 | ret = phy_scan_fixups(phydev); |
508 | if (ret < 0) | 561 | if (ret < 0) |
509 | return ret; | 562 | return ret; |
510 | 563 | ||
511 | return phydev->drv->config_init(phydev); | 564 | return phydev->drv->config_init(phydev); |
512 | } | 565 | } |
566 | EXPORT_SYMBOL(phy_init_hw); | ||
513 | 567 | ||
514 | /** | 568 | /** |
515 | * phy_attach_direct - attach a network device to a given PHY device pointer | 569 | * phy_attach_direct - attach a network device to a given PHY device pointer |