[PATCH net v2 3/4] net: axienet: quiesce the TX queue across a DMA error reset
Sagi Maimon
maimon.sagi at gmail.com
Thu Sep 24 06:51:15 PDT 2026
axienet_dma_err_handler() resets the DMA engine, frees every TX
descriptor's skb and mapping, and rewinds lp->tx_bd_ci and
lp->tx_bd_tail to 0. It has two problems with the transmit path.
First, nothing excludes axienet_start_xmit() while it does so.
napi_disable() only stops axienet_tx_poll(), and the handler takes no
transmit lock. A transmit running concurrently can publish an skb into
a descriptor that the handler then frees, and dereference it afterwards
in netdev_sent_queue(), or program a descriptor whose mapping the
handler has just released and kick XAXIDMA_TX_TDESC with a tail pointer
the handler is about to rewind.
Second, the handler never restarts the queue. If the ring was full when
the error hit, axienet_start_xmit() had stopped the queue with
netif_stop_queue(), and that __QUEUE_STATE_DRV_XOFF survives the reset:
netdev_reset_queue() clears only __QUEUE_STATE_STACK_XOFF, and nothing
at all without CONFIG_BQL. The wake in axienet_tx_poll() is reached
only when axienet_free_tx_chain() reclaims packets, which cannot happen
once the handler has cleared every status word, so the interface stops
transmitting until it is brought down and up again.
Quiesce the transmit path with netif_tx_disable() once TX NAPI is
disabled, so that no transmit is in progress or can start while the ring
is torn down, and wake the queue once the reset is complete. Because
the handler now owns the queue state for its whole duration, the wake
cannot be lost to a concurrent netif_stop_queue().
Skip the wake if the interface is being stopped or the device has been
detached for suspend, or it would undo the stop that
netif_device_detach() installed; axienet_stop() and axienet_open() own
the queue state then. A detach racing with the check is covered by
axienet_stop() quiescing the queue again before it tears anything down.
Both problems were reported by the Sashiko AI review bot.
Tested on an AXI Ethernet MAC behind a PCIe endpoint: traffic passes,
including across ten down/up cycles made with traffic running, with this
series applied. The DMA error path itself was not exercised.
Fixes: 8a3b7a252dca ("drivers/net/ethernet/xilinx: added Xilinx AXI Ethernet driver")
Assisted-by: LLM sparse
Signed-off-by: Sagi Maimon <maimon.sagi at gmail.com>
---
drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 6d448d0b523d..f16dbfc7dc93 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -2724,6 +2724,11 @@ static void axienet_dma_err_handler(struct work_struct *work)
napi_disable(&lp->napi_tx);
napi_disable(&lp->napi_rx);
+ /* With TX NAPI disabled nothing else can wake the queue. Stop it and
+ * wait out any transmit in progress, so the ring can be torn down.
+ */
+ netif_tx_disable(ndev);
+
axienet_setoptions(ndev, lp->options &
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
@@ -2791,6 +2796,13 @@ static void axienet_dma_err_handler(struct work_struct *work)
napi_enable(&lp->napi_rx);
napi_enable(&lp->napi_tx);
axienet_setoptions(ndev, lp->options);
+
+ /* Leave the queue stopped if the interface is going down or the
+ * device was detached for suspend: axienet_stop() and axienet_open()
+ * own the queue state then.
+ */
+ if (!READ_ONCE(lp->stopping) && netif_device_present(ndev))
+ netif_wake_queue(ndev);
}
/**
--
2.47.0
More information about the linux-arm-kernel
mailing list