From: "Russell King (Oracle)" Subject: [PATCH net-next 4/4] net: phy: track PHY WoL enable state Track the PHY Wake-on-LAN enable state so we don't need to call phy_ethtool_get_wol() in phy_suspend(), thus taking the phydev lock. Signed-off-by: Russell King (Oracle) --- drivers/net/phy/phy.c | 10 ++++++++++ drivers/net/phy/phy_device.c | 17 ++++++++++++++--- include/linux/phy.h | 2 ++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5bb33af2a4cb..2324544aae0d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1644,11 +1644,21 @@ EXPORT_SYMBOL(phy_ethtool_set_eee); */ int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { + struct ethtool_wolinfo w = { .cmd = ETHTOOL_GWOL }; int ret; if (phydev->drv && phydev->drv->set_wol) { mutex_lock(&phydev->lock); ret = phydev->drv->set_wol(phydev, wol); + + /* Read back the WoL enabled state for the PHY and update + * our saved state. + */ + if (phydev->drv->get_wol) { + phydev->drv->get_wol(phydev, &w); + phydev->phy_wol_enabled = w.wolopts; + } + mutex_unlock(&phydev->lock); return ret; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 2ce74593d6e4..c874c1ec5ada 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1850,7 +1850,6 @@ EXPORT_SYMBOL(phy_detach); int phy_suspend(struct phy_device *phydev) { - struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; struct net_device *netdev = phydev->attached_dev; struct phy_driver *phydrv = phydev->drv; int ret; @@ -1858,8 +1857,9 @@ int phy_suspend(struct phy_device *phydev) if (phydev->suspended) return 0; - phy_ethtool_get_wol(phydev, &wol); - phydev->wol_enabled = wol.wolopts || (netdev && netdev->wol_enabled); + phydev->wol_enabled = phydev->phy_wol_enabled || + (netdev && netdev->wol_enabled); + /* If the device has WOL enabled, we cannot suspend the PHY */ if (phydev->wol_enabled && !(phydrv->flags & PHY_ALWAYS_CALL_SUSPEND)) return -EBUSY; @@ -3251,6 +3251,14 @@ struct fwnode_handle *fwnode_get_phy_node(const struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_get_phy_node); +static void phy_update_wol_state(struct phy_device *phydev) +{ + struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; + + phy_ethtool_get_wol(phydev, &wol); + phydev->phy_wol_enabled = wol.wolopts; +} + /** * phy_probe - probe and init a PHY device * @dev: device to probe and init @@ -3364,6 +3372,9 @@ static int phy_probe(struct device *dev) /* Set the state to READY by default */ phydev->state = PHY_READY; + /* Initialise phydev->wol_enabled state */ + phy_update_wol_state(phydev); + /* Get the LEDs from the device tree, and instantiate standard * LEDs for them. */ diff --git a/include/linux/phy.h b/include/linux/phy.h index 5dcab361a220..514c1d077bb9 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -557,6 +557,7 @@ struct macsec_ops; * @downshifted_rate: Set true if link speed has been downshifted. * @is_on_sfp_module: Set true if PHY is located on an SFP module. * @mac_managed_pm: Set true if MAC driver takes of suspending/resuming PHY + * @phy_wol_enabled: Set to true if the PHY has Wake-on-Lan enabled. * @wol_enabled: Set to true if the PHY or the attached MAC have Wake-on-LAN * enabled. * @state: State of the PHY for management purposes @@ -655,6 +656,7 @@ struct phy_device { unsigned downshifted_rate:1; unsigned is_on_sfp_module:1; unsigned mac_managed_pm:1; + unsigned phy_wol_enabled:1; unsigned wol_enabled:1; unsigned autoneg:1; -- 2.30.2