mirror of
https://github.com/lukaszraczylo/talos-builder.git
synced 2026-07-16 06:34:05 +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>.
144 lines
4.9 KiB
Diff
144 lines
4.9 KiB
Diff
From 0000000000000000000000000000000000000003 Mon Sep 17 00:00:00 2001
|
|
From: Lukasz Raczylo <lukasz@raczylo.com>
|
|
Date: Fri, 24 Apr 2026 00:00:00 +0000
|
|
Subject: [PATCH 3/3] net: macb: add TX stall watchdog to recover from lost
|
|
TCOMP
|
|
|
|
Patches 1/3 and 2/3 close two races by which a TCOMP interrupt can
|
|
be lost on PCIe-attached macb instances. This patch adds a
|
|
defence-in-depth safety net: a per-queue delayed_work that calls
|
|
macb_tx_restart() if queue->tx_tail has not advanced in one second
|
|
despite the ring being non-empty.
|
|
|
|
The watchdog introduces no new recovery logic. macb_tx_restart()
|
|
already exists, is correctly locked, and already checks the
|
|
hardware's TBQP against the driver's head index before writing
|
|
TSTART: on a healthy ring it is a no-op at the hardware level. All
|
|
the watchdog adds is the trigger.
|
|
|
|
If patches 1/3 and 2/3 completely eliminate the stall, this code
|
|
never does anything beyond a spin_lock/unlock and a branch per
|
|
second per queue. If a further race remains -- hardware or
|
|
driver-level -- this turns a multi-minute silent hang into a
|
|
one-second bump.
|
|
|
|
On our 24-node Raspberry Pi 5 fleet this was empirically needed:
|
|
before the patches in this series, multiple nodes per day hit the
|
|
stall and required external watchdog intervention to recover.
|
|
|
|
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.h | 4 ++
|
|
drivers/net/ethernet/cadence/macb_main.c | 63 ++++++++++++++++++++++++
|
|
2 files changed, 67 insertions(+)
|
|
|
|
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
|
|
--- a/drivers/net/ethernet/cadence/macb.h
|
|
+++ b/drivers/net/ethernet/cadence/macb.h
|
|
@@ -1294,6 +1294,11 @@
|
|
struct work_struct tx_error_task;
|
|
bool txubr_pending;
|
|
bool tx_pending;
|
|
+
|
|
+ /* TX stall watchdog -- see macb_tx_stall_watchdog() in macb_main.c */
|
|
+ struct delayed_work tx_stall_watchdog_work;
|
|
+ unsigned int tx_stall_last_tail;
|
|
+
|
|
struct napi_struct napi_tx;
|
|
|
|
dma_addr_t rx_ring_dma;
|
|
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
|
|
@@ -2030,6 +2030,59 @@
|
|
return work_done;
|
|
}
|
|
|
|
+#define MACB_TX_STALL_INTERVAL_MS 1000
|
|
+
|
|
+/*
|
|
+ * TX stall watchdog.
|
|
+ *
|
|
+ * Defence-in-depth against lost TCOMP interrupts. macb already has a
|
|
+ * recovery chain (tx_pending -> txubr_pending -> macb_tx_restart())
|
|
+ * that fires on TCOMP; if TCOMP itself is lost the TX ring stalls
|
|
+ * silently until something else kicks TSTART. This watchdog runs
|
|
+ * once per second per queue, snapshots tx_tail, and calls
|
|
+ * macb_tx_restart() if the ring is non-empty and tx_tail has not
|
|
+ * advanced since the previous tick.
|
|
+ *
|
|
+ * macb_tx_restart() already checks the hardware's TBQP against the
|
|
+ * driver's head index before re-asserting TSTART, so on a healthy
|
|
+ * ring this is a no-op at the hardware level. The watchdog only
|
|
+ * adds the missing trigger.
|
|
+ */
|
|
+static void macb_tx_stall_watchdog(struct work_struct *work)
|
|
+{
|
|
+ struct macb_queue *queue = container_of(to_delayed_work(work),
|
|
+ struct macb_queue,
|
|
+ tx_stall_watchdog_work);
|
|
+ struct macb *bp = queue->bp;
|
|
+ unsigned int cur_tail, cur_head;
|
|
+ bool stalled = false;
|
|
+ unsigned long flags;
|
|
+
|
|
+ if (!netif_running(bp->dev))
|
|
+ return;
|
|
+
|
|
+ spin_lock_irqsave(&queue->tx_ptr_lock, flags);
|
|
+ cur_tail = queue->tx_tail;
|
|
+ cur_head = queue->tx_head;
|
|
+ if (cur_head != cur_tail &&
|
|
+ cur_tail == queue->tx_stall_last_tail)
|
|
+ stalled = true;
|
|
+ else
|
|
+ queue->tx_stall_last_tail = cur_tail;
|
|
+ spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);
|
|
+
|
|
+ if (stalled) {
|
|
+ netdev_warn_once(bp->dev,
|
|
+ "TX stall detected on queue %u (tail=%u head=%u); re-kicking TSTART\n",
|
|
+ (unsigned int)(queue - bp->queues),
|
|
+ cur_tail, cur_head);
|
|
+ macb_tx_restart(queue);
|
|
+ }
|
|
+
|
|
+ schedule_delayed_work(&queue->tx_stall_watchdog_work,
|
|
+ msecs_to_jiffies(MACB_TX_STALL_INTERVAL_MS));
|
|
+}
|
|
+
|
|
static void macb_hresp_error_task(struct work_struct *work)
|
|
{
|
|
struct macb *bp = from_work(bp, work, hresp_err_bh_work);
|
|
@@ -3297,6 +3350,9 @@
|
|
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
|
|
napi_enable(&queue->napi_rx);
|
|
napi_enable(&queue->napi_tx);
|
|
+ queue->tx_stall_last_tail = queue->tx_tail;
|
|
+ schedule_delayed_work(&queue->tx_stall_watchdog_work,
|
|
+ msecs_to_jiffies(MACB_TX_STALL_INTERVAL_MS));
|
|
}
|
|
|
|
macb_init_hw(bp);
|
|
@@ -3343,6 +3399,7 @@
|
|
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
|
|
napi_disable(&queue->napi_rx);
|
|
napi_disable(&queue->napi_tx);
|
|
+ cancel_delayed_work_sync(&queue->tx_stall_watchdog_work);
|
|
netdev_tx_reset_queue(netdev_get_tx_queue(dev, q));
|
|
}
|
|
|
|
@@ -4941,6 +4998,8 @@
|
|
}
|
|
|
|
INIT_WORK(&queue->tx_error_task, macb_tx_error_task);
|
|
+ INIT_DELAYED_WORK(&queue->tx_stall_watchdog_work,
|
|
+ macb_tx_stall_watchdog);
|
|
q++;
|
|
}
|
|
|
|
--
|
|
2.44.0
|