From 263a5514cb9535380734b5e300b298f82570eb57 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Thu, 29 Oct 2026 12:47:47 +0100 Subject: [PATCH] net: lan966x: don't free XDP buffers in fdma tx clear with budget 0 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(). netpoll calls the NAPI poll with a budget of 0 and hardirqs disabled. With a budget of 0, a driver cannot call any XDP or page pool API. Before this patch, the XDP_TX pages and ndo_xdp_xmit frames are freed regardless of the budget. With netconsole on the port that owns the FDMA NAPI, such a buffer is freed with hardirqs disabled, and __page_pool_put_page() warns via lockdep_assert_no_hardirq(). Leave the XDP buffers of completed DCBs in place when the budget is 0, and free them in the next NAPI poll. napi_consume_skb() already handles a budget of 0, so skbs are still freed. Found by an AI code review agent. Reproduced on a lan9668 board with a modified kernel that runs the NAPI poll with a budget of 0 and hardirqs disabled. With the fix the warning is gone. Fixes: 19c6f534f636 ("net: lan966x: Add support for XDP_TX") Signed-off-by: Daniel Machon Reviewed-by: Simon Horman Link: https://patch.msgid.link/20261029-lan966x-fdma-tx-clear-budget-v1-1-38c52d7aab8c@microchip.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c index 21668bbcc906..1fbe910c5ec3 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_fdma.c @@ -353,6 +353,12 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight) if (!fdma_db_is_done(db)) continue; + /* XDP and page pool APIs can't be used with a budget of 0. + * Leave these buffers for the next NAPI poll. + */ + if (!weight && !dcb_buf->use_skb) + continue; + dcb_buf->dev->stats.tx_packets++; dcb_buf->dev->stats.tx_bytes += dcb_buf->len;