RDMA/cxgb3: QP flush fixes
- Flush the QP only after the HW disables the connection. Currently we flush the QP when transitioning to CLOSING. This exposes a race condition where the HW can complete a RECV WR, for instance, -and- the SW can flush that same WR. - Only call CQ event handlers on flush IFF we actually flushed something. Signed-off-by: Steve Wise <swise@opengridcomputing.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
committed by
Roland Dreier
parent
57ce41d1d1
commit
c8286944b8
@@ -359,9 +359,10 @@ static void insert_recv_cqe(struct t3_wq *wq, struct t3_cq *cq)
|
|||||||
cq->sw_wptr++;
|
cq->sw_wptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count)
|
int cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count)
|
||||||
{
|
{
|
||||||
u32 ptr;
|
u32 ptr;
|
||||||
|
int flushed = 0;
|
||||||
|
|
||||||
PDBG("%s wq %p cq %p\n", __func__, wq, cq);
|
PDBG("%s wq %p cq %p\n", __func__, wq, cq);
|
||||||
|
|
||||||
@@ -369,8 +370,11 @@ void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count)
|
|||||||
PDBG("%s rq_rptr %u rq_wptr %u skip count %u\n", __func__,
|
PDBG("%s rq_rptr %u rq_wptr %u skip count %u\n", __func__,
|
||||||
wq->rq_rptr, wq->rq_wptr, count);
|
wq->rq_rptr, wq->rq_wptr, count);
|
||||||
ptr = wq->rq_rptr + count;
|
ptr = wq->rq_rptr + count;
|
||||||
while (ptr++ != wq->rq_wptr)
|
while (ptr++ != wq->rq_wptr) {
|
||||||
insert_recv_cqe(wq, cq);
|
insert_recv_cqe(wq, cq);
|
||||||
|
flushed++;
|
||||||
|
}
|
||||||
|
return flushed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void insert_sq_cqe(struct t3_wq *wq, struct t3_cq *cq,
|
static void insert_sq_cqe(struct t3_wq *wq, struct t3_cq *cq,
|
||||||
@@ -394,9 +398,10 @@ static void insert_sq_cqe(struct t3_wq *wq, struct t3_cq *cq,
|
|||||||
cq->sw_wptr++;
|
cq->sw_wptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count)
|
int cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count)
|
||||||
{
|
{
|
||||||
__u32 ptr;
|
__u32 ptr;
|
||||||
|
int flushed = 0;
|
||||||
struct t3_swsq *sqp = wq->sq + Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2);
|
struct t3_swsq *sqp = wq->sq + Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2);
|
||||||
|
|
||||||
ptr = wq->sq_rptr + count;
|
ptr = wq->sq_rptr + count;
|
||||||
@@ -405,7 +410,9 @@ void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count)
|
|||||||
insert_sq_cqe(wq, cq, sqp);
|
insert_sq_cqe(wq, cq, sqp);
|
||||||
sqp++;
|
sqp++;
|
||||||
ptr++;
|
ptr++;
|
||||||
|
flushed++;
|
||||||
}
|
}
|
||||||
|
return flushed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -173,8 +173,8 @@ u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp);
|
|||||||
void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid);
|
void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid);
|
||||||
int __init cxio_hal_init(void);
|
int __init cxio_hal_init(void);
|
||||||
void __exit cxio_hal_exit(void);
|
void __exit cxio_hal_exit(void);
|
||||||
void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count);
|
int cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count);
|
||||||
void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count);
|
int cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count);
|
||||||
void cxio_count_rcqes(struct t3_cq *cq, struct t3_wq *wq, int *count);
|
void cxio_count_rcqes(struct t3_cq *cq, struct t3_wq *wq, int *count);
|
||||||
void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count);
|
void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count);
|
||||||
void cxio_flush_hw_cq(struct t3_cq *cq);
|
void cxio_flush_hw_cq(struct t3_cq *cq);
|
||||||
|
@@ -655,6 +655,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
|
|||||||
{
|
{
|
||||||
struct iwch_cq *rchp, *schp;
|
struct iwch_cq *rchp, *schp;
|
||||||
int count;
|
int count;
|
||||||
|
int flushed;
|
||||||
|
|
||||||
rchp = get_chp(qhp->rhp, qhp->attr.rcq);
|
rchp = get_chp(qhp->rhp, qhp->attr.rcq);
|
||||||
schp = get_chp(qhp->rhp, qhp->attr.scq);
|
schp = get_chp(qhp->rhp, qhp->attr.scq);
|
||||||
@@ -669,9 +670,10 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
|
|||||||
spin_lock(&qhp->lock);
|
spin_lock(&qhp->lock);
|
||||||
cxio_flush_hw_cq(&rchp->cq);
|
cxio_flush_hw_cq(&rchp->cq);
|
||||||
cxio_count_rcqes(&rchp->cq, &qhp->wq, &count);
|
cxio_count_rcqes(&rchp->cq, &qhp->wq, &count);
|
||||||
cxio_flush_rq(&qhp->wq, &rchp->cq, count);
|
flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count);
|
||||||
spin_unlock(&qhp->lock);
|
spin_unlock(&qhp->lock);
|
||||||
spin_unlock_irqrestore(&rchp->lock, *flag);
|
spin_unlock_irqrestore(&rchp->lock, *flag);
|
||||||
|
if (flushed)
|
||||||
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
|
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
|
||||||
|
|
||||||
/* locking heirarchy: cq lock first, then qp lock. */
|
/* locking heirarchy: cq lock first, then qp lock. */
|
||||||
@@ -679,9 +681,10 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
|
|||||||
spin_lock(&qhp->lock);
|
spin_lock(&qhp->lock);
|
||||||
cxio_flush_hw_cq(&schp->cq);
|
cxio_flush_hw_cq(&schp->cq);
|
||||||
cxio_count_scqes(&schp->cq, &qhp->wq, &count);
|
cxio_count_scqes(&schp->cq, &qhp->wq, &count);
|
||||||
cxio_flush_sq(&qhp->wq, &schp->cq, count);
|
flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count);
|
||||||
spin_unlock(&qhp->lock);
|
spin_unlock(&qhp->lock);
|
||||||
spin_unlock_irqrestore(&schp->lock, *flag);
|
spin_unlock_irqrestore(&schp->lock, *flag);
|
||||||
|
if (flushed)
|
||||||
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
|
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
|
||||||
|
|
||||||
/* deref */
|
/* deref */
|
||||||
@@ -880,7 +883,6 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
|
|||||||
ep = qhp->ep;
|
ep = qhp->ep;
|
||||||
get_ep(&ep->com);
|
get_ep(&ep->com);
|
||||||
}
|
}
|
||||||
flush_qp(qhp, &flag);
|
|
||||||
break;
|
break;
|
||||||
case IWCH_QP_STATE_TERMINATE:
|
case IWCH_QP_STATE_TERMINATE:
|
||||||
qhp->attr.state = IWCH_QP_STATE_TERMINATE;
|
qhp->attr.state = IWCH_QP_STATE_TERMINATE;
|
||||||
@@ -911,6 +913,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
|
|||||||
}
|
}
|
||||||
switch (attrs->next_state) {
|
switch (attrs->next_state) {
|
||||||
case IWCH_QP_STATE_IDLE:
|
case IWCH_QP_STATE_IDLE:
|
||||||
|
flush_qp(qhp, &flag);
|
||||||
qhp->attr.state = IWCH_QP_STATE_IDLE;
|
qhp->attr.state = IWCH_QP_STATE_IDLE;
|
||||||
qhp->attr.llp_stream_handle = NULL;
|
qhp->attr.llp_stream_handle = NULL;
|
||||||
put_ep(&qhp->ep->com);
|
put_ep(&qhp->ep->com);
|
||||||
|
Reference in New Issue
Block a user