18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright(c) 2015 - 2018 Intel Corporation.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license.  When using or
58c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
108c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as
118c2ecf20Sopenharmony_ci * published by the Free Software Foundation.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
148c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
168c2ecf20Sopenharmony_ci * General Public License for more details.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci * BSD LICENSE
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
218c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
228c2ecf20Sopenharmony_ci * are met:
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci *  - Redistributions of source code must retain the above copyright
258c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
268c2ecf20Sopenharmony_ci *  - Redistributions in binary form must reproduce the above copyright
278c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in
288c2ecf20Sopenharmony_ci *    the documentation and/or other materials provided with the
298c2ecf20Sopenharmony_ci *    distribution.
308c2ecf20Sopenharmony_ci *  - Neither the name of Intel Corporation nor the names of its
318c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived
328c2ecf20Sopenharmony_ci *    from this software without specific prior written permission.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
358c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
368c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
378c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
388c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
398c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
408c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
418c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
428c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
438c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
448c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#include "hfi.h"
498c2ecf20Sopenharmony_ci#include "verbs_txreq.h"
508c2ecf20Sopenharmony_ci#include "qp.h"
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* cut down ridiculously long IB macro names */
538c2ecf20Sopenharmony_ci#define OP(x) UC_OP(x)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/**
568c2ecf20Sopenharmony_ci * hfi1_make_uc_req - construct a request packet (SEND, RDMA write)
578c2ecf20Sopenharmony_ci * @qp: a pointer to the QP
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci * Assume s_lock is held.
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * Return 1 if constructed; otherwise, return 0.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_ciint hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
668c2ecf20Sopenharmony_ci	struct ib_other_headers *ohdr;
678c2ecf20Sopenharmony_ci	struct rvt_swqe *wqe;
688c2ecf20Sopenharmony_ci	u32 hwords;
698c2ecf20Sopenharmony_ci	u32 bth0 = 0;
708c2ecf20Sopenharmony_ci	u32 len;
718c2ecf20Sopenharmony_ci	u32 pmtu = qp->pmtu;
728c2ecf20Sopenharmony_ci	int middle = 0;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	ps->s_txreq = get_txreq(ps->dev, qp);
758c2ecf20Sopenharmony_ci	if (!ps->s_txreq)
768c2ecf20Sopenharmony_ci		goto bail_no_tx;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_SEND_OK)) {
798c2ecf20Sopenharmony_ci		if (!(ib_rvt_state_ops[qp->state] & RVT_FLUSH_SEND))
808c2ecf20Sopenharmony_ci			goto bail;
818c2ecf20Sopenharmony_ci		/* We are in the error state, flush the work request. */
828c2ecf20Sopenharmony_ci		if (qp->s_last == READ_ONCE(qp->s_head))
838c2ecf20Sopenharmony_ci			goto bail;
848c2ecf20Sopenharmony_ci		/* If DMAs are in progress, we can't flush immediately. */
858c2ecf20Sopenharmony_ci		if (iowait_sdma_pending(&priv->s_iowait)) {
868c2ecf20Sopenharmony_ci			qp->s_flags |= RVT_S_WAIT_DMA;
878c2ecf20Sopenharmony_ci			goto bail;
888c2ecf20Sopenharmony_ci		}
898c2ecf20Sopenharmony_ci		clear_ahg(qp);
908c2ecf20Sopenharmony_ci		wqe = rvt_get_swqe_ptr(qp, qp->s_last);
918c2ecf20Sopenharmony_ci		rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
928c2ecf20Sopenharmony_ci		goto done_free_tx;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (priv->hdr_type == HFI1_PKT_TYPE_9B) {
968c2ecf20Sopenharmony_ci		/* header size in 32-bit words LRH+BTH = (8+12)/4. */
978c2ecf20Sopenharmony_ci		hwords = 5;
988c2ecf20Sopenharmony_ci		if (rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH)
998c2ecf20Sopenharmony_ci			ohdr = &ps->s_txreq->phdr.hdr.ibh.u.l.oth;
1008c2ecf20Sopenharmony_ci		else
1018c2ecf20Sopenharmony_ci			ohdr = &ps->s_txreq->phdr.hdr.ibh.u.oth;
1028c2ecf20Sopenharmony_ci	} else {
1038c2ecf20Sopenharmony_ci		/* header size in 32-bit words 16B LRH+BTH = (16+12)/4. */
1048c2ecf20Sopenharmony_ci		hwords = 7;
1058c2ecf20Sopenharmony_ci		if ((rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) &&
1068c2ecf20Sopenharmony_ci		    (hfi1_check_mcast(rdma_ah_get_dlid(&qp->remote_ah_attr))))
1078c2ecf20Sopenharmony_ci			ohdr = &ps->s_txreq->phdr.hdr.opah.u.l.oth;
1088c2ecf20Sopenharmony_ci		else
1098c2ecf20Sopenharmony_ci			ohdr = &ps->s_txreq->phdr.hdr.opah.u.oth;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/* Get the next send request. */
1138c2ecf20Sopenharmony_ci	wqe = rvt_get_swqe_ptr(qp, qp->s_cur);
1148c2ecf20Sopenharmony_ci	qp->s_wqe = NULL;
1158c2ecf20Sopenharmony_ci	switch (qp->s_state) {
1168c2ecf20Sopenharmony_ci	default:
1178c2ecf20Sopenharmony_ci		if (!(ib_rvt_state_ops[qp->state] &
1188c2ecf20Sopenharmony_ci		    RVT_PROCESS_NEXT_SEND_OK))
1198c2ecf20Sopenharmony_ci			goto bail;
1208c2ecf20Sopenharmony_ci		/* Check if send work queue is empty. */
1218c2ecf20Sopenharmony_ci		if (qp->s_cur == READ_ONCE(qp->s_head)) {
1228c2ecf20Sopenharmony_ci			clear_ahg(qp);
1238c2ecf20Sopenharmony_ci			goto bail;
1248c2ecf20Sopenharmony_ci		}
1258c2ecf20Sopenharmony_ci		/*
1268c2ecf20Sopenharmony_ci		 * Local operations are processed immediately
1278c2ecf20Sopenharmony_ci		 * after all prior requests have completed.
1288c2ecf20Sopenharmony_ci		 */
1298c2ecf20Sopenharmony_ci		if (wqe->wr.opcode == IB_WR_REG_MR ||
1308c2ecf20Sopenharmony_ci		    wqe->wr.opcode == IB_WR_LOCAL_INV) {
1318c2ecf20Sopenharmony_ci			int local_ops = 0;
1328c2ecf20Sopenharmony_ci			int err = 0;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci			if (qp->s_last != qp->s_cur)
1358c2ecf20Sopenharmony_ci				goto bail;
1368c2ecf20Sopenharmony_ci			if (++qp->s_cur == qp->s_size)
1378c2ecf20Sopenharmony_ci				qp->s_cur = 0;
1388c2ecf20Sopenharmony_ci			if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) {
1398c2ecf20Sopenharmony_ci				err = rvt_invalidate_rkey(
1408c2ecf20Sopenharmony_ci					qp, wqe->wr.ex.invalidate_rkey);
1418c2ecf20Sopenharmony_ci				local_ops = 1;
1428c2ecf20Sopenharmony_ci			}
1438c2ecf20Sopenharmony_ci			rvt_send_complete(qp, wqe, err ? IB_WC_LOC_PROT_ERR
1448c2ecf20Sopenharmony_ci							: IB_WC_SUCCESS);
1458c2ecf20Sopenharmony_ci			if (local_ops)
1468c2ecf20Sopenharmony_ci				atomic_dec(&qp->local_ops_pending);
1478c2ecf20Sopenharmony_ci			goto done_free_tx;
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci		/*
1508c2ecf20Sopenharmony_ci		 * Start a new request.
1518c2ecf20Sopenharmony_ci		 */
1528c2ecf20Sopenharmony_ci		qp->s_psn = wqe->psn;
1538c2ecf20Sopenharmony_ci		qp->s_sge.sge = wqe->sg_list[0];
1548c2ecf20Sopenharmony_ci		qp->s_sge.sg_list = wqe->sg_list + 1;
1558c2ecf20Sopenharmony_ci		qp->s_sge.num_sge = wqe->wr.num_sge;
1568c2ecf20Sopenharmony_ci		qp->s_sge.total_len = wqe->length;
1578c2ecf20Sopenharmony_ci		len = wqe->length;
1588c2ecf20Sopenharmony_ci		qp->s_len = len;
1598c2ecf20Sopenharmony_ci		switch (wqe->wr.opcode) {
1608c2ecf20Sopenharmony_ci		case IB_WR_SEND:
1618c2ecf20Sopenharmony_ci		case IB_WR_SEND_WITH_IMM:
1628c2ecf20Sopenharmony_ci			if (len > pmtu) {
1638c2ecf20Sopenharmony_ci				qp->s_state = OP(SEND_FIRST);
1648c2ecf20Sopenharmony_ci				len = pmtu;
1658c2ecf20Sopenharmony_ci				break;
1668c2ecf20Sopenharmony_ci			}
1678c2ecf20Sopenharmony_ci			if (wqe->wr.opcode == IB_WR_SEND) {
1688c2ecf20Sopenharmony_ci				qp->s_state = OP(SEND_ONLY);
1698c2ecf20Sopenharmony_ci			} else {
1708c2ecf20Sopenharmony_ci				qp->s_state =
1718c2ecf20Sopenharmony_ci					OP(SEND_ONLY_WITH_IMMEDIATE);
1728c2ecf20Sopenharmony_ci				/* Immediate data comes after the BTH */
1738c2ecf20Sopenharmony_ci				ohdr->u.imm_data = wqe->wr.ex.imm_data;
1748c2ecf20Sopenharmony_ci				hwords += 1;
1758c2ecf20Sopenharmony_ci			}
1768c2ecf20Sopenharmony_ci			if (wqe->wr.send_flags & IB_SEND_SOLICITED)
1778c2ecf20Sopenharmony_ci				bth0 |= IB_BTH_SOLICITED;
1788c2ecf20Sopenharmony_ci			qp->s_wqe = wqe;
1798c2ecf20Sopenharmony_ci			if (++qp->s_cur >= qp->s_size)
1808c2ecf20Sopenharmony_ci				qp->s_cur = 0;
1818c2ecf20Sopenharmony_ci			break;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		case IB_WR_RDMA_WRITE:
1848c2ecf20Sopenharmony_ci		case IB_WR_RDMA_WRITE_WITH_IMM:
1858c2ecf20Sopenharmony_ci			ohdr->u.rc.reth.vaddr =
1868c2ecf20Sopenharmony_ci				cpu_to_be64(wqe->rdma_wr.remote_addr);
1878c2ecf20Sopenharmony_ci			ohdr->u.rc.reth.rkey =
1888c2ecf20Sopenharmony_ci				cpu_to_be32(wqe->rdma_wr.rkey);
1898c2ecf20Sopenharmony_ci			ohdr->u.rc.reth.length = cpu_to_be32(len);
1908c2ecf20Sopenharmony_ci			hwords += sizeof(struct ib_reth) / 4;
1918c2ecf20Sopenharmony_ci			if (len > pmtu) {
1928c2ecf20Sopenharmony_ci				qp->s_state = OP(RDMA_WRITE_FIRST);
1938c2ecf20Sopenharmony_ci				len = pmtu;
1948c2ecf20Sopenharmony_ci				break;
1958c2ecf20Sopenharmony_ci			}
1968c2ecf20Sopenharmony_ci			if (wqe->wr.opcode == IB_WR_RDMA_WRITE) {
1978c2ecf20Sopenharmony_ci				qp->s_state = OP(RDMA_WRITE_ONLY);
1988c2ecf20Sopenharmony_ci			} else {
1998c2ecf20Sopenharmony_ci				qp->s_state =
2008c2ecf20Sopenharmony_ci					OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
2018c2ecf20Sopenharmony_ci				/* Immediate data comes after the RETH */
2028c2ecf20Sopenharmony_ci				ohdr->u.rc.imm_data = wqe->wr.ex.imm_data;
2038c2ecf20Sopenharmony_ci				hwords += 1;
2048c2ecf20Sopenharmony_ci				if (wqe->wr.send_flags & IB_SEND_SOLICITED)
2058c2ecf20Sopenharmony_ci					bth0 |= IB_BTH_SOLICITED;
2068c2ecf20Sopenharmony_ci			}
2078c2ecf20Sopenharmony_ci			qp->s_wqe = wqe;
2088c2ecf20Sopenharmony_ci			if (++qp->s_cur >= qp->s_size)
2098c2ecf20Sopenharmony_ci				qp->s_cur = 0;
2108c2ecf20Sopenharmony_ci			break;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci		default:
2138c2ecf20Sopenharmony_ci			goto bail;
2148c2ecf20Sopenharmony_ci		}
2158c2ecf20Sopenharmony_ci		break;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	case OP(SEND_FIRST):
2188c2ecf20Sopenharmony_ci		qp->s_state = OP(SEND_MIDDLE);
2198c2ecf20Sopenharmony_ci		fallthrough;
2208c2ecf20Sopenharmony_ci	case OP(SEND_MIDDLE):
2218c2ecf20Sopenharmony_ci		len = qp->s_len;
2228c2ecf20Sopenharmony_ci		if (len > pmtu) {
2238c2ecf20Sopenharmony_ci			len = pmtu;
2248c2ecf20Sopenharmony_ci			middle = HFI1_CAP_IS_KSET(SDMA_AHG);
2258c2ecf20Sopenharmony_ci			break;
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci		if (wqe->wr.opcode == IB_WR_SEND) {
2288c2ecf20Sopenharmony_ci			qp->s_state = OP(SEND_LAST);
2298c2ecf20Sopenharmony_ci		} else {
2308c2ecf20Sopenharmony_ci			qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);
2318c2ecf20Sopenharmony_ci			/* Immediate data comes after the BTH */
2328c2ecf20Sopenharmony_ci			ohdr->u.imm_data = wqe->wr.ex.imm_data;
2338c2ecf20Sopenharmony_ci			hwords += 1;
2348c2ecf20Sopenharmony_ci		}
2358c2ecf20Sopenharmony_ci		if (wqe->wr.send_flags & IB_SEND_SOLICITED)
2368c2ecf20Sopenharmony_ci			bth0 |= IB_BTH_SOLICITED;
2378c2ecf20Sopenharmony_ci		qp->s_wqe = wqe;
2388c2ecf20Sopenharmony_ci		if (++qp->s_cur >= qp->s_size)
2398c2ecf20Sopenharmony_ci			qp->s_cur = 0;
2408c2ecf20Sopenharmony_ci		break;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_FIRST):
2438c2ecf20Sopenharmony_ci		qp->s_state = OP(RDMA_WRITE_MIDDLE);
2448c2ecf20Sopenharmony_ci		fallthrough;
2458c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_MIDDLE):
2468c2ecf20Sopenharmony_ci		len = qp->s_len;
2478c2ecf20Sopenharmony_ci		if (len > pmtu) {
2488c2ecf20Sopenharmony_ci			len = pmtu;
2498c2ecf20Sopenharmony_ci			middle = HFI1_CAP_IS_KSET(SDMA_AHG);
2508c2ecf20Sopenharmony_ci			break;
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci		if (wqe->wr.opcode == IB_WR_RDMA_WRITE) {
2538c2ecf20Sopenharmony_ci			qp->s_state = OP(RDMA_WRITE_LAST);
2548c2ecf20Sopenharmony_ci		} else {
2558c2ecf20Sopenharmony_ci			qp->s_state =
2568c2ecf20Sopenharmony_ci				OP(RDMA_WRITE_LAST_WITH_IMMEDIATE);
2578c2ecf20Sopenharmony_ci			/* Immediate data comes after the BTH */
2588c2ecf20Sopenharmony_ci			ohdr->u.imm_data = wqe->wr.ex.imm_data;
2598c2ecf20Sopenharmony_ci			hwords += 1;
2608c2ecf20Sopenharmony_ci			if (wqe->wr.send_flags & IB_SEND_SOLICITED)
2618c2ecf20Sopenharmony_ci				bth0 |= IB_BTH_SOLICITED;
2628c2ecf20Sopenharmony_ci		}
2638c2ecf20Sopenharmony_ci		qp->s_wqe = wqe;
2648c2ecf20Sopenharmony_ci		if (++qp->s_cur >= qp->s_size)
2658c2ecf20Sopenharmony_ci			qp->s_cur = 0;
2668c2ecf20Sopenharmony_ci		break;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	qp->s_len -= len;
2698c2ecf20Sopenharmony_ci	ps->s_txreq->hdr_dwords = hwords;
2708c2ecf20Sopenharmony_ci	ps->s_txreq->sde = priv->s_sde;
2718c2ecf20Sopenharmony_ci	ps->s_txreq->ss = &qp->s_sge;
2728c2ecf20Sopenharmony_ci	ps->s_txreq->s_cur_size = len;
2738c2ecf20Sopenharmony_ci	hfi1_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24),
2748c2ecf20Sopenharmony_ci			     qp->remote_qpn, mask_psn(qp->s_psn++),
2758c2ecf20Sopenharmony_ci			     middle, ps);
2768c2ecf20Sopenharmony_ci	return 1;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cidone_free_tx:
2798c2ecf20Sopenharmony_ci	hfi1_put_txreq(ps->s_txreq);
2808c2ecf20Sopenharmony_ci	ps->s_txreq = NULL;
2818c2ecf20Sopenharmony_ci	return 1;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cibail:
2848c2ecf20Sopenharmony_ci	hfi1_put_txreq(ps->s_txreq);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cibail_no_tx:
2878c2ecf20Sopenharmony_ci	ps->s_txreq = NULL;
2888c2ecf20Sopenharmony_ci	qp->s_flags &= ~RVT_S_BUSY;
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/**
2938c2ecf20Sopenharmony_ci * hfi1_uc_rcv - handle an incoming UC packet
2948c2ecf20Sopenharmony_ci * @ibp: the port the packet came in on
2958c2ecf20Sopenharmony_ci * @hdr: the header of the packet
2968c2ecf20Sopenharmony_ci * @rcv_flags: flags relevant to rcv processing
2978c2ecf20Sopenharmony_ci * @data: the packet data
2988c2ecf20Sopenharmony_ci * @tlen: the length of the packet
2998c2ecf20Sopenharmony_ci * @qp: the QP for this packet.
3008c2ecf20Sopenharmony_ci *
3018c2ecf20Sopenharmony_ci * This is called from qp_rcv() to process an incoming UC packet
3028c2ecf20Sopenharmony_ci * for the given QP.
3038c2ecf20Sopenharmony_ci * Called at interrupt level.
3048c2ecf20Sopenharmony_ci */
3058c2ecf20Sopenharmony_civoid hfi1_uc_rcv(struct hfi1_packet *packet)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct hfi1_ibport *ibp = rcd_to_iport(packet->rcd);
3088c2ecf20Sopenharmony_ci	void *data = packet->payload;
3098c2ecf20Sopenharmony_ci	u32 tlen = packet->tlen;
3108c2ecf20Sopenharmony_ci	struct rvt_qp *qp = packet->qp;
3118c2ecf20Sopenharmony_ci	struct ib_other_headers *ohdr = packet->ohdr;
3128c2ecf20Sopenharmony_ci	u32 opcode = packet->opcode;
3138c2ecf20Sopenharmony_ci	u32 hdrsize = packet->hlen;
3148c2ecf20Sopenharmony_ci	u32 psn;
3158c2ecf20Sopenharmony_ci	u32 pad = packet->pad;
3168c2ecf20Sopenharmony_ci	struct ib_wc wc;
3178c2ecf20Sopenharmony_ci	u32 pmtu = qp->pmtu;
3188c2ecf20Sopenharmony_ci	struct ib_reth *reth;
3198c2ecf20Sopenharmony_ci	int ret;
3208c2ecf20Sopenharmony_ci	u8 extra_bytes = pad + packet->extra_byte + (SIZE_OF_CRC << 2);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (hfi1_ruc_check_hdr(ibp, packet))
3238c2ecf20Sopenharmony_ci		return;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	process_ecn(qp, packet);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	psn = ib_bth_get_psn(ohdr);
3288c2ecf20Sopenharmony_ci	/* Compare the PSN verses the expected PSN. */
3298c2ecf20Sopenharmony_ci	if (unlikely(cmp_psn(psn, qp->r_psn) != 0)) {
3308c2ecf20Sopenharmony_ci		/*
3318c2ecf20Sopenharmony_ci		 * Handle a sequence error.
3328c2ecf20Sopenharmony_ci		 * Silently drop any current message.
3338c2ecf20Sopenharmony_ci		 */
3348c2ecf20Sopenharmony_ci		qp->r_psn = psn;
3358c2ecf20Sopenharmony_ciinv:
3368c2ecf20Sopenharmony_ci		if (qp->r_state == OP(SEND_FIRST) ||
3378c2ecf20Sopenharmony_ci		    qp->r_state == OP(SEND_MIDDLE)) {
3388c2ecf20Sopenharmony_ci			set_bit(RVT_R_REWIND_SGE, &qp->r_aflags);
3398c2ecf20Sopenharmony_ci			qp->r_sge.num_sge = 0;
3408c2ecf20Sopenharmony_ci		} else {
3418c2ecf20Sopenharmony_ci			rvt_put_ss(&qp->r_sge);
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci		qp->r_state = OP(SEND_LAST);
3448c2ecf20Sopenharmony_ci		switch (opcode) {
3458c2ecf20Sopenharmony_ci		case OP(SEND_FIRST):
3468c2ecf20Sopenharmony_ci		case OP(SEND_ONLY):
3478c2ecf20Sopenharmony_ci		case OP(SEND_ONLY_WITH_IMMEDIATE):
3488c2ecf20Sopenharmony_ci			goto send_first;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		case OP(RDMA_WRITE_FIRST):
3518c2ecf20Sopenharmony_ci		case OP(RDMA_WRITE_ONLY):
3528c2ecf20Sopenharmony_ci		case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE):
3538c2ecf20Sopenharmony_ci			goto rdma_first;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		default:
3568c2ecf20Sopenharmony_ci			goto drop;
3578c2ecf20Sopenharmony_ci		}
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/* Check for opcode sequence errors. */
3618c2ecf20Sopenharmony_ci	switch (qp->r_state) {
3628c2ecf20Sopenharmony_ci	case OP(SEND_FIRST):
3638c2ecf20Sopenharmony_ci	case OP(SEND_MIDDLE):
3648c2ecf20Sopenharmony_ci		if (opcode == OP(SEND_MIDDLE) ||
3658c2ecf20Sopenharmony_ci		    opcode == OP(SEND_LAST) ||
3668c2ecf20Sopenharmony_ci		    opcode == OP(SEND_LAST_WITH_IMMEDIATE))
3678c2ecf20Sopenharmony_ci			break;
3688c2ecf20Sopenharmony_ci		goto inv;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_FIRST):
3718c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_MIDDLE):
3728c2ecf20Sopenharmony_ci		if (opcode == OP(RDMA_WRITE_MIDDLE) ||
3738c2ecf20Sopenharmony_ci		    opcode == OP(RDMA_WRITE_LAST) ||
3748c2ecf20Sopenharmony_ci		    opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
3758c2ecf20Sopenharmony_ci			break;
3768c2ecf20Sopenharmony_ci		goto inv;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	default:
3798c2ecf20Sopenharmony_ci		if (opcode == OP(SEND_FIRST) ||
3808c2ecf20Sopenharmony_ci		    opcode == OP(SEND_ONLY) ||
3818c2ecf20Sopenharmony_ci		    opcode == OP(SEND_ONLY_WITH_IMMEDIATE) ||
3828c2ecf20Sopenharmony_ci		    opcode == OP(RDMA_WRITE_FIRST) ||
3838c2ecf20Sopenharmony_ci		    opcode == OP(RDMA_WRITE_ONLY) ||
3848c2ecf20Sopenharmony_ci		    opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
3858c2ecf20Sopenharmony_ci			break;
3868c2ecf20Sopenharmony_ci		goto inv;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (qp->state == IB_QPS_RTR && !(qp->r_flags & RVT_R_COMM_EST))
3908c2ecf20Sopenharmony_ci		rvt_comm_est(qp);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	/* OK, process the packet. */
3938c2ecf20Sopenharmony_ci	switch (opcode) {
3948c2ecf20Sopenharmony_ci	case OP(SEND_FIRST):
3958c2ecf20Sopenharmony_ci	case OP(SEND_ONLY):
3968c2ecf20Sopenharmony_ci	case OP(SEND_ONLY_WITH_IMMEDIATE):
3978c2ecf20Sopenharmony_cisend_first:
3988c2ecf20Sopenharmony_ci		if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) {
3998c2ecf20Sopenharmony_ci			qp->r_sge = qp->s_rdma_read_sge;
4008c2ecf20Sopenharmony_ci		} else {
4018c2ecf20Sopenharmony_ci			ret = rvt_get_rwqe(qp, false);
4028c2ecf20Sopenharmony_ci			if (ret < 0)
4038c2ecf20Sopenharmony_ci				goto op_err;
4048c2ecf20Sopenharmony_ci			if (!ret)
4058c2ecf20Sopenharmony_ci				goto drop;
4068c2ecf20Sopenharmony_ci			/*
4078c2ecf20Sopenharmony_ci			 * qp->s_rdma_read_sge will be the owner
4088c2ecf20Sopenharmony_ci			 * of the mr references.
4098c2ecf20Sopenharmony_ci			 */
4108c2ecf20Sopenharmony_ci			qp->s_rdma_read_sge = qp->r_sge;
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci		qp->r_rcv_len = 0;
4138c2ecf20Sopenharmony_ci		if (opcode == OP(SEND_ONLY))
4148c2ecf20Sopenharmony_ci			goto no_immediate_data;
4158c2ecf20Sopenharmony_ci		else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE))
4168c2ecf20Sopenharmony_ci			goto send_last_imm;
4178c2ecf20Sopenharmony_ci		fallthrough;
4188c2ecf20Sopenharmony_ci	case OP(SEND_MIDDLE):
4198c2ecf20Sopenharmony_ci		/* Check for invalid length PMTU or posted rwqe len. */
4208c2ecf20Sopenharmony_ci		/*
4218c2ecf20Sopenharmony_ci		 * There will be no padding for 9B packet but 16B packets
4228c2ecf20Sopenharmony_ci		 * will come in with some padding since we always add
4238c2ecf20Sopenharmony_ci		 * CRC and LT bytes which will need to be flit aligned
4248c2ecf20Sopenharmony_ci		 */
4258c2ecf20Sopenharmony_ci		if (unlikely(tlen != (hdrsize + pmtu + extra_bytes)))
4268c2ecf20Sopenharmony_ci			goto rewind;
4278c2ecf20Sopenharmony_ci		qp->r_rcv_len += pmtu;
4288c2ecf20Sopenharmony_ci		if (unlikely(qp->r_rcv_len > qp->r_len))
4298c2ecf20Sopenharmony_ci			goto rewind;
4308c2ecf20Sopenharmony_ci		rvt_copy_sge(qp, &qp->r_sge, data, pmtu, false, false);
4318c2ecf20Sopenharmony_ci		break;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	case OP(SEND_LAST_WITH_IMMEDIATE):
4348c2ecf20Sopenharmony_cisend_last_imm:
4358c2ecf20Sopenharmony_ci		wc.ex.imm_data = ohdr->u.imm_data;
4368c2ecf20Sopenharmony_ci		wc.wc_flags = IB_WC_WITH_IMM;
4378c2ecf20Sopenharmony_ci		goto send_last;
4388c2ecf20Sopenharmony_ci	case OP(SEND_LAST):
4398c2ecf20Sopenharmony_cino_immediate_data:
4408c2ecf20Sopenharmony_ci		wc.ex.imm_data = 0;
4418c2ecf20Sopenharmony_ci		wc.wc_flags = 0;
4428c2ecf20Sopenharmony_cisend_last:
4438c2ecf20Sopenharmony_ci		/* Check for invalid length. */
4448c2ecf20Sopenharmony_ci		/* LAST len should be >= 1 */
4458c2ecf20Sopenharmony_ci		if (unlikely(tlen < (hdrsize + extra_bytes)))
4468c2ecf20Sopenharmony_ci			goto rewind;
4478c2ecf20Sopenharmony_ci		/* Don't count the CRC. */
4488c2ecf20Sopenharmony_ci		tlen -= (hdrsize + extra_bytes);
4498c2ecf20Sopenharmony_ci		wc.byte_len = tlen + qp->r_rcv_len;
4508c2ecf20Sopenharmony_ci		if (unlikely(wc.byte_len > qp->r_len))
4518c2ecf20Sopenharmony_ci			goto rewind;
4528c2ecf20Sopenharmony_ci		wc.opcode = IB_WC_RECV;
4538c2ecf20Sopenharmony_ci		rvt_copy_sge(qp, &qp->r_sge, data, tlen, false, false);
4548c2ecf20Sopenharmony_ci		rvt_put_ss(&qp->s_rdma_read_sge);
4558c2ecf20Sopenharmony_cilast_imm:
4568c2ecf20Sopenharmony_ci		wc.wr_id = qp->r_wr_id;
4578c2ecf20Sopenharmony_ci		wc.status = IB_WC_SUCCESS;
4588c2ecf20Sopenharmony_ci		wc.qp = &qp->ibqp;
4598c2ecf20Sopenharmony_ci		wc.src_qp = qp->remote_qpn;
4608c2ecf20Sopenharmony_ci		wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX;
4618c2ecf20Sopenharmony_ci		/*
4628c2ecf20Sopenharmony_ci		 * It seems that IB mandates the presence of an SL in a
4638c2ecf20Sopenharmony_ci		 * work completion only for the UD transport (see section
4648c2ecf20Sopenharmony_ci		 * 11.4.2 of IBTA Vol. 1).
4658c2ecf20Sopenharmony_ci		 *
4668c2ecf20Sopenharmony_ci		 * However, the way the SL is chosen below is consistent
4678c2ecf20Sopenharmony_ci		 * with the way that IB/qib works and is trying avoid
4688c2ecf20Sopenharmony_ci		 * introducing incompatibilities.
4698c2ecf20Sopenharmony_ci		 *
4708c2ecf20Sopenharmony_ci		 * See also OPA Vol. 1, section 9.7.6, and table 9-17.
4718c2ecf20Sopenharmony_ci		 */
4728c2ecf20Sopenharmony_ci		wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr);
4738c2ecf20Sopenharmony_ci		/* zero fields that are N/A */
4748c2ecf20Sopenharmony_ci		wc.vendor_err = 0;
4758c2ecf20Sopenharmony_ci		wc.pkey_index = 0;
4768c2ecf20Sopenharmony_ci		wc.dlid_path_bits = 0;
4778c2ecf20Sopenharmony_ci		wc.port_num = 0;
4788c2ecf20Sopenharmony_ci		/* Signal completion event if the solicited bit is set. */
4798c2ecf20Sopenharmony_ci		rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
4808c2ecf20Sopenharmony_ci		break;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_FIRST):
4838c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_ONLY):
4848c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */
4858c2ecf20Sopenharmony_cirdma_first:
4868c2ecf20Sopenharmony_ci		if (unlikely(!(qp->qp_access_flags &
4878c2ecf20Sopenharmony_ci			       IB_ACCESS_REMOTE_WRITE))) {
4888c2ecf20Sopenharmony_ci			goto drop;
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci		reth = &ohdr->u.rc.reth;
4918c2ecf20Sopenharmony_ci		qp->r_len = be32_to_cpu(reth->length);
4928c2ecf20Sopenharmony_ci		qp->r_rcv_len = 0;
4938c2ecf20Sopenharmony_ci		qp->r_sge.sg_list = NULL;
4948c2ecf20Sopenharmony_ci		if (qp->r_len != 0) {
4958c2ecf20Sopenharmony_ci			u32 rkey = be32_to_cpu(reth->rkey);
4968c2ecf20Sopenharmony_ci			u64 vaddr = be64_to_cpu(reth->vaddr);
4978c2ecf20Sopenharmony_ci			int ok;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci			/* Check rkey */
5008c2ecf20Sopenharmony_ci			ok = rvt_rkey_ok(qp, &qp->r_sge.sge, qp->r_len,
5018c2ecf20Sopenharmony_ci					 vaddr, rkey, IB_ACCESS_REMOTE_WRITE);
5028c2ecf20Sopenharmony_ci			if (unlikely(!ok))
5038c2ecf20Sopenharmony_ci				goto drop;
5048c2ecf20Sopenharmony_ci			qp->r_sge.num_sge = 1;
5058c2ecf20Sopenharmony_ci		} else {
5068c2ecf20Sopenharmony_ci			qp->r_sge.num_sge = 0;
5078c2ecf20Sopenharmony_ci			qp->r_sge.sge.mr = NULL;
5088c2ecf20Sopenharmony_ci			qp->r_sge.sge.vaddr = NULL;
5098c2ecf20Sopenharmony_ci			qp->r_sge.sge.length = 0;
5108c2ecf20Sopenharmony_ci			qp->r_sge.sge.sge_length = 0;
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci		if (opcode == OP(RDMA_WRITE_ONLY)) {
5138c2ecf20Sopenharmony_ci			goto rdma_last;
5148c2ecf20Sopenharmony_ci		} else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) {
5158c2ecf20Sopenharmony_ci			wc.ex.imm_data = ohdr->u.rc.imm_data;
5168c2ecf20Sopenharmony_ci			goto rdma_last_imm;
5178c2ecf20Sopenharmony_ci		}
5188c2ecf20Sopenharmony_ci		fallthrough;
5198c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_MIDDLE):
5208c2ecf20Sopenharmony_ci		/* Check for invalid length PMTU or posted rwqe len. */
5218c2ecf20Sopenharmony_ci		if (unlikely(tlen != (hdrsize + pmtu + 4)))
5228c2ecf20Sopenharmony_ci			goto drop;
5238c2ecf20Sopenharmony_ci		qp->r_rcv_len += pmtu;
5248c2ecf20Sopenharmony_ci		if (unlikely(qp->r_rcv_len > qp->r_len))
5258c2ecf20Sopenharmony_ci			goto drop;
5268c2ecf20Sopenharmony_ci		rvt_copy_sge(qp, &qp->r_sge, data, pmtu, true, false);
5278c2ecf20Sopenharmony_ci		break;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
5308c2ecf20Sopenharmony_ci		wc.ex.imm_data = ohdr->u.imm_data;
5318c2ecf20Sopenharmony_cirdma_last_imm:
5328c2ecf20Sopenharmony_ci		wc.wc_flags = IB_WC_WITH_IMM;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		/* Check for invalid length. */
5358c2ecf20Sopenharmony_ci		/* LAST len should be >= 1 */
5368c2ecf20Sopenharmony_ci		if (unlikely(tlen < (hdrsize + pad + 4)))
5378c2ecf20Sopenharmony_ci			goto drop;
5388c2ecf20Sopenharmony_ci		/* Don't count the CRC. */
5398c2ecf20Sopenharmony_ci		tlen -= (hdrsize + extra_bytes);
5408c2ecf20Sopenharmony_ci		if (unlikely(tlen + qp->r_rcv_len != qp->r_len))
5418c2ecf20Sopenharmony_ci			goto drop;
5428c2ecf20Sopenharmony_ci		if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) {
5438c2ecf20Sopenharmony_ci			rvt_put_ss(&qp->s_rdma_read_sge);
5448c2ecf20Sopenharmony_ci		} else {
5458c2ecf20Sopenharmony_ci			ret = rvt_get_rwqe(qp, true);
5468c2ecf20Sopenharmony_ci			if (ret < 0)
5478c2ecf20Sopenharmony_ci				goto op_err;
5488c2ecf20Sopenharmony_ci			if (!ret)
5498c2ecf20Sopenharmony_ci				goto drop;
5508c2ecf20Sopenharmony_ci		}
5518c2ecf20Sopenharmony_ci		wc.byte_len = qp->r_len;
5528c2ecf20Sopenharmony_ci		wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
5538c2ecf20Sopenharmony_ci		rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false);
5548c2ecf20Sopenharmony_ci		rvt_put_ss(&qp->r_sge);
5558c2ecf20Sopenharmony_ci		goto last_imm;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	case OP(RDMA_WRITE_LAST):
5588c2ecf20Sopenharmony_cirdma_last:
5598c2ecf20Sopenharmony_ci		/* Check for invalid length. */
5608c2ecf20Sopenharmony_ci		/* LAST len should be >= 1 */
5618c2ecf20Sopenharmony_ci		if (unlikely(tlen < (hdrsize + pad + 4)))
5628c2ecf20Sopenharmony_ci			goto drop;
5638c2ecf20Sopenharmony_ci		/* Don't count the CRC. */
5648c2ecf20Sopenharmony_ci		tlen -= (hdrsize + extra_bytes);
5658c2ecf20Sopenharmony_ci		if (unlikely(tlen + qp->r_rcv_len != qp->r_len))
5668c2ecf20Sopenharmony_ci			goto drop;
5678c2ecf20Sopenharmony_ci		rvt_copy_sge(qp, &qp->r_sge, data, tlen, true, false);
5688c2ecf20Sopenharmony_ci		rvt_put_ss(&qp->r_sge);
5698c2ecf20Sopenharmony_ci		break;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	default:
5728c2ecf20Sopenharmony_ci		/* Drop packet for unknown opcodes. */
5738c2ecf20Sopenharmony_ci		goto drop;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci	qp->r_psn++;
5768c2ecf20Sopenharmony_ci	qp->r_state = opcode;
5778c2ecf20Sopenharmony_ci	return;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cirewind:
5808c2ecf20Sopenharmony_ci	set_bit(RVT_R_REWIND_SGE, &qp->r_aflags);
5818c2ecf20Sopenharmony_ci	qp->r_sge.num_sge = 0;
5828c2ecf20Sopenharmony_cidrop:
5838c2ecf20Sopenharmony_ci	ibp->rvp.n_pkt_drops++;
5848c2ecf20Sopenharmony_ci	return;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ciop_err:
5878c2ecf20Sopenharmony_ci	rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
5888c2ecf20Sopenharmony_ci}
589