[MT7621] How to use a page_pool correctly?

Page pool is disabled for mt7621.

> I debugged a bit more the problem and the issue is due to a 2 bytes alignment
> introduced by mt7621 on packet data.
> Since mt7621 is a low-end SoC and I do not have other SoCs for testing, I will
> enable xdp support just for MT7986 for the moment. Thanks a lot for reporting the
> issue and for testing.
>

Thanks to you for such a quick fix. Feel free to send us whatever
patch you need to test on mt7621.

https://lore.kernel.org/all/CAMhs-H_K8j55o=Ky=vCokHUsbTz6ZU_fc3RLue-neY1ox8ncsA@mail.gmail.com/

So here is my ugly patch with 2 buffers per page.

--- a/mtk_eth_soc.c
+++ b/mtk_eth_soc.c
@@ -1887,7 +1887,6 @@ static bool mtk_page_pool_enabled(struct mtk_eth *eth)
 }
 
 static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
-					      struct xdp_rxq_info *xdp_q,
 					      int id, int size)
 {
 	struct page_pool_params pp_params = {
@@ -1896,48 +1895,32 @@ static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth,
 		.pool_size = size,
 		.nid = NUMA_NO_NODE,
 		.dev = eth->dma_dev,
-		.offset = MTK_PP_HEADROOM,
-		.max_len = MTK_PP_MAX_BUF_SIZE,
+		.offset = 0,
+		.max_len = PAGE_SIZE,
 	};
 	struct page_pool *pp;
-	int err;
 
-	pp_params.dma_dir = rcu_access_pointer(eth->prog) ? DMA_BIDIRECTIONAL
-							  : DMA_FROM_DEVICE;
+	pp_params.napi = &eth->rx_napi;
+	pp_params.dma_dir = DMA_FROM_DEVICE;
 	pp = page_pool_create(&pp_params);
 	if (IS_ERR(pp))
 		return pp;
 
-	err = __xdp_rxq_info_reg(xdp_q, &eth->dummy_dev, id,
-				 eth->rx_napi.napi_id, PAGE_SIZE);
-	if (err < 0)
-		goto err_free_pp;
-
-	err = xdp_rxq_info_reg_mem_model(xdp_q, MEM_TYPE_PAGE_POOL, pp);
-	if (err)
-		goto err_unregister_rxq;
-
 	return pp;
-
-err_unregister_rxq:
-	xdp_rxq_info_unreg(xdp_q);
-err_free_pp:
-	page_pool_destroy(pp);
-
-	return ERR_PTR(err);
 }
 
 static void *mtk_page_pool_get_buff(struct page_pool *pp, dma_addr_t *dma_addr,
 				    gfp_t gfp_mask)
 {
 	struct page *page;
+	unsigned int offset = 0;
 
-	page = page_pool_alloc_pages(pp, gfp_mask | __GFP_NOWARN);
+	page = page_pool_dev_alloc_frag(pp, &offset, PAGE_SIZE / 2);
 	if (!page)
 		return NULL;
 
-	*dma_addr = page_pool_get_dma_addr(page) + MTK_PP_HEADROOM;
-	return page_address(page);
+	*dma_addr = page_pool_get_dma_addr(page) + offset;
+	return page_address(page) + offset;
 }
 
 static void mtk_rx_put_buff(struct mtk_rx_ring *ring, void *data, bool napi)
@@ -2258,8 +2241,6 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 		/* alloc new buffer */
 		if (ring->page_pool) {
 			struct page *page = virt_to_head_page(data);
-			struct xdp_buff xdp;
-			u32 ret;
 
 			new_data = mtk_page_pool_get_buff(ring->page_pool,
 							  &dma_addr,
@@ -2270,22 +2251,12 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 			}
 
 			dma_sync_single_for_cpu(eth->dma_dev,
-				page_pool_get_dma_addr(page) + MTK_PP_HEADROOM,
-				pktlen, page_pool_get_dma_dir(ring->page_pool));
+				rxd->rxd1,
+				pktlen, DMA_FROM_DEVICE);
 
-			xdp_init_buff(&xdp, PAGE_SIZE, &ring->xdp_q);
-			xdp_prepare_buff(&xdp, data, MTK_PP_HEADROOM, pktlen,
-					 false);
-			xdp_buff_clear_frags_flag(&xdp);
+			net_prefetch(data);
 
-			ret = mtk_xdp_run(eth, ring, &xdp, netdev);
-			if (ret == XDP_REDIRECT)
-				xdp_flush = true;
-
-			if (ret != XDP_PASS)
-				goto skip_rx;
-
-			skb = napi_build_skb(data, PAGE_SIZE);
+			skb = napi_build_skb(data, PAGE_SIZE / 2);
 			if (unlikely(!skb)) {
 				page_pool_put_full_page(ring->page_pool,
 							page, true);
@@ -2293,8 +2264,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
 				goto skip_rx;
 			}
 
-			skb_reserve(skb, xdp.data - xdp.data_hard_start);
-			skb_put(skb, xdp.data_end - xdp.data);
+			skb_reserve(skb, 2);
+			__skb_put(skb, pktlen);
 			skb_mark_for_recycle(skb);
 		} else {
 			if (ring->frag_size <= PAGE_SIZE)
@@ -2819,7 +2790,7 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 		rx_dma_size = MTK_HW_LRO_DMA_SIZE;
 	} else {
 		rx_data_len = ETH_DATA_LEN;
-		rx_dma_size = MTK_DMA_SIZE;
+		rx_dma_size = 256;
 	}
 
 	ring->frag_size = mtk_max_frag_size(rx_data_len);
@@ -2829,16 +2800,14 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag)
 	if (!ring->data)
 		return -ENOMEM;
 
-	if (mtk_page_pool_enabled(eth)) {
-		struct page_pool *pp;
+	struct page_pool *pp;
 
-		pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no,
+	pp = mtk_create_page_pool(eth, ring_no,
 					  rx_dma_size);
-		if (IS_ERR(pp))
-			return PTR_ERR(pp);
+	if (IS_ERR(pp))
+		return PTR_ERR(pp);
 
-		ring->page_pool = pp;
-	}
+	ring->page_pool = pp;
 
 	if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SRAM) ||
 	    rx_flag != MTK_RX_FLAGS_NORMAL) {
@@ -2976,8 +2945,6 @@ static void mtk_rx_clean(struct mtk_eth *eth, struct mtk_rx_ring *ring, bool in_
 	}
 
 	if (ring->page_pool) {
-		if (xdp_rxq_info_is_reg(&ring->xdp_q))
-			xdp_rxq_info_unreg(&ring->xdp_q);
 		page_pool_destroy(ring->page_pool);
 		ring->page_pool = NULL;
 	}

Have no problems with openwrt default config and 1500 MTU. CPU usage is much lower (WAN/LAN -> WIFI/USB).

  1. Should I use SKB_HEADROOM (NET_SKB_PAD + NET_IP_ALIGN) as offset?
  2. Should I use SKB_WITH_OVERHEAD(PAGE_SIZE / 2) instead of pktlen for dma_sync_single_for_cpu