@@ -72,12 +72,24 @@ struct mlx4_create_cq {
__u64 db_addr;
};
+struct mlx4_create_cq_ex {
+ struct ibv_create_cq_ex ibv_cmd;
+ __u64 buf_addr;
+ __u64 db_addr;
+};
+
struct mlx4_create_cq_resp {
struct ibv_create_cq_resp ibv_resp;
__u32 cqn;
__u32 reserved;
};
+struct mlx4_create_cq_resp_ex {
+ struct ibv_create_cq_resp_ex ibv_resp;
+ __u32 cqn;
+ __u32 reserved;
+};
+
struct mlx4_resize_cq {
struct ibv_resize_cq ibv_cmd;
__u64 buf_addr;
@@ -208,6 +208,7 @@ static int mlx4_init_context(struct verbs_device *v_device,
verbs_set_ctx_op(verbs_ctx, ibv_create_flow, ibv_cmd_create_flow);
verbs_set_ctx_op(verbs_ctx, ibv_destroy_flow, ibv_cmd_destroy_flow);
verbs_set_ctx_op(verbs_ctx, query_device_ex, mlx4_query_device_ex);
+ verbs_set_ctx_op(verbs_ctx, create_cq_ex, mlx4_create_cq_ex);
return 0;
@@ -222,6 +222,7 @@ struct mlx4_cq {
uint32_t *arm_db;
int arm_sn;
int cqe_size;
+ int creation_flags;
};
struct mlx4_srq {
@@ -402,6 +403,8 @@ int mlx4_dereg_mr(struct ibv_mr *mr);
struct ibv_cq *mlx4_create_cq(struct ibv_context *context, int cqe,
struct ibv_comp_channel *channel,
int comp_vector);
+struct ibv_cq *mlx4_create_cq_ex(struct ibv_context *context,
+ struct ibv_create_cq_attr_ex *cq_attr);
int mlx4_alloc_cq_buf(struct mlx4_device *dev, struct mlx4_buf *buf, int nent,
int entry_size);
int mlx4_resize_cq(struct ibv_cq *cq, int cqe);
@@ -272,19 +272,69 @@ int align_queue_size(int req)
return nent;
}
-struct ibv_cq *mlx4_create_cq(struct ibv_context *context, int cqe,
- struct ibv_comp_channel *channel,
- int comp_vector)
+enum cmd_type {
+ MLX4_CMD_TYPE_BASIC,
+ MLX4_CMD_TYPE_EXTENDED
+};
+
+enum {
+ CREATE_CQ_SUPPORTED_COMP_MASK = IBV_CREATE_CQ_ATTR_FLAGS
+};
+
+enum {
+ CREATE_CQ_SUPPORTED_FLAGS = IBV_CREATE_CQ_ATTR_COMPLETION_TIMESTAMP
+};
+
+enum {
+ CREATE_CQ_SUPPORTED_WC_FLAGS = IBV_WC_STANDARD_FLAGS
+};
+
+static struct ibv_cq *create_cq(struct ibv_context *context,
+ struct ibv_create_cq_attr_ex *cq_attr,
+ enum cmd_type cmd_type)
{
- struct mlx4_create_cq cmd;
- struct mlx4_create_cq_resp resp;
- struct mlx4_cq *cq;
- int ret;
- struct mlx4_context *mctx = to_mctx(context);
+ struct mlx4_create_cq cmd;
+ struct mlx4_create_cq_ex cmd_e;
+ struct mlx4_create_cq_resp resp;
+ struct mlx4_create_cq_resp_ex resp_e;
+ struct mlx4_cq *cq;
+ int ret;
+ struct mlx4_context *mctx = to_mctx(context);
+ struct ibv_create_cq_attr_ex cq_attr_e;
+ int cqe;
/* Sanity check CQ size before proceeding */
- if (cqe > 0x3fffff)
+ if (cq_attr->cqe > 0x3fffff)
+ return NULL;
+
+ if (cq_attr->comp_mask & ~CREATE_CQ_SUPPORTED_COMP_MASK) {
+ errno = EINVAL;
return NULL;
+ }
+
+ if (cq_attr->comp_mask & IBV_CREATE_CQ_ATTR_FLAGS &&
+ cq_attr->flags & ~CREATE_CQ_SUPPORTED_FLAGS) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (cq_attr->wc_flags & ~CREATE_CQ_SUPPORTED_WC_FLAGS) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+
+ if (!(cq_attr->wc_flags & IBV_WC_EX_WITH_COMPLETION_TIMESTAMP) !=
+ !(cq_attr->comp_mask & IBV_CREATE_CQ_ATTR_FLAGS &&
+ cq_attr->flags & IBV_CREATE_CQ_ATTR_COMPLETION_TIMESTAMP)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (cq_attr->wc_flags & IBV_WC_EX_WITH_COMPLETION_TIMESTAMP &&
+ cq_attr->wc_flags & (IBV_WC_EX_WITH_SL | IBV_WC_EX_WITH_SLID)) {
+ errno = EOPNOTSUPP;
+ return NULL;
+ }
cq = malloc(sizeof *cq);
if (!cq)
@@ -295,9 +345,11 @@ struct ibv_cq *mlx4_create_cq(struct ibv_context *context, int cqe,
if (pthread_spin_init(&cq->lock, PTHREAD_PROCESS_PRIVATE))
goto err;
- cqe = align_queue_size(cqe + 1);
+ cq_attr_e = *cq_attr;
+ cqe = align_queue_size(cq_attr->cqe + 1);
- if (mlx4_alloc_cq_buf(to_mdev(context->device), &cq->buf, cqe, mctx->cqe_size))
+ if (mlx4_alloc_cq_buf(to_mdev(context->device), &cq->buf, cqe,
+ mctx->cqe_size))
goto err;
cq->cqe_size = mctx->cqe_size;
@@ -310,15 +362,31 @@ struct ibv_cq *mlx4_create_cq(struct ibv_context *context, int cqe,
cq->arm_sn = 1;
*cq->set_ci_db = 0;
- cmd.buf_addr = (uintptr_t) cq->buf.buf;
- cmd.db_addr = (uintptr_t) cq->set_ci_db;
+ if (cmd_type == MLX4_CMD_TYPE_BASIC) {
+ cmd.buf_addr = (uintptr_t)cq->buf.buf;
+ cmd.db_addr = (uintptr_t)cq->set_ci_db;
+
+ ret = ibv_cmd_create_cq(context, cqe - 1,
+ cq_attr_e.channel, cq_attr_e.comp_vector,
+ &cq->ibv_cq, &cmd.ibv_cmd, sizeof(cmd),
+ &resp.ibv_resp, sizeof(resp));
+ } else {
+ cmd_e.buf_addr = (uintptr_t)cq->buf.buf;
+ cmd_e.db_addr = (uintptr_t)cq->set_ci_db;
+
+ cq_attr_e.cqe = cqe - 1;
+ ret = ibv_cmd_create_cq_ex(context, &cq_attr_e, &cq->ibv_cq,
+ &cmd_e.ibv_cmd,
+ sizeof(cmd_e.ibv_cmd), sizeof(cmd_e),
+ &resp_e.ibv_resp,
+ sizeof(resp_e.ibv_resp),
+ sizeof(resp_e));
+ }
- ret = ibv_cmd_create_cq(context, cqe - 1, channel, comp_vector,
- &cq->ibv_cq, &cmd.ibv_cmd, sizeof cmd,
- &resp.ibv_resp, sizeof resp);
if (ret)
goto err_db;
+ cq->creation_flags = cmd_e.ibv_cmd.flags;
cq->cqn = resp.cqn;
return &cq->ibv_cq;
@@ -335,6 +403,23 @@ err:
return NULL;
}
+struct ibv_cq *mlx4_create_cq(struct ibv_context *context, int cqe,
+ struct ibv_comp_channel *channel,
+ int comp_vector)
+{
+ struct ibv_create_cq_attr_ex attr = {.cqe = cqe, .channel = channel,
+ .comp_vector = comp_vector,
+ .wc_flags = IBV_WC_STANDARD_FLAGS};
+
+ return create_cq(context, &attr, MLX4_CMD_TYPE_BASIC);
+}
+
+struct ibv_cq *mlx4_create_cq_ex(struct ibv_context *context,
+ struct ibv_create_cq_attr_ex *cq_attr)
+{
+ return create_cq(context, cq_attr, MLX4_CMD_TYPE_EXTENDED);
+}
+
int mlx4_resize_cq(struct ibv_cq *ibcq, int cqe)
{
struct mlx4_cq *cq = to_mcq(ibcq);
Add an extension verb mlx4_create_cq_ex that follows the standard extension verb mechanism. This function is similar to mlx4_create_cq but supports the extension verbs functions and stores the creation flags for later use (for example, timestamp flag is used in poll_cq). The function fails if the user passes unsupported WC attributes. Signed-off-by: Matan Barak <matanb@mellanox.com> --- src/mlx4-abi.h | 12 ++++++ src/mlx4.c | 1 + src/mlx4.h | 3 ++ src/verbs.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 117 insertions(+), 16 deletions(-)