aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-01-27 03:16:56 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-27 03:16:56 -0500
commit971f49dee2639badd70bea6cf92e4eaa357ffecf (patch)
treeddf90b1789e8a24547a0bf6786274df77eebd330
parentd2fa7cc4e3bd759f5c8e093d1e08b718c722f319 (diff)
parent803dd9c77ac3a08958535f2a1ad5890104e2c235 (diff)
Merge branch 'phy-next'
Florian Fainelli says: ==================== net: phy: prevent double suspend This patch series addresses a problem that Fugang and I observed on different platforms where a given PHY device might end-up being suspended twice. Once as part of the call from ndo_open() all the way down to phy_detach() and phy_suspend() and a second time when the generic platform device/driver suspend/resume callbacks are called in drivers/net/phy/mdio_bus.c. Thanks to Fugang for giving this a quick try on i.MX6/FEC and reporting positive test results! ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/phy/mdio_bus.c14
-rw-r--r--drivers/net/phy/phy_device.c22
-rw-r--r--include/linux/phy.h3
3 files changed, 29 insertions, 10 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 50051f271b10..095ef3fe369a 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -443,9 +443,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
443 if (!drv || !phydrv->suspend) 443 if (!drv || !phydrv->suspend)
444 return false; 444 return false;
445 445
446 /* PHY not attached? May suspend. */ 446 /* PHY not attached? May suspend if the PHY has not already been
447 * suspended as part of a prior call to phy_disconnect() ->
448 * phy_detach() -> phy_suspend() because the parent netdev might be the
449 * MDIO bus driver and clock gated at this point.
450 */
447 if (!netdev) 451 if (!netdev)
448 return true; 452 return !phydev->suspended;
449 453
450 /* Don't suspend PHY if the attched netdev parent may wakeup. 454 /* Don't suspend PHY if the attched netdev parent may wakeup.
451 * The parent may point to a PCI device, as in tg3 driver. 455 * The parent may point to a PCI device, as in tg3 driver.
@@ -465,7 +469,6 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
465 469
466static int mdio_bus_suspend(struct device *dev) 470static int mdio_bus_suspend(struct device *dev)
467{ 471{
468 struct phy_driver *phydrv = to_phy_driver(dev->driver);
469 struct phy_device *phydev = to_phy_device(dev); 472 struct phy_device *phydev = to_phy_device(dev);
470 473
471 /* We must stop the state machine manually, otherwise it stops out of 474 /* We must stop the state machine manually, otherwise it stops out of
@@ -479,19 +482,18 @@ static int mdio_bus_suspend(struct device *dev)
479 if (!mdio_bus_phy_may_suspend(phydev)) 482 if (!mdio_bus_phy_may_suspend(phydev))
480 return 0; 483 return 0;
481 484
482 return phydrv->suspend(phydev); 485 return phy_suspend(phydev);
483} 486}
484 487
485static int mdio_bus_resume(struct device *dev) 488static int mdio_bus_resume(struct device *dev)
486{ 489{
487 struct phy_driver *phydrv = to_phy_driver(dev->driver);
488 struct phy_device *phydev = to_phy_device(dev); 490 struct phy_device *phydev = to_phy_device(dev);
489 int ret; 491 int ret;
490 492
491 if (!mdio_bus_phy_may_suspend(phydev)) 493 if (!mdio_bus_phy_may_suspend(phydev))
492 goto no_resume; 494 goto no_resume;
493 495
494 ret = phydrv->resume(phydev); 496 ret = phy_resume(phydev);
495 if (ret < 0) 497 if (ret < 0)
496 return ret; 498 return ret;
497 499
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 3fc91e89f5a5..bdfe51fc3a65 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -699,6 +699,7 @@ int phy_suspend(struct phy_device *phydev)
699{ 699{
700 struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); 700 struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
701 struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; 701 struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
702 int ret = 0;
702 703
703 /* If the device has WOL enabled, we cannot suspend the PHY */ 704 /* If the device has WOL enabled, we cannot suspend the PHY */
704 phy_ethtool_get_wol(phydev, &wol); 705 phy_ethtool_get_wol(phydev, &wol);
@@ -706,18 +707,31 @@ int phy_suspend(struct phy_device *phydev)
706 return -EBUSY; 707 return -EBUSY;
707 708
708 if (phydrv->suspend) 709 if (phydrv->suspend)
709 return phydrv->suspend(phydev); 710 ret = phydrv->suspend(phydev);
710 return 0; 711
712 if (ret)
713 return ret;
714
715 phydev->suspended = true;
716
717 return ret;
711} 718}
712EXPORT_SYMBOL(phy_suspend); 719EXPORT_SYMBOL(phy_suspend);
713 720
714int phy_resume(struct phy_device *phydev) 721int phy_resume(struct phy_device *phydev)
715{ 722{
716 struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); 723 struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
724 int ret = 0;
717 725
718 if (phydrv->resume) 726 if (phydrv->resume)
719 return phydrv->resume(phydev); 727 ret = phydrv->resume(phydev);
720 return 0; 728
729 if (ret)
730 return ret;
731
732 phydev->suspended = false;
733
734 return ret;
721} 735}
722EXPORT_SYMBOL(phy_resume); 736EXPORT_SYMBOL(phy_resume);
723 737
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 9c189a1fa3a2..685809835b5c 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -327,6 +327,8 @@ struct phy_c45_device_ids {
327 * c45_ids: 802.3-c45 Device Identifers if is_c45. 327 * c45_ids: 802.3-c45 Device Identifers if is_c45.
328 * is_c45: Set to true if this phy uses clause 45 addressing. 328 * is_c45: Set to true if this phy uses clause 45 addressing.
329 * is_internal: Set to true if this phy is internal to a MAC. 329 * is_internal: Set to true if this phy is internal to a MAC.
330 * has_fixups: Set to true if this phy has fixups/quirks.
331 * suspended: Set to true if this phy has been suspended successfully.
330 * state: state of the PHY for management purposes 332 * state: state of the PHY for management purposes
331 * dev_flags: Device-specific flags used by the PHY driver. 333 * dev_flags: Device-specific flags used by the PHY driver.
332 * addr: Bus address of PHY 334 * addr: Bus address of PHY
@@ -364,6 +366,7 @@ struct phy_device {
364 bool is_c45; 366 bool is_c45;
365 bool is_internal; 367 bool is_internal;
366 bool has_fixups; 368 bool has_fixups;
369 bool suspended;
367 370
368 enum phy_state state; 371 enum phy_state state;
369 372