162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/skbuff.h> 862306a36Sopenharmony_ci#include <crypto/hash.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "rxe.h" 1162306a36Sopenharmony_ci#include "rxe_loc.h" 1262306a36Sopenharmony_ci#include "rxe_queue.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe, 1562306a36Sopenharmony_ci u32 opcode); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic inline void retry_first_write_send(struct rxe_qp *qp, 1862306a36Sopenharmony_ci struct rxe_send_wqe *wqe, int npsn) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci int i; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci for (i = 0; i < npsn; i++) { 2362306a36Sopenharmony_ci int to_send = (wqe->dma.resid > qp->mtu) ? 2462306a36Sopenharmony_ci qp->mtu : wqe->dma.resid; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci qp->req.opcode = next_opcode(qp, wqe, 2762306a36Sopenharmony_ci wqe->wr.opcode); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_INLINE) { 3062306a36Sopenharmony_ci wqe->dma.resid -= to_send; 3162306a36Sopenharmony_ci wqe->dma.sge_offset += to_send; 3262306a36Sopenharmony_ci } else { 3362306a36Sopenharmony_ci advance_dma_data(&wqe->dma, to_send); 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void req_retry(struct rxe_qp *qp) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct rxe_send_wqe *wqe; 4162306a36Sopenharmony_ci unsigned int wqe_index; 4262306a36Sopenharmony_ci unsigned int mask; 4362306a36Sopenharmony_ci int npsn; 4462306a36Sopenharmony_ci int first = 1; 4562306a36Sopenharmony_ci struct rxe_queue *q = qp->sq.queue; 4662306a36Sopenharmony_ci unsigned int cons; 4762306a36Sopenharmony_ci unsigned int prod; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci cons = queue_get_consumer(q, QUEUE_TYPE_FROM_CLIENT); 5062306a36Sopenharmony_ci prod = queue_get_producer(q, QUEUE_TYPE_FROM_CLIENT); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci qp->req.wqe_index = cons; 5362306a36Sopenharmony_ci qp->req.psn = qp->comp.psn; 5462306a36Sopenharmony_ci qp->req.opcode = -1; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (wqe_index = cons; wqe_index != prod; 5762306a36Sopenharmony_ci wqe_index = queue_next_index(q, wqe_index)) { 5862306a36Sopenharmony_ci wqe = queue_addr_from_index(qp->sq.queue, wqe_index); 5962306a36Sopenharmony_ci mask = wr_opcode_mask(wqe->wr.opcode, qp); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (wqe->state == wqe_state_posted) 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (wqe->state == wqe_state_done) 6562306a36Sopenharmony_ci continue; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci wqe->iova = (mask & WR_ATOMIC_MASK) ? 6862306a36Sopenharmony_ci wqe->wr.wr.atomic.remote_addr : 6962306a36Sopenharmony_ci (mask & WR_READ_OR_WRITE_MASK) ? 7062306a36Sopenharmony_ci wqe->wr.wr.rdma.remote_addr : 7162306a36Sopenharmony_ci 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (!first || (mask & WR_READ_MASK) == 0) { 7462306a36Sopenharmony_ci wqe->dma.resid = wqe->dma.length; 7562306a36Sopenharmony_ci wqe->dma.cur_sge = 0; 7662306a36Sopenharmony_ci wqe->dma.sge_offset = 0; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (first) { 8062306a36Sopenharmony_ci first = 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (mask & WR_WRITE_OR_SEND_MASK) { 8362306a36Sopenharmony_ci npsn = (qp->comp.psn - wqe->first_psn) & 8462306a36Sopenharmony_ci BTH_PSN_MASK; 8562306a36Sopenharmony_ci retry_first_write_send(qp, wqe, npsn); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (mask & WR_READ_MASK) { 8962306a36Sopenharmony_ci npsn = (wqe->dma.length - wqe->dma.resid) / 9062306a36Sopenharmony_ci qp->mtu; 9162306a36Sopenharmony_ci wqe->iova += npsn * qp->mtu; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci wqe->state = wqe_state_posted; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_civoid rnr_nak_timer(struct timer_list *t) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct rxe_qp *qp = from_timer(qp, t, rnr_nak_timer); 10262306a36Sopenharmony_ci unsigned long flags; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci rxe_dbg_qp(qp, "nak timer fired\n"); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 10762306a36Sopenharmony_ci if (qp->valid) { 10862306a36Sopenharmony_ci /* request a send queue retry */ 10962306a36Sopenharmony_ci qp->req.need_retry = 1; 11062306a36Sopenharmony_ci qp->req.wait_for_rnr_timer = 0; 11162306a36Sopenharmony_ci rxe_sched_task(&qp->req.task); 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void req_check_sq_drain_done(struct rxe_qp *qp) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct rxe_queue *q; 11962306a36Sopenharmony_ci unsigned int index; 12062306a36Sopenharmony_ci unsigned int cons; 12162306a36Sopenharmony_ci struct rxe_send_wqe *wqe; 12262306a36Sopenharmony_ci unsigned long flags; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 12562306a36Sopenharmony_ci if (qp_state(qp) == IB_QPS_SQD) { 12662306a36Sopenharmony_ci q = qp->sq.queue; 12762306a36Sopenharmony_ci index = qp->req.wqe_index; 12862306a36Sopenharmony_ci cons = queue_get_consumer(q, QUEUE_TYPE_FROM_CLIENT); 12962306a36Sopenharmony_ci wqe = queue_addr_from_index(q, cons); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* check to see if we are drained; 13262306a36Sopenharmony_ci * state_lock used by requester and completer 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci do { 13562306a36Sopenharmony_ci if (!qp->attr.sq_draining) 13662306a36Sopenharmony_ci /* comp just finished */ 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (wqe && ((index != cons) || 14062306a36Sopenharmony_ci (wqe->state != wqe_state_posted))) 14162306a36Sopenharmony_ci /* comp not done yet */ 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci qp->attr.sq_draining = 0; 14562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (qp->ibqp.event_handler) { 14862306a36Sopenharmony_ci struct ib_event ev; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ev.device = qp->ibqp.device; 15162306a36Sopenharmony_ci ev.element.qp = &qp->ibqp; 15262306a36Sopenharmony_ci ev.event = IB_EVENT_SQ_DRAINED; 15362306a36Sopenharmony_ci qp->ibqp.event_handler(&ev, 15462306a36Sopenharmony_ci qp->ibqp.qp_context); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci return; 15762306a36Sopenharmony_ci } while (0); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic struct rxe_send_wqe *__req_next_wqe(struct rxe_qp *qp) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct rxe_queue *q = qp->sq.queue; 16562306a36Sopenharmony_ci unsigned int index = qp->req.wqe_index; 16662306a36Sopenharmony_ci unsigned int prod; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci prod = queue_get_producer(q, QUEUE_TYPE_FROM_CLIENT); 16962306a36Sopenharmony_ci if (index == prod) 17062306a36Sopenharmony_ci return NULL; 17162306a36Sopenharmony_ci else 17262306a36Sopenharmony_ci return queue_addr_from_index(q, index); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct rxe_send_wqe *wqe; 17862306a36Sopenharmony_ci unsigned long flags; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci req_check_sq_drain_done(qp); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci wqe = __req_next_wqe(qp); 18362306a36Sopenharmony_ci if (wqe == NULL) 18462306a36Sopenharmony_ci return NULL; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 18762306a36Sopenharmony_ci if (unlikely((qp_state(qp) == IB_QPS_SQD) && 18862306a36Sopenharmony_ci (wqe->state != wqe_state_processing))) { 18962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 19062306a36Sopenharmony_ci return NULL; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci wqe->mask = wr_opcode_mask(wqe->wr.opcode, qp); 19562306a36Sopenharmony_ci return wqe; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/** 19962306a36Sopenharmony_ci * rxe_wqe_is_fenced - check if next wqe is fenced 20062306a36Sopenharmony_ci * @qp: the queue pair 20162306a36Sopenharmony_ci * @wqe: the next wqe 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Returns: 1 if wqe needs to wait 20462306a36Sopenharmony_ci * 0 if wqe is ready to go 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic int rxe_wqe_is_fenced(struct rxe_qp *qp, struct rxe_send_wqe *wqe) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci /* Local invalidate fence (LIF) see IBA 10.6.5.1 20962306a36Sopenharmony_ci * Requires ALL previous operations on the send queue 21062306a36Sopenharmony_ci * are complete. Make mandatory for the rxe driver. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_LOCAL_INV) 21362306a36Sopenharmony_ci return qp->req.wqe_index != queue_get_consumer(qp->sq.queue, 21462306a36Sopenharmony_ci QUEUE_TYPE_FROM_CLIENT); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Fence see IBA 10.8.3.3 21762306a36Sopenharmony_ci * Requires that all previous read and atomic operations 21862306a36Sopenharmony_ci * are complete. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci return (wqe->wr.send_flags & IB_SEND_FENCE) && 22162306a36Sopenharmony_ci atomic_read(&qp->req.rd_atomic) != qp->attr.max_rd_atomic; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int next_opcode_rc(struct rxe_qp *qp, u32 opcode, int fits) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci switch (opcode) { 22762306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 22862306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_FIRST || 22962306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_MIDDLE) 23062306a36Sopenharmony_ci return fits ? 23162306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_LAST : 23262306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_MIDDLE; 23362306a36Sopenharmony_ci else 23462306a36Sopenharmony_ci return fits ? 23562306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_ONLY : 23662306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_FIRST; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 23962306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_FIRST || 24062306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_RC_RDMA_WRITE_MIDDLE) 24162306a36Sopenharmony_ci return fits ? 24262306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE : 24362306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_MIDDLE; 24462306a36Sopenharmony_ci else 24562306a36Sopenharmony_ci return fits ? 24662306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE : 24762306a36Sopenharmony_ci IB_OPCODE_RC_RDMA_WRITE_FIRST; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci case IB_WR_SEND: 25062306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST || 25162306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE) 25262306a36Sopenharmony_ci return fits ? 25362306a36Sopenharmony_ci IB_OPCODE_RC_SEND_LAST : 25462306a36Sopenharmony_ci IB_OPCODE_RC_SEND_MIDDLE; 25562306a36Sopenharmony_ci else 25662306a36Sopenharmony_ci return fits ? 25762306a36Sopenharmony_ci IB_OPCODE_RC_SEND_ONLY : 25862306a36Sopenharmony_ci IB_OPCODE_RC_SEND_FIRST; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 26162306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST || 26262306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE) 26362306a36Sopenharmony_ci return fits ? 26462306a36Sopenharmony_ci IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE : 26562306a36Sopenharmony_ci IB_OPCODE_RC_SEND_MIDDLE; 26662306a36Sopenharmony_ci else 26762306a36Sopenharmony_ci return fits ? 26862306a36Sopenharmony_ci IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE : 26962306a36Sopenharmony_ci IB_OPCODE_RC_SEND_FIRST; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci case IB_WR_FLUSH: 27262306a36Sopenharmony_ci return IB_OPCODE_RC_FLUSH; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci case IB_WR_RDMA_READ: 27562306a36Sopenharmony_ci return IB_OPCODE_RC_RDMA_READ_REQUEST; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: 27862306a36Sopenharmony_ci return IB_OPCODE_RC_COMPARE_SWAP; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: 28162306a36Sopenharmony_ci return IB_OPCODE_RC_FETCH_ADD; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 28462306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_RC_SEND_FIRST || 28562306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_RC_SEND_MIDDLE) 28662306a36Sopenharmony_ci return fits ? IB_OPCODE_RC_SEND_LAST_WITH_INVALIDATE : 28762306a36Sopenharmony_ci IB_OPCODE_RC_SEND_MIDDLE; 28862306a36Sopenharmony_ci else 28962306a36Sopenharmony_ci return fits ? IB_OPCODE_RC_SEND_ONLY_WITH_INVALIDATE : 29062306a36Sopenharmony_ci IB_OPCODE_RC_SEND_FIRST; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci case IB_WR_ATOMIC_WRITE: 29362306a36Sopenharmony_ci return IB_OPCODE_RC_ATOMIC_WRITE; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci case IB_WR_REG_MR: 29662306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 29762306a36Sopenharmony_ci return opcode; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return -EINVAL; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int next_opcode_uc(struct rxe_qp *qp, u32 opcode, int fits) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci switch (opcode) { 30662306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 30762306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_FIRST || 30862306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_MIDDLE) 30962306a36Sopenharmony_ci return fits ? 31062306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_LAST : 31162306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_MIDDLE; 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci return fits ? 31462306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_ONLY : 31562306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_FIRST; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 31862306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_FIRST || 31962306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_UC_RDMA_WRITE_MIDDLE) 32062306a36Sopenharmony_ci return fits ? 32162306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE : 32262306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_MIDDLE; 32362306a36Sopenharmony_ci else 32462306a36Sopenharmony_ci return fits ? 32562306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE : 32662306a36Sopenharmony_ci IB_OPCODE_UC_RDMA_WRITE_FIRST; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci case IB_WR_SEND: 32962306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_UC_SEND_FIRST || 33062306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_UC_SEND_MIDDLE) 33162306a36Sopenharmony_ci return fits ? 33262306a36Sopenharmony_ci IB_OPCODE_UC_SEND_LAST : 33362306a36Sopenharmony_ci IB_OPCODE_UC_SEND_MIDDLE; 33462306a36Sopenharmony_ci else 33562306a36Sopenharmony_ci return fits ? 33662306a36Sopenharmony_ci IB_OPCODE_UC_SEND_ONLY : 33762306a36Sopenharmony_ci IB_OPCODE_UC_SEND_FIRST; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 34062306a36Sopenharmony_ci if (qp->req.opcode == IB_OPCODE_UC_SEND_FIRST || 34162306a36Sopenharmony_ci qp->req.opcode == IB_OPCODE_UC_SEND_MIDDLE) 34262306a36Sopenharmony_ci return fits ? 34362306a36Sopenharmony_ci IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE : 34462306a36Sopenharmony_ci IB_OPCODE_UC_SEND_MIDDLE; 34562306a36Sopenharmony_ci else 34662306a36Sopenharmony_ci return fits ? 34762306a36Sopenharmony_ci IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE : 34862306a36Sopenharmony_ci IB_OPCODE_UC_SEND_FIRST; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return -EINVAL; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int next_opcode(struct rxe_qp *qp, struct rxe_send_wqe *wqe, 35562306a36Sopenharmony_ci u32 opcode) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci int fits = (wqe->dma.resid <= qp->mtu); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci switch (qp_type(qp)) { 36062306a36Sopenharmony_ci case IB_QPT_RC: 36162306a36Sopenharmony_ci return next_opcode_rc(qp, opcode, fits); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci case IB_QPT_UC: 36462306a36Sopenharmony_ci return next_opcode_uc(qp, opcode, fits); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci case IB_QPT_UD: 36762306a36Sopenharmony_ci case IB_QPT_GSI: 36862306a36Sopenharmony_ci switch (opcode) { 36962306a36Sopenharmony_ci case IB_WR_SEND: 37062306a36Sopenharmony_ci return IB_OPCODE_UD_SEND_ONLY; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 37362306a36Sopenharmony_ci return IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci default: 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic inline int check_init_depth(struct rxe_qp *qp, struct rxe_send_wqe *wqe) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci int depth; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (wqe->has_rd_atomic) 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci qp->req.need_rd_atomic = 1; 39262306a36Sopenharmony_ci depth = atomic_dec_return(&qp->req.rd_atomic); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (depth >= 0) { 39562306a36Sopenharmony_ci qp->req.need_rd_atomic = 0; 39662306a36Sopenharmony_ci wqe->has_rd_atomic = 1; 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci atomic_inc(&qp->req.rd_atomic); 40162306a36Sopenharmony_ci return -EAGAIN; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic inline int get_mtu(struct rxe_qp *qp) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if ((qp_type(qp) == IB_QPT_RC) || (qp_type(qp) == IB_QPT_UC)) 40962306a36Sopenharmony_ci return qp->mtu; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return rxe->port.mtu_cap; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic struct sk_buff *init_req_packet(struct rxe_qp *qp, 41562306a36Sopenharmony_ci struct rxe_av *av, 41662306a36Sopenharmony_ci struct rxe_send_wqe *wqe, 41762306a36Sopenharmony_ci int opcode, u32 payload, 41862306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 42162306a36Sopenharmony_ci struct sk_buff *skb; 42262306a36Sopenharmony_ci struct rxe_send_wr *ibwr = &wqe->wr; 42362306a36Sopenharmony_ci int pad = (-payload) & 0x3; 42462306a36Sopenharmony_ci int paylen; 42562306a36Sopenharmony_ci int solicited; 42662306a36Sopenharmony_ci u32 qp_num; 42762306a36Sopenharmony_ci int ack_req; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* length from start of bth to end of icrc */ 43062306a36Sopenharmony_ci paylen = rxe_opcode[opcode].length + payload + pad + RXE_ICRC_SIZE; 43162306a36Sopenharmony_ci pkt->paylen = paylen; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* init skb */ 43462306a36Sopenharmony_ci skb = rxe_init_packet(rxe, av, paylen, pkt); 43562306a36Sopenharmony_ci if (unlikely(!skb)) 43662306a36Sopenharmony_ci return NULL; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* init bth */ 43962306a36Sopenharmony_ci solicited = (ibwr->send_flags & IB_SEND_SOLICITED) && 44062306a36Sopenharmony_ci (pkt->mask & RXE_END_MASK) && 44162306a36Sopenharmony_ci ((pkt->mask & (RXE_SEND_MASK)) || 44262306a36Sopenharmony_ci (pkt->mask & (RXE_WRITE_MASK | RXE_IMMDT_MASK)) == 44362306a36Sopenharmony_ci (RXE_WRITE_MASK | RXE_IMMDT_MASK)); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci qp_num = (pkt->mask & RXE_DETH_MASK) ? ibwr->wr.ud.remote_qpn : 44662306a36Sopenharmony_ci qp->attr.dest_qp_num; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci ack_req = ((pkt->mask & RXE_END_MASK) || 44962306a36Sopenharmony_ci (qp->req.noack_pkts++ > RXE_MAX_PKT_PER_ACK)); 45062306a36Sopenharmony_ci if (ack_req) 45162306a36Sopenharmony_ci qp->req.noack_pkts = 0; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci bth_init(pkt, pkt->opcode, solicited, 0, pad, IB_DEFAULT_PKEY_FULL, qp_num, 45462306a36Sopenharmony_ci ack_req, pkt->psn); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* init optional headers */ 45762306a36Sopenharmony_ci if (pkt->mask & RXE_RETH_MASK) { 45862306a36Sopenharmony_ci if (pkt->mask & RXE_FETH_MASK) 45962306a36Sopenharmony_ci reth_set_rkey(pkt, ibwr->wr.flush.rkey); 46062306a36Sopenharmony_ci else 46162306a36Sopenharmony_ci reth_set_rkey(pkt, ibwr->wr.rdma.rkey); 46262306a36Sopenharmony_ci reth_set_va(pkt, wqe->iova); 46362306a36Sopenharmony_ci reth_set_len(pkt, wqe->dma.resid); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Fill Flush Extension Transport Header */ 46762306a36Sopenharmony_ci if (pkt->mask & RXE_FETH_MASK) 46862306a36Sopenharmony_ci feth_init(pkt, ibwr->wr.flush.type, ibwr->wr.flush.level); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (pkt->mask & RXE_IMMDT_MASK) 47162306a36Sopenharmony_ci immdt_set_imm(pkt, ibwr->ex.imm_data); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (pkt->mask & RXE_IETH_MASK) 47462306a36Sopenharmony_ci ieth_set_rkey(pkt, ibwr->ex.invalidate_rkey); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (pkt->mask & RXE_ATMETH_MASK) { 47762306a36Sopenharmony_ci atmeth_set_va(pkt, wqe->iova); 47862306a36Sopenharmony_ci if (opcode == IB_OPCODE_RC_COMPARE_SWAP) { 47962306a36Sopenharmony_ci atmeth_set_swap_add(pkt, ibwr->wr.atomic.swap); 48062306a36Sopenharmony_ci atmeth_set_comp(pkt, ibwr->wr.atomic.compare_add); 48162306a36Sopenharmony_ci } else { 48262306a36Sopenharmony_ci atmeth_set_swap_add(pkt, ibwr->wr.atomic.compare_add); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci atmeth_set_rkey(pkt, ibwr->wr.atomic.rkey); 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (pkt->mask & RXE_DETH_MASK) { 48862306a36Sopenharmony_ci if (qp->ibqp.qp_num == 1) 48962306a36Sopenharmony_ci deth_set_qkey(pkt, GSI_QKEY); 49062306a36Sopenharmony_ci else 49162306a36Sopenharmony_ci deth_set_qkey(pkt, ibwr->wr.ud.remote_qkey); 49262306a36Sopenharmony_ci deth_set_sqp(pkt, qp->ibqp.qp_num); 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return skb; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int finish_packet(struct rxe_qp *qp, struct rxe_av *av, 49962306a36Sopenharmony_ci struct rxe_send_wqe *wqe, struct rxe_pkt_info *pkt, 50062306a36Sopenharmony_ci struct sk_buff *skb, u32 payload) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci int err; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci err = rxe_prepare(av, pkt, skb); 50562306a36Sopenharmony_ci if (err) 50662306a36Sopenharmony_ci return err; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (pkt->mask & RXE_WRITE_OR_SEND_MASK) { 50962306a36Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_INLINE) { 51062306a36Sopenharmony_ci u8 *tmp = &wqe->dma.inline_data[wqe->dma.sge_offset]; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci memcpy(payload_addr(pkt), tmp, payload); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci wqe->dma.resid -= payload; 51562306a36Sopenharmony_ci wqe->dma.sge_offset += payload; 51662306a36Sopenharmony_ci } else { 51762306a36Sopenharmony_ci err = copy_data(qp->pd, 0, &wqe->dma, 51862306a36Sopenharmony_ci payload_addr(pkt), payload, 51962306a36Sopenharmony_ci RXE_FROM_MR_OBJ); 52062306a36Sopenharmony_ci if (err) 52162306a36Sopenharmony_ci return err; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci if (bth_pad(pkt)) { 52462306a36Sopenharmony_ci u8 *pad = payload_addr(pkt) + payload; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci memset(pad, 0, bth_pad(pkt)); 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci } else if (pkt->mask & RXE_FLUSH_MASK) { 52962306a36Sopenharmony_ci /* oA19-2: shall have no payload. */ 53062306a36Sopenharmony_ci wqe->dma.resid = 0; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (pkt->mask & RXE_ATOMIC_WRITE_MASK) { 53462306a36Sopenharmony_ci memcpy(payload_addr(pkt), wqe->dma.atomic_wr, payload); 53562306a36Sopenharmony_ci wqe->dma.resid -= payload; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic void update_wqe_state(struct rxe_qp *qp, 54262306a36Sopenharmony_ci struct rxe_send_wqe *wqe, 54362306a36Sopenharmony_ci struct rxe_pkt_info *pkt) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci if (pkt->mask & RXE_END_MASK) { 54662306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_RC) 54762306a36Sopenharmony_ci wqe->state = wqe_state_pending; 54862306a36Sopenharmony_ci } else { 54962306a36Sopenharmony_ci wqe->state = wqe_state_processing; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic void update_wqe_psn(struct rxe_qp *qp, 55462306a36Sopenharmony_ci struct rxe_send_wqe *wqe, 55562306a36Sopenharmony_ci struct rxe_pkt_info *pkt, 55662306a36Sopenharmony_ci u32 payload) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci /* number of packets left to send including current one */ 55962306a36Sopenharmony_ci int num_pkt = (wqe->dma.resid + payload + qp->mtu - 1) / qp->mtu; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* handle zero length packet case */ 56262306a36Sopenharmony_ci if (num_pkt == 0) 56362306a36Sopenharmony_ci num_pkt = 1; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (pkt->mask & RXE_START_MASK) { 56662306a36Sopenharmony_ci wqe->first_psn = qp->req.psn; 56762306a36Sopenharmony_ci wqe->last_psn = (qp->req.psn + num_pkt - 1) & BTH_PSN_MASK; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (pkt->mask & RXE_READ_MASK) 57162306a36Sopenharmony_ci qp->req.psn = (wqe->first_psn + num_pkt) & BTH_PSN_MASK; 57262306a36Sopenharmony_ci else 57362306a36Sopenharmony_ci qp->req.psn = (qp->req.psn + 1) & BTH_PSN_MASK; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic void save_state(struct rxe_send_wqe *wqe, 57762306a36Sopenharmony_ci struct rxe_qp *qp, 57862306a36Sopenharmony_ci struct rxe_send_wqe *rollback_wqe, 57962306a36Sopenharmony_ci u32 *rollback_psn) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci rollback_wqe->state = wqe->state; 58262306a36Sopenharmony_ci rollback_wqe->first_psn = wqe->first_psn; 58362306a36Sopenharmony_ci rollback_wqe->last_psn = wqe->last_psn; 58462306a36Sopenharmony_ci rollback_wqe->dma = wqe->dma; 58562306a36Sopenharmony_ci *rollback_psn = qp->req.psn; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic void rollback_state(struct rxe_send_wqe *wqe, 58962306a36Sopenharmony_ci struct rxe_qp *qp, 59062306a36Sopenharmony_ci struct rxe_send_wqe *rollback_wqe, 59162306a36Sopenharmony_ci u32 rollback_psn) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci wqe->state = rollback_wqe->state; 59462306a36Sopenharmony_ci wqe->first_psn = rollback_wqe->first_psn; 59562306a36Sopenharmony_ci wqe->last_psn = rollback_wqe->last_psn; 59662306a36Sopenharmony_ci wqe->dma = rollback_wqe->dma; 59762306a36Sopenharmony_ci qp->req.psn = rollback_psn; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic void update_state(struct rxe_qp *qp, struct rxe_pkt_info *pkt) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci qp->req.opcode = pkt->opcode; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (pkt->mask & RXE_END_MASK) 60562306a36Sopenharmony_ci qp->req.wqe_index = queue_next_index(qp->sq.queue, 60662306a36Sopenharmony_ci qp->req.wqe_index); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci qp->need_req_skb = 0; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (qp->qp_timeout_jiffies && !timer_pending(&qp->retrans_timer)) 61162306a36Sopenharmony_ci mod_timer(&qp->retrans_timer, 61262306a36Sopenharmony_ci jiffies + qp->qp_timeout_jiffies); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int rxe_do_local_ops(struct rxe_qp *qp, struct rxe_send_wqe *wqe) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci u8 opcode = wqe->wr.opcode; 61862306a36Sopenharmony_ci u32 rkey; 61962306a36Sopenharmony_ci int ret; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci switch (opcode) { 62262306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 62362306a36Sopenharmony_ci rkey = wqe->wr.ex.invalidate_rkey; 62462306a36Sopenharmony_ci if (rkey_is_mw(rkey)) 62562306a36Sopenharmony_ci ret = rxe_invalidate_mw(qp, rkey); 62662306a36Sopenharmony_ci else 62762306a36Sopenharmony_ci ret = rxe_invalidate_mr(qp, rkey); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (unlikely(ret)) { 63062306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 63162306a36Sopenharmony_ci return ret; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case IB_WR_REG_MR: 63562306a36Sopenharmony_ci ret = rxe_reg_fast_mr(qp, wqe); 63662306a36Sopenharmony_ci if (unlikely(ret)) { 63762306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci case IB_WR_BIND_MW: 64262306a36Sopenharmony_ci ret = rxe_bind_mw(qp, wqe); 64362306a36Sopenharmony_ci if (unlikely(ret)) { 64462306a36Sopenharmony_ci wqe->status = IB_WC_MW_BIND_ERR; 64562306a36Sopenharmony_ci return ret; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci break; 64862306a36Sopenharmony_ci default: 64962306a36Sopenharmony_ci rxe_dbg_qp(qp, "Unexpected send wqe opcode %d\n", opcode); 65062306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 65162306a36Sopenharmony_ci return -EINVAL; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci wqe->state = wqe_state_done; 65562306a36Sopenharmony_ci wqe->status = IB_WC_SUCCESS; 65662306a36Sopenharmony_ci qp->req.wqe_index = queue_next_index(qp->sq.queue, qp->req.wqe_index); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* There is no ack coming for local work requests 65962306a36Sopenharmony_ci * which can lead to a deadlock. So go ahead and complete 66062306a36Sopenharmony_ci * it now. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_ci rxe_sched_task(&qp->comp.task); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ciint rxe_requester(struct rxe_qp *qp) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct rxe_dev *rxe = to_rdev(qp->ibqp.device); 67062306a36Sopenharmony_ci struct rxe_pkt_info pkt; 67162306a36Sopenharmony_ci struct sk_buff *skb; 67262306a36Sopenharmony_ci struct rxe_send_wqe *wqe; 67362306a36Sopenharmony_ci enum rxe_hdr_mask mask; 67462306a36Sopenharmony_ci u32 payload; 67562306a36Sopenharmony_ci int mtu; 67662306a36Sopenharmony_ci int opcode; 67762306a36Sopenharmony_ci int err; 67862306a36Sopenharmony_ci int ret; 67962306a36Sopenharmony_ci struct rxe_send_wqe rollback_wqe; 68062306a36Sopenharmony_ci u32 rollback_psn; 68162306a36Sopenharmony_ci struct rxe_queue *q = qp->sq.queue; 68262306a36Sopenharmony_ci struct rxe_ah *ah; 68362306a36Sopenharmony_ci struct rxe_av *av; 68462306a36Sopenharmony_ci unsigned long flags; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci spin_lock_irqsave(&qp->state_lock, flags); 68762306a36Sopenharmony_ci if (unlikely(!qp->valid)) { 68862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 68962306a36Sopenharmony_ci goto exit; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (unlikely(qp_state(qp) == IB_QPS_ERR)) { 69362306a36Sopenharmony_ci wqe = __req_next_wqe(qp); 69462306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 69562306a36Sopenharmony_ci if (wqe) 69662306a36Sopenharmony_ci goto err; 69762306a36Sopenharmony_ci else 69862306a36Sopenharmony_ci goto exit; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (unlikely(qp_state(qp) == IB_QPS_RESET)) { 70262306a36Sopenharmony_ci qp->req.wqe_index = queue_get_consumer(q, 70362306a36Sopenharmony_ci QUEUE_TYPE_FROM_CLIENT); 70462306a36Sopenharmony_ci qp->req.opcode = -1; 70562306a36Sopenharmony_ci qp->req.need_rd_atomic = 0; 70662306a36Sopenharmony_ci qp->req.wait_psn = 0; 70762306a36Sopenharmony_ci qp->req.need_retry = 0; 70862306a36Sopenharmony_ci qp->req.wait_for_rnr_timer = 0; 70962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 71062306a36Sopenharmony_ci goto exit; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->state_lock, flags); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* we come here if the retransmit timer has fired 71562306a36Sopenharmony_ci * or if the rnr timer has fired. If the retransmit 71662306a36Sopenharmony_ci * timer fires while we are processing an RNR NAK wait 71762306a36Sopenharmony_ci * until the rnr timer has fired before starting the 71862306a36Sopenharmony_ci * retry flow 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ci if (unlikely(qp->req.need_retry && !qp->req.wait_for_rnr_timer)) { 72162306a36Sopenharmony_ci req_retry(qp); 72262306a36Sopenharmony_ci qp->req.need_retry = 0; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci wqe = req_next_wqe(qp); 72662306a36Sopenharmony_ci if (unlikely(!wqe)) 72762306a36Sopenharmony_ci goto exit; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (rxe_wqe_is_fenced(qp, wqe)) { 73062306a36Sopenharmony_ci qp->req.wait_fence = 1; 73162306a36Sopenharmony_ci goto exit; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (wqe->mask & WR_LOCAL_OP_MASK) { 73562306a36Sopenharmony_ci err = rxe_do_local_ops(qp, wqe); 73662306a36Sopenharmony_ci if (unlikely(err)) 73762306a36Sopenharmony_ci goto err; 73862306a36Sopenharmony_ci else 73962306a36Sopenharmony_ci goto done; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (unlikely(qp_type(qp) == IB_QPT_RC && 74362306a36Sopenharmony_ci psn_compare(qp->req.psn, (qp->comp.psn + 74462306a36Sopenharmony_ci RXE_MAX_UNACKED_PSNS)) > 0)) { 74562306a36Sopenharmony_ci qp->req.wait_psn = 1; 74662306a36Sopenharmony_ci goto exit; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* Limit the number of inflight SKBs per QP */ 75062306a36Sopenharmony_ci if (unlikely(atomic_read(&qp->skb_out) > 75162306a36Sopenharmony_ci RXE_INFLIGHT_SKBS_PER_QP_HIGH)) { 75262306a36Sopenharmony_ci qp->need_req_skb = 1; 75362306a36Sopenharmony_ci goto exit; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci opcode = next_opcode(qp, wqe, wqe->wr.opcode); 75762306a36Sopenharmony_ci if (unlikely(opcode < 0)) { 75862306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 75962306a36Sopenharmony_ci goto err; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci mask = rxe_opcode[opcode].mask; 76362306a36Sopenharmony_ci if (unlikely(mask & (RXE_READ_OR_ATOMIC_MASK | 76462306a36Sopenharmony_ci RXE_ATOMIC_WRITE_MASK))) { 76562306a36Sopenharmony_ci if (check_init_depth(qp, wqe)) 76662306a36Sopenharmony_ci goto exit; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci mtu = get_mtu(qp); 77062306a36Sopenharmony_ci payload = (mask & (RXE_WRITE_OR_SEND_MASK | RXE_ATOMIC_WRITE_MASK)) ? 77162306a36Sopenharmony_ci wqe->dma.resid : 0; 77262306a36Sopenharmony_ci if (payload > mtu) { 77362306a36Sopenharmony_ci if (qp_type(qp) == IB_QPT_UD) { 77462306a36Sopenharmony_ci /* C10-93.1.1: If the total sum of all the buffer lengths specified for a 77562306a36Sopenharmony_ci * UD message exceeds the MTU of the port as returned by QueryHCA, the CI 77662306a36Sopenharmony_ci * shall not emit any packets for this message. Further, the CI shall not 77762306a36Sopenharmony_ci * generate an error due to this condition. 77862306a36Sopenharmony_ci */ 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* fake a successful UD send */ 78162306a36Sopenharmony_ci wqe->first_psn = qp->req.psn; 78262306a36Sopenharmony_ci wqe->last_psn = qp->req.psn; 78362306a36Sopenharmony_ci qp->req.psn = (qp->req.psn + 1) & BTH_PSN_MASK; 78462306a36Sopenharmony_ci qp->req.opcode = IB_OPCODE_UD_SEND_ONLY; 78562306a36Sopenharmony_ci qp->req.wqe_index = queue_next_index(qp->sq.queue, 78662306a36Sopenharmony_ci qp->req.wqe_index); 78762306a36Sopenharmony_ci wqe->state = wqe_state_done; 78862306a36Sopenharmony_ci wqe->status = IB_WC_SUCCESS; 78962306a36Sopenharmony_ci rxe_sched_task(&qp->comp.task); 79062306a36Sopenharmony_ci goto done; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci payload = mtu; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci pkt.rxe = rxe; 79662306a36Sopenharmony_ci pkt.opcode = opcode; 79762306a36Sopenharmony_ci pkt.qp = qp; 79862306a36Sopenharmony_ci pkt.psn = qp->req.psn; 79962306a36Sopenharmony_ci pkt.mask = rxe_opcode[opcode].mask; 80062306a36Sopenharmony_ci pkt.wqe = wqe; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* save wqe state before we build and send packet */ 80362306a36Sopenharmony_ci save_state(wqe, qp, &rollback_wqe, &rollback_psn); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci av = rxe_get_av(&pkt, &ah); 80662306a36Sopenharmony_ci if (unlikely(!av)) { 80762306a36Sopenharmony_ci rxe_dbg_qp(qp, "Failed no address vector\n"); 80862306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 80962306a36Sopenharmony_ci goto err; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci skb = init_req_packet(qp, av, wqe, opcode, payload, &pkt); 81362306a36Sopenharmony_ci if (unlikely(!skb)) { 81462306a36Sopenharmony_ci rxe_dbg_qp(qp, "Failed allocating skb\n"); 81562306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 81662306a36Sopenharmony_ci if (ah) 81762306a36Sopenharmony_ci rxe_put(ah); 81862306a36Sopenharmony_ci goto err; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci err = finish_packet(qp, av, wqe, &pkt, skb, payload); 82262306a36Sopenharmony_ci if (unlikely(err)) { 82362306a36Sopenharmony_ci rxe_dbg_qp(qp, "Error during finish packet\n"); 82462306a36Sopenharmony_ci if (err == -EFAULT) 82562306a36Sopenharmony_ci wqe->status = IB_WC_LOC_PROT_ERR; 82662306a36Sopenharmony_ci else 82762306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 82862306a36Sopenharmony_ci kfree_skb(skb); 82962306a36Sopenharmony_ci if (ah) 83062306a36Sopenharmony_ci rxe_put(ah); 83162306a36Sopenharmony_ci goto err; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (ah) 83562306a36Sopenharmony_ci rxe_put(ah); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* update wqe state as though we had sent it */ 83862306a36Sopenharmony_ci update_wqe_state(qp, wqe, &pkt); 83962306a36Sopenharmony_ci update_wqe_psn(qp, wqe, &pkt, payload); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci err = rxe_xmit_packet(qp, &pkt, skb); 84262306a36Sopenharmony_ci if (err) { 84362306a36Sopenharmony_ci if (err != -EAGAIN) { 84462306a36Sopenharmony_ci wqe->status = IB_WC_LOC_QP_OP_ERR; 84562306a36Sopenharmony_ci goto err; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* the packet was dropped so reset wqe to the state 84962306a36Sopenharmony_ci * before we sent it so we can try to resend 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_ci rollback_state(wqe, qp, &rollback_wqe, rollback_psn); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* force a delay until the dropped packet is freed and 85462306a36Sopenharmony_ci * the send queue is drained below the low water mark 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci qp->need_req_skb = 1; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci rxe_sched_task(&qp->req.task); 85962306a36Sopenharmony_ci goto exit; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci update_state(qp, &pkt); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* A non-zero return value will cause rxe_do_task to 86562306a36Sopenharmony_ci * exit its loop and end the work item. A zero return 86662306a36Sopenharmony_ci * will continue looping and return to rxe_requester 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_cidone: 86962306a36Sopenharmony_ci ret = 0; 87062306a36Sopenharmony_ci goto out; 87162306a36Sopenharmony_cierr: 87262306a36Sopenharmony_ci /* update wqe_index for each wqe completion */ 87362306a36Sopenharmony_ci qp->req.wqe_index = queue_next_index(qp->sq.queue, qp->req.wqe_index); 87462306a36Sopenharmony_ci wqe->state = wqe_state_error; 87562306a36Sopenharmony_ci rxe_qp_error(qp); 87662306a36Sopenharmony_ciexit: 87762306a36Sopenharmony_ci ret = -EAGAIN; 87862306a36Sopenharmony_ciout: 87962306a36Sopenharmony_ci return ret; 88062306a36Sopenharmony_ci} 881