Merge branch 'stmmac-wol-fix'

Joakim Zhang says:

====================
net: stmmac: fix WoL issue

This patch set fixes stmmac not working after system resume back with WoL
active. Thanks a lot for Russell King keeps looking into this issue.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2021-09-07 14:04:59 +01:00
commit d1bf73387b
3 changed files with 103 additions and 18 deletions

View file

@ -7123,8 +7123,6 @@ int stmmac_suspend(struct device *dev)
if (!ndev || !netif_running(ndev))
return 0;
phylink_mac_change(priv->phylink, false);
mutex_lock(&priv->lock);
netif_device_detach(ndev);
@ -7150,14 +7148,6 @@ int stmmac_suspend(struct device *dev)
stmmac_pmt(priv, priv->hw, priv->wolopts);
priv->irq_wake = 1;
} else {
mutex_unlock(&priv->lock);
rtnl_lock();
if (device_may_wakeup(priv->device))
phylink_speed_down(priv->phylink, false);
phylink_stop(priv->phylink);
rtnl_unlock();
mutex_lock(&priv->lock);
stmmac_mac_set(priv, priv->ioaddr, false);
pinctrl_pm_select_sleep_state(priv->device);
/* Disable clock in case of PWM is off */
@ -7171,6 +7161,16 @@ int stmmac_suspend(struct device *dev)
mutex_unlock(&priv->lock);
rtnl_lock();
if (device_may_wakeup(priv->device) && priv->plat->pmt) {
phylink_suspend(priv->phylink, true);
} else {
if (device_may_wakeup(priv->device))
phylink_speed_down(priv->phylink, false);
phylink_suspend(priv->phylink, false);
}
rtnl_unlock();
if (priv->dma_cap.fpesel) {
/* Disable FPE */
stmmac_fpe_configure(priv, priv->ioaddr,
@ -7261,13 +7261,15 @@ int stmmac_resume(struct device *dev)
return ret;
}
if (!device_may_wakeup(priv->device) || !priv->plat->pmt) {
rtnl_lock();
phylink_start(priv->phylink);
/* We may have called phylink_speed_down before */
phylink_speed_up(priv->phylink);
rtnl_unlock();
rtnl_lock();
if (device_may_wakeup(priv->device) && priv->plat->pmt) {
phylink_resume(priv->phylink);
} else {
phylink_resume(priv->phylink);
if (device_may_wakeup(priv->device))
phylink_speed_up(priv->phylink);
}
rtnl_unlock();
rtnl_lock();
mutex_lock(&priv->lock);
@ -7288,8 +7290,6 @@ int stmmac_resume(struct device *dev)
mutex_unlock(&priv->lock);
rtnl_unlock();
phylink_mac_change(priv->phylink, true);
netif_device_attach(ndev);
return 0;

View file

@ -33,6 +33,7 @@
enum {
PHYLINK_DISABLE_STOPPED,
PHYLINK_DISABLE_LINK,
PHYLINK_DISABLE_MAC_WOL,
};
/**
@ -1282,6 +1283,9 @@ EXPORT_SYMBOL_GPL(phylink_start);
* network device driver's &struct net_device_ops ndo_stop() method. The
* network device's carrier state should not be changed prior to calling this
* function.
*
* This will synchronously bring down the link if the link is not already
* down (in other words, it will trigger a mac_link_down() method call.)
*/
void phylink_stop(struct phylink *pl)
{
@ -1301,6 +1305,84 @@ void phylink_stop(struct phylink *pl)
}
EXPORT_SYMBOL_GPL(phylink_stop);
/**
* phylink_suspend() - handle a network device suspend event
* @pl: a pointer to a &struct phylink returned from phylink_create()
* @mac_wol: true if the MAC needs to receive packets for Wake-on-Lan
*
* Handle a network device suspend event. There are several cases:
* - If Wake-on-Lan is not active, we can bring down the link between
* the MAC and PHY by calling phylink_stop().
* - If Wake-on-Lan is active, and being handled only by the PHY, we
* can also bring down the link between the MAC and PHY.
* - If Wake-on-Lan is active, but being handled by the MAC, the MAC
* still needs to receive packets, so we can not bring the link down.
*/
void phylink_suspend(struct phylink *pl, bool mac_wol)
{
ASSERT_RTNL();
if (mac_wol && (!pl->netdev || pl->netdev->wol_enabled)) {
/* Wake-on-Lan enabled, MAC handling */
mutex_lock(&pl->state_mutex);
/* Stop the resolver bringing the link up */
__set_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state);
/* Disable the carrier, to prevent transmit timeouts,
* but one would hope all packets have been sent. This
* also means phylink_resolve() will do nothing.
*/
netif_carrier_off(pl->netdev);
/* We do not call mac_link_down() here as we want the
* link to remain up to receive the WoL packets.
*/
mutex_unlock(&pl->state_mutex);
} else {
phylink_stop(pl);
}
}
EXPORT_SYMBOL_GPL(phylink_suspend);
/**
* phylink_resume() - handle a network device resume event
* @pl: a pointer to a &struct phylink returned from phylink_create()
*
* Undo the effects of phylink_suspend(), returning the link to an
* operational state.
*/
void phylink_resume(struct phylink *pl)
{
ASSERT_RTNL();
if (test_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state)) {
/* Wake-on-Lan enabled, MAC handling */
/* Call mac_link_down() so we keep the overall state balanced.
* Do this under the state_mutex lock for consistency. This
* will cause a "Link Down" message to be printed during
* resume, which is harmless - the true link state will be
* printed when we run a resolve.
*/
mutex_lock(&pl->state_mutex);
phylink_link_down(pl);
mutex_unlock(&pl->state_mutex);
/* Re-apply the link parameters so that all the settings get
* restored to the MAC.
*/
phylink_mac_initial_config(pl, true);
/* Re-enable and re-resolve the link parameters */
clear_bit(PHYLINK_DISABLE_MAC_WOL, &pl->phylink_disable_state);
phylink_run_resolve(pl);
} else {
phylink_start(pl);
}
}
EXPORT_SYMBOL_GPL(phylink_resume);
/**
* phylink_ethtool_get_wol() - get the wake on lan parameters for the PHY
* @pl: a pointer to a &struct phylink returned from phylink_create()

View file

@ -451,6 +451,9 @@ void phylink_mac_change(struct phylink *, bool up);
void phylink_start(struct phylink *);
void phylink_stop(struct phylink *);
void phylink_suspend(struct phylink *pl, bool mac_wol);
void phylink_resume(struct phylink *pl);
void phylink_ethtool_get_wol(struct phylink *, struct ethtool_wolinfo *);
int phylink_ethtool_set_wol(struct phylink *, struct ethtool_wolinfo *);