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 - 2026 Red Hat, Inc.