verbs/mlx5: Expose tag matching capabilities

[PATCH 23/31] FreeBSD OFED support for DPDK MLX5 PMD

a) Expose tag matching capabilities and show them in ibv_devinfo.

b) verbs: Introduce tag matching SRQ
Introducing tag matching SRQ (TM-SRQ), which retains basic semantic of
regular SRQ, reports completions to own CQ, and has additional tag
based message receiving mechanism.
Detailed description for the TM-SRQ usage was added into
Documentation/tag_matching.md

c) mlx5: Add support to tag matching SRQ type
Create command QP for a tag-matching SRQ. Command QP used for
inserting/removing entries from the tag matching list. This command QP
is hidden from the users in the mlx5_srq structure.
New verb ibv_post_srq_ops() will be added in next patch to use it.

Differential revision:	https://reviews.freebsd.org/D32198
MFC after:	1 month
This commit is contained in:
Vag Singh authored and Konstantin Belousov committed 2026-09-16 17:12:09 +03:00
1 parent 0bf5db3ac9
commit 4601cb6295
8 files changed
+237 -21

No files matched your search

+28
View File
@@ -237,6 +237,23 @@ int ibv_cmd_query_device_ex(struct ibv_context *context,
attr->raw_packet_caps = resp->raw_packet_caps;
}
if (attr_size >= offsetof(struct ibv_device_attr_ex, tm_caps) +
sizeof(attr->tm_caps)) {
if (resp->response_length >=
offsetof(struct ibv_query_device_resp_ex, tm_caps) +
sizeof(resp->tm_caps)) {
attr->tm_caps.max_rndv_hdr_size =
resp->tm_caps.max_rndv_hdr_size;
attr->tm_caps.max_num_tags =
resp->tm_caps.max_num_tags;
attr->tm_caps.flags = resp->tm_caps.flags;
attr->tm_caps.max_ops =
resp->tm_caps.max_ops;
attr->tm_caps.max_sge =
resp->tm_caps.max_sge;
}
}
return 0;
}
@@ -703,6 +720,17 @@ int ibv_cmd_create_srq_ex(struct ibv_context *context,
vxrcd = container_of(attr_ex->xrcd, struct verbs_xrcd, xrcd);
cmd->xrcd_handle = vxrcd->handle;
cmd->cq_handle = attr_ex->cq->handle;
} else if (attr_ex->comp_mask & IBV_SRQ_INIT_ATTR_TM) {
if (cmd->srq_type != IBV_SRQT_TM)
return EINVAL;
if (!(attr_ex->comp_mask & IBV_SRQ_INIT_ATTR_CQ) ||
!attr_ex->tm_cap.max_num_tags)
return EINVAL;
cmd->cq_handle = attr_ex->cq->handle;
cmd->max_num_tags = attr_ex->tm_cap.max_num_tags;
} else if (cmd->srq_type != IBV_SRQT_BASIC) {
return EINVAL;
}
ret = pthread_mutex_init(&srq->srq.mutex, NULL);
@@ -343,6 +343,22 @@ static void print_device_cap_flags_ex(uint64_t device_cap_flags_ex)
ex_flags & unknown_flags);
}
static void print_tm_caps(const struct ibv_tm_caps *caps)
{
if (caps->max_num_tags) {
printf("\tmax_rndv_hdr_size:\t\t%u\n",
caps->max_rndv_hdr_size);
printf("\tmax_num_tags:\t\t\t%u\n", caps->max_num_tags);
printf("\tmax_ops:\t\t\t%u\n", caps->max_ops);
printf("\tmax_sge:\t\t\t%u\n", caps->max_sge);
printf("\tflags:\n");
if (caps->flags & IBV_TM_CAP_RC)
printf("\t\t\t\t\tIBV_TM_CAP_RC\n");
} else {
printf("\ttag matching not supported\n");
}
}
static void print_tso_caps(const struct ibv_tso_caps *caps)
{
uint32_t unknown_general_caps = ~(1 << IBV_QPT_RAW_PACKET |
@@ -522,6 +538,7 @@ static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port)
print_rss_caps(&device_attr.rss_caps);
printf("\tmax_wq_type_rq:\t\t\t%u\n", device_attr.max_wq_type_rq);
print_packet_pacing_caps(&device_attr.packet_pacing_caps);
print_tm_caps(&device_attr.tm_caps);
}
for (port = 1; port <= device_attr.orig_attr.phys_port_cnt; ++port) {
+11 -1
View File
@@ -280,6 +280,15 @@ struct ibv_rss_caps_resp {
__u32 reserved;
};
struct ibv_tm_caps_resp {
__u32 max_rndv_hdr_size;
__u32 max_num_tags;
__u32 flags;
__u32 max_ops;
__u32 max_sge;
__u32 reserved;
};
struct ibv_query_device_resp_ex {
struct ibv_query_device_resp base;
__u32 comp_mask;
@@ -291,6 +300,7 @@ struct ibv_query_device_resp_ex {
struct ibv_rss_caps_resp rss_caps;
__u32 max_wq_type_rq;
__u32 raw_packet_caps;
struct ibv_tm_caps_resp tm_caps;
};
struct ibv_query_port {
@@ -1116,7 +1126,7 @@ struct ibv_create_xsrq {
__u32 max_wr;
__u32 max_sge;
__u32 srq_limit;
__u32 reserved;
__u32 max_num_tags;
__u32 xrcd_handle;
__u32 cq_handle;
__u64 driver_data[0];
@@ -26,10 +26,11 @@ struct ibv_srq_init_attr_ex {
void *srq_context; /* Associated context of the SRQ */
struct ibv_srq_attr attr; /* SRQ attributes */
uint32_t comp_mask; /* Identifies valid fields */
enum ibv_srq_type srq_type; /* Basic / XRC */
enum ibv_srq_type srq_type; /* Basic / XRC / tag matching */
struct ibv_pd *pd; /* PD associated with the SRQ */
struct ibv_xrcd *xrcd; /* XRC domain to associate with the SRQ */
struct ibv_cq *cq; /* CQ to associate with the SRQ for XRC mode */
struct ibv_tm_cap tm_cap; /* Tag matching attributes */
.in -8
};
.sp
@@ -41,6 +42,16 @@ uint32_t max_sge; /* Requested max number of scatter eleme
uint32_t srq_limit; /* The limit value of the SRQ */
.in -8
};
.sp
.nf
struct ibv_tm_cap {
.in +8
uint32_t max_num_tags; /* Tag matching list size */
uint32_t max_ops; /* Number of outstanding tag list operations */
.in -8
};
.sp
.nf
.fi
.PP
The function
@@ -33,6 +33,7 @@ struct ibv_rss_caps rss_caps; /* RSS capabilities */
uint32_t max_wq_type_rq; /* Max Work Queue from type RQ */
struct ibv_packet_pacing_caps packet_pacing_caps; /* Packet pacing capabilities */
uint32_t raw_packet_caps; /* Raw packet capabilities, use enum ibv_raw_packet_caps */
struct ibv_tm_caps tm_caps; /* Tag matching capabilities */
.in -8
};
@@ -84,6 +85,22 @@ IBV_RAW_PACKET_CAP_IP_CSUM = 1 << 2, /* IP CSUM offload is supported */
.in -8
};
enum ibv_tm_cap_flags {
.in +8
IBV_TM_CAP_RC = 1 << 0, /* Support tag matching on RC transport */
.in -8
};
struct ibv_tm_caps {
.in +8
uint32_t max_rndv_hdr_size; /* Max size of rendezvous request header */
uint32_t max_num_tags; /* Max number of tagged buffers in a TM-SRQ matching list */
uint32_t flags; /* From enum ibv_tm_cap_flags */
uint32_t max_ops; /* Max number of outstanding list operations */
uint32_t max_sge; /* Max number of SGEs in a tagged buffer */
.in -8
};
.fi
.SH "RETURN VALUE"
.B ibv_query_device_ex()
+28 -2
View File
@@ -259,6 +259,23 @@ enum ibv_raw_packet_caps {
IBV_RAW_PACKET_CAP_IP_CSUM = 1 << 2,
};
enum ibv_tm_cap_flags {
IBV_TM_CAP_RC = 1 << 0,
};
struct ibv_tm_caps {
/* Max size of rendezvous request header */
uint32_t max_rndv_hdr_size;
/* Max number of tagged buffers in a TM-SRQ matching list */
uint32_t max_num_tags;
/* From enum ibv_tm_cap_flags */
uint32_t flags;
/* Max number of outstanding list operations */
uint32_t max_ops;
/* Max number of SGEs in a tagged buffer */
uint32_t max_sge;
};
struct ibv_device_attr_ex {
struct ibv_device_attr orig_attr;
uint32_t comp_mask;
@@ -271,6 +288,7 @@ struct ibv_device_attr_ex {
uint32_t max_wq_type_rq;
struct ibv_packet_pacing_caps packet_pacing_caps;
uint32_t raw_packet_caps; /* Use ibv_raw_packet_caps */
struct ibv_tm_caps tm_caps;
};
enum ibv_mtu {
@@ -654,7 +672,8 @@ struct ibv_srq_init_attr {
enum ibv_srq_type {
IBV_SRQT_BASIC,
IBV_SRQT_XRC
IBV_SRQT_XRC,
IBV_SRQT_TM,
};
enum ibv_srq_init_attr_mask {
@@ -662,7 +681,13 @@ enum ibv_srq_init_attr_mask {
IBV_SRQ_INIT_ATTR_PD = 1 << 1,
IBV_SRQ_INIT_ATTR_XRCD = 1 << 2,
IBV_SRQ_INIT_ATTR_CQ = 1 << 3,
IBV_SRQ_INIT_ATTR_RESERVED = 1 << 4
IBV_SRQ_INIT_ATTR_TM = 1 << 4,
IBV_SRQ_INIT_ATTR_RESERVED = 1 << 5,
};
struct ibv_tm_cap {
uint32_t max_num_tags;
uint32_t max_ops;
};
struct ibv_srq_init_attr_ex {
@@ -674,6 +699,7 @@ struct ibv_srq_init_attr_ex {
struct ibv_pd *pd;
struct ibv_xrcd *xrcd;
struct ibv_cq *cq;
struct ibv_tm_cap tm_cap;
};
enum ibv_wq_type {
+1
View File
@@ -360,6 +360,7 @@ struct mlx5_srq {
__be32 *db;
uint16_t counter;
int wq_sig;
struct ibv_qp *cmd_qp;
};
struct wr_list {
+123 -17
View File
@@ -752,6 +752,13 @@ int mlx5_destroy_srq(struct ibv_srq *srq)
struct mlx5_srq *msrq = to_msrq(srq);
struct mlx5_context *ctx = to_mctx(srq->context);
if (msrq->cmd_qp) {
ret = mlx5_destroy_qp(msrq->cmd_qp);
if (ret)
return ret;
msrq->cmd_qp = NULL;
}
ret = ibv_cmd_destroy_srq(srq);
if (ret)
return ret;
@@ -1816,9 +1823,94 @@ int mlx5_close_xrcd(struct ibv_xrcd *ib_xrcd)
return ret;
}
static struct ibv_srq *
mlx5_create_xrc_srq(struct ibv_context *context,
struct ibv_srq_init_attr_ex *attr)
static struct ibv_qp *
create_cmd_qp(struct ibv_context *context,
struct ibv_srq_init_attr_ex *srq_attr,
struct ibv_srq *srq)
{
struct ibv_qp_init_attr_ex init_attr = {};
FILE *fp = to_mctx(context)->dbg_fp;
struct ibv_port_attr port_attr;
struct ibv_modify_qp qcmd = {};
struct ibv_qp_attr attr = {};
struct ibv_query_port pcmd;
struct ibv_qp *qp;
int attr_mask;
int port = 1;
int ret;
ret = ibv_cmd_query_port(context, port, &port_attr,
&pcmd, sizeof(pcmd));
if (ret) {
mlx5_dbg(fp, MLX5_DBG_QP, "ret %d\n", ret);
return NULL;
}
init_attr.qp_type = IBV_QPT_RC;
init_attr.srq = srq;
/* Command QP will be used to pass MLX5_OPCODE_TAG_MATCHING messages
* to add/remove tag matching list entries.
* WQ size is based on max_ops parameter holding max number of
* outstanding list operations.
*/
init_attr.cap.max_send_wr = srq_attr->tm_cap.max_ops;
/* Tag matching list entry will point to a single sge buffer */
init_attr.cap.max_send_sge = 1;
init_attr.comp_mask = IBV_QP_INIT_ATTR_PD;
init_attr.pd = srq_attr->pd;
init_attr.send_cq = srq_attr->cq;
init_attr.recv_cq = srq_attr->cq;
qp = create_qp(context, &init_attr);
if (!qp)
return NULL;
attr.qp_state = IBV_QPS_INIT;
attr.port_num = port;
attr_mask = IBV_QP_STATE | IBV_QP_PKEY_INDEX
| IBV_QP_PORT | IBV_QP_ACCESS_FLAGS;
ret = ibv_cmd_modify_qp(qp, &attr, attr_mask, &qcmd, sizeof(qcmd));
if (ret) {
mlx5_dbg(fp, MLX5_DBG_QP, "ret %d\n", ret);
goto err;
}
attr.qp_state = IBV_QPS_RTR;
attr.path_mtu = IBV_MTU_256;
attr.dest_qp_num = qp->qp_num; /* Loopback */
attr.ah_attr.dlid = port_attr.lid;
attr.ah_attr.port_num = port;
attr_mask = IBV_QP_STATE | IBV_QP_AV | IBV_QP_PATH_MTU
| IBV_QP_DEST_QPN | IBV_QP_RQ_PSN
| IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER;
ret = ibv_cmd_modify_qp(qp, &attr, attr_mask, &qcmd, sizeof(qcmd));
if (ret) {
mlx5_dbg(fp, MLX5_DBG_QP, "ret %d\n", ret);
goto err;
}
attr.qp_state = IBV_QPS_RTS;
attr_mask = IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT
| IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN
| IBV_QP_MAX_QP_RD_ATOMIC;
ret = ibv_cmd_modify_qp(qp, &attr, attr_mask, &qcmd, sizeof(qcmd));
if (ret) {
mlx5_dbg(fp, MLX5_DBG_QP, "ret %d\n", ret);
goto err;
}
return qp;
err:
mlx5_destroy_qp(qp);
return NULL;
}
struct ibv_srq *mlx5_create_srq_ex(struct ibv_context *context,
struct ibv_srq_init_attr_ex *attr)
{
int err;
struct mlx5_create_srq_ex cmd;
@@ -1830,6 +1922,24 @@ mlx5_create_xrc_srq(struct ibv_context *context,
int uidx;
FILE *fp = ctx->dbg_fp;
if (!(attr->comp_mask & IBV_SRQ_INIT_ATTR_TYPE) ||
(attr->srq_type == IBV_SRQT_BASIC))
return mlx5_create_srq(attr->pd,
(struct ibv_srq_init_attr *)attr);
if (attr->srq_type != IBV_SRQT_XRC &&
attr->srq_type != IBV_SRQT_TM) {
errno = EINVAL;
return NULL;
}
/* An extended CQ is required to read TM information from */
if (attr->srq_type == IBV_SRQT_TM &&
!(attr->cq && (to_mcq(attr->cq)->flags & MLX5_CQ_FLAGS_EXTENDED))) {
errno = EINVAL;
return NULL;
}
msrq = calloc(1, sizeof(*msrq));
if (!msrq)
return NULL;
@@ -1908,10 +2018,16 @@ mlx5_create_xrc_srq(struct ibv_context *context,
if (err)
goto err_free_uidx;
if (attr->srq_type == IBV_SRQT_TM) {
msrq->cmd_qp = create_cmd_qp(context, attr, ibsrq);
if (!msrq->cmd_qp)
goto err_destroy;
}
if (!ctx->cqe_version) {
err = mlx5_store_srq(to_mctx(context), resp.srqn, msrq);
if (err)
goto err_destroy;
goto err_free_cmd;
pthread_mutex_unlock(&ctx->srq_table_mutex);
}
@@ -1922,6 +2038,9 @@ mlx5_create_xrc_srq(struct ibv_context *context,
return ibsrq;
err_free_cmd:
if (msrq->cmd_qp)
mlx5_destroy_qp(msrq->cmd_qp);
err_destroy:
ibv_cmd_destroy_srq(ibsrq);
@@ -1947,19 +2066,6 @@ err:
return NULL;
}
struct ibv_srq *mlx5_create_srq_ex(struct ibv_context *context,
struct ibv_srq_init_attr_ex *attr)
{
if (!(attr->comp_mask & IBV_SRQ_INIT_ATTR_TYPE) ||
(attr->srq_type == IBV_SRQT_BASIC))
return mlx5_create_srq(attr->pd,
(struct ibv_srq_init_attr *)attr);
else if (attr->srq_type == IBV_SRQT_XRC)
return mlx5_create_xrc_srq(context, attr);
return NULL;
}
int mlx5_query_device_ex(struct ibv_context *context,
const struct ibv_query_device_ex_input *input,
struct ibv_device_attr_ex *attr,