Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: page_pool: add the possibility to sync DMA memory for device

Introduce the following parameters in order to add the possibility to sync
DMA memory for device before putting allocated pages in the page_pool
caches:
- PP_FLAG_DMA_SYNC_DEV: if set in page_pool_params flags, all pages that
the driver gets from page_pool will be DMA-synced-for-device according
to the length provided by the device driver. Please note DMA-sync-for-CPU
is still device driver responsibility
- offset: DMA address offset where the DMA engine starts copying rx data
- max_len: maximum DMA memory size page_pool is allowed to flush. This
is currently used in __page_pool_alloc_pages_slow routine when pages
are allocated from page allocator
These parameters are supposed to be set by device drivers.

This optimization reduces the length of the DMA-sync-for-device.
The optimization is valid because pages are initially
DMA-synced-for-device as defined via max_len. At RX time, the driver
will perform a DMA-sync-for-CPU on the memory for the packet length.
What is important is the memory occupied by packet payload, because
this is the area CPU is allowed to read and modify. As we don't track
cache-lines written into by the CPU, simply use the packet payload length
as dma_sync_size at page_pool recycle time. This also take into account
any tail-extend.

Tested-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Lorenzo Bianconi and committed by
David S. Miller
e68bc756 f383b295

+52 -8
+18 -6
include/net/page_pool.h
··· 34 34 #include <linux/ptr_ring.h> 35 35 #include <linux/dma-direction.h> 36 36 37 - #define PP_FLAG_DMA_MAP 1 /* Should page_pool do the DMA map/unmap */ 38 - #define PP_FLAG_ALL PP_FLAG_DMA_MAP 37 + #define PP_FLAG_DMA_MAP BIT(0) /* Should page_pool do the DMA 38 + * map/unmap 39 + */ 40 + #define PP_FLAG_DMA_SYNC_DEV BIT(1) /* If set all pages that the driver gets 41 + * from page_pool will be 42 + * DMA-synced-for-device according to 43 + * the length provided by the device 44 + * driver. 45 + * Please note DMA-sync-for-CPU is still 46 + * device driver responsibility 47 + */ 48 + #define PP_FLAG_ALL (PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV) 39 49 40 50 /* 41 51 * Fast allocation side cache array/stack ··· 75 65 int nid; /* Numa node id to allocate from pages from */ 76 66 struct device *dev; /* device, for DMA pre-mapping purposes */ 77 67 enum dma_data_direction dma_dir; /* DMA mapping direction */ 68 + unsigned int max_len; /* max DMA sync memory size */ 69 + unsigned int offset; /* DMA addr offset */ 78 70 }; 79 71 80 72 struct page_pool { ··· 163 151 #endif 164 152 165 153 /* Never call this directly, use helpers below */ 166 - void __page_pool_put_page(struct page_pool *pool, 167 - struct page *page, bool allow_direct); 154 + void __page_pool_put_page(struct page_pool *pool, struct page *page, 155 + unsigned int dma_sync_size, bool allow_direct); 168 156 169 157 static inline void page_pool_put_page(struct page_pool *pool, 170 158 struct page *page, bool allow_direct) ··· 173 161 * allow registering MEM_TYPE_PAGE_POOL, but shield linker. 174 162 */ 175 163 #ifdef CONFIG_PAGE_POOL 176 - __page_pool_put_page(pool, page, allow_direct); 164 + __page_pool_put_page(pool, page, -1, allow_direct); 177 165 #endif 178 166 } 179 167 /* Very limited use-cases allow recycle direct */ 180 168 static inline void page_pool_recycle_direct(struct page_pool *pool, 181 169 struct page *page) 182 170 { 183 - __page_pool_put_page(pool, page, true); 171 + __page_pool_put_page(pool, page, -1, true); 184 172 } 185 173 186 174 /* Disconnects a page (from a page_pool). API users can have a need
+34 -2
net/core/page_pool.c
··· 47 47 (pool->p.dma_dir != DMA_BIDIRECTIONAL)) 48 48 return -EINVAL; 49 49 50 + if (pool->p.flags & PP_FLAG_DMA_SYNC_DEV) { 51 + /* In order to request DMA-sync-for-device the page 52 + * needs to be mapped 53 + */ 54 + if (!(pool->p.flags & PP_FLAG_DMA_MAP)) 55 + return -EINVAL; 56 + 57 + if (!pool->p.max_len) 58 + return -EINVAL; 59 + 60 + /* pool->p.offset has to be set according to the address 61 + * offset used by the DMA engine to start copying rx data 62 + */ 63 + } 64 + 50 65 if (ptr_ring_init(&pool->ring, ring_qsize, GFP_KERNEL) < 0) 51 66 return -ENOMEM; 52 67 ··· 130 115 return page; 131 116 } 132 117 118 + static void page_pool_dma_sync_for_device(struct page_pool *pool, 119 + struct page *page, 120 + unsigned int dma_sync_size) 121 + { 122 + dma_sync_size = min(dma_sync_size, pool->p.max_len); 123 + dma_sync_single_range_for_device(pool->p.dev, page->dma_addr, 124 + pool->p.offset, dma_sync_size, 125 + pool->p.dma_dir); 126 + } 127 + 133 128 /* slow path */ 134 129 noinline 135 130 static struct page *__page_pool_alloc_pages_slow(struct page_pool *pool, ··· 183 158 return NULL; 184 159 } 185 160 page->dma_addr = dma; 161 + 162 + if (pool->p.flags & PP_FLAG_DMA_SYNC_DEV) 163 + page_pool_dma_sync_for_device(pool, page, pool->p.max_len); 186 164 187 165 skip_dma_map: 188 166 /* Track how many pages are held 'in-flight' */ ··· 320 292 return !page_is_pfmemalloc(page) && page_to_nid(page) == pool->p.nid; 321 293 } 322 294 323 - void __page_pool_put_page(struct page_pool *pool, 324 - struct page *page, bool allow_direct) 295 + void __page_pool_put_page(struct page_pool *pool, struct page *page, 296 + unsigned int dma_sync_size, bool allow_direct) 325 297 { 326 298 /* This allocator is optimized for the XDP mode that uses 327 299 * one-frame-per-page, but have fallbacks that act like the ··· 332 304 if (likely(page_ref_count(page) == 1 && 333 305 pool_page_reusable(pool, page))) { 334 306 /* Read barrier done in page_ref_count / READ_ONCE */ 307 + 308 + if (pool->p.flags & PP_FLAG_DMA_SYNC_DEV) 309 + page_pool_dma_sync_for_device(pool, page, 310 + dma_sync_size); 335 311 336 312 if (allow_direct && in_serving_softirq()) 337 313 if (__page_pool_recycle_direct(page, pool))