octeontx2-pf: Add support for page pool

Page pool for each rx queue enhance rx side performance
by reclaiming buffers back to each queue specific pool. DMA
mapping is done only for first allocation of buffers.
As subsequent buffers allocation avoid DMA mapping,
it results in performance improvement.

Image        |  Performance
------------ | ------------
Vannila      |   3Mpps
             |
with this    |   42Mpps
change	     |
---------------------------

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Link: https://lore.kernel.org/r/20230522020404.152020-1-rkannoth@marvell.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Ratheesh Kannoth 2023-05-22 07:34:04 +05:30 committed by Paolo Abeni
parent 62a41dc716
commit b2e3406a38
7 changed files with 96 additions and 22 deletions

View File

@ -32,6 +32,7 @@ config OCTEONTX2_PF
tristate "Marvell OcteonTX2 NIC Physical Function driver" tristate "Marvell OcteonTX2 NIC Physical Function driver"
select OCTEONTX2_MBOX select OCTEONTX2_MBOX
select NET_DEVLINK select NET_DEVLINK
select PAGE_POOL
depends on (64BIT && COMPILE_TEST) || ARM64 depends on (64BIT && COMPILE_TEST) || ARM64
select DIMLIB select DIMLIB
depends on PCI depends on PCI

View File

@ -518,11 +518,32 @@ void otx2_config_irq_coalescing(struct otx2_nic *pfvf, int qidx)
(pfvf->hw.cq_ecount_wait - 1)); (pfvf->hw.cq_ecount_wait - 1));
} }
static int otx2_alloc_pool_buf(struct otx2_nic *pfvf, struct otx2_pool *pool,
dma_addr_t *dma)
{
unsigned int offset = 0;
struct page *page;
size_t sz;
sz = SKB_DATA_ALIGN(pool->rbsize);
sz = ALIGN(sz, OTX2_ALIGN);
page = page_pool_alloc_frag(pool->page_pool, &offset, sz, GFP_ATOMIC);
if (unlikely(!page))
return -ENOMEM;
*dma = page_pool_get_dma_addr(page) + offset;
return 0;
}
static int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, static int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool,
dma_addr_t *dma) dma_addr_t *dma)
{ {
u8 *buf; u8 *buf;
if (pool->page_pool)
return otx2_alloc_pool_buf(pfvf, pool, dma);
buf = napi_alloc_frag_align(pool->rbsize, OTX2_ALIGN); buf = napi_alloc_frag_align(pool->rbsize, OTX2_ALIGN);
if (unlikely(!buf)) if (unlikely(!buf))
return -ENOMEM; return -ENOMEM;
@ -1205,10 +1226,31 @@ void otx2_sq_free_sqbs(struct otx2_nic *pfvf)
} }
} }
void otx2_free_bufs(struct otx2_nic *pfvf, struct otx2_pool *pool,
u64 iova, int size)
{
struct page *page;
u64 pa;
pa = otx2_iova_to_phys(pfvf->iommu_domain, iova);
page = virt_to_head_page(phys_to_virt(pa));
if (pool->page_pool) {
page_pool_put_full_page(pool->page_pool, page, true);
} else {
dma_unmap_page_attrs(pfvf->dev, iova, size,
DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
put_page(page);
}
}
void otx2_free_aura_ptr(struct otx2_nic *pfvf, int type) void otx2_free_aura_ptr(struct otx2_nic *pfvf, int type)
{ {
int pool_id, pool_start = 0, pool_end = 0, size = 0; int pool_id, pool_start = 0, pool_end = 0, size = 0;
u64 iova, pa; struct otx2_pool *pool;
u64 iova;
if (type == AURA_NIX_SQ) { if (type == AURA_NIX_SQ) {
pool_start = otx2_get_pool_idx(pfvf, type, 0); pool_start = otx2_get_pool_idx(pfvf, type, 0);
@ -1224,15 +1266,13 @@ void otx2_free_aura_ptr(struct otx2_nic *pfvf, int type)
/* Free SQB and RQB pointers from the aura pool */ /* Free SQB and RQB pointers from the aura pool */
for (pool_id = pool_start; pool_id < pool_end; pool_id++) { for (pool_id = pool_start; pool_id < pool_end; pool_id++) {
iova = otx2_aura_allocptr(pfvf, pool_id); iova = otx2_aura_allocptr(pfvf, pool_id);
pool = &pfvf->qset.pool[pool_id];
while (iova) { while (iova) {
if (type == AURA_NIX_RQ) if (type == AURA_NIX_RQ)
iova -= OTX2_HEAD_ROOM; iova -= OTX2_HEAD_ROOM;
pa = otx2_iova_to_phys(pfvf->iommu_domain, iova); otx2_free_bufs(pfvf, pool, iova, size);
dma_unmap_page_attrs(pfvf->dev, iova, size,
DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
put_page(virt_to_page(phys_to_virt(pa)));
iova = otx2_aura_allocptr(pfvf, pool_id); iova = otx2_aura_allocptr(pfvf, pool_id);
} }
} }
@ -1250,6 +1290,8 @@ void otx2_aura_pool_free(struct otx2_nic *pfvf)
pool = &pfvf->qset.pool[pool_id]; pool = &pfvf->qset.pool[pool_id];
qmem_free(pfvf->dev, pool->stack); qmem_free(pfvf->dev, pool->stack);
qmem_free(pfvf->dev, pool->fc_addr); qmem_free(pfvf->dev, pool->fc_addr);
page_pool_destroy(pool->page_pool);
pool->page_pool = NULL;
} }
devm_kfree(pfvf->dev, pfvf->qset.pool); devm_kfree(pfvf->dev, pfvf->qset.pool);
pfvf->qset.pool = NULL; pfvf->qset.pool = NULL;
@ -1333,8 +1375,9 @@ int otx2_aura_init(struct otx2_nic *pfvf, int aura_id,
} }
int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id,
int stack_pages, int numptrs, int buf_size) int stack_pages, int numptrs, int buf_size, int type)
{ {
struct page_pool_params pp_params = { 0 };
struct npa_aq_enq_req *aq; struct npa_aq_enq_req *aq;
struct otx2_pool *pool; struct otx2_pool *pool;
int err; int err;
@ -1378,6 +1421,22 @@ int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id,
aq->ctype = NPA_AQ_CTYPE_POOL; aq->ctype = NPA_AQ_CTYPE_POOL;
aq->op = NPA_AQ_INSTOP_INIT; aq->op = NPA_AQ_INSTOP_INIT;
if (type != AURA_NIX_RQ) {
pool->page_pool = NULL;
return 0;
}
pp_params.flags = PP_FLAG_PAGE_FRAG | PP_FLAG_DMA_MAP;
pp_params.pool_size = numptrs;
pp_params.nid = NUMA_NO_NODE;
pp_params.dev = pfvf->dev;
pp_params.dma_dir = DMA_FROM_DEVICE;
pool->page_pool = page_pool_create(&pp_params);
if (IS_ERR(pool->page_pool)) {
netdev_err(pfvf->netdev, "Creation of page pool failed\n");
return PTR_ERR(pool->page_pool);
}
return 0; return 0;
} }
@ -1412,7 +1471,7 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf)
/* Initialize pool context */ /* Initialize pool context */
err = otx2_pool_init(pfvf, pool_id, stack_pages, err = otx2_pool_init(pfvf, pool_id, stack_pages,
num_sqbs, hw->sqb_size); num_sqbs, hw->sqb_size, AURA_NIX_SQ);
if (err) if (err)
goto fail; goto fail;
} }
@ -1475,7 +1534,7 @@ int otx2_rq_aura_pool_init(struct otx2_nic *pfvf)
} }
for (pool_id = 0; pool_id < hw->rqpool_cnt; pool_id++) { for (pool_id = 0; pool_id < hw->rqpool_cnt; pool_id++) {
err = otx2_pool_init(pfvf, pool_id, stack_pages, err = otx2_pool_init(pfvf, pool_id, stack_pages,
num_ptrs, pfvf->rbsize); num_ptrs, pfvf->rbsize, AURA_NIX_RQ);
if (err) if (err)
goto fail; goto fail;
} }
@ -1659,7 +1718,6 @@ int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable)
req->bpid_per_chan = 0; req->bpid_per_chan = 0;
#endif #endif
return otx2_sync_mbox_msg(&pfvf->mbox); return otx2_sync_mbox_msg(&pfvf->mbox);
} }
EXPORT_SYMBOL(otx2_nix_config_bp); EXPORT_SYMBOL(otx2_nix_config_bp);

View File

@ -976,7 +976,7 @@ int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool,
int otx2_rxtx_enable(struct otx2_nic *pfvf, bool enable); int otx2_rxtx_enable(struct otx2_nic *pfvf, bool enable);
void otx2_ctx_disable(struct mbox *mbox, int type, bool npa); void otx2_ctx_disable(struct mbox *mbox, int type, bool npa);
int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable); int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable);
void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq); void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, int qidx);
void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq); void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq);
int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura); int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura);
int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura);
@ -984,7 +984,7 @@ int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura);
int otx2_alloc_buffer(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, int otx2_alloc_buffer(struct otx2_nic *pfvf, struct otx2_cq_queue *cq,
dma_addr_t *dma); dma_addr_t *dma);
int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id,
int stack_pages, int numptrs, int buf_size); int stack_pages, int numptrs, int buf_size, int type);
int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, int otx2_aura_init(struct otx2_nic *pfvf, int aura_id,
int pool_id, int numptrs); int pool_id, int numptrs);
@ -1054,6 +1054,8 @@ u16 otx2_get_max_mtu(struct otx2_nic *pfvf);
int otx2_handle_ntuple_tc_features(struct net_device *netdev, int otx2_handle_ntuple_tc_features(struct net_device *netdev,
netdev_features_t features); netdev_features_t features);
int otx2_smq_flush(struct otx2_nic *pfvf, int smq); int otx2_smq_flush(struct otx2_nic *pfvf, int smq);
void otx2_free_bufs(struct otx2_nic *pfvf, struct otx2_pool *pool,
u64 iova, int size);
/* tc support */ /* tc support */
int otx2_init_tc(struct otx2_nic *nic); int otx2_init_tc(struct otx2_nic *nic);

View File

@ -1555,7 +1555,9 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
struct nix_lf_free_req *free_req; struct nix_lf_free_req *free_req;
struct mbox *mbox = &pf->mbox; struct mbox *mbox = &pf->mbox;
struct otx2_cq_queue *cq; struct otx2_cq_queue *cq;
struct otx2_pool *pool;
struct msg_req *req; struct msg_req *req;
int pool_id;
int qidx; int qidx;
/* Ensure all SQE are processed */ /* Ensure all SQE are processed */
@ -1584,7 +1586,7 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
for (qidx = 0; qidx < qset->cq_cnt; qidx++) { for (qidx = 0; qidx < qset->cq_cnt; qidx++) {
cq = &qset->cq[qidx]; cq = &qset->cq[qidx];
if (cq->cq_type == CQ_RX) if (cq->cq_type == CQ_RX)
otx2_cleanup_rx_cqes(pf, cq); otx2_cleanup_rx_cqes(pf, cq, qidx);
else else
otx2_cleanup_tx_cqes(pf, cq); otx2_cleanup_tx_cqes(pf, cq);
} }
@ -1594,6 +1596,13 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
/* Free RQ buffer pointers*/ /* Free RQ buffer pointers*/
otx2_free_aura_ptr(pf, AURA_NIX_RQ); otx2_free_aura_ptr(pf, AURA_NIX_RQ);
for (qidx = 0; qidx < pf->hw.rx_queues; qidx++) {
pool_id = otx2_get_pool_idx(pf, AURA_NIX_RQ, qidx);
pool = &pf->qset.pool[pool_id];
page_pool_destroy(pool->page_pool);
pool->page_pool = NULL;
}
otx2_free_cq_res(pf); otx2_free_cq_res(pf);
/* Free all ingress bandwidth profiles allocated */ /* Free all ingress bandwidth profiles allocated */

View File

@ -217,9 +217,6 @@ static bool otx2_skb_add_frag(struct otx2_nic *pfvf, struct sk_buff *skb,
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
va - page_address(page) + off, va - page_address(page) + off,
len - off, pfvf->rbsize); len - off, pfvf->rbsize);
otx2_dma_unmap_page(pfvf, iova - OTX2_HEAD_ROOM,
pfvf->rbsize, DMA_FROM_DEVICE);
return true; return true;
} }
@ -382,6 +379,8 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf,
if (pfvf->netdev->features & NETIF_F_RXCSUM) if (pfvf->netdev->features & NETIF_F_RXCSUM)
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_mark_for_recycle(skb);
napi_gro_frags(napi); napi_gro_frags(napi);
} }
@ -1186,11 +1185,13 @@ bool otx2_sq_append_skb(struct net_device *netdev, struct otx2_snd_queue *sq,
} }
EXPORT_SYMBOL(otx2_sq_append_skb); EXPORT_SYMBOL(otx2_sq_append_skb);
void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq) void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, int qidx)
{ {
struct nix_cqe_rx_s *cqe; struct nix_cqe_rx_s *cqe;
struct otx2_pool *pool;
int processed_cqe = 0; int processed_cqe = 0;
u64 iova, pa; u16 pool_id;
u64 iova;
if (pfvf->xdp_prog) if (pfvf->xdp_prog)
xdp_rxq_info_unreg(&cq->xdp_rxq); xdp_rxq_info_unreg(&cq->xdp_rxq);
@ -1198,6 +1199,9 @@ void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq)
if (otx2_nix_cq_op_status(pfvf, cq) || !cq->pend_cqe) if (otx2_nix_cq_op_status(pfvf, cq) || !cq->pend_cqe)
return; return;
pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_RQ, qidx);
pool = &pfvf->qset.pool[pool_id];
while (cq->pend_cqe) { while (cq->pend_cqe) {
cqe = (struct nix_cqe_rx_s *)otx2_get_next_cqe(cq); cqe = (struct nix_cqe_rx_s *)otx2_get_next_cqe(cq);
processed_cqe++; processed_cqe++;
@ -1210,9 +1214,8 @@ void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq)
continue; continue;
} }
iova = cqe->sg.seg_addr - OTX2_HEAD_ROOM; iova = cqe->sg.seg_addr - OTX2_HEAD_ROOM;
pa = otx2_iova_to_phys(pfvf->iommu_domain, iova);
otx2_dma_unmap_page(pfvf, iova, pfvf->rbsize, DMA_FROM_DEVICE); otx2_free_bufs(pfvf, pool, iova, pfvf->rbsize);
put_page(virt_to_page(phys_to_virt(pa)));
} }
/* Free CQEs to HW */ /* Free CQEs to HW */

View File

@ -118,6 +118,7 @@ struct otx2_cq_poll {
struct otx2_pool { struct otx2_pool {
struct qmem *stack; struct qmem *stack;
struct qmem *fc_addr; struct qmem *fc_addr;
struct page_pool *page_pool;
u16 rbsize; u16 rbsize;
}; };

View File

@ -63,7 +63,7 @@ static int otx2_qos_sq_aura_pool_init(struct otx2_nic *pfvf, int qidx)
/* Initialize pool context */ /* Initialize pool context */
err = otx2_pool_init(pfvf, pool_id, stack_pages, err = otx2_pool_init(pfvf, pool_id, stack_pages,
num_sqbs, hw->sqb_size); num_sqbs, hw->sqb_size, AURA_NIX_SQ);
if (err) if (err)
goto aura_free; goto aura_free;