diff options
-rw-r--r-- | Documentation/networking/phy.txt | 3 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 5 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 56 |
3 files changed, 60 insertions, 4 deletions
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index d5b1a3935245..ebf270719402 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt | |||
@@ -255,7 +255,8 @@ Writing a PHY driver | |||
255 | 255 | ||
256 | config_init: configures PHY into a sane state after a reset. | 256 | config_init: configures PHY into a sane state after a reset. |
257 | For instance, a Davicom PHY requires descrambling disabled. | 257 | For instance, a Davicom PHY requires descrambling disabled. |
258 | probe: Does any setup needed by the driver | 258 | probe: Allocate phy->priv, optionally refuse to bind. |
259 | PHY may not have been reset or had fixups run yet. | ||
259 | suspend/resume: power management | 260 | suspend/resume: power management |
260 | config_aneg: Changes the speed/duplex/negotiation settings | 261 | config_aneg: Changes the speed/duplex/negotiation settings |
261 | read_status: Reads the current speed/duplex/negotiation settings | 262 | read_status: Reads the current speed/duplex/negotiation settings |
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5d7101b3b604..e3dd69100da8 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -318,6 +318,7 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
318 | { | 318 | { |
319 | struct mii_ioctl_data *mii_data = if_mii(ifr); | 319 | struct mii_ioctl_data *mii_data = if_mii(ifr); |
320 | u16 val = mii_data->val_in; | 320 | u16 val = mii_data->val_in; |
321 | int ret = 0; | ||
321 | 322 | ||
322 | switch (cmd) { | 323 | switch (cmd) { |
323 | case SIOCGMIIPHY: | 324 | case SIOCGMIIPHY: |
@@ -362,7 +363,7 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
362 | 363 | ||
363 | if (mii_data->reg_num == MII_BMCR && | 364 | if (mii_data->reg_num == MII_BMCR && |
364 | val & BMCR_RESET) | 365 | val & BMCR_RESET) |
365 | phy_init_hw(phydev); | 366 | ret = phy_init_hw(phydev); |
366 | break; | 367 | break; |
367 | 368 | ||
368 | case SIOCSHWTSTAMP: | 369 | case SIOCSHWTSTAMP: |
@@ -374,7 +375,7 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
374 | return -EOPNOTSUPP; | 375 | return -EOPNOTSUPP; |
375 | } | 376 | } |
376 | 377 | ||
377 | return 0; | 378 | return ret; |
378 | } | 379 | } |
379 | EXPORT_SYMBOL(phy_mii_ioctl); | 380 | EXPORT_SYMBOL(phy_mii_ioctl); |
380 | 381 | ||
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 |