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