net: stmmac: convert to phylink-managed Wake-on-Lan

Convert stmmac to use phylink-managed Wake-on-Lan support. To achieve
this, we implement the .mac_wol_set() method, which simply configures
the driver model's struct device wakeup for stmmac, and sets the
priv->wolopts appropriately.

When STMMAC_FLAG_USE_PHY_WOL is set, in the stmmac world this means to
only use the PHY's WoL support and ignore the MAC's WoL capabilities.
To preserve this behaviour, we enable phylink's legacy mode, and avoid
telling phylink that the MAC has any WoL support. This achieves the
same functionality for this case.

When STMMAC_FLAG_USE_PHY_WOL is not set, we provide the MAC's WoL
capabilities to phylink, which then allows phylink to choose between
the PHY and MAC for WoL depending on their individual capabilities
as described in the phylink commit. This only augments the WoL
functionality with PHYs that declare to the driver model that they are
wake-up capable. Currently, very few PHY drivers support this.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/E1vBrRC-0000000BLzg-2tA4@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Russell King (Oracle)
2025-10-23 10:16:50 +01:00
committed by Jakub Kicinski
parent dc1a2a9ce5
commit 6911308d7d
4 changed files with 36 additions and 38 deletions

View File

@@ -291,6 +291,7 @@ struct stmmac_priv {
int hw_cap_support;
int synopsys_id;
u32 msg_enable;
/* Our MAC Wake-on-Lan options */
int wolopts;
int wol_irq;
u32 gmii_address_bus_config;
@@ -379,11 +380,6 @@ enum stmmac_state {
extern const struct dev_pm_ops stmmac_simple_pm_ops;
static inline bool stmmac_wol_enabled_mac(struct stmmac_priv *priv)
{
return priv->plat->pmt && device_may_wakeup(priv->device);
}
static inline bool stmmac_wol_enabled_phy(struct stmmac_priv *priv)
{
return !priv->plat->pmt && device_may_wakeup(priv->device);

View File

@@ -724,41 +724,19 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct stmmac_priv *priv = netdev_priv(dev);
if (!priv->plat->pmt)
return phylink_ethtool_get_wol(priv->phylink, wol);
mutex_lock(&priv->lock);
if (device_can_wakeup(priv->device)) {
wol->supported = WAKE_MAGIC | WAKE_UCAST;
if (priv->hw_cap_support && !priv->dma_cap.pmt_magic_frame)
wol->supported &= ~WAKE_MAGIC;
wol->wolopts = priv->wolopts;
}
mutex_unlock(&priv->lock);
return phylink_ethtool_get_wol(priv->phylink, wol);
}
static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct stmmac_priv *priv = netdev_priv(dev);
int ret;
if (!device_can_wakeup(priv->device))
return -EOPNOTSUPP;
ret = phylink_ethtool_set_wol(priv->phylink, wol);
if (!ret)
device_set_wakeup_enable(priv->device, !!wol->wolopts);
if (!priv->plat->pmt) {
int ret = phylink_ethtool_set_wol(priv->phylink, wol);
if (!ret)
device_set_wakeup_enable(priv->device, !!wol->wolopts);
return ret;
}
device_set_wakeup_enable(priv->device, !!wol->wolopts);
mutex_lock(&priv->lock);
priv->wolopts = wol->wolopts;
mutex_unlock(&priv->lock);
return 0;
return ret;
}
static int stmmac_ethtool_op_get_eee(struct net_device *dev,

View File

@@ -1073,6 +1073,20 @@ static int stmmac_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
return 0;
}
static int stmmac_mac_wol_set(struct phylink_config *config, u32 wolopts,
const u8 *sopass)
{
struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev));
device_set_wakeup_enable(priv->device, !!wolopts);
mutex_lock(&priv->lock);
priv->wolopts = wolopts;
mutex_unlock(&priv->lock);
return 0;
}
static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
.mac_get_caps = stmmac_mac_get_caps,
.mac_select_pcs = stmmac_mac_select_pcs,
@@ -1082,6 +1096,7 @@ static const struct phylink_mac_ops stmmac_phylink_mac_ops = {
.mac_link_up = stmmac_mac_link_up,
.mac_disable_tx_lpi = stmmac_mac_disable_tx_lpi,
.mac_enable_tx_lpi = stmmac_mac_enable_tx_lpi,
.mac_wol_set = stmmac_mac_wol_set,
};
/**
@@ -1266,6 +1281,15 @@ static int stmmac_phylink_setup(struct stmmac_priv *priv)
config->eee_enabled_default = true;
}
if (priv->plat->flags & STMMAC_FLAG_USE_PHY_WOL) {
config->wol_phy_legacy = true;
} else {
if (priv->dma_cap.pmt_remote_wake_up)
config->wol_mac_support |= WAKE_UCAST;
if (priv->dma_cap.pmt_magic_frame)
config->wol_mac_support |= WAKE_MAGIC;
}
fwnode = priv->plat->port_node;
if (!fwnode)
fwnode = dev_fwnode(priv->device);
@@ -7760,7 +7784,7 @@ int stmmac_suspend(struct device *dev)
priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv);
/* Enable Power down mode by programming the PMT regs */
if (stmmac_wol_enabled_mac(priv)) {
if (priv->wolopts) {
stmmac_pmt(priv, priv->hw, priv->wolopts);
priv->irq_wake = 1;
} else {
@@ -7774,7 +7798,7 @@ int stmmac_suspend(struct device *dev)
if (stmmac_wol_enabled_phy(priv))
phylink_speed_down(priv->phylink, false);
phylink_suspend(priv->phylink, stmmac_wol_enabled_mac(priv));
phylink_suspend(priv->phylink, !!priv->wolopts);
rtnl_unlock();
if (stmmac_fpe_supported(priv))
@@ -7850,7 +7874,7 @@ int stmmac_resume(struct device *dev)
* this bit because it can generate problems while resuming
* from another devices (e.g. serial console).
*/
if (stmmac_wol_enabled_mac(priv)) {
if (priv->wolopts) {
mutex_lock(&priv->lock);
stmmac_pmt(priv, priv->hw, 0);
mutex_unlock(&priv->lock);

View File

@@ -969,7 +969,7 @@ static int __maybe_unused stmmac_pltfr_noirq_suspend(struct device *dev)
if (!netif_running(ndev))
return 0;
if (!stmmac_wol_enabled_mac(priv)) {
if (!priv->wolopts) {
/* Disable clock in case of PWM is off */
clk_disable_unprepare(priv->plat->clk_ptp_ref);
@@ -990,7 +990,7 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev)
if (!netif_running(ndev))
return 0;
if (!stmmac_wol_enabled_mac(priv)) {
if (!priv->wolopts) {
/* enable the clk previously disabled */
ret = pm_runtime_force_resume(dev);
if (ret)