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

From: Dragos Tatulea

Date: Wed Oct 14 2026 - 13:26:06 EST




On 03.10.26 23:22, Luigi Rizzo wrote:
> 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.
>
What is the difference between using the DMA_PMD pool or one (or a few)
coherent DMA (2MB) buffers allocated by the driver?

> 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;
Why are only headers considered for bouncing? Because they have the
highest mapping overhead?

Note that TSO/GSO packets will copy the header inline in the WQE
already. But not for small packets.

> } 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;
> +}
> +
This looks like a form of tx-copybreak.

Thanks,
Dragos