[PATCH rdma-next 2/8] RDMA/mlx5: Refactor raw packet QP rate limit handling
From: Edward Srouji
Date: Sun May 24 2026 - 11:40:01 EST
From: Maher Sanalla <msanalla@xxxxxxxxxx>
Refactor the raw packet QP modify path to extract rate limit
configuration into a qp_rl_parse() helper that parses user attributes,
and a qp_rl_prepare() helper that handles FW rate limit table
adjustments before the SQ modify itself.
Use qp_rl_commit() to commit changes to QP once FW call
succeeds, and qp_rl_rollback() to rollback changes done to
the FW rate limit table in the prepare stage, in case the
modify operation fails.
These helpers will be reused for extending rate limit support to
additional QP types in the following patch.
Signed-off-by: Maher Sanalla <msanalla@xxxxxxxxxx>
Reviewed-by: Michael Guralnik <michaelgur@xxxxxxxxxx>
Signed-off-by: Edward Srouji <edwards@xxxxxxxxxx>
---
drivers/infiniband/hw/mlx5/qp.c | 168 ++++++++++++++++++++++++++--------------
1 file changed, 110 insertions(+), 58 deletions(-)
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 6f88f9c52ad09860474824c88fdc73858045bbd0..fde319a021908317d96f3cdd212ea5ebf691f13a 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -64,12 +64,19 @@ enum {
MLX5_QP_RM_GO_BACK_N = 0x1,
};
+struct mlx5_rate_limit_ctx {
+ struct mlx5_rate_limit rl_old;
+ struct mlx5_rate_limit rl_desired;
+ u16 rl_desired_index;
+ bool rl_changed;
+};
+
struct mlx5_modify_raw_qp_param {
u16 operation;
u32 set_mask; /* raw_qp_set_mask_map */
- struct mlx5_rate_limit rl;
+ struct mlx5_rate_limit_ctx rl_ctx;
u8 rq_q_ctr_id;
u32 port;
@@ -3833,15 +3840,88 @@ static int modify_raw_packet_qp_rq(
return err;
}
+static int qp_rl_parse(struct mlx5_ib_dev *dev,
+ const struct ib_qp_attr *attr,
+ const struct mlx5_ib_modify_qp *ucmd,
+ struct mlx5_rate_limit *rl_desired)
+{
+ rl_desired->rate = attr->rate_limit;
+
+ if (ucmd->burst_info.max_burst_sz) {
+ if (!attr->rate_limit ||
+ !MLX5_CAP_QOS(dev->mdev, packet_pacing_burst_bound))
+ return -EINVAL;
+ rl_desired->max_burst_sz = ucmd->burst_info.max_burst_sz;
+ }
+
+ if (ucmd->burst_info.typical_pkt_sz) {
+ if (!attr->rate_limit ||
+ !MLX5_CAP_QOS(dev->mdev, packet_pacing_typical_size))
+ return -EINVAL;
+ rl_desired->typical_pkt_sz = ucmd->burst_info.typical_pkt_sz;
+ }
+
+ return 0;
+}
+
+static int qp_rl_prepare(struct mlx5_ib_dev *dev,
+ struct mlx5_ib_qp *qp, u16 op,
+ struct mlx5_rate_limit_ctx *ctx)
+{
+ int err;
+
+ ctx->rl_old = qp->rl;
+
+ if (!qp->sq.wqe_cnt)
+ return 0;
+
+ if (op != MLX5_CMD_OP_RTR2RTS_QP &&
+ op != MLX5_CMD_OP_RTS2RTS_QP)
+ return 0;
+
+ ctx->rl_changed = true;
+
+ if (ctx->rl_desired.rate) {
+ err = mlx5_rl_add_rate(dev->mdev, &ctx->rl_desired_index,
+ &ctx->rl_desired);
+ if (err) {
+ pr_err("Failed configuring rate limit(err %d): rate %u, max_burst_sz %u, typical_pkt_sz %u\n",
+ err, ctx->rl_desired.rate,
+ ctx->rl_desired.max_burst_sz,
+ ctx->rl_desired.typical_pkt_sz);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void qp_rl_rollback(struct mlx5_core_dev *dev,
+ struct mlx5_rate_limit_ctx *ctx)
+{
+ if (ctx->rl_desired_index)
+ mlx5_rl_remove_rate(dev, &ctx->rl_desired);
+}
+
+static void qp_rl_commit(struct mlx5_core_dev *dev,
+ struct mlx5_ib_qp *qp,
+ struct mlx5_rate_limit_ctx *ctx)
+{
+ if (!ctx->rl_changed)
+ return;
+
+ if (ctx->rl_old.rate)
+ mlx5_rl_remove_rate(dev, &ctx->rl_old);
+
+ qp->rl = ctx->rl_desired;
+}
+
static int modify_raw_packet_qp_sq(
struct mlx5_core_dev *dev, struct mlx5_ib_sq *sq, int new_state,
const struct mlx5_modify_raw_qp_param *raw_qp_param, struct ib_pd *pd)
{
+ const struct mlx5_rate_limit_ctx *rl_ctx = &raw_qp_param->rl_ctx;
struct mlx5_ib_qp *ibqp = sq->base.container_mibqp;
- struct mlx5_rate_limit old_rl = ibqp->rl;
- struct mlx5_rate_limit new_rl = old_rl;
- bool new_rate_added = false;
- u16 rl_index = 0;
void *in;
void *sqc;
int inlen;
@@ -3859,49 +3939,26 @@ static int modify_raw_packet_qp_sq(
MLX5_SET(sqc, sqc, state, new_state);
if (raw_qp_param->set_mask & MLX5_RAW_QP_RATE_LIMIT) {
- if (new_state != MLX5_SQC_STATE_RDY)
+ if (new_state != MLX5_SQC_STATE_RDY) {
pr_warn("%s: Rate limit can only be changed when SQ is moving to RDY\n",
__func__);
- else
- new_rl = raw_qp_param->rl;
- }
-
- if (!mlx5_rl_are_equal(&old_rl, &new_rl)) {
- if (new_rl.rate) {
- err = mlx5_rl_add_rate(dev, &rl_index, &new_rl);
- if (err) {
- pr_err("Failed configuring rate limit(err %d): \
- rate %u, max_burst_sz %u, typical_pkt_sz %u\n",
- err, new_rl.rate, new_rl.max_burst_sz,
- new_rl.typical_pkt_sz);
-
- goto out;
- }
- new_rate_added = true;
+ } else if (rl_ctx->rl_changed) {
+ MLX5_SET64(modify_sq_in, in, modify_bitmask, 1);
+ /* index 0 means no limit */
+ MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index,
+ rl_ctx->rl_desired_index);
}
-
- MLX5_SET64(modify_sq_in, in, modify_bitmask, 1);
- /* index 0 means no limit */
- MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index, rl_index);
}
err = mlx5_core_modify_sq(dev, sq->base.mqp.qpn, in);
- if (err) {
- /* Remove new rate from table if failed */
- if (new_rate_added)
- mlx5_rl_remove_rate(dev, &new_rl);
+ if (err)
goto out;
- }
- /* Only remove the old rate after new rate was set */
- if ((old_rl.rate && !mlx5_rl_are_equal(&old_rl, &new_rl)) ||
- (new_state != MLX5_SQC_STATE_RDY)) {
- mlx5_rl_remove_rate(dev, &old_rl);
- if (new_state != MLX5_SQC_STATE_RDY)
- memset(&new_rl, 0, sizeof(new_rl));
+ if (new_state != MLX5_SQC_STATE_RDY) {
+ mlx5_rl_remove_rate(dev, &ibqp->rl);
+ memset(&ibqp->rl, 0, sizeof(ibqp->rl));
}
- ibqp->rl = new_rl;
sq->state = new_state;
out:
@@ -4376,34 +4433,29 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
raw_qp_param.port = attr->port_num;
if (attr_mask & IB_QP_RATE_LIMIT) {
- raw_qp_param.rl.rate = attr->rate_limit;
-
- if (ucmd->burst_info.max_burst_sz) {
- if (attr->rate_limit &&
- MLX5_CAP_QOS(dev->mdev, packet_pacing_burst_bound)) {
- raw_qp_param.rl.max_burst_sz =
- ucmd->burst_info.max_burst_sz;
- } else {
- err = -EINVAL;
- goto out;
- }
- }
+ err = qp_rl_parse(dev, qp, attr, ucmd,
+ &raw_qp_param.rl_ctx.rl_desired);
+ if (err)
+ goto out;
- if (ucmd->burst_info.typical_pkt_sz) {
- if (attr->rate_limit &&
- MLX5_CAP_QOS(dev->mdev, packet_pacing_typical_size)) {
- raw_qp_param.rl.typical_pkt_sz =
- ucmd->burst_info.typical_pkt_sz;
- } else {
- err = -EINVAL;
+ if (!mlx5_rl_are_equal(&raw_qp_param.rl_ctx.rl_desired,
+ &qp->rl)) {
+ err = qp_rl_prepare(dev, qp, op,
+ &raw_qp_param.rl_ctx);
+ if (err)
goto out;
- }
}
raw_qp_param.set_mask |= MLX5_RAW_QP_RATE_LIMIT;
}
err = modify_raw_packet_qp(dev, qp, &raw_qp_param, tx_affinity);
+ if (err) {
+ qp_rl_rollback(dev->mdev, &raw_qp_param.rl_ctx);
+ goto out;
+ }
+
+ qp_rl_commit(dev->mdev, qp, &raw_qp_param.rl_ctx);
} else {
if (udata) {
/* For the kernel flows, the resp will stay zero */
--
2.49.0