From: Colton Pawielski via B4 Relay <devnull+colton.pawielski.gmail.com@kernel.org>
To: Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
Daniel Palmer <daniel@0x0f.com>,
Geert Uytterhoeven <geert@linux-m68k.org>,
Karl Mehltretter <kmehltretter@gmail.com>,
Colton Pawielski <colton.pawielski@gmail.com>
Subject: [PATCH net v2] net: 8139cp: keep Rx masked while NAPI is scheduled
Date: Sat, 31 Oct 2026 11:47:23 -0500 [thread overview]
Message-ID: <20261031-b4-8139cp-napi-v2-1-5824797c0fe6@gmail.com> (raw)
From: Colton Pawielski <colton.pawielski@gmail.com>
cp_rx_poll() calls napi_complete_done() and only then takes cp->lock
with interrupts disabled to unmask the Rx interrupts. An interrupt
that is not masked while polling (TxOK, TxErr, ...) can arrive in
between. cp_interrupt() then sees the Rx status bits, which are still
set, finds NAPI no longer scheduled, masks Rx and schedules NAPI again.
cp_rx_poll() then carries on and unmasks Rx anyway.
From that point Rx interrupts are enabled while NAPI is scheduled:
cp_interrupt() leaves the Rx bits for the poll routine, does not mask
them because napi_schedule_prep() fails, and the level-triggered
interrupt fires again as soon as it returns. On an SH7751 LANDISK
under combined Tx/Rx load this interrupt storm was captured with a RAM
trace right before the board locked up hard.
Mask Rx in cp_interrupt() whenever Rx status is pending, not only when
NAPI gets scheduled. If the race leaves Rx unmasked, the next interrupt
masks it again, and the pending poll unmasks it when it completes.
Fixes: ab1e7e1d2666 ("8139cp: use napi_complete_done()")
Signed-off-by: Colton Pawielski <colton.pawielski@gmail.com>
---
An AI coding assistant (Claude Opus 5.5, in Claude Code) did most of the
debugging: it instrumented the driver with a RAM-backed trace of register
accesses and IRQ entry/exit that survives the power cycle, and decoded
the trace after the hang.
Tested on I-O DATA LANDISK boards (SH7751R, RTL8139C+ rev 0x20).
Without a fix, pulling 300 MB over ssh while reading the disk
(concurrent IDE and network DMA) hard-hung the board in 7 of 8 runs.
With this version that test passed every run on two boards over several
sessions (16/16 and 24/24), as did the runs that also pushed 100 MB to
the board at the same time (6/6 and 9/9).
The LANDISK is UP, so SMP was tested on a Raspberry Pi CM4 (4x
Cortex-A72, arm64, PROVE_LOCKING) with an RTL8139C+ on a PCI card
behind a PCIe-to-PCI bridge, pulling TCP data from the far end of the
card's link:
- without a fix: the CM4 hard-hung during the first 100 MB transfer
(2 of 2 boots)
- v1: lockdep warning within seconds ("HARDIRQ-safe -> HARDIRQ-unsafe
lock order", cp->lock held in cp_rx_poll() across
napi_complete_done())
- v2: 32/32 transfers (16x 100 MB, 16x 500 MB) and 12/12 runs with a
concurrent push, about 14 million interrupts, no lockdep warnings
It was also checked in QEMU: x86_64, -smp 4, PROVE_LOCKING, with
QEMU's emulated rtl8139 (which binds to 8139cp). Ping plus 1.5 GB of
TCP downloads ran without any lockdep warnings. v1 hard-locked there
shortly after link up.
---
Changes in v2:
- v1 moved napi_complete_done() under cp->lock, but it flushes GRO into
the stack, and a reply sent from there (ARP, TCP ACK) re-enters
cp_start_xmit() and deadlocks on cp->lock on SMP. Reported by the
Sashiko review, reproduced in QEMU and flagged by lockdep on the
CM4. Leave cp_rx_poll() alone and keep Rx masked from
cp_interrupt() instead.
- Reworded the subject, since the race is now recovered from rather than
closed.
- Dropped Daniel's and Geert's Tested-by since the fix is different.
- Link to v1: https://patch.msgid.link/20261021-b4-8139cp-napi-v1-1-c9b683d9564b@gmail.com
---
drivers/net/ethernet/realtek/8139cp.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 9016527e229a..8f81dc7deef1 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -600,11 +600,11 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
goto out_unlock;
}
- if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
- if (napi_schedule_prep(&cp->napi)) {
- cpw16_f(IntrMask, cp_norx_intr_mask);
+ if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) {
+ cpw16_f(IntrMask, cp_norx_intr_mask);
+ if (napi_schedule_prep(&cp->napi))
__napi_schedule(&cp->napi);
- }
+ }
if (status & (TxOK | TxErr | TxEmpty | SWInt))
cp_tx(cp);
---
base-commit: cb284914e749388eef402938bdb3115fe1f6d337
change-id: 20261021-b4-8139cp-napi-8e139f232736
Best regards,
--
Colton Pawielski <colton.pawielski@gmail.com>
reply other threads:[~2026-10-31 16:48 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261031-b4-8139cp-napi-v2-1-5824797c0fe6@gmail.com \
--to=devnull+colton.pawielski.gmail.com@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=colton.pawielski@gmail.com \
--cc=daniel@0x0f.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=geert@linux-m68k.org \
--cc=kmehltretter@gmail.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--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
all inboxes | Powered by JetHome®