162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright(c) 2015 - 2018 Intel Corporation.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/spinlock.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hfi.h"
962306a36Sopenharmony_ci#include "mad.h"
1062306a36Sopenharmony_ci#include "qp.h"
1162306a36Sopenharmony_ci#include "verbs_txreq.h"
1262306a36Sopenharmony_ci#include "trace.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	return (gid->global.interface_id == id &&
1762306a36Sopenharmony_ci		(gid->global.subnet_prefix == gid_prefix ||
1862306a36Sopenharmony_ci		 gid->global.subnet_prefix == IB_DEFAULT_GID_PREFIX));
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * This should be called with the QP r_lock held.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * The s_lock will be acquired around the hfi1_migrate_qp() call.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ciint hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	__be64 guid;
3062306a36Sopenharmony_ci	unsigned long flags;
3162306a36Sopenharmony_ci	struct rvt_qp *qp = packet->qp;
3262306a36Sopenharmony_ci	u8 sc5 = ibp->sl_to_sc[rdma_ah_get_sl(&qp->remote_ah_attr)];
3362306a36Sopenharmony_ci	u32 dlid = packet->dlid;
3462306a36Sopenharmony_ci	u32 slid = packet->slid;
3562306a36Sopenharmony_ci	u32 sl = packet->sl;
3662306a36Sopenharmony_ci	bool migrated = packet->migrated;
3762306a36Sopenharmony_ci	u16 pkey = packet->pkey;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (qp->s_mig_state == IB_MIG_ARMED && migrated) {
4062306a36Sopenharmony_ci		if (!packet->grh) {
4162306a36Sopenharmony_ci			if ((rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
4262306a36Sopenharmony_ci			     IB_AH_GRH) &&
4362306a36Sopenharmony_ci			    (packet->etype != RHF_RCV_TYPE_BYPASS))
4462306a36Sopenharmony_ci				return 1;
4562306a36Sopenharmony_ci		} else {
4662306a36Sopenharmony_ci			const struct ib_global_route *grh;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci			if (!(rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
4962306a36Sopenharmony_ci			      IB_AH_GRH))
5062306a36Sopenharmony_ci				return 1;
5162306a36Sopenharmony_ci			grh = rdma_ah_read_grh(&qp->alt_ah_attr);
5262306a36Sopenharmony_ci			guid = get_sguid(ibp, grh->sgid_index);
5362306a36Sopenharmony_ci			if (!gid_ok(&packet->grh->dgid, ibp->rvp.gid_prefix,
5462306a36Sopenharmony_ci				    guid))
5562306a36Sopenharmony_ci				return 1;
5662306a36Sopenharmony_ci			if (!gid_ok(
5762306a36Sopenharmony_ci				&packet->grh->sgid,
5862306a36Sopenharmony_ci				grh->dgid.global.subnet_prefix,
5962306a36Sopenharmony_ci				grh->dgid.global.interface_id))
6062306a36Sopenharmony_ci				return 1;
6162306a36Sopenharmony_ci		}
6262306a36Sopenharmony_ci		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
6362306a36Sopenharmony_ci					    sc5, slid))) {
6462306a36Sopenharmony_ci			hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
6562306a36Sopenharmony_ci				      slid, dlid);
6662306a36Sopenharmony_ci			return 1;
6762306a36Sopenharmony_ci		}
6862306a36Sopenharmony_ci		/* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */
6962306a36Sopenharmony_ci		if (slid != rdma_ah_get_dlid(&qp->alt_ah_attr) ||
7062306a36Sopenharmony_ci		    ppd_from_ibp(ibp)->port !=
7162306a36Sopenharmony_ci			rdma_ah_get_port_num(&qp->alt_ah_attr))
7262306a36Sopenharmony_ci			return 1;
7362306a36Sopenharmony_ci		spin_lock_irqsave(&qp->s_lock, flags);
7462306a36Sopenharmony_ci		hfi1_migrate_qp(qp);
7562306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->s_lock, flags);
7662306a36Sopenharmony_ci	} else {
7762306a36Sopenharmony_ci		if (!packet->grh) {
7862306a36Sopenharmony_ci			if ((rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
7962306a36Sopenharmony_ci			     IB_AH_GRH) &&
8062306a36Sopenharmony_ci			    (packet->etype != RHF_RCV_TYPE_BYPASS))
8162306a36Sopenharmony_ci				return 1;
8262306a36Sopenharmony_ci		} else {
8362306a36Sopenharmony_ci			const struct ib_global_route *grh;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci			if (!(rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
8662306a36Sopenharmony_ci						   IB_AH_GRH))
8762306a36Sopenharmony_ci				return 1;
8862306a36Sopenharmony_ci			grh = rdma_ah_read_grh(&qp->remote_ah_attr);
8962306a36Sopenharmony_ci			guid = get_sguid(ibp, grh->sgid_index);
9062306a36Sopenharmony_ci			if (!gid_ok(&packet->grh->dgid, ibp->rvp.gid_prefix,
9162306a36Sopenharmony_ci				    guid))
9262306a36Sopenharmony_ci				return 1;
9362306a36Sopenharmony_ci			if (!gid_ok(
9462306a36Sopenharmony_ci			     &packet->grh->sgid,
9562306a36Sopenharmony_ci			     grh->dgid.global.subnet_prefix,
9662306a36Sopenharmony_ci			     grh->dgid.global.interface_id))
9762306a36Sopenharmony_ci				return 1;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci		if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
10062306a36Sopenharmony_ci					    sc5, slid))) {
10162306a36Sopenharmony_ci			hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
10262306a36Sopenharmony_ci				      slid, dlid);
10362306a36Sopenharmony_ci			return 1;
10462306a36Sopenharmony_ci		}
10562306a36Sopenharmony_ci		/* Validate the SLID. See Ch. 9.6.1.5 */
10662306a36Sopenharmony_ci		if ((slid != rdma_ah_get_dlid(&qp->remote_ah_attr)) ||
10762306a36Sopenharmony_ci		    ppd_from_ibp(ibp)->port != qp->port_num)
10862306a36Sopenharmony_ci			return 1;
10962306a36Sopenharmony_ci		if (qp->s_mig_state == IB_MIG_REARM && !migrated)
11062306a36Sopenharmony_ci			qp->s_mig_state = IB_MIG_ARMED;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/**
11762306a36Sopenharmony_ci * hfi1_make_grh - construct a GRH header
11862306a36Sopenharmony_ci * @ibp: a pointer to the IB port
11962306a36Sopenharmony_ci * @hdr: a pointer to the GRH header being constructed
12062306a36Sopenharmony_ci * @grh: the global route address to send to
12162306a36Sopenharmony_ci * @hwords: size of header after grh being sent in dwords
12262306a36Sopenharmony_ci * @nwords: the number of 32 bit words of data being sent
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * Return the size of the header in 32 bit words.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_ciu32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr,
12762306a36Sopenharmony_ci		  const struct ib_global_route *grh, u32 hwords, u32 nwords)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	hdr->version_tclass_flow =
13062306a36Sopenharmony_ci		cpu_to_be32((IB_GRH_VERSION << IB_GRH_VERSION_SHIFT) |
13162306a36Sopenharmony_ci			    (grh->traffic_class << IB_GRH_TCLASS_SHIFT) |
13262306a36Sopenharmony_ci			    (grh->flow_label << IB_GRH_FLOW_SHIFT));
13362306a36Sopenharmony_ci	hdr->paylen = cpu_to_be16((hwords + nwords) << 2);
13462306a36Sopenharmony_ci	/* next_hdr is defined by C8-7 in ch. 8.4.1 */
13562306a36Sopenharmony_ci	hdr->next_hdr = IB_GRH_NEXT_HDR;
13662306a36Sopenharmony_ci	hdr->hop_limit = grh->hop_limit;
13762306a36Sopenharmony_ci	/* The SGID is 32-bit aligned. */
13862306a36Sopenharmony_ci	hdr->sgid.global.subnet_prefix = ibp->rvp.gid_prefix;
13962306a36Sopenharmony_ci	hdr->sgid.global.interface_id =
14062306a36Sopenharmony_ci		grh->sgid_index < HFI1_GUIDS_PER_PORT ?
14162306a36Sopenharmony_ci		get_sguid(ibp, grh->sgid_index) :
14262306a36Sopenharmony_ci		get_sguid(ibp, HFI1_PORT_GUID_INDEX);
14362306a36Sopenharmony_ci	hdr->dgid = grh->dgid;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* GRH header size in 32-bit words. */
14662306a36Sopenharmony_ci	return sizeof(struct ib_grh) / sizeof(u32);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define BTH2_OFFSET (offsetof(struct hfi1_sdma_header, \
15062306a36Sopenharmony_ci			      hdr.ibh.u.oth.bth[2]) / 4)
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci/**
15362306a36Sopenharmony_ci * build_ahg - create ahg in s_ahg
15462306a36Sopenharmony_ci * @qp: a pointer to QP
15562306a36Sopenharmony_ci * @npsn: the next PSN for the request/response
15662306a36Sopenharmony_ci *
15762306a36Sopenharmony_ci * This routine handles the AHG by allocating an ahg entry and causing the
15862306a36Sopenharmony_ci * copy of the first middle.
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci * Subsequent middles use the copied entry, editing the
16162306a36Sopenharmony_ci * PSN with 1 or 2 edits.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_cistatic inline void build_ahg(struct rvt_qp *qp, u32 npsn)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (unlikely(qp->s_flags & HFI1_S_AHG_CLEAR))
16862306a36Sopenharmony_ci		clear_ahg(qp);
16962306a36Sopenharmony_ci	if (!(qp->s_flags & HFI1_S_AHG_VALID)) {
17062306a36Sopenharmony_ci		/* first middle that needs copy  */
17162306a36Sopenharmony_ci		if (qp->s_ahgidx < 0)
17262306a36Sopenharmony_ci			qp->s_ahgidx = sdma_ahg_alloc(priv->s_sde);
17362306a36Sopenharmony_ci		if (qp->s_ahgidx >= 0) {
17462306a36Sopenharmony_ci			qp->s_ahgpsn = npsn;
17562306a36Sopenharmony_ci			priv->s_ahg->tx_flags |= SDMA_TXREQ_F_AHG_COPY;
17662306a36Sopenharmony_ci			/* save to protect a change in another thread */
17762306a36Sopenharmony_ci			priv->s_ahg->ahgidx = qp->s_ahgidx;
17862306a36Sopenharmony_ci			qp->s_flags |= HFI1_S_AHG_VALID;
17962306a36Sopenharmony_ci		}
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		/* subsequent middle after valid */
18262306a36Sopenharmony_ci		if (qp->s_ahgidx >= 0) {
18362306a36Sopenharmony_ci			priv->s_ahg->tx_flags |= SDMA_TXREQ_F_USE_AHG;
18462306a36Sopenharmony_ci			priv->s_ahg->ahgidx = qp->s_ahgidx;
18562306a36Sopenharmony_ci			priv->s_ahg->ahgcount++;
18662306a36Sopenharmony_ci			priv->s_ahg->ahgdesc[0] =
18762306a36Sopenharmony_ci				sdma_build_ahg_descriptor(
18862306a36Sopenharmony_ci					(__force u16)cpu_to_be16((u16)npsn),
18962306a36Sopenharmony_ci					BTH2_OFFSET,
19062306a36Sopenharmony_ci					16,
19162306a36Sopenharmony_ci					16);
19262306a36Sopenharmony_ci			if ((npsn & 0xffff0000) !=
19362306a36Sopenharmony_ci					(qp->s_ahgpsn & 0xffff0000)) {
19462306a36Sopenharmony_ci				priv->s_ahg->ahgcount++;
19562306a36Sopenharmony_ci				priv->s_ahg->ahgdesc[1] =
19662306a36Sopenharmony_ci					sdma_build_ahg_descriptor(
19762306a36Sopenharmony_ci						(__force u16)cpu_to_be16(
19862306a36Sopenharmony_ci							(u16)(npsn >> 16)),
19962306a36Sopenharmony_ci						BTH2_OFFSET,
20062306a36Sopenharmony_ci						0,
20162306a36Sopenharmony_ci						16);
20262306a36Sopenharmony_ci			}
20362306a36Sopenharmony_ci		}
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic inline void hfi1_make_ruc_bth(struct rvt_qp *qp,
20862306a36Sopenharmony_ci				     struct ib_other_headers *ohdr,
20962306a36Sopenharmony_ci				     u32 bth0, u32 bth1, u32 bth2)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	ohdr->bth[0] = cpu_to_be32(bth0);
21262306a36Sopenharmony_ci	ohdr->bth[1] = cpu_to_be32(bth1);
21362306a36Sopenharmony_ci	ohdr->bth[2] = cpu_to_be32(bth2);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/**
21762306a36Sopenharmony_ci * hfi1_make_ruc_header_16B - build a 16B header
21862306a36Sopenharmony_ci * @qp: the queue pair
21962306a36Sopenharmony_ci * @ohdr: a pointer to the destination header memory
22062306a36Sopenharmony_ci * @bth0: bth0 passed in from the RC/UC builder
22162306a36Sopenharmony_ci * @bth1: bth1 passed in from the RC/UC builder
22262306a36Sopenharmony_ci * @bth2: bth2 passed in from the RC/UC builder
22362306a36Sopenharmony_ci * @middle: non zero implies indicates ahg "could" be used
22462306a36Sopenharmony_ci * @ps: the current packet state
22562306a36Sopenharmony_ci *
22662306a36Sopenharmony_ci * This routine may disarm ahg under these situations:
22762306a36Sopenharmony_ci * - packet needs a GRH
22862306a36Sopenharmony_ci * - BECN needed
22962306a36Sopenharmony_ci * - migration state not IB_MIG_MIGRATED
23062306a36Sopenharmony_ci */
23162306a36Sopenharmony_cistatic inline void hfi1_make_ruc_header_16B(struct rvt_qp *qp,
23262306a36Sopenharmony_ci					    struct ib_other_headers *ohdr,
23362306a36Sopenharmony_ci					    u32 bth0, u32 bth1, u32 bth2,
23462306a36Sopenharmony_ci					    int middle,
23562306a36Sopenharmony_ci					    struct hfi1_pkt_state *ps)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
23862306a36Sopenharmony_ci	struct hfi1_ibport *ibp = ps->ibp;
23962306a36Sopenharmony_ci	struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
24062306a36Sopenharmony_ci	u32 slid;
24162306a36Sopenharmony_ci	u16 pkey = hfi1_get_pkey(ibp, qp->s_pkey_index);
24262306a36Sopenharmony_ci	u8 l4 = OPA_16B_L4_IB_LOCAL;
24362306a36Sopenharmony_ci	u8 extra_bytes = hfi1_get_16b_padding(
24462306a36Sopenharmony_ci				(ps->s_txreq->hdr_dwords << 2),
24562306a36Sopenharmony_ci				ps->s_txreq->s_cur_size);
24662306a36Sopenharmony_ci	u32 nwords = SIZE_OF_CRC + ((ps->s_txreq->s_cur_size +
24762306a36Sopenharmony_ci				 extra_bytes + SIZE_OF_LT) >> 2);
24862306a36Sopenharmony_ci	bool becn = false;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (unlikely(rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) &&
25162306a36Sopenharmony_ci	    hfi1_check_mcast(rdma_ah_get_dlid(&qp->remote_ah_attr))) {
25262306a36Sopenharmony_ci		struct ib_grh *grh;
25362306a36Sopenharmony_ci		struct ib_global_route *grd =
25462306a36Sopenharmony_ci			rdma_ah_retrieve_grh(&qp->remote_ah_attr);
25562306a36Sopenharmony_ci		/*
25662306a36Sopenharmony_ci		 * Ensure OPA GIDs are transformed to IB gids
25762306a36Sopenharmony_ci		 * before creating the GRH.
25862306a36Sopenharmony_ci		 */
25962306a36Sopenharmony_ci		if (grd->sgid_index == OPA_GID_INDEX)
26062306a36Sopenharmony_ci			grd->sgid_index = 0;
26162306a36Sopenharmony_ci		grh = &ps->s_txreq->phdr.hdr.opah.u.l.grh;
26262306a36Sopenharmony_ci		l4 = OPA_16B_L4_IB_GLOBAL;
26362306a36Sopenharmony_ci		ps->s_txreq->hdr_dwords +=
26462306a36Sopenharmony_ci			hfi1_make_grh(ibp, grh, grd,
26562306a36Sopenharmony_ci				      ps->s_txreq->hdr_dwords - LRH_16B_DWORDS,
26662306a36Sopenharmony_ci				      nwords);
26762306a36Sopenharmony_ci		middle = 0;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (qp->s_mig_state == IB_MIG_MIGRATED)
27162306a36Sopenharmony_ci		bth1 |= OPA_BTH_MIG_REQ;
27262306a36Sopenharmony_ci	else
27362306a36Sopenharmony_ci		middle = 0;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (qp->s_flags & RVT_S_ECN) {
27662306a36Sopenharmony_ci		qp->s_flags &= ~RVT_S_ECN;
27762306a36Sopenharmony_ci		/* we recently received a FECN, so return a BECN */
27862306a36Sopenharmony_ci		becn = true;
27962306a36Sopenharmony_ci		middle = 0;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci	if (middle)
28262306a36Sopenharmony_ci		build_ahg(qp, bth2);
28362306a36Sopenharmony_ci	else
28462306a36Sopenharmony_ci		qp->s_flags &= ~HFI1_S_AHG_VALID;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	bth0 |= pkey;
28762306a36Sopenharmony_ci	bth0 |= extra_bytes << 20;
28862306a36Sopenharmony_ci	hfi1_make_ruc_bth(qp, ohdr, bth0, bth1, bth2);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (!ppd->lid)
29162306a36Sopenharmony_ci		slid = be32_to_cpu(OPA_LID_PERMISSIVE);
29262306a36Sopenharmony_ci	else
29362306a36Sopenharmony_ci		slid = ppd->lid |
29462306a36Sopenharmony_ci			(rdma_ah_get_path_bits(&qp->remote_ah_attr) &
29562306a36Sopenharmony_ci			((1 << ppd->lmc) - 1));
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	hfi1_make_16b_hdr(&ps->s_txreq->phdr.hdr.opah,
29862306a36Sopenharmony_ci			  slid,
29962306a36Sopenharmony_ci			  opa_get_lid(rdma_ah_get_dlid(&qp->remote_ah_attr),
30062306a36Sopenharmony_ci				      16B),
30162306a36Sopenharmony_ci			  (ps->s_txreq->hdr_dwords + nwords) >> 1,
30262306a36Sopenharmony_ci			  pkey, becn, 0, l4, priv->s_sc);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci/**
30662306a36Sopenharmony_ci * hfi1_make_ruc_header_9B - build a 9B header
30762306a36Sopenharmony_ci * @qp: the queue pair
30862306a36Sopenharmony_ci * @ohdr: a pointer to the destination header memory
30962306a36Sopenharmony_ci * @bth0: bth0 passed in from the RC/UC builder
31062306a36Sopenharmony_ci * @bth1: bth1 passed in from the RC/UC builder
31162306a36Sopenharmony_ci * @bth2: bth2 passed in from the RC/UC builder
31262306a36Sopenharmony_ci * @middle: non zero implies indicates ahg "could" be used
31362306a36Sopenharmony_ci * @ps: the current packet state
31462306a36Sopenharmony_ci *
31562306a36Sopenharmony_ci * This routine may disarm ahg under these situations:
31662306a36Sopenharmony_ci * - packet needs a GRH
31762306a36Sopenharmony_ci * - BECN needed
31862306a36Sopenharmony_ci * - migration state not IB_MIG_MIGRATED
31962306a36Sopenharmony_ci */
32062306a36Sopenharmony_cistatic inline void hfi1_make_ruc_header_9B(struct rvt_qp *qp,
32162306a36Sopenharmony_ci					   struct ib_other_headers *ohdr,
32262306a36Sopenharmony_ci					   u32 bth0, u32 bth1, u32 bth2,
32362306a36Sopenharmony_ci					   int middle,
32462306a36Sopenharmony_ci					   struct hfi1_pkt_state *ps)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
32762306a36Sopenharmony_ci	struct hfi1_ibport *ibp = ps->ibp;
32862306a36Sopenharmony_ci	u16 pkey = hfi1_get_pkey(ibp, qp->s_pkey_index);
32962306a36Sopenharmony_ci	u16 lrh0 = HFI1_LRH_BTH;
33062306a36Sopenharmony_ci	u8 extra_bytes = -ps->s_txreq->s_cur_size & 3;
33162306a36Sopenharmony_ci	u32 nwords = SIZE_OF_CRC + ((ps->s_txreq->s_cur_size +
33262306a36Sopenharmony_ci					 extra_bytes) >> 2);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (unlikely(rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH)) {
33562306a36Sopenharmony_ci		struct ib_grh *grh = &ps->s_txreq->phdr.hdr.ibh.u.l.grh;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		lrh0 = HFI1_LRH_GRH;
33862306a36Sopenharmony_ci		ps->s_txreq->hdr_dwords +=
33962306a36Sopenharmony_ci			hfi1_make_grh(ibp, grh,
34062306a36Sopenharmony_ci				      rdma_ah_read_grh(&qp->remote_ah_attr),
34162306a36Sopenharmony_ci				      ps->s_txreq->hdr_dwords - LRH_9B_DWORDS,
34262306a36Sopenharmony_ci				      nwords);
34362306a36Sopenharmony_ci		middle = 0;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci	lrh0 |= (priv->s_sc & 0xf) << 12 |
34662306a36Sopenharmony_ci		(rdma_ah_get_sl(&qp->remote_ah_attr) & 0xf) << 4;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (qp->s_mig_state == IB_MIG_MIGRATED)
34962306a36Sopenharmony_ci		bth0 |= IB_BTH_MIG_REQ;
35062306a36Sopenharmony_ci	else
35162306a36Sopenharmony_ci		middle = 0;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (qp->s_flags & RVT_S_ECN) {
35462306a36Sopenharmony_ci		qp->s_flags &= ~RVT_S_ECN;
35562306a36Sopenharmony_ci		/* we recently received a FECN, so return a BECN */
35662306a36Sopenharmony_ci		bth1 |= (IB_BECN_MASK << IB_BECN_SHIFT);
35762306a36Sopenharmony_ci		middle = 0;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	if (middle)
36062306a36Sopenharmony_ci		build_ahg(qp, bth2);
36162306a36Sopenharmony_ci	else
36262306a36Sopenharmony_ci		qp->s_flags &= ~HFI1_S_AHG_VALID;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	bth0 |= pkey;
36562306a36Sopenharmony_ci	bth0 |= extra_bytes << 20;
36662306a36Sopenharmony_ci	hfi1_make_ruc_bth(qp, ohdr, bth0, bth1, bth2);
36762306a36Sopenharmony_ci	hfi1_make_ib_hdr(&ps->s_txreq->phdr.hdr.ibh,
36862306a36Sopenharmony_ci			 lrh0,
36962306a36Sopenharmony_ci			 ps->s_txreq->hdr_dwords + nwords,
37062306a36Sopenharmony_ci			 opa_get_lid(rdma_ah_get_dlid(&qp->remote_ah_attr), 9B),
37162306a36Sopenharmony_ci			 ppd_from_ibp(ibp)->lid |
37262306a36Sopenharmony_ci				rdma_ah_get_path_bits(&qp->remote_ah_attr));
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_citypedef void (*hfi1_make_ruc_hdr)(struct rvt_qp *qp,
37662306a36Sopenharmony_ci				  struct ib_other_headers *ohdr,
37762306a36Sopenharmony_ci				  u32 bth0, u32 bth1, u32 bth2, int middle,
37862306a36Sopenharmony_ci				  struct hfi1_pkt_state *ps);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/* We support only two types - 9B and 16B for now */
38162306a36Sopenharmony_cistatic const hfi1_make_ruc_hdr hfi1_ruc_header_tbl[2] = {
38262306a36Sopenharmony_ci	[HFI1_PKT_TYPE_9B] = &hfi1_make_ruc_header_9B,
38362306a36Sopenharmony_ci	[HFI1_PKT_TYPE_16B] = &hfi1_make_ruc_header_16B
38462306a36Sopenharmony_ci};
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_civoid hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr,
38762306a36Sopenharmony_ci			  u32 bth0, u32 bth1, u32 bth2, int middle,
38862306a36Sopenharmony_ci			  struct hfi1_pkt_state *ps)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/*
39362306a36Sopenharmony_ci	 * reset s_ahg/AHG fields
39462306a36Sopenharmony_ci	 *
39562306a36Sopenharmony_ci	 * This insures that the ahgentry/ahgcount
39662306a36Sopenharmony_ci	 * are at a non-AHG default to protect
39762306a36Sopenharmony_ci	 * build_verbs_tx_desc() from using
39862306a36Sopenharmony_ci	 * an include ahgidx.
39962306a36Sopenharmony_ci	 *
40062306a36Sopenharmony_ci	 * build_ahg() will modify as appropriate
40162306a36Sopenharmony_ci	 * to use the AHG feature.
40262306a36Sopenharmony_ci	 */
40362306a36Sopenharmony_ci	priv->s_ahg->tx_flags = 0;
40462306a36Sopenharmony_ci	priv->s_ahg->ahgcount = 0;
40562306a36Sopenharmony_ci	priv->s_ahg->ahgidx = 0;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* Make the appropriate header */
40862306a36Sopenharmony_ci	hfi1_ruc_header_tbl[priv->hdr_type](qp, ohdr, bth0, bth1, bth2, middle,
40962306a36Sopenharmony_ci					    ps);
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/* when sending, force a reschedule every one of these periods */
41362306a36Sopenharmony_ci#define SEND_RESCHED_TIMEOUT (5 * HZ)  /* 5s in jiffies */
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * hfi1_schedule_send_yield - test for a yield required for QP
41762306a36Sopenharmony_ci * send engine
41862306a36Sopenharmony_ci * @qp: a pointer to QP
41962306a36Sopenharmony_ci * @ps: a pointer to a structure with commonly lookup values for
42062306a36Sopenharmony_ci *      the send engine progress
42162306a36Sopenharmony_ci * @tid: true if it is the tid leg
42262306a36Sopenharmony_ci *
42362306a36Sopenharmony_ci * This routine checks if the time slice for the QP has expired
42462306a36Sopenharmony_ci * for RC QPs, if so an additional work entry is queued. At this
42562306a36Sopenharmony_ci * point, other QPs have an opportunity to be scheduled. It
42662306a36Sopenharmony_ci * returns true if a yield is required, otherwise, false
42762306a36Sopenharmony_ci * is returned.
42862306a36Sopenharmony_ci */
42962306a36Sopenharmony_cibool hfi1_schedule_send_yield(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
43062306a36Sopenharmony_ci			      bool tid)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	ps->pkts_sent = true;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	if (unlikely(time_after(jiffies, ps->timeout))) {
43562306a36Sopenharmony_ci		if (!ps->in_thread ||
43662306a36Sopenharmony_ci		    workqueue_congested(ps->cpu, ps->ppd->hfi1_wq)) {
43762306a36Sopenharmony_ci			spin_lock_irqsave(&qp->s_lock, ps->flags);
43862306a36Sopenharmony_ci			if (!tid) {
43962306a36Sopenharmony_ci				qp->s_flags &= ~RVT_S_BUSY;
44062306a36Sopenharmony_ci				hfi1_schedule_send(qp);
44162306a36Sopenharmony_ci			} else {
44262306a36Sopenharmony_ci				struct hfi1_qp_priv *priv = qp->priv;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci				if (priv->s_flags &
44562306a36Sopenharmony_ci				    HFI1_S_TID_BUSY_SET) {
44662306a36Sopenharmony_ci					qp->s_flags &= ~RVT_S_BUSY;
44762306a36Sopenharmony_ci					priv->s_flags &=
44862306a36Sopenharmony_ci						~(HFI1_S_TID_BUSY_SET |
44962306a36Sopenharmony_ci						  RVT_S_BUSY);
45062306a36Sopenharmony_ci				} else {
45162306a36Sopenharmony_ci					priv->s_flags &= ~RVT_S_BUSY;
45262306a36Sopenharmony_ci				}
45362306a36Sopenharmony_ci				hfi1_schedule_tid_send(qp);
45462306a36Sopenharmony_ci			}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci			spin_unlock_irqrestore(&qp->s_lock, ps->flags);
45762306a36Sopenharmony_ci			this_cpu_inc(*ps->ppd->dd->send_schedule);
45862306a36Sopenharmony_ci			trace_hfi1_rc_expired_time_slice(qp, true);
45962306a36Sopenharmony_ci			return true;
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		cond_resched();
46362306a36Sopenharmony_ci		this_cpu_inc(*ps->ppd->dd->send_schedule);
46462306a36Sopenharmony_ci		ps->timeout = jiffies + ps->timeout_int;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	trace_hfi1_rc_expired_time_slice(qp, false);
46862306a36Sopenharmony_ci	return false;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_civoid hfi1_do_send_from_rvt(struct rvt_qp *qp)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	hfi1_do_send(qp, false);
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_civoid _hfi1_do_send(struct work_struct *work)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct iowait_work *w = container_of(work, struct iowait_work, iowork);
47962306a36Sopenharmony_ci	struct rvt_qp *qp = iowait_to_qp(w->iow);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	hfi1_do_send(qp, true);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/**
48562306a36Sopenharmony_ci * hfi1_do_send - perform a send on a QP
48662306a36Sopenharmony_ci * @qp: a pointer to the QP
48762306a36Sopenharmony_ci * @in_thread: true if in a workqueue thread
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci * Process entries in the send work queue until credit or queue is
49062306a36Sopenharmony_ci * exhausted.  Only allow one CPU to send a packet per QP.
49162306a36Sopenharmony_ci * Otherwise, two threads could send packets out of order.
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_civoid hfi1_do_send(struct rvt_qp *qp, bool in_thread)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct hfi1_pkt_state ps;
49662306a36Sopenharmony_ci	struct hfi1_qp_priv *priv = qp->priv;
49762306a36Sopenharmony_ci	int (*make_req)(struct rvt_qp *qp, struct hfi1_pkt_state *ps);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	ps.dev = to_idev(qp->ibqp.device);
50062306a36Sopenharmony_ci	ps.ibp = to_iport(qp->ibqp.device, qp->port_num);
50162306a36Sopenharmony_ci	ps.ppd = ppd_from_ibp(ps.ibp);
50262306a36Sopenharmony_ci	ps.in_thread = in_thread;
50362306a36Sopenharmony_ci	ps.wait = iowait_get_ib_work(&priv->s_iowait);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	trace_hfi1_rc_do_send(qp, in_thread);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	switch (qp->ibqp.qp_type) {
50862306a36Sopenharmony_ci	case IB_QPT_RC:
50962306a36Sopenharmony_ci		if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
51062306a36Sopenharmony_ci				   ~((1 << ps.ppd->lmc) - 1)) ==
51162306a36Sopenharmony_ci				  ps.ppd->lid)) {
51262306a36Sopenharmony_ci			rvt_ruc_loopback(qp);
51362306a36Sopenharmony_ci			return;
51462306a36Sopenharmony_ci		}
51562306a36Sopenharmony_ci		make_req = hfi1_make_rc_req;
51662306a36Sopenharmony_ci		ps.timeout_int = qp->timeout_jiffies;
51762306a36Sopenharmony_ci		break;
51862306a36Sopenharmony_ci	case IB_QPT_UC:
51962306a36Sopenharmony_ci		if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
52062306a36Sopenharmony_ci				   ~((1 << ps.ppd->lmc) - 1)) ==
52162306a36Sopenharmony_ci				  ps.ppd->lid)) {
52262306a36Sopenharmony_ci			rvt_ruc_loopback(qp);
52362306a36Sopenharmony_ci			return;
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci		make_req = hfi1_make_uc_req;
52662306a36Sopenharmony_ci		ps.timeout_int = SEND_RESCHED_TIMEOUT;
52762306a36Sopenharmony_ci		break;
52862306a36Sopenharmony_ci	default:
52962306a36Sopenharmony_ci		make_req = hfi1_make_ud_req;
53062306a36Sopenharmony_ci		ps.timeout_int = SEND_RESCHED_TIMEOUT;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	spin_lock_irqsave(&qp->s_lock, ps.flags);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* Return if we are already busy processing a work request. */
53662306a36Sopenharmony_ci	if (!hfi1_send_ok(qp)) {
53762306a36Sopenharmony_ci		if (qp->s_flags & HFI1_S_ANY_WAIT_IO)
53862306a36Sopenharmony_ci			iowait_set_flag(&priv->s_iowait, IOWAIT_PENDING_IB);
53962306a36Sopenharmony_ci		spin_unlock_irqrestore(&qp->s_lock, ps.flags);
54062306a36Sopenharmony_ci		return;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	qp->s_flags |= RVT_S_BUSY;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	ps.timeout_int = ps.timeout_int / 8;
54662306a36Sopenharmony_ci	ps.timeout = jiffies + ps.timeout_int;
54762306a36Sopenharmony_ci	ps.cpu = priv->s_sde ? priv->s_sde->cpu :
54862306a36Sopenharmony_ci			cpumask_first(cpumask_of_node(ps.ppd->dd->node));
54962306a36Sopenharmony_ci	ps.pkts_sent = false;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* insure a pre-built packet is handled  */
55262306a36Sopenharmony_ci	ps.s_txreq = get_waiting_verbs_txreq(ps.wait);
55362306a36Sopenharmony_ci	do {
55462306a36Sopenharmony_ci		/* Check for a constructed packet to be sent. */
55562306a36Sopenharmony_ci		if (ps.s_txreq) {
55662306a36Sopenharmony_ci			if (priv->s_flags & HFI1_S_TID_BUSY_SET)
55762306a36Sopenharmony_ci				qp->s_flags |= RVT_S_BUSY;
55862306a36Sopenharmony_ci			spin_unlock_irqrestore(&qp->s_lock, ps.flags);
55962306a36Sopenharmony_ci			/*
56062306a36Sopenharmony_ci			 * If the packet cannot be sent now, return and
56162306a36Sopenharmony_ci			 * the send engine will be woken up later.
56262306a36Sopenharmony_ci			 */
56362306a36Sopenharmony_ci			if (hfi1_verbs_send(qp, &ps))
56462306a36Sopenharmony_ci				return;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci			/* allow other tasks to run */
56762306a36Sopenharmony_ci			if (hfi1_schedule_send_yield(qp, &ps, false))
56862306a36Sopenharmony_ci				return;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci			spin_lock_irqsave(&qp->s_lock, ps.flags);
57162306a36Sopenharmony_ci		}
57262306a36Sopenharmony_ci	} while (make_req(qp, &ps));
57362306a36Sopenharmony_ci	iowait_starve_clear(ps.pkts_sent, &priv->s_iowait);
57462306a36Sopenharmony_ci	spin_unlock_irqrestore(&qp->s_lock, ps.flags);
57562306a36Sopenharmony_ci}
576