Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: airoha: Fix page recycling in airoha_qdma_rx_process()

Do not recycle the page twice in airoha_qdma_rx_process routine in case
of error. Just run dev_kfree_skb() if the skb has been allocated and marked
for recycling. Run page_pool_put_full_page() directly if the skb has not
been allocated yet.
Moreover, rely on DMA address from queue entry element instead of reading
it from the DMA descriptor for DMA syncing in airoha_qdma_rx_process().

Fixes: e12182ddb6e71 ("net: airoha: Enable Rx Scatter-Gather")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250515-airoha-fix-rx-process-error-condition-v2-1-657e92c894b9@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Lorenzo Bianconi and committed by
Jakub Kicinski
d6d2b0e1 43f0999a

+9 -13
+9 -13
drivers/net/ethernet/airoha/airoha_eth.c
··· 614 614 struct airoha_queue_entry *e = &q->entry[q->tail]; 615 615 struct airoha_qdma_desc *desc = &q->desc[q->tail]; 616 616 u32 hash, reason, msg1 = le32_to_cpu(desc->msg1); 617 - dma_addr_t dma_addr = le32_to_cpu(desc->addr); 618 617 struct page *page = virt_to_head_page(e->buf); 619 618 u32 desc_ctrl = le32_to_cpu(desc->ctrl); 620 619 struct airoha_gdm_port *port; ··· 622 623 if (!(desc_ctrl & QDMA_DESC_DONE_MASK)) 623 624 break; 624 625 625 - if (!dma_addr) 626 - break; 627 - 628 - len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl); 629 - if (!len) 630 - break; 631 - 632 626 q->tail = (q->tail + 1) % q->ndesc; 633 627 q->queued--; 634 628 635 - dma_sync_single_for_cpu(eth->dev, dma_addr, 629 + dma_sync_single_for_cpu(eth->dev, e->dma_addr, 636 630 SKB_WITH_OVERHEAD(q->buf_size), dir); 637 631 632 + len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl); 638 633 data_len = q->skb ? q->buf_size 639 634 : SKB_WITH_OVERHEAD(q->buf_size); 640 - if (data_len < len) 635 + if (!len || data_len < len) 641 636 goto free_frag; 642 637 643 638 p = airoha_qdma_get_gdm_port(eth, desc); ··· 694 701 q->skb = NULL; 695 702 continue; 696 703 free_frag: 697 - page_pool_put_full_page(q->page_pool, page, true); 698 - dev_kfree_skb(q->skb); 699 - q->skb = NULL; 704 + if (q->skb) { 705 + dev_kfree_skb(q->skb); 706 + q->skb = NULL; 707 + } else { 708 + page_pool_put_full_page(q->page_pool, page, true); 709 + } 700 710 } 701 711 airoha_qdma_fill_rx_queue(q); 702 712