--- /dev/null
+From 90702dcd19c093621b422ba16fcfd870afe2552f Mon Sep 17 00:00:00 2001
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+Date: Tue, 7 Sep 2021 18:56:47 +0800
+Subject: net: stmmac: fix MAC not working when system resume back with WoL active
+
+From: Joakim Zhang <qiangqing.zhang@nxp.com>
+
+commit 90702dcd19c093621b422ba16fcfd870afe2552f upstream.
+
+We can reproduce this issue with below steps:
+1) enable WoL on the host
+2) host system suspended
+3) remote client send out wakeup packets
+We can see that host system resume back, but can't work, such as ping failed.
+
+After a bit digging, this issue is introduced by the commit 46f69ded988d
+("net: stmmac: Use resolved link config in mac_link_up()"), which use
+the finalised link parameters in mac_link_up() rather than the
+parameters in mac_config().
+
+There are two scenarios for MAC suspend/resume in STMMAC driver:
+
+1) MAC suspend with WoL inactive, stmmac_suspend() call
+phylink_mac_change() to notify phylink machine that a change in MAC
+state, then .mac_link_down callback would be invoked. Further, it will
+call phylink_stop() to stop the phylink instance. When MAC resume back,
+firstly phylink_start() is called to start the phylink instance, then
+call phylink_mac_change() which will finally trigger phylink machine to
+invoke .mac_config and .mac_link_up callback. All is fine since
+configuration in these two callbacks will be initialized, that means MAC
+can restore the state.
+
+2) MAC suspend with WoL active, phylink_mac_change() will put link
+down, but there is no phylink_stop() to stop the phylink instance, so it
+will link up again, that means .mac_config and .mac_link_up would be
+invoked before system suspended. After system resume back, it will do
+DMA initialization and SW reset which let MAC lost the hardware setting
+(i.e MAC_Configuration register(offset 0x0) is reset). Since link is up
+before system suspended, so .mac_link_up would not be invoked after
+system resume back, lead to there is no chance to initialize the
+configuration in .mac_link_up callback, as a result, MAC can't work any
+longer.
+
+After discussed with Russell King [1], we confirm that phylink framework
+have not take WoL into consideration yet. This patch calls
+phylink_suspend()/phylink_resume() functions which is newly introduced
+by Russell King to fix this issue.
+
+[1] https://lore.kernel.org/netdev/20210901090228.11308-1-qiangqing.zhang@nxp.com/
+
+Fixes: 46f69ded988d ("net: stmmac: Use resolved link config in mac_link_up()")
+Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 36 +++++++++++-----------
+ 1 file changed, 18 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -7118,8 +7118,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);
+@@ -7145,14 +7143,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 */
+@@ -7166,6 +7156,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,
+@@ -7256,13 +7256,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);
+@@ -7283,8 +7285,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;