Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 3491c9e799fb ("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>

authored by

Yuval Basson and committed by
Jason Gunthorpe
acca72e2 317000b9

+12 -14
+2 -2
drivers/infiniband/hw/qedr/qedr.h
··· 344 344 u32 wqe_prod; 345 345 u32 sge_prod; 346 346 u32 wr_prod_cnt; 347 - u32 wr_cons_cnt; 347 + atomic_t wr_cons_cnt; 348 348 u32 num_elems; 349 349 350 - u32 *virt_prod_pair_addr; 350 + struct rdma_srq_producers *virt_prod_pair_addr; 351 351 dma_addr_t phy_prod_pair_addr; 352 352 }; 353 353
+10 -12
drivers/infiniband/hw/qedr/verbs.c
··· 3686 3686 * count and consumer count and subtract it from max 3687 3687 * work request supported so that we get elements left. 3688 3688 */ 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); 3690 3690 3691 3691 return hw_srq->max_wr - used; 3692 3692 } ··· 3701 3701 unsigned long flags; 3702 3702 int status = 0; 3703 3703 u32 num_sge; 3704 - u32 offset; 3705 3704 3706 3705 spin_lock_irqsave(&srq->lock, flags); 3707 3706 ··· 3713 3714 if (!qedr_srq_elem_left(hw_srq) || 3714 3715 wr->num_sge > srq->hw_srq.max_sges) { 3715 3716 DP_ERR(dev, "Can't post WR (%d,%d) || (%d > %d)\n", 3716 - hw_srq->wr_prod_cnt, hw_srq->wr_cons_cnt, 3717 + hw_srq->wr_prod_cnt, 3718 + atomic_read(&hw_srq->wr_cons_cnt), 3717 3719 wr->num_sge, srq->hw_srq.max_sges); 3718 3720 status = -ENOMEM; 3719 3721 *bad_wr = wr; ··· 3748 3748 hw_srq->sge_prod++; 3749 3749 } 3750 3750 3751 - /* Flush WQE and SGE information before 3751 + /* Update WQE and SGE information before 3752 3752 * updating producer. 3753 3753 */ 3754 - wmb(); 3754 + dma_wmb(); 3755 3755 3756 3756 /* SRQ producer is 8 bytes. Need to update SGE producer index 3757 3757 * in first 4 bytes and need to update WQE producer in 3758 3758 * next 4 bytes. 3759 3759 */ 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; 3764 3764 3765 - /* Flush producer after updating it. */ 3766 - wmb(); 3767 3765 wr = wr->next; 3768 3766 } 3769 3767 ··· 4180 4182 } else { 4181 4183 __process_resp_one(dev, qp, cq, wc, resp, wr_id); 4182 4184 } 4183 - srq->hw_srq.wr_cons_cnt++; 4185 + atomic_inc(&srq->hw_srq.wr_cons_cnt); 4184 4186 4185 4187 return 1; 4186 4188 }