mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
The Netlink support for querying page pool stats has been proven out in production, let's remove the mention of the helper meant for dumping page pool stats into ethtool -S from the docs. Call out in the kdoc that this API is deprecated. Some drivers may not be able to use the Netlink API (if page pool is shared across netdevs). So the old API is not _completely_ dead. But we shouldn't advertise it. Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de> Reviewed-by: Tariq Toukan <tariqt@nvidia.com> Link: https://patch.msgid.link/20260526155722.2790742-4-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
182 lines
6.1 KiB
ReStructuredText
182 lines
6.1 KiB
ReStructuredText
.. SPDX-License-Identifier: GPL-2.0
|
|
|
|
=============
|
|
Page Pool API
|
|
=============
|
|
|
|
.. kernel-doc:: include/net/page_pool/helpers.h
|
|
:doc: page_pool allocator
|
|
|
|
Architecture overview
|
|
=====================
|
|
|
|
.. code-block:: none
|
|
|
|
+------------------+
|
|
| Driver |
|
|
+------------------+
|
|
^
|
|
|
|
|
|
|
|
|
|
|
v
|
|
+--------------------------------------------+
|
|
| request memory |
|
|
+--------------------------------------------+
|
|
^ ^
|
|
| |
|
|
| Pool empty | Pool has entries
|
|
| |
|
|
v v
|
|
+-----------------------+ +------------------------+
|
|
| alloc (and map) pages | | get page from cache |
|
|
+-----------------------+ +------------------------+
|
|
^ ^
|
|
| |
|
|
| cache available | No entries, refill
|
|
| | from ptr-ring
|
|
| |
|
|
v v
|
|
+-----------------+ +------------------+
|
|
| Fast cache | | ptr-ring cache |
|
|
+-----------------+ +------------------+
|
|
|
|
Monitoring
|
|
==========
|
|
Information about allocated page pools, their memory use, recycling statistics
|
|
etc. can be accessed via the netdev genetlink family
|
|
(see Documentation/netlink/specs/netdev.yaml).
|
|
|
|
Statistics
|
|
----------
|
|
|
|
.. kernel-doc:: include/net/page_pool/types.h
|
|
:identifiers: struct page_pool_recycle_stats
|
|
struct page_pool_alloc_stats
|
|
struct page_pool_stats
|
|
|
|
API interface
|
|
=============
|
|
The number of pools created **must** match the number of NAPI contexts / queues
|
|
unless hardware restrictions make that impossible. This would otherwise beat the
|
|
purpose of page pool, which is allocate pages fast from cache without locking.
|
|
This lockless guarantee naturally comes from running under a NAPI softirq.
|
|
The protection doesn't strictly have to be NAPI, any guarantee that allocating
|
|
a page will cause no race conditions is enough.
|
|
|
|
If ``params.napi`` is set, the NAPI instance must be the sole consumer
|
|
context for pages allocated from the pool. In other words, when running in
|
|
that NAPI context, the page pool may safely access consumer-side resources
|
|
**without any additional locking**.
|
|
|
|
.. kernel-doc:: net/core/page_pool.c
|
|
:identifiers: page_pool_create
|
|
|
|
.. kernel-doc:: include/net/page_pool/types.h
|
|
:identifiers: struct page_pool_params
|
|
|
|
.. kernel-doc:: include/net/page_pool/helpers.h
|
|
:identifiers: page_pool_put_page page_pool_put_full_page
|
|
page_pool_recycle_direct page_pool_free_va
|
|
page_pool_dev_alloc_pages page_pool_dev_alloc_frag
|
|
page_pool_dev_alloc page_pool_dev_alloc_va
|
|
page_pool_get_dma_addr page_pool_get_dma_dir
|
|
|
|
.. kernel-doc:: net/core/page_pool.c
|
|
:identifiers: page_pool_put_page_bulk
|
|
|
|
DMA sync
|
|
--------
|
|
Driver is always responsible for syncing the pages for the CPU.
|
|
Drivers may choose to take care of syncing for the device as well
|
|
or set the ``PP_FLAG_DMA_SYNC_DEV`` flag to request that pages
|
|
allocated from the page pool are already synced for the device.
|
|
|
|
If ``PP_FLAG_DMA_SYNC_DEV`` is set, the driver must inform the core what portion
|
|
of the buffer has to be synced. This allows the core to avoid syncing the entire
|
|
page when the drivers knows that the device only accessed a portion of the page.
|
|
|
|
Most drivers will reserve headroom in front of the frame. This part
|
|
of the buffer is not touched by the device, so to avoid syncing
|
|
it drivers can set the ``offset`` field in struct page_pool_params
|
|
appropriately.
|
|
|
|
For pages recycled on the XDP xmit and skb paths the page pool will
|
|
use the ``max_len`` member of struct page_pool_params to decide how
|
|
much of the page needs to be synced (starting at ``offset``).
|
|
When directly freeing pages in the driver (page_pool_put_page())
|
|
the ``dma_sync_size`` argument specifies how much of the buffer needs
|
|
to be synced.
|
|
|
|
If in doubt set ``offset`` to 0, ``max_len`` to ``PAGE_SIZE`` and
|
|
pass -1 as ``dma_sync_size``. That combination of arguments is always
|
|
correct.
|
|
|
|
Note that the syncing parameters are for the **entire page**, even if
|
|
the driver allocates fragments (e.g. via ``page_pool_dev_alloc_frag()``).
|
|
Unless the driver author really understands page pool internals
|
|
it's recommended to always use ``offset = 0``, ``max_len = PAGE_SIZE``
|
|
with fragmented page pools.
|
|
|
|
Coding examples
|
|
===============
|
|
|
|
Registration
|
|
------------
|
|
|
|
.. code-block:: c
|
|
|
|
/* Page pool registration */
|
|
struct page_pool_params pp_params = { 0 };
|
|
struct xdp_rxq_info xdp_rxq;
|
|
int err;
|
|
|
|
pp_params.order = 0;
|
|
/* internal DMA mapping in page_pool */
|
|
pp_params.flags = PP_FLAG_DMA_MAP;
|
|
pp_params.pool_size = DESC_NUM;
|
|
pp_params.nid = NUMA_NO_NODE;
|
|
pp_params.dev = priv->dev;
|
|
pp_params.napi = napi; /* only if this NAPI is the sole consumer, see above */
|
|
pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
|
|
page_pool = page_pool_create(&pp_params);
|
|
|
|
err = xdp_rxq_info_reg(&xdp_rxq, ndev, 0);
|
|
if (err)
|
|
goto err_out;
|
|
|
|
err = xdp_rxq_info_reg_mem_model(&xdp_rxq, MEM_TYPE_PAGE_POOL, page_pool);
|
|
if (err)
|
|
goto err_out;
|
|
|
|
NAPI poller
|
|
-----------
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
/* NAPI Rx poller */
|
|
enum dma_data_direction dma_dir;
|
|
|
|
dma_dir = page_pool_get_dma_dir(dring->page_pool);
|
|
while (done < budget) {
|
|
if (some error)
|
|
page_pool_recycle_direct(page_pool, page);
|
|
if (packet_is_xdp) {
|
|
if XDP_DROP:
|
|
page_pool_recycle_direct(page_pool, page);
|
|
} else (packet_is_skb) {
|
|
skb_mark_for_recycle(skb);
|
|
new_page = page_pool_dev_alloc_pages(page_pool);
|
|
}
|
|
}
|
|
|
|
Driver unload
|
|
-------------
|
|
|
|
.. code-block:: c
|
|
|
|
/* Driver unload */
|
|
page_pool_put_full_page(page_pool, page, false);
|
|
xdp_rxq_info_unreg(&xdp_rxq);
|