From b2e17432e7ee75997657f99862eb83be0c78a6c1 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Mon, 26 Oct 2026 14:45:58 +0100 Subject: [PATCH] net: lan966x: don't disable hardirqs in fdma tx clear path lan966x_fdma_tx_clear_buf() runs from the NAPI poll and frees the buffers of completed tx DCBs with napi_consume_skb(), page_pool_recycle_direct() and xdp_return_frame_bulk(), under lan966x->tx_lock. Before this patch, the lock is taken with spin_lock_irqsave(), so the buffers are freed with hardirqs disabled. RX skbs are marked for page_pool recycling, so when such an skb is forwarded back out and its tx completion frees it here, the free path reaches __page_pool_put_page(), which warns via lockdep_assert_no_hardirq(). Take tx_lock with a plain spin_lock(), as the other tx_lock users, lan966x_port_xmit() and lan966x_fdma_xmit_xdpf(), already do. tx_clear_buf() runs from the NAPI poll, so disabling hardirqs there is not needed. Found with lockdep enabled (CONFIG_PROVE_LOCKING), which the assert depends on. Reproduced on a lan9668 board by redirecting received frames out of another port with tc mirred. Fixes: 11871aba1974 ("net: lan96x: Use page_pool API") Signed-off-by: Daniel Machon Link: https://patch.msgid.link/20261026-lan966x-fdma-tx-clear-hardirq-v1-1-5f70f026a2e4@microchip.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c index 8ea86b800af7..21668bbcc906 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c @@ -336,14 +336,13 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight) struct lan966x_tx_dcb_buf *dcb_buf; struct fdma *fdma = &tx->fdma; struct xdp_frame_bulk bq; - unsigned long flags; bool clear = false; struct fdma_db *db; int i; xdp_frame_bulk_init(&bq); - spin_lock_irqsave(&lan966x->tx_lock, flags); + spin_lock(&lan966x->tx_lock); for (i = 0; i < fdma->n_dcbs; ++i) { dcb_buf = &tx->dcbs_buf[i]; @@ -388,7 +387,7 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight) if (clear) lan966x_fdma_wakeup_netdev(lan966x); - spin_unlock_irqrestore(&lan966x->tx_lock, flags); + spin_unlock(&lan966x->tx_lock); } static int lan966x_fdma_rx_check_frame(struct lan966x_rx *rx, u64 *src_port)