[RFC: DMA_PMD 19/22] net/mlx5e: Use DMA_PMD memory for tx header bounce buffers

From: Luigi Rizzo

Date: Sat Oct 03 2026 - 17:32:38 EST


When dev->dma_pmd_tx_hdrs is enabled, allocate a MAX_TCP_HEADER
bounce buffer per TX DMA FIFO slot out of the DMA_PMD arena. When the
linear portion of a transmitted packet is at most MAX_TCP_HEADER bytes,
copy it into the pre-mapped bounce buffer instead of calling
dma_map_single()/dma_unmap_single() on every packet.

Signed-off-by: Luigi Rizzo <lrizzo@xxxxxxxxxx>
---
drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 ++
.../net/ethernet/mellanox/mlx5/core/en/txrx.h | 4 ++-
.../net/ethernet/mellanox/mlx5/core/en_main.c | 14 ++++++++++
.../net/ethernet/mellanox/mlx5/core/en_tx.c | 28 +++++++++++++++----
4 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index a3945195f454e..d762ad1c1ffaf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -442,6 +442,8 @@ struct mlx5e_txqsq {
struct mlx5e_sq_dma *dma_fifo;
struct mlx5e_skb_fifo skb_fifo;
struct mlx5e_tx_wqe_info *wqe_info;
+ void *tx_hdr_bufs;
+ dma_addr_t tx_hdr_bufs_dma;
} db;
void __iomem *uar_map;
struct netdev_queue *txq;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
index f2a8453d8dce0..6de7a2a430d72 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
@@ -365,7 +365,9 @@ mlx5e_tx_dma_unmap(struct device *pdev, struct mlx5e_sq_dma *dma)
{
switch (dma->type) {
case MLX5E_DMA_MAP_SINGLE:
- dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
+ if (dma->size)
+ dma_unmap_single(pdev, dma->addr, dma->size,
+ DMA_TO_DEVICE);
break;
case MLX5E_DMA_MAP_PAGE:
netmem_dma_unmap_page_attrs(pdev, dma->addr, dma->size,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 4c6060d54fbed..efd766aa43a02 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -1666,6 +1666,13 @@ static void mlx5e_free_icosq(struct mlx5e_icosq *sq)

void mlx5e_free_txqsq_db(struct mlx5e_txqsq *sq)
{
+ if (sq->db.tx_hdr_bufs) {
+ int wq_sz = mlx5_wq_cyc_get_size(&sq->wq);
+ int df_sz = wq_sz * MLX5_SEND_WQEBB_NUM_DS;
+
+ dma_free_coherent(sq->pdev, df_sz * MAX_TCP_HEADER,
+ sq->db.tx_hdr_bufs, sq->db.tx_hdr_bufs_dma);
+ }
kvfree(sq->db.wqe_info);
kvfree(sq->db.skb_fifo.fifo);
kvfree(sq->db.dma_fifo);
@@ -1690,6 +1697,13 @@ int mlx5e_alloc_txqsq_db(struct mlx5e_txqsq *sq, int numa)
return -ENOMEM;
}

+ if (sq->pdev->dma_pmd_tx_hdrs)
+ sq->db.tx_hdr_bufs =
+ dma_alloc_coherent(sq->pdev,
+ df_sz * MAX_TCP_HEADER,
+ &sq->db.tx_hdr_bufs_dma,
+ GFP_KERNEL | __GFP_NOWARN);
+
sq->dma_fifo_mask = df_sz - 1;

sq->db.skb_fifo.pc = &sq->skb_fifo_pc;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index 0b5e600e4a6a9..3b6a7a8b0128e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -177,6 +177,27 @@ mlx5e_tx_get_gso_ihs(struct mlx5e_txqsq *sq, struct sk_buff *skb)
return ihs;
}

+static inline dma_addr_t
+mlx5e_tx_map_hdr(struct mlx5e_txqsq *sq, unsigned char *data, u32 len)
+{
+ dma_addr_t dma_addr;
+
+ if (sq->db.tx_hdr_bufs && len <= MAX_TCP_HEADER) {
+ u32 off = (sq->dma_fifo_pc & sq->dma_fifo_mask) *
+ MAX_TCP_HEADER;
+
+ memcpy(sq->db.tx_hdr_bufs + off, data, len);
+ dma_addr = sq->db.tx_hdr_bufs_dma + off;
+ mlx5e_dma_push_single(sq, dma_addr, 0);
+ return dma_addr;
+ }
+
+ dma_addr = dma_map_single(sq->pdev, data, len, DMA_TO_DEVICE);
+ if (likely(!dma_mapping_error(sq->pdev, dma_addr)))
+ mlx5e_dma_push_single(sq, dma_addr, len);
+ return dma_addr;
+}
+
static inline int
mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb,
unsigned char *skb_data, u16 headlen,
@@ -187,8 +208,7 @@ mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb,
int i;

if (headlen) {
- dma_addr = dma_map_single(sq->pdev, skb_data, headlen,
- DMA_TO_DEVICE);
+ dma_addr = mlx5e_tx_map_hdr(sq, skb_data, headlen);
if (unlikely(dma_mapping_error(sq->pdev, dma_addr)))
goto dma_unmap_wqe_err;

@@ -196,7 +216,6 @@ mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb,
dseg->lkey = sq->mkey_be;
dseg->byte_count = cpu_to_be32(headlen);

- mlx5e_dma_push_single(sq, dma_addr, headlen);
num_dma++;
dseg++;
}
@@ -578,7 +597,7 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
txd.data = skb->data;
txd.len = skb->len;

- txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
+ txd.dma_addr = mlx5e_tx_map_hdr(sq, txd.data, txd.len);
if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
goto err_unmap;

@@ -591,7 +610,6 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,

sq->stats->xmit_more += xmit_more;

- mlx5e_dma_push_single(sq, txd.dma_addr, txd.len);
mlx5e_skb_fifo_push(&sq->db.skb_fifo, skb);
mlx5e_tx_mpwqe_add_dseg(sq, &txd);
mlx5e_tx_skb_update_ts_flags(skb);
--
2.56.0.rc1.315.gc6ed9934b7-goog