[PATCH net-next 06/10] net/mlx5e: Add data direct TX infrastructure

From: Tariq Toukan

Date: Thu Oct 08 2026 - 09:31:39 EST


From: Dragos Tatulea <dtatulea@xxxxxxxxxx>

Data direct is a HW feature that allows a type of peer-to-peer DMA
between the NIC and another device (e.g. GPU) going through a specific
PCIe topology.

For data direct to work on the TX path, a crossing mkey is necessary
which is created as a mlx5e resource. This mkey is used by all SQs.
For simplicity always create this resource and link it to the SQ
if data direct is supported.

An SQ state flag is added as well to signal to the TX data path that
data direct is enabled.

This commit has no functional changes. data direct mode will be
enabled in a subsequent commit and mlx5e_queue_get_dma_dev() will then
point to the right device.

Signed-off-by: Dragos Tatulea <dtatulea@xxxxxxxxxx>
Signed-off-by: Tariq Toukan <tariqt@xxxxxxxxxx>
---
drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +
.../mellanox/mlx5/core/en/reporter_tx.c | 1 +
.../ethernet/mellanox/mlx5/core/en_common.c | 38 ++++++++++++++++++-
.../net/ethernet/mellanox/mlx5/core/en_main.c | 6 +++
.../net/ethernet/mellanox/mlx5/core/en_tx.c | 4 +-
include/linux/mlx5/driver.h | 1 +
6 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index d716e70c6d47..23e45e87cdee 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -397,6 +397,7 @@ enum {
MLX5E_SQ_STATE_PENDING_XSK_TX,
MLX5E_SQ_STATE_PENDING_TLS_RX_RESYNC,
MLX5E_SQ_STATE_LOCK_NEEDED,
+ MLX5E_SQ_STATE_DATA_DIRECT, /* set when the sq maps net_iov frags through data direct */
MLX5E_NUM_SQ_STATES, /* Must be kept last */
};

@@ -453,6 +454,7 @@ struct mlx5e_txqsq {
u8 min_inline_mode;
struct device *pdev;
__be32 mkey_be;
+ __be32 crossing_mkey_be;
unsigned long state;
unsigned int hw_mtu;
struct mlx5_clock *clock;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
index 8409ae73768f..b4a4ff877bbc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c
@@ -18,6 +18,7 @@ static const char * const sq_sw_state_type_name[] = {
[MLX5E_SQ_STATE_PENDING_XSK_TX] = "pending_xsk_tx",
[MLX5E_SQ_STATE_PENDING_TLS_RX_RESYNC] = "pending_tls_rx_resync",
[MLX5E_SQ_STATE_LOCK_NEEDED] = "lock_needed",
+ [MLX5E_SQ_STATE_DATA_DIRECT] = "data_direct",
};

static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
index c2d4bae533de..c1d3b2ba1864 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
@@ -30,6 +30,8 @@
* SOFTWARE.
*/

+#include <linux/mlx5/data_direct.h>
+
#include "devlink.h"
#include "en.h"
#include "lib/crypto.h"
@@ -153,6 +155,30 @@ mlx5e_get_devlink_param_num_doorbells(struct mlx5_core_dev *dev)
return err ? MLX5_DEFAULT_NUM_DOORBELLS : val.vu32;
}

+static int mlx5e_create_data_direct_crossing_mkey(struct mlx5_core_dev *mdev)
+{
+ struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
+
+ if (!mdev->data_direct ||
+ !MLX5_CAP_GEN(mdev, crossing_vhca_mkey))
+ return 0;
+
+ return mlx5e_create_crossing_vhca_mkey(mdev, mdev->data_direct->mkey,
+ U64_MAX,
+ &res->data_direct_crossing_mkey);
+}
+
+static void mlx5e_destroy_data_direct_crossing_mkey(struct mlx5_core_dev *mdev)
+{
+ struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
+
+ if (!mdev->data_direct ||
+ !MLX5_CAP_GEN(mdev, crossing_vhca_mkey))
+ return;
+
+ mlx5_core_destroy_mkey(mdev, res->data_direct_crossing_mkey);
+}
+
int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
{
struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
@@ -177,12 +203,19 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
goto err_dealloc_transport_domain;
}

+ err = mlx5e_create_data_direct_crossing_mkey(mdev);
+ if (err) {
+ mlx5_core_err(mdev, "create data direct crossing mkey failed, %d\n",
+ err);
+ goto err_destroy_mkey;
+ }
+
num_doorbells = min(mlx5e_get_devlink_param_num_doorbells(mdev),
mlx5e_get_max_num_channels(mdev));
res->bfregs = kzalloc_objs(*res->bfregs, num_doorbells);
if (!res->bfregs) {
err = -ENOMEM;
- goto err_destroy_mkey;
+ goto err_destroy_crossing_mkey;
}

for (i = 0; i < num_doorbells; i++) {
@@ -221,6 +254,8 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
for (i = 0; i < res->num_bfregs; i++)
mlx5_free_bfreg(mdev, res->bfregs + i);
kfree(res->bfregs);
+err_destroy_crossing_mkey:
+ mlx5e_destroy_data_direct_crossing_mkey(mdev);
err_destroy_mkey:
mlx5_core_destroy_mkey(mdev, res->mkey);
err_dealloc_transport_domain:
@@ -241,6 +276,7 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev)
for (unsigned int i = 0; i < res->num_bfregs; i++)
mlx5_free_bfreg(mdev, res->bfregs + i);
kfree(res->bfregs);
+ mlx5e_destroy_data_direct_crossing_mkey(mdev);
mlx5_core_destroy_mkey(mdev, res->mkey);
mlx5_core_dealloc_transport_domain(mdev, res->td.tdn);
mlx5_core_dealloc_pd(mdev, res->pdn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index e0d46e067c72..d5282a301621 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -1825,6 +1825,12 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
set_bit(MLX5E_SQ_STATE_IPSEC, &sq->state);
if (param->is_mpw)
set_bit(MLX5E_SQ_STATE_MPWQE, &sq->state);
+ if (MLX5E_GET_PFLAG(params, MLX5E_PFLAG_DATA_DIRECT)) {
+ u32 mkey = mdev->mlx5e_res.hw_objs.data_direct_crossing_mkey;
+
+ sq->crossing_mkey_be = cpu_to_be32(mkey);
+ set_bit(MLX5E_SQ_STATE_DATA_DIRECT, &sq->state);
+ }
sq->stop_room = param->stop_room;
sq->ptp_cyc2time = mlx5_sq_ts_translator(mdev);

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index 14479da98f42..62ffb41a64df 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -182,6 +182,7 @@ mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb,
unsigned char *skb_data, u16 headlen,
struct mlx5_wqe_data_seg *dseg)
{
+ bool dd = test_bit(MLX5E_SQ_STATE_DATA_DIRECT, &sq->state);
dma_addr_t dma_addr = 0;
u8 num_dma = 0;
int i;
@@ -211,7 +212,8 @@ mlx5e_txwqe_build_dsegs(struct mlx5e_txqsq *sq, struct sk_buff *skb,
goto dma_unmap_wqe_err;

dseg->addr = cpu_to_be64(dma_addr);
- dseg->lkey = sq->mkey_be;
+ dseg->lkey = dd && skb_frag_is_net_iov(frag) ?
+ sq->crossing_mkey_be : sq->mkey_be;
dseg->byte_count = cpu_to_be32(fsz);

mlx5e_dma_push_netmem(sq, skb_frag_netmem(frag), dma_addr, fsz);
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index abb99371ff13..4c8b447337f1 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -678,6 +678,7 @@ struct mlx5e_resources {
u32 pdn;
struct mlx5_td td;
u32 mkey;
+ u32 data_direct_crossing_mkey;
struct mlx5_sq_bfreg *bfregs;
unsigned int num_bfregs;
#define MLX5_MAX_NUM_TC 8
--
2.44.0