Re: dwmac-motorcomm: RX dies after long s2idle, only wrapper SYS_RESET recovers
From: Giuseppe Nespolino
Date: Thu Aug 13 2026 - 10:34:42 EST
DISCLAIMER: most of what I write in this message comes from AI-driven
analysis, even though I manually tested the steps.
Follow-up, with the TX measurement I owed you, and a correction to
something I implied earlier.
TX first. The bug reproduced again today; I forced 20 raw Ethernet frames
out (AF_PACKET, EtherType 0x88b5, so no configuration change and no
dependency on a working RX):
mmc_tx_framecount_gb +20 frames really went out
netdev tx_packets +20
tx-0 vector +0
rx-0 vector +0
TX interrupts aren't delivered either, matching what you saw with OOB WOL
enabled. Register signature identical to the previous occurrence:
OOB_WOL_CTRL 0x1, MGMT_INT_CTRL0 0x11, MSI-X vector 0 unmasked, and all
512 RX descriptors written back with plausible lengths and OWN clear.
Now the correction: the failure is intermittent, and I had been assuming it
was deterministic for long suspends. With the pci_wake_from_d3() change
loaded I went through three long s2idle cycles and only the third broke:
13h52m lease 6s after resume fine
27min lease 7s after resume fine
31min no lease broken
The longest one was fine, so duration isn't a monotonic predictor either.
With n=3 I can't distinguish a partial effect of that change from plain
stochastic behaviour, so I'm claiming nothing for it - dropping it as a fix,
and happy to send it separately as a cleanup if you want it.
On the isolation I'd left open: motorcomm_init() on its own does not
recover the controller, not even followed by a full ip link down/up (tx-0
+0, rx-0 +0 throughout). The SYS_RESET is the necessary part.
But the reset alone isn't sufficient either, which answers the design
question I asked you, so you needn't. Right after the SYS_RESET:
MGMT_INT_CTRL0 0x003f0000 mask field 0x3f, every source masked
INT_MODERATION 0x00000000
reset + OOB_WOL_CTRL alone left interrupts dead; adding the
MGMT_INT_CTRL0 = 0 unmask and INT_MODERATION recovered it immediately
(tx-0 +16, rx-0 +220, DHCP completed). So the reset has to be followed by
the motorcomm_init() that resume already calls - it can neither replace it
nor be trimmed. What I can't separate is whether the OOB WOL clear or the
unmask is the load-bearing half, since the reset does both.
That makes the patch motorcomm_reset() plus the eFuse settle delay,
inserted before the existing motorcomm_init() call in motorcomm_resume().
Given the intermittency, waiting for natural occurrences is a poor way to
validate it. Instead I'll inject the fault deterministically: arm OOB WOL
by hand with the one writel, then suspend and resume, and check whether the
patched resume hook brings it back. On the current driver it stays dead, so
that gives a clean result per cycle instead of a coin flip. I'll keep
counting natural cycles in the background too.
Giuseppe