162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci============= 462306a36Sopenharmony_ciPage Pool API 562306a36Sopenharmony_ci============= 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci.. kernel-doc:: include/net/page_pool/helpers.h 862306a36Sopenharmony_ci :doc: page_pool allocator 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciArchitecture overview 1162306a36Sopenharmony_ci===================== 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci.. code-block:: none 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci +------------------+ 1662306a36Sopenharmony_ci | Driver | 1762306a36Sopenharmony_ci +------------------+ 1862306a36Sopenharmony_ci ^ 1962306a36Sopenharmony_ci | 2062306a36Sopenharmony_ci | 2162306a36Sopenharmony_ci | 2262306a36Sopenharmony_ci v 2362306a36Sopenharmony_ci +--------------------------------------------+ 2462306a36Sopenharmony_ci | request memory | 2562306a36Sopenharmony_ci +--------------------------------------------+ 2662306a36Sopenharmony_ci ^ ^ 2762306a36Sopenharmony_ci | | 2862306a36Sopenharmony_ci | Pool empty | Pool has entries 2962306a36Sopenharmony_ci | | 3062306a36Sopenharmony_ci v v 3162306a36Sopenharmony_ci +-----------------------+ +------------------------+ 3262306a36Sopenharmony_ci | alloc (and map) pages | | get page from cache | 3362306a36Sopenharmony_ci +-----------------------+ +------------------------+ 3462306a36Sopenharmony_ci ^ ^ 3562306a36Sopenharmony_ci | | 3662306a36Sopenharmony_ci | cache available | No entries, refill 3762306a36Sopenharmony_ci | | from ptr-ring 3862306a36Sopenharmony_ci | | 3962306a36Sopenharmony_ci v v 4062306a36Sopenharmony_ci +-----------------+ +------------------+ 4162306a36Sopenharmony_ci | Fast cache | | ptr-ring cache | 4262306a36Sopenharmony_ci +-----------------+ +------------------+ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciAPI interface 4562306a36Sopenharmony_ci============= 4662306a36Sopenharmony_ciThe number of pools created **must** match the number of hardware queues 4762306a36Sopenharmony_ciunless hardware restrictions make that impossible. This would otherwise beat the 4862306a36Sopenharmony_cipurpose of page pool, which is allocate pages fast from cache without locking. 4962306a36Sopenharmony_ciThis lockless guarantee naturally comes from running under a NAPI softirq. 5062306a36Sopenharmony_ciThe protection doesn't strictly have to be NAPI, any guarantee that allocating 5162306a36Sopenharmony_cia page will cause no race conditions is enough. 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci.. kernel-doc:: net/core/page_pool.c 5462306a36Sopenharmony_ci :identifiers: page_pool_create 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci.. kernel-doc:: include/net/page_pool/types.h 5762306a36Sopenharmony_ci :identifiers: struct page_pool_params 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci.. kernel-doc:: include/net/page_pool/helpers.h 6062306a36Sopenharmony_ci :identifiers: page_pool_put_page page_pool_put_full_page 6162306a36Sopenharmony_ci page_pool_recycle_direct page_pool_dev_alloc_pages 6262306a36Sopenharmony_ci page_pool_get_dma_addr page_pool_get_dma_dir 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci.. kernel-doc:: net/core/page_pool.c 6562306a36Sopenharmony_ci :identifiers: page_pool_put_page_bulk page_pool_get_stats 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciDMA sync 6862306a36Sopenharmony_ci-------- 6962306a36Sopenharmony_ciDriver is always responsible for syncing the pages for the CPU. 7062306a36Sopenharmony_ciDrivers may choose to take care of syncing for the device as well 7162306a36Sopenharmony_cior set the ``PP_FLAG_DMA_SYNC_DEV`` flag to request that pages 7262306a36Sopenharmony_ciallocated from the page pool are already synced for the device. 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ciIf ``PP_FLAG_DMA_SYNC_DEV`` is set, the driver must inform the core what portion 7562306a36Sopenharmony_ciof the buffer has to be synced. This allows the core to avoid syncing the entire 7662306a36Sopenharmony_cipage when the drivers knows that the device only accessed a portion of the page. 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciMost drivers will reserve headroom in front of the frame. This part 7962306a36Sopenharmony_ciof the buffer is not touched by the device, so to avoid syncing 8062306a36Sopenharmony_ciit drivers can set the ``offset`` field in struct page_pool_params 8162306a36Sopenharmony_ciappropriately. 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciFor pages recycled on the XDP xmit and skb paths the page pool will 8462306a36Sopenharmony_ciuse the ``max_len`` member of struct page_pool_params to decide how 8562306a36Sopenharmony_cimuch of the page needs to be synced (starting at ``offset``). 8662306a36Sopenharmony_ciWhen directly freeing pages in the driver (page_pool_put_page()) 8762306a36Sopenharmony_cithe ``dma_sync_size`` argument specifies how much of the buffer needs 8862306a36Sopenharmony_cito be synced. 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciIf in doubt set ``offset`` to 0, ``max_len`` to ``PAGE_SIZE`` and 9162306a36Sopenharmony_cipass -1 as ``dma_sync_size``. That combination of arguments is always 9262306a36Sopenharmony_cicorrect. 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciNote that the syncing parameters are for the entire page. 9562306a36Sopenharmony_ciThis is important to remember when using fragments (``PP_FLAG_PAGE_FRAG``), 9662306a36Sopenharmony_ciwhere allocated buffers may be smaller than a full page. 9762306a36Sopenharmony_ciUnless the driver author really understands page pool internals 9862306a36Sopenharmony_ciit's recommended to always use ``offset = 0``, ``max_len = PAGE_SIZE`` 9962306a36Sopenharmony_ciwith fragmented page pools. 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciStats API and structures 10262306a36Sopenharmony_ci------------------------ 10362306a36Sopenharmony_ciIf the kernel is configured with ``CONFIG_PAGE_POOL_STATS=y``, the API 10462306a36Sopenharmony_cipage_pool_get_stats() and structures described below are available. 10562306a36Sopenharmony_ciIt takes a pointer to a ``struct page_pool`` and a pointer to a struct 10662306a36Sopenharmony_cipage_pool_stats allocated by the caller. 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciThe API will fill in the provided struct page_pool_stats with 10962306a36Sopenharmony_cistatistics about the page_pool. 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci.. kernel-doc:: include/net/page_pool/types.h 11262306a36Sopenharmony_ci :identifiers: struct page_pool_recycle_stats 11362306a36Sopenharmony_ci struct page_pool_alloc_stats 11462306a36Sopenharmony_ci struct page_pool_stats 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciCoding examples 11762306a36Sopenharmony_ci=============== 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciRegistration 12062306a36Sopenharmony_ci------------ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci.. code-block:: c 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Page pool registration */ 12562306a36Sopenharmony_ci struct page_pool_params pp_params = { 0 }; 12662306a36Sopenharmony_ci struct xdp_rxq_info xdp_rxq; 12762306a36Sopenharmony_ci int err; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci pp_params.order = 0; 13062306a36Sopenharmony_ci /* internal DMA mapping in page_pool */ 13162306a36Sopenharmony_ci pp_params.flags = PP_FLAG_DMA_MAP; 13262306a36Sopenharmony_ci pp_params.pool_size = DESC_NUM; 13362306a36Sopenharmony_ci pp_params.nid = NUMA_NO_NODE; 13462306a36Sopenharmony_ci pp_params.dev = priv->dev; 13562306a36Sopenharmony_ci pp_params.napi = napi; /* only if locking is tied to NAPI */ 13662306a36Sopenharmony_ci pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE; 13762306a36Sopenharmony_ci page_pool = page_pool_create(&pp_params); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci err = xdp_rxq_info_reg(&xdp_rxq, ndev, 0); 14062306a36Sopenharmony_ci if (err) 14162306a36Sopenharmony_ci goto err_out; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci err = xdp_rxq_info_reg_mem_model(&xdp_rxq, MEM_TYPE_PAGE_POOL, page_pool); 14462306a36Sopenharmony_ci if (err) 14562306a36Sopenharmony_ci goto err_out; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciNAPI poller 14862306a36Sopenharmony_ci----------- 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci.. code-block:: c 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* NAPI Rx poller */ 15462306a36Sopenharmony_ci enum dma_data_direction dma_dir; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci dma_dir = page_pool_get_dma_dir(dring->page_pool); 15762306a36Sopenharmony_ci while (done < budget) { 15862306a36Sopenharmony_ci if (some error) 15962306a36Sopenharmony_ci page_pool_recycle_direct(page_pool, page); 16062306a36Sopenharmony_ci if (packet_is_xdp) { 16162306a36Sopenharmony_ci if XDP_DROP: 16262306a36Sopenharmony_ci page_pool_recycle_direct(page_pool, page); 16362306a36Sopenharmony_ci } else (packet_is_skb) { 16462306a36Sopenharmony_ci skb_mark_for_recycle(skb); 16562306a36Sopenharmony_ci new_page = page_pool_dev_alloc_pages(page_pool); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciStats 17062306a36Sopenharmony_ci----- 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci.. code-block:: c 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci #ifdef CONFIG_PAGE_POOL_STATS 17562306a36Sopenharmony_ci /* retrieve stats */ 17662306a36Sopenharmony_ci struct page_pool_stats stats = { 0 }; 17762306a36Sopenharmony_ci if (page_pool_get_stats(page_pool, &stats)) { 17862306a36Sopenharmony_ci /* perhaps the driver reports statistics with ethool */ 17962306a36Sopenharmony_ci ethtool_print_allocation_stats(&stats.alloc_stats); 18062306a36Sopenharmony_ci ethtool_print_recycle_stats(&stats.recycle_stats); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci #endif 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ciDriver unload 18562306a36Sopenharmony_ci------------- 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci.. code-block:: c 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Driver unload */ 19062306a36Sopenharmony_ci page_pool_put_full_page(page_pool, page, false); 19162306a36Sopenharmony_ci xdp_rxq_info_unreg(&xdp_rxq); 192