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
next 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