Netdev List
 help / color / mirror / Atom feed
From: Igor Velkov <iav@iav.lv>
To: Andrew Lunn <andrew@lunn.ch>,
	Heiner Kallweit <hkallweit1@gmail.com>,
	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>
Cc: "Lukas Wunner" <lukas@wunner.de>,
	"Rafael J. Wysocki" <rafael.j.wysocki@intel.com>,
	"Wei Fang" <wei.fang@nxp.com>,
	"Niklas Söderlund" <niklas.soderlund@ragnatech.se>,
	"Paul Barker" <paul@pbarker.dev>,
	"Florian Fainelli" <florian.fainelli@broadcom.com>,
	"Doug Berger" <opendmb@gmail.com>,
	"Thangaraj Samynathan" <Thangaraj.S@microchip.com>,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	"Igor Velkov" <iav@iav.lv>
Subject: [PATCH net v2 2/2] net: phy: postpone PHY interrupts during sleep with MAC-managed PM
Date: Mon, 26 Oct 2026 06:53:43 +0200	[thread overview]
Message-ID: <20261026045343.837889-3-iav@iav.lv> (raw)
In-Reply-To: <20261026045343.837889-1-iav@iav.lv>

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 and
phy_interrupt() runs the PHY driver's handler at any point of the sleep
transition. If the MAC driver powers the MDIO bus down, the MDIO access
in that handler can stall the CPU. This happens on both sides:

- suspend: the MAC's suspend callback stops the PHY, the link goes
  down, and the handler runs while the MAC powers down;
- resume: resume_device_irqs() re-enables a pending interrupt before
  the MAC resumes.

On Helios64 (dwmac-rk, RTL8211F with its interrupt line described in
DT) both hang the board: the handler reads INSR while the GMAC clocks
are off, after rk_gmac_suspend() or before rk_gmac_resume().

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. As for other PHYs, an interrupt in that window now signals a
wakeup event if Wake-on-LAN is enabled or the device may wake the
system.

MAC drivers that close the interface in suspend free the interrupt
before the PHY resumes, so phy_free_interrupt() re-enables a line left
disabled by a postponed interrupt if other handlers still share it.

Tested on Helios64 with 7.3, s2idle without Wake-on-LAN, GMAC clocks
off in suspend: 10 of 10 cycles got through suspend, 4 of them then
hit a separate PCIe error on resume. The same kernel without these
changes hung or reset after the link went down in 10 of 10.

Fixes: 1758bde2e4aa ("net: phy: Don't trigger state machine while in suspend")
Signed-off-by: Igor Velkov <iav@iav.lv>
---
 drivers/net/phy/phy.c        |  9 ++++++++
 drivers/net/phy/phy_device.c | 44 ++++++++++++++++++++++--------------
 2 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index fce9bc7be330..00aa48e807a5 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1508,6 +1508,15 @@ void phy_free_interrupt(struct phy_device *phydev)
 {
 	phy_disable_interrupts(phydev);
 	free_irq(phydev->irq, phydev);
+
+	/* Undo the disable_irq_nosync() of a postponed interrupt if the line
+	 * is still shared; otherwise the next irq_startup() resets the depth.
+	 */
+	if (phydev->irq_rerun) {
+		phydev->irq_rerun = 0;
+		if (irq_has_action(phydev->irq))
+			enable_irq(phydev->irq);
+	}
 }
 EXPORT_SYMBOL(phy_free_interrupt);
 
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 5d4508bcfbe9..e2807e08e436 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -336,18 +336,20 @@ 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.
+	 * This holds when the MAC manages PHY PM too: an interrupt can still
+	 * fire while the MAC has the PHY or the MDIO bus powered down.
 	 */
 	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
@@ -364,13 +366,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;
@@ -393,19 +415,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


  parent reply	other threads:[~2026-10-26  4:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-26  4:53 [PATCH net v2 0/2] net: phy: postpone PHY interrupts during sleep with MAC-managed PM Igor Velkov
2026-10-26  4:53 ` [PATCH net v2 1/2] net: phy: move irq_suspended and irq_rerun out of the bitfield Igor Velkov
2026-10-26 12:54   ` Andrew Lunn
2026-10-26 17:32     ` Igor Velkov
2026-10-26  4:53 ` Igor Velkov [this message]
2026-10-27 16:55   ` [PATCH net v2 2/2] net: phy: postpone PHY interrupts during sleep with MAC-managed PM 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=20261026045343.837889-3-iav@iav.lv \
    --to=iav@iav.lv \
    --cc=Thangaraj.S@microchip.com \
    --cc=andrew@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@kernel.org \
    --cc=florian.fainelli@broadcom.com \
    --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=niklas.soderlund@ragnatech.se \
    --cc=opendmb@gmail.com \
    --cc=pabeni@redhat.com \
    --cc=paul@pbarker.dev \
    --cc=rafael.j.wysocki@intel.com \
    --cc=wei.fang@nxp.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