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