aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
diff options
context:
space:
mode:
authorDevesh Sharma <devesh.sharma@emulex.com>2014-02-04 01:26:54 -0500
committerRoland Dreier <roland@purestorage.com>2014-04-03 11:29:34 -0400
commitea61762679cd4d409dcaa6f502f190f4c8156d09 (patch)
tree5827d101e41788a4ff93c2368eaa4d3ec5ae337a /drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
parentbc1b04ab34a1485339571242cb0fbad823835685 (diff)
RDMA/ocrdma: EQ full catastrophe avoidance
Stale entries in the CQ being destroyed causes hardware to generate EQEs indefinitely for a given CQ. Thus causing uncontrolled execution of irq_handler. This patch fixes this using following sementics: * irq_handler will ring EQ doorbell atleast once and implement budgeting scheme. * cq_destroy will count number of valid entires during destroy and ring cq-db so that hardware does not generate uncontrolled EQE. * cq_destroy will synchronize with last running irq_handler instance. * arm_cq will always defer arming CQ till poll_cq, except for the first arm_cq call. * poll_cq will always ring cq-db with arm=SET if arm_cq was called prior to enter poll_cq. * poll_cq will always ring cq-db with arm=UNSET if arm_cq was not called prior to enter poll_cq. Signed-off-by: Devesh Sharma <devesh.sharma@emulex.com> Signed-off-by: Selvin Xavier <selvin.xavier@emulex.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband/hw/ocrdma/ocrdma_verbs.c')
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c81
1 files changed, 61 insertions, 20 deletions
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index f1108ebae83a..7d59ed340991 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -910,6 +910,7 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,
910 spin_lock_init(&cq->comp_handler_lock); 910 spin_lock_init(&cq->comp_handler_lock);
911 INIT_LIST_HEAD(&cq->sq_head); 911 INIT_LIST_HEAD(&cq->sq_head);
912 INIT_LIST_HEAD(&cq->rq_head); 912 INIT_LIST_HEAD(&cq->rq_head);
913 cq->first_arm = true;
913 914
914 if (ib_ctx) { 915 if (ib_ctx) {
915 uctx = get_ocrdma_ucontext(ib_ctx); 916 uctx = get_ocrdma_ucontext(ib_ctx);
@@ -927,9 +928,7 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,
927 goto ctx_err; 928 goto ctx_err;
928 } 929 }
929 cq->phase = OCRDMA_CQE_VALID; 930 cq->phase = OCRDMA_CQE_VALID;
930 cq->arm_needed = true;
931 dev->cq_tbl[cq->id] = cq; 931 dev->cq_tbl[cq->id] = cq;
932
933 return &cq->ibcq; 932 return &cq->ibcq;
934 933
935ctx_err: 934ctx_err:
@@ -952,15 +951,52 @@ int ocrdma_resize_cq(struct ib_cq *ibcq, int new_cnt,
952 return status; 951 return status;
953} 952}
954 953
954static void ocrdma_flush_cq(struct ocrdma_cq *cq)
955{
956 int cqe_cnt;
957 int valid_count = 0;
958 unsigned long flags;
959
960 struct ocrdma_dev *dev = get_ocrdma_dev(cq->ibcq.device);
961 struct ocrdma_cqe *cqe = NULL;
962
963 cqe = cq->va;
964 cqe_cnt = cq->cqe_cnt;
965
966 /* Last irq might have scheduled a polling thread
967 * sync-up with it before hard flushing.
968 */
969 spin_lock_irqsave(&cq->cq_lock, flags);
970 while (cqe_cnt) {
971 if (is_cqe_valid(cq, cqe))
972 valid_count++;
973 cqe++;
974 cqe_cnt--;
975 }
976 ocrdma_ring_cq_db(dev, cq->id, false, false, valid_count);
977 spin_unlock_irqrestore(&cq->cq_lock, flags);
978}
979
955int ocrdma_destroy_cq(struct ib_cq *ibcq) 980int ocrdma_destroy_cq(struct ib_cq *ibcq)
956{ 981{
957 int status; 982 int status;
958 struct ocrdma_cq *cq = get_ocrdma_cq(ibcq); 983 struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
984 struct ocrdma_eq *eq = NULL;
959 struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device); 985 struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
960 int pdid = 0; 986 int pdid = 0;
987 u32 irq, indx;
961 988
962 status = ocrdma_mbx_destroy_cq(dev, cq); 989 dev->cq_tbl[cq->id] = NULL;
990 indx = ocrdma_get_eq_table_index(dev, cq->eqn);
991 if (indx == -EINVAL)
992 BUG();
963 993
994 eq = &dev->eq_tbl[indx];
995 irq = ocrdma_get_irq(dev, eq);
996 synchronize_irq(irq);
997 ocrdma_flush_cq(cq);
998
999 status = ocrdma_mbx_destroy_cq(dev, cq);
964 if (cq->ucontext) { 1000 if (cq->ucontext) {
965 pdid = cq->ucontext->cntxt_pd->id; 1001 pdid = cq->ucontext->cntxt_pd->id;
966 ocrdma_del_mmap(cq->ucontext, (u64) cq->pa, 1002 ocrdma_del_mmap(cq->ucontext, (u64) cq->pa,
@@ -969,7 +1005,6 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
969 ocrdma_get_db_addr(dev, pdid), 1005 ocrdma_get_db_addr(dev, pdid),
970 dev->nic_info.db_page_size); 1006 dev->nic_info.db_page_size);
971 } 1007 }
972 dev->cq_tbl[cq->id] = NULL;
973 1008
974 kfree(cq); 1009 kfree(cq);
975 return status; 1010 return status;
@@ -2705,10 +2740,18 @@ expand_cqe:
2705 } 2740 }
2706stop_cqe: 2741stop_cqe:
2707 cq->getp = cur_getp; 2742 cq->getp = cur_getp;
2708 if (polled_hw_cqes || expand || stop) { 2743 if (cq->deferred_arm) {
2709 ocrdma_ring_cq_db(dev, cq->id, cq->armed, cq->solicited, 2744 ocrdma_ring_cq_db(dev, cq->id, true, cq->deferred_sol,
2745 polled_hw_cqes);
2746 cq->deferred_arm = false;
2747 cq->deferred_sol = false;
2748 } else {
2749 /* We need to pop the CQE. No need to arm */
2750 ocrdma_ring_cq_db(dev, cq->id, false, cq->deferred_sol,
2710 polled_hw_cqes); 2751 polled_hw_cqes);
2752 cq->deferred_sol = false;
2711 } 2753 }
2754
2712 return i; 2755 return i;
2713} 2756}
2714 2757
@@ -2780,30 +2823,28 @@ int ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags)
2780 struct ocrdma_cq *cq = get_ocrdma_cq(ibcq); 2823 struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
2781 struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device); 2824 struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
2782 u16 cq_id; 2825 u16 cq_id;
2783 u16 cur_getp;
2784 struct ocrdma_cqe *cqe;
2785 unsigned long flags; 2826 unsigned long flags;
2827 bool arm_needed = false, sol_needed = false;
2786 2828
2787 cq_id = cq->id; 2829 cq_id = cq->id;
2788 2830
2789 spin_lock_irqsave(&cq->cq_lock, flags); 2831 spin_lock_irqsave(&cq->cq_lock, flags);
2790 if (cq_flags & IB_CQ_NEXT_COMP || cq_flags & IB_CQ_SOLICITED) 2832 if (cq_flags & IB_CQ_NEXT_COMP || cq_flags & IB_CQ_SOLICITED)
2791 cq->armed = true; 2833 arm_needed = true;
2792 if (cq_flags & IB_CQ_SOLICITED) 2834 if (cq_flags & IB_CQ_SOLICITED)
2793 cq->solicited = true; 2835 sol_needed = true;
2794
2795 cur_getp = cq->getp;
2796 cqe = cq->va + cur_getp;
2797 2836
2798 /* check whether any valid cqe exist or not, if not then safe to 2837 if (cq->first_arm) {
2799 * arm. If cqe is not yet consumed, then let it get consumed and then 2838 ocrdma_ring_cq_db(dev, cq_id, arm_needed, sol_needed, 0);
2800 * we arm it to avoid false interrupts. 2839 cq->first_arm = false;
2801 */ 2840 goto skip_defer;
2802 if (!is_cqe_valid(cq, cqe) || cq->arm_needed) {
2803 cq->arm_needed = false;
2804 ocrdma_ring_cq_db(dev, cq_id, cq->armed, cq->solicited, 0);
2805 } 2841 }
2842 cq->deferred_arm = true;
2843
2844skip_defer:
2845 cq->deferred_sol = sol_needed;
2806 spin_unlock_irqrestore(&cq->cq_lock, flags); 2846 spin_unlock_irqrestore(&cq->cq_lock, flags);
2847
2807 return 0; 2848 return 0;
2808} 2849}
2809 2850