]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
RDMA/hns: Fix wrong WQE data when QP wraps around
authorJunxian Huang <huangjunxian6@hisilicon.com>
Thu, 16 Oct 2025 11:40:50 +0000 (19:40 +0800)
committerLeon Romanovsky <leon@kernel.org>
Mon, 27 Oct 2025 09:44:00 +0000 (05:44 -0400)
When QP wraps around, WQE data from the previous use at the same
position still remains as driver does not clear it. The WQE field
layout differs across different opcodes, causing that the fields
that are not explicitly assigned for the current opcode retain
stale values, and are issued to HW by mistake. Such fields are as
follows:

* MSG_START_SGE_IDX field in ATOMIC WQE
* BLOCK_SIZE and ZBVA fields in FRMR WQE
* DirectWQE fields when DirectWQE not used

For ATOMIC WQE, always set the latest sge index in MSG_START_SGE_IDX
as required by HW.

For FRMR WQE and DirectWQE, clear only those unassigned fields
instead of the entire WQE to avoid performance penalty.

Fixes: 68a997c5d28c ("RDMA/hns: Add FRMR support for hip08")
Signed-off-by: Junxian Huang <huangjunxian6@hisilicon.com>
Link: https://patch.msgid.link/20251016114051.1963197-4-huangjunxian6@hisilicon.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
drivers/infiniband/hw/hns/hns_roce_hw_v2.c

index f82bdd46a9174a75faaba383c7b85567e8659695..ab378525b296ac8d1d63b1e223be681ec12ca618 100644 (file)
@@ -165,6 +165,8 @@ static void set_frmr_seg(struct hns_roce_v2_rc_send_wqe *rc_sq_wqe,
        hr_reg_write(fseg, FRMR_PBL_BUF_PG_SZ,
                     to_hr_hw_page_shift(mr->pbl_mtr.hem_cfg.buf_pg_shift));
        hr_reg_clear(fseg, FRMR_BLK_MODE);
+       hr_reg_clear(fseg, FRMR_BLOCK_SIZE);
+       hr_reg_clear(fseg, FRMR_ZBVA);
 }
 
 static void set_atomic_seg(const struct ib_send_wr *wr,
@@ -339,9 +341,6 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr,
        int j = 0;
        int i;
 
-       hr_reg_write(rc_sq_wqe, RC_SEND_WQE_MSG_START_SGE_IDX,
-                    (*sge_ind) & (qp->sge.sge_cnt - 1));
-
        hr_reg_write(rc_sq_wqe, RC_SEND_WQE_INLINE,
                     !!(wr->send_flags & IB_SEND_INLINE));
        if (wr->send_flags & IB_SEND_INLINE)
@@ -586,6 +585,9 @@ static inline int set_rc_wqe(struct hns_roce_qp *qp,
        hr_reg_write(rc_sq_wqe, RC_SEND_WQE_CQE,
                     (wr->send_flags & IB_SEND_SIGNALED) ? 1 : 0);
 
+       hr_reg_write(rc_sq_wqe, RC_SEND_WQE_MSG_START_SGE_IDX,
+                    curr_idx & (qp->sge.sge_cnt - 1));
+
        if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
            wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
                if (msg_len != ATOMIC_WR_LEN)
@@ -734,6 +736,9 @@ static int hns_roce_v2_post_send(struct ib_qp *ibqp,
                owner_bit =
                       ~(((qp->sq.head + nreq) >> ilog2(qp->sq.wqe_cnt)) & 0x1);
 
+               /* RC and UD share the same DirectWQE field layout */
+               ((struct hns_roce_v2_rc_send_wqe *)wqe)->byte_4 = 0;
+
                /* Corresponding to the QP type, wqe process separately */
                if (ibqp->qp_type == IB_QPT_RC)
                        ret = set_rc_wqe(qp, wr, wqe, &sge_idx, owner_bit);