@@ -615,10 +615,10 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
615615 struct airoha_qdma_desc * desc = & q -> desc [q -> tail ];
616616 u32 hash , reason , msg1 = le32_to_cpu (desc -> msg1 );
617617 dma_addr_t dma_addr = le32_to_cpu (desc -> addr );
618+ struct page * page = virt_to_head_page (e -> buf );
618619 u32 desc_ctrl = le32_to_cpu (desc -> ctrl );
619620 struct airoha_gdm_port * port ;
620- struct sk_buff * skb ;
621- int len , p ;
621+ int data_len , len , p ;
622622
623623 if (!(desc_ctrl & QDMA_DESC_DONE_MASK ))
624624 break ;
@@ -636,30 +636,41 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
636636 dma_sync_single_for_cpu (eth -> dev , dma_addr ,
637637 SKB_WITH_OVERHEAD (q -> buf_size ), dir );
638638
639+ data_len = q -> skb ? q -> buf_size
640+ : SKB_WITH_OVERHEAD (q -> buf_size );
641+ if (data_len < len )
642+ goto free_frag ;
643+
639644 p = airoha_qdma_get_gdm_port (eth , desc );
640- if (p < 0 || !eth -> ports [p ]) {
641- page_pool_put_full_page (q -> page_pool ,
642- virt_to_head_page (e -> buf ),
643- true);
644- continue ;
645- }
645+ if (p < 0 || !eth -> ports [p ])
646+ goto free_frag ;
646647
647648 port = eth -> ports [p ];
648- skb = napi_build_skb (e -> buf , q -> buf_size );
649- if (!skb ) {
650- page_pool_put_full_page (q -> page_pool ,
651- virt_to_head_page (e -> buf ),
652- true);
653- break ;
649+ if (!q -> skb ) { /* first buffer */
650+ q -> skb = napi_build_skb (e -> buf , q -> buf_size );
651+ if (!q -> skb )
652+ goto free_frag ;
653+
654+ __skb_put (q -> skb , len );
655+ skb_mark_for_recycle (q -> skb );
656+ q -> skb -> dev = port -> dev ;
657+ q -> skb -> protocol = eth_type_trans (q -> skb , port -> dev );
658+ q -> skb -> ip_summed = CHECKSUM_UNNECESSARY ;
659+ skb_record_rx_queue (q -> skb , qid );
660+ } else { /* scattered frame */
661+ struct skb_shared_info * shinfo = skb_shinfo (q -> skb );
662+ int nr_frags = shinfo -> nr_frags ;
663+
664+ if (nr_frags >= ARRAY_SIZE (shinfo -> frags ))
665+ goto free_frag ;
666+
667+ skb_add_rx_frag (q -> skb , nr_frags , page ,
668+ e -> buf - page_address (page ), len ,
669+ q -> buf_size );
654670 }
655671
656- skb_reserve (skb , 2 );
657- __skb_put (skb , len );
658- skb_mark_for_recycle (skb );
659- skb -> dev = port -> dev ;
660- skb -> protocol = eth_type_trans (skb , skb -> dev );
661- skb -> ip_summed = CHECKSUM_UNNECESSARY ;
662- skb_record_rx_queue (skb , qid );
672+ if (FIELD_GET (QDMA_DESC_MORE_MASK , desc_ctrl ))
673+ continue ;
663674
664675 if (netdev_uses_dsa (port -> dev )) {
665676 /* PPE module requires untagged packets to work
@@ -672,22 +683,27 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
672683
673684 if (sptag < ARRAY_SIZE (port -> dsa_meta ) &&
674685 port -> dsa_meta [sptag ])
675- skb_dst_set_noref (skb ,
686+ skb_dst_set_noref (q -> skb ,
676687 & port -> dsa_meta [sptag ]-> dst );
677688 }
678689
679690 hash = FIELD_GET (AIROHA_RXD4_FOE_ENTRY , msg1 );
680691 if (hash != AIROHA_RXD4_FOE_ENTRY )
681- skb_set_hash (skb , jhash_1word (hash , 0 ),
692+ skb_set_hash (q -> skb , jhash_1word (hash , 0 ),
682693 PKT_HASH_TYPE_L4 );
683694
684695 reason = FIELD_GET (AIROHA_RXD4_PPE_CPU_REASON , msg1 );
685696 if (reason == PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED )
686697 airoha_ppe_check_skb (eth -> ppe , hash );
687698
688- napi_gro_receive (& q -> napi , skb );
689-
690699 done ++ ;
700+ napi_gro_receive (& q -> napi , q -> skb );
701+ q -> skb = NULL ;
702+ continue ;
703+ free_frag :
704+ page_pool_put_full_page (q -> page_pool , page , true);
705+ dev_kfree_skb (q -> skb );
706+ q -> skb = NULL ;
691707 }
692708 airoha_qdma_fill_rx_queue (q );
693709
@@ -762,6 +778,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
762778 FIELD_PREP (RX_RING_THR_MASK , thr ));
763779 airoha_qdma_rmw (qdma , REG_RX_DMA_IDX (qid ), RX_RING_DMA_IDX_MASK ,
764780 FIELD_PREP (RX_RING_DMA_IDX_MASK , q -> head ));
781+ airoha_qdma_set (qdma , REG_RX_SCATTER_CFG (qid ), RX_RING_SG_EN_MASK );
765782
766783 airoha_qdma_fill_rx_queue (q );
767784
@@ -1161,7 +1178,6 @@ static int airoha_qdma_hw_init(struct airoha_qdma *qdma)
11611178 }
11621179
11631180 airoha_qdma_wr (qdma , REG_QDMA_GLOBAL_CFG ,
1164- GLOBAL_CFG_RX_2B_OFFSET_MASK |
11651181 FIELD_PREP (GLOBAL_CFG_DMA_PREFERENCE_MASK , 3 ) |
11661182 GLOBAL_CFG_CPU_TXR_RR_MASK |
11671183 GLOBAL_CFG_PAYLOAD_BYTE_SWAP_MASK |
0 commit comments