Skip to content

Commit 3383a99

Browse files
Yuval Bassongregkh
authored andcommitted
RDMA/qedr: SRQ's bug fixes
[ Upstream commit acca72e ] 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/20200708195526.31040-1-ybason@marvell.com Signed-off-by: Michal Kalderon <mkalderon@marvell.com> Signed-off-by: Yuval Basson <ybason@marvell.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent dbc374d commit 3383a99

2 files changed

Lines changed: 12 additions & 14 deletions

File tree

drivers/infiniband/hw/qedr/qedr.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,10 @@ struct qedr_srq_hwq_info {
351351
u32 wqe_prod;
352352
u32 sge_prod;
353353
u32 wr_prod_cnt;
354-
u32 wr_cons_cnt;
354+
atomic_t wr_cons_cnt;
355355
u32 num_elems;
356356

357-
u32 *virt_prod_pair_addr;
357+
struct rdma_srq_producers *virt_prod_pair_addr;
358358
dma_addr_t phy_prod_pair_addr;
359359
};
360360

drivers/infiniband/hw/qedr/verbs.c

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

35823582
return hw_srq->max_wr - used;
35833583
}
@@ -3592,7 +3592,6 @@ int qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
35923592
unsigned long flags;
35933593
int status = 0;
35943594
u32 num_sge;
3595-
u32 offset;
35963595

35973596
spin_lock_irqsave(&srq->lock, flags);
35983597

@@ -3605,7 +3604,8 @@ int qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
36053604
if (!qedr_srq_elem_left(hw_srq) ||
36063605
wr->num_sge > srq->hw_srq.max_sges) {
36073606
DP_ERR(dev, "Can't post WR (%d,%d) || (%d > %d)\n",
3608-
hw_srq->wr_prod_cnt, hw_srq->wr_cons_cnt,
3607+
hw_srq->wr_prod_cnt,
3608+
atomic_read(&hw_srq->wr_cons_cnt),
36093609
wr->num_sge, srq->hw_srq.max_sges);
36103610
status = -ENOMEM;
36113611
*bad_wr = wr;
@@ -3639,22 +3639,20 @@ int qedr_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr,
36393639
hw_srq->sge_prod++;
36403640
}
36413641

3642-
/* Flush WQE and SGE information before
3642+
/* Update WQE and SGE information before
36433643
* updating producer.
36443644
*/
3645-
wmb();
3645+
dma_wmb();
36463646

36473647
/* SRQ producer is 8 bytes. Need to update SGE producer index
36483648
* in first 4 bytes and need to update WQE producer in
36493649
* next 4 bytes.
36503650
*/
3651-
*srq->hw_srq.virt_prod_pair_addr = hw_srq->sge_prod;
3652-
offset = offsetof(struct rdma_srq_producers, wqe_prod);
3653-
*((u8 *)srq->hw_srq.virt_prod_pair_addr + offset) =
3654-
hw_srq->wqe_prod;
3651+
srq->hw_srq.virt_prod_pair_addr->sge_prod = hw_srq->sge_prod;
3652+
/* Make sure sge producer is updated first */
3653+
dma_wmb();
3654+
srq->hw_srq.virt_prod_pair_addr->wqe_prod = hw_srq->wqe_prod;
36553655

3656-
/* Flush producer after updating it. */
3657-
wmb();
36583656
wr = wr->next;
36593657
}
36603658

@@ -4077,7 +4075,7 @@ static int process_resp_one_srq(struct qedr_dev *dev, struct qedr_qp *qp,
40774075
} else {
40784076
__process_resp_one(dev, qp, cq, wc, resp, wr_id);
40794077
}
4080-
srq->hw_srq.wr_cons_cnt++;
4078+
atomic_inc(&srq->hw_srq.wr_cons_cnt);
40814079

40824080
return 1;
40834081
}

0 commit comments

Comments
 (0)