Commit 971f49de authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents d2fa7cc4 803dd9c7
......@@ -443,9 +443,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
if (!drv || !phydrv->suspend)
return false;
/* PHY not attached? May suspend. */
/* PHY not attached? May suspend if the PHY has not already been
* suspended as part of a prior call to phy_disconnect() ->
* phy_detach() -> phy_suspend() because the parent netdev might be the
* MDIO bus driver and clock gated at this point.
*/
if (!netdev)
return true;
return !phydev->suspended;
/* Don't suspend PHY if the attched netdev parent may wakeup.
* 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)
static int mdio_bus_suspend(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
/* We must stop the state machine manually, otherwise it stops out of
......@@ -479,19 +482,18 @@ static int mdio_bus_suspend(struct device *dev)
if (!mdio_bus_phy_may_suspend(phydev))
return 0;
return phydrv->suspend(phydev);
return phy_suspend(phydev);
}
static int mdio_bus_resume(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
int ret;
if (!mdio_bus_phy_may_suspend(phydev))
goto no_resume;
ret = phydrv->resume(phydev);
ret = phy_resume(phydev);
if (ret < 0)
return ret;
......
......@@ -699,6 +699,7 @@ int phy_suspend(struct phy_device *phydev)
{
struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
int ret = 0;
/* If the device has WOL enabled, we cannot suspend the PHY */
phy_ethtool_get_wol(phydev, &wol);
......@@ -706,18 +707,31 @@ int phy_suspend(struct phy_device *phydev)
return -EBUSY;
if (phydrv->suspend)
return phydrv->suspend(phydev);
return 0;
ret = phydrv->suspend(phydev);
if (ret)
return ret;
phydev->suspended = true;
return ret;
}
EXPORT_SYMBOL(phy_suspend);
int phy_resume(struct phy_device *phydev)
{
struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
int ret = 0;
if (phydrv->resume)
return phydrv->resume(phydev);
return 0;
ret = phydrv->resume(phydev);
if (ret)
return ret;
phydev->suspended = false;
return ret;
}
EXPORT_SYMBOL(phy_resume);
......
......@@ -327,6 +327,8 @@ struct phy_c45_device_ids {
* c45_ids: 802.3-c45 Device Identifers if is_c45.
* is_c45: Set to true if this phy uses clause 45 addressing.
* is_internal: Set to true if this phy is internal to a MAC.
* has_fixups: Set to true if this phy has fixups/quirks.
* suspended: Set to true if this phy has been suspended successfully.
* state: state of the PHY for management purposes
* dev_flags: Device-specific flags used by the PHY driver.
* addr: Bus address of PHY
......@@ -364,6 +366,7 @@ struct phy_device {
bool is_c45;
bool is_internal;
bool has_fixups;
bool suspended;
enum phy_state state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment