aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKumar Sanghvi <kumaras@chelsio.com>2011-10-24 11:50:22 -0400
committerRoland Dreier <roland@purestorage.com>2011-10-31 14:33:17 -0400
commitf7cc25d018f1e9af6767ee7774bbe83452e9fdf4 (patch)
tree43d10d7038f8295b4ad92e938b0c705db5ce58b3
parent976d167615b64e14bc1491ca51d424e2ba9a5e84 (diff)
RDMA/cxgb3: Serialize calls to CQ's comp_handler
iw_cxgb3 has a potential problem where a CQ's comp_handler can get called simultaneously from different places in iw_cxgb3 driver. This does not comply with Documentation/infiniband/core_locking.txt, which states that at a given point of time, there should be only one callback per CQ should be active. Such problem was reported by Parav Pandit <Parav.Pandit@Emulex.Com> for iw_cxgb4 driver. Based on discussion between Parav Pandit and Steve Wise, this patch fixes the above problem by serializing the calls to a CQ's comp_handler using a spin_lock. Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com> Acked-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_ev.c6
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.h1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c14
4 files changed, 20 insertions, 2 deletions
diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c
index 71e0d845da3d..abcc9e76962b 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_ev.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c
@@ -46,6 +46,7 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
46 struct ib_event event; 46 struct ib_event event;
47 struct iwch_qp_attributes attrs; 47 struct iwch_qp_attributes attrs;
48 struct iwch_qp *qhp; 48 struct iwch_qp *qhp;
49 unsigned long flag;
49 50
50 spin_lock(&rnicp->lock); 51 spin_lock(&rnicp->lock);
51 qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe)); 52 qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe));
@@ -94,7 +95,9 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
94 if (qhp->ibqp.event_handler) 95 if (qhp->ibqp.event_handler)
95 (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context); 96 (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
96 97
98 spin_lock_irqsave(&chp->comp_handler_lock, flag);
97 (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); 99 (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
100 spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
98 101
99 if (atomic_dec_and_test(&qhp->refcnt)) 102 if (atomic_dec_and_test(&qhp->refcnt))
100 wake_up(&qhp->wait); 103 wake_up(&qhp->wait);
@@ -107,6 +110,7 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
107 struct iwch_cq *chp; 110 struct iwch_cq *chp;
108 struct iwch_qp *qhp; 111 struct iwch_qp *qhp;
109 u32 cqid = RSPQ_CQID(rsp_msg); 112 u32 cqid = RSPQ_CQID(rsp_msg);
113 unsigned long flag;
110 114
111 rnicp = (struct iwch_dev *) rdev_p->ulp; 115 rnicp = (struct iwch_dev *) rdev_p->ulp;
112 spin_lock(&rnicp->lock); 116 spin_lock(&rnicp->lock);
@@ -170,7 +174,9 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
170 */ 174 */
171 if (qhp->ep && SQ_TYPE(rsp_msg->cqe)) 175 if (qhp->ep && SQ_TYPE(rsp_msg->cqe))
172 dst_confirm(qhp->ep->dst); 176 dst_confirm(qhp->ep->dst);
177 spin_lock_irqsave(&chp->comp_handler_lock, flag);
173 (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context); 178 (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
179 spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
174 break; 180 break;
175 181
176 case TPT_ERR_STAG: 182 case TPT_ERR_STAG:
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index c7d9411f2954..37c224fc3ad9 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -190,6 +190,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
190 chp->rhp = rhp; 190 chp->rhp = rhp;
191 chp->ibcq.cqe = 1 << chp->cq.size_log2; 191 chp->ibcq.cqe = 1 << chp->cq.size_log2;
192 spin_lock_init(&chp->lock); 192 spin_lock_init(&chp->lock);
193 spin_lock_init(&chp->comp_handler_lock);
193 atomic_set(&chp->refcnt, 1); 194 atomic_set(&chp->refcnt, 1);
194 init_waitqueue_head(&chp->wait); 195 init_waitqueue_head(&chp->wait);
195 if (insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid)) { 196 if (insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid)) {
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
index 9a342c9b220d..87c14b0c5ac0 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -103,6 +103,7 @@ struct iwch_cq {
103 struct iwch_dev *rhp; 103 struct iwch_dev *rhp;
104 struct t3_cq cq; 104 struct t3_cq cq;
105 spinlock_t lock; 105 spinlock_t lock;
106 spinlock_t comp_handler_lock;
106 atomic_t refcnt; 107 atomic_t refcnt;
107 wait_queue_head_t wait; 108 wait_queue_head_t wait;
108 u32 __user *user_rptr_addr; 109 u32 __user *user_rptr_addr;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index ecd313f359a4..bea5839d89ee 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -822,8 +822,11 @@ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
822 flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count); 822 flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count);
823 spin_unlock(&qhp->lock); 823 spin_unlock(&qhp->lock);
824 spin_unlock_irqrestore(&rchp->lock, *flag); 824 spin_unlock_irqrestore(&rchp->lock, *flag);
825 if (flushed) 825 if (flushed) {
826 spin_lock_irqsave(&rchp->comp_handler_lock, *flag);
826 (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); 827 (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
828 spin_unlock_irqrestore(&rchp->comp_handler_lock, *flag);
829 }
827 830
828 /* locking hierarchy: cq lock first, then qp lock. */ 831 /* locking hierarchy: cq lock first, then qp lock. */
829 spin_lock_irqsave(&schp->lock, *flag); 832 spin_lock_irqsave(&schp->lock, *flag);
@@ -833,8 +836,11 @@ static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
833 flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count); 836 flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count);
834 spin_unlock(&qhp->lock); 837 spin_unlock(&qhp->lock);
835 spin_unlock_irqrestore(&schp->lock, *flag); 838 spin_unlock_irqrestore(&schp->lock, *flag);
836 if (flushed) 839 if (flushed) {
840 spin_lock_irqsave(&schp->comp_handler_lock, *flag);
837 (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); 841 (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
842 spin_unlock_irqrestore(&schp->comp_handler_lock, *flag);
843 }
838 844
839 /* deref */ 845 /* deref */
840 if (atomic_dec_and_test(&qhp->refcnt)) 846 if (atomic_dec_and_test(&qhp->refcnt))
@@ -853,11 +859,15 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
853 if (qhp->ibqp.uobject) { 859 if (qhp->ibqp.uobject) {
854 cxio_set_wq_in_error(&qhp->wq); 860 cxio_set_wq_in_error(&qhp->wq);
855 cxio_set_cq_in_error(&rchp->cq); 861 cxio_set_cq_in_error(&rchp->cq);
862 spin_lock_irqsave(&rchp->comp_handler_lock, *flag);
856 (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); 863 (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
864 spin_unlock_irqrestore(&rchp->comp_handler_lock, *flag);
857 if (schp != rchp) { 865 if (schp != rchp) {
858 cxio_set_cq_in_error(&schp->cq); 866 cxio_set_cq_in_error(&schp->cq);
867 spin_lock_irqsave(&schp->comp_handler_lock, *flag);
859 (*schp->ibcq.comp_handler)(&schp->ibcq, 868 (*schp->ibcq.comp_handler)(&schp->ibcq,
860 schp->ibcq.cq_context); 869 schp->ibcq.cq_context);
870 spin_unlock_irqrestore(&schp->comp_handler_lock, *flag);
861 } 871 }
862 return; 872 return;
863 } 873 }