]> git.karo-electronics.de Git - linux-beck.git/commitdiff
RDMA/nes: Clean out CQ completions when QP is destroyed
authorDon Wood <donald.e.wood@intel.com>
Sun, 6 Sep 2009 03:36:37 +0000 (20:36 -0700)
committerRoland Dreier <rolandd@cisco.com>
Sun, 6 Sep 2009 03:36:37 +0000 (20:36 -0700)
When a QP is destroyed, unprocessed CQ entries could still reference
the QP.  This change zeroes the context value at QP destroy time.  By
skipping over cqe's with a zero context, poll_cq no longer processes a
cqe for a destroyed QP.

Signed-off-by: Don Wood <donald.e.wood@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/hw/nes/nes_verbs.c

index 21e0fd336cf710196dcbf2fe5bb3daecac7a21f4..c6b5873416eb4b964b80a51c38e1ca72d532d46c 100644 (file)
@@ -1505,13 +1505,46 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
 }
 
 
+/**
+ * nes_clean_cq
+ */
+static void nes_clean_cq(struct nes_qp *nesqp, struct nes_cq *nescq)
+{
+       u32 cq_head;
+       u32 lo;
+       u32 hi;
+       u64 u64temp;
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&nescq->lock, flags);
+
+       cq_head = nescq->hw_cq.cq_head;
+       while (le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
+               rmb();
+               lo = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+               hi = le32_to_cpu(nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]);
+               u64temp = (((u64)hi) << 32) | ((u64)lo);
+               u64temp &= ~(NES_SW_CONTEXT_ALIGN-1);
+               if (u64temp == (u64)(unsigned long)nesqp) {
+                       /* Zero the context value so cqe will be ignored */
+                       nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] = 0;
+                       nescq->hw_cq.cq_vbase[cq_head].cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX] = 0;
+               }
+
+               if (++cq_head >= nescq->hw_cq.cq_size)
+                       cq_head = 0;
+       }
+
+       spin_unlock_irqrestore(&nescq->lock, flags);
+}
+
+
 /**
  * nes_destroy_qp
  */
 static int nes_destroy_qp(struct ib_qp *ibqp)
 {
        struct nes_qp *nesqp = to_nesqp(ibqp);
-       /* struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); */
        struct nes_ucontext *nes_ucontext;
        struct ib_qp_attr attr;
        struct iw_cm_id *cm_id;
@@ -1548,7 +1581,6 @@ static int nes_destroy_qp(struct ib_qp *ibqp)
                        nes_debug(NES_DBG_QP, "OFA CM event_handler returned, ret=%d\n", ret);
        }
 
-
        if (nesqp->user_mode) {
                if ((ibqp->uobject)&&(ibqp->uobject->context)) {
                        nes_ucontext = to_nesucontext(ibqp->uobject->context);
@@ -1560,6 +1592,13 @@ static int nes_destroy_qp(struct ib_qp *ibqp)
                }
                if (nesqp->pbl_pbase)
                        kunmap(nesqp->page);
+       } else {
+               /* Clean any pending completions from the cq(s) */
+               if (nesqp->nesscq)
+                       nes_clean_cq(nesqp, nesqp->nesscq);
+
+               if ((nesqp->nesrcq) && (nesqp->nesrcq != nesqp->nesscq))
+                       nes_clean_cq(nesqp, nesqp->nesrcq);
        }
 
        nes_rem_ref(&nesqp->ibqp);
@@ -3547,7 +3586,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
 {
        u64 u64temp;
        u64 wrid;
-       /* u64 u64temp; */
        unsigned long flags = 0;
        struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
        struct nes_device *nesdev = nesvnic->nesdev;
@@ -3560,7 +3598,6 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
        u32 cqe_count = 0;
        u32 wqe_index;
        u32 u32temp;
-       /* u32 counter; */
 
        nes_debug(NES_DBG_CQ, "\n");
 
@@ -3570,24 +3607,27 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
        cq_size = nescq->hw_cq.cq_size;
 
        while (cqe_count < num_entries) {
-               if (le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
-                               NES_CQE_VALID) {
-                       /*
-                        * Make sure we read CQ entry contents *after*
-                        * we've checked the valid bit.
-                        */
-                       rmb();
-
-                       cqe = nescq->hw_cq.cq_vbase[head];
-                       nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
-                       u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
-                       wqe_index = u32temp &
-                                       (nesdev->nesadapter->max_qp_wr - 1);
-                       u32temp &= ~(NES_SW_CONTEXT_ALIGN-1);
-                       /* parse CQE, get completion context from WQE (either rq or sq */
-                       u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
-                                       ((u64)u32temp);
-                       nesqp = *((struct nes_qp **)&u64temp);
+               if ((le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
+                               NES_CQE_VALID) == 0)
+                       break;
+
+               /*
+                * Make sure we read CQ entry contents *after*
+                * we've checked the valid bit.
+                */
+               rmb();
+
+               cqe = nescq->hw_cq.cq_vbase[head];
+               nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
+               u32temp = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+               wqe_index = u32temp & (nesdev->nesadapter->max_qp_wr - 1);
+               u32temp &= ~(NES_SW_CONTEXT_ALIGN-1);
+               /* parse CQE, get completion context from WQE (either rq or sq) */
+               u64temp = (((u64)(le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
+                               ((u64)u32temp);
+
+               if (u64temp) {
+                       nesqp = (struct nes_qp *)(unsigned long)u64temp;
                        memset(entry, 0, sizeof *entry);
                        if (cqe.cqe_words[NES_CQE_ERROR_CODE_IDX] == 0) {
                                entry->status = IB_WC_SUCCESS;
@@ -3601,7 +3641,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
                        if (le32_to_cpu(cqe.cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_SQ) {
                                if (nesqp->skip_lsmm) {
                                        nesqp->skip_lsmm = 0;
-                                       wq_tail = nesqp->hwqp.sq_tail++;
+                                       nesqp->hwqp.sq_tail++;
                                }
 
                                /* Working on a SQ Completion*/
@@ -3643,24 +3683,25 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
                                        ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32);
                                        entry->opcode = IB_WC_RECV;
                        }
-                       entry->wr_id = wrid;
 
-                       if (++head >= cq_size)
-                               head = 0;
-                       cqe_count++;
-                       nescq->polled_completions++;
-                       if ((nescq->polled_completions > (cq_size / 2)) ||
-                                       (nescq->polled_completions == 255)) {
-                               nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes"
-                                               " are pending %u of %u.\n",
-                                               nescq->hw_cq.cq_number, nescq->polled_completions, cq_size);
-                               nes_write32(nesdev->regs+NES_CQE_ALLOC,
-                                               nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
-                               nescq->polled_completions = 0;
-                       }
+                       entry->wr_id = wrid;
                        entry++;
-               } else
-                       break;
+                       cqe_count++;
+               }
+
+               if (++head >= cq_size)
+                       head = 0;
+               nescq->polled_completions++;
+
+               if ((nescq->polled_completions > (cq_size / 2)) ||
+                               (nescq->polled_completions == 255)) {
+                       nes_debug(NES_DBG_CQ, "CQ%u Issuing CQE Allocate since more than half of cqes"
+                                       " are pending %u of %u.\n",
+                                       nescq->hw_cq.cq_number, nescq->polled_completions, cq_size);
+                       nes_write32(nesdev->regs+NES_CQE_ALLOC,
+                                       nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
+                       nescq->polled_completions = 0;
+               }
        }
 
        if (nescq->polled_completions) {