[PATCH net-next v4 2/2] net: stmmac: Stop Tx queue when (en|dis)abling XSK pools
Kurt Kanzenbach
kurt at linutronix.de
Thu Oct 22 00:01:35 PDT 2026
When enabling or disabling XSK pools in parallel to Tx traffic, kernel
crashes occur. For VLAN tagged frames that happens in stmmac_xmit() ->
dwmac4_set_vlan_tag() and for normal frames in stmmac_xmit() ->
dwmac4_set_addr(). Both of these functions access the Tx DMA descriptors.
The XDP pool (en|dis)ablement frees and reallocates the Tx DMA resources:
stmmac_disable_tx_queue:
__free_dma_tx_desc_resources
stmmac_enable_tx_queue:
__alloc_dma_tx_desc_resources
__init_dma_tx_desc_rings
NAPI is disabled during that allocation window, but the Tx queue is not
stopped. Therefore, add the stopping of the Tx queue during the enabling
and disabling of XSK pools.
The issue can be easily reproduced by:
1. Run iperf
2. Run application which opens an AF_XDP/ZC socket
Also add a dedicated queue check for the XDP Tx paths.
Fixes: 132c32ee5bc0 ("net: stmmac: Add TX via XDP zero-copy socket")
Suggested-by: Nicolai Buchwitz <nb at tipi-net.de> # XDP Tx checks
Reviewed-by: Nicolai Buchwitz <nb at tipi-net.de>
Tested-by: Nicolai Buchwitz <nb at tipi-net.de> # stm32mp215
Signed-off-by: Kurt Kanzenbach <kurt at linutronix.de>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++++
drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c | 13 +++++++++++++
2 files changed, 17 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 27c4a249e560..2083520179a6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -5270,6 +5270,10 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
if (unlikely(xdp_frame_has_frags(xdpf)))
num_frames += sinfo->nr_frags;
+ /* Ring may be torn down for an XSK pool switch */
+ if (netif_tx_queue_stopped(netdev_get_tx_queue(priv->dev, queue)))
+ return STMMAC_XDP_CONSUMED;
+
if (stmmac_tx_avail(priv, queue) < max(num_frames, txq_thr))
return STMMAC_XDP_CONSUMED;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c
index 9af9e0cb366c..14445683a5c3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c
@@ -6,6 +6,15 @@
#include "stmmac.h"
#include "stmmac_xdp.h"
+static void stmmac_xdp_stop_tx_queue(struct stmmac_priv *priv, u16 queue)
+{
+ struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue);
+
+ __netif_tx_lock_bh(nq);
+ netif_tx_stop_queue(nq);
+ __netif_tx_unlock_bh(nq);
+}
+
static int stmmac_xdp_enable_pool(struct stmmac_priv *priv,
struct xsk_buff_pool *pool, u16 queue)
{
@@ -36,6 +45,7 @@ static int stmmac_xdp_enable_pool(struct stmmac_priv *priv,
if (need_update) {
napi_disable(&ch->rx_napi);
napi_disable(&ch->tx_napi);
+ stmmac_xdp_stop_tx_queue(priv, queue);
stmmac_disable_rx_queue(priv, queue);
stmmac_disable_tx_queue(priv, queue);
}
@@ -46,6 +56,7 @@ static int stmmac_xdp_enable_pool(struct stmmac_priv *priv,
stmmac_enable_rx_queue(priv, queue);
stmmac_enable_tx_queue(priv, queue);
napi_enable(&ch->rxtx_napi);
+ netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, queue));
err = stmmac_xsk_wakeup(priv->dev, queue, XDP_WAKEUP_RX);
if (err)
@@ -73,6 +84,7 @@ static int stmmac_xdp_disable_pool(struct stmmac_priv *priv, u16 queue)
if (need_update) {
napi_disable(&ch->rxtx_napi);
+ stmmac_xdp_stop_tx_queue(priv, queue);
stmmac_disable_rx_queue(priv, queue);
stmmac_disable_tx_queue(priv, queue);
synchronize_rcu();
@@ -87,6 +99,7 @@ static int stmmac_xdp_disable_pool(struct stmmac_priv *priv, u16 queue)
stmmac_enable_tx_queue(priv, queue);
napi_enable(&ch->rx_napi);
napi_enable(&ch->tx_napi);
+ netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, queue));
}
return 0;
--
2.47.3
More information about the linux-arm-kernel
mailing list