aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c66
1 files changed, 44 insertions, 22 deletions
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 47999bb2b5f5..f28362616413 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -834,20 +834,20 @@ static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
return 0;
}
-static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
- struct ocrdma_cq *cq)
+static struct ocrdma_cq *_ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq, bool sq)
{
- unsigned long flags;
struct ocrdma_qp *qp;
- bool buddy_cq_found = false;
- /* Go through list of QPs in error state which are using this CQ
- * and invoke its callback handler to trigger CQE processing for
- * error/flushed CQE. It is rare to find more than few entries in
- * this list as most consumers stops after getting error CQE.
- * List is traversed only once when a matching buddy cq found for a QP.
- */
- spin_lock_irqsave(&dev->flush_q_lock, flags);
- list_for_each_entry(qp, &cq->sq_head, sq_entry) {
+ struct list_head *cur;
+ struct ocrdma_cq *bcq = NULL;
+ struct list_head *head = sq?(&cq->sq_head):(&cq->rq_head);
+
+ list_for_each(cur, head) {
+ if (sq)
+ qp = list_entry(cur, struct ocrdma_qp, sq_entry);
+ else
+ qp = list_entry(cur, struct ocrdma_qp, rq_entry);
+
if (qp->srq)
continue;
/* if wq and rq share the same cq, than comp_handler
@@ -859,19 +859,41 @@ static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
* if completion came on rq, sq's cq is buddy cq.
*/
if (qp->sq_cq == cq)
- cq = qp->rq_cq;
+ bcq = qp->rq_cq;
else
- cq = qp->sq_cq;
- buddy_cq_found = true;
- break;
+ bcq = qp->sq_cq;
+ return bcq;
}
+ return NULL;
+}
+
+static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq)
+{
+ unsigned long flags;
+ struct ocrdma_cq *bcq = NULL;
+
+ /* Go through list of QPs in error state which are using this CQ
+ * and invoke its callback handler to trigger CQE processing for
+ * error/flushed CQE. It is rare to find more than few entries in
+ * this list as most consumers stops after getting error CQE.
+ * List is traversed only once when a matching buddy cq found for a QP.
+ */
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
+ /* Check if buddy CQ is present.
+ * true - Check for SQ CQ
+ * false - Check for RQ CQ
+ */
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, true);
+ if (bcq == NULL)
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, false);
spin_unlock_irqrestore(&dev->flush_q_lock, flags);
- if (buddy_cq_found == false)
- return;
- if (cq->ibcq.comp_handler) {
- spin_lock_irqsave(&cq->comp_handler_lock, flags);
- (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
- spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
+
+ /* if there is valid buddy cq, look for its completion handler */
+ if (bcq && bcq->ibcq.comp_handler) {
+ spin_lock_irqsave(&bcq->comp_handler_lock, flags);
+ (*bcq->ibcq.comp_handler) (&bcq->ibcq, bcq->ibcq.cq_context);
+ spin_unlock_irqrestore(&bcq->comp_handler_lock, flags);
}
}