diff mbox series

[rdma-core,6/6] mlx5: Introduce a new send API in direct verbs

Message ID 1552911859-4073-7-git-send-email-yishaih@mellanox.com (mailing list archive)
State Not Applicable
Headers show
Series verbs: Introduce a new post send API | expand

Commit Message

Yishai Hadas March 18, 2019, 12:24 p.m. UTC
From: Guy Levi <guyle@mellanox.com>

A new send API was introduced by libibverbs. This is a mlx5 specific API
extension to the generic one which is introduced in DV. By calling
mlx5dv_create_qp with the generic attr, send_ops_flags, mlx5 specific
send work features can be used. The new struct, mlx5dv_qp_ex, is used
to access mlx5 specific send work micro-functions.

Till now, the driver let to create a QP with DC transport type w/o a
data-path support (Users had to implement data-path by themselves). Now,
we introduce a DC support over DV new post send API which is actually a
complete DC data-path support (Post a send WR, post a receive WR and poll
a WC).

Signed-off-by: Guy Levi <guyle@mellanox.com>
Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
---
 debian/ibverbs-providers.symbols         |   2 +
 providers/mlx5/CMakeLists.txt            |   2 +-
 providers/mlx5/libmlx5.map               |   6 ++
 providers/mlx5/man/CMakeLists.txt        |   3 +
 providers/mlx5/man/mlx5dv_create_qp.3.md |   5 ++
 providers/mlx5/man/mlx5dv_wr_post.3.md   |  94 ++++++++++++++++++++++++++
 providers/mlx5/mlx5.h                    |   9 ++-
 providers/mlx5/mlx5dv.h                  |  20 ++++++
 providers/mlx5/qp.c                      | 112 ++++++++++++++++++++++---------
 providers/mlx5/verbs.c                   |  17 ++++-
 10 files changed, 236 insertions(+), 34 deletions(-)
 create mode 100644 providers/mlx5/man/mlx5dv_wr_post.3.md
diff mbox series

Patch

diff --git a/debian/ibverbs-providers.symbols b/debian/ibverbs-providers.symbols
index 9be0a94..309bbef 100644
--- a/debian/ibverbs-providers.symbols
+++ b/debian/ibverbs-providers.symbols
@@ -17,6 +17,7 @@  libmlx5.so.1 ibverbs-providers #MINVER#
  MLX5_1.7@MLX5_1.7 21
  MLX5_1.8@MLX5_1.8 22
  MLX5_1.9@MLX5_1.9 23
+ MLX5_1.10@MLX5_1.10 24
  mlx5dv_init_obj@MLX5_1.0 13
  mlx5dv_init_obj@MLX5_1.2 15
  mlx5dv_query_device@MLX5_1.0 13
@@ -57,3 +58,4 @@  libmlx5.so.1 ibverbs-providers #MINVER#
  mlx5dv_devx_destroy_cmd_comp@MLX5_1.9 23
  mlx5dv_devx_get_async_cmd_comp@MLX5_1.9 23
  mlx5dv_devx_obj_query_async@MLX5_1.9 23
+ mlx5dv_qp_ex_from_ibv_qp_ex@MLX5_1.10 24
diff --git a/providers/mlx5/CMakeLists.txt b/providers/mlx5/CMakeLists.txt
index d629c58..88b1246 100644
--- a/providers/mlx5/CMakeLists.txt
+++ b/providers/mlx5/CMakeLists.txt
@@ -11,7 +11,7 @@  if (MLX5_MW_DEBUG)
 endif()
 
 rdma_shared_provider(mlx5 libmlx5.map
-  1 1.9.${PACKAGE_VERSION}
+  1 1.10.${PACKAGE_VERSION}
   buf.c
   cq.c
   dbrec.c
diff --git a/providers/mlx5/libmlx5.map b/providers/mlx5/libmlx5.map
index be99767..28c8616 100644
--- a/providers/mlx5/libmlx5.map
+++ b/providers/mlx5/libmlx5.map
@@ -79,4 +79,10 @@  MLX5_1.9 {
 		mlx5dv_devx_destroy_cmd_comp;
 		mlx5dv_devx_get_async_cmd_comp;
 		mlx5dv_devx_obj_query_async;
+		mlx5dv_qp_ex_from_ibv_qp_ex;
 } MLX5_1.8;
+
+MLX5_1.10 {
+	global:
+		mlx5dv_qp_ex_from_ibv_qp_ex;
+} MLX5_1.9;
diff --git a/providers/mlx5/man/CMakeLists.txt b/providers/mlx5/man/CMakeLists.txt
index d8d42c3..24bd5d8 100644
--- a/providers/mlx5/man/CMakeLists.txt
+++ b/providers/mlx5/man/CMakeLists.txt
@@ -18,6 +18,7 @@  rdma_man_pages(
   mlx5dv_open_device.3.md
   mlx5dv_query_device.3
   mlx5dv_ts_to_ns.3
+  mlx5dv_wr_post.3.md
   mlx5dv.7
 )
 rdma_alias_man_pages(
@@ -39,4 +40,6 @@  rdma_alias_man_pages(
  mlx5dv_devx_qp_modify.3 mlx5dv_devx_ind_tbl_modify.3
  mlx5dv_devx_qp_modify.3 mlx5dv_devx_ind_tbl_query.3
  mlx5dv_devx_umem_reg.3 mlx5dv_devx_umem_dereg.3
+ mlx5dv_wr_post.3 mlx5dv_wr_set_dc_addr.3
+ mlx5dv_wr_post.3 mlx5dv_qp_ex_from_ibv_qp_ex.3
 )
diff --git a/providers/mlx5/man/mlx5dv_create_qp.3.md b/providers/mlx5/man/mlx5dv_create_qp.3.md
index c21b527..7a93e84 100644
--- a/providers/mlx5/man/mlx5dv_create_qp.3.md
+++ b/providers/mlx5/man/mlx5dv_create_qp.3.md
@@ -95,6 +95,11 @@  struct mlx5dv_dc_init_attr {
 :	used to create a DCT QP.
 
 
+# NOTES
+
+**mlx5dv_qp_ex_from_ibv_qp_ex()** is used to get *struct mlx5dv_qp_ex* for
+accessing the send ops interfaces when IBV_QP_INIT_ATTR_SEND_OPS_FLAGS is used.
+
 # RETURN VALUE
 
 **mlx5dv_create_qp()**
diff --git a/providers/mlx5/man/mlx5dv_wr_post.3.md b/providers/mlx5/man/mlx5dv_wr_post.3.md
new file mode 100644
index 0000000..2c17627
--- /dev/null
+++ b/providers/mlx5/man/mlx5dv_wr_post.3.md
@@ -0,0 +1,94 @@ 
+---
+date: 2019-02-24
+footer: mlx5
+header: "mlx5 Programmer's Manual"
+tagline: Verbs
+layout: page
+license: 'Licensed under the OpenIB.org BSD license (FreeBSD Variant) - See COPYING.md'
+section: 3
+title: MLX5DV_WR
+---
+
+# NAME
+
+mlx5dv_wr_set_dc_addr - Attach a DC info to the last work request
+
+# SYNOPSIS
+
+```c
+#include <infiniband/mlx5dv.h>
+
+static inline void mlx5dv_wr_set_dc_addr(struct mlx5dv_qp_ex *mqp,
+                                         struct ibv_ah *ah,
+                                         uint32_t remote_dctn,
+                                         uint64_t remote_dc_key);
+```
+
+# DESCRIPTION
+
+The MLX5DV work request APIs (mlx5dv_wr_\*) is an extension for IBV work
+request API (ibv_wr_\*) with mlx5 specific features for send work request.
+This may be used together with or without ibv_wr_* calls.
+
+# USAGE
+
+To use these APIs a QP must be created using mlx5dv_create_qp() with
+*send_ops_flags* of struct ibv_qp_init_attr_ex set.
+
+If the QP does not support all the requested work request types then QP
+creation will fail.
+
+The mlx5dv_qp_ex is extracted from the IBV_QP by ibv_qp_to_qp_ex() and
+mlx5dv_qp_ex_from_ibv_qp_ex(). This should be used to apply the mlx5 specific
+features on the posted WR.
+
+A work request creation requires to use the ibv_qp_ex as described in the
+man for ibv_wr_post and mlx5dv_qp with its available builders and setters.
+
+## QP Specific setters
+
+*DCI* QPs
+:   *mlx5dv_wr_set_dc_addr()* must be called to set the DCI WR properties. The
+    destination address of the work is specified by *ah*, the remote DCT
+    number is specified by *remote_dctn* and the DC key is specified by
+    *remote_dc_key*.
+    This setter is available when the QP transport is DCI and send_ops_flags
+    in struct ibv_qp_init_attr_ex is set.
+    The available builders and setters for DCI QP are the same as RC QP.
+
+# EXAMPLE
+
+```c
+/* create DC QP type and specify the required send opcodes */
+attr_ex.qp_type = IBV_QPT_DRIVER;
+attr_ex.comp_mask |= IBV_QP_INIT_ATTR_SEND_OPS_FLAGS;
+attr_ex.send_ops_flags |= IBV_QP_EX_WITH_RDMA_WRITE;
+
+attr_dv.comp_mask |= MLX5DV_QP_INIT_ATTR_MASK_DC;
+attr_dv.dc_init_attr.dc_type = MLX5DV_DCTYPE_DCI;
+
+ibv_qp *qp = mlx5dv_create_qp(ctx, attr_ex, attr_dv);
+ibv_qp_ex *qpx = ibv_qp_to_qp_ex(qp);
+mlx5dv_qp_ex *mqpx = mlx5dv_qp_ex_from_ibv_qp_ex(qpx);
+
+ibv_wr_start(qpx);
+
+/* Use ibv_qp_ex object to set WR generic attributes */
+qpx->wr_id = my_wr_id_1;
+qpx->wr_flags = IBV_SEND_SIGNALED;
+ibv_wr_rdma_write(qpx, rkey, remote_addr_1);
+ibv_wr_set_sge(qpx, lkey, local_addr_1, length_1);
+
+/* Use mlx5 DC setter using mlx5dv_qp_ex object */
+mlx5dv_wr_set_wr_dc_addr(mqpx, ah, remote_dctn, remote_dc_key);
+
+ret = ibv_wr_complete(qpx);
+```
+
+# SEE ALSO
+
+**ibv_post_send**(3), **ibv_create_qp_ex(3)**, **ibv_wr_post(3)**.
+
+# AUTHOR
+
+Guy Levi <guyle@mellanox.com>
diff --git a/providers/mlx5/mlx5.h b/providers/mlx5/mlx5.h
index 3a22fde..c7c54fd 100644
--- a/providers/mlx5/mlx5.h
+++ b/providers/mlx5/mlx5.h
@@ -503,6 +503,7 @@  enum mlx5_qp_flags {
 struct mlx5_qp {
 	struct mlx5_resource            rsc; /* This struct must be first */
 	struct verbs_qp			verbs_qp;
+	struct mlx5dv_qp_ex		dv_qp;
 	struct ibv_qp		       *ibv_qp;
 	struct mlx5_buf                 buf;
 	int                             max_inline_data;
@@ -690,6 +691,11 @@  static inline struct mlx5_qp *to_mqp(struct ibv_qp *ibqp)
 	return container_of(vqp, struct mlx5_qp, verbs_qp);
 }
 
+static inline struct mlx5_qp *mqp_from_mlx5dv_qp_ex(struct mlx5dv_qp_ex *dv_qp)
+{
+	return container_of(dv_qp, struct mlx5_qp, dv_qp);
+}
+
 static inline struct mlx5_rwq *to_mrwq(struct ibv_wq *ibwq)
 {
 	return container_of(ibwq, struct mlx5_rwq, wq);
@@ -930,7 +936,8 @@  int mlx5_advise_mr(struct ibv_pd *pd,
 		   struct ibv_sge *sg_list,
 		   uint32_t num_sges);
 int mlx5_qp_fill_wr_pfns(struct mlx5_qp *mqp,
-			 const struct ibv_qp_init_attr_ex *attr);
+			 const struct ibv_qp_init_attr_ex *attr,
+			 const struct mlx5dv_qp_init_attr *mlx5_attr);
 
 static inline void *mlx5_find_uidx(struct mlx5_context *ctx, uint32_t uidx)
 {
diff --git a/providers/mlx5/mlx5dv.h b/providers/mlx5/mlx5dv.h
index e2788d8..de4018c 100644
--- a/providers/mlx5/mlx5dv.h
+++ b/providers/mlx5/mlx5dv.h
@@ -193,6 +193,26 @@  struct ibv_qp *mlx5dv_create_qp(struct ibv_context *context,
 				struct ibv_qp_init_attr_ex *qp_attr,
 				struct mlx5dv_qp_init_attr *mlx5_qp_attr);
 
+struct mlx5dv_qp_ex {
+	uint64_t comp_mask;
+	/*
+	 * Available just for the MLX5 DC QP type with send opcodes of type:
+	 * rdma, atomic and send.
+	 */
+	void (*wr_set_dc_addr)(struct mlx5dv_qp_ex *mqp, struct ibv_ah *ah,
+			       uint32_t remote_dctn, uint64_t remote_dc_key);
+};
+
+struct mlx5dv_qp_ex *mlx5dv_qp_ex_from_ibv_qp_ex(struct ibv_qp_ex *qp);
+
+static inline void mlx5dv_wr_set_dc_addr(struct mlx5dv_qp_ex *mqp,
+					 struct ibv_ah *ah,
+					 uint32_t remote_dctn,
+					 uint64_t remote_dc_key)
+{
+	mqp->wr_set_dc_addr(mqp, ah, remote_dctn, remote_dc_key);
+}
+
 enum mlx5dv_flow_action_esp_mask {
 	MLX5DV_FLOW_ACTION_ESP_MASK_FLAGS	= 1 << 0,
 };
diff --git a/providers/mlx5/qp.c b/providers/mlx5/qp.c
index f3bce40..b2f749c 100644
--- a/providers/mlx5/qp.c
+++ b/providers/mlx5/qp.c
@@ -1168,7 +1168,7 @@  int mlx5_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr,
 }
 
 enum {
-	WQE_REQ_SETTERS_UD_XRC = 2,
+	WQE_REQ_SETTERS_UD_XRC_DC = 2,
 };
 
 static void mlx5_send_wr_start(struct ibv_qp_ex *ibqp)
@@ -1296,14 +1296,15 @@  static inline void _mlx5_send_wr_send(struct ibv_qp_ex *ibqp,
 
 	_common_wqe_init(ibqp, ib_op);
 
-	if (ibqp->qp_base.qp_type == IBV_QPT_UD)
+	if (ibqp->qp_base.qp_type == IBV_QPT_UD ||
+	    ibqp->qp_base.qp_type == IBV_QPT_DRIVER)
 		transport_seg_sz = sizeof(struct mlx5_wqe_datagram_seg);
 	else if (ibqp->qp_base.qp_type == IBV_QPT_XRC_SEND)
 		transport_seg_sz = sizeof(struct mlx5_wqe_xrc_seg);
 
 	mqp->cur_data = (void *)mqp->cur_ctrl + sizeof(struct mlx5_wqe_ctrl_seg) +
 			transport_seg_sz;
-	/* In UD, cur_data may overrun the SQ */
+	/* In UD/DC cur_data may overrun the SQ */
 	if (unlikely(mqp->cur_data == mqp->sq.qend))
 		mqp->cur_data = mlx5_get_send_wqe(mqp, 0);
 
@@ -1435,11 +1436,16 @@  static inline void _mlx5_send_wr_rdma(struct ibv_qp_ex *ibqp,
 
 	_common_wqe_init(ibqp, ib_op);
 
-	if (ibqp->qp_base.qp_type == IBV_QPT_XRC_SEND)
+	if (ibqp->qp_base.qp_type == IBV_QPT_DRIVER)
+		transport_seg_sz = sizeof(struct mlx5_wqe_datagram_seg);
+	else if (ibqp->qp_base.qp_type == IBV_QPT_XRC_SEND)
 		transport_seg_sz = sizeof(struct mlx5_wqe_xrc_seg);
 
 	raddr_seg = (void *)mqp->cur_ctrl + sizeof(struct mlx5_wqe_ctrl_seg) +
 		    transport_seg_sz;
+	/* In DC raddr_seg may overrun the SQ */
+	if (unlikely(raddr_seg == mqp->sq.qend))
+		raddr_seg = mlx5_get_send_wqe(mqp, 0);
 
 	set_raddr_seg(raddr_seg, remote_addr, rkey);
 
@@ -1490,11 +1496,16 @@  static inline void _mlx5_send_wr_atomic(struct ibv_qp_ex *ibqp, uint32_t rkey,
 
 	_common_wqe_init(ibqp, ib_op);
 
-	if (ibqp->qp_base.qp_type == IBV_QPT_XRC_SEND)
+	if (ibqp->qp_base.qp_type == IBV_QPT_DRIVER)
+		transport_seg_sz = sizeof(struct mlx5_wqe_datagram_seg);
+	else if (ibqp->qp_base.qp_type == IBV_QPT_XRC_SEND)
 		transport_seg_sz = sizeof(struct mlx5_wqe_xrc_seg);
 
 	raddr_seg = (void *)mqp->cur_ctrl + sizeof(struct mlx5_wqe_ctrl_seg) +
 		    transport_seg_sz;
+	/* In DC raddr_seg may overrun the SQ */
+	if (unlikely(raddr_seg == mqp->sq.qend))
+		raddr_seg = mlx5_get_send_wqe(mqp, 0);
 
 	set_raddr_seg(raddr_seg, remote_addr, rkey);
 
@@ -1608,14 +1619,14 @@  mlx5_send_wr_set_sge_rc_uc(struct ibv_qp_ex *ibqp, uint32_t lkey,
 }
 
 static void
-mlx5_send_wr_set_sge_ud_xrc(struct ibv_qp_ex *ibqp, uint32_t lkey,
-			    uint64_t addr, uint32_t length)
+mlx5_send_wr_set_sge_ud_xrc_dc(struct ibv_qp_ex *ibqp, uint32_t lkey,
+			       uint64_t addr, uint32_t length)
 {
 	struct mlx5_qp *mqp = to_mqp((struct ibv_qp *)ibqp);
 
 	_mlx5_send_wr_set_sge(mqp, lkey, addr, length);
 
-	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC - 1)
+	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC_DC - 1)
 		_common_wqe_finilize(mqp);
 	else
 		mqp->cur_setters_cnt++;
@@ -1696,14 +1707,14 @@  mlx5_send_wr_set_sge_list_rc_uc(struct ibv_qp_ex *ibqp, size_t num_sge,
 }
 
 static void
-mlx5_send_wr_set_sge_list_ud_xrc(struct ibv_qp_ex *ibqp, size_t num_sge,
-				 const struct ibv_sge *sg_list)
+mlx5_send_wr_set_sge_list_ud_xrc_dc(struct ibv_qp_ex *ibqp, size_t num_sge,
+				    const struct ibv_sge *sg_list)
 {
 	struct mlx5_qp *mqp = to_mqp((struct ibv_qp *)ibqp);
 
 	_mlx5_send_wr_set_sge_list(mqp, num_sge, sg_list);
 
-	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC - 1)
+	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC_DC - 1)
 		_common_wqe_finilize(mqp);
 	else
 		mqp->cur_setters_cnt++;
@@ -1833,14 +1844,14 @@  mlx5_send_wr_set_inline_data_rc_uc(struct ibv_qp_ex *ibqp, void *addr,
 }
 
 static void
-mlx5_send_wr_set_inline_data_ud_xrc(struct ibv_qp_ex *ibqp, void *addr,
-				    size_t length)
+mlx5_send_wr_set_inline_data_ud_xrc_dc(struct ibv_qp_ex *ibqp, void *addr,
+				       size_t length)
 {
 	struct mlx5_qp *mqp = to_mqp((struct ibv_qp *)ibqp);
 
 	_mlx5_send_wr_set_inline_data(mqp, addr, length);
 
-	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC - 1)
+	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC_DC - 1)
 		_common_wqe_finilize(mqp);
 	else
 		mqp->cur_setters_cnt++;
@@ -1927,15 +1938,15 @@  mlx5_send_wr_set_inline_data_list_rc_uc(struct ibv_qp_ex *ibqp,
 }
 
 static void
-mlx5_send_wr_set_inline_data_list_ud_xrc(struct ibv_qp_ex *ibqp,
-					 size_t num_buf,
-					 const struct ibv_data_buf *buf_list)
+mlx5_send_wr_set_inline_data_list_ud_xrc_dc(struct ibv_qp_ex *ibqp,
+					    size_t num_buf,
+					    const struct ibv_data_buf *buf_list)
 {
 	struct mlx5_qp *mqp = to_mqp((struct ibv_qp *)ibqp);
 
 	_mlx5_send_wr_set_inline_data_list(mqp, num_buf, buf_list);
 
-	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC - 1)
+	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC_DC - 1)
 		_common_wqe_finilize(mqp);
 	else
 		mqp->cur_setters_cnt++;
@@ -2012,7 +2023,7 @@  mlx5_send_wr_set_ud_addr(struct ibv_qp_ex *ibqp, struct ibv_ah *ah,
 
 	_set_datagram_seg(dseg, &mah->av, remote_qpn, remote_qkey);
 
-	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC - 1)
+	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC_DC - 1)
 		_common_wqe_finilize(mqp);
 	else
 		mqp->cur_setters_cnt++;
@@ -2027,7 +2038,27 @@  mlx5_send_wr_set_xrc_srqn(struct ibv_qp_ex *ibqp, uint32_t remote_srqn)
 
 	xrc_seg->xrc_srqn = htobe32(remote_srqn);
 
-	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC - 1)
+	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC_DC - 1)
+		_common_wqe_finilize(mqp);
+	else
+		mqp->cur_setters_cnt++;
+}
+
+static void mlx5_send_wr_set_dc_addr(struct mlx5dv_qp_ex *dv_qp,
+				     struct ibv_ah *ah,
+				     uint32_t remote_dctn,
+				     uint64_t remote_dc_key)
+{
+	struct mlx5_qp *mqp = mqp_from_mlx5dv_qp_ex(dv_qp);
+	struct mlx5_wqe_datagram_seg *dseg =
+		(void *)mqp->cur_ctrl + sizeof(struct mlx5_wqe_ctrl_seg);
+	struct mlx5_ah *mah = to_mah(ah);
+
+	memcpy(&dseg->av, &mah->av, sizeof(dseg->av));
+	dseg->av.dqp_dct |= htobe32(remote_dctn | MLX5_EXTENDED_UD_AV);
+	dseg->av.key.dc_key = htobe64(remote_dc_key);
+
+	if (mqp->cur_setters_cnt == WQE_REQ_SETTERS_UD_XRC_DC - 1)
 		_common_wqe_finilize(mqp);
 	else
 		mqp->cur_setters_cnt++;
@@ -2047,6 +2078,8 @@  enum {
 		IBV_QP_EX_WITH_BIND_MW,
 	MLX5_SUPPORTED_SEND_OPS_FLAGS_XRC =
 		MLX5_SUPPORTED_SEND_OPS_FLAGS_RC,
+	MLX5_SUPPORTED_SEND_OPS_FLAGS_DCI =
+		MLX5_SUPPORTED_SEND_OPS_FLAGS_RC,
 	MLX5_SUPPORTED_SEND_OPS_FLAGS_UD =
 		IBV_QP_EX_WITH_SEND |
 		IBV_QP_EX_WITH_SEND_WITH_IMM,
@@ -2063,7 +2096,7 @@  enum {
 		IBV_QP_EX_WITH_TSO,
 };
 
-static void fill_wr_builders_rc_xrc(struct ibv_qp_ex *ibqp)
+static void fill_wr_builders_rc_xrc_dc(struct ibv_qp_ex *ibqp)
 {
 	ibqp->wr_send = mlx5_send_wr_send_other;
 	ibqp->wr_send_imm = mlx5_send_wr_send_imm;
@@ -2108,12 +2141,12 @@  static void fill_wr_setters_rc_uc(struct ibv_qp_ex *ibqp)
 	ibqp->wr_set_inline_data_list = mlx5_send_wr_set_inline_data_list_rc_uc;
 }
 
-static void fill_wr_setters_ud_xrc(struct ibv_qp_ex *ibqp)
+static void fill_wr_setters_ud_xrc_dc(struct ibv_qp_ex *ibqp)
 {
-	ibqp->wr_set_sge = mlx5_send_wr_set_sge_ud_xrc;
-	ibqp->wr_set_sge_list = mlx5_send_wr_set_sge_list_ud_xrc;
-	ibqp->wr_set_inline_data = mlx5_send_wr_set_inline_data_ud_xrc;
-	ibqp->wr_set_inline_data_list = mlx5_send_wr_set_inline_data_list_ud_xrc;
+	ibqp->wr_set_sge = mlx5_send_wr_set_sge_ud_xrc_dc;
+	ibqp->wr_set_sge_list = mlx5_send_wr_set_sge_list_ud_xrc_dc;
+	ibqp->wr_set_inline_data = mlx5_send_wr_set_inline_data_ud_xrc_dc;
+	ibqp->wr_set_inline_data_list = mlx5_send_wr_set_inline_data_list_ud_xrc_dc;
 }
 
 static void fill_wr_setters_eth(struct ibv_qp_ex *ibqp)
@@ -2125,10 +2158,12 @@  static void fill_wr_setters_eth(struct ibv_qp_ex *ibqp)
 }
 
 int mlx5_qp_fill_wr_pfns(struct mlx5_qp *mqp,
-			 const struct ibv_qp_init_attr_ex *attr)
+			 const struct ibv_qp_init_attr_ex *attr,
+			 const struct mlx5dv_qp_init_attr *mlx5_attr)
 {
 	struct ibv_qp_ex *ibqp = &mqp->verbs_qp.qp_ex;
 	uint64_t ops = attr->send_ops_flags;
+	struct mlx5dv_qp_ex *dv_qp;
 
 	ibqp->wr_start = mlx5_send_wr_start;
 	ibqp->wr_complete = mlx5_send_wr_complete;
@@ -2145,7 +2180,7 @@  int mlx5_qp_fill_wr_pfns(struct mlx5_qp *mqp,
 		if (ops & ~MLX5_SUPPORTED_SEND_OPS_FLAGS_RC)
 			return EOPNOTSUPP;
 
-		fill_wr_builders_rc_xrc(ibqp);
+		fill_wr_builders_rc_xrc_dc(ibqp);
 		fill_wr_setters_rc_uc(ibqp);
 		break;
 
@@ -2161,8 +2196,8 @@  int mlx5_qp_fill_wr_pfns(struct mlx5_qp *mqp,
 		if (ops & ~MLX5_SUPPORTED_SEND_OPS_FLAGS_XRC)
 			return EOPNOTSUPP;
 
-		fill_wr_builders_rc_xrc(ibqp);
-		fill_wr_setters_ud_xrc(ibqp);
+		fill_wr_builders_rc_xrc_dc(ibqp);
+		fill_wr_setters_ud_xrc_dc(ibqp);
 		ibqp->wr_set_xrc_srqn = mlx5_send_wr_set_xrc_srqn;
 		break;
 
@@ -2174,7 +2209,7 @@  int mlx5_qp_fill_wr_pfns(struct mlx5_qp *mqp,
 			return EOPNOTSUPP;
 
 		fill_wr_builders_ud(ibqp);
-		fill_wr_setters_ud_xrc(ibqp);
+		fill_wr_setters_ud_xrc_dc(ibqp);
 		ibqp->wr_set_ud_addr = mlx5_send_wr_set_ud_addr;
 		break;
 
@@ -2186,6 +2221,21 @@  int mlx5_qp_fill_wr_pfns(struct mlx5_qp *mqp,
 		fill_wr_setters_eth(ibqp);
 		break;
 
+	case IBV_QPT_DRIVER:
+		dv_qp = &mqp->dv_qp;
+
+		if (!(mlx5_attr->comp_mask & MLX5DV_QP_INIT_ATTR_MASK_DC &&
+		      mlx5_attr->dc_init_attr.dc_type == MLX5DV_DCTYPE_DCI))
+			return EOPNOTSUPP;
+
+		if (ops & ~MLX5_SUPPORTED_SEND_OPS_FLAGS_DCI)
+			return EOPNOTSUPP;
+
+		fill_wr_builders_rc_xrc_dc(ibqp);
+		fill_wr_setters_ud_xrc_dc(ibqp);
+		dv_qp->wr_set_dc_addr = mlx5_send_wr_set_dc_addr;
+		break;
+
 	default:
 		return EOPNOTSUPP;
 	}
diff --git a/providers/mlx5/verbs.c b/providers/mlx5/verbs.c
index 870279e..abbbf5a 100644
--- a/providers/mlx5/verbs.c
+++ b/providers/mlx5/verbs.c
@@ -1913,7 +1913,17 @@  static struct ibv_qp *create_qp(struct ibv_context *context,
 		qp->atomics_enabled = 1;
 
 	if (attr->comp_mask & IBV_QP_INIT_ATTR_SEND_OPS_FLAGS) {
-		ret = mlx5_qp_fill_wr_pfns(qp, attr);
+		/*
+		 * Scatter2cqe, which is a data-path optimization, is disabled
+		 * since driver DC data-path doesn't support it.
+		 */
+		if (mlx5_qp_attr &&
+		    mlx5_qp_attr->comp_mask & MLX5DV_QP_INIT_ATTR_MASK_DC) {
+			mlx5_create_flags &= ~MLX5_QP_FLAG_SCATTER_CQE;
+			scatter_to_cqe_configured = true;
+		}
+
+		ret = mlx5_qp_fill_wr_pfns(qp, attr, mlx5_qp_attr);
 		if (ret) {
 			errno = ret;
 			mlx5_dbg(fp, MLX5_DBG_QP, "Failed to handle operations flags (errno %d)\n", errno);
@@ -2589,6 +2599,11 @@  struct ibv_qp *mlx5dv_create_qp(struct ibv_context *context,
 	return create_qp(context, qp_attr, mlx5_qp_attr);
 }
 
+struct mlx5dv_qp_ex *mlx5dv_qp_ex_from_ibv_qp_ex(struct ibv_qp_ex *qp)
+{
+	return &(container_of(qp, struct mlx5_qp, verbs_qp.qp_ex))->dv_qp;
+}
+
 int mlx5_get_srq_num(struct ibv_srq *srq, uint32_t *srq_num)
 {
 	struct mlx5_srq *msrq = to_msrq(srq);