Attaching an XDP program while Tx traffic is running results in kernel crashes in stmmac_xmit() -> dwmac4_set_addr(). Loading an XDP program tears down and reallocates all DMA resources via stmmac_xdp_release() and stmmac_xdp_open(). stmmac_xdp_release() stops the Tx queues before disabling NAPI: stmmac_xdp_release: netif_tx_disable stmmac_disable_all_queues ... free_dma_desc_resources A Tx NAPI poll may still be in flight at that point. stmmac_tx_clean() takes the Tx queue lock, reaps completed descriptors and wakes the queue again when it observes it stopped with enough descriptors available. Nothing stops the queue afterwards, so the Tx path resumes while free_dma_desc_resources() releases the descriptor rings underneath it. On non-coherent platforms dma_free_coherent() tears down the vmalloc mapping of the descriptors, so the subsequent stmmac_xmit() faults on an unmapped address instead of corrupting memory silently. Disable NAPI first and stop the Tx queues afterwards, which is the order already used by __stmmac_release(). The issue can be easily reproduced by: 1. Run iperf 2. Run application which opens an AF_XDP/ZC socket Assisted-by: Claude:claude-opus-5 Fixes: 77711683a504 ("net: stmmac: ensure tx function is not running in stmmac_xdp_release()") Signed-off-by: Kurt Kanzenbach --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 62c3441911e7..928aa05aa87d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7118,15 +7118,15 @@ void stmmac_xdp_release(struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); u8 chan; - /* Ensure tx function is not running */ - netif_tx_disable(dev); - /* Disable NAPI process */ stmmac_disable_all_queues(priv); for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); + /* Ensure tx function is not running */ + netif_tx_disable(dev); + /* Free the IRQ lines */ stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0); -- 2.47.3 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. Update trans_start when stopping the queue to avoid spurious watchdog timeouts. The issue can be easily reproduced by: 1. Run iperf 2. Run application which opens an AF_XDP/ZC socket Fixes: 132c32ee5bc0 ("net: stmmac: Add TX via XDP zero-copy socket") Signed-off-by: Kurt Kanzenbach --- drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c index d7e4db7224b0..883bd3fe8089 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c @@ -6,6 +6,16 @@ #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); + txq_trans_cond_update(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 +46,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 +57,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 +85,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 +100,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