// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB /* * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
*/
enum comp_state {
COMPST_GET_ACK,
COMPST_GET_WQE,
COMPST_COMP_WQE,
COMPST_COMP_ACK,
COMPST_CHECK_PSN,
COMPST_CHECK_ACK,
COMPST_READ,
COMPST_ATOMIC,
COMPST_WRITE_SEND,
COMPST_UPDATE_COMP,
COMPST_ERROR_RETRY,
COMPST_RNR_RETRY,
COMPST_ERROR,
COMPST_EXIT, /* We have an issue, and we want to rerun the completer */
COMPST_DONE, /* The completer finished successflly */
};
staticenum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode)
{ switch (opcode) { case IB_WR_RDMA_WRITE: return IB_WC_RDMA_WRITE; case IB_WR_RDMA_WRITE_WITH_IMM: return IB_WC_RDMA_WRITE; case IB_WR_SEND: return IB_WC_SEND; case IB_WR_SEND_WITH_IMM: return IB_WC_SEND; case IB_WR_RDMA_READ: return IB_WC_RDMA_READ; case IB_WR_ATOMIC_CMP_AND_SWP: return IB_WC_COMP_SWAP; case IB_WR_ATOMIC_FETCH_AND_ADD: return IB_WC_FETCH_ADD; case IB_WR_LSO: return IB_WC_LSO; case IB_WR_SEND_WITH_INV: return IB_WC_SEND; case IB_WR_RDMA_READ_WITH_INV: return IB_WC_RDMA_READ; case IB_WR_LOCAL_INV: return IB_WC_LOCAL_INV; case IB_WR_REG_MR: return IB_WC_REG_MR; case IB_WR_BIND_MW: return IB_WC_BIND_MW; case IB_WR_ATOMIC_WRITE: return IB_WC_ATOMIC_WRITE; case IB_WR_FLUSH: return IB_WC_FLUSH;
/* we come here whether or not we found a response packet to see if * there are any posted WQEs
*/
wqe = queue_head(qp->sq.queue, QUEUE_TYPE_FROM_CLIENT);
*wqe_p = wqe;
/* no WQE or requester has not started it yet */ if (!wqe || wqe->state == wqe_state_posted) return pkt ? COMPST_DONE : COMPST_EXIT;
/* WQE does not require an ack */ if (wqe->state == wqe_state_done) return COMPST_COMP_WQE;
/* WQE caused an error */ if (wqe->state == wqe_state_error) return COMPST_ERROR;
/* we have a WQE, if we also have an ack check its PSN */ return pkt ? COMPST_CHECK_PSN : COMPST_EXIT;
}
/* check to see if response is past the oldest WQE. if it is, complete * send/write or error read/atomic
*/
diff = psn_compare(pkt->psn, wqe->last_psn); if (diff > 0) { if (wqe->state == wqe_state_pending) { if (wqe->mask & WR_ATOMIC_OR_READ_MASK) return COMPST_ERROR_RETRY;
/* Check the sequence only */ switch (qp->comp.opcode) { case -1: /* Will catch all *_ONLY cases. */ if (!(mask & RXE_START_MASK)) return COMPST_ERROR;
break;
case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST: case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE: /* Check NAK code to handle a remote error */ if (pkt->opcode == IB_OPCODE_RC_ACKNOWLEDGE) break;
if (pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE &&
pkt->opcode != IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST) { /* read retries of partial data may restart from * read response first or response only.
*/ if ((pkt->psn == wqe->first_psn &&
pkt->opcode ==
IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) ||
(wqe->first_psn == wqe->last_psn &&
pkt->opcode ==
IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY)) break;
/* Check operation validity. */ switch (pkt->opcode) { case IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST: case IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST: case IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY:
syn = aeth_syn(pkt);
if ((syn & AETH_TYPE_MASK) != AETH_ACK) return COMPST_ERROR;
if (wqe->wr.opcode == IB_WR_ATOMIC_WRITE) return COMPST_WRITE_SEND;
fallthrough; /* (IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE doesn't have an AETH)
*/ case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE: if (wqe->wr.opcode != IB_WR_RDMA_READ &&
wqe->wr.opcode != IB_WR_RDMA_READ_WITH_INV &&
wqe->wr.opcode != IB_WR_FLUSH) {
wqe->status = IB_WC_FATAL_ERR; return COMPST_ERROR;
}
reset_retry_counters(qp); return COMPST_READ;
case IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE:
syn = aeth_syn(pkt);
if ((syn & AETH_TYPE_MASK) != AETH_ACK) return COMPST_ERROR;
/* * IBA Spec. Section 10.7.3.1 SIGNALED COMPLETIONS * ---------8<---------8<------------- * ...Note that if a completion error occurs, a Work Completion * will always be generated, even if the signaling * indicator requests an Unsignaled Completion. * ---------8<---------8<-------------
*/ staticvoid do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
{ struct rxe_dev *rxe = to_rdev(qp->ibqp.device); struct rxe_cqe cqe; bool post;
/* do we need to post a completion */
post = ((qp->sq_sig_type == IB_SIGNAL_ALL_WR) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED) ||
wqe->status != IB_WC_SUCCESS);
/* * we completed something so let req run again * if it is trying to fence
*/ if (qp->req.wait_fence) {
qp->req.wait_fence = 0;
qp->req.again = 1;
}
}
/* drain and optionally complete the send queue * if unable to complete a wqe, i.e. cq is full, stop * completing and flush the remaining wqes
*/ staticvoid flush_send_queue(struct rxe_qp *qp, bool notify)
{ struct rxe_send_wqe *wqe; struct rxe_queue *q = qp->sq.queue; int err;
/* send queue never got created. nothing to do. */ if (!qp->sq.queue) return;
while ((wqe = queue_head(q, q->type))) { if (notify) {
err = flush_send_wqe(qp, wqe); if (err)
notify = 0;
}
queue_advance_consumer(q, q->type);
}
}
/* reset the retry timer if * - QP is type RC * - there is a packet sent by the requester that * might be acked (we still might get spurious * timeouts but try to keep them as few as possible) * - the timeout parameter is set * - the QP is alive
*/ staticvoid reset_retry_timer(struct rxe_qp *qp)
{ unsignedlong flags;
while (1) {
rxe_dbg_qp(qp, "state = %s\n", comp_state_name[state]); switch (state) { case COMPST_GET_ACK:
skb = skb_dequeue(&qp->resp_pkts); if (skb) {
pkt = SKB_TO_PKT(skb);
qp->comp.timeout_retry = 0;
}
state = COMPST_GET_WQE; break;
case COMPST_GET_WQE:
state = get_wqe(qp, pkt, &wqe); break;
case COMPST_CHECK_PSN:
state = check_psn(qp, pkt, wqe); break;
case COMPST_CHECK_ACK:
state = check_ack(qp, pkt, wqe); break;
case COMPST_READ:
state = do_read(qp, pkt, wqe); break;
case COMPST_ATOMIC:
state = do_atomic(qp, pkt, wqe); break;
case COMPST_WRITE_SEND: if (wqe->state == wqe_state_pending &&
wqe->last_psn == pkt->psn)
state = COMPST_COMP_ACK; else
state = COMPST_UPDATE_COMP; break;
case COMPST_COMP_ACK:
state = complete_ack(qp, pkt, wqe); break;
case COMPST_COMP_WQE:
state = complete_wqe(qp, pkt, wqe); break;
case COMPST_UPDATE_COMP: if (pkt->mask & RXE_END_MASK)
qp->comp.opcode = -1; else
qp->comp.opcode = pkt->opcode;
if (qp->req.wait_psn) {
qp->req.wait_psn = 0;
qp->req.again = 1;
}
state = COMPST_DONE; break;
case COMPST_DONE: goto done;
case COMPST_EXIT: if (qp->comp.timeout_retry && wqe) {
state = COMPST_ERROR_RETRY; break;
}
reset_retry_timer(qp); gotoexit;
case COMPST_ERROR_RETRY: /* we come here if the retry timer fired and we did * not receive a response packet. try to retry the send * queue if that makes sense and the limits have not * been exceeded. remember that some timeouts are * spurious since we do not reset the timer but kick * it down the road or let it expire
*/
/* there is nothing to retry in this case */ if (!wqe || (wqe->state == wqe_state_posted)) gotoexit;
/* if we've started a retry, don't start another * retry sequence, unless this is a timeout.
*/ if (qp->comp.started_retry &&
!qp->comp.timeout_retry) goto done;
if (qp->comp.retry_cnt > 0) { if (qp->comp.retry_cnt != 7)
qp->comp.retry_cnt--;
/* no point in retrying if we have already * seen the last ack that the requester could * have caused
*/ if (psn_compare(qp->req.psn,
qp->comp.psn) > 0) { /* tell the requester to retry the * send queue next time around
*/
rxe_counter_inc(rxe,
RXE_CNT_COMP_RETRY);
qp->req.need_retry = 1;
qp->comp.started_retry = 1;
qp->req.again = 1;
} goto done;
/* A non-zero return value will cause rxe_do_task to * exit its loop and end the work item. A zero return * will continue looping and return to rxe_completer
*/
done:
ret = 0; goto out; exit:
ret = (qp->req.again) ? 0 : -EAGAIN;
out:
qp->req.again = 0; if (pkt)
free_pkt(pkt); return ret;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.