Version: 1
-Previous: 9c927a492c4b681fa8f6f01004d811187ae7c1b2
-Head: b301fa827367508d386a607cfad5b9863372f456
+Previous: 15fbbd6a1651ac1cd8fdf42d86c640c350d8d2bf
+Head: 092bcc697d9bb0d4fe8cc322d57b9248800d2e71
Applied:
verbs-ext: b1cc207d04e9df91c000aadd20d3612f3cb58552
xrcd: f2b48b365d126d1c4bc61b3b3ea1ab9b7f2544f4
srq_ex: 91fdc5b4aaf078280ff31bd0cf35760a6ae5dd10
- xrc_qp: a98e29562c1d727dd492cfa66b628369460969f6
- refresh-temp: b301fa827367508d386a607cfad5b9863372f456
+ xrc_qp: 092bcc697d9bb0d4fe8cc322d57b9248800d2e71
Unapplied:
open_qp: 02ed1a5b57528c104aefa6608f45bdf2d718ded3
open_qp_man: 3ba2056186d67520b8302137c5906a0083891d7f
+++ /dev/null
-Bottom: f12a9640338b48e3a608e0b2ec69517ecd34327e
-Top: 61b6c90445f6c7731dcbedec80b9701b071ba0f8
-Author: Sean Hefty <sean.hefty@intel.com>
-Date: 2012-09-28 10:44:45 -0700
-
-Refresh of xrc_qp
-
----
-
-diff --git a/include/infiniband/driver.h b/include/infiniband/driver.h
-index 05ff730..d43ae07 100644
---- a/include/infiniband/driver.h
-+++ b/include/infiniband/driver.h
-@@ -81,6 +81,16 @@ struct verbs_srq {
- uint32_t srq_num;
- };
-
-+enum verbs_qp_mask {
-+ VERBS_QP_XRCD = 1 << 0,
-+ VERBS_QP_RESERVED = 1 << 1
-+};
-+
-+struct verbs_qp {
-+ struct ibv_qp qp;
-+ uint32_t comp_mask;
-+ struct verbs_xrcd *xrcd;
-+};
- typedef struct ibv_device *(*ibv_driver_init_func)(const char *uverbs_sys_path,
- int abi_version);
- typedef struct verbs_device *(*verbs_driver_init_func)(const char *uverbs_sys_path,
-@@ -152,6 +162,10 @@ int ibv_cmd_create_qp(struct ibv_pd *pd,
- struct ibv_qp *qp, struct ibv_qp_init_attr *attr,
- struct ibv_create_qp *cmd, size_t cmd_size,
- struct ibv_create_qp_resp *resp, size_t resp_size);
-+int ibv_cmd_create_qp_ex(struct ibv_context *context,
-+ struct verbs_qp *qp, struct ibv_qp_init_attr_ex *attr_ex,
-+ struct ibv_create_qp *cmd, size_t cmd_size,
-+ struct ibv_create_qp_resp *resp, size_t resp_size);
- int ibv_cmd_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *qp_attr,
- int attr_mask,
- struct ibv_qp_init_attr *qp_init_attr,
-diff --git a/include/infiniband/kern-abi.h b/include/infiniband/kern-abi.h
-index 3d72fa7..b6d5ce9 100644
---- a/include/infiniband/kern-abi.h
-+++ b/include/infiniband/kern-abi.h
-@@ -617,6 +617,11 @@ struct ibv_kern_send_wr {
- __u32 remote_qkey;
- __u32 reserved;
- } ud;
-+ struct {
-+ __u64 reserved[3];
-+ __u32 reserved2;
-+ __u32 remote_srqn;
-+ } xrc;
- } wr;
- };
-
-diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h
-index 6465aae..1356757 100644
---- a/include/infiniband/verbs.h
-+++ b/include/infiniband/verbs.h
-@@ -91,21 +91,22 @@ enum ibv_transport_type {
- };
-
- enum ibv_device_cap_flags {
-- IBV_DEVICE_RESIZE_MAX_WR = 1,
-- IBV_DEVICE_BAD_PKEY_CNTR = 1 << 1,
-- IBV_DEVICE_BAD_QKEY_CNTR = 1 << 2,
-- IBV_DEVICE_RAW_MULTI = 1 << 3,
-- IBV_DEVICE_AUTO_PATH_MIG = 1 << 4,
-- IBV_DEVICE_CHANGE_PHY_PORT = 1 << 5,
-- IBV_DEVICE_UD_AV_PORT_ENFORCE = 1 << 6,
-- IBV_DEVICE_CURR_QP_STATE_MOD = 1 << 7,
-- IBV_DEVICE_SHUTDOWN_PORT = 1 << 8,
-- IBV_DEVICE_INIT_TYPE = 1 << 9,
-- IBV_DEVICE_PORT_ACTIVE_EVENT = 1 << 10,
-- IBV_DEVICE_SYS_IMAGE_GUID = 1 << 11,
-- IBV_DEVICE_RC_RNR_NAK_GEN = 1 << 12,
-- IBV_DEVICE_SRQ_RESIZE = 1 << 13,
-- IBV_DEVICE_N_NOTIFY_CQ = 1 << 14
-+ IBV_DEVICE_RESIZE_MAX_WR = 1,
-+ IBV_DEVICE_BAD_PKEY_CNTR = 1 << 1,
-+ IBV_DEVICE_BAD_QKEY_CNTR = 1 << 2,
-+ IBV_DEVICE_RAW_MULTI = 1 << 3,
-+ IBV_DEVICE_AUTO_PATH_MIG = 1 << 4,
-+ IBV_DEVICE_CHANGE_PHY_PORT = 1 << 5,
-+ IBV_DEVICE_UD_AV_PORT_ENFORCE = 1 << 6,
-+ IBV_DEVICE_CURR_QP_STATE_MOD = 1 << 7,
-+ IBV_DEVICE_SHUTDOWN_PORT = 1 << 8,
-+ IBV_DEVICE_INIT_TYPE = 1 << 9,
-+ IBV_DEVICE_PORT_ACTIVE_EVENT = 1 << 10,
-+ IBV_DEVICE_SYS_IMAGE_GUID = 1 << 11,
-+ IBV_DEVICE_RC_RNR_NAK_GEN = 1 << 12,
-+ IBV_DEVICE_SRQ_RESIZE = 1 << 13,
-+ IBV_DEVICE_N_NOTIFY_CQ = 1 << 14,
-+ IBV_DEVICE_XRC = 1 << 20
- };
-
- enum ibv_atomic_cap {
-@@ -445,7 +446,11 @@ struct ibv_srq_init_attr_ex {
- };
-
- enum ibv_qp_type {
-- IBV_QPT_RC = 2, IBV_QPT_UC, IBV_QPT_UD
-+ IBV_QPT_RC = 2,
-+ IBV_QPT_UC,
-+ IBV_QPT_UD,
-+ IBV_QPT_XRC_SEND = 9,
-+ IBV_QPT_XRC_RECV
- };
-
- struct ibv_qp_cap {
-@@ -466,6 +471,26 @@ struct ibv_qp_init_attr {
- int sq_sig_all;
- };
-
-+enum ibv_qp_init_attr_mask {
-+ IBV_QP_INIT_ATTR_PD = 1 << 0,
-+ IBV_QP_INIT_ATTR_XRCD = 1 << 1,
-+ IBV_QP_INIT_ATTR_RESERVED = 1 << 2
-+};
-+
-+struct ibv_qp_init_attr_ex {
-+ void *qp_context;
-+ struct ibv_cq *send_cq;
-+ struct ibv_cq *recv_cq;
-+ struct ibv_srq *srq;
-+ struct ibv_qp_cap cap;
-+ enum ibv_qp_type qp_type;
-+ int sq_sig_all;
-+
-+ uint32_t comp_mask;
-+ struct ibv_pd *pd;
-+ struct ibv_xrcd *xrcd;
-+};
-+
- enum ibv_qp_attr_mask {
- IBV_QP_STATE = 1 << 0,
- IBV_QP_CUR_STATE = 1 << 1,
-@@ -579,6 +604,11 @@ struct ibv_send_wr {
- uint32_t remote_qpn;
- uint32_t remote_qkey;
- } ud;
-+ struct {
-+ uint64_t reserved[3];
-+ uint32_t reserved2;
-+ uint32_t remote_srqn;
-+ } xrc;
- } wr;
- };
-
-@@ -755,7 +785,8 @@ struct ibv_context {
- enum verbs_context_mask {
- VERBS_CONTEXT_XRCD = 1 << 0,
- VERBS_CONTEXT_SRQ = 1 << 1,
-- VERBS_CONTEXT_RESERVED = 1 << 2
-+ VERBS_CONTEXT_QP = 1 << 2,
-+ VERBS_CONTEXT_RESERVED = 1 << 3
- };
-
- struct verbs_context {
-@@ -763,6 +794,8 @@ struct verbs_context {
- int (*drv_new_func1) (); new corresponding provider call of func1
- int (*lib_new_func1) (); New library call func1
- */
-+ struct ibv_qp * (*create_qp_ex)(struct ibv_context *context,
-+ struct ibv_qp_init_attr_ex *qp_init_attr_ex);
- uint32_t (*get_srq_num)(struct ibv_srq *srq);
- struct ibv_srq * (*create_srq_ex)(struct ibv_context *context,
- struct ibv_srq_init_attr_ex *srq_init_attr_ex);
-@@ -1123,6 +1156,23 @@ static inline int ibv_post_srq_recv(struct ibv_srq *srq,
- struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,
- struct ibv_qp_init_attr *qp_init_attr);
-
-+static inline struct ibv_qp *
-+ibv_create_qp_ex(struct ibv_context *context, struct ibv_qp_init_attr_ex *qp_init_attr_ex)
-+{
-+ struct verbs_context *vctx;
-+ uint32_t mask = qp_init_attr_ex->comp_mask;
-+
-+ if (!(mask & ~(IBV_QP_INIT_ATTR_PD)) && (mask & IBV_QP_INIT_ATTR_PD))
-+ return ibv_create_qp(qp_init_attr_ex->pd,
-+ (struct ibv_qp_init_attr *) qp_init_attr_ex);
-+
-+ if (!(vctx = verbs_get_ctx_op(context, create_qp_ex))) {
-+ errno = ENOSYS;
-+ return NULL;
-+ }
-+ return vctx->create_qp_ex(context, qp_init_attr_ex);
-+}
-+
- /**
- * ibv_modify_qp - Modify a queue pair.
- */
-diff --git a/src/cmd.c b/src/cmd.c
-index 641ab28..87ac062 100644
---- a/src/cmd.c
-+++ b/src/cmd.c
-@@ -666,6 +666,98 @@ int ibv_cmd_destroy_srq(struct ibv_srq *srq)
- return 0;
- }
-
-+int ibv_cmd_create_qp_ex(struct ibv_context *context,
-+ struct verbs_qp *qp, struct ibv_qp_init_attr_ex *attr_ex,
-+ struct ibv_create_qp *cmd, size_t cmd_size,
-+ struct ibv_create_qp_resp *resp, size_t resp_size)
-+{
-+ struct verbs_xrcd *vxrcd = NULL;
-+
-+ IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_QP, resp, resp_size);
-+
-+ if (attr_ex->comp_mask >= IBV_QP_INIT_ATTR_RESERVED)
-+ return ENOSYS;
-+
-+ cmd->user_handle = (uintptr_t) qp;
-+
-+ if (attr_ex->comp_mask & IBV_QP_INIT_ATTR_XRCD) {
-+ vxrcd = container_of(attr_ex->xrcd, struct verbs_xrcd, xrcd);
-+ cmd->pd_handle = vxrcd->handle;
-+ } else {
-+ if (!(attr_ex->comp_mask & IBV_QP_INIT_ATTR_PD))
-+ return EINVAL;
-+
-+ cmd->pd_handle = attr_ex->pd->handle;
-+ cmd->send_cq_handle = attr_ex->send_cq->handle;
-+
-+ if (attr_ex->qp_type != IBV_QPT_XRC_SEND) {
-+ cmd->recv_cq_handle = attr_ex->recv_cq->handle;
-+ cmd->srq_handle = attr_ex->srq ? attr_ex->srq->handle : 0;
-+ }
-+ }
-+
-+ cmd->max_send_wr = attr_ex->cap.max_send_wr;
-+ cmd->max_recv_wr = attr_ex->cap.max_recv_wr;
-+ cmd->max_send_sge = attr_ex->cap.max_send_sge;
-+ cmd->max_recv_sge = attr_ex->cap.max_recv_sge;
-+ cmd->max_inline_data = attr_ex->cap.max_inline_data;
-+ cmd->sq_sig_all = attr_ex->sq_sig_all;
-+ cmd->qp_type = attr_ex->qp_type;
-+ cmd->is_srq = !!attr_ex->srq;
-+ cmd->reserved = 0;
-+
-+ if (write(context->cmd_fd, cmd, cmd_size) != cmd_size)
-+ return errno;
-+
-+ (void) VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
-+
-+ if (abi_ver > 3) {
-+ attr_ex->cap.max_recv_sge = resp->max_recv_sge;
-+ attr_ex->cap.max_send_sge = resp->max_send_sge;
-+ attr_ex->cap.max_recv_wr = resp->max_recv_wr;
-+ attr_ex->cap.max_send_wr = resp->max_send_wr;
-+ attr_ex->cap.max_inline_data = resp->max_inline_data;
-+ }
-+
-+ if (abi_ver == 4) {
-+ struct ibv_create_qp_resp_v4 *resp_v4 =
-+ (struct ibv_create_qp_resp_v4 *) resp;
-+
-+ memmove((void *) resp + sizeof *resp,
-+ (void *) resp_v4 + sizeof *resp_v4,
-+ resp_size - sizeof *resp);
-+ } else if (abi_ver <= 3) {
-+ struct ibv_create_qp_resp_v3 *resp_v3 =
-+ (struct ibv_create_qp_resp_v3 *) resp;
-+
-+ memmove((void *) resp + sizeof *resp,
-+ (void *) resp_v3 + sizeof *resp_v3,
-+ resp_size - sizeof *resp);
-+ }
-+
-+ qp->qp.handle = resp->qp_handle;
-+ qp->qp.qp_num = resp->qpn;
-+ qp->qp.context = context;
-+ qp->qp.qp_context = attr_ex->qp_context;
-+ qp->qp.pd = attr_ex->pd;
-+ qp->qp.send_cq = attr_ex->send_cq;
-+ qp->qp.recv_cq = attr_ex->recv_cq;
-+ qp->qp.srq = attr_ex->srq;
-+ qp->qp.qp_type = attr_ex->qp_type;
-+ qp->qp.state = IBV_QPS_RESET;
-+ qp->qp.events_completed = 0;
-+ pthread_mutex_init(&qp->qp.mutex, NULL);
-+ pthread_cond_init(&qp->qp.cond, NULL);
-+
-+ qp->comp_mask = 0;
-+ if (attr_ex->comp_mask & IBV_QP_INIT_ATTR_XRCD) {
-+ qp->comp_mask |= VERBS_QP_XRCD;
-+ qp->xrcd = vxrcd;
-+ }
-+
-+ return 0;
-+}
-+
- int ibv_cmd_create_qp(struct ibv_pd *pd,
- struct ibv_qp *qp, struct ibv_qp_init_attr *attr,
- struct ibv_create_qp *cmd, size_t cmd_size,
-@@ -674,7 +766,7 @@ int ibv_cmd_create_qp(struct ibv_pd *pd,
- IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_QP, resp, resp_size);
-
- cmd->user_handle = (uintptr_t) qp;
-- cmd->pd_handle = pd->handle;
-+ cmd->pd_handle = pd->handle;
- cmd->send_cq_handle = attr->send_cq->handle;
- cmd->recv_cq_handle = attr->recv_cq->handle;
- cmd->srq_handle = attr->srq ? attr->srq->handle : 0;
-diff --git a/src/libibverbs.map b/src/libibverbs.map
-index c8ec645..4249793 100644
---- a/src/libibverbs.map
-+++ b/src/libibverbs.map
-@@ -101,5 +101,6 @@ IBVERBS_1.1 {
- ibv_cmd_open_xrcd;
- ibv_cmd_close_xrcd;
- ibv_cmd_create_srq_ex;
-+ ibv_cmd_create_qp_ex;
-
- } IBVERBS_1.0;
Bottom: f12a9640338b48e3a608e0b2ec69517ecd34327e
-Top: f12a9640338b48e3a608e0b2ec69517ecd34327e
+Top: 61b6c90445f6c7731dcbedec80b9701b071ba0f8
Author: Sean Hefty <sean.hefty@intel.com>
Date: 2012-09-17 16:00:12 -0700
---
-
+diff --git a/include/infiniband/driver.h b/include/infiniband/driver.h
+index 05ff730..d43ae07 100644
+--- a/include/infiniband/driver.h
++++ b/include/infiniband/driver.h
+@@ -81,6 +81,16 @@ struct verbs_srq {
+ uint32_t srq_num;
+ };
+
++enum verbs_qp_mask {
++ VERBS_QP_XRCD = 1 << 0,
++ VERBS_QP_RESERVED = 1 << 1
++};
++
++struct verbs_qp {
++ struct ibv_qp qp;
++ uint32_t comp_mask;
++ struct verbs_xrcd *xrcd;
++};
+ typedef struct ibv_device *(*ibv_driver_init_func)(const char *uverbs_sys_path,
+ int abi_version);
+ typedef struct verbs_device *(*verbs_driver_init_func)(const char *uverbs_sys_path,
+@@ -152,6 +162,10 @@ int ibv_cmd_create_qp(struct ibv_pd *pd,
+ struct ibv_qp *qp, struct ibv_qp_init_attr *attr,
+ struct ibv_create_qp *cmd, size_t cmd_size,
+ struct ibv_create_qp_resp *resp, size_t resp_size);
++int ibv_cmd_create_qp_ex(struct ibv_context *context,
++ struct verbs_qp *qp, struct ibv_qp_init_attr_ex *attr_ex,
++ struct ibv_create_qp *cmd, size_t cmd_size,
++ struct ibv_create_qp_resp *resp, size_t resp_size);
+ int ibv_cmd_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *qp_attr,
+ int attr_mask,
+ struct ibv_qp_init_attr *qp_init_attr,
+diff --git a/include/infiniband/kern-abi.h b/include/infiniband/kern-abi.h
+index 3d72fa7..b6d5ce9 100644
+--- a/include/infiniband/kern-abi.h
++++ b/include/infiniband/kern-abi.h
+@@ -617,6 +617,11 @@ struct ibv_kern_send_wr {
+ __u32 remote_qkey;
+ __u32 reserved;
+ } ud;
++ struct {
++ __u64 reserved[3];
++ __u32 reserved2;
++ __u32 remote_srqn;
++ } xrc;
+ } wr;
+ };
+
+diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h
+index 6465aae..1356757 100644
+--- a/include/infiniband/verbs.h
++++ b/include/infiniband/verbs.h
+@@ -91,21 +91,22 @@ enum ibv_transport_type {
+ };
+
+ enum ibv_device_cap_flags {
+- IBV_DEVICE_RESIZE_MAX_WR = 1,
+- IBV_DEVICE_BAD_PKEY_CNTR = 1 << 1,
+- IBV_DEVICE_BAD_QKEY_CNTR = 1 << 2,
+- IBV_DEVICE_RAW_MULTI = 1 << 3,
+- IBV_DEVICE_AUTO_PATH_MIG = 1 << 4,
+- IBV_DEVICE_CHANGE_PHY_PORT = 1 << 5,
+- IBV_DEVICE_UD_AV_PORT_ENFORCE = 1 << 6,
+- IBV_DEVICE_CURR_QP_STATE_MOD = 1 << 7,
+- IBV_DEVICE_SHUTDOWN_PORT = 1 << 8,
+- IBV_DEVICE_INIT_TYPE = 1 << 9,
+- IBV_DEVICE_PORT_ACTIVE_EVENT = 1 << 10,
+- IBV_DEVICE_SYS_IMAGE_GUID = 1 << 11,
+- IBV_DEVICE_RC_RNR_NAK_GEN = 1 << 12,
+- IBV_DEVICE_SRQ_RESIZE = 1 << 13,
+- IBV_DEVICE_N_NOTIFY_CQ = 1 << 14
++ IBV_DEVICE_RESIZE_MAX_WR = 1,
++ IBV_DEVICE_BAD_PKEY_CNTR = 1 << 1,
++ IBV_DEVICE_BAD_QKEY_CNTR = 1 << 2,
++ IBV_DEVICE_RAW_MULTI = 1 << 3,
++ IBV_DEVICE_AUTO_PATH_MIG = 1 << 4,
++ IBV_DEVICE_CHANGE_PHY_PORT = 1 << 5,
++ IBV_DEVICE_UD_AV_PORT_ENFORCE = 1 << 6,
++ IBV_DEVICE_CURR_QP_STATE_MOD = 1 << 7,
++ IBV_DEVICE_SHUTDOWN_PORT = 1 << 8,
++ IBV_DEVICE_INIT_TYPE = 1 << 9,
++ IBV_DEVICE_PORT_ACTIVE_EVENT = 1 << 10,
++ IBV_DEVICE_SYS_IMAGE_GUID = 1 << 11,
++ IBV_DEVICE_RC_RNR_NAK_GEN = 1 << 12,
++ IBV_DEVICE_SRQ_RESIZE = 1 << 13,
++ IBV_DEVICE_N_NOTIFY_CQ = 1 << 14,
++ IBV_DEVICE_XRC = 1 << 20
+ };
+
+ enum ibv_atomic_cap {
+@@ -445,7 +446,11 @@ struct ibv_srq_init_attr_ex {
+ };
+
+ enum ibv_qp_type {
+- IBV_QPT_RC = 2, IBV_QPT_UC, IBV_QPT_UD
++ IBV_QPT_RC = 2,
++ IBV_QPT_UC,
++ IBV_QPT_UD,
++ IBV_QPT_XRC_SEND = 9,
++ IBV_QPT_XRC_RECV
+ };
+
+ struct ibv_qp_cap {
+@@ -466,6 +471,26 @@ struct ibv_qp_init_attr {
+ int sq_sig_all;
+ };
+
++enum ibv_qp_init_attr_mask {
++ IBV_QP_INIT_ATTR_PD = 1 << 0,
++ IBV_QP_INIT_ATTR_XRCD = 1 << 1,
++ IBV_QP_INIT_ATTR_RESERVED = 1 << 2
++};
++
++struct ibv_qp_init_attr_ex {
++ void *qp_context;
++ struct ibv_cq *send_cq;
++ struct ibv_cq *recv_cq;
++ struct ibv_srq *srq;
++ struct ibv_qp_cap cap;
++ enum ibv_qp_type qp_type;
++ int sq_sig_all;
++
++ uint32_t comp_mask;
++ struct ibv_pd *pd;
++ struct ibv_xrcd *xrcd;
++};
++
+ enum ibv_qp_attr_mask {
+ IBV_QP_STATE = 1 << 0,
+ IBV_QP_CUR_STATE = 1 << 1,
+@@ -579,6 +604,11 @@ struct ibv_send_wr {
+ uint32_t remote_qpn;
+ uint32_t remote_qkey;
+ } ud;
++ struct {
++ uint64_t reserved[3];
++ uint32_t reserved2;
++ uint32_t remote_srqn;
++ } xrc;
+ } wr;
+ };
+
+@@ -755,7 +785,8 @@ struct ibv_context {
+ enum verbs_context_mask {
+ VERBS_CONTEXT_XRCD = 1 << 0,
+ VERBS_CONTEXT_SRQ = 1 << 1,
+- VERBS_CONTEXT_RESERVED = 1 << 2
++ VERBS_CONTEXT_QP = 1 << 2,
++ VERBS_CONTEXT_RESERVED = 1 << 3
+ };
+
+ struct verbs_context {
+@@ -763,6 +794,8 @@ struct verbs_context {
+ int (*drv_new_func1) (); new corresponding provider call of func1
+ int (*lib_new_func1) (); New library call func1
+ */
++ struct ibv_qp * (*create_qp_ex)(struct ibv_context *context,
++ struct ibv_qp_init_attr_ex *qp_init_attr_ex);
+ uint32_t (*get_srq_num)(struct ibv_srq *srq);
+ struct ibv_srq * (*create_srq_ex)(struct ibv_context *context,
+ struct ibv_srq_init_attr_ex *srq_init_attr_ex);
+@@ -1123,6 +1156,23 @@ static inline int ibv_post_srq_recv(struct ibv_srq *srq,
+ struct ibv_qp *ibv_create_qp(struct ibv_pd *pd,
+ struct ibv_qp_init_attr *qp_init_attr);
+
++static inline struct ibv_qp *
++ibv_create_qp_ex(struct ibv_context *context, struct ibv_qp_init_attr_ex *qp_init_attr_ex)
++{
++ struct verbs_context *vctx;
++ uint32_t mask = qp_init_attr_ex->comp_mask;
++
++ if (!(mask & ~(IBV_QP_INIT_ATTR_PD)) && (mask & IBV_QP_INIT_ATTR_PD))
++ return ibv_create_qp(qp_init_attr_ex->pd,
++ (struct ibv_qp_init_attr *) qp_init_attr_ex);
++
++ if (!(vctx = verbs_get_ctx_op(context, create_qp_ex))) {
++ errno = ENOSYS;
++ return NULL;
++ }
++ return vctx->create_qp_ex(context, qp_init_attr_ex);
++}
++
+ /**
+ * ibv_modify_qp - Modify a queue pair.
+ */
+diff --git a/src/cmd.c b/src/cmd.c
+index 641ab28..87ac062 100644
+--- a/src/cmd.c
++++ b/src/cmd.c
+@@ -666,6 +666,98 @@ int ibv_cmd_destroy_srq(struct ibv_srq *srq)
+ return 0;
+ }
+
++int ibv_cmd_create_qp_ex(struct ibv_context *context,
++ struct verbs_qp *qp, struct ibv_qp_init_attr_ex *attr_ex,
++ struct ibv_create_qp *cmd, size_t cmd_size,
++ struct ibv_create_qp_resp *resp, size_t resp_size)
++{
++ struct verbs_xrcd *vxrcd = NULL;
++
++ IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_QP, resp, resp_size);
++
++ if (attr_ex->comp_mask >= IBV_QP_INIT_ATTR_RESERVED)
++ return ENOSYS;
++
++ cmd->user_handle = (uintptr_t) qp;
++
++ if (attr_ex->comp_mask & IBV_QP_INIT_ATTR_XRCD) {
++ vxrcd = container_of(attr_ex->xrcd, struct verbs_xrcd, xrcd);
++ cmd->pd_handle = vxrcd->handle;
++ } else {
++ if (!(attr_ex->comp_mask & IBV_QP_INIT_ATTR_PD))
++ return EINVAL;
++
++ cmd->pd_handle = attr_ex->pd->handle;
++ cmd->send_cq_handle = attr_ex->send_cq->handle;
++
++ if (attr_ex->qp_type != IBV_QPT_XRC_SEND) {
++ cmd->recv_cq_handle = attr_ex->recv_cq->handle;
++ cmd->srq_handle = attr_ex->srq ? attr_ex->srq->handle : 0;
++ }
++ }
++
++ cmd->max_send_wr = attr_ex->cap.max_send_wr;
++ cmd->max_recv_wr = attr_ex->cap.max_recv_wr;
++ cmd->max_send_sge = attr_ex->cap.max_send_sge;
++ cmd->max_recv_sge = attr_ex->cap.max_recv_sge;
++ cmd->max_inline_data = attr_ex->cap.max_inline_data;
++ cmd->sq_sig_all = attr_ex->sq_sig_all;
++ cmd->qp_type = attr_ex->qp_type;
++ cmd->is_srq = !!attr_ex->srq;
++ cmd->reserved = 0;
++
++ if (write(context->cmd_fd, cmd, cmd_size) != cmd_size)
++ return errno;
++
++ (void) VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
++
++ if (abi_ver > 3) {
++ attr_ex->cap.max_recv_sge = resp->max_recv_sge;
++ attr_ex->cap.max_send_sge = resp->max_send_sge;
++ attr_ex->cap.max_recv_wr = resp->max_recv_wr;
++ attr_ex->cap.max_send_wr = resp->max_send_wr;
++ attr_ex->cap.max_inline_data = resp->max_inline_data;
++ }
++
++ if (abi_ver == 4) {
++ struct ibv_create_qp_resp_v4 *resp_v4 =
++ (struct ibv_create_qp_resp_v4 *) resp;
++
++ memmove((void *) resp + sizeof *resp,
++ (void *) resp_v4 + sizeof *resp_v4,
++ resp_size - sizeof *resp);
++ } else if (abi_ver <= 3) {
++ struct ibv_create_qp_resp_v3 *resp_v3 =
++ (struct ibv_create_qp_resp_v3 *) resp;
++
++ memmove((void *) resp + sizeof *resp,
++ (void *) resp_v3 + sizeof *resp_v3,
++ resp_size - sizeof *resp);
++ }
++
++ qp->qp.handle = resp->qp_handle;
++ qp->qp.qp_num = resp->qpn;
++ qp->qp.context = context;
++ qp->qp.qp_context = attr_ex->qp_context;
++ qp->qp.pd = attr_ex->pd;
++ qp->qp.send_cq = attr_ex->send_cq;
++ qp->qp.recv_cq = attr_ex->recv_cq;
++ qp->qp.srq = attr_ex->srq;
++ qp->qp.qp_type = attr_ex->qp_type;
++ qp->qp.state = IBV_QPS_RESET;
++ qp->qp.events_completed = 0;
++ pthread_mutex_init(&qp->qp.mutex, NULL);
++ pthread_cond_init(&qp->qp.cond, NULL);
++
++ qp->comp_mask = 0;
++ if (attr_ex->comp_mask & IBV_QP_INIT_ATTR_XRCD) {
++ qp->comp_mask |= VERBS_QP_XRCD;
++ qp->xrcd = vxrcd;
++ }
++
++ return 0;
++}
++
+ int ibv_cmd_create_qp(struct ibv_pd *pd,
+ struct ibv_qp *qp, struct ibv_qp_init_attr *attr,
+ struct ibv_create_qp *cmd, size_t cmd_size,
+@@ -674,7 +766,7 @@ int ibv_cmd_create_qp(struct ibv_pd *pd,
+ IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_QP, resp, resp_size);
+
+ cmd->user_handle = (uintptr_t) qp;
+- cmd->pd_handle = pd->handle;
++ cmd->pd_handle = pd->handle;
+ cmd->send_cq_handle = attr->send_cq->handle;
+ cmd->recv_cq_handle = attr->recv_cq->handle;
+ cmd->srq_handle = attr->srq ? attr->srq->handle : 0;
+diff --git a/src/libibverbs.map b/src/libibverbs.map
+index c8ec645..4249793 100644
+--- a/src/libibverbs.map
++++ b/src/libibverbs.map
+@@ -101,5 +101,6 @@ IBVERBS_1.1 {
+ ibv_cmd_open_xrcd;
+ ibv_cmd_close_xrcd;
+ ibv_cmd_create_srq_ex;
++ ibv_cmd_create_qp_ex;
+
+ } IBVERBS_1.0;