diff options
| author | Kumar Sanghvi <kumaras@chelsio.com> | 2011-10-24 11:50:22 -0400 |
|---|---|---|
| committer | Roland Dreier <roland@purestorage.com> | 2011-10-31 14:33:17 -0400 |
| commit | f7cc25d018f1e9af6767ee7774bbe83452e9fdf4 (patch) | |
| tree | 43d10d7038f8295b4ad92e938b0c705db5ce58b3 | |
| parent | 976d167615b64e14bc1491ca51d424e2ba9a5e84 (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.c | 6 | ||||
| -rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_provider.c | 1 | ||||
| -rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_provider.h | 1 | ||||
| -rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch_qp.c | 14 |
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 | } |
