RDMA/cxgb4: Only call CQ completion handler if it is armed
[linux-2.6-block.git] / drivers / infiniband / hw / cxgb4 / qp.c
index 086f62f5dc9e2ba5978e81f02e8e392c8e201774..60cfc11a66e479e14c1ab54eada29a6d99e43450 100644 (file)
@@ -1066,7 +1066,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
                       struct c4iw_cq *schp)
 {
        int count;
-       int flushed;
+       int rq_flushed, sq_flushed;
        unsigned long flag;
 
        PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
@@ -1084,27 +1084,40 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
 
        c4iw_flush_hw_cq(rchp);
        c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
-       flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
+       rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
        spin_unlock(&qhp->lock);
        spin_unlock_irqrestore(&rchp->lock, flag);
-       if (flushed) {
-               spin_lock_irqsave(&rchp->comp_handler_lock, flag);
-               (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
-               spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
-       }
 
        /* locking hierarchy: cq lock first, then qp lock. */
        spin_lock_irqsave(&schp->lock, flag);
        spin_lock(&qhp->lock);
        if (schp != rchp)
                c4iw_flush_hw_cq(schp);
-       flushed = c4iw_flush_sq(qhp);
+       sq_flushed = c4iw_flush_sq(qhp);
        spin_unlock(&qhp->lock);
        spin_unlock_irqrestore(&schp->lock, flag);
-       if (flushed) {
-               spin_lock_irqsave(&schp->comp_handler_lock, flag);
-               (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
-               spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
+
+       if (schp == rchp) {
+               if (t4_clear_cq_armed(&rchp->cq) &&
+                   (rq_flushed || sq_flushed)) {
+                       spin_lock_irqsave(&rchp->comp_handler_lock, flag);
+                       (*rchp->ibcq.comp_handler)(&rchp->ibcq,
+                                                  rchp->ibcq.cq_context);
+                       spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
+               }
+       } else {
+               if (t4_clear_cq_armed(&rchp->cq) && rq_flushed) {
+                       spin_lock_irqsave(&rchp->comp_handler_lock, flag);
+                       (*rchp->ibcq.comp_handler)(&rchp->ibcq,
+                                                  rchp->ibcq.cq_context);
+                       spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
+               }
+               if (t4_clear_cq_armed(&schp->cq) && sq_flushed) {
+                       spin_lock_irqsave(&schp->comp_handler_lock, flag);
+                       (*schp->ibcq.comp_handler)(&schp->ibcq,
+                                                  schp->ibcq.cq_context);
+                       spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
+               }
        }
 }