When xsk_buff_add_frag() fails, i40e_clean_rx_irq_zc() frees the frame but stays on the current descriptor, so the next poll restarts from the freed head. If the frags array was full, the retry passes on a frame missing the freed frags, with its head already on the free list. If the buffer is a duplicate, every poll fails the same way and the queue stalls. Free the current buffer along with the frame and move on to the next descriptor, as ice does. The rest of the dropped frame is received as a new frame. xp_free() skips a duplicate already freed with the frame. Fixes: 1c9ba9c14658 ("i40e: xsk: add RX multi-buffer support") Signed-off-by: Maciej Fijalkowski --- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index 51a05ce4c7ce..e6ae4c7a5cb3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -469,16 +469,24 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget) xsk_buff_set_size(bi, size); xsk_buff_dma_sync_for_cpu(bi); - if (!first) + if (++next_to_process == count) + next_to_process = 0; + + if (!first) { first = bi; - else if (!xsk_buff_add_frag(first, bi)) { + } else if (!xsk_buff_add_frag(first, bi)) { + /* Drop what has been gathered so far. xp_free() skips + * @bi if it duplicates a buffer that is already on a + * pool list. Remaining buffers of this packet, if any, + * will be processed as a new packet. + */ xsk_buff_free(first); - break; + xsk_buff_free(bi); + next_to_clean = next_to_process; + first = NULL; + continue; } - if (++next_to_process == count) - next_to_process = 0; - if (i40e_is_non_eop(rx_ring, rx_desc)) continue; -- 2.43.0