162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2015 - 2018 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "hfi.h" 762306a36Sopenharmony_ci#include "verbs_txreq.h" 862306a36Sopenharmony_ci#include "qp.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* cut down ridiculously long IB macro names */ 1162306a36Sopenharmony_ci#define OP(x) UC_OP(x) 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/** 1462306a36Sopenharmony_ci * hfi1_make_uc_req - construct a request packet (SEND, RDMA write) 1562306a36Sopenharmony_ci * @qp: a pointer to the QP 1662306a36Sopenharmony_ci * @ps: the current packet state 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Assume s_lock is held. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Return 1 if constructed; otherwise, return 0. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ciint hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci struct hfi1_qp_priv *priv = qp->priv; 2562306a36Sopenharmony_ci struct ib_other_headers *ohdr; 2662306a36Sopenharmony_ci struct rvt_swqe *wqe; 2762306a36Sopenharmony_ci u32 hwords; 2862306a36Sopenharmony_ci u32 bth0 = 0; 2962306a36Sopenharmony_ci u32 len; 3062306a36Sopenharmony_ci u32 pmtu = qp->pmtu; 3162306a36Sopenharmony_ci int middle = 0; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci ps->s_txreq = get_txreq(ps->dev, qp); 3462306a36Sopenharmony_ci if (!ps->s_txreq) 3562306a36Sopenharmony_ci goto bail_no_tx; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_SEND_OK)) { 3862306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_FLUSH_SEND)) 3962306a36Sopenharmony_ci goto bail; 4062306a36Sopenharmony_ci /* We are in the error state, flush the work request. */ 4162306a36Sopenharmony_ci if (qp->s_last == READ_ONCE(qp->s_head)) 4262306a36Sopenharmony_ci goto bail; 4362306a36Sopenharmony_ci /* If DMAs are in progress, we can't flush immediately. */ 4462306a36Sopenharmony_ci if (iowait_sdma_pending(&priv->s_iowait)) { 4562306a36Sopenharmony_ci qp->s_flags |= RVT_S_WAIT_DMA; 4662306a36Sopenharmony_ci goto bail; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci clear_ahg(qp); 4962306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_last); 5062306a36Sopenharmony_ci rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); 5162306a36Sopenharmony_ci goto done_free_tx; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (priv->hdr_type == HFI1_PKT_TYPE_9B) { 5562306a36Sopenharmony_ci /* header size in 32-bit words LRH+BTH = (8+12)/4. */ 5662306a36Sopenharmony_ci hwords = 5; 5762306a36Sopenharmony_ci if (rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) 5862306a36Sopenharmony_ci ohdr = &ps->s_txreq->phdr.hdr.ibh.u.l.oth; 5962306a36Sopenharmony_ci else 6062306a36Sopenharmony_ci ohdr = &ps->s_txreq->phdr.hdr.ibh.u.oth; 6162306a36Sopenharmony_ci } else { 6262306a36Sopenharmony_ci /* header size in 32-bit words 16B LRH+BTH = (16+12)/4. */ 6362306a36Sopenharmony_ci hwords = 7; 6462306a36Sopenharmony_ci if ((rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) && 6562306a36Sopenharmony_ci (hfi1_check_mcast(rdma_ah_get_dlid(&qp->remote_ah_attr)))) 6662306a36Sopenharmony_ci ohdr = &ps->s_txreq->phdr.hdr.opah.u.l.oth; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci ohdr = &ps->s_txreq->phdr.hdr.opah.u.oth; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Get the next send request. */ 7262306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_cur); 7362306a36Sopenharmony_ci qp->s_wqe = NULL; 7462306a36Sopenharmony_ci switch (qp->s_state) { 7562306a36Sopenharmony_ci default: 7662306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & 7762306a36Sopenharmony_ci RVT_PROCESS_NEXT_SEND_OK)) 7862306a36Sopenharmony_ci goto bail; 7962306a36Sopenharmony_ci /* Check if send work queue is empty. */ 8062306a36Sopenharmony_ci if (qp->s_cur == READ_ONCE(qp->s_head)) { 8162306a36Sopenharmony_ci clear_ahg(qp); 8262306a36Sopenharmony_ci goto bail; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * Local operations are processed immediately 8662306a36Sopenharmony_ci * after all prior requests have completed. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_REG_MR || 8962306a36Sopenharmony_ci wqe->wr.opcode == IB_WR_LOCAL_INV) { 9062306a36Sopenharmony_ci int local_ops = 0; 9162306a36Sopenharmony_ci int err = 0; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (qp->s_last != qp->s_cur) 9462306a36Sopenharmony_ci goto bail; 9562306a36Sopenharmony_ci if (++qp->s_cur == qp->s_size) 9662306a36Sopenharmony_ci qp->s_cur = 0; 9762306a36Sopenharmony_ci if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) { 9862306a36Sopenharmony_ci err = rvt_invalidate_rkey( 9962306a36Sopenharmony_ci qp, wqe->wr.ex.invalidate_rkey); 10062306a36Sopenharmony_ci local_ops = 1; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci rvt_send_complete(qp, wqe, err ? IB_WC_LOC_PROT_ERR 10362306a36Sopenharmony_ci : IB_WC_SUCCESS); 10462306a36Sopenharmony_ci if (local_ops) 10562306a36Sopenharmony_ci atomic_dec(&qp->local_ops_pending); 10662306a36Sopenharmony_ci goto done_free_tx; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci /* 10962306a36Sopenharmony_ci * Start a new request. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci qp->s_psn = wqe->psn; 11262306a36Sopenharmony_ci qp->s_sge.sge = wqe->sg_list[0]; 11362306a36Sopenharmony_ci qp->s_sge.sg_list = wqe->sg_list + 1; 11462306a36Sopenharmony_ci qp->s_sge.num_sge = wqe->wr.num_sge; 11562306a36Sopenharmony_ci qp->s_sge.total_len = wqe->length; 11662306a36Sopenharmony_ci len = wqe->length; 11762306a36Sopenharmony_ci qp->s_len = len; 11862306a36Sopenharmony_ci switch (wqe->wr.opcode) { 11962306a36Sopenharmony_ci case IB_WR_SEND: 12062306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 12162306a36Sopenharmony_ci if (len > pmtu) { 12262306a36Sopenharmony_ci qp->s_state = OP(SEND_FIRST); 12362306a36Sopenharmony_ci len = pmtu; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND) { 12762306a36Sopenharmony_ci qp->s_state = OP(SEND_ONLY); 12862306a36Sopenharmony_ci } else { 12962306a36Sopenharmony_ci qp->s_state = 13062306a36Sopenharmony_ci OP(SEND_ONLY_WITH_IMMEDIATE); 13162306a36Sopenharmony_ci /* Immediate data comes after the BTH */ 13262306a36Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 13362306a36Sopenharmony_ci hwords += 1; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 13662306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 13762306a36Sopenharmony_ci qp->s_wqe = wqe; 13862306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 13962306a36Sopenharmony_ci qp->s_cur = 0; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 14362306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 14462306a36Sopenharmony_ci ohdr->u.rc.reth.vaddr = 14562306a36Sopenharmony_ci cpu_to_be64(wqe->rdma_wr.remote_addr); 14662306a36Sopenharmony_ci ohdr->u.rc.reth.rkey = 14762306a36Sopenharmony_ci cpu_to_be32(wqe->rdma_wr.rkey); 14862306a36Sopenharmony_ci ohdr->u.rc.reth.length = cpu_to_be32(len); 14962306a36Sopenharmony_ci hwords += sizeof(struct ib_reth) / 4; 15062306a36Sopenharmony_ci if (len > pmtu) { 15162306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_FIRST); 15262306a36Sopenharmony_ci len = pmtu; 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE) { 15662306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_ONLY); 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci qp->s_state = 15962306a36Sopenharmony_ci OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE); 16062306a36Sopenharmony_ci /* Immediate data comes after the RETH */ 16162306a36Sopenharmony_ci ohdr->u.rc.imm_data = wqe->wr.ex.imm_data; 16262306a36Sopenharmony_ci hwords += 1; 16362306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 16462306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci qp->s_wqe = wqe; 16762306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 16862306a36Sopenharmony_ci qp->s_cur = 0; 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci default: 17262306a36Sopenharmony_ci goto bail; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci case OP(SEND_FIRST): 17762306a36Sopenharmony_ci qp->s_state = OP(SEND_MIDDLE); 17862306a36Sopenharmony_ci fallthrough; 17962306a36Sopenharmony_ci case OP(SEND_MIDDLE): 18062306a36Sopenharmony_ci len = qp->s_len; 18162306a36Sopenharmony_ci if (len > pmtu) { 18262306a36Sopenharmony_ci len = pmtu; 18362306a36Sopenharmony_ci middle = HFI1_CAP_IS_KSET(SDMA_AHG); 18462306a36Sopenharmony_ci break; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND) { 18762306a36Sopenharmony_ci qp->s_state = OP(SEND_LAST); 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); 19062306a36Sopenharmony_ci /* Immediate data comes after the BTH */ 19162306a36Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 19262306a36Sopenharmony_ci hwords += 1; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 19562306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 19662306a36Sopenharmony_ci qp->s_wqe = wqe; 19762306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 19862306a36Sopenharmony_ci qp->s_cur = 0; 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 20262306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_MIDDLE); 20362306a36Sopenharmony_ci fallthrough; 20462306a36Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 20562306a36Sopenharmony_ci len = qp->s_len; 20662306a36Sopenharmony_ci if (len > pmtu) { 20762306a36Sopenharmony_ci len = pmtu; 20862306a36Sopenharmony_ci middle = HFI1_CAP_IS_KSET(SDMA_AHG); 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE) { 21262306a36Sopenharmony_ci qp->s_state = OP(RDMA_WRITE_LAST); 21362306a36Sopenharmony_ci } else { 21462306a36Sopenharmony_ci qp->s_state = 21562306a36Sopenharmony_ci OP(RDMA_WRITE_LAST_WITH_IMMEDIATE); 21662306a36Sopenharmony_ci /* Immediate data comes after the BTH */ 21762306a36Sopenharmony_ci ohdr->u.imm_data = wqe->wr.ex.imm_data; 21862306a36Sopenharmony_ci hwords += 1; 21962306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 22062306a36Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci qp->s_wqe = wqe; 22362306a36Sopenharmony_ci if (++qp->s_cur >= qp->s_size) 22462306a36Sopenharmony_ci qp->s_cur = 0; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci qp->s_len -= len; 22862306a36Sopenharmony_ci ps->s_txreq->hdr_dwords = hwords; 22962306a36Sopenharmony_ci ps->s_txreq->sde = priv->s_sde; 23062306a36Sopenharmony_ci ps->s_txreq->ss = &qp->s_sge; 23162306a36Sopenharmony_ci ps->s_txreq->s_cur_size = len; 23262306a36Sopenharmony_ci hfi1_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24), 23362306a36Sopenharmony_ci qp->remote_qpn, mask_psn(qp->s_psn++), 23462306a36Sopenharmony_ci middle, ps); 23562306a36Sopenharmony_ci return 1; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cidone_free_tx: 23862306a36Sopenharmony_ci hfi1_put_txreq(ps->s_txreq); 23962306a36Sopenharmony_ci ps->s_txreq = NULL; 24062306a36Sopenharmony_ci return 1; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cibail: 24362306a36Sopenharmony_ci hfi1_put_txreq(ps->s_txreq); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cibail_no_tx: 24662306a36Sopenharmony_ci ps->s_txreq = NULL; 24762306a36Sopenharmony_ci qp->s_flags &= ~RVT_S_BUSY; 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/** 25262306a36Sopenharmony_ci * hfi1_uc_rcv - handle an incoming UC packet 25362306a36Sopenharmony_ci * @packet: the packet structure 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * This is called from qp_rcv() to process an incoming UC packet 25662306a36Sopenharmony_ci * for the given QP. 25762306a36Sopenharmony_ci * Called at interrupt level. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_civoid hfi1_uc_rcv(struct hfi1_packet *packet) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct hfi1_ibport *ibp = rcd_to_iport(packet->rcd); 26262306a36Sopenharmony_ci void *data = packet->payload; 26362306a36Sopenharmony_ci u32 tlen = packet->tlen; 26462306a36Sopenharmony_ci struct rvt_qp *qp = packet->qp; 26562306a36Sopenharmony_ci struct ib_other_headers *ohdr = packet->ohdr; 26662306a36Sopenharmony_ci u32 opcode = packet->opcode; 26762306a36Sopenharmony_ci u32 hdrsize = packet->hlen; 26862306a36Sopenharmony_ci u32 psn; 26962306a36Sopenharmony_ci u32 pad = packet->pad; 27062306a36Sopenharmony_ci struct ib_wc wc; 27162306a36Sopenharmony_ci u32 pmtu = qp->pmtu; 27262306a36Sopenharmony_ci struct ib_reth *reth; 27362306a36Sopenharmony_ci int ret; 27462306a36Sopenharmony_ci u8 extra_bytes = pad + packet->extra_byte + (SIZE_OF_CRC << 2); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (hfi1_ruc_check_hdr(ibp, packet)) 27762306a36Sopenharmony_ci return; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci process_ecn(qp, packet); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci psn = ib_bth_get_psn(ohdr); 28262306a36Sopenharmony_ci /* Compare the PSN verses the expected PSN. */ 28362306a36Sopenharmony_ci if (unlikely(cmp_psn(psn, qp->r_psn) != 0)) { 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * Handle a sequence error. 28662306a36Sopenharmony_ci * Silently drop any current message. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci qp->r_psn = psn; 28962306a36Sopenharmony_ciinv: 29062306a36Sopenharmony_ci if (qp->r_state == OP(SEND_FIRST) || 29162306a36Sopenharmony_ci qp->r_state == OP(SEND_MIDDLE)) { 29262306a36Sopenharmony_ci set_bit(RVT_R_REWIND_SGE, &qp->r_aflags); 29362306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 29462306a36Sopenharmony_ci } else { 29562306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci qp->r_state = OP(SEND_LAST); 29862306a36Sopenharmony_ci switch (opcode) { 29962306a36Sopenharmony_ci case OP(SEND_FIRST): 30062306a36Sopenharmony_ci case OP(SEND_ONLY): 30162306a36Sopenharmony_ci case OP(SEND_ONLY_WITH_IMMEDIATE): 30262306a36Sopenharmony_ci goto send_first; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 30562306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY): 30662306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): 30762306a36Sopenharmony_ci goto rdma_first; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci default: 31062306a36Sopenharmony_ci goto drop; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Check for opcode sequence errors. */ 31562306a36Sopenharmony_ci switch (qp->r_state) { 31662306a36Sopenharmony_ci case OP(SEND_FIRST): 31762306a36Sopenharmony_ci case OP(SEND_MIDDLE): 31862306a36Sopenharmony_ci if (opcode == OP(SEND_MIDDLE) || 31962306a36Sopenharmony_ci opcode == OP(SEND_LAST) || 32062306a36Sopenharmony_ci opcode == OP(SEND_LAST_WITH_IMMEDIATE)) 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci goto inv; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 32562306a36Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 32662306a36Sopenharmony_ci if (opcode == OP(RDMA_WRITE_MIDDLE) || 32762306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_LAST) || 32862306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci goto inv; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci default: 33362306a36Sopenharmony_ci if (opcode == OP(SEND_FIRST) || 33462306a36Sopenharmony_ci opcode == OP(SEND_ONLY) || 33562306a36Sopenharmony_ci opcode == OP(SEND_ONLY_WITH_IMMEDIATE) || 33662306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_FIRST) || 33762306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_ONLY) || 33862306a36Sopenharmony_ci opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci goto inv; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (qp->state == IB_QPS_RTR && !(qp->r_flags & RVT_R_COMM_EST)) 34462306a36Sopenharmony_ci rvt_comm_est(qp); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* OK, process the packet. */ 34762306a36Sopenharmony_ci switch (opcode) { 34862306a36Sopenharmony_ci case OP(SEND_FIRST): 34962306a36Sopenharmony_ci case OP(SEND_ONLY): 35062306a36Sopenharmony_ci case OP(SEND_ONLY_WITH_IMMEDIATE): 35162306a36Sopenharmony_cisend_first: 35262306a36Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) { 35362306a36Sopenharmony_ci qp->r_sge = qp->s_rdma_read_sge; 35462306a36Sopenharmony_ci } else { 35562306a36Sopenharmony_ci ret = rvt_get_rwqe(qp, false); 35662306a36Sopenharmony_ci if (ret < 0) 35762306a36Sopenharmony_ci goto op_err; 35862306a36Sopenharmony_ci if (!ret) 35962306a36Sopenharmony_ci goto drop; 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * qp->s_rdma_read_sge will be the owner 36262306a36Sopenharmony_ci * of the mr references. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci qp->s_rdma_read_sge = qp->r_sge; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci qp->r_rcv_len = 0; 36762306a36Sopenharmony_ci if (opcode == OP(SEND_ONLY)) 36862306a36Sopenharmony_ci goto no_immediate_data; 36962306a36Sopenharmony_ci else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE)) 37062306a36Sopenharmony_ci goto send_last_imm; 37162306a36Sopenharmony_ci fallthrough; 37262306a36Sopenharmony_ci case OP(SEND_MIDDLE): 37362306a36Sopenharmony_ci /* Check for invalid length PMTU or posted rwqe len. */ 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * There will be no padding for 9B packet but 16B packets 37662306a36Sopenharmony_ci * will come in with some padding since we always add 37762306a36Sopenharmony_ci * CRC and LT bytes which will need to be flit aligned 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci if (unlikely(tlen != (hdrsize + pmtu + extra_bytes))) 38062306a36Sopenharmony_ci goto rewind; 38162306a36Sopenharmony_ci qp->r_rcv_len += pmtu; 38262306a36Sopenharmony_ci if (unlikely(qp->r_rcv_len > qp->r_len)) 38362306a36Sopenharmony_ci goto rewind; 38462306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false); 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci case OP(SEND_LAST_WITH_IMMEDIATE): 38862306a36Sopenharmony_cisend_last_imm: 38962306a36Sopenharmony_ci wc.ex.imm_data = ohdr->u.imm_data; 39062306a36Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 39162306a36Sopenharmony_ci goto send_last; 39262306a36Sopenharmony_ci case OP(SEND_LAST): 39362306a36Sopenharmony_cino_immediate_data: 39462306a36Sopenharmony_ci wc.ex.imm_data = 0; 39562306a36Sopenharmony_ci wc.wc_flags = 0; 39662306a36Sopenharmony_cisend_last: 39762306a36Sopenharmony_ci /* Check for invalid length. */ 39862306a36Sopenharmony_ci /* LAST len should be >= 1 */ 39962306a36Sopenharmony_ci if (unlikely(tlen < (hdrsize + extra_bytes))) 40062306a36Sopenharmony_ci goto rewind; 40162306a36Sopenharmony_ci /* Don't count the CRC. */ 40262306a36Sopenharmony_ci tlen -= (hdrsize + extra_bytes); 40362306a36Sopenharmony_ci wc.byte_len = tlen + qp->r_rcv_len; 40462306a36Sopenharmony_ci if (unlikely(wc.byte_len > qp->r_len)) 40562306a36Sopenharmony_ci goto rewind; 40662306a36Sopenharmony_ci wc.opcode = IB_WC_RECV; 40762306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false); 40862306a36Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 40962306a36Sopenharmony_cilast_imm: 41062306a36Sopenharmony_ci wc.wr_id = qp->r_wr_id; 41162306a36Sopenharmony_ci wc.status = IB_WC_SUCCESS; 41262306a36Sopenharmony_ci wc.qp = &qp->ibqp; 41362306a36Sopenharmony_ci wc.src_qp = qp->remote_qpn; 41462306a36Sopenharmony_ci wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX; 41562306a36Sopenharmony_ci /* 41662306a36Sopenharmony_ci * It seems that IB mandates the presence of an SL in a 41762306a36Sopenharmony_ci * work completion only for the UD transport (see section 41862306a36Sopenharmony_ci * 11.4.2 of IBTA Vol. 1). 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * However, the way the SL is chosen below is consistent 42162306a36Sopenharmony_ci * with the way that IB/qib works and is trying avoid 42262306a36Sopenharmony_ci * introducing incompatibilities. 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * See also OPA Vol. 1, section 9.7.6, and table 9-17. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ci wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); 42762306a36Sopenharmony_ci /* zero fields that are N/A */ 42862306a36Sopenharmony_ci wc.vendor_err = 0; 42962306a36Sopenharmony_ci wc.pkey_index = 0; 43062306a36Sopenharmony_ci wc.dlid_path_bits = 0; 43162306a36Sopenharmony_ci wc.port_num = 0; 43262306a36Sopenharmony_ci /* Signal completion event if the solicited bit is set. */ 43362306a36Sopenharmony_ci rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr)); 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci case OP(RDMA_WRITE_FIRST): 43762306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY): 43862306a36Sopenharmony_ci case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */ 43962306a36Sopenharmony_cirdma_first: 44062306a36Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & 44162306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE))) { 44262306a36Sopenharmony_ci goto drop; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci reth = &ohdr->u.rc.reth; 44562306a36Sopenharmony_ci qp->r_len = be32_to_cpu(reth->length); 44662306a36Sopenharmony_ci qp->r_rcv_len = 0; 44762306a36Sopenharmony_ci qp->r_sge.sg_list = NULL; 44862306a36Sopenharmony_ci if (qp->r_len != 0) { 44962306a36Sopenharmony_ci u32 rkey = be32_to_cpu(reth->rkey); 45062306a36Sopenharmony_ci u64 vaddr = be64_to_cpu(reth->vaddr); 45162306a36Sopenharmony_ci int ok; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Check rkey */ 45462306a36Sopenharmony_ci ok = rvt_rkey_ok(qp, &qp->r_sge.sge, qp->r_len, 45562306a36Sopenharmony_ci vaddr, rkey, IB_ACCESS_REMOTE_WRITE); 45662306a36Sopenharmony_ci if (unlikely(!ok)) 45762306a36Sopenharmony_ci goto drop; 45862306a36Sopenharmony_ci qp->r_sge.num_sge = 1; 45962306a36Sopenharmony_ci } else { 46062306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 46162306a36Sopenharmony_ci qp->r_sge.sge.mr = NULL; 46262306a36Sopenharmony_ci qp->r_sge.sge.vaddr = NULL; 46362306a36Sopenharmony_ci qp->r_sge.sge.length = 0; 46462306a36Sopenharmony_ci qp->r_sge.sge.sge_length = 0; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci if (opcode == OP(RDMA_WRITE_ONLY)) { 46762306a36Sopenharmony_ci goto rdma_last; 46862306a36Sopenharmony_ci } else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) { 46962306a36Sopenharmony_ci wc.ex.imm_data = ohdr->u.rc.imm_data; 47062306a36Sopenharmony_ci goto rdma_last_imm; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci fallthrough; 47362306a36Sopenharmony_ci case OP(RDMA_WRITE_MIDDLE): 47462306a36Sopenharmony_ci /* Check for invalid length PMTU or posted rwqe len. */ 47562306a36Sopenharmony_ci if (unlikely(tlen != (hdrsize + pmtu + 4))) 47662306a36Sopenharmony_ci goto drop; 47762306a36Sopenharmony_ci qp->r_rcv_len += pmtu; 47862306a36Sopenharmony_ci if (unlikely(qp->r_rcv_len > qp->r_len)) 47962306a36Sopenharmony_ci goto drop; 48062306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): 48462306a36Sopenharmony_ci wc.ex.imm_data = ohdr->u.imm_data; 48562306a36Sopenharmony_cirdma_last_imm: 48662306a36Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Check for invalid length. */ 48962306a36Sopenharmony_ci /* LAST len should be >= 1 */ 49062306a36Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 49162306a36Sopenharmony_ci goto drop; 49262306a36Sopenharmony_ci /* Don't count the CRC. */ 49362306a36Sopenharmony_ci tlen -= (hdrsize + extra_bytes); 49462306a36Sopenharmony_ci if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) 49562306a36Sopenharmony_ci goto drop; 49662306a36Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) { 49762306a36Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 49862306a36Sopenharmony_ci } else { 49962306a36Sopenharmony_ci ret = rvt_get_rwqe(qp, true); 50062306a36Sopenharmony_ci if (ret < 0) 50162306a36Sopenharmony_ci goto op_err; 50262306a36Sopenharmony_ci if (!ret) 50362306a36Sopenharmony_ci goto drop; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci wc.byte_len = qp->r_len; 50662306a36Sopenharmony_ci wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; 50762306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); 50862306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 50962306a36Sopenharmony_ci goto last_imm; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci case OP(RDMA_WRITE_LAST): 51262306a36Sopenharmony_cirdma_last: 51362306a36Sopenharmony_ci /* Check for invalid length. */ 51462306a36Sopenharmony_ci /* LAST len should be >= 1 */ 51562306a36Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 51662306a36Sopenharmony_ci goto drop; 51762306a36Sopenharmony_ci /* Don't count the CRC. */ 51862306a36Sopenharmony_ci tlen -= (hdrsize + extra_bytes); 51962306a36Sopenharmony_ci if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) 52062306a36Sopenharmony_ci goto drop; 52162306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false); 52262306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci default: 52662306a36Sopenharmony_ci /* Drop packet for unknown opcodes. */ 52762306a36Sopenharmony_ci goto drop; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci qp->r_psn++; 53062306a36Sopenharmony_ci qp->r_state = opcode; 53162306a36Sopenharmony_ci return; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cirewind: 53462306a36Sopenharmony_ci set_bit(RVT_R_REWIND_SGE, &qp->r_aflags); 53562306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 53662306a36Sopenharmony_cidrop: 53762306a36Sopenharmony_ci ibp->rvp.n_pkt_drops++; 53862306a36Sopenharmony_ci return; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ciop_err: 54162306a36Sopenharmony_ci rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR); 54262306a36Sopenharmony_ci} 543