162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * page_pool/helpers.h 462306a36Sopenharmony_ci * Author: Jesper Dangaard Brouer <netoptimizer@brouer.com> 562306a36Sopenharmony_ci * Copyright (C) 2016 Red Hat, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/** 962306a36Sopenharmony_ci * DOC: page_pool allocator 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The page_pool allocator is optimized for the XDP mode that 1262306a36Sopenharmony_ci * uses one frame per-page, but it can fallback on the 1362306a36Sopenharmony_ci * regular page allocator APIs. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Basic use involves replacing alloc_pages() calls with the 1662306a36Sopenharmony_ci * page_pool_alloc_pages() call. Drivers should use 1762306a36Sopenharmony_ci * page_pool_dev_alloc_pages() replacing dev_alloc_pages(). 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * The API keeps track of in-flight pages, in order to let API users know 2062306a36Sopenharmony_ci * when it is safe to free a page_pool object. Thus, API users 2162306a36Sopenharmony_ci * must call page_pool_put_page() to free the page, or attach 2262306a36Sopenharmony_ci * the page to a page_pool-aware object like skbs marked with 2362306a36Sopenharmony_ci * skb_mark_for_recycle(). 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * API users must call page_pool_put_page() once on a page, as it 2662306a36Sopenharmony_ci * will either recycle the page, or in case of refcnt > 1, it will 2762306a36Sopenharmony_ci * release the DMA mapping and in-flight state accounting. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci#ifndef _NET_PAGE_POOL_HELPERS_H 3062306a36Sopenharmony_ci#define _NET_PAGE_POOL_HELPERS_H 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <net/page_pool/types.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#ifdef CONFIG_PAGE_POOL_STATS 3562306a36Sopenharmony_ciint page_pool_ethtool_stats_get_count(void); 3662306a36Sopenharmony_ciu8 *page_pool_ethtool_stats_get_strings(u8 *data); 3762306a36Sopenharmony_ciu64 *page_pool_ethtool_stats_get(u64 *data, void *stats); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Drivers that wish to harvest page pool stats and report them to users 4162306a36Sopenharmony_ci * (perhaps via ethtool, debugfs, or another mechanism) can allocate a 4262306a36Sopenharmony_ci * struct page_pool_stats call page_pool_get_stats to get stats for the specified pool. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cibool page_pool_get_stats(struct page_pool *pool, 4562306a36Sopenharmony_ci struct page_pool_stats *stats); 4662306a36Sopenharmony_ci#else 4762306a36Sopenharmony_cistatic inline int page_pool_ethtool_stats_get_count(void) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return 0; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic inline u8 *page_pool_ethtool_stats_get_strings(u8 *data) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci return data; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic inline u64 *page_pool_ethtool_stats_get(u64 *data, void *stats) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci return data; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci#endif 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/** 6462306a36Sopenharmony_ci * page_pool_dev_alloc_pages() - allocate a page. 6562306a36Sopenharmony_ci * @pool: pool from which to allocate 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * Get a page from the page allocator or page_pool caches. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_cistatic inline struct page *page_pool_dev_alloc_pages(struct page_pool *pool) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return page_pool_alloc_pages(pool, gfp); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic inline struct page *page_pool_dev_alloc_frag(struct page_pool *pool, 7762306a36Sopenharmony_ci unsigned int *offset, 7862306a36Sopenharmony_ci unsigned int size) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return page_pool_alloc_frag(pool, offset, size, gfp); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/** 8662306a36Sopenharmony_ci * page_pool_get_dma_dir() - Retrieve the stored DMA direction. 8762306a36Sopenharmony_ci * @pool: pool from which page was allocated 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * Get the stored dma direction. A driver might decide to store this locally 9062306a36Sopenharmony_ci * and avoid the extra cache line from page_pool to determine the direction. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistatic 9362306a36Sopenharmony_ciinline enum dma_data_direction page_pool_get_dma_dir(struct page_pool *pool) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci return pool->p.dma_dir; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* pp_frag_count represents the number of writers who can update the page 9962306a36Sopenharmony_ci * either by updating skb->data or via DMA mappings for the device. 10062306a36Sopenharmony_ci * We can't rely on the page refcnt for that as we don't know who might be 10162306a36Sopenharmony_ci * holding page references and we can't reliably destroy or sync DMA mappings 10262306a36Sopenharmony_ci * of the fragments. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * When pp_frag_count reaches 0 we can either recycle the page if the page 10562306a36Sopenharmony_ci * refcnt is 1 or return it back to the memory allocator and destroy any 10662306a36Sopenharmony_ci * mappings we have. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic inline void page_pool_fragment_page(struct page *page, long nr) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci atomic_long_set(&page->pp_frag_count, nr); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic inline long page_pool_defrag_page(struct page *page, long nr) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci long ret; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* If nr == pp_frag_count then we have cleared all remaining 11862306a36Sopenharmony_ci * references to the page. No need to actually overwrite it, instead 11962306a36Sopenharmony_ci * we can leave this to be overwritten by the calling function. 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * The main advantage to doing this is that an atomic_read is 12262306a36Sopenharmony_ci * generally a much cheaper operation than an atomic update, 12362306a36Sopenharmony_ci * especially when dealing with a page that may be partitioned 12462306a36Sopenharmony_ci * into only 2 or 3 pieces. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci if (atomic_long_read(&page->pp_frag_count) == nr) 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci ret = atomic_long_sub_return(nr, &page->pp_frag_count); 13062306a36Sopenharmony_ci WARN_ON(ret < 0); 13162306a36Sopenharmony_ci return ret; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic inline bool page_pool_is_last_frag(struct page_pool *pool, 13562306a36Sopenharmony_ci struct page *page) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci /* If fragments aren't enabled or count is 0 we were the last user */ 13862306a36Sopenharmony_ci return !(pool->p.flags & PP_FLAG_PAGE_FRAG) || 13962306a36Sopenharmony_ci (page_pool_defrag_page(page, 1) == 0); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * page_pool_put_page() - release a reference to a page pool page 14462306a36Sopenharmony_ci * @pool: pool from which page was allocated 14562306a36Sopenharmony_ci * @page: page to release a reference on 14662306a36Sopenharmony_ci * @dma_sync_size: how much of the page may have been touched by the device 14762306a36Sopenharmony_ci * @allow_direct: released by the consumer, allow lockless caching 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * The outcome of this depends on the page refcnt. If the driver bumps 15062306a36Sopenharmony_ci * the refcnt > 1 this will unmap the page. If the page refcnt is 1 15162306a36Sopenharmony_ci * the allocator owns the page and will try to recycle it in one of the pool 15262306a36Sopenharmony_ci * caches. If PP_FLAG_DMA_SYNC_DEV is set, the page will be synced for_device 15362306a36Sopenharmony_ci * using dma_sync_single_range_for_device(). 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_cistatic inline void page_pool_put_page(struct page_pool *pool, 15662306a36Sopenharmony_ci struct page *page, 15762306a36Sopenharmony_ci unsigned int dma_sync_size, 15862306a36Sopenharmony_ci bool allow_direct) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci /* When page_pool isn't compiled-in, net/core/xdp.c doesn't 16162306a36Sopenharmony_ci * allow registering MEM_TYPE_PAGE_POOL, but shield linker. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci#ifdef CONFIG_PAGE_POOL 16462306a36Sopenharmony_ci if (!page_pool_is_last_frag(pool, page)) 16562306a36Sopenharmony_ci return; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci page_pool_put_defragged_page(pool, page, dma_sync_size, allow_direct); 16862306a36Sopenharmony_ci#endif 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * page_pool_put_full_page() - release a reference on a page pool page 17362306a36Sopenharmony_ci * @pool: pool from which page was allocated 17462306a36Sopenharmony_ci * @page: page to release a reference on 17562306a36Sopenharmony_ci * @allow_direct: released by the consumer, allow lockless caching 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * Similar to page_pool_put_page(), but will DMA sync the entire memory area 17862306a36Sopenharmony_ci * as configured in &page_pool_params.max_len. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_cistatic inline void page_pool_put_full_page(struct page_pool *pool, 18162306a36Sopenharmony_ci struct page *page, bool allow_direct) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci page_pool_put_page(pool, page, -1, allow_direct); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/** 18762306a36Sopenharmony_ci * page_pool_recycle_direct() - release a reference on a page pool page 18862306a36Sopenharmony_ci * @pool: pool from which page was allocated 18962306a36Sopenharmony_ci * @page: page to release a reference on 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * Similar to page_pool_put_full_page() but caller must guarantee safe context 19262306a36Sopenharmony_ci * (e.g NAPI), since it will recycle the page directly into the pool fast cache. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_cistatic inline void page_pool_recycle_direct(struct page_pool *pool, 19562306a36Sopenharmony_ci struct page *page) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci page_pool_put_full_page(pool, page, true); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#define PAGE_POOL_DMA_USE_PP_FRAG_COUNT \ 20162306a36Sopenharmony_ci (sizeof(dma_addr_t) > sizeof(unsigned long)) 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/** 20462306a36Sopenharmony_ci * page_pool_get_dma_addr() - Retrieve the stored DMA address. 20562306a36Sopenharmony_ci * @page: page allocated from a page pool 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * Fetch the DMA address of the page. The page pool to which the page belongs 20862306a36Sopenharmony_ci * must had been created with PP_FLAG_DMA_MAP. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_cistatic inline dma_addr_t page_pool_get_dma_addr(struct page *page) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci dma_addr_t ret = page->dma_addr; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (PAGE_POOL_DMA_USE_PP_FRAG_COUNT) 21562306a36Sopenharmony_ci ret |= (dma_addr_t)page->dma_addr_upper << 16 << 16; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return ret; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic inline void page_pool_set_dma_addr(struct page *page, dma_addr_t addr) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci page->dma_addr = addr; 22362306a36Sopenharmony_ci if (PAGE_POOL_DMA_USE_PP_FRAG_COUNT) 22462306a36Sopenharmony_ci page->dma_addr_upper = upper_32_bits(addr); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic inline bool page_pool_put(struct page_pool *pool) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci return refcount_dec_and_test(&pool->user_cnt); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic inline void page_pool_nid_changed(struct page_pool *pool, int new_nid) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci if (unlikely(pool->p.nid != new_nid)) 23562306a36Sopenharmony_ci page_pool_update_nid(pool, new_nid); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#endif /* _NET_PAGE_POOL_HELPERS_H */ 239