Skip to content

Commit acca72e

Browse files
Yuval Bassonjgunthorpe
authored andcommitted
RDMA/qedr: SRQ's bug fixes
QP's with the same SRQ, working on different CQs and running in parallel on different CPUs could lead to a race when maintaining the SRQ consumer count, and leads to FW running out of SRQs. Update the consumer atomically. Make sure the wqe_prod is updated after the sge_prod due to FW requirements. Fixes: 3491c9e ("qedr: Add support for kernel mode SRQ's") Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michal Kalderon <[email protected]> Signed-off-by: Yuval Basson <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 317000b commit acca72e

File tree

2 files changed

+12
-14
lines changed

2 files changed

+12
-14
lines changed

drivers/infiniband/hw/qedr/qedr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,10 @@ struct qedr_srq_hwq_info {
344344
u32 wqe_prod;
345345
u32 sge_prod;
346346
u32 wr_prod_cnt;
347-
u32 wr_cons_cnt;
347+
atomic_t wr_cons_cnt;
348348
u32 num_elems;
349349

350-
u32 *virt_prod_pair_addr;
350+
struct rdma_srq_producers *virt_prod_pair_addr;
351351
dma_addr_t phy_prod_pair_addr;
352352
};
353353

drivers/infiniband/hw/qedr/verbs.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3686,7 +3686,7 @@ static u32 qedr_srq_elem_left(struct qedr_srq_hwq_info *hw_srq)
36863686
* count and consumer count and subtract it from max
36873687
* work request supported so that we get elements left.
36883688
*/
3689-
used = hw_srq->wr_prod_cnt - hw_srq->wr_cons_cnt;
3689+
used = hw_srq->wr_prod_cnt - (u32)atomic_read(&hw_srq->wr_cons_cnt);
36903690

36913691
return hw_srq->max_wr - used;
36923692
}
@@ -3701,7 +3701,6 @@ int qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
37013701
unsigned long flags;
37023702
int status = 0;
37033703
u32 num_sge;
3704-
u32 offset;
37053704

37063705
spin_lock_irqsave(&srq->lock, flags);
37073706

@@ -3714,7 +3713,8 @@ int qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
37143713
if (!qedr_srq_elem_left(hw_srq) ||
37153714
wr->num_sge > srq->hw_srq.max_sges) {
37163715
DP_ERR(dev, "Can't post WR (%d,%d) || (%d > %d)\n",
3717-
hw_srq->wr_prod_cnt, hw_srq->wr_cons_cnt,
3716+
hw_srq->wr_prod_cnt,
3717+
atomic_read(&hw_srq->wr_cons_cnt),
37183718
wr->num_sge, srq->hw_srq.max_sges);
37193719
status = -ENOMEM;
37203720
*bad_wr = wr;
@@ -3748,22 +3748,20 @@ int qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
37483748
hw_srq->sge_prod++;
37493749
}
37503750

3751-
/* Flush WQE and SGE information before
3751+
/* Update WQE and SGE information before
37523752
* updating producer.
37533753
*/
3754-
wmb();
3754+
dma_wmb();
37553755

37563756
/* SRQ producer is 8 bytes. Need to update SGE producer index
37573757
* in first 4 bytes and need to update WQE producer in
37583758
* next 4 bytes.
37593759
*/
3760-
*srq->hw_srq.virt_prod_pair_addr = hw_srq->sge_prod;
3761-
offset = offsetof(struct rdma_srq_producers, wqe_prod);
3762-
*((u8 *)srq->hw_srq.virt_prod_pair_addr + offset) =
3763-
hw_srq->wqe_prod;
3760+
srq->hw_srq.virt_prod_pair_addr->sge_prod = hw_srq->sge_prod;
3761+
/* Make sure sge producer is updated first */
3762+
dma_wmb();
3763+
srq->hw_srq.virt_prod_pair_addr->wqe_prod = hw_srq->wqe_prod;
37643764

3765-
/* Flush producer after updating it. */
3766-
wmb();
37673765
wr = wr->next;
37683766
}
37693767

@@ -4182,7 +4180,7 @@ static int process_resp_one_srq(struct qedr_dev *dev, struct qedr_qp *qp,
41824180
} else {
41834181
__process_resp_one(dev, qp, cq, wc, resp, wr_id);
41844182
}
4185-
srq->hw_srq.wr_cons_cnt++;
4183+
atomic_inc(&srq->hw_srq.wr_cons_cnt);
41864184

41874185
return 1;
41884186
}

0 commit comments

Comments
 (0)