Skip to content

Commit b5b60bb

Browse files
Amit Cohenkuba-moo
Amit Cohen
authored andcommitted
mlxsw: pci: Use page pool for Rx buffers allocation
As part of driver init, all Rx queues are filled with buffers for hardware usage. Later, when a packet is received, a new buffer should be allocated to be used by hardware instead of the received buffer. Packet's processing time includes allocation time, which can be improved using page pool. Using page pool, DMA mapping is done only for first allocation of buffers. As subsequent buffers allocation avoid DMA mapping, it results in performance improvement. The purpose of page pool is to allocate pages fast from cache without locking. This lockless guarantee naturally comes from running under a NAPI. Use page pool to allocate the data buffer only, so hardware will use it to fill the packet. At completion time, attach the data buffer (now filled with packet payload) to new SKB which is allocated around the received buffer. SKB building at completion time prevents cache miss for each packet, as now the SKB is allocated right before packets will be handled by networking stack. Page pool for each Rx queue enhances Rx side performance by reclaiming buffers back to each queue specific pool. This change significantly improves driver performance, CPU can handle about 345% of the packets per second it previously handled. Signed-off-by: Amit Cohen <[email protected]> Reviewed-by: Petr Machata <[email protected]> Reviewed-by: Ido Schimmel <[email protected]> Signed-off-by: Petr Machata <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Link: https://lore.kernel.org/r/1cf788a8f43c70aae6d526018ef77becb27ad6d3.1718709196.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 5642c6a commit b5b60bb

File tree

1 file changed

+64
-39
lines changed
  • drivers/net/ethernet/mellanox/mlxsw

1 file changed

+64
-39
lines changed

drivers/net/ethernet/mellanox/mlxsw/pci.c

+64-39
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct mlxsw_pci_mem_item {
6262
};
6363

6464
struct mlxsw_pci_queue_elem_info {
65+
struct page *page;
6566
char *elem; /* pointer to actual dma mapped element mem chunk */
6667
union {
6768
struct {
@@ -346,6 +347,19 @@ static void mlxsw_pci_sdq_fini(struct mlxsw_pci *mlxsw_pci,
346347
(MLXSW_PCI_SKB_HEADROOM + \
347348
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
348349

350+
static void
351+
mlxsw_pci_wqe_rx_frag_set(struct mlxsw_pci *mlxsw_pci, struct page *page,
352+
char *wqe, int index, size_t frag_len)
353+
{
354+
dma_addr_t mapaddr;
355+
356+
mapaddr = page_pool_get_dma_addr(page);
357+
mapaddr += MLXSW_PCI_SKB_HEADROOM;
358+
359+
mlxsw_pci_wqe_address_set(wqe, index, mapaddr);
360+
mlxsw_pci_wqe_byte_count_set(wqe, index, frag_len);
361+
}
362+
349363
static int mlxsw_pci_wqe_frag_map(struct mlxsw_pci *mlxsw_pci, char *wqe,
350364
int index, char *frag_data, size_t frag_len,
351365
int direction)
@@ -375,43 +389,46 @@ static void mlxsw_pci_wqe_frag_unmap(struct mlxsw_pci *mlxsw_pci, char *wqe,
375389
dma_unmap_single(&pdev->dev, mapaddr, frag_len, direction);
376390
}
377391

378-
static int mlxsw_pci_rdq_skb_alloc(struct mlxsw_pci *mlxsw_pci,
379-
struct mlxsw_pci_queue_elem_info *elem_info,
380-
gfp_t gfp)
392+
static struct sk_buff *mlxsw_pci_rdq_build_skb(struct page *page,
393+
u16 byte_count)
394+
{
395+
void *data = page_address(page);
396+
unsigned int allocated_size;
397+
struct sk_buff *skb;
398+
399+
allocated_size = page_size(page);
400+
skb = napi_build_skb(data, allocated_size);
401+
if (unlikely(!skb))
402+
return ERR_PTR(-ENOMEM);
403+
404+
skb_reserve(skb, MLXSW_PCI_SKB_HEADROOM);
405+
skb_put(skb, byte_count);
406+
return skb;
407+
}
408+
409+
static int mlxsw_pci_rdq_page_alloc(struct mlxsw_pci_queue *q,
410+
struct mlxsw_pci_queue_elem_info *elem_info)
381411
{
412+
struct mlxsw_pci_queue *cq = q->u.rdq.cq;
382413
size_t buf_len = MLXSW_PORT_MAX_MTU;
383414
char *wqe = elem_info->elem;
384-
struct sk_buff *skb;
385-
int err;
415+
struct page *page;
386416

387-
skb = __netdev_alloc_skb_ip_align(NULL, buf_len, gfp);
388-
if (!skb)
417+
page = page_pool_dev_alloc_pages(cq->u.cq.page_pool);
418+
if (unlikely(!page))
389419
return -ENOMEM;
390420

391-
err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data,
392-
buf_len, DMA_FROM_DEVICE);
393-
if (err)
394-
goto err_frag_map;
395-
396-
elem_info->u.rdq.skb = skb;
421+
mlxsw_pci_wqe_rx_frag_set(q->pci, page, wqe, 0, buf_len);
422+
elem_info->page = page;
397423
return 0;
398-
399-
err_frag_map:
400-
dev_kfree_skb_any(skb);
401-
return err;
402424
}
403425

404-
static void mlxsw_pci_rdq_skb_free(struct mlxsw_pci *mlxsw_pci,
405-
struct mlxsw_pci_queue_elem_info *elem_info)
426+
static void mlxsw_pci_rdq_page_free(struct mlxsw_pci_queue *q,
427+
struct mlxsw_pci_queue_elem_info *elem_info)
406428
{
407-
struct sk_buff *skb;
408-
char *wqe;
429+
struct mlxsw_pci_queue *cq = q->u.rdq.cq;
409430

410-
skb = elem_info->u.rdq.skb;
411-
wqe = elem_info->elem;
412-
413-
mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE);
414-
dev_kfree_skb_any(skb);
431+
page_pool_put_page(cq->u.cq.page_pool, elem_info->page, -1, false);
415432
}
416433

417434
static int mlxsw_pci_rdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
@@ -452,7 +469,7 @@ static int mlxsw_pci_rdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
452469
for (i = 0; i < q->count; i++) {
453470
elem_info = mlxsw_pci_queue_elem_info_producer_get(q);
454471
BUG_ON(!elem_info);
455-
err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info, GFP_KERNEL);
472+
err = mlxsw_pci_rdq_page_alloc(q, elem_info);
456473
if (err)
457474
goto rollback;
458475
/* Everything is set up, ring doorbell to pass elem to HW */
@@ -465,7 +482,7 @@ static int mlxsw_pci_rdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
465482
rollback:
466483
for (i--; i >= 0; i--) {
467484
elem_info = mlxsw_pci_queue_elem_info_get(q, i);
468-
mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info);
485+
mlxsw_pci_rdq_page_free(q, elem_info);
469486
}
470487
q->u.rdq.cq = NULL;
471488
cq->u.cq.dq = NULL;
@@ -483,7 +500,7 @@ static void mlxsw_pci_rdq_fini(struct mlxsw_pci *mlxsw_pci,
483500
mlxsw_cmd_hw2sw_rdq(mlxsw_pci->core, q->num);
484501
for (i = 0; i < q->count; i++) {
485502
elem_info = mlxsw_pci_queue_elem_info_get(q, i);
486-
mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info);
503+
mlxsw_pci_rdq_page_free(q, elem_info);
487504
}
488505
}
489506

@@ -618,26 +635,38 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci,
618635
{
619636
struct pci_dev *pdev = mlxsw_pci->pdev;
620637
struct mlxsw_pci_queue_elem_info *elem_info;
638+
struct mlxsw_pci_queue *cq = q->u.rdq.cq;
621639
struct mlxsw_rx_info rx_info = {};
622-
char wqe[MLXSW_PCI_WQE_SIZE];
623640
struct sk_buff *skb;
641+
struct page *page;
624642
u16 byte_count;
625643
int err;
626644

627645
elem_info = mlxsw_pci_queue_elem_info_consumer_get(q);
628-
skb = elem_info->u.rdq.skb;
629-
memcpy(wqe, elem_info->elem, MLXSW_PCI_WQE_SIZE);
630646

631647
if (q->consumer_counter++ != consumer_counter_limit)
632648
dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in RDQ\n");
633649

634-
err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info, GFP_ATOMIC);
650+
byte_count = mlxsw_pci_cqe_byte_count_get(cqe);
651+
if (mlxsw_pci_cqe_crc_get(cqe_v, cqe))
652+
byte_count -= ETH_FCS_LEN;
653+
654+
page = elem_info->page;
655+
656+
err = mlxsw_pci_rdq_page_alloc(q, elem_info);
635657
if (err) {
636-
dev_err_ratelimited(&pdev->dev, "Failed to alloc skb for RDQ\n");
658+
dev_err_ratelimited(&pdev->dev, "Failed to alloc page\n");
659+
goto out;
660+
}
661+
662+
skb = mlxsw_pci_rdq_build_skb(page, byte_count);
663+
if (IS_ERR(skb)) {
664+
dev_err_ratelimited(&pdev->dev, "Failed to build skb for RDQ\n");
665+
page_pool_recycle_direct(cq->u.cq.page_pool, page);
637666
goto out;
638667
}
639668

640-
mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE);
669+
skb_mark_for_recycle(skb);
641670

642671
if (mlxsw_pci_cqe_lag_get(cqe_v, cqe)) {
643672
rx_info.is_lag = true;
@@ -670,10 +699,6 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci,
670699

671700
mlxsw_pci_skb_cb_ts_set(mlxsw_pci, skb, cqe_v, cqe);
672701

673-
byte_count = mlxsw_pci_cqe_byte_count_get(cqe);
674-
if (mlxsw_pci_cqe_crc_get(cqe_v, cqe))
675-
byte_count -= ETH_FCS_LEN;
676-
skb_put(skb, byte_count);
677702
mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info);
678703

679704
out:

0 commit comments

Comments
 (0)