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 <linux/spinlock.h>
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include "hfi.h"
518c2ecf20Sopenharmony_ci#include "mad.h"
528c2ecf20Sopenharmony_ci#include "qp.h"
538c2ecf20Sopenharmony_ci#include "verbs_txreq.h"
548c2ecf20Sopenharmony_ci#include "trace.h"
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	return (gid->global.interface_id == id &&
598c2ecf20Sopenharmony_ci		(gid->global.subnet_prefix == gid_prefix ||
608c2ecf20Sopenharmony_ci		 gid->global.subnet_prefix == IB_DEFAULT_GID_PREFIX));
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * This should be called with the QP r_lock held.
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci * The s_lock will be acquired around the hfi1_migrate_qp() call.
688c2ecf20Sopenharmony_ci */
698c2ecf20Sopenharmony_ciint hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	__be64 guid;
728c2ecf20Sopenharmony_ci	unsigned long flags;
738c2ecf20Sopenharmony_ci	struct rvt_qp *qp = packet->qp;
748c2ecf20Sopenharmony_ci	u8 sc5 = ibp->sl_to_sc[rdma_ah_get_sl(&qp->remote_ah_attr)];
758c2ecf20Sopenharmony_ci	u32 dlid = packet->dlid;
768c2ecf20Sopenharmony_ci	u32 slid = packet->slid;
778c2ecf20Sopenharmony_ci	u32 sl = packet->sl;
788c2ecf20Sopenharmony_ci	bool migrated = packet->migrated;
798c2ecf20Sopenharmony_ci	u16 pkey = packet->pkey;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (qp->s_mig_state == IB_MIG_ARMED && migrated) {
828c2ecf20Sopenharmony_ci		if (!packet->grh) {
838c2ecf20Sopenharmony_ci			if ((rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
848c2ecf20Sopenharmony_ci			     IB_AH_GRH) &&
858c2ecf20Sopenharmony_ci			    (packet->etype != RHF_RCV_TYPE_BYPASS))
868c2ecf20Sopenharmony_ci				return 1;
878c2ecf20Sopenharmony_ci		} else {
888c2ecf20Sopenharmony_ci			const struct ib_global_route *grh;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci			if (!(rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
918c2ecf20Sopenharmony_ci			      IB_AH_GRH))
928c2ecf20Sopenharmony_ci				return 1;
938c2ecf20Sopenharmony_ci			grh = rdma_ah_read_grh(&qp->alt_ah_attr);
948c2ecf20Sopenharmony_ci			guid = get_sguid(ibp, grh->sgid_index);
958c2ecf20Sopenharmony_ci			if (!gid_ok(&packet->grh->dgid, ibp->rvp.gid_prefix,
968c2ecf20Sopenharmony_ci				    guid))
978c2ecf20Sopenharmony_ci				return 1;
988c2ecf20Sopenharmony_ci			if (!gid_ok(
998c2ecf20Sopenharmony_ci				&packet->grh->sgid,
1008c2ecf20Sopenharmony_ci				grh->dgid.global.subnet_prefix,
1018c2ecf20Sopenharmony_ci				grh->dgid.global.interface_id))
1028c2ecf20Sopenharmony_ci				return 1;
1038c2ecf20Sopenharmony_ci		}
1048c2ecf20Sopenharmony_ci		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
1058c2ecf20Sopenharmony_ci					    sc5, slid))) {
1068c2ecf20Sopenharmony_ci			hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
1078c2ecf20Sopenharmony_ci				      slid, dlid);
1088c2ecf20Sopenharmony_ci			return 1;
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci		/* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */
1118c2ecf20Sopenharmony_ci		if (slid != rdma_ah_get_dlid(&qp->alt_ah_attr) ||
1128c2ecf20Sopenharmony_ci		    ppd_from_ibp(ibp)->port !=
1138c2ecf20Sopenharmony_ci			rdma_ah_get_port_num(&qp->alt_ah_attr))
1148c2ecf20Sopenharmony_ci			return 1;
1158c2ecf20Sopenharmony_ci		spin_lock_irqsave(&qp->s_lock, flags);
1168c2ecf20Sopenharmony_ci		hfi1_migrate_qp(qp);
1178c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&qp->s_lock, flags);
1188c2ecf20Sopenharmony_ci	} else {
1198c2ecf20Sopenharmony_ci		if (!packet->grh) {
1208c2ecf20Sopenharmony_ci			if ((rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
1218c2ecf20Sopenharmony_ci			     IB_AH_GRH) &&
1228c2ecf20Sopenharmony_ci			    (packet->etype != RHF_RCV_TYPE_BYPASS))
1238c2ecf20Sopenharmony_ci				return 1;
1248c2ecf20Sopenharmony_ci		} else {
1258c2ecf20Sopenharmony_ci			const struct ib_global_route *grh;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci			if (!(rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
1288c2ecf20Sopenharmony_ci						   IB_AH_GRH))
1298c2ecf20Sopenharmony_ci				return 1;
1308c2ecf20Sopenharmony_ci			grh = rdma_ah_read_grh(&qp->remote_ah_attr);
1318c2ecf20Sopenharmony_ci			guid = get_sguid(ibp, grh->sgid_index);
1328c2ecf20Sopenharmony_ci			if (!gid_ok(&packet->grh->dgid, ibp->rvp.gid_prefix,
1338c2ecf20Sopenharmony_ci				    guid))
1348c2ecf20Sopenharmony_ci				return 1;
1358c2ecf20Sopenharmony_ci			if (!gid_ok(
1368c2ecf20Sopenharmony_ci			     &packet->grh->sgid,
1378c2ecf20Sopenharmony_ci			     grh->dgid.global.subnet_prefix,
1388c2ecf20Sopenharmony_ci			     grh->dgid.global.interface_id))
1398c2ecf20Sopenharmony_ci				return 1;
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
1428c2ecf20Sopenharmony_ci					    sc5, slid))) {
1438c2ecf20Sopenharmony_ci			hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
1448c2ecf20Sopenharmony_ci				      slid, dlid);
1458c2ecf20Sopenharmony_ci			return 1;
1468c2ecf20Sopenharmony_ci		}
1478c2ecf20Sopenharmony_ci		/* Validate the SLID. See Ch. 9.6.1.5 */
1488c2ecf20Sopenharmony_ci		if ((slid != rdma_ah_get_dlid(&qp->remote_ah_attr)) ||
1498c2ecf20Sopenharmony_ci		    ppd_from_ibp(ibp)->port != qp->port_num)
1508c2ecf20Sopenharmony_ci			return 1;
1518c2ecf20Sopenharmony_ci		if (qp->s_mig_state == IB_MIG_REARM && !migrated)
1528c2ecf20Sopenharmony_ci			qp->s_mig_state = IB_MIG_ARMED;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return 0;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/**
1598c2ecf20Sopenharmony_ci * hfi1_make_grh - construct a GRH header
1608c2ecf20Sopenharmony_ci * @ibp: a pointer to the IB port
1618c2ecf20Sopenharmony_ci * @hdr: a pointer to the GRH header being constructed
1628c2ecf20Sopenharmony_ci * @grh: the global route address to send to
1638c2ecf20Sopenharmony_ci * @hwords: size of header after grh being sent in dwords
1648c2ecf20Sopenharmony_ci * @nwords: the number of 32 bit words of data being sent
1658c2ecf20Sopenharmony_ci *
1668c2ecf20Sopenharmony_ci * Return the size of the header in 32 bit words.
1678c2ecf20Sopenharmony_ci */
1688c2ecf20Sopenharmony_ciu32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr,
1698c2ecf20Sopenharmony_ci		  const struct ib_global_route *grh, u32 hwords, u32 nwords)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	hdr->version_tclass_flow =
1728c2ecf20Sopenharmony_ci		cpu_to_be32((IB_GRH_VERSION << IB_GRH_VERSION_SHIFT) |
1738c2ecf20Sopenharmony_ci			    (grh->traffic_class << IB_GRH_TCLASS_SHIFT) |
1748c2ecf20Sopenharmony_ci			    (grh->flow_label << IB_GRH_FLOW_SHIFT));
1758c2ecf20Sopenharmony_ci	hdr->paylen = cpu_to_be16((hwords + nwords) << 2);
1768c2ecf20Sopenharmony_ci	/* next_hdr is defined by C8-7 in ch. 8.4.1 */
1778c2ecf20Sopenharmony_ci	hdr->next_hdr = IB_GRH_NEXT_HDR;
1788c2ecf20Sopenharmony_ci	hdr->hop_limit = grh->hop_limit;
1798c2ecf20Sopenharmony_ci	/* The SGID is 32-bit aligned. */
1808c2ecf20Sopenharmony_ci	hdr->sgid.global.subnet_prefix = ibp->rvp.gid_prefix;
1818c2ecf20Sopenharmony_ci	hdr->sgid.global.interface_id =
1828c2ecf20Sopenharmony_ci		grh->sgid_index < HFI1_GUIDS_PER_PORT ?
1838c2ecf20Sopenharmony_ci		get_sguid(ibp, grh->sgid_index) :
1848c2ecf20Sopenharmony_ci		get_sguid(ibp, HFI1_PORT_GUID_INDEX);
1858c2ecf20Sopenharmony_ci	hdr->dgid = grh->dgid;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* GRH header size in 32-bit words. */
1888c2ecf20Sopenharmony_ci	return sizeof(struct ib_grh) / sizeof(u32);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci#define BTH2_OFFSET (offsetof(struct hfi1_sdma_header, \
1928c2ecf20Sopenharmony_ci			      hdr.ibh.u.oth.bth[2]) / 4)
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/**
1958c2ecf20Sopenharmony_ci * build_ahg - create ahg in s_ahg
1968c2ecf20Sopenharmony_ci * @qp: a pointer to QP
1978c2ecf20Sopenharmony_ci * @npsn: the next PSN for the request/response
1988c2ecf20Sopenharmony_ci *
1998c2ecf20Sopenharmony_ci * This routine handles the AHG by allocating an ahg entry and causing the
2008c2ecf20Sopenharmony_ci * copy of the first middle.
2018c2ecf20Sopenharmony_ci *
2028c2ecf20Sopenharmony_ci * Subsequent middles use the copied entry, editing the
2038c2ecf20Sopenharmony_ci * PSN with 1 or 2 edits.
2048c2ecf20Sopenharmony_ci */
2058c2ecf20Sopenharmony_cistatic inline void build_ahg(struct rvt_qp *qp, u32 npsn)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (unlikely(qp->s_flags & HFI1_S_AHG_CLEAR))
2108c2ecf20Sopenharmony_ci		clear_ahg(qp);
2118c2ecf20Sopenharmony_ci	if (!(qp->s_flags & HFI1_S_AHG_VALID)) {
2128c2ecf20Sopenharmony_ci		/* first middle that needs copy  */
2138c2ecf20Sopenharmony_ci		if (qp->s_ahgidx < 0)
2148c2ecf20Sopenharmony_ci			qp->s_ahgidx = sdma_ahg_alloc(priv->s_sde);
2158c2ecf20Sopenharmony_ci		if (qp->s_ahgidx >= 0) {
2168c2ecf20Sopenharmony_ci			qp->s_ahgpsn = npsn;
2178c2ecf20Sopenharmony_ci			priv->s_ahg->tx_flags |= SDMA_TXREQ_F_AHG_COPY;
2188c2ecf20Sopenharmony_ci			/* save to protect a change in another thread */
2198c2ecf20Sopenharmony_ci			priv->s_ahg->ahgidx = qp->s_ahgidx;
2208c2ecf20Sopenharmony_ci			qp->s_flags |= HFI1_S_AHG_VALID;
2218c2ecf20Sopenharmony_ci		}
2228c2ecf20Sopenharmony_ci	} else {
2238c2ecf20Sopenharmony_ci		/* subsequent middle after valid */
2248c2ecf20Sopenharmony_ci		if (qp->s_ahgidx >= 0) {
2258c2ecf20Sopenharmony_ci			priv->s_ahg->tx_flags |= SDMA_TXREQ_F_USE_AHG;
2268c2ecf20Sopenharmony_ci			priv->s_ahg->ahgidx = qp->s_ahgidx;
2278c2ecf20Sopenharmony_ci			priv->s_ahg->ahgcount++;
2288c2ecf20Sopenharmony_ci			priv->s_ahg->ahgdesc[0] =
2298c2ecf20Sopenharmony_ci				sdma_build_ahg_descriptor(
2308c2ecf20Sopenharmony_ci					(__force u16)cpu_to_be16((u16)npsn),
2318c2ecf20Sopenharmony_ci					BTH2_OFFSET,
2328c2ecf20Sopenharmony_ci					16,
2338c2ecf20Sopenharmony_ci					16);
2348c2ecf20Sopenharmony_ci			if ((npsn & 0xffff0000) !=
2358c2ecf20Sopenharmony_ci					(qp->s_ahgpsn & 0xffff0000)) {
2368c2ecf20Sopenharmony_ci				priv->s_ahg->ahgcount++;
2378c2ecf20Sopenharmony_ci				priv->s_ahg->ahgdesc[1] =
2388c2ecf20Sopenharmony_ci					sdma_build_ahg_descriptor(
2398c2ecf20Sopenharmony_ci						(__force u16)cpu_to_be16(
2408c2ecf20Sopenharmony_ci							(u16)(npsn >> 16)),
2418c2ecf20Sopenharmony_ci						BTH2_OFFSET,
2428c2ecf20Sopenharmony_ci						0,
2438c2ecf20Sopenharmony_ci						16);
2448c2ecf20Sopenharmony_ci			}
2458c2ecf20Sopenharmony_ci		}
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic inline void hfi1_make_ruc_bth(struct rvt_qp *qp,
2508c2ecf20Sopenharmony_ci				     struct ib_other_headers *ohdr,
2518c2ecf20Sopenharmony_ci				     u32 bth0, u32 bth1, u32 bth2)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	ohdr->bth[0] = cpu_to_be32(bth0);
2548c2ecf20Sopenharmony_ci	ohdr->bth[1] = cpu_to_be32(bth1);
2558c2ecf20Sopenharmony_ci	ohdr->bth[2] = cpu_to_be32(bth2);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/**
2598c2ecf20Sopenharmony_ci * hfi1_make_ruc_header_16B - build a 16B header
2608c2ecf20Sopenharmony_ci * @qp: the queue pair
2618c2ecf20Sopenharmony_ci * @ohdr: a pointer to the destination header memory
2628c2ecf20Sopenharmony_ci * @bth0: bth0 passed in from the RC/UC builder
2638c2ecf20Sopenharmony_ci * @bth2: bth2 passed in from the RC/UC builder
2648c2ecf20Sopenharmony_ci * @middle: non zero implies indicates ahg "could" be used
2658c2ecf20Sopenharmony_ci * @ps: the current packet state
2668c2ecf20Sopenharmony_ci *
2678c2ecf20Sopenharmony_ci * This routine may disarm ahg under these situations:
2688c2ecf20Sopenharmony_ci * - packet needs a GRH
2698c2ecf20Sopenharmony_ci * - BECN needed
2708c2ecf20Sopenharmony_ci * - migration state not IB_MIG_MIGRATED
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_cistatic inline void hfi1_make_ruc_header_16B(struct rvt_qp *qp,
2738c2ecf20Sopenharmony_ci					    struct ib_other_headers *ohdr,
2748c2ecf20Sopenharmony_ci					    u32 bth0, u32 bth1, u32 bth2,
2758c2ecf20Sopenharmony_ci					    int middle,
2768c2ecf20Sopenharmony_ci					    struct hfi1_pkt_state *ps)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
2798c2ecf20Sopenharmony_ci	struct hfi1_ibport *ibp = ps->ibp;
2808c2ecf20Sopenharmony_ci	struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
2818c2ecf20Sopenharmony_ci	u32 slid;
2828c2ecf20Sopenharmony_ci	u16 pkey = hfi1_get_pkey(ibp, qp->s_pkey_index);
2838c2ecf20Sopenharmony_ci	u8 l4 = OPA_16B_L4_IB_LOCAL;
2848c2ecf20Sopenharmony_ci	u8 extra_bytes = hfi1_get_16b_padding(
2858c2ecf20Sopenharmony_ci				(ps->s_txreq->hdr_dwords << 2),
2868c2ecf20Sopenharmony_ci				ps->s_txreq->s_cur_size);
2878c2ecf20Sopenharmony_ci	u32 nwords = SIZE_OF_CRC + ((ps->s_txreq->s_cur_size +
2888c2ecf20Sopenharmony_ci				 extra_bytes + SIZE_OF_LT) >> 2);
2898c2ecf20Sopenharmony_ci	bool becn = false;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (unlikely(rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) &&
2928c2ecf20Sopenharmony_ci	    hfi1_check_mcast(rdma_ah_get_dlid(&qp->remote_ah_attr))) {
2938c2ecf20Sopenharmony_ci		struct ib_grh *grh;
2948c2ecf20Sopenharmony_ci		struct ib_global_route *grd =
2958c2ecf20Sopenharmony_ci			rdma_ah_retrieve_grh(&qp->remote_ah_attr);
2968c2ecf20Sopenharmony_ci		/*
2978c2ecf20Sopenharmony_ci		 * Ensure OPA GIDs are transformed to IB gids
2988c2ecf20Sopenharmony_ci		 * before creating the GRH.
2998c2ecf20Sopenharmony_ci		 */
3008c2ecf20Sopenharmony_ci		if (grd->sgid_index == OPA_GID_INDEX)
3018c2ecf20Sopenharmony_ci			grd->sgid_index = 0;
3028c2ecf20Sopenharmony_ci		grh = &ps->s_txreq->phdr.hdr.opah.u.l.grh;
3038c2ecf20Sopenharmony_ci		l4 = OPA_16B_L4_IB_GLOBAL;
3048c2ecf20Sopenharmony_ci		ps->s_txreq->hdr_dwords +=
3058c2ecf20Sopenharmony_ci			hfi1_make_grh(ibp, grh, grd,
3068c2ecf20Sopenharmony_ci				      ps->s_txreq->hdr_dwords - LRH_16B_DWORDS,
3078c2ecf20Sopenharmony_ci				      nwords);
3088c2ecf20Sopenharmony_ci		middle = 0;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (qp->s_mig_state == IB_MIG_MIGRATED)
3128c2ecf20Sopenharmony_ci		bth1 |= OPA_BTH_MIG_REQ;
3138c2ecf20Sopenharmony_ci	else
3148c2ecf20Sopenharmony_ci		middle = 0;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	if (qp->s_flags & RVT_S_ECN) {
3178c2ecf20Sopenharmony_ci		qp->s_flags &= ~RVT_S_ECN;
3188c2ecf20Sopenharmony_ci		/* we recently received a FECN, so return a BECN */
3198c2ecf20Sopenharmony_ci		becn = true;
3208c2ecf20Sopenharmony_ci		middle = 0;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	if (middle)
3238c2ecf20Sopenharmony_ci		build_ahg(qp, bth2);
3248c2ecf20Sopenharmony_ci	else
3258c2ecf20Sopenharmony_ci		qp->s_flags &= ~HFI1_S_AHG_VALID;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	bth0 |= pkey;
3288c2ecf20Sopenharmony_ci	bth0 |= extra_bytes << 20;
3298c2ecf20Sopenharmony_ci	hfi1_make_ruc_bth(qp, ohdr, bth0, bth1, bth2);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (!ppd->lid)
3328c2ecf20Sopenharmony_ci		slid = be32_to_cpu(OPA_LID_PERMISSIVE);
3338c2ecf20Sopenharmony_ci	else
3348c2ecf20Sopenharmony_ci		slid = ppd->lid |
3358c2ecf20Sopenharmony_ci			(rdma_ah_get_path_bits(&qp->remote_ah_attr) &
3368c2ecf20Sopenharmony_ci			((1 << ppd->lmc) - 1));
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	hfi1_make_16b_hdr(&ps->s_txreq->phdr.hdr.opah,
3398c2ecf20Sopenharmony_ci			  slid,
3408c2ecf20Sopenharmony_ci			  opa_get_lid(rdma_ah_get_dlid(&qp->remote_ah_attr),
3418c2ecf20Sopenharmony_ci				      16B),
3428c2ecf20Sopenharmony_ci			  (ps->s_txreq->hdr_dwords + nwords) >> 1,
3438c2ecf20Sopenharmony_ci			  pkey, becn, 0, l4, priv->s_sc);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci/**
3478c2ecf20Sopenharmony_ci * hfi1_make_ruc_header_9B - build a 9B header
3488c2ecf20Sopenharmony_ci * @qp: the queue pair
3498c2ecf20Sopenharmony_ci * @ohdr: a pointer to the destination header memory
3508c2ecf20Sopenharmony_ci * @bth0: bth0 passed in from the RC/UC builder
3518c2ecf20Sopenharmony_ci * @bth2: bth2 passed in from the RC/UC builder
3528c2ecf20Sopenharmony_ci * @middle: non zero implies indicates ahg "could" be used
3538c2ecf20Sopenharmony_ci * @ps: the current packet state
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci * This routine may disarm ahg under these situations:
3568c2ecf20Sopenharmony_ci * - packet needs a GRH
3578c2ecf20Sopenharmony_ci * - BECN needed
3588c2ecf20Sopenharmony_ci * - migration state not IB_MIG_MIGRATED
3598c2ecf20Sopenharmony_ci */
3608c2ecf20Sopenharmony_cistatic inline void hfi1_make_ruc_header_9B(struct rvt_qp *qp,
3618c2ecf20Sopenharmony_ci					   struct ib_other_headers *ohdr,
3628c2ecf20Sopenharmony_ci					   u32 bth0, u32 bth1, u32 bth2,
3638c2ecf20Sopenharmony_ci					   int middle,
3648c2ecf20Sopenharmony_ci					   struct hfi1_pkt_state *ps)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
3678c2ecf20Sopenharmony_ci	struct hfi1_ibport *ibp = ps->ibp;
3688c2ecf20Sopenharmony_ci	u16 pkey = hfi1_get_pkey(ibp, qp->s_pkey_index);
3698c2ecf20Sopenharmony_ci	u16 lrh0 = HFI1_LRH_BTH;
3708c2ecf20Sopenharmony_ci	u8 extra_bytes = -ps->s_txreq->s_cur_size & 3;
3718c2ecf20Sopenharmony_ci	u32 nwords = SIZE_OF_CRC + ((ps->s_txreq->s_cur_size +
3728c2ecf20Sopenharmony_ci					 extra_bytes) >> 2);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (unlikely(rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH)) {
3758c2ecf20Sopenharmony_ci		struct ib_grh *grh = &ps->s_txreq->phdr.hdr.ibh.u.l.grh;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		lrh0 = HFI1_LRH_GRH;
3788c2ecf20Sopenharmony_ci		ps->s_txreq->hdr_dwords +=
3798c2ecf20Sopenharmony_ci			hfi1_make_grh(ibp, grh,
3808c2ecf20Sopenharmony_ci				      rdma_ah_read_grh(&qp->remote_ah_attr),
3818c2ecf20Sopenharmony_ci				      ps->s_txreq->hdr_dwords - LRH_9B_DWORDS,
3828c2ecf20Sopenharmony_ci				      nwords);
3838c2ecf20Sopenharmony_ci		middle = 0;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci	lrh0 |= (priv->s_sc & 0xf) << 12 |
3868c2ecf20Sopenharmony_ci		(rdma_ah_get_sl(&qp->remote_ah_attr) & 0xf) << 4;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (qp->s_mig_state == IB_MIG_MIGRATED)
3898c2ecf20Sopenharmony_ci		bth0 |= IB_BTH_MIG_REQ;
3908c2ecf20Sopenharmony_ci	else
3918c2ecf20Sopenharmony_ci		middle = 0;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (qp->s_flags & RVT_S_ECN) {
3948c2ecf20Sopenharmony_ci		qp->s_flags &= ~RVT_S_ECN;
3958c2ecf20Sopenharmony_ci		/* we recently received a FECN, so return a BECN */
3968c2ecf20Sopenharmony_ci		bth1 |= (IB_BECN_MASK << IB_BECN_SHIFT);
3978c2ecf20Sopenharmony_ci		middle = 0;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci	if (middle)
4008c2ecf20Sopenharmony_ci		build_ahg(qp, bth2);
4018c2ecf20Sopenharmony_ci	else
4028c2ecf20Sopenharmony_ci		qp->s_flags &= ~HFI1_S_AHG_VALID;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	bth0 |= pkey;
4058c2ecf20Sopenharmony_ci	bth0 |= extra_bytes << 20;
4068c2ecf20Sopenharmony_ci	hfi1_make_ruc_bth(qp, ohdr, bth0, bth1, bth2);
4078c2ecf20Sopenharmony_ci	hfi1_make_ib_hdr(&ps->s_txreq->phdr.hdr.ibh,
4088c2ecf20Sopenharmony_ci			 lrh0,
4098c2ecf20Sopenharmony_ci			 ps->s_txreq->hdr_dwords + nwords,
4108c2ecf20Sopenharmony_ci			 opa_get_lid(rdma_ah_get_dlid(&qp->remote_ah_attr), 9B),
4118c2ecf20Sopenharmony_ci			 ppd_from_ibp(ibp)->lid |
4128c2ecf20Sopenharmony_ci				rdma_ah_get_path_bits(&qp->remote_ah_attr));
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_citypedef void (*hfi1_make_ruc_hdr)(struct rvt_qp *qp,
4168c2ecf20Sopenharmony_ci				  struct ib_other_headers *ohdr,
4178c2ecf20Sopenharmony_ci				  u32 bth0, u32 bth1, u32 bth2, int middle,
4188c2ecf20Sopenharmony_ci				  struct hfi1_pkt_state *ps);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/* We support only two types - 9B and 16B for now */
4218c2ecf20Sopenharmony_cistatic const hfi1_make_ruc_hdr hfi1_ruc_header_tbl[2] = {
4228c2ecf20Sopenharmony_ci	[HFI1_PKT_TYPE_9B] = &hfi1_make_ruc_header_9B,
4238c2ecf20Sopenharmony_ci	[HFI1_PKT_TYPE_16B] = &hfi1_make_ruc_header_16B
4248c2ecf20Sopenharmony_ci};
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_civoid hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr,
4278c2ecf20Sopenharmony_ci			  u32 bth0, u32 bth1, u32 bth2, int middle,
4288c2ecf20Sopenharmony_ci			  struct hfi1_pkt_state *ps)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/*
4338c2ecf20Sopenharmony_ci	 * reset s_ahg/AHG fields
4348c2ecf20Sopenharmony_ci	 *
4358c2ecf20Sopenharmony_ci	 * This insures that the ahgentry/ahgcount
4368c2ecf20Sopenharmony_ci	 * are at a non-AHG default to protect
4378c2ecf20Sopenharmony_ci	 * build_verbs_tx_desc() from using
4388c2ecf20Sopenharmony_ci	 * an include ahgidx.
4398c2ecf20Sopenharmony_ci	 *
4408c2ecf20Sopenharmony_ci	 * build_ahg() will modify as appropriate
4418c2ecf20Sopenharmony_ci	 * to use the AHG feature.
4428c2ecf20Sopenharmony_ci	 */
4438c2ecf20Sopenharmony_ci	priv->s_ahg->tx_flags = 0;
4448c2ecf20Sopenharmony_ci	priv->s_ahg->ahgcount = 0;
4458c2ecf20Sopenharmony_ci	priv->s_ahg->ahgidx = 0;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* Make the appropriate header */
4488c2ecf20Sopenharmony_ci	hfi1_ruc_header_tbl[priv->hdr_type](qp, ohdr, bth0, bth1, bth2, middle,
4498c2ecf20Sopenharmony_ci					    ps);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci/* when sending, force a reschedule every one of these periods */
4538c2ecf20Sopenharmony_ci#define SEND_RESCHED_TIMEOUT (5 * HZ)  /* 5s in jiffies */
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci/**
4568c2ecf20Sopenharmony_ci * hfi1_schedule_send_yield - test for a yield required for QP
4578c2ecf20Sopenharmony_ci * send engine
4588c2ecf20Sopenharmony_ci * @timeout: Final time for timeout slice for jiffies
4598c2ecf20Sopenharmony_ci * @qp: a pointer to QP
4608c2ecf20Sopenharmony_ci * @ps: a pointer to a structure with commonly lookup values for
4618c2ecf20Sopenharmony_ci *      the the send engine progress
4628c2ecf20Sopenharmony_ci * @tid - true if it is the tid leg
4638c2ecf20Sopenharmony_ci *
4648c2ecf20Sopenharmony_ci * This routine checks if the time slice for the QP has expired
4658c2ecf20Sopenharmony_ci * for RC QPs, if so an additional work entry is queued. At this
4668c2ecf20Sopenharmony_ci * point, other QPs have an opportunity to be scheduled. It
4678c2ecf20Sopenharmony_ci * returns true if a yield is required, otherwise, false
4688c2ecf20Sopenharmony_ci * is returned.
4698c2ecf20Sopenharmony_ci */
4708c2ecf20Sopenharmony_cibool hfi1_schedule_send_yield(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
4718c2ecf20Sopenharmony_ci			      bool tid)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	ps->pkts_sent = true;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (unlikely(time_after(jiffies, ps->timeout))) {
4768c2ecf20Sopenharmony_ci		if (!ps->in_thread ||
4778c2ecf20Sopenharmony_ci		    workqueue_congested(ps->cpu, ps->ppd->hfi1_wq)) {
4788c2ecf20Sopenharmony_ci			spin_lock_irqsave(&qp->s_lock, ps->flags);
4798c2ecf20Sopenharmony_ci			if (!tid) {
4808c2ecf20Sopenharmony_ci				qp->s_flags &= ~RVT_S_BUSY;
4818c2ecf20Sopenharmony_ci				hfi1_schedule_send(qp);
4828c2ecf20Sopenharmony_ci			} else {
4838c2ecf20Sopenharmony_ci				struct hfi1_qp_priv *priv = qp->priv;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci				if (priv->s_flags &
4868c2ecf20Sopenharmony_ci				    HFI1_S_TID_BUSY_SET) {
4878c2ecf20Sopenharmony_ci					qp->s_flags &= ~RVT_S_BUSY;
4888c2ecf20Sopenharmony_ci					priv->s_flags &=
4898c2ecf20Sopenharmony_ci						~(HFI1_S_TID_BUSY_SET |
4908c2ecf20Sopenharmony_ci						  RVT_S_BUSY);
4918c2ecf20Sopenharmony_ci				} else {
4928c2ecf20Sopenharmony_ci					priv->s_flags &= ~RVT_S_BUSY;
4938c2ecf20Sopenharmony_ci				}
4948c2ecf20Sopenharmony_ci				hfi1_schedule_tid_send(qp);
4958c2ecf20Sopenharmony_ci			}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&qp->s_lock, ps->flags);
4988c2ecf20Sopenharmony_ci			this_cpu_inc(*ps->ppd->dd->send_schedule);
4998c2ecf20Sopenharmony_ci			trace_hfi1_rc_expired_time_slice(qp, true);
5008c2ecf20Sopenharmony_ci			return true;
5018c2ecf20Sopenharmony_ci		}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		cond_resched();
5048c2ecf20Sopenharmony_ci		this_cpu_inc(*ps->ppd->dd->send_schedule);
5058c2ecf20Sopenharmony_ci		ps->timeout = jiffies + ps->timeout_int;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	trace_hfi1_rc_expired_time_slice(qp, false);
5098c2ecf20Sopenharmony_ci	return false;
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_civoid hfi1_do_send_from_rvt(struct rvt_qp *qp)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	hfi1_do_send(qp, false);
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_civoid _hfi1_do_send(struct work_struct *work)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct iowait_work *w = container_of(work, struct iowait_work, iowork);
5208c2ecf20Sopenharmony_ci	struct rvt_qp *qp = iowait_to_qp(w->iow);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	hfi1_do_send(qp, true);
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci/**
5268c2ecf20Sopenharmony_ci * hfi1_do_send - perform a send on a QP
5278c2ecf20Sopenharmony_ci * @qp: a pointer to the QP
5288c2ecf20Sopenharmony_ci * @in_thread: true if in a workqueue thread
5298c2ecf20Sopenharmony_ci *
5308c2ecf20Sopenharmony_ci * Process entries in the send work queue until credit or queue is
5318c2ecf20Sopenharmony_ci * exhausted.  Only allow one CPU to send a packet per QP.
5328c2ecf20Sopenharmony_ci * Otherwise, two threads could send packets out of order.
5338c2ecf20Sopenharmony_ci */
5348c2ecf20Sopenharmony_civoid hfi1_do_send(struct rvt_qp *qp, bool in_thread)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct hfi1_pkt_state ps;
5378c2ecf20Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
5388c2ecf20Sopenharmony_ci	int (*make_req)(struct rvt_qp *qp, struct hfi1_pkt_state *ps);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	ps.dev = to_idev(qp->ibqp.device);
5418c2ecf20Sopenharmony_ci	ps.ibp = to_iport(qp->ibqp.device, qp->port_num);
5428c2ecf20Sopenharmony_ci	ps.ppd = ppd_from_ibp(ps.ibp);
5438c2ecf20Sopenharmony_ci	ps.in_thread = in_thread;
5448c2ecf20Sopenharmony_ci	ps.wait = iowait_get_ib_work(&priv->s_iowait);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	trace_hfi1_rc_do_send(qp, in_thread);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	switch (qp->ibqp.qp_type) {
5498c2ecf20Sopenharmony_ci	case IB_QPT_RC:
5508c2ecf20Sopenharmony_ci		if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
5518c2ecf20Sopenharmony_ci				   ~((1 << ps.ppd->lmc) - 1)) ==
5528c2ecf20Sopenharmony_ci				  ps.ppd->lid)) {
5538c2ecf20Sopenharmony_ci			rvt_ruc_loopback(qp);
5548c2ecf20Sopenharmony_ci			return;
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci		make_req = hfi1_make_rc_req;
5578c2ecf20Sopenharmony_ci		ps.timeout_int = qp->timeout_jiffies;
5588c2ecf20Sopenharmony_ci		break;
5598c2ecf20Sopenharmony_ci	case IB_QPT_UC:
5608c2ecf20Sopenharmony_ci		if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
5618c2ecf20Sopenharmony_ci				   ~((1 << ps.ppd->lmc) - 1)) ==
5628c2ecf20Sopenharmony_ci				  ps.ppd->lid)) {
5638c2ecf20Sopenharmony_ci			rvt_ruc_loopback(qp);
5648c2ecf20Sopenharmony_ci			return;
5658c2ecf20Sopenharmony_ci		}
5668c2ecf20Sopenharmony_ci		make_req = hfi1_make_uc_req;
5678c2ecf20Sopenharmony_ci		ps.timeout_int = SEND_RESCHED_TIMEOUT;
5688c2ecf20Sopenharmony_ci		break;
5698c2ecf20Sopenharmony_ci	default:
5708c2ecf20Sopenharmony_ci		make_req = hfi1_make_ud_req;
5718c2ecf20Sopenharmony_ci		ps.timeout_int = SEND_RESCHED_TIMEOUT;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	spin_lock_irqsave(&qp->s_lock, ps.flags);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* Return if we are already busy processing a work request. */
5778c2ecf20Sopenharmony_ci	if (!hfi1_send_ok(qp)) {
5788c2ecf20Sopenharmony_ci		if (qp->s_flags & HFI1_S_ANY_WAIT_IO)
5798c2ecf20Sopenharmony_ci			iowait_set_flag(&priv->s_iowait, IOWAIT_PENDING_IB);
5808c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&qp->s_lock, ps.flags);
5818c2ecf20Sopenharmony_ci		return;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	qp->s_flags |= RVT_S_BUSY;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	ps.timeout_int = ps.timeout_int / 8;
5878c2ecf20Sopenharmony_ci	ps.timeout = jiffies + ps.timeout_int;
5888c2ecf20Sopenharmony_ci	ps.cpu = priv->s_sde ? priv->s_sde->cpu :
5898c2ecf20Sopenharmony_ci			cpumask_first(cpumask_of_node(ps.ppd->dd->node));
5908c2ecf20Sopenharmony_ci	ps.pkts_sent = false;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/* insure a pre-built packet is handled  */
5938c2ecf20Sopenharmony_ci	ps.s_txreq = get_waiting_verbs_txreq(ps.wait);
5948c2ecf20Sopenharmony_ci	do {
5958c2ecf20Sopenharmony_ci		/* Check for a constructed packet to be sent. */
5968c2ecf20Sopenharmony_ci		if (ps.s_txreq) {
5978c2ecf20Sopenharmony_ci			if (priv->s_flags & HFI1_S_TID_BUSY_SET)
5988c2ecf20Sopenharmony_ci				qp->s_flags |= RVT_S_BUSY;
5998c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&qp->s_lock, ps.flags);
6008c2ecf20Sopenharmony_ci			/*
6018c2ecf20Sopenharmony_ci			 * If the packet cannot be sent now, return and
6028c2ecf20Sopenharmony_ci			 * the send engine will be woken up later.
6038c2ecf20Sopenharmony_ci			 */
6048c2ecf20Sopenharmony_ci			if (hfi1_verbs_send(qp, &ps))
6058c2ecf20Sopenharmony_ci				return;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci			/* allow other tasks to run */
6088c2ecf20Sopenharmony_ci			if (hfi1_schedule_send_yield(qp, &ps, false))
6098c2ecf20Sopenharmony_ci				return;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci			spin_lock_irqsave(&qp->s_lock, ps.flags);
6128c2ecf20Sopenharmony_ci		}
6138c2ecf20Sopenharmony_ci	} while (make_req(qp, &ps));
6148c2ecf20Sopenharmony_ci	iowait_starve_clear(ps.pkts_sent, &priv->s_iowait);
6158c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&qp->s_lock, ps.flags);
6168c2ecf20Sopenharmony_ci}
617