IB/ipath: Fix PSN update for RC retries
This patch fixes a number of bugs with updating the PSN for retries of RC requests. Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
0434d271fd
commit
6f5c407460
|
@ -444,7 +444,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
|
||||||
qp->s_psn = wqe->lpsn + 1;
|
qp->s_psn = wqe->lpsn + 1;
|
||||||
else {
|
else {
|
||||||
qp->s_psn++;
|
qp->s_psn++;
|
||||||
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
|
if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
|
||||||
qp->s_next_psn = qp->s_psn;
|
qp->s_next_psn = qp->s_psn;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -471,7 +471,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case OP(SEND_MIDDLE):
|
case OP(SEND_MIDDLE):
|
||||||
bth2 = qp->s_psn++ & IPATH_PSN_MASK;
|
bth2 = qp->s_psn++ & IPATH_PSN_MASK;
|
||||||
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
|
if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
|
||||||
qp->s_next_psn = qp->s_psn;
|
qp->s_next_psn = qp->s_psn;
|
||||||
ss = &qp->s_sge;
|
ss = &qp->s_sge;
|
||||||
len = qp->s_len;
|
len = qp->s_len;
|
||||||
|
@ -507,7 +507,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case OP(RDMA_WRITE_MIDDLE):
|
case OP(RDMA_WRITE_MIDDLE):
|
||||||
bth2 = qp->s_psn++ & IPATH_PSN_MASK;
|
bth2 = qp->s_psn++ & IPATH_PSN_MASK;
|
||||||
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
|
if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
|
||||||
qp->s_next_psn = qp->s_psn;
|
qp->s_next_psn = qp->s_psn;
|
||||||
ss = &qp->s_sge;
|
ss = &qp->s_sge;
|
||||||
len = qp->s_len;
|
len = qp->s_len;
|
||||||
|
@ -546,7 +546,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
|
||||||
qp->s_state = OP(RDMA_READ_REQUEST);
|
qp->s_state = OP(RDMA_READ_REQUEST);
|
||||||
hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
|
hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
|
||||||
bth2 = qp->s_psn++ & IPATH_PSN_MASK;
|
bth2 = qp->s_psn++ & IPATH_PSN_MASK;
|
||||||
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
|
if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
|
||||||
qp->s_next_psn = qp->s_psn;
|
qp->s_next_psn = qp->s_psn;
|
||||||
ss = NULL;
|
ss = NULL;
|
||||||
len = 0;
|
len = 0;
|
||||||
|
@ -779,7 +779,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
|
||||||
if (wqe->wr.opcode == IB_WR_RDMA_READ)
|
if (wqe->wr.opcode == IB_WR_RDMA_READ)
|
||||||
dev->n_rc_resends++;
|
dev->n_rc_resends++;
|
||||||
else
|
else
|
||||||
dev->n_rc_resends += (int)qp->s_psn - (int)psn;
|
dev->n_rc_resends += (qp->s_psn - psn) & IPATH_PSN_MASK;
|
||||||
|
|
||||||
reset_psn(qp, psn);
|
reset_psn(qp, psn);
|
||||||
tasklet_hi_schedule(&qp->s_task);
|
tasklet_hi_schedule(&qp->s_task);
|
||||||
|
@ -915,15 +915,19 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
|
||||||
if (qp->s_last == qp->s_cur) {
|
if (qp->s_last == qp->s_cur) {
|
||||||
if (++qp->s_cur >= qp->s_size)
|
if (++qp->s_cur >= qp->s_size)
|
||||||
qp->s_cur = 0;
|
qp->s_cur = 0;
|
||||||
|
qp->s_last = qp->s_cur;
|
||||||
|
if (qp->s_last == qp->s_tail)
|
||||||
|
break;
|
||||||
wqe = get_swqe_ptr(qp, qp->s_cur);
|
wqe = get_swqe_ptr(qp, qp->s_cur);
|
||||||
qp->s_state = OP(SEND_LAST);
|
qp->s_state = OP(SEND_LAST);
|
||||||
qp->s_psn = wqe->psn;
|
qp->s_psn = wqe->psn;
|
||||||
|
} else {
|
||||||
|
if (++qp->s_last >= qp->s_size)
|
||||||
|
qp->s_last = 0;
|
||||||
|
if (qp->s_last == qp->s_tail)
|
||||||
|
break;
|
||||||
|
wqe = get_swqe_ptr(qp, qp->s_last);
|
||||||
}
|
}
|
||||||
if (++qp->s_last >= qp->s_size)
|
|
||||||
qp->s_last = 0;
|
|
||||||
wqe = get_swqe_ptr(qp, qp->s_last);
|
|
||||||
if (qp->s_last == qp->s_tail)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (aeth >> 29) {
|
switch (aeth >> 29) {
|
||||||
|
@ -935,6 +939,18 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
|
||||||
list_add_tail(&qp->timerwait,
|
list_add_tail(&qp->timerwait,
|
||||||
&dev->pending[dev->pending_index]);
|
&dev->pending[dev->pending_index]);
|
||||||
spin_unlock(&dev->pending_lock);
|
spin_unlock(&dev->pending_lock);
|
||||||
|
/*
|
||||||
|
* If we get a partial ACK for a resent operation,
|
||||||
|
* we can stop resending the earlier packets and
|
||||||
|
* continue with the next packet the receiver wants.
|
||||||
|
*/
|
||||||
|
if (ipath_cmp24(qp->s_psn, psn) <= 0) {
|
||||||
|
reset_psn(qp, psn + 1);
|
||||||
|
tasklet_hi_schedule(&qp->s_task);
|
||||||
|
}
|
||||||
|
} else if (ipath_cmp24(qp->s_psn, psn) <= 0) {
|
||||||
|
qp->s_state = OP(SEND_LAST);
|
||||||
|
qp->s_psn = psn + 1;
|
||||||
}
|
}
|
||||||
ipath_get_credit(qp, aeth);
|
ipath_get_credit(qp, aeth);
|
||||||
qp->s_rnr_retry = qp->s_rnr_retry_cnt;
|
qp->s_rnr_retry = qp->s_rnr_retry_cnt;
|
||||||
|
@ -945,22 +961,23 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
|
||||||
|
|
||||||
case 1: /* RNR NAK */
|
case 1: /* RNR NAK */
|
||||||
dev->n_rnr_naks++;
|
dev->n_rnr_naks++;
|
||||||
|
if (qp->s_last == qp->s_tail)
|
||||||
|
goto bail;
|
||||||
if (qp->s_rnr_retry == 0) {
|
if (qp->s_rnr_retry == 0) {
|
||||||
if (qp->s_last == qp->s_tail)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
wc.status = IB_WC_RNR_RETRY_EXC_ERR;
|
wc.status = IB_WC_RNR_RETRY_EXC_ERR;
|
||||||
goto class_b;
|
goto class_b;
|
||||||
}
|
}
|
||||||
if (qp->s_rnr_retry_cnt < 7)
|
if (qp->s_rnr_retry_cnt < 7)
|
||||||
qp->s_rnr_retry--;
|
qp->s_rnr_retry--;
|
||||||
if (qp->s_last == qp->s_tail)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
/* The last valid PSN is the previous PSN. */
|
/* The last valid PSN is the previous PSN. */
|
||||||
update_last_psn(qp, psn - 1);
|
update_last_psn(qp, psn - 1);
|
||||||
|
|
||||||
dev->n_rc_resends += (int)qp->s_psn - (int)psn;
|
if (wqe->wr.opcode == IB_WR_RDMA_READ)
|
||||||
|
dev->n_rc_resends++;
|
||||||
|
else
|
||||||
|
dev->n_rc_resends +=
|
||||||
|
(qp->s_psn - psn) & IPATH_PSN_MASK;
|
||||||
|
|
||||||
reset_psn(qp, psn);
|
reset_psn(qp, psn);
|
||||||
|
|
||||||
|
@ -971,26 +988,20 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
|
||||||
goto bail;
|
goto bail;
|
||||||
|
|
||||||
case 3: /* NAK */
|
case 3: /* NAK */
|
||||||
/* The last valid PSN seen is the previous request's. */
|
if (qp->s_last == qp->s_tail)
|
||||||
if (qp->s_last != qp->s_tail)
|
goto bail;
|
||||||
update_last_psn(qp, wqe->psn - 1);
|
/* The last valid PSN is the previous PSN. */
|
||||||
|
update_last_psn(qp, psn - 1);
|
||||||
switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
|
switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
|
||||||
IPATH_AETH_CREDIT_MASK) {
|
IPATH_AETH_CREDIT_MASK) {
|
||||||
case 0: /* PSN sequence error */
|
case 0: /* PSN sequence error */
|
||||||
dev->n_seq_naks++;
|
dev->n_seq_naks++;
|
||||||
/*
|
/*
|
||||||
* Back up to the responder's expected PSN. XXX
|
* Back up to the responder's expected PSN.
|
||||||
* Note that we might get a NAK in the middle of an
|
* Note that we might get a NAK in the middle of an
|
||||||
* RDMA READ response which terminates the RDMA
|
* RDMA READ response which terminates the RDMA
|
||||||
* READ.
|
* READ.
|
||||||
*/
|
*/
|
||||||
if (qp->s_last == qp->s_tail)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (ipath_cmp24(psn, wqe->psn) < 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Retry the request. */
|
|
||||||
ipath_restart_rc(qp, psn, &wc);
|
ipath_restart_rc(qp, psn, &wc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue