From 63c4530050d02dfa49b9a6b55cab7f6ac27be50b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 26 May 2026 08:57:19 -0700 Subject: [PATCH 1/4] docs: net: page_pool: drop reference to removed PP_FLAG_PAGE_FRAG The flag was removed in commit 09d96ee5674a ("page_pool: remove PP_FLAG_PAGE_FRAG"), but the documentation still mentions it when describing fragment usage. Drop the stale reference; the fragment API does not require any opt-in flag. Reviewed-by: Nicolai Buchwitz Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260526155722.2790742-2-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/page_pool.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 9d958128a57c..6e43e1953218 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -98,9 +98,8 @@ 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. -This is important to remember when using fragments (``PP_FLAG_PAGE_FRAG``), -where allocated buffers may be smaller than a full page. +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. From bbf2313cbeafee939301d6fe2c486b58413b8857 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 26 May 2026 08:57:20 -0700 Subject: [PATCH 2/4] docs: clarify page pool NAPI consumer requirement The comment about requirements when to set the NAPI pointer may not be super clear. Add more words. Reviewed-by: Nicolai Buchwitz Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260526155722.2790742-3-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/page_pool.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 6e43e1953218..5409c68be3fc 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -48,13 +48,18 @@ genetlink family (see Documentation/netlink/specs/netdev.yaml). API interface ============= -The number of pools created **must** match the number of hardware queues +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 @@ -139,7 +144,7 @@ Registration pp_params.pool_size = DESC_NUM; pp_params.nid = NUMA_NO_NODE; pp_params.dev = priv->dev; - pp_params.napi = napi; /* only if locking is tied to NAPI */ + 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); From ac0056e4f14b03eb3e933c857aef080a2b8dfdf4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 26 May 2026 08:57:21 -0700 Subject: [PATCH 3/4] docs: page_pool: drop the mention of the legacy stats API 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 Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260526155722.2790742-4-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/page_pool.rst | 46 +++++++------------------- net/core/page_pool.c | 3 ++ 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 5409c68be3fc..817f8b78d246 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -43,8 +43,17 @@ Architecture overview Monitoring ========== -Information about page pools on the system can be accessed via the netdev -genetlink family (see Documentation/netlink/specs/netdev.yaml). +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 ============= @@ -74,7 +83,7 @@ that NAPI context, the page pool may safely access consumer-side resources page_pool_get_dma_addr page_pool_get_dma_dir .. kernel-doc:: net/core/page_pool.c - :identifiers: page_pool_put_page_bulk page_pool_get_stats + :identifiers: page_pool_put_page_bulk DMA sync -------- @@ -109,22 +118,6 @@ 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. -Stats API and structures ------------------------- -If the kernel is configured with ``CONFIG_PAGE_POOL_STATS=y``, the API -page_pool_get_stats() and structures described below are available. -It takes a pointer to a ``struct page_pool`` and a pointer to a struct -page_pool_stats allocated by the caller. - -Older drivers expose page pool statistics via ethtool or debugfs. -The same statistics are accessible via the netlink netdev family -in a driver-independent fashion. - -.. kernel-doc:: include/net/page_pool/types.h - :identifiers: struct page_pool_recycle_stats - struct page_pool_alloc_stats - struct page_pool_stats - Coding examples =============== @@ -178,21 +171,6 @@ NAPI poller } } -Stats ------ - -.. code-block:: c - - #ifdef CONFIG_PAGE_POOL_STATS - /* retrieve stats */ - struct page_pool_stats stats = { 0 }; - if (page_pool_get_stats(page_pool, &stats)) { - /* perhaps the driver reports statistics with ethool */ - ethtool_print_allocation_stats(&stats.alloc_stats); - ethtool_print_recycle_stats(&stats.recycle_stats); - } - #endif - Driver unload ------------- diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 8171d1173221..7798726f5a3e 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -76,6 +76,9 @@ static const char pp_stats[][ETH_GSTRING_LEN] = { * @pool: pool from which page was allocated * @stats: struct page_pool_stats to fill in * + * Deprecated driver API for querying stats. Page pool stats can be queried + * via netdev Netlink. + * * Retrieve statistics about the page_pool. This API is only available * if the kernel has been configured with ``CONFIG_PAGE_POOL_STATS=y``. * A pointer to a caller allocated struct page_pool_stats structure From 81a4d039537a89e7619aa94c5b6db051ae0b180c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 26 May 2026 08:57:22 -0700 Subject: [PATCH 4/4] net: make page_pool_get_stats() void The kdoc for page_pool_get_stats() is missing a Returns: statement. Looking at this function, I have no idea what is the purpose of the bool it returns. My guess was that maybe the static inline stub returns false if CONFIG_PAGE_POOL_STATS=n but such static inline helper doesn't exist at all. All callers pass a pointer to a struct on the stack. Make this function void. Reviewed-by: Nicolai Buchwitz Reviewed-by: Tariq Toukan Link: https://patch.msgid.link/20260526155722.2790742-5-kuba@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 3 +-- include/net/page_pool/helpers.h | 2 +- net/core/page_pool.c | 7 +------ net/core/page_pool_user.c | 3 +-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 1a3ecf073913..7f33261ba655 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -496,8 +496,7 @@ static void mlx5e_stats_update_stats_rq_page_pool(struct mlx5e_channel *c) struct page_pool *pool = c->rq.page_pool; struct page_pool_stats stats = { 0 }; - if (!page_pool_get_stats(pool, &stats)) - return; + page_pool_get_stats(pool, &stats); rq_stats->pp_alloc_fast = stats.alloc_stats.fast; rq_stats->pp_alloc_slow = stats.alloc_stats.slow; diff --git a/include/net/page_pool/helpers.h b/include/net/page_pool/helpers.h index 3247026e096a..e2730dd273b2 100644 --- a/include/net/page_pool/helpers.h +++ b/include/net/page_pool/helpers.h @@ -64,7 +64,7 @@ int page_pool_ethtool_stats_get_count(void); u8 *page_pool_ethtool_stats_get_strings(u8 *data); u64 *page_pool_ethtool_stats_get(u64 *data, const void *stats); -bool page_pool_get_stats(const struct page_pool *pool, +void page_pool_get_stats(const struct page_pool *pool, struct page_pool_stats *stats); #else static inline int page_pool_ethtool_stats_get_count(void) diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 7798726f5a3e..21dc4a9c8714 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -85,14 +85,11 @@ static const char pp_stats[][ETH_GSTRING_LEN] = { * is passed to this API which is filled in. The caller can then report * those stats to the user (perhaps via ethtool, debugfs, etc.). */ -bool page_pool_get_stats(const struct page_pool *pool, +void page_pool_get_stats(const struct page_pool *pool, struct page_pool_stats *stats) { int cpu = 0; - if (!stats) - return false; - /* The caller is responsible to initialize stats. */ stats->alloc_stats.fast += pool->alloc_stats.fast; stats->alloc_stats.slow += pool->alloc_stats.slow; @@ -111,8 +108,6 @@ bool page_pool_get_stats(const struct page_pool *pool, stats->recycle_stats.ring_full += pcpu->ring_full; stats->recycle_stats.released_refcnt += pcpu->released_refcnt; } - - return true; } EXPORT_SYMBOL(page_pool_get_stats); diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c index 1cdef13e6cea..ef4261c0e8ea 100644 --- a/net/core/page_pool_user.c +++ b/net/core/page_pool_user.c @@ -127,8 +127,7 @@ page_pool_nl_stats_fill(struct sk_buff *rsp, const struct page_pool *pool, struct nlattr *nest; void *hdr; - if (!page_pool_get_stats(pool, &stats)) - return 0; + page_pool_get_stats(pool, &stats); hdr = genlmsg_iput(rsp, info); if (!hdr)