Files
talos-builder/patches/linux/0002-net-macb-re-check-ISR-after-IER-re-enable-in-macb_tx.patch
T
lukaszraczylo 2ed45176d6 Add macb silent TX stall fix series to kernel build
Three-patch series targeting the BCM2712/RP1 (Raspberry Pi 5)
silent TX hang documented at:
  * https://github.com/cilium/cilium/issues/43198
  * https://bugs.launchpad.net/ubuntu/+source/linux-raspi/+bug/2133877

  0001: flush PCIe posted write after TSTART doorbell
  0002: re-check ISR after IER re-enable in macb_tx_poll
  0003: add TX stall watchdog fallback for lost TCOMP

New patches live in patches/linux/ and are copied into
checkouts/pkgs/kernel/build/patches/ via a new 'patches-linux'
Makefile target, wired into the existing 'patches' aggregate.

Verified to apply cleanly against raspberrypi/linux @ f2f68e79f16f
(the ref pinned by the preceding commit).

Author of the patches: Lukasz Raczylo <lukasz@raczylo.com>.
2026-04-24 18:47:51 +01:00

99 lines
4.2 KiB
Diff

From 0000000000000000000000000000000000000002 Mon Sep 17 00:00:00 2001
From: Lukasz Raczylo <lukasz@raczylo.com>
Date: Fri, 24 Apr 2026 00:00:00 +0000
Subject: [PATCH 2/3] net: macb: re-check ISR after IER re-enable in
macb_tx_poll
macb_tx_poll() runs with TCOMP masked, drains the TX ring, then
calls napi_complete_done() and re-enables TCOMP via IER. An
existing comment in the function notes:
/* Packet completions only seem to propagate to raise
* interrupts when interrupts are enabled at the time, so if
* packets were sent while interrupts were disabled,
* they will not cause another interrupt to be generated when
* interrupts are re-enabled.
*/
and mitigates this by calling macb_tx_complete_pending() to look
for a completed descriptor whose TX_USED bit the hardware has
DMA'd but whose completion we processed without ever seeing an
interrupt for.
macb_tx_complete_pending() only inspects driver-visible ring state
(descriptor->ctrl, after rmb()). On PCIe-attached parts (BCM2712 +
RP1 on Raspberry Pi 5 in particular) the descriptor DMA write that
sets TX_USED can still be in flight in the PCIe fabric when we
check. The read-memory-barrier synchronises the CPU view of earlier
CPU writes, but does not force the peripheral's in-flight DMA to
retire. In that window the check returns false, napi exits, the
IER re-enable does not re-fire (the quirk above), and the queue
stalls silently.
Re-check the hardware's own ISR state as well. Reading a MAC
register after IER re-enable serves two purposes:
(1) It drains any in-flight PCIe DMA writes of descriptor state,
so a subsequent macb_tx_complete_pending() sees an accurate
view of TX_USED.
(2) It directly observes whether the hardware currently has a
pending TCOMP signal, catching the case the existing driver
comment describes (completions raised while masked, not
re-fired).
If either path indicates pending work, schedule NAPI again.
Combined with the PCIe posted-write flush in patch 1/3, this closes
the observed silent-TX-stall path on BCM2712/RP1 reported at the
links below.
Link: https://github.com/cilium/cilium/issues/43198
Link: https://bugs.launchpad.net/ubuntu/+source/linux-raspi/+bug/2133877
Signed-off-by: Lukasz Raczylo <lukasz@raczylo.com>
---
drivers/net/ethernet/cadence/macb_main.c | 25 +++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -2000,17 +2000,25 @@
if (work_done < budget && napi_complete_done(napi, work_done)) {
queue_writel(queue, IER, MACB_BIT(TCOMP));
- /* Packet completions only seem to propagate to raise
- * interrupts when interrupts are enabled at the time, so if
- * packets were sent while interrupts were disabled,
- * they will not cause another interrupt to be generated when
- * interrupts are re-enabled.
- * Check for this case here to avoid losing a wakeup. This can
- * potentially race with the interrupt handler doing the same
- * actions if an interrupt is raised just after enabling them,
- * but this should be harmless.
+ /*
+ * TCOMP events that fire while the interrupt is masked do
+ * not re-fire when IER is re-enabled. Catch this two ways
+ * to avoid losing a wakeup:
+ *
+ * (1) Read ISR -- catches completions the hardware flagged
+ * but that we did not see as an interrupt. The MMIO
+ * read doubles as a PCIe read barrier, flushing any
+ * in-flight descriptor TX_USED DMA writes into memory.
+ * (2) macb_tx_complete_pending() inspects the ring after
+ * that flush, catching a descriptor whose TX_USED is
+ * now visible as a result of the barrier.
+ *
+ * This can race with the interrupt handler taking the same
+ * path if an interrupt fires just after the IER write;
+ * rescheduling NAPI in that case is harmless.
*/
- if (macb_tx_complete_pending(queue)) {
+ if ((queue_readl(queue, ISR) & MACB_BIT(TCOMP)) ||
+ macb_tx_complete_pending(queue)) {
queue_writel(queue, IDR, MACB_BIT(TCOMP));
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
queue_writel(queue, ISR, MACB_BIT(TCOMP));
--
2.44.0