]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/infiniband/hw/nes/nes_verbs.c
RDMA/nes: Use the flush code to fill in cqe error
[mv-sheeva.git] / drivers / infiniband / hw / nes / nes_verbs.c
index 21e0fd336cf710196dcbf2fe5bb3daecac7a21f4..993c1d4e0618ad11d0a25a634fe7fafa7bf648c9 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);
@@ -2884,7 +2923,7 @@ static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
  * nes_hw_modify_qp
  */
 int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp,
-               u32 next_iwarp_state, u32 wait_completion)
+               u32 next_iwarp_state, u32 termlen, u32 wait_completion)
 {
        struct nes_hw_cqp_wqe *cqp_wqe;
        /* struct iw_cm_id *cm_id = nesqp->cm_id; */
@@ -2916,6 +2955,13 @@ int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp,
        set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id);
        set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, (u64)nesqp->nesqp_context_pbase);
 
+       /* If sending a terminate message, fill in the length (in words) */
+       if (((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) == NES_CQP_QP_IWARP_STATE_TERMINATE) &&
+           !(next_iwarp_state & NES_CQP_QP_TERM_DONT_SEND_TERM_MSG)) {
+               termlen = ((termlen + 3) >> 2) << NES_CQP_OP_TERMLEN_SHIFT;
+               set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_NEW_MSS_IDX, termlen);
+       }
+
        atomic_set(&cqp_request->refcount, 2);
        nes_post_cqp_request(nesdev, cqp_request);
 
@@ -3086,6 +3132,9 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                                }
                                nes_debug(NES_DBG_MOD_QP, "QP%u: new state = error\n",
                                                nesqp->hwqp.qp_id);
+                               if (nesqp->term_flags)
+                                       del_timer(&nesqp->terminate_timer);
+
                                next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
                                /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
                                        if (nesqp->hte_added) {
@@ -3163,7 +3212,7 @@ int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 
        if (issue_modify_qp) {
                nes_debug(NES_DBG_MOD_QP, "call nes_hw_modify_qp\n");
-               ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 1);
+               ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0, 1);
                if (ret)
                        nes_debug(NES_DBG_MOD_QP, "nes_hw_modify_qp (next_iwarp_state = 0x%08X)"
                                        " failed for QP%u.\n",
@@ -3328,6 +3377,12 @@ static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
        head = nesqp->hwqp.sq_head;
 
        while (ib_wr) {
+               /* Check for QP error */
+               if (nesqp->term_flags) {
+                       err = -EINVAL;
+                       break;
+               }
+
                /* Check for SQ overflow */
                if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
                        err = -EINVAL;
@@ -3484,6 +3539,12 @@ static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
        head = nesqp->hwqp.rq_head;
 
        while (ib_wr) {
+               /* Check for QP error */
+               if (nesqp->term_flags) {
+                       err = -EINVAL;
+                       break;
+               }
+
                if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
                        err = -EINVAL;
                        break;
@@ -3547,7 +3608,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;
@@ -3555,12 +3615,13 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
        struct nes_qp *nesqp;
        struct nes_hw_cqe cqe;
        u32 head;
-       u32 wq_tail;
+       u32 wq_tail = 0;
        u32 cq_size;
        u32 cqe_count = 0;
        u32 wqe_index;
        u32 u32temp;
-       /* u32 counter; */
+       u32 move_cq_head = 1;
+       u32 err_code;
 
        nes_debug(NES_DBG_CQ, "\n");
 
@@ -3570,29 +3631,40 @@ 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];
+               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;
                        } else {
-                               entry->status = IB_WC_WR_FLUSH_ERR;
+                               err_code = le32_to_cpu(cqe.cqe_words[NES_CQE_ERROR_CODE_IDX]);
+                               if (NES_IWARP_CQE_MAJOR_DRV == (err_code >> 16)) {
+                                       entry->status = err_code & 0x0000ffff;
+
+                                       /* The rest of the cqe's will be marked as flushed */
+                                       nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] =
+                                               cpu_to_le32((NES_IWARP_CQE_MAJOR_FLUSH << 16) |
+                                                           NES_IWARP_CQE_MINOR_FLUSH);
+                               } else
+                                       entry->status = IB_WC_WR_FLUSH_ERR;
                        }
 
                        entry->qp = &nesqp->ibqp;
@@ -3601,20 +3673,18 @@ 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*/
-                               wq_tail = wqe_index;
-                               nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1);
-                               wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail].
+                               wrid = (((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index].
                                                wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) |
-                                               ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wq_tail].
+                                               ((u64)(cpu_to_le32((u32)nesqp->hwqp.sq_vbase[wqe_index].
                                                wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX])));
-                               entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+                               entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index].
                                                wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX]);
 
-                               switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+                               switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index].
                                                wqe_words[NES_IWARP_SQ_WQE_MISC_IDX]) & 0x3f) {
                                        case NES_IWARP_SQ_OP_RDMAW:
                                                nes_debug(NES_DBG_CQ, "Operation = RDMA WRITE.\n");
@@ -3623,7 +3693,7 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
                                        case NES_IWARP_SQ_OP_RDMAR:
                                                nes_debug(NES_DBG_CQ, "Operation = RDMA READ.\n");
                                                entry->opcode = IB_WC_RDMA_READ;
-                                               entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+                                               entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wqe_index].
                                                                wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX]);
                                                break;
                                        case NES_IWARP_SQ_OP_SENDINV:
@@ -3634,33 +3704,54 @@ static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
                                                entry->opcode = IB_WC_SEND;
                                                break;
                                }
+
+                               nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1);
+                               if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.sq_tail != nesqp->hwqp.sq_head)) {
+                                       move_cq_head = 0;
+                                       wq_tail = nesqp->hwqp.sq_tail;
+                               }
                        } else {
                                /* Working on a RQ Completion*/
-                               wq_tail = wqe_index;
-                                       nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1);
                                entry->byte_len = le32_to_cpu(cqe.cqe_words[NES_CQE_PAYLOAD_LENGTH_IDX]);
-                               wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) |
-                                       ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wq_tail].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32);
+                               wrid = ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]))) |
+                                       ((u64)(le32_to_cpu(nesqp->hwqp.rq_vbase[wqe_index].wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX]))<<32);
                                        entry->opcode = IB_WC_RECV;
+
+                               nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1);
+                               if ((entry->status != IB_WC_SUCCESS) && (nesqp->hwqp.rq_tail != nesqp->hwqp.rq_head)) {
+                                       move_cq_head = 0;
+                                       wq_tail = nesqp->hwqp.rq_tail;
+                               }
                        }
+
                        entry->wr_id = wrid;
+                       entry++;
+                       cqe_count++;
+               }
 
+               if (move_cq_head) {
+                       nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
                        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);
+                                       " 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->hw_cq.cq_number | (nescq->polled_completions << 16));
                                nescq->polled_completions = 0;
                        }
-                       entry++;
-               } else
-                       break;
+               } else {
+                       /* Update the wqe index and set status to flush */
+                       wqe_index = le32_to_cpu(cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+                       wqe_index = (wqe_index & (~(nesdev->nesadapter->max_qp_wr - 1))) | wq_tail;
+                       nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] =
+                               cpu_to_le32(wqe_index);
+                       move_cq_head = 1; /* ready for next pass */
+               }
        }
 
        if (nescq->polled_completions) {