diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 9d958128a57c..817f8b78d246 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -43,18 +43,32 @@ 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 ============= -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 @@ -69,7 +83,7 @@ a page will cause no race conditions is enough. 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 -------- @@ -98,29 +112,12 @@ 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. -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 =============== @@ -140,7 +137,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); @@ -174,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/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 8171d1173221..21dc4a9c8714 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -76,20 +76,20 @@ 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 * 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; @@ -108,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)