mirror of
https://github.com/lukaszraczylo/talos-builder.git
synced 2026-07-07 05:34:34 +00:00
2ed45176d6
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>.
99 lines
4.2 KiB
Diff
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
|