diff options
author | Tariq Toukan <tariqt@mellanox.com> | 2017-11-28 04:03:37 -0500 |
---|---|---|
committer | Saeed Mahameed <saeedm@mellanox.com> | 2018-03-30 19:55:06 -0400 |
commit | 9f9e9cd50eac6ad09cb053509f2e764bddc05f18 (patch) | |
tree | 8b3a3f9c6a1e07c13ef23ec1cebd960fc4ddfad7 | |
parent | 22f4539881944a8acc9c6f5afa7aa7f028898002 (diff) |
net/mlx5e: Remove page_ref bulking in Striding RQ
When many packets reside on the same page, the bulking of
page_ref modifications reduces the total number of atomic
operations executed.
Besides the necessary 2 operations on page alloc/free, we
have the following extra ops per page:
- one on WQE allocation (bump refcnt to maximum possible),
- zero ops for SKBs,
- one on WQE free,
a constant of two operations in total, no matter how many
packets/SKBs actually populate the page.
Without this bulking, we have:
- no ops on WQE allocation or free,
- one op per SKB,
Comparing the two methods when PAGE_SIZE is 4K:
- As mentioned above, bulking method always executes 2 operations,
not more, but not less.
- In the default MTU configuration (1500, stride size is 2K),
the non-bulking method execute 2 ops as well.
- For larger MTUs with stride size of 4K, non-bulking method
executes only a single op.
- For XDP (stride size of 4K, no SKBs), non-bulking method
executes no ops at all!
Hence, to optimize the flows with linear SKB and XDP over Striding RQ,
we here remove the page_ref bulking method.
Performance testing:
ConnectX-5, Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz.
Single core packet rate (64 bytes).
Early drop in TC: no degradation.
XDP_DROP:
before: 14,270,188 pps
after: 20,503,603 pps, 43% improvement.
Signed-off-by: Tariq Toukan <tariqt@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 47 |
2 files changed, 16 insertions, 32 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 7997d7c159db..5853de4e4fc7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h | |||
@@ -456,7 +456,6 @@ struct mlx5e_umr_dma_info { | |||
456 | struct mlx5e_mpw_info { | 456 | struct mlx5e_mpw_info { |
457 | struct mlx5e_umr_dma_info umr; | 457 | struct mlx5e_umr_dma_info umr; |
458 | u16 consumed_strides; | 458 | u16 consumed_strides; |
459 | u16 skbs_frags[MLX5_MPWRQ_PAGES_PER_WQE]; | ||
460 | DECLARE_BITMAP(xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE); | 459 | DECLARE_BITMAP(xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE); |
461 | }; | 460 | }; |
462 | 461 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 1da79cab1838..9bb47a6d40f1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | |||
@@ -296,37 +296,28 @@ void mlx5e_dealloc_rx_wqe(struct mlx5e_rq *rq, u16 ix) | |||
296 | mlx5e_free_rx_wqe(rq, wi); | 296 | mlx5e_free_rx_wqe(rq, wi); |
297 | } | 297 | } |
298 | 298 | ||
299 | static inline int mlx5e_mpwqe_strides_per_page(struct mlx5e_rq *rq) | ||
300 | { | ||
301 | return rq->mpwqe.num_strides >> MLX5_MPWRQ_WQE_PAGE_ORDER; | ||
302 | } | ||
303 | |||
304 | static inline void mlx5e_add_skb_frag_mpwqe(struct mlx5e_rq *rq, | 299 | static inline void mlx5e_add_skb_frag_mpwqe(struct mlx5e_rq *rq, |
305 | struct sk_buff *skb, | 300 | struct sk_buff *skb, |
306 | struct mlx5e_mpw_info *wi, | 301 | struct mlx5e_dma_info *di, |
307 | u32 page_idx, u32 frag_offset, | 302 | u32 frag_offset, u32 len) |
308 | u32 len) | ||
309 | { | 303 | { |
310 | unsigned int truesize = ALIGN(len, BIT(rq->mpwqe.log_stride_sz)); | 304 | unsigned int truesize = ALIGN(len, BIT(rq->mpwqe.log_stride_sz)); |
311 | 305 | ||
312 | dma_sync_single_for_cpu(rq->pdev, | 306 | dma_sync_single_for_cpu(rq->pdev, |
313 | wi->umr.dma_info[page_idx].addr + frag_offset, | 307 | di->addr + frag_offset, |
314 | len, DMA_FROM_DEVICE); | 308 | len, DMA_FROM_DEVICE); |
315 | wi->skbs_frags[page_idx]++; | 309 | page_ref_inc(di->page); |
316 | skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, | 310 | skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, |
317 | wi->umr.dma_info[page_idx].page, frag_offset, | 311 | di->page, frag_offset, len, truesize); |
318 | len, truesize); | ||
319 | } | 312 | } |
320 | 313 | ||
321 | static inline void | 314 | static inline void |
322 | mlx5e_copy_skb_header_mpwqe(struct device *pdev, | 315 | mlx5e_copy_skb_header_mpwqe(struct device *pdev, |
323 | struct sk_buff *skb, | 316 | struct sk_buff *skb, |
324 | struct mlx5e_mpw_info *wi, | 317 | struct mlx5e_dma_info *dma_info, |
325 | u32 page_idx, u32 offset, | 318 | u32 offset, u32 headlen) |
326 | u32 headlen) | ||
327 | { | 319 | { |
328 | u16 headlen_pg = min_t(u32, headlen, PAGE_SIZE - offset); | 320 | u16 headlen_pg = min_t(u32, headlen, PAGE_SIZE - offset); |
329 | struct mlx5e_dma_info *dma_info = &wi->umr.dma_info[page_idx]; | ||
330 | unsigned int len; | 321 | unsigned int len; |
331 | 322 | ||
332 | /* Aligning len to sizeof(long) optimizes memcpy performance */ | 323 | /* Aligning len to sizeof(long) optimizes memcpy performance */ |
@@ -351,15 +342,12 @@ void mlx5e_free_rx_mpwqe(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi) | |||
351 | { | 342 | { |
352 | const bool no_xdp_xmit = | 343 | const bool no_xdp_xmit = |
353 | bitmap_empty(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE); | 344 | bitmap_empty(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE); |
354 | int pg_strides = mlx5e_mpwqe_strides_per_page(rq); | ||
355 | struct mlx5e_dma_info *dma_info = wi->umr.dma_info; | 345 | struct mlx5e_dma_info *dma_info = wi->umr.dma_info; |
356 | int i; | 346 | int i; |
357 | 347 | ||
358 | for (i = 0; i < MLX5_MPWRQ_PAGES_PER_WQE; i++) { | 348 | for (i = 0; i < MLX5_MPWRQ_PAGES_PER_WQE; i++) |
359 | page_ref_sub(dma_info[i].page, pg_strides - wi->skbs_frags[i]); | ||
360 | if (no_xdp_xmit || !test_bit(i, wi->xdp_xmit_bitmap)) | 349 | if (no_xdp_xmit || !test_bit(i, wi->xdp_xmit_bitmap)) |
361 | mlx5e_page_release(rq, &dma_info[i], true); | 350 | mlx5e_page_release(rq, &dma_info[i], true); |
362 | } | ||
363 | } | 351 | } |
364 | 352 | ||
365 | static void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq) | 353 | static void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq) |
@@ -380,7 +368,6 @@ static void mlx5e_post_rx_mpwqe(struct mlx5e_rq *rq) | |||
380 | static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix) | 368 | static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix) |
381 | { | 369 | { |
382 | struct mlx5e_mpw_info *wi = &rq->mpwqe.info[ix]; | 370 | struct mlx5e_mpw_info *wi = &rq->mpwqe.info[ix]; |
383 | int pg_strides = mlx5e_mpwqe_strides_per_page(rq); | ||
384 | struct mlx5e_dma_info *dma_info = &wi->umr.dma_info[0]; | 371 | struct mlx5e_dma_info *dma_info = &wi->umr.dma_info[0]; |
385 | struct mlx5e_icosq *sq = &rq->channel->icosq; | 372 | struct mlx5e_icosq *sq = &rq->channel->icosq; |
386 | struct mlx5_wq_cyc *wq = &sq->wq; | 373 | struct mlx5_wq_cyc *wq = &sq->wq; |
@@ -403,10 +390,8 @@ static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix) | |||
403 | if (unlikely(err)) | 390 | if (unlikely(err)) |
404 | goto err_unmap; | 391 | goto err_unmap; |
405 | umr_wqe->inline_mtts[i].ptag = cpu_to_be64(dma_info->addr | MLX5_EN_WR); | 392 | umr_wqe->inline_mtts[i].ptag = cpu_to_be64(dma_info->addr | MLX5_EN_WR); |
406 | page_ref_add(dma_info->page, pg_strides); | ||
407 | } | 393 | } |
408 | 394 | ||
409 | memset(wi->skbs_frags, 0, sizeof(*wi->skbs_frags) * MLX5_MPWRQ_PAGES_PER_WQE); | ||
410 | bitmap_zero(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE); | 395 | bitmap_zero(wi->xdp_xmit_bitmap, MLX5_MPWRQ_PAGES_PER_WQE); |
411 | wi->consumed_strides = 0; | 396 | wi->consumed_strides = 0; |
412 | 397 | ||
@@ -425,7 +410,6 @@ static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix) | |||
425 | err_unmap: | 410 | err_unmap: |
426 | while (--i >= 0) { | 411 | while (--i >= 0) { |
427 | dma_info--; | 412 | dma_info--; |
428 | page_ref_sub(dma_info->page, pg_strides); | ||
429 | mlx5e_page_release(rq, dma_info, true); | 413 | mlx5e_page_release(rq, dma_info, true); |
430 | } | 414 | } |
431 | rq->stats.buff_alloc_err++; | 415 | rq->stats.buff_alloc_err++; |
@@ -987,9 +971,10 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w | |||
987 | u16 cqe_bcnt, u32 head_offset, u32 page_idx) | 971 | u16 cqe_bcnt, u32 head_offset, u32 page_idx) |
988 | { | 972 | { |
989 | u16 headlen = min_t(u16, MLX5_MPWRQ_SMALL_PACKET_THRESHOLD, cqe_bcnt); | 973 | u16 headlen = min_t(u16, MLX5_MPWRQ_SMALL_PACKET_THRESHOLD, cqe_bcnt); |
974 | struct mlx5e_dma_info *di = &wi->umr.dma_info[page_idx]; | ||
990 | u32 frag_offset = head_offset + headlen; | 975 | u32 frag_offset = head_offset + headlen; |
991 | u16 byte_cnt = cqe_bcnt - headlen; | 976 | u32 byte_cnt = cqe_bcnt - headlen; |
992 | u32 head_page_idx = page_idx; | 977 | struct mlx5e_dma_info *head_di = di; |
993 | struct sk_buff *skb; | 978 | struct sk_buff *skb; |
994 | 979 | ||
995 | skb = napi_alloc_skb(rq->cq.napi, | 980 | skb = napi_alloc_skb(rq->cq.napi, |
@@ -1002,7 +987,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w | |||
1002 | prefetchw(skb->data); | 987 | prefetchw(skb->data); |
1003 | 988 | ||
1004 | if (unlikely(frag_offset >= PAGE_SIZE)) { | 989 | if (unlikely(frag_offset >= PAGE_SIZE)) { |
1005 | page_idx++; | 990 | di++; |
1006 | frag_offset -= PAGE_SIZE; | 991 | frag_offset -= PAGE_SIZE; |
1007 | } | 992 | } |
1008 | 993 | ||
@@ -1010,14 +995,14 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w | |||
1010 | u32 pg_consumed_bytes = | 995 | u32 pg_consumed_bytes = |
1011 | min_t(u32, PAGE_SIZE - frag_offset, byte_cnt); | 996 | min_t(u32, PAGE_SIZE - frag_offset, byte_cnt); |
1012 | 997 | ||
1013 | mlx5e_add_skb_frag_mpwqe(rq, skb, wi, page_idx, frag_offset, | 998 | mlx5e_add_skb_frag_mpwqe(rq, skb, di, frag_offset, |
1014 | pg_consumed_bytes); | 999 | pg_consumed_bytes); |
1015 | byte_cnt -= pg_consumed_bytes; | 1000 | byte_cnt -= pg_consumed_bytes; |
1016 | frag_offset = 0; | 1001 | frag_offset = 0; |
1017 | page_idx++; | 1002 | di++; |
1018 | } | 1003 | } |
1019 | /* copy header */ | 1004 | /* copy header */ |
1020 | mlx5e_copy_skb_header_mpwqe(rq->pdev, skb, wi, head_page_idx, | 1005 | mlx5e_copy_skb_header_mpwqe(rq->pdev, skb, head_di, |
1021 | head_offset, headlen); | 1006 | head_offset, headlen); |
1022 | /* skb linear part was allocated with headlen and aligned to long */ | 1007 | /* skb linear part was allocated with headlen and aligned to long */ |
1023 | skb->tail += headlen; | 1008 | skb->tail += headlen; |
@@ -1060,7 +1045,7 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi, | |||
1060 | return NULL; | 1045 | return NULL; |
1061 | 1046 | ||
1062 | /* queue up for recycling/reuse */ | 1047 | /* queue up for recycling/reuse */ |
1063 | wi->skbs_frags[page_idx]++; | 1048 | page_ref_inc(di->page); |
1064 | 1049 | ||
1065 | return skb; | 1050 | return skb; |
1066 | } | 1051 | } |