aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/cxgb3
diff options
context:
space:
mode:
authorSteve Wise <swise@opengridcomputing.com>2010-10-21 08:37:06 -0400
committerRoland Dreier <rolandd@cisco.com>2010-10-23 01:00:53 -0400
commitb955150ea784af4c193b708a2e8091673bf23004 (patch)
tree9ec764564c3b9702b4df57acf2a5a2584dafdd8b /drivers/infiniband/hw/cxgb3
parent252a52aa4fa22a668f019e55b3aac3ff71ec1c29 (diff)
RDMA/cxgb3: When a user QP is marked in error, also mark the CQs in error
The flushing of work requests for user QPs is implemented entirely in the user mode library. The only kernel interaction is to mark the user QP object indicating it is in error when the QP exits RTS. When the user QP operations are called by the application (eg: post_send, post_recv), the QP in error bit is checked and if set, the library flushes the QP. If, however, the application is not doing IO, but rather just polling the CQ, it will never get flushed work requests. This breaks some classes of applications. This patch adds logic to mark user CQs in error when a QP that is bound to the CQ is marked in error. The library poll code can then notice the CQ is in error and flush all the in error QPs bound to that CQ. Design: - add 1 extra CQE entry to the CQ memory that will be used to indicate in error status. - return the desired CQ memory size that should be mapped by the library - bump the ABI since the create_cq uverbs response changes. - detect older libraries and reduce the mmap size accordingly. (The ABI bump doesn't break old libraries, since they didn't check the ABI field anyway) Signed-off-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/cxgb3')
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h16
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_ev.c17
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c24
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c25
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_user.h8
6 files changed, 71 insertions, 20 deletions
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 005b7b52bc1e..09dda0b8740e 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -160,6 +160,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq, int kernel)
160 struct rdma_cq_setup setup; 160 struct rdma_cq_setup setup;
161 int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe); 161 int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe);
162 162
163 size += 1; /* one extra page for storing cq-in-err state */
163 cq->cqid = cxio_hal_get_cqid(rdev_p->rscp); 164 cq->cqid = cxio_hal_get_cqid(rdev_p->rscp);
164 if (!cq->cqid) 165 if (!cq->cqid)
165 return -ENOMEM; 166 return -ENOMEM;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index e5ddb63e7d23..4bb997aa39d0 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -728,6 +728,22 @@ struct t3_cq {
728#define CQ_VLD_ENTRY(ptr,size_log2,cqe) (Q_GENBIT(ptr,size_log2) == \ 728#define CQ_VLD_ENTRY(ptr,size_log2,cqe) (Q_GENBIT(ptr,size_log2) == \
729 CQE_GENBIT(*cqe)) 729 CQE_GENBIT(*cqe))
730 730
731struct t3_cq_status_page {
732 u32 cq_err;
733};
734
735static inline int cxio_cq_in_error(struct t3_cq *cq)
736{
737 return ((struct t3_cq_status_page *)
738 &cq->queue[1 << cq->size_log2])->cq_err;
739}
740
741static inline void cxio_set_cq_in_error(struct t3_cq *cq)
742{
743 ((struct t3_cq_status_page *)
744 &cq->queue[1 << cq->size_log2])->cq_err = 1;
745}
746
731static inline void cxio_set_wq_in_error(struct t3_wq *wq) 747static inline void cxio_set_wq_in_error(struct t3_wq *wq)
732{ 748{
733 wq->queue->wq_in_err.err |= 1; 749 wq->queue->wq_in_err.err |= 1;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c
index 6afc89e7572c..71e0d845da3d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_ev.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c
@@ -76,6 +76,14 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
76 atomic_inc(&qhp->refcnt); 76 atomic_inc(&qhp->refcnt);
77 spin_unlock(&rnicp->lock); 77 spin_unlock(&rnicp->lock);
78 78
79 if (qhp->attr.state == IWCH_QP_STATE_RTS) {
80 attrs.next_state = IWCH_QP_STATE_TERMINATE;
81 iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
82 &attrs, 1);
83 if (send_term)
84 iwch_post_terminate(qhp, rsp_msg);
85 }
86
79 event.event = ib_event; 87 event.event = ib_event;
80 event.device = chp->ibcq.device; 88 event.device = chp->ibcq.device;
81 if (ib_event == IB_EVENT_CQ_ERR) 89 if (ib_event == IB_EVENT_CQ_ERR)
@@ -86,13 +94,7 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
86 if (qhp->ibqp.event_handler) 94 if (qhp->ibqp.event_handler)
87 (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context); 95 (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
88 96
89 if (qhp->attr.state == IWCH_QP_STATE_RTS) { 97 (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
90 attrs.next_state = IWCH_QP_STATE_TERMINATE;
91 iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
92 &attrs, 1);
93 if (send_term)
94 iwch_post_terminate(qhp, rsp_msg);
95 }
96 98
97 if (atomic_dec_and_test(&qhp->refcnt)) 99 if (atomic_dec_and_test(&qhp->refcnt))
98 wake_up(&qhp->wait); 100 wake_up(&qhp->wait);
@@ -179,7 +181,6 @@ void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
179 case TPT_ERR_BOUND: 181 case TPT_ERR_BOUND:
180 case TPT_ERR_INVALIDATE_SHARED_MR: 182 case TPT_ERR_INVALIDATE_SHARED_MR:
181 case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND: 183 case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:
182 (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
183 post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_ACCESS_ERR, 1); 184 post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_ACCESS_ERR, 1);
184 break; 185 break;
185 186
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index fca0b4b747e4..2e2741307af4 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -154,6 +154,8 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
154 struct iwch_create_cq_resp uresp; 154 struct iwch_create_cq_resp uresp;
155 struct iwch_create_cq_req ureq; 155 struct iwch_create_cq_req ureq;
156 struct iwch_ucontext *ucontext = NULL; 156 struct iwch_ucontext *ucontext = NULL;
157 static int warned;
158 size_t resplen;
157 159
158 PDBG("%s ib_dev %p entries %d\n", __func__, ibdev, entries); 160 PDBG("%s ib_dev %p entries %d\n", __func__, ibdev, entries);
159 rhp = to_iwch_dev(ibdev); 161 rhp = to_iwch_dev(ibdev);
@@ -217,15 +219,26 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
217 uresp.key = ucontext->key; 219 uresp.key = ucontext->key;
218 ucontext->key += PAGE_SIZE; 220 ucontext->key += PAGE_SIZE;
219 spin_unlock(&ucontext->mmap_lock); 221 spin_unlock(&ucontext->mmap_lock);
220 if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) { 222 mm->key = uresp.key;
223 mm->addr = virt_to_phys(chp->cq.queue);
224 if (udata->outlen < sizeof uresp) {
225 if (!warned++)
226 printk(KERN_WARNING MOD "Warning - "
227 "downlevel libcxgb3 (non-fatal).\n");
228 mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
229 sizeof(struct t3_cqe));
230 resplen = sizeof(struct iwch_create_cq_resp_v0);
231 } else {
232 mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
233 sizeof(struct t3_cqe));
234 uresp.memsize = mm->len;
235 resplen = sizeof uresp;
236 }
237 if (ib_copy_to_udata(udata, &uresp, resplen)) {
221 kfree(mm); 238 kfree(mm);
222 iwch_destroy_cq(&chp->ibcq); 239 iwch_destroy_cq(&chp->ibcq);
223 return ERR_PTR(-EFAULT); 240 return ERR_PTR(-EFAULT);
224 } 241 }
225 mm->key = uresp.key;
226 mm->addr = virt_to_phys(chp->cq.queue);
227 mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
228 sizeof (struct t3_cqe));
229 insert_mmap(ucontext, mm); 242 insert_mmap(ucontext, mm);
230 } 243 }
231 PDBG("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n", 244 PDBG("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n",
@@ -1414,6 +1427,7 @@ int iwch_register_device(struct iwch_dev *dev)
1414 dev->ibdev.post_send = iwch_post_send; 1427 dev->ibdev.post_send = iwch_post_send;
1415 dev->ibdev.post_recv = iwch_post_receive; 1428 dev->ibdev.post_recv = iwch_post_receive;
1416 dev->ibdev.get_protocol_stats = iwch_get_mib; 1429 dev->ibdev.get_protocol_stats = iwch_get_mib;
1430 dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION;
1417 1431
1418 dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL); 1432 dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
1419 if (!dev->ibdev.iwcm) 1433 if (!dev->ibdev.iwcm)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index c64d27bf2c15..0993137181d7 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -802,14 +802,12 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
802/* 802/*
803 * Assumes qhp lock is held. 803 * Assumes qhp lock is held.
804 */ 804 */
805static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) 805static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
806 struct iwch_cq *schp, unsigned long *flag)
806{ 807{
807 struct iwch_cq *rchp, *schp;
808 int count; 808 int count;
809 int flushed; 809 int flushed;
810 810
811 rchp = get_chp(qhp->rhp, qhp->attr.rcq);
812 schp = get_chp(qhp->rhp, qhp->attr.scq);
813 811
814 PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp); 812 PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
815 /* take a ref on the qhp since we must release the lock */ 813 /* take a ref on the qhp since we must release the lock */
@@ -847,10 +845,23 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
847 845
848static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) 846static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
849{ 847{
850 if (qhp->ibqp.uobject) 848 struct iwch_cq *rchp, *schp;
849
850 rchp = get_chp(qhp->rhp, qhp->attr.rcq);
851 schp = get_chp(qhp->rhp, qhp->attr.scq);
852
853 if (qhp->ibqp.uobject) {
851 cxio_set_wq_in_error(&qhp->wq); 854 cxio_set_wq_in_error(&qhp->wq);
852 else 855 cxio_set_cq_in_error(&rchp->cq);
853 __flush_qp(qhp, flag); 856 (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
857 if (schp != rchp) {
858 cxio_set_cq_in_error(&schp->cq);
859 (*schp->ibcq.comp_handler)(&schp->ibcq,
860 schp->ibcq.cq_context);
861 }
862 return;
863 }
864 __flush_qp(qhp, rchp, schp, flag);
854} 865}
855 866
856 867
diff --git a/drivers/infiniband/hw/cxgb3/iwch_user.h b/drivers/infiniband/hw/cxgb3/iwch_user.h
index cb7086f558c1..a277c31fcaf7 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_user.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_user.h
@@ -45,10 +45,18 @@ struct iwch_create_cq_req {
45 __u64 user_rptr_addr; 45 __u64 user_rptr_addr;
46}; 46};
47 47
48struct iwch_create_cq_resp_v0 {
49 __u64 key;
50 __u32 cqid;
51 __u32 size_log2;
52};
53
48struct iwch_create_cq_resp { 54struct iwch_create_cq_resp {
49 __u64 key; 55 __u64 key;
50 __u32 cqid; 56 __u32 cqid;
51 __u32 size_log2; 57 __u32 size_log2;
58 __u32 memsize;
59 __u32 reserved;
52}; 60};
53 61
54struct iwch_create_qp_resp { 62struct iwch_create_qp_resp {