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:55:48 EST
On 14.10.26 19:22, Dragos Tatulea wrote:
>
>
> 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?
>
The patch was actually using the coherent buffer. My bad, sorry.
>> 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?
I meant to say headers and small packets.
>
> 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