Commit 034e285f authored by Xiao Yang's avatar Xiao Yang Committed by Jason Gunthorpe

RDMA/rxe: Make responder support atomic write on RC service

Make responder process an atomic write request and send a read response
on RC service.

Link: https://lore.kernel.org/r/1669905568-62-2-git-send-email-yangx.jy@fujitsu.comSigned-off-by: default avatarXiao Yang <yangx.jy@fujitsu.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent abb633cf
...@@ -22,6 +22,7 @@ enum resp_states { ...@@ -22,6 +22,7 @@ enum resp_states {
RESPST_EXECUTE, RESPST_EXECUTE,
RESPST_READ_REPLY, RESPST_READ_REPLY,
RESPST_ATOMIC_REPLY, RESPST_ATOMIC_REPLY,
RESPST_ATOMIC_WRITE_REPLY,
RESPST_COMPLETE, RESPST_COMPLETE,
RESPST_ACKNOWLEDGE, RESPST_ACKNOWLEDGE,
RESPST_CLEANUP, RESPST_CLEANUP,
...@@ -57,6 +58,7 @@ static char *resp_state_name[] = { ...@@ -57,6 +58,7 @@ static char *resp_state_name[] = {
[RESPST_EXECUTE] = "EXECUTE", [RESPST_EXECUTE] = "EXECUTE",
[RESPST_READ_REPLY] = "READ_REPLY", [RESPST_READ_REPLY] = "READ_REPLY",
[RESPST_ATOMIC_REPLY] = "ATOMIC_REPLY", [RESPST_ATOMIC_REPLY] = "ATOMIC_REPLY",
[RESPST_ATOMIC_WRITE_REPLY] = "ATOMIC_WRITE_REPLY",
[RESPST_COMPLETE] = "COMPLETE", [RESPST_COMPLETE] = "COMPLETE",
[RESPST_ACKNOWLEDGE] = "ACKNOWLEDGE", [RESPST_ACKNOWLEDGE] = "ACKNOWLEDGE",
[RESPST_CLEANUP] = "CLEANUP", [RESPST_CLEANUP] = "CLEANUP",
...@@ -263,7 +265,7 @@ static enum resp_states check_op_valid(struct rxe_qp *qp, ...@@ -263,7 +265,7 @@ static enum resp_states check_op_valid(struct rxe_qp *qp,
case IB_QPT_RC: case IB_QPT_RC:
if (((pkt->mask & RXE_READ_MASK) && if (((pkt->mask & RXE_READ_MASK) &&
!(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_READ)) || !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_READ)) ||
((pkt->mask & RXE_WRITE_MASK) && ((pkt->mask & (RXE_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) &&
!(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_WRITE)) || !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_WRITE)) ||
((pkt->mask & RXE_ATOMIC_MASK) && ((pkt->mask & RXE_ATOMIC_MASK) &&
!(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) { !(qp->attr.qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) {
...@@ -367,7 +369,7 @@ static enum resp_states check_resource(struct rxe_qp *qp, ...@@ -367,7 +369,7 @@ static enum resp_states check_resource(struct rxe_qp *qp,
} }
} }
if (pkt->mask & RXE_READ_OR_ATOMIC_MASK) { if (pkt->mask & (RXE_READ_OR_ATOMIC_MASK | RXE_ATOMIC_WRITE_MASK)) {
/* it is the requesters job to not send /* it is the requesters job to not send
* too many read/atomic ops, we just * too many read/atomic ops, we just
* recycle the responder resource queue * recycle the responder resource queue
...@@ -438,7 +440,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp, ...@@ -438,7 +440,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
enum resp_states state; enum resp_states state;
int access; int access;
if (pkt->mask & RXE_READ_OR_WRITE_MASK) { if (pkt->mask & (RXE_READ_OR_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) {
if (pkt->mask & RXE_RETH_MASK) { if (pkt->mask & RXE_RETH_MASK) {
qp->resp.va = reth_va(pkt); qp->resp.va = reth_va(pkt);
qp->resp.offset = 0; qp->resp.offset = 0;
...@@ -504,7 +506,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp, ...@@ -504,7 +506,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
goto err; goto err;
} }
if (pkt->mask & RXE_WRITE_MASK) { if (pkt->mask & (RXE_WRITE_MASK | RXE_ATOMIC_WRITE_MASK)) {
if (resid > mtu) { if (resid > mtu) {
if (pktlen != mtu || bth_pad(pkt)) { if (pktlen != mtu || bth_pad(pkt)) {
state = RESPST_ERR_LENGTH; state = RESPST_ERR_LENGTH;
...@@ -604,6 +606,7 @@ static struct resp_res *rxe_prepare_res(struct rxe_qp *qp, ...@@ -604,6 +606,7 @@ static struct resp_res *rxe_prepare_res(struct rxe_qp *qp,
res->state = rdatm_res_state_new; res->state = rdatm_res_state_new;
break; break;
case RXE_ATOMIC_MASK: case RXE_ATOMIC_MASK:
case RXE_ATOMIC_WRITE_MASK:
res->first_psn = pkt->psn; res->first_psn = pkt->psn;
res->last_psn = pkt->psn; res->last_psn = pkt->psn;
res->cur_psn = pkt->psn; res->cur_psn = pkt->psn;
...@@ -673,6 +676,55 @@ static enum resp_states atomic_reply(struct rxe_qp *qp, ...@@ -673,6 +676,55 @@ static enum resp_states atomic_reply(struct rxe_qp *qp,
return ret; return ret;
} }
static enum resp_states atomic_write_reply(struct rxe_qp *qp,
struct rxe_pkt_info *pkt)
{
u64 src, *dst;
struct resp_res *res = qp->resp.res;
struct rxe_mr *mr = qp->resp.mr;
int payload = payload_size(pkt);
if (!res) {
res = rxe_prepare_res(qp, pkt, RXE_ATOMIC_WRITE_MASK);
qp->resp.res = res;
}
if (!res->replay) {
#ifdef CONFIG_64BIT
if (mr->state != RXE_MR_STATE_VALID)
return RESPST_ERR_RKEY_VIOLATION;
memcpy(&src, payload_addr(pkt), payload);
dst = iova_to_vaddr(mr, qp->resp.va + qp->resp.offset, payload);
/* check vaddr is 8 bytes aligned. */
if (!dst || (uintptr_t)dst & 7)
return RESPST_ERR_MISALIGNED_ATOMIC;
/* Do atomic write after all prior operations have completed */
smp_store_release(dst, src);
/* decrease resp.resid to zero */
qp->resp.resid -= sizeof(payload);
qp->resp.msn++;
/* next expected psn, read handles this separately */
qp->resp.psn = (pkt->psn + 1) & BTH_PSN_MASK;
qp->resp.ack_psn = qp->resp.psn;
qp->resp.opcode = pkt->opcode;
qp->resp.status = IB_WC_SUCCESS;
return RESPST_ACKNOWLEDGE;
#else
return RESPST_ERR_UNSUPPORTED_OPCODE;
#endif /* CONFIG_64BIT */
}
return RESPST_ACKNOWLEDGE;
}
static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp, static struct sk_buff *prepare_ack_packet(struct rxe_qp *qp,
struct rxe_pkt_info *ack, struct rxe_pkt_info *ack,
int opcode, int opcode,
...@@ -912,6 +964,8 @@ static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt) ...@@ -912,6 +964,8 @@ static enum resp_states execute(struct rxe_qp *qp, struct rxe_pkt_info *pkt)
return RESPST_READ_REPLY; return RESPST_READ_REPLY;
} else if (pkt->mask & RXE_ATOMIC_MASK) { } else if (pkt->mask & RXE_ATOMIC_MASK) {
return RESPST_ATOMIC_REPLY; return RESPST_ATOMIC_REPLY;
} else if (pkt->mask & RXE_ATOMIC_WRITE_MASK) {
return RESPST_ATOMIC_WRITE_REPLY;
} else { } else {
/* Unreachable */ /* Unreachable */
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
...@@ -1085,6 +1139,19 @@ static int send_atomic_ack(struct rxe_qp *qp, u8 syndrome, u32 psn) ...@@ -1085,6 +1139,19 @@ static int send_atomic_ack(struct rxe_qp *qp, u8 syndrome, u32 psn)
return ret; return ret;
} }
static int send_read_response_ack(struct rxe_qp *qp, u8 syndrome, u32 psn)
{
int ret = send_common_ack(qp, syndrome, psn,
IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY,
"RDMA READ response of length zero ACK");
/* have to clear this since it is used to trigger
* long read replies
*/
qp->resp.res = NULL;
return ret;
}
static enum resp_states acknowledge(struct rxe_qp *qp, static enum resp_states acknowledge(struct rxe_qp *qp,
struct rxe_pkt_info *pkt) struct rxe_pkt_info *pkt)
{ {
...@@ -1095,6 +1162,8 @@ static enum resp_states acknowledge(struct rxe_qp *qp, ...@@ -1095,6 +1162,8 @@ static enum resp_states acknowledge(struct rxe_qp *qp,
send_ack(qp, qp->resp.aeth_syndrome, pkt->psn); send_ack(qp, qp->resp.aeth_syndrome, pkt->psn);
else if (pkt->mask & RXE_ATOMIC_MASK) else if (pkt->mask & RXE_ATOMIC_MASK)
send_atomic_ack(qp, AETH_ACK_UNLIMITED, pkt->psn); send_atomic_ack(qp, AETH_ACK_UNLIMITED, pkt->psn);
else if (pkt->mask & RXE_ATOMIC_WRITE_MASK)
send_read_response_ack(qp, AETH_ACK_UNLIMITED, pkt->psn);
else if (bth_ack(pkt)) else if (bth_ack(pkt))
send_ack(qp, AETH_ACK_UNLIMITED, pkt->psn); send_ack(qp, AETH_ACK_UNLIMITED, pkt->psn);
...@@ -1206,7 +1275,9 @@ static enum resp_states duplicate_request(struct rxe_qp *qp, ...@@ -1206,7 +1275,9 @@ static enum resp_states duplicate_request(struct rxe_qp *qp,
res->replay = 1; res->replay = 1;
res->cur_psn = pkt->psn; res->cur_psn = pkt->psn;
qp->resp.res = res; qp->resp.res = res;
rc = RESPST_ATOMIC_REPLY; rc = pkt->mask & RXE_ATOMIC_MASK ?
RESPST_ATOMIC_REPLY :
RESPST_ATOMIC_WRITE_REPLY;
goto out; goto out;
} }
...@@ -1343,6 +1414,9 @@ int rxe_responder(void *arg) ...@@ -1343,6 +1414,9 @@ int rxe_responder(void *arg)
case RESPST_ATOMIC_REPLY: case RESPST_ATOMIC_REPLY:
state = atomic_reply(qp, pkt); state = atomic_reply(qp, pkt);
break; break;
case RESPST_ATOMIC_WRITE_REPLY:
state = atomic_write_reply(qp, pkt);
break;
case RESPST_ACKNOWLEDGE: case RESPST_ACKNOWLEDGE:
state = acknowledge(qp, pkt); state = acknowledge(qp, pkt);
break; break;
......
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