Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -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;

+18 −4
Original line number Diff line number Diff line
@@ -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);

+3 −0
Original line number Diff line number Diff line
@@ -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;