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

libeth: convert to netmem

Back when the libeth Rx core was initially written, devmem was a draft
and netmem_ref didn't exist in the mainline. Now that it's here, make
libeth MP-agnostic before introducing any new code or any new library
users.
When it's known that the created PP/FQ is for header buffers, use faster
"unsafe" underscored netmem <--> virt accessors as netmem_is_net_iov()
is always false in that case, but consumes some cycles (bit test +
true branch).

Reviewed-by: Mina Almasry <almasrymina@google.com>
Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>

authored by

Alexander Lobakin and committed by
Tony Nguyen
6ad5ff6e 359bcf15

+46 -36
+8 -6
drivers/net/ethernet/intel/iavf/iavf_txrx.c
··· 723 723 for (u32 i = rx_ring->next_to_clean; i != rx_ring->next_to_use; ) { 724 724 const struct libeth_fqe *rx_fqes = &rx_ring->rx_fqes[i]; 725 725 726 - page_pool_put_full_page(rx_ring->pp, rx_fqes->page, false); 726 + libeth_rx_recycle_slow(rx_fqes->netmem); 727 727 728 728 if (unlikely(++i == rx_ring->count)) 729 729 i = 0; ··· 1197 1197 const struct libeth_fqe *rx_buffer, 1198 1198 unsigned int size) 1199 1199 { 1200 - u32 hr = rx_buffer->page->pp->p.offset; 1200 + u32 hr = netmem_get_pp(rx_buffer->netmem)->p.offset; 1201 1201 1202 - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buffer->page, 1203 - rx_buffer->offset + hr, size, rx_buffer->truesize); 1202 + skb_add_rx_frag_netmem(skb, skb_shinfo(skb)->nr_frags, 1203 + rx_buffer->netmem, rx_buffer->offset + hr, 1204 + size, rx_buffer->truesize); 1204 1205 } 1205 1206 1206 1207 /** ··· 1215 1214 static struct sk_buff *iavf_build_skb(const struct libeth_fqe *rx_buffer, 1216 1215 unsigned int size) 1217 1216 { 1218 - u32 hr = rx_buffer->page->pp->p.offset; 1217 + struct page *buf_page = __netmem_to_page(rx_buffer->netmem); 1218 + u32 hr = buf_page->pp->p.offset; 1219 1219 struct sk_buff *skb; 1220 1220 void *va; 1221 1221 1222 1222 /* prefetch first cache line of first page */ 1223 - va = page_address(rx_buffer->page) + rx_buffer->offset; 1223 + va = page_address(buf_page) + rx_buffer->offset; 1224 1224 net_prefetch(va + hr); 1225 1225 1226 1226 /* build an skb around the page buffer */
+1 -1
drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
··· 1006 1006 break; 1007 1007 1008 1008 skip_data: 1009 - rx_buf->page = NULL; 1009 + rx_buf->netmem = 0; 1010 1010 1011 1011 IDPF_SINGLEQ_BUMP_RING_IDX(rx_q, ntc); 1012 1012 cleaned_count++;
+21 -15
drivers/net/ethernet/intel/idpf/idpf_txrx.c
··· 383 383 */ 384 384 static void idpf_rx_page_rel(struct libeth_fqe *rx_buf) 385 385 { 386 - if (unlikely(!rx_buf->page)) 386 + if (unlikely(!rx_buf->netmem)) 387 387 return; 388 388 389 - page_pool_put_full_page(rx_buf->page->pp, rx_buf->page, false); 389 + libeth_rx_recycle_slow(rx_buf->netmem); 390 390 391 - rx_buf->page = NULL; 391 + rx_buf->netmem = 0; 392 392 rx_buf->offset = 0; 393 393 } 394 394 ··· 3240 3240 void idpf_rx_add_frag(struct idpf_rx_buf *rx_buf, struct sk_buff *skb, 3241 3241 unsigned int size) 3242 3242 { 3243 - u32 hr = rx_buf->page->pp->p.offset; 3243 + u32 hr = netmem_get_pp(rx_buf->netmem)->p.offset; 3244 3244 3245 - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_buf->page, 3246 - rx_buf->offset + hr, size, rx_buf->truesize); 3245 + skb_add_rx_frag_netmem(skb, skb_shinfo(skb)->nr_frags, rx_buf->netmem, 3246 + rx_buf->offset + hr, size, rx_buf->truesize); 3247 3247 } 3248 3248 3249 3249 /** ··· 3266 3266 struct libeth_fqe *buf, u32 data_len) 3267 3267 { 3268 3268 u32 copy = data_len <= L1_CACHE_BYTES ? data_len : ETH_HLEN; 3269 + struct page *hdr_page, *buf_page; 3269 3270 const void *src; 3270 3271 void *dst; 3271 3272 3272 - if (!libeth_rx_sync_for_cpu(buf, copy)) 3273 + if (unlikely(netmem_is_net_iov(buf->netmem)) || 3274 + !libeth_rx_sync_for_cpu(buf, copy)) 3273 3275 return 0; 3274 3276 3275 - dst = page_address(hdr->page) + hdr->offset + hdr->page->pp->p.offset; 3276 - src = page_address(buf->page) + buf->offset + buf->page->pp->p.offset; 3277 - memcpy(dst, src, LARGEST_ALIGN(copy)); 3277 + hdr_page = __netmem_to_page(hdr->netmem); 3278 + buf_page = __netmem_to_page(buf->netmem); 3279 + dst = page_address(hdr_page) + hdr->offset + hdr_page->pp->p.offset; 3280 + src = page_address(buf_page) + buf->offset + buf_page->pp->p.offset; 3278 3281 3282 + memcpy(dst, src, LARGEST_ALIGN(copy)); 3279 3283 buf->offset += copy; 3280 3284 3281 3285 return copy; ··· 3295 3291 */ 3296 3292 struct sk_buff *idpf_rx_build_skb(const struct libeth_fqe *buf, u32 size) 3297 3293 { 3298 - u32 hr = buf->page->pp->p.offset; 3294 + struct page *buf_page = __netmem_to_page(buf->netmem); 3295 + u32 hr = buf_page->pp->p.offset; 3299 3296 struct sk_buff *skb; 3300 3297 void *va; 3301 3298 3302 - va = page_address(buf->page) + buf->offset; 3299 + va = page_address(buf_page) + buf->offset; 3303 3300 prefetch(va + hr); 3304 3301 3305 3302 skb = napi_build_skb(va, buf->truesize); ··· 3434 3429 3435 3430 if (unlikely(!hdr_len && !skb)) { 3436 3431 hdr_len = idpf_rx_hsplit_wa(hdr, rx_buf, pkt_len); 3437 - pkt_len -= hdr_len; 3432 + /* If failed, drop both buffers by setting len to 0 */ 3433 + pkt_len -= hdr_len ? : pkt_len; 3438 3434 3439 3435 u64_stats_update_begin(&rxq->stats_sync); 3440 3436 u64_stats_inc(&rxq->q_stats.hsplit_buf_ovf); ··· 3452 3446 u64_stats_update_end(&rxq->stats_sync); 3453 3447 } 3454 3448 3455 - hdr->page = NULL; 3449 + hdr->netmem = 0; 3456 3450 3457 3451 payload: 3458 3452 if (!libeth_rx_sync_for_cpu(rx_buf, pkt_len)) ··· 3468 3462 break; 3469 3463 3470 3464 skip_data: 3471 - rx_buf->page = NULL; 3465 + rx_buf->netmem = 0; 3472 3466 3473 3467 idpf_rx_post_buf_refill(refillq, buf_id); 3474 3468 IDPF_RX_BUMP_NTC(rxq, ntc);
+4 -4
drivers/net/ethernet/intel/libeth/rx.c
··· 204 204 EXPORT_SYMBOL_GPL(libeth_rx_fq_destroy); 205 205 206 206 /** 207 - * libeth_rx_recycle_slow - recycle a libeth page from the NAPI context 208 - * @page: page to recycle 207 + * libeth_rx_recycle_slow - recycle libeth netmem 208 + * @netmem: network memory to recycle 209 209 * 210 210 * To be used on exceptions or rare cases not requiring fast inline recycling. 211 211 */ 212 - void libeth_rx_recycle_slow(struct page *page) 212 + void __cold libeth_rx_recycle_slow(netmem_ref netmem) 213 213 { 214 - page_pool_recycle_direct(page->pp, page); 214 + page_pool_put_full_netmem(netmem_get_pp(netmem), netmem, false); 215 215 } 216 216 EXPORT_SYMBOL_GPL(libeth_rx_recycle_slow); 217 217
+12 -10
include/net/libeth/rx.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* Copyright (C) 2024 Intel Corporation */ 2 + /* Copyright (C) 2024-2025 Intel Corporation */ 3 3 4 4 #ifndef __LIBETH_RX_H 5 5 #define __LIBETH_RX_H ··· 31 31 32 32 /** 33 33 * struct libeth_fqe - structure representing an Rx buffer (fill queue element) 34 - * @page: page holding the buffer 34 + * @netmem: network memory reference holding the buffer 35 35 * @offset: offset from the page start (to the headroom) 36 36 * @truesize: total space occupied by the buffer (w/ headroom and tailroom) 37 37 * ··· 40 40 * former, @offset is always 0 and @truesize is always ```PAGE_SIZE```. 41 41 */ 42 42 struct libeth_fqe { 43 - struct page *page; 43 + netmem_ref netmem; 44 44 u32 offset; 45 45 u32 truesize; 46 46 } __aligned_largest; ··· 102 102 struct libeth_fqe *buf = &fq->fqes[i]; 103 103 104 104 buf->truesize = fq->truesize; 105 - buf->page = page_pool_dev_alloc(fq->pp, &buf->offset, &buf->truesize); 106 - if (unlikely(!buf->page)) 105 + buf->netmem = page_pool_dev_alloc_netmem(fq->pp, &buf->offset, 106 + &buf->truesize); 107 + if (unlikely(!buf->netmem)) 107 108 return DMA_MAPPING_ERROR; 108 109 109 - return page_pool_get_dma_addr(buf->page) + buf->offset + 110 + return page_pool_get_dma_addr_netmem(buf->netmem) + buf->offset + 110 111 fq->pp->p.offset; 111 112 } 112 113 113 - void libeth_rx_recycle_slow(struct page *page); 114 + void libeth_rx_recycle_slow(netmem_ref netmem); 114 115 115 116 /** 116 117 * libeth_rx_sync_for_cpu - synchronize or recycle buffer post DMA ··· 127 126 static inline bool libeth_rx_sync_for_cpu(const struct libeth_fqe *fqe, 128 127 u32 len) 129 128 { 130 - struct page *page = fqe->page; 129 + netmem_ref netmem = fqe->netmem; 131 130 132 131 /* Very rare, but possible case. The most common reason: 133 132 * the last fragment contained FCS only, which was then 134 133 * stripped by the HW. 135 134 */ 136 135 if (unlikely(!len)) { 137 - libeth_rx_recycle_slow(page); 136 + libeth_rx_recycle_slow(netmem); 138 137 return false; 139 138 } 140 139 141 - page_pool_dma_sync_for_cpu(page->pp, page, fqe->offset, len); 140 + page_pool_dma_sync_netmem_for_cpu(netmem_get_pp(netmem), netmem, 141 + fqe->offset, len); 142 142 143 143 return true; 144 144 }