Skip to content

Commit

Permalink
IB/ipath: Fix RDMA read retry code
Browse files Browse the repository at this point in the history
A RDMA read response or atomic response can ACK earlier sends and RDMA
writes.  In this case, the wrong work request pointer was being used
to store the read first response or atomic result.  Also, if a RDMA
read request is retried, the code to compute which request to resend
was incorrect.

Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
  • Loading branch information
Ralph Campbell authored and Roland Dreier committed Jul 10, 2007
1 parent 9380068 commit 06ee109
Showing 1 changed file with 38 additions and 19 deletions.
57 changes: 38 additions & 19 deletions drivers/infiniband/hw/ipath/ipath_rc.c
Original file line number Diff line number Diff line change
Expand Up @@ -806,13 +806,15 @@ static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
* Called at interrupt level with the QP s_lock held and interrupts disabled.
* Returns 1 if OK, 0 if current operation should be aborted (NAK).
*/
static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
u64 val)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ib_wc wc;
struct ipath_swqe *wqe;
int ret = 0;
u32 ack_psn;
int diff;

/*
* Remove the QP from the timeout queue (or RNR timeout queue).
Expand Down Expand Up @@ -840,7 +842,19 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* The MSN might be for a later WQE than the PSN indicates so
* only complete WQEs that the PSN finishes.
*/
while (ipath_cmp24(ack_psn, wqe->lpsn) >= 0) {
while ((diff = ipath_cmp24(ack_psn, wqe->lpsn)) >= 0) {
/*
* RDMA_READ_RESPONSE_ONLY is a special case since
* we want to generate completion events for everything
* before the RDMA read, copy the data, then generate
* the completion for the read.
*/
if (wqe->wr.opcode == IB_WR_RDMA_READ &&
opcode == OP(RDMA_READ_RESPONSE_ONLY) &&
diff == 0) {
ret = 1;
goto bail;
}
/*
* If this request is a RDMA read or atomic, and the ACK is
* for a later operation, this ACK NAKs the RDMA read or
Expand All @@ -851,12 +865,10 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* is sent but before the response is received.
*/
if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
(opcode != OP(RDMA_READ_RESPONSE_LAST) ||
ipath_cmp24(ack_psn, wqe->lpsn) != 0)) ||
(opcode != OP(RDMA_READ_RESPONSE_LAST) || diff != 0)) ||
((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) &&
(opcode != OP(ATOMIC_ACKNOWLEDGE) ||
ipath_cmp24(wqe->psn, psn) != 0))) {
(opcode != OP(ATOMIC_ACKNOWLEDGE) || diff != 0))) {
/*
* The last valid PSN seen is the previous
* request's.
Expand All @@ -870,6 +882,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
*/
goto bail;
}
if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
*(u64 *) wqe->sg_list[0].vaddr = val;
if (qp->s_num_rd_atomic &&
(wqe->wr.opcode == IB_WR_RDMA_READ ||
wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
Expand Down Expand Up @@ -1079,6 +1094,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
int diff;
u32 pad;
u32 aeth;
u64 val;

spin_lock_irqsave(&qp->s_lock, flags);

Expand Down Expand Up @@ -1118,21 +1134,20 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
data += sizeof(__be32);
}
if (opcode == OP(ATOMIC_ACKNOWLEDGE)) {
u64 val;

if (!header_in_data) {
__be32 *p = ohdr->u.at.atomic_ack_eth;

val = ((u64) be32_to_cpu(p[0]) << 32) |
be32_to_cpu(p[1]);
} else
val = be64_to_cpu(((__be64 *) data)[0]);
*(u64 *) wqe->sg_list[0].vaddr = val;
}
if (!do_rc_ack(qp, aeth, psn, opcode) ||
} else
val = 0;
if (!do_rc_ack(qp, aeth, psn, opcode, val) ||
opcode != OP(RDMA_READ_RESPONSE_FIRST))
goto ack_done;
hdrsize += 4;
wqe = get_swqe_ptr(qp, qp->s_last);
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_op_err;
/*
Expand Down Expand Up @@ -1176,13 +1191,12 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto bail;

case OP(RDMA_READ_RESPONSE_ONLY):
if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
dev->n_rdma_seq++;
ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
if (!header_in_data)
aeth = be32_to_cpu(ohdr->u.aeth);
else
aeth = be32_to_cpu(((__be32 *) data)[0]);
if (!do_rc_ack(qp, aeth, psn, opcode, 0))
goto ack_done;
}
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_op_err;
/* Get the number of bytes the message was padded by. */
pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
/*
Expand All @@ -1197,6 +1211,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
* have to be careful to copy the data to the right
* location.
*/
wqe = get_swqe_ptr(qp, qp->s_last);
qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
wqe, psn, pmtu);
goto read_last;
Expand Down Expand Up @@ -1230,7 +1245,8 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
data += sizeof(__be32);
}
ipath_copy_sge(&qp->s_rdma_read_sge, data, tlen);
(void) do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST));
(void) do_rc_ack(qp, aeth, psn,
OP(RDMA_READ_RESPONSE_LAST), 0);
goto ack_done;
}

Expand Down Expand Up @@ -1344,8 +1360,11 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
e = NULL;
break;
}
if (ipath_cmp24(psn, e->psn) >= 0)
if (ipath_cmp24(psn, e->psn) >= 0) {
if (prev == qp->s_tail_ack_queue)
old_req = 0;
break;
}
}
switch (opcode) {
case OP(RDMA_READ_REQUEST): {
Expand Down

0 comments on commit 06ee109

Please sign in to comment.