Add phy_may_wakeup() which uses the driver model's device_may_wakeup()
when the PHY driver has marked the device as wakeup capable in the
driver model, otherwise use phy_drv_wol_enabled().
Replace the sites that used to call phy_drv_wol_enabled() with this
as checking the driver model will be more efficient than checking the
WoL state.
Export phy_may_wakeup() so that phylink can use it.
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phy_device.c | 14 ++++++++++++--
include/linux/phy.h | 9 +++++++++
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 01269b865f5e..4c8df9f02eb3 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -251,6 +251,16 @@ static bool phy_drv_wol_enabled(struct phy_device *phydev)
return wol.wolopts != 0;
}
+bool phy_may_wakeup(struct phy_device *phydev)
+{
+ /* If the PHY is using driver-model based wakeup, use that state. */
+ if (phy_can_wakeup(phydev))
+ return device_may_wakeup(&phydev->mdio.dev);
+
+ return phy_drv_wol_enabled(phydev);
+}
+EXPORT_SYMBOL_GPL(phy_may_wakeup);
+
static void phy_link_change(struct phy_device *phydev, bool up)
{
struct net_device *netdev = phydev->attached_dev;
@@ -302,7 +312,7 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
/* If the PHY on the mido bus is not attached but has WOL enabled
* we cannot suspend the PHY.
*/
- if (!netdev && phy_drv_wol_enabled(phydev))
+ if (!netdev && phy_may_wakeup(phydev))
return false;
/* PHY not attached? May suspend if the PHY has not already been
@@ -1909,7 +1919,7 @@ int phy_suspend(struct phy_device *phydev)
if (phydev->suspended || !phydrv)
return 0;
- phydev->wol_enabled = phy_drv_wol_enabled(phydev) ||
+ phydev->wol_enabled = phy_may_wakeup(phydev) ||
(netdev && netdev->ethtool->wol_enabled);
/* If the device has WOL enabled, we cannot suspend the PHY */
if (phydev->wol_enabled && !(phydrv->flags & PHY_ALWAYS_CALL_SUSPEND))
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 7f6758198948..2292ee9a93c0 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1391,6 +1391,15 @@ static inline bool phy_can_wakeup(struct phy_device *phydev)
return device_can_wakeup(&phydev->mdio.dev);
}
+/**
+ * phy_may_wakeup() - indicate whether PHY has driver model wakeup is enabled
+ * @phydev: The phy_device struct
+ *
+ * Returns: true/false depending on the PHY driver's device_set_wakeup_enabled()
+ * setting.
+ */
+bool phy_may_wakeup(struct phy_device *phydev);
+
void phy_resolve_aneg_pause(struct phy_device *phydev);
void phy_resolve_aneg_linkmode(struct phy_device *phydev);
--
2.47.3
On 9/28/25 10:58, Russell King (Oracle) wrote: > Add phy_may_wakeup() which uses the driver model's device_may_wakeup() > when the PHY driver has marked the device as wakeup capable in the > driver model, otherwise use phy_drv_wol_enabled(). > > Replace the sites that used to call phy_drv_wol_enabled() with this > as checking the driver model will be more efficient than checking the > WoL state. > > Export phy_may_wakeup() so that phylink can use it. > > Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> > --- > drivers/net/phy/phy_device.c | 14 ++++++++++++-- > include/linux/phy.h | 9 +++++++++ > 2 files changed, 21 insertions(+), 2 deletions(-) > > diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c > index 01269b865f5e..4c8df9f02eb3 100644 > --- a/drivers/net/phy/phy_device.c > +++ b/drivers/net/phy/phy_device.c > @@ -251,6 +251,16 @@ static bool phy_drv_wol_enabled(struct phy_device *phydev) > return wol.wolopts != 0; > } > > +bool phy_may_wakeup(struct phy_device *phydev) > +{ > + /* If the PHY is using driver-model based wakeup, use that state. */ > + if (phy_can_wakeup(phydev)) > + return device_may_wakeup(&phydev->mdio.dev); > + > + return phy_drv_wol_enabled(phydev); > +} > +EXPORT_SYMBOL_GPL(phy_may_wakeup); > + > static void phy_link_change(struct phy_device *phydev, bool up) > { > struct net_device *netdev = phydev->attached_dev; > @@ -302,7 +312,7 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) > /* If the PHY on the mido bus is not attached but has WOL enabled > * we cannot suspend the PHY. > */ > - if (!netdev && phy_drv_wol_enabled(phydev)) > + if (!netdev && phy_may_wakeup(phydev)) > return false; > > /* PHY not attached? May suspend if the PHY has not already been > @@ -1909,7 +1919,7 @@ int phy_suspend(struct phy_device *phydev) > if (phydev->suspended || !phydrv) > return 0; > > - phydev->wol_enabled = phy_drv_wol_enabled(phydev) || > + phydev->wol_enabled = phy_may_wakeup(phydev) || > (netdev && netdev->ethtool->wol_enabled); Hi Russell, First of all, thank you for taking the time to propose something. IIUC, using ethtool to enable WoL with, e.g: "ethtool -s end0 wol g" even if the WoL isn't really supported will prevent the phy suspend. Therefore, PHY drivers should be adapted to implement something like: if (!device_can_wakeup(&dev->mdio.dev)) return -EOPNOTSUPP; in their set_wol() ops to fully adapt to what you propose, right? > /* If the device has WOL enabled, we cannot suspend the PHY */ > if (phydev->wol_enabled && !(phydrv->flags & PHY_ALWAYS_CALL_SUSPEND)) > diff --git a/include/linux/phy.h b/include/linux/phy.h > index 7f6758198948..2292ee9a93c0 100644 > --- a/include/linux/phy.h > +++ b/include/linux/phy.h > @@ -1391,6 +1391,15 @@ static inline bool phy_can_wakeup(struct phy_device *phydev) > return device_can_wakeup(&phydev->mdio.dev); > } > > +/** > + * phy_may_wakeup() - indicate whether PHY has driver model wakeup is enabled > + * @phydev: The phy_device struct > + * > + * Returns: true/false depending on the PHY driver's device_set_wakeup_enabled() > + * setting. > + */ > +bool phy_may_wakeup(struct phy_device *phydev); > + > void phy_resolve_aneg_pause(struct phy_device *phydev); > void phy_resolve_aneg_linkmode(struct phy_device *phydev); >
On Tue, Sep 30, 2025 at 11:04:28AM +0200, Gatien CHEVALLIER wrote: > Hi Russell, > > First of all, thank you for taking the time to propose something. > > IIUC, using ethtool to enable WoL with, e.g: "ethtool -s end0 wol g" > even if the WoL isn't really supported will prevent the phy suspend. This is correct - whenever a PHY has WoL enabled, it won't be suspended as it has to listen for the configured wake-up packet(s). > Therefore, PHY drivers should be adapted to implement something like: > > if (!device_can_wakeup(&dev->mdio.dev)) > return -EOPNOTSUPP; > > in their set_wol() ops to fully adapt to what you propose, right? That's not sufficient. Yes, it's one of the things they need to do. 1. get_wol() should set ->supported to 0 (or at least not add anything to it) if wake-up is not possible. 2. set_wol() should not enable WoL modes or return -EOPNOTSUPP as you have above if wake-up is not possible. It should also call device_set_wakeup_enable() to indicate whether wake-up has been enabled for this device or not. 3. the PHY driver's probe function needs to be modified to call device_set_wakeup_capable() to configure whether this device _really_ can wake-up the system. See realtek_main.c::rtl8211f_probe() and broadcom.c as examples. 4. if using interrupt-based wake-up, use devm_pm_set_wake_irq() so the driver core can manage the irq-wake configuration. See realtek_main.c - that's the driver I recently fixed (it had many issues). -- RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
© 2016 - 2025 Red Hat, Inc.