Skip to contentSkip to conversation

net: stmmac: improve WOL

PATCH In review Jisheng Zhang 2 participants 7 messages Jul 27, 2020 – Jul 29, 2020

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover net: stmmac: improve WOL

Currently, stmmac driver relies on the HW PMT to support WOL. We want to support phy based WOL.

patch1 is a small improvement to disable WAKE_MAGIC for PMT case if no pmt_magic_frame.
patch2 and patch3 are two prepation patches.
patch4 implement the phy based WOL
patch5 tries to save a bit energy if WOL is enabled.

Jisheng Zhang (5):
net: stmmac: Remove WAKE_MAGIC if HW shows no pmt_magic_frame
net: stmmac: Move device_can_wakeup() check earlier in set_wol
net: stmmac: only call pmt() during suspend/resume if HW enables PMT
net: stmmac: Support WOL with phy
net: stmmac: speed down the PHY, if WoL used, to save energy

 .../ethernet/stmicro/stmmac/stmmac_ethtool.c  | 19 ++++++++++++++++---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 18 +++++++++++++++---
 2 files changed, 31 insertions(+), 6 deletions(-)
Signature · 1 line
2.28.0.rc0
#1 lore raw

PATCH 1/5 net: stmmac: Remove WAKE_MAGIC if HW shows no pmt_magic_frame

Remove WAKE_MAGIC from supported modes if the HW capability register shows no support for pmt_magic_frame.

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +2 -0
index eae11c585025..9e0af626a24a 100644
@@ -603,6 +603,8 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *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);
Signature · 1 line
2.28.0.rc0
#2 lore raw

PATCH 2/5 net: stmmac: Move device_can_wakeup() check earlier in set_wol

In reply to Jisheng Zhang

If !device_can_wakeup(), there's no need to futher check. And return -EOPNOTSUPP rather than -EINVAL if !device_can_wakeup().

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +3 -3
index 9e0af626a24a..79795bebd3a2 100644
@@ -615,15 +615,15 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 	struct stmmac_priv *priv = netdev_priv(dev);
 	u32 support = WAKE_MAGIC | WAKE_UCAST;
 
+	if (!device_can_wakeup(priv->device))
+		return -EOPNOTSUPP;
+
 	/* By default almost all GMAC devices support the WoL via
 	 * magic frame but we can disable it if the HW capability
 	 * register shows no support for pmt_magic_frame. */
 	if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame))
 		wol->wolopts &= ~WAKE_MAGIC;
 
-	if (!device_can_wakeup(priv->device))
-		return -EINVAL;
-
 	if (wol->wolopts & ~support)
 		return -EINVAL;
 
Signature · 1 line
2.28.0.rc0
#3 lore raw

PATCH 3/5 net: stmmac: only call pmt() during suspend/resume if HW enables PMT

In reply to Jisheng Zhang

This is to prepare WOL support with phy. Compared with WOL implementation which relies on the MAC's PMT features, in phy supported WOL case, device_may_wakeup() may also be true, but we should not call mac's pmt() function if HW doesn't enable PMT.

And during resume, we should call phylink_start() if PMT is disabled.

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +3 -3
index 73677c3b33b6..358fd3bf9ef5 100644
@@ -5085,7 +5085,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 (device_may_wakeup(priv->device)) {
+	if (device_may_wakeup(priv->device) && priv->plat->pmt) {
 		stmmac_pmt(priv, priv->hw, priv->wolopts);
 		priv->irq_wake = 1;
 	} else {
@@ -5157,7 +5157,7 @@ int stmmac_resume(struct device *dev)
 	 * this bit because it can generate problems while resuming
 	 * from another devices (e.g. serial console).
 	 */
-	if (device_may_wakeup(priv->device)) {
+	if (device_may_wakeup(priv->device) && priv->plat->pmt) {
 		mutex_lock(&priv->lock);
 		stmmac_pmt(priv, priv->hw, 0);
 		mutex_unlock(&priv->lock);
@@ -5200,7 +5200,7 @@ int stmmac_resume(struct device *dev)
 
 	mutex_unlock(&priv->lock);
 
-	if (!device_may_wakeup(priv->device)) {
+	if (!device_may_wakeup(priv->device) || !priv->plat->pmt) {
 		rtnl_lock();
 		phylink_start(priv->phylink);
 		rtnl_unlock();
Signature · 1 line
2.28.0.rc0
#4 lore raw

PATCH 4/5 net: stmmac: Support WOL with phy

In reply to Jisheng Zhang

Currently, the stmmac driver WOL implementation relies on MAC's PMT feature. We have a case: the MAC HW doesn't enable PMT, instead, we rely on the phy to support WOL. Implement the support for this case.

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 11 +++++++++++
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c    |  4 ++++
 2 files changed, 15 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +11 -0
index 79795bebd3a2..05d63963fdb7 100644
@@ -600,6 +600,9 @@ 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;
@@ -618,6 +621,14 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 	if (!device_can_wakeup(priv->device))
 		return -EOPNOTSUPP;
 
+	if (!priv->plat->pmt) {
+		int ret = phylink_ethtool_set_wol(priv->phylink, wol);
+
+		if (!ret)
+			device_set_wakeup_enable(&dev->dev, !!wol->wolopts);
+		return ret;
+	}
+
 	/* By default almost all GMAC devices support the WoL via
 	 * magic frame but we can disable it if the HW capability
 	 * register shows no support for pmt_magic_frame. */
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +4 -0
index 358fd3bf9ef5..32c0c9647b87 100644
@@ -1075,6 +1075,7 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
  */
 static int stmmac_init_phy(struct net_device *dev)
 {
+	struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
 	struct stmmac_priv *priv = netdev_priv(dev);
 	struct device_node *node;
 	int ret;
@@ -1100,6 +1101,9 @@ static int stmmac_init_phy(struct net_device *dev)
 		ret = phylink_connect_phy(priv->phylink, phydev);
 	}
 
+	phylink_ethtool_get_wol(priv->phylink, &wol);
+	device_set_wakeup_capable(priv->device, !!wol.supported);
+
 	return ret;
 }
 
Signature · 1 line
2.28.0.rc0
#5 lore raw

PATCH 5/5 net: stmmac: Speed down the PHY if WoL to save energy

In reply to Jisheng Zhang

When WoL is enabled and the machine is powered off, the PHY remains waiting for wakeup events at max speed, which is a waste of energy.

Slow down the PHY speed before stopping the ethernet if WoL is enabled,

---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +8 -0
index 32c0c9647b87..89b2b3472852 100644
@@ -2823,6 +2823,8 @@ static int stmmac_open(struct net_device *dev)
 	stmmac_init_coalesce(priv);
 
 	phylink_start(priv->phylink);
+	/* We may have called phylink_speed_down before */
+	phylink_speed_up(priv->phylink);
 
 	/* Request the IRQ lines */
 	ret = request_irq(dev->irq, stmmac_interrupt,
@@ -2896,6 +2898,8 @@ static int stmmac_release(struct net_device *dev)
 	if (priv->eee_enabled)
 		del_timer_sync(&priv->eee_ctrl_timer);
 
+	if (device_may_wakeup(priv->device))
+		phylink_speed_down(priv->phylink, false);
 	/* Stop and disconnect the PHY */
 	phylink_stop(priv->phylink);
 	phylink_disconnect_phy(priv->phylink);
@@ -5095,6 +5099,8 @@ int stmmac_suspend(struct device *dev)
 	} 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);
@@ -5207,6 +5213,8 @@ int stmmac_resume(struct device *dev)
 	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();
 	}
 
Signature · 1 line
2.28.0.rc0
maintainer
#6 lore raw
In reply to Jisheng Zhang

From: Jisheng Zhang <[email protected]>
Date: Mon, 27 Jul 2020 19:01:07 +0800

Quoted 8 lines

Currently, stmmac driver relies on the HW PMT to support WOL. We want to support phy based WOL.

patch1 is a small improvement to disable WAKE_MAGIC for PMT case if no pmt_magic_frame.
patch2 and patch3 are two prepation patches.
patch4 implement the phy based WOL
patch5 tries to save a bit energy if WOL is enabled.

Series applied to net-next, thanks.