Netdev List
 help / color / mirror / Atom feed
From: Igor Velkov <iav@iav.lv>
To: Andrew Lunn <andrew@lunn.ch>, Heiner Kallweit <hkallweit1@gmail.com>
Cc: Russell King <linux@armlinux.org.uk>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@kernel.org>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Lukas Wunner <lukas@wunner.de>,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH net] net: phy: postpone PHY interrupts during sleep with MAC-managed PM
Date: Fri,  2 Oct 2026 07:35:48 +0300	[thread overview]
Message-ID: <20261002043548.1302145-1-iav@iav.lv> (raw)

mdio_bus_phy_suspend() and mdio_bus_phy_resume() return early when the
MAC driver manages PHY PM, so the PHY never gets irq_suspended. A PHY
interrupt that wakes the system fires as soon as resume_device_irqs()
re-enables the line, before the MAC driver resumes, and phy_interrupt()
runs the PHY driver's handler at once. If the MDIO bus was powered down
in suspend, the MDIO access in that handler stalls the CPU.

On Helios64 (dwmac-rk, RTL8211F with an interrupt line, Wake-on-LAN in
the PHY) the wake interrupt reads INSR while the GMAC clocks are off,
and the board hangs within a few suspend cycles.

Set irq_suspended for these PHYs too. The PHY device is a child of its
MDIO bus, so mdio_bus_phy_resume() runs after the bus is back (with
stmmac, after the MAC) and replays the postponed interrupt then.
phy_suspend(), phy_resume() and the state machine stay with the MAC
driver.

Drop a pending rerun when the interrupt is freed: MAC drivers that close
the interface in suspend free and request it again before the PHY
resumes.

Tested on Helios64 with 7.3-rc5, the GMAC powered down in suspend and
Wake-on-LAN in the PHY: 20 of 20 magic-packet wakes. Without it the
same setup hung within 1 to 7 cycles in 14 of 16 runs, some on
instrumented builds; one run passed 25 cycles. ODROID-HC4
(dwmac-meson8b, RTL8211F with an interrupt line): 10 of 10.

Fixes: 1758bde2e4aa ("net: phy: Don't trigger state machine while in suspend")
Assisted-by: LLM
Signed-off-by: Igor Velkov <iav@iav.lv>
---
This replaces the dwmac-rk change that kept the GMAC powered instead:
https://lore.kernel.org/r/20260930-dwmac-rk-phy-wol-v1-1-9fdc50bd9ae4@iav.lv

Build-tested on net: allmodconfig and allyesconfig with W=1, no new
warnings.

 drivers/net/phy/phy.c        |  2 ++
 drivers/net/phy/phy_device.c | 43 ++++++++++++++++++++++--------------
 2 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index fce9bc7be330..cd189ecee55e 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1507,6 +1507,8 @@ EXPORT_SYMBOL(phy_request_interrupt);
 void phy_free_interrupt(struct phy_device *phydev)
 {
 	phy_disable_interrupts(phydev);
+	/* A freed interrupt has nothing left to rerun on resume. */
+	phydev->irq_rerun = 0;
 	free_irq(phydev->irq, phydev);
 }
 EXPORT_SYMBOL(phy_free_interrupt);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 94b2e85e00a3..948818964841 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -347,18 +347,19 @@ static __maybe_unused int mdio_bus_phy_suspend(struct device *dev)
 {
 	struct phy_device *phydev = to_phy_device(dev);
 
-	if (phydev->mac_managed_pm)
-		return 0;
-
 	/* Wakeup interrupts may occur during the system sleep transition when
 	 * the PHY is inaccessible. Set flag to postpone handling until the PHY
 	 * has resumed. Wait for concurrent interrupt handler to complete.
+	 * The MDIO bus may be powered down even when the MAC manages PHY PM.
 	 */
 	if (phy_interrupt_is_valid(phydev)) {
 		phydev->irq_suspended = 1;
 		synchronize_irq(phydev->irq);
 	}
 
+	if (phydev->mac_managed_pm)
+		return 0;
+
 	/* We must stop the state machine manually, otherwise it stops out of
 	 * control, possibly with the phydev->lock held. Upon resume, netdev
 	 * may call phy routines that try to grab the same lock, and that may
@@ -375,13 +376,33 @@ static __maybe_unused int mdio_bus_phy_suspend(struct device *dev)
 	return phy_suspend(phydev);
 }
 
+static __maybe_unused void mdio_bus_phy_resume_irq(struct phy_device *phydev)
+{
+	if (!phy_interrupt_is_valid(phydev))
+		return;
+
+	phydev->irq_suspended = 0;
+	synchronize_irq(phydev->irq);
+
+	/* Rerun interrupts which were postponed by phy_interrupt()
+	 * because they occurred during the system sleep transition.
+	 */
+	if (phydev->irq_rerun) {
+		phydev->irq_rerun = 0;
+		enable_irq(phydev->irq);
+		irq_wake_thread(phydev->irq, phydev);
+	}
+}
+
 static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
 {
 	struct phy_device *phydev = to_phy_device(dev);
 	int ret;
 
-	if (phydev->mac_managed_pm)
+	if (phydev->mac_managed_pm) {
+		mdio_bus_phy_resume_irq(phydev);
 		return 0;
+	}
 
 	if (!phydev->suspended_by_mdio_bus)
 		goto no_resume;
@@ -404,19 +425,7 @@ static __maybe_unused int mdio_bus_phy_resume(struct device *dev)
 	if (ret < 0)
 		return ret;
 no_resume:
-	if (phy_interrupt_is_valid(phydev)) {
-		phydev->irq_suspended = 0;
-		synchronize_irq(phydev->irq);
-
-		/* Rerun interrupts which were postponed by phy_interrupt()
-		 * because they occurred during the system sleep transition.
-		 */
-		if (phydev->irq_rerun) {
-			phydev->irq_rerun = 0;
-			enable_irq(phydev->irq);
-			irq_wake_thread(phydev->irq, phydev);
-		}
-	}
+	mdio_bus_phy_resume_irq(phydev);
 
 	if (phy_uses_state_machine(phydev))
 		phy_start_machine(phydev);
-- 
2.43.0


             reply	other threads:[~2026-10-02  4:36 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-02  4:35 Igor Velkov [this message]
2026-10-02  5:03 ` [PATCH net] net: phy: postpone PHY interrupts during sleep with MAC-managed PM Igor Velkov
2026-10-03 20:35 ` Igor Velkov
2026-10-04 14:28 ` Andrew Lunn
2026-10-04 18:21   ` Igor Velkov
2026-10-04 14:35 ` Andrew Lunn
2026-10-06  4:38 ` netdev-bot+sashiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261002043548.1302145-1-iav@iav.lv \
    --to=iav@iav.lv \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=hkallweit1@gmail.com \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=lukas@wunner.de \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox