| From: Bharat Potnuri <bharat@chelsio.com> |
| Date: Fri, 27 Apr 2018 16:41:16 +0530 |
| Subject: iw_cxgb4: Atomically flush per QP HW CQEs |
| |
| commit 2df19e19ae90d94fd8724083f161f368a2797537 upstream. |
| |
| When a CQ is shared by multiple QPs, c4iw_flush_hw_cq() needs to acquire |
| corresponding QP lock before moving the CQEs into its corresponding SW |
| queue and accessing the SQ contents for completing a WR. |
| Ignore CQEs if corresponding QP is already flushed. |
| |
| Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com> |
| Reviewed-by: Steve Wise <swise@opengridcomputing.com> |
| Signed-off-by: Doug Ledford <dledford@redhat.com> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/infiniband/hw/cxgb4/cq.c | 11 ++++++++++- |
| drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2 +- |
| drivers/infiniband/hw/cxgb4/qp.c | 4 ++-- |
| 3 files changed, 13 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/infiniband/hw/cxgb4/cq.c |
| +++ b/drivers/infiniband/hw/cxgb4/cq.c |
| @@ -331,7 +331,7 @@ static void advance_oldest_read(struct t |
| * Deal with out-of-order and/or completions that complete |
| * prior unsignalled WRs. |
| */ |
| -void c4iw_flush_hw_cq(struct c4iw_cq *chp) |
| +void c4iw_flush_hw_cq(struct c4iw_cq *chp, struct c4iw_qp *flush_qhp) |
| { |
| struct t4_cqe *hw_cqe, *swcqe, read_cqe; |
| struct c4iw_qp *qhp; |
| @@ -355,6 +355,13 @@ void c4iw_flush_hw_cq(struct c4iw_cq *ch |
| if (qhp == NULL) |
| goto next_cqe; |
| |
| + if (flush_qhp != qhp) { |
| + spin_lock(&qhp->lock); |
| + |
| + if (qhp->wq.flushed == 1) |
| + goto next_cqe; |
| + } |
| + |
| if (CQE_OPCODE(hw_cqe) == FW_RI_TERMINATE) |
| goto next_cqe; |
| |
| @@ -406,6 +413,8 @@ void c4iw_flush_hw_cq(struct c4iw_cq *ch |
| next_cqe: |
| t4_hwcq_consume(&chp->cq); |
| ret = t4_next_hw_cqe(&chp->cq, &hw_cqe); |
| + if (qhp && flush_qhp != qhp) |
| + spin_unlock(&qhp->lock); |
| } |
| } |
| |
| --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h |
| +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h |
| @@ -977,7 +977,7 @@ void c4iw_pblpool_free(struct c4iw_rdev |
| u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size); |
| void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size); |
| int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb); |
| -void c4iw_flush_hw_cq(struct c4iw_cq *chp); |
| +void c4iw_flush_hw_cq(struct c4iw_cq *chp, struct c4iw_qp *flush_qhp); |
| void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count); |
| int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp); |
| int c4iw_flush_rq(struct t4_wq *wq, struct t4_cq *cq, int count); |
| --- a/drivers/infiniband/hw/cxgb4/qp.c |
| +++ b/drivers/infiniband/hw/cxgb4/qp.c |
| @@ -1082,7 +1082,7 @@ static void __flush_qp(struct c4iw_qp *q |
| } |
| qhp->wq.flushed = 1; |
| |
| - c4iw_flush_hw_cq(rchp); |
| + c4iw_flush_hw_cq(rchp, qhp); |
| c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count); |
| flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count); |
| spin_unlock(&qhp->lock); |
| @@ -1097,7 +1097,7 @@ static void __flush_qp(struct c4iw_qp *q |
| spin_lock_irqsave(&schp->lock, flag); |
| spin_lock(&qhp->lock); |
| if (schp != rchp) |
| - c4iw_flush_hw_cq(schp); |
| + c4iw_flush_hw_cq(schp, qhp); |
| flushed = c4iw_flush_sq(qhp); |
| spin_unlock(&qhp->lock); |
| spin_unlock_irqrestore(&schp->lock, flag); |