Commit 325abead authored by Vipul Pandya's avatar Vipul Pandya Committed by Roland Dreier

RDMA/cxgb4: Keep QP referenced until TID released

The driver is currently releasing the last ref on the QP too early.
This can cause bus errors due to HW still fetching WRs from the HW
queue.  The fix is to keep a qp ref until we release the HW TID.
Signed-off-by: default avatarVipul Pandya <vipul@chelsio.com>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent 1557967b
...@@ -143,6 +143,18 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status); ...@@ -143,6 +143,18 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status);
static LIST_HEAD(timeout_list); static LIST_HEAD(timeout_list);
static spinlock_t timeout_lock; static spinlock_t timeout_lock;
static void deref_qp(struct c4iw_ep *ep)
{
c4iw_qp_rem_ref(&ep->com.qp->ibqp);
clear_bit(QP_REFERENCED, &ep->com.flags);
}
static void ref_qp(struct c4iw_ep *ep)
{
set_bit(QP_REFERENCED, &ep->com.flags);
c4iw_qp_add_ref(&ep->com.qp->ibqp);
}
static void start_ep_timer(struct c4iw_ep *ep) static void start_ep_timer(struct c4iw_ep *ep)
{ {
PDBG("%s ep %p\n", __func__, ep); PDBG("%s ep %p\n", __func__, ep);
...@@ -271,6 +283,8 @@ void _c4iw_free_ep(struct kref *kref) ...@@ -271,6 +283,8 @@ void _c4iw_free_ep(struct kref *kref)
ep = container_of(kref, struct c4iw_ep, com.kref); ep = container_of(kref, struct c4iw_ep, com.kref);
PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]); PDBG("%s ep %p state %s\n", __func__, ep, states[state_read(&ep->com)]);
if (test_bit(QP_REFERENCED, &ep->com.flags))
deref_qp(ep);
if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) { if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid); cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid);
dst_release(ep->dst); dst_release(ep->dst);
...@@ -863,7 +877,6 @@ static void close_complete_upcall(struct c4iw_ep *ep) ...@@ -863,7 +877,6 @@ static void close_complete_upcall(struct c4iw_ep *ep)
ep->com.cm_id->event_handler(ep->com.cm_id, &event); ep->com.cm_id->event_handler(ep->com.cm_id, &event);
ep->com.cm_id->rem_ref(ep->com.cm_id); ep->com.cm_id->rem_ref(ep->com.cm_id);
ep->com.cm_id = NULL; ep->com.cm_id = NULL;
ep->com.qp = NULL;
set_bit(CLOSE_UPCALL, &ep->com.history); set_bit(CLOSE_UPCALL, &ep->com.history);
} }
} }
...@@ -906,7 +919,6 @@ static void peer_abort_upcall(struct c4iw_ep *ep) ...@@ -906,7 +919,6 @@ static void peer_abort_upcall(struct c4iw_ep *ep)
ep->com.cm_id->event_handler(ep->com.cm_id, &event); ep->com.cm_id->event_handler(ep->com.cm_id, &event);
ep->com.cm_id->rem_ref(ep->com.cm_id); ep->com.cm_id->rem_ref(ep->com.cm_id);
ep->com.cm_id = NULL; ep->com.cm_id = NULL;
ep->com.qp = NULL;
set_bit(ABORT_UPCALL, &ep->com.history); set_bit(ABORT_UPCALL, &ep->com.history);
} }
} }
...@@ -946,7 +958,6 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status) ...@@ -946,7 +958,6 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
if (status < 0) { if (status < 0) {
ep->com.cm_id->rem_ref(ep->com.cm_id); ep->com.cm_id->rem_ref(ep->com.cm_id);
ep->com.cm_id = NULL; ep->com.cm_id = NULL;
ep->com.qp = NULL;
} }
} }
...@@ -2434,6 +2445,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ...@@ -2434,6 +2445,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
cm_id->add_ref(cm_id); cm_id->add_ref(cm_id);
ep->com.cm_id = cm_id; ep->com.cm_id = cm_id;
ep->com.qp = qp; ep->com.qp = qp;
ref_qp(ep);
/* bind QP to EP and move to RTS */ /* bind QP to EP and move to RTS */
attrs.mpa_attr = ep->mpa_attr; attrs.mpa_attr = ep->mpa_attr;
...@@ -2464,7 +2476,6 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ...@@ -2464,7 +2476,6 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
return 0; return 0;
err1: err1:
ep->com.cm_id = NULL; ep->com.cm_id = NULL;
ep->com.qp = NULL;
cm_id->rem_ref(cm_id); cm_id->rem_ref(cm_id);
err: err:
c4iw_put_ep(&ep->com); c4iw_put_ep(&ep->com);
...@@ -2505,6 +2516,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ...@@ -2505,6 +2516,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->com.cm_id = cm_id; ep->com.cm_id = cm_id;
ep->com.qp = get_qhp(dev, conn_param->qpn); ep->com.qp = get_qhp(dev, conn_param->qpn);
BUG_ON(!ep->com.qp); BUG_ON(!ep->com.qp);
ref_qp(ep);
PDBG("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn, PDBG("%s qpn 0x%x qp %p cm_id %p\n", __func__, conn_param->qpn,
ep->com.qp, cm_id); ep->com.qp, cm_id);
......
...@@ -716,6 +716,7 @@ enum c4iw_ep_flags { ...@@ -716,6 +716,7 @@ enum c4iw_ep_flags {
ABORT_REQ_IN_PROGRESS = 1, ABORT_REQ_IN_PROGRESS = 1,
RELEASE_RESOURCES = 2, RELEASE_RESOURCES = 2,
CLOSE_SENT = 3, CLOSE_SENT = 3,
QP_REFERENCED = 5,
}; };
enum c4iw_ep_history { enum c4iw_ep_history {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment