1*145eba1aSCai Huoqing // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
2f48ad614SDennis Dalessandro /*
32e2ba09eSMike Marciniszyn * Copyright(c) 2015 - 2018 Intel Corporation.
4f48ad614SDennis Dalessandro */
5f48ad614SDennis Dalessandro
6f48ad614SDennis Dalessandro #include <linux/spinlock.h>
7f48ad614SDennis Dalessandro
8f48ad614SDennis Dalessandro #include "hfi.h"
9f48ad614SDennis Dalessandro #include "mad.h"
10f48ad614SDennis Dalessandro #include "qp.h"
11f48ad614SDennis Dalessandro #include "verbs_txreq.h"
12f48ad614SDennis Dalessandro #include "trace.h"
13f48ad614SDennis Dalessandro
gid_ok(union ib_gid * gid,__be64 gid_prefix,__be64 id)14f48ad614SDennis Dalessandro static int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id)
15f48ad614SDennis Dalessandro {
16f48ad614SDennis Dalessandro return (gid->global.interface_id == id &&
17f48ad614SDennis Dalessandro (gid->global.subnet_prefix == gid_prefix ||
18f48ad614SDennis Dalessandro gid->global.subnet_prefix == IB_DEFAULT_GID_PREFIX));
19f48ad614SDennis Dalessandro }
20f48ad614SDennis Dalessandro
21f48ad614SDennis Dalessandro /*
22f48ad614SDennis Dalessandro *
23f48ad614SDennis Dalessandro * This should be called with the QP r_lock held.
24f48ad614SDennis Dalessandro *
25f48ad614SDennis Dalessandro * The s_lock will be acquired around the hfi1_migrate_qp() call.
26f48ad614SDennis Dalessandro */
hfi1_ruc_check_hdr(struct hfi1_ibport * ibp,struct hfi1_packet * packet)279039746cSDon Hiatt int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_packet *packet)
28f48ad614SDennis Dalessandro {
29f48ad614SDennis Dalessandro __be64 guid;
30f48ad614SDennis Dalessandro unsigned long flags;
319039746cSDon Hiatt struct rvt_qp *qp = packet->qp;
32d8966fcdSDasaratharaman Chandramouli u8 sc5 = ibp->sl_to_sc[rdma_ah_get_sl(&qp->remote_ah_attr)];
339039746cSDon Hiatt u32 dlid = packet->dlid;
349039746cSDon Hiatt u32 slid = packet->slid;
359039746cSDon Hiatt u32 sl = packet->sl;
366d6b8848SSebastian Sanchez bool migrated = packet->migrated;
376d6b8848SSebastian Sanchez u16 pkey = packet->pkey;
389039746cSDon Hiatt
399039746cSDon Hiatt if (qp->s_mig_state == IB_MIG_ARMED && migrated) {
409039746cSDon Hiatt if (!packet->grh) {
415786adf3SDon Hiatt if ((rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
425786adf3SDon Hiatt IB_AH_GRH) &&
435786adf3SDon Hiatt (packet->etype != RHF_RCV_TYPE_BYPASS))
449039746cSDon Hiatt return 1;
45f48ad614SDennis Dalessandro } else {
46d8966fcdSDasaratharaman Chandramouli const struct ib_global_route *grh;
47d8966fcdSDasaratharaman Chandramouli
48d8966fcdSDasaratharaman Chandramouli if (!(rdma_ah_get_ah_flags(&qp->alt_ah_attr) &
49d8966fcdSDasaratharaman Chandramouli IB_AH_GRH))
509039746cSDon Hiatt return 1;
51d8966fcdSDasaratharaman Chandramouli grh = rdma_ah_read_grh(&qp->alt_ah_attr);
52d8966fcdSDasaratharaman Chandramouli guid = get_sguid(ibp, grh->sgid_index);
539039746cSDon Hiatt if (!gid_ok(&packet->grh->dgid, ibp->rvp.gid_prefix,
54f48ad614SDennis Dalessandro guid))
559039746cSDon Hiatt return 1;
56f48ad614SDennis Dalessandro if (!gid_ok(
579039746cSDon Hiatt &packet->grh->sgid,
58d8966fcdSDasaratharaman Chandramouli grh->dgid.global.subnet_prefix,
59d8966fcdSDasaratharaman Chandramouli grh->dgid.global.interface_id))
609039746cSDon Hiatt return 1;
61f48ad614SDennis Dalessandro }
625786adf3SDon Hiatt if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
639039746cSDon Hiatt sc5, slid))) {
645786adf3SDon Hiatt hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
655786adf3SDon Hiatt slid, dlid);
669039746cSDon Hiatt return 1;
67f48ad614SDennis Dalessandro }
68f48ad614SDennis Dalessandro /* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */
699039746cSDon Hiatt if (slid != rdma_ah_get_dlid(&qp->alt_ah_attr) ||
70d8966fcdSDasaratharaman Chandramouli ppd_from_ibp(ibp)->port !=
71d8966fcdSDasaratharaman Chandramouli rdma_ah_get_port_num(&qp->alt_ah_attr))
729039746cSDon Hiatt return 1;
73f48ad614SDennis Dalessandro spin_lock_irqsave(&qp->s_lock, flags);
74f48ad614SDennis Dalessandro hfi1_migrate_qp(qp);
75f48ad614SDennis Dalessandro spin_unlock_irqrestore(&qp->s_lock, flags);
76f48ad614SDennis Dalessandro } else {
779039746cSDon Hiatt if (!packet->grh) {
785786adf3SDon Hiatt if ((rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
795786adf3SDon Hiatt IB_AH_GRH) &&
805786adf3SDon Hiatt (packet->etype != RHF_RCV_TYPE_BYPASS))
819039746cSDon Hiatt return 1;
82f48ad614SDennis Dalessandro } else {
83d8966fcdSDasaratharaman Chandramouli const struct ib_global_route *grh;
84d8966fcdSDasaratharaman Chandramouli
85d8966fcdSDasaratharaman Chandramouli if (!(rdma_ah_get_ah_flags(&qp->remote_ah_attr) &
86d8966fcdSDasaratharaman Chandramouli IB_AH_GRH))
879039746cSDon Hiatt return 1;
88d8966fcdSDasaratharaman Chandramouli grh = rdma_ah_read_grh(&qp->remote_ah_attr);
89d8966fcdSDasaratharaman Chandramouli guid = get_sguid(ibp, grh->sgid_index);
909039746cSDon Hiatt if (!gid_ok(&packet->grh->dgid, ibp->rvp.gid_prefix,
91f48ad614SDennis Dalessandro guid))
929039746cSDon Hiatt return 1;
93f48ad614SDennis Dalessandro if (!gid_ok(
949039746cSDon Hiatt &packet->grh->sgid,
95d8966fcdSDasaratharaman Chandramouli grh->dgid.global.subnet_prefix,
96d8966fcdSDasaratharaman Chandramouli grh->dgid.global.interface_id))
979039746cSDon Hiatt return 1;
98f48ad614SDennis Dalessandro }
995786adf3SDon Hiatt if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), pkey,
1009039746cSDon Hiatt sc5, slid))) {
1015786adf3SDon Hiatt hfi1_bad_pkey(ibp, pkey, sl, 0, qp->ibqp.qp_num,
1025786adf3SDon Hiatt slid, dlid);
1039039746cSDon Hiatt return 1;
104f48ad614SDennis Dalessandro }
105f48ad614SDennis Dalessandro /* Validate the SLID. See Ch. 9.6.1.5 */
1069039746cSDon Hiatt if ((slid != rdma_ah_get_dlid(&qp->remote_ah_attr)) ||
107f48ad614SDennis Dalessandro ppd_from_ibp(ibp)->port != qp->port_num)
1089039746cSDon Hiatt return 1;
1099039746cSDon Hiatt if (qp->s_mig_state == IB_MIG_REARM && !migrated)
110f48ad614SDennis Dalessandro qp->s_mig_state = IB_MIG_ARMED;
111f48ad614SDennis Dalessandro }
112f48ad614SDennis Dalessandro
113f48ad614SDennis Dalessandro return 0;
114f48ad614SDennis Dalessandro }
115f48ad614SDennis Dalessandro
116f48ad614SDennis Dalessandro /**
117f48ad614SDennis Dalessandro * hfi1_make_grh - construct a GRH header
118f48ad614SDennis Dalessandro * @ibp: a pointer to the IB port
119f48ad614SDennis Dalessandro * @hdr: a pointer to the GRH header being constructed
120f48ad614SDennis Dalessandro * @grh: the global route address to send to
12188733e3bSDon Hiatt * @hwords: size of header after grh being sent in dwords
122f48ad614SDennis Dalessandro * @nwords: the number of 32 bit words of data being sent
123f48ad614SDennis Dalessandro *
124f48ad614SDennis Dalessandro * Return the size of the header in 32 bit words.
125f48ad614SDennis Dalessandro */
hfi1_make_grh(struct hfi1_ibport * ibp,struct ib_grh * hdr,const struct ib_global_route * grh,u32 hwords,u32 nwords)126f48ad614SDennis Dalessandro u32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr,
127d8966fcdSDasaratharaman Chandramouli const struct ib_global_route *grh, u32 hwords, u32 nwords)
128f48ad614SDennis Dalessandro {
129f48ad614SDennis Dalessandro hdr->version_tclass_flow =
130f48ad614SDennis Dalessandro cpu_to_be32((IB_GRH_VERSION << IB_GRH_VERSION_SHIFT) |
131f48ad614SDennis Dalessandro (grh->traffic_class << IB_GRH_TCLASS_SHIFT) |
132f48ad614SDennis Dalessandro (grh->flow_label << IB_GRH_FLOW_SHIFT));
13388733e3bSDon Hiatt hdr->paylen = cpu_to_be16((hwords + nwords) << 2);
134f48ad614SDennis Dalessandro /* next_hdr is defined by C8-7 in ch. 8.4.1 */
135f48ad614SDennis Dalessandro hdr->next_hdr = IB_GRH_NEXT_HDR;
136f48ad614SDennis Dalessandro hdr->hop_limit = grh->hop_limit;
137f48ad614SDennis Dalessandro /* The SGID is 32-bit aligned. */
138f48ad614SDennis Dalessandro hdr->sgid.global.subnet_prefix = ibp->rvp.gid_prefix;
139f48ad614SDennis Dalessandro hdr->sgid.global.interface_id =
140a6cd5f08SJakub Pawlak grh->sgid_index < HFI1_GUIDS_PER_PORT ?
141a6cd5f08SJakub Pawlak get_sguid(ibp, grh->sgid_index) :
142a6cd5f08SJakub Pawlak get_sguid(ibp, HFI1_PORT_GUID_INDEX);
143f48ad614SDennis Dalessandro hdr->dgid = grh->dgid;
144f48ad614SDennis Dalessandro
145f48ad614SDennis Dalessandro /* GRH header size in 32-bit words. */
146f48ad614SDennis Dalessandro return sizeof(struct ib_grh) / sizeof(u32);
147f48ad614SDennis Dalessandro }
148f48ad614SDennis Dalessandro
14930e07416SDon Hiatt #define BTH2_OFFSET (offsetof(struct hfi1_sdma_header, \
15030e07416SDon Hiatt hdr.ibh.u.oth.bth[2]) / 4)
151f48ad614SDennis Dalessandro
152f48ad614SDennis Dalessandro /**
153a9b6b3bcSDasaratharaman Chandramouli * build_ahg - create ahg in s_ahg
154f48ad614SDennis Dalessandro * @qp: a pointer to QP
155f48ad614SDennis Dalessandro * @npsn: the next PSN for the request/response
156f48ad614SDennis Dalessandro *
157f48ad614SDennis Dalessandro * This routine handles the AHG by allocating an ahg entry and causing the
158f48ad614SDennis Dalessandro * copy of the first middle.
159f48ad614SDennis Dalessandro *
160f48ad614SDennis Dalessandro * Subsequent middles use the copied entry, editing the
161f48ad614SDennis Dalessandro * PSN with 1 or 2 edits.
162f48ad614SDennis Dalessandro */
build_ahg(struct rvt_qp * qp,u32 npsn)163f48ad614SDennis Dalessandro static inline void build_ahg(struct rvt_qp *qp, u32 npsn)
164f48ad614SDennis Dalessandro {
165f48ad614SDennis Dalessandro struct hfi1_qp_priv *priv = qp->priv;
166f48ad614SDennis Dalessandro
1672e2ba09eSMike Marciniszyn if (unlikely(qp->s_flags & HFI1_S_AHG_CLEAR))
168f48ad614SDennis Dalessandro clear_ahg(qp);
1692e2ba09eSMike Marciniszyn if (!(qp->s_flags & HFI1_S_AHG_VALID)) {
170f48ad614SDennis Dalessandro /* first middle that needs copy */
171f48ad614SDennis Dalessandro if (qp->s_ahgidx < 0)
172f48ad614SDennis Dalessandro qp->s_ahgidx = sdma_ahg_alloc(priv->s_sde);
173f48ad614SDennis Dalessandro if (qp->s_ahgidx >= 0) {
174f48ad614SDennis Dalessandro qp->s_ahgpsn = npsn;
175a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->tx_flags |= SDMA_TXREQ_F_AHG_COPY;
176f48ad614SDennis Dalessandro /* save to protect a change in another thread */
177a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgidx = qp->s_ahgidx;
1782e2ba09eSMike Marciniszyn qp->s_flags |= HFI1_S_AHG_VALID;
179f48ad614SDennis Dalessandro }
180f48ad614SDennis Dalessandro } else {
181f48ad614SDennis Dalessandro /* subsequent middle after valid */
182f48ad614SDennis Dalessandro if (qp->s_ahgidx >= 0) {
183a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->tx_flags |= SDMA_TXREQ_F_USE_AHG;
184a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgidx = qp->s_ahgidx;
185a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgcount++;
186a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgdesc[0] =
187f48ad614SDennis Dalessandro sdma_build_ahg_descriptor(
188f48ad614SDennis Dalessandro (__force u16)cpu_to_be16((u16)npsn),
189f48ad614SDennis Dalessandro BTH2_OFFSET,
190f48ad614SDennis Dalessandro 16,
191f48ad614SDennis Dalessandro 16);
192f48ad614SDennis Dalessandro if ((npsn & 0xffff0000) !=
193f48ad614SDennis Dalessandro (qp->s_ahgpsn & 0xffff0000)) {
194a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgcount++;
195a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgdesc[1] =
196f48ad614SDennis Dalessandro sdma_build_ahg_descriptor(
197f48ad614SDennis Dalessandro (__force u16)cpu_to_be16(
198f48ad614SDennis Dalessandro (u16)(npsn >> 16)),
199f48ad614SDennis Dalessandro BTH2_OFFSET,
200f48ad614SDennis Dalessandro 0,
201f48ad614SDennis Dalessandro 16);
202f48ad614SDennis Dalessandro }
203f48ad614SDennis Dalessandro }
204f48ad614SDennis Dalessandro }
205f48ad614SDennis Dalessandro }
206f48ad614SDennis Dalessandro
hfi1_make_ruc_bth(struct rvt_qp * qp,struct ib_other_headers * ohdr,u32 bth0,u32 bth1,u32 bth2)2075b6cabb0SDon Hiatt static inline void hfi1_make_ruc_bth(struct rvt_qp *qp,
2085b6cabb0SDon Hiatt struct ib_other_headers *ohdr,
2095b6cabb0SDon Hiatt u32 bth0, u32 bth1, u32 bth2)
2105b6cabb0SDon Hiatt {
2115b6cabb0SDon Hiatt ohdr->bth[0] = cpu_to_be32(bth0);
2125b6cabb0SDon Hiatt ohdr->bth[1] = cpu_to_be32(bth1);
2135b6cabb0SDon Hiatt ohdr->bth[2] = cpu_to_be32(bth2);
2145b6cabb0SDon Hiatt }
2155b6cabb0SDon Hiatt
2160a0bcb04SMike Marciniszyn /**
2170a0bcb04SMike Marciniszyn * hfi1_make_ruc_header_16B - build a 16B header
2180a0bcb04SMike Marciniszyn * @qp: the queue pair
2190a0bcb04SMike Marciniszyn * @ohdr: a pointer to the destination header memory
2200a0bcb04SMike Marciniszyn * @bth0: bth0 passed in from the RC/UC builder
2210654a746SLee Jones * @bth1: bth1 passed in from the RC/UC builder
2220a0bcb04SMike Marciniszyn * @bth2: bth2 passed in from the RC/UC builder
2230a0bcb04SMike Marciniszyn * @middle: non zero implies indicates ahg "could" be used
2240a0bcb04SMike Marciniszyn * @ps: the current packet state
2250a0bcb04SMike Marciniszyn *
2260a0bcb04SMike Marciniszyn * This routine may disarm ahg under these situations:
2270a0bcb04SMike Marciniszyn * - packet needs a GRH
2280a0bcb04SMike Marciniszyn * - BECN needed
2290a0bcb04SMike Marciniszyn * - migration state not IB_MIG_MIGRATED
2300a0bcb04SMike Marciniszyn */
hfi1_make_ruc_header_16B(struct rvt_qp * qp,struct ib_other_headers * ohdr,u32 bth0,u32 bth1,u32 bth2,int middle,struct hfi1_pkt_state * ps)2315b6cabb0SDon Hiatt static inline void hfi1_make_ruc_header_16B(struct rvt_qp *qp,
2325b6cabb0SDon Hiatt struct ib_other_headers *ohdr,
23344e43d91SMitko Haralanov u32 bth0, u32 bth1, u32 bth2,
23444e43d91SMitko Haralanov int middle,
235f48ad614SDennis Dalessandro struct hfi1_pkt_state *ps)
236f48ad614SDennis Dalessandro {
237f48ad614SDennis Dalessandro struct hfi1_qp_priv *priv = qp->priv;
238f48ad614SDennis Dalessandro struct hfi1_ibport *ibp = ps->ibp;
2395b6cabb0SDon Hiatt struct hfi1_pportdata *ppd = ppd_from_ibp(ibp);
2405b6cabb0SDon Hiatt u32 slid;
2415b6cabb0SDon Hiatt u16 pkey = hfi1_get_pkey(ibp, qp->s_pkey_index);
2425b6cabb0SDon Hiatt u8 l4 = OPA_16B_L4_IB_LOCAL;
2439636258fSMitko Haralanov u8 extra_bytes = hfi1_get_16b_padding(
2449636258fSMitko Haralanov (ps->s_txreq->hdr_dwords << 2),
2455b6cabb0SDon Hiatt ps->s_txreq->s_cur_size);
2465b6cabb0SDon Hiatt u32 nwords = SIZE_OF_CRC + ((ps->s_txreq->s_cur_size +
2475b6cabb0SDon Hiatt extra_bytes + SIZE_OF_LT) >> 2);
248ca85bb1cSSebastian Sanchez bool becn = false;
249f48ad614SDennis Dalessandro
2505b6cabb0SDon Hiatt if (unlikely(rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH) &&
2515b6cabb0SDon Hiatt hfi1_check_mcast(rdma_ah_get_dlid(&qp->remote_ah_attr))) {
2525b6cabb0SDon Hiatt struct ib_grh *grh;
2535b6cabb0SDon Hiatt struct ib_global_route *grd =
2545b6cabb0SDon Hiatt rdma_ah_retrieve_grh(&qp->remote_ah_attr);
2555b6cabb0SDon Hiatt /*
2565b6cabb0SDon Hiatt * Ensure OPA GIDs are transformed to IB gids
2575b6cabb0SDon Hiatt * before creating the GRH.
2585b6cabb0SDon Hiatt */
2595b6cabb0SDon Hiatt if (grd->sgid_index == OPA_GID_INDEX)
2605b6cabb0SDon Hiatt grd->sgid_index = 0;
2615b6cabb0SDon Hiatt grh = &ps->s_txreq->phdr.hdr.opah.u.l.grh;
2625b6cabb0SDon Hiatt l4 = OPA_16B_L4_IB_GLOBAL;
26378d3633bSMike Marciniszyn ps->s_txreq->hdr_dwords +=
26478d3633bSMike Marciniszyn hfi1_make_grh(ibp, grh, grd,
26578d3633bSMike Marciniszyn ps->s_txreq->hdr_dwords - LRH_16B_DWORDS,
26678d3633bSMike Marciniszyn nwords);
2675b6cabb0SDon Hiatt middle = 0;
2685b6cabb0SDon Hiatt }
2695b6cabb0SDon Hiatt
2705b6cabb0SDon Hiatt if (qp->s_mig_state == IB_MIG_MIGRATED)
2715b6cabb0SDon Hiatt bth1 |= OPA_BTH_MIG_REQ;
2725b6cabb0SDon Hiatt else
2735b6cabb0SDon Hiatt middle = 0;
2745b6cabb0SDon Hiatt
2750a0bcb04SMike Marciniszyn if (qp->s_flags & RVT_S_ECN) {
2760a0bcb04SMike Marciniszyn qp->s_flags &= ~RVT_S_ECN;
2770a0bcb04SMike Marciniszyn /* we recently received a FECN, so return a BECN */
2780a0bcb04SMike Marciniszyn becn = true;
2790a0bcb04SMike Marciniszyn middle = 0;
2800a0bcb04SMike Marciniszyn }
2815b6cabb0SDon Hiatt if (middle)
2825b6cabb0SDon Hiatt build_ahg(qp, bth2);
2835b6cabb0SDon Hiatt else
2842e2ba09eSMike Marciniszyn qp->s_flags &= ~HFI1_S_AHG_VALID;
2855b6cabb0SDon Hiatt
2865b6cabb0SDon Hiatt bth0 |= pkey;
2875b6cabb0SDon Hiatt bth0 |= extra_bytes << 20;
2885b6cabb0SDon Hiatt hfi1_make_ruc_bth(qp, ohdr, bth0, bth1, bth2);
2895b6cabb0SDon Hiatt
2905b6cabb0SDon Hiatt if (!ppd->lid)
2915b6cabb0SDon Hiatt slid = be32_to_cpu(OPA_LID_PERMISSIVE);
2925b6cabb0SDon Hiatt else
2935b6cabb0SDon Hiatt slid = ppd->lid |
2945b6cabb0SDon Hiatt (rdma_ah_get_path_bits(&qp->remote_ah_attr) &
2955b6cabb0SDon Hiatt ((1 << ppd->lmc) - 1));
2965b6cabb0SDon Hiatt
2975b6cabb0SDon Hiatt hfi1_make_16b_hdr(&ps->s_txreq->phdr.hdr.opah,
2985b6cabb0SDon Hiatt slid,
2995b6cabb0SDon Hiatt opa_get_lid(rdma_ah_get_dlid(&qp->remote_ah_attr),
3005b6cabb0SDon Hiatt 16B),
3019636258fSMitko Haralanov (ps->s_txreq->hdr_dwords + nwords) >> 1,
3025b6cabb0SDon Hiatt pkey, becn, 0, l4, priv->s_sc);
3035b6cabb0SDon Hiatt }
3045b6cabb0SDon Hiatt
3050a0bcb04SMike Marciniszyn /**
3060a0bcb04SMike Marciniszyn * hfi1_make_ruc_header_9B - build a 9B header
3070a0bcb04SMike Marciniszyn * @qp: the queue pair
3080a0bcb04SMike Marciniszyn * @ohdr: a pointer to the destination header memory
3090a0bcb04SMike Marciniszyn * @bth0: bth0 passed in from the RC/UC builder
3100654a746SLee Jones * @bth1: bth1 passed in from the RC/UC builder
3110a0bcb04SMike Marciniszyn * @bth2: bth2 passed in from the RC/UC builder
3120a0bcb04SMike Marciniszyn * @middle: non zero implies indicates ahg "could" be used
3130a0bcb04SMike Marciniszyn * @ps: the current packet state
3140a0bcb04SMike Marciniszyn *
3150a0bcb04SMike Marciniszyn * This routine may disarm ahg under these situations:
3160a0bcb04SMike Marciniszyn * - packet needs a GRH
3170a0bcb04SMike Marciniszyn * - BECN needed
3180a0bcb04SMike Marciniszyn * - migration state not IB_MIG_MIGRATED
3190a0bcb04SMike Marciniszyn */
hfi1_make_ruc_header_9B(struct rvt_qp * qp,struct ib_other_headers * ohdr,u32 bth0,u32 bth1,u32 bth2,int middle,struct hfi1_pkt_state * ps)3205b6cabb0SDon Hiatt static inline void hfi1_make_ruc_header_9B(struct rvt_qp *qp,
3215b6cabb0SDon Hiatt struct ib_other_headers *ohdr,
32244e43d91SMitko Haralanov u32 bth0, u32 bth1, u32 bth2,
32344e43d91SMitko Haralanov int middle,
3245b6cabb0SDon Hiatt struct hfi1_pkt_state *ps)
3255b6cabb0SDon Hiatt {
3265b6cabb0SDon Hiatt struct hfi1_qp_priv *priv = qp->priv;
3275b6cabb0SDon Hiatt struct hfi1_ibport *ibp = ps->ibp;
3285b6cabb0SDon Hiatt u16 pkey = hfi1_get_pkey(ibp, qp->s_pkey_index);
3295b6cabb0SDon Hiatt u16 lrh0 = HFI1_LRH_BTH;
3305b6cabb0SDon Hiatt u8 extra_bytes = -ps->s_txreq->s_cur_size & 3;
3315b6cabb0SDon Hiatt u32 nwords = SIZE_OF_CRC + ((ps->s_txreq->s_cur_size +
3325b6cabb0SDon Hiatt extra_bytes) >> 2);
3335b6cabb0SDon Hiatt
334d8966fcdSDasaratharaman Chandramouli if (unlikely(rdma_ah_get_ah_flags(&qp->remote_ah_attr) & IB_AH_GRH)) {
3355b6cabb0SDon Hiatt struct ib_grh *grh = &ps->s_txreq->phdr.hdr.ibh.u.l.grh;
3365b6cabb0SDon Hiatt
337f48ad614SDennis Dalessandro lrh0 = HFI1_LRH_GRH;
3389636258fSMitko Haralanov ps->s_txreq->hdr_dwords +=
3395b6cabb0SDon Hiatt hfi1_make_grh(ibp, grh,
3405b6cabb0SDon Hiatt rdma_ah_read_grh(&qp->remote_ah_attr),
34178d3633bSMike Marciniszyn ps->s_txreq->hdr_dwords - LRH_9B_DWORDS,
34278d3633bSMike Marciniszyn nwords);
343f48ad614SDennis Dalessandro middle = 0;
344f48ad614SDennis Dalessandro }
345d8966fcdSDasaratharaman Chandramouli lrh0 |= (priv->s_sc & 0xf) << 12 |
346d8966fcdSDasaratharaman Chandramouli (rdma_ah_get_sl(&qp->remote_ah_attr) & 0xf) << 4;
3475b6cabb0SDon Hiatt
3485b6cabb0SDon Hiatt if (qp->s_mig_state == IB_MIG_MIGRATED)
3495b6cabb0SDon Hiatt bth0 |= IB_BTH_MIG_REQ;
3505b6cabb0SDon Hiatt else
3515b6cabb0SDon Hiatt middle = 0;
3525b6cabb0SDon Hiatt
3530a0bcb04SMike Marciniszyn if (qp->s_flags & RVT_S_ECN) {
3540a0bcb04SMike Marciniszyn qp->s_flags &= ~RVT_S_ECN;
3550a0bcb04SMike Marciniszyn /* we recently received a FECN, so return a BECN */
3560a0bcb04SMike Marciniszyn bth1 |= (IB_BECN_MASK << IB_BECN_SHIFT);
3570a0bcb04SMike Marciniszyn middle = 0;
3580a0bcb04SMike Marciniszyn }
3595b6cabb0SDon Hiatt if (middle)
3605b6cabb0SDon Hiatt build_ahg(qp, bth2);
3615b6cabb0SDon Hiatt else
3622e2ba09eSMike Marciniszyn qp->s_flags &= ~HFI1_S_AHG_VALID;
3635b6cabb0SDon Hiatt
3645b6cabb0SDon Hiatt bth0 |= pkey;
3655b6cabb0SDon Hiatt bth0 |= extra_bytes << 20;
3665b6cabb0SDon Hiatt hfi1_make_ruc_bth(qp, ohdr, bth0, bth1, bth2);
3675b6cabb0SDon Hiatt hfi1_make_ib_hdr(&ps->s_txreq->phdr.hdr.ibh,
3685b6cabb0SDon Hiatt lrh0,
3699636258fSMitko Haralanov ps->s_txreq->hdr_dwords + nwords,
3705b6cabb0SDon Hiatt opa_get_lid(rdma_ah_get_dlid(&qp->remote_ah_attr), 9B),
3715b6cabb0SDon Hiatt ppd_from_ibp(ibp)->lid |
3725b6cabb0SDon Hiatt rdma_ah_get_path_bits(&qp->remote_ah_attr));
3735b6cabb0SDon Hiatt }
3745b6cabb0SDon Hiatt
3755b6cabb0SDon Hiatt typedef void (*hfi1_make_ruc_hdr)(struct rvt_qp *qp,
3765b6cabb0SDon Hiatt struct ib_other_headers *ohdr,
37744e43d91SMitko Haralanov u32 bth0, u32 bth1, u32 bth2, int middle,
3785b6cabb0SDon Hiatt struct hfi1_pkt_state *ps);
3795b6cabb0SDon Hiatt
3805b6cabb0SDon Hiatt /* We support only two types - 9B and 16B for now */
3815b6cabb0SDon Hiatt static const hfi1_make_ruc_hdr hfi1_ruc_header_tbl[2] = {
3825b6cabb0SDon Hiatt [HFI1_PKT_TYPE_9B] = &hfi1_make_ruc_header_9B,
3835b6cabb0SDon Hiatt [HFI1_PKT_TYPE_16B] = &hfi1_make_ruc_header_16B
3845b6cabb0SDon Hiatt };
3855b6cabb0SDon Hiatt
hfi1_make_ruc_header(struct rvt_qp * qp,struct ib_other_headers * ohdr,u32 bth0,u32 bth1,u32 bth2,int middle,struct hfi1_pkt_state * ps)3865b6cabb0SDon Hiatt void hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr,
38744e43d91SMitko Haralanov u32 bth0, u32 bth1, u32 bth2, int middle,
3885b6cabb0SDon Hiatt struct hfi1_pkt_state *ps)
3895b6cabb0SDon Hiatt {
3905b6cabb0SDon Hiatt struct hfi1_qp_priv *priv = qp->priv;
3915b6cabb0SDon Hiatt
392f48ad614SDennis Dalessandro /*
393a9b6b3bcSDasaratharaman Chandramouli * reset s_ahg/AHG fields
394f48ad614SDennis Dalessandro *
395f48ad614SDennis Dalessandro * This insures that the ahgentry/ahgcount
396f48ad614SDennis Dalessandro * are at a non-AHG default to protect
397f48ad614SDennis Dalessandro * build_verbs_tx_desc() from using
398f48ad614SDennis Dalessandro * an include ahgidx.
399f48ad614SDennis Dalessandro *
400f48ad614SDennis Dalessandro * build_ahg() will modify as appropriate
401f48ad614SDennis Dalessandro * to use the AHG feature.
402f48ad614SDennis Dalessandro */
403a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->tx_flags = 0;
404a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgcount = 0;
405a9b6b3bcSDasaratharaman Chandramouli priv->s_ahg->ahgidx = 0;
4065b6cabb0SDon Hiatt
4075b6cabb0SDon Hiatt /* Make the appropriate header */
40844e43d91SMitko Haralanov hfi1_ruc_header_tbl[priv->hdr_type](qp, ohdr, bth0, bth1, bth2, middle,
40944e43d91SMitko Haralanov ps);
410f48ad614SDennis Dalessandro }
411f48ad614SDennis Dalessandro
412f48ad614SDennis Dalessandro /* when sending, force a reschedule every one of these periods */
413f48ad614SDennis Dalessandro #define SEND_RESCHED_TIMEOUT (5 * HZ) /* 5s in jiffies */
414f48ad614SDennis Dalessandro
415dd1ed108SMike Marciniszyn /**
416572f0c33SKaike Wan * hfi1_schedule_send_yield - test for a yield required for QP
417572f0c33SKaike Wan * send engine
418dd1ed108SMike Marciniszyn * @qp: a pointer to QP
419dd1ed108SMike Marciniszyn * @ps: a pointer to a structure with commonly lookup values for
420991c4274SCai Huoqing * the send engine progress
4210654a746SLee Jones * @tid: true if it is the tid leg
422dd1ed108SMike Marciniszyn *
423dd1ed108SMike Marciniszyn * This routine checks if the time slice for the QP has expired
424dd1ed108SMike Marciniszyn * for RC QPs, if so an additional work entry is queued. At this
425dd1ed108SMike Marciniszyn * point, other QPs have an opportunity to be scheduled. It
426dd1ed108SMike Marciniszyn * returns true if a yield is required, otherwise, false
427dd1ed108SMike Marciniszyn * is returned.
428dd1ed108SMike Marciniszyn */
hfi1_schedule_send_yield(struct rvt_qp * qp,struct hfi1_pkt_state * ps,bool tid)429572f0c33SKaike Wan bool hfi1_schedule_send_yield(struct rvt_qp *qp, struct hfi1_pkt_state *ps,
430572f0c33SKaike Wan bool tid)
431dd1ed108SMike Marciniszyn {
432bcad2913SKaike Wan ps->pkts_sent = true;
433bcad2913SKaike Wan
434dd1ed108SMike Marciniszyn if (unlikely(time_after(jiffies, ps->timeout))) {
435dd1ed108SMike Marciniszyn if (!ps->in_thread ||
436dd1ed108SMike Marciniszyn workqueue_congested(ps->cpu, ps->ppd->hfi1_wq)) {
437dd1ed108SMike Marciniszyn spin_lock_irqsave(&qp->s_lock, ps->flags);
438572f0c33SKaike Wan if (!tid) {
439dd1ed108SMike Marciniszyn qp->s_flags &= ~RVT_S_BUSY;
440dd1ed108SMike Marciniszyn hfi1_schedule_send(qp);
441572f0c33SKaike Wan } else {
442572f0c33SKaike Wan struct hfi1_qp_priv *priv = qp->priv;
443572f0c33SKaike Wan
444572f0c33SKaike Wan if (priv->s_flags &
445572f0c33SKaike Wan HFI1_S_TID_BUSY_SET) {
446572f0c33SKaike Wan qp->s_flags &= ~RVT_S_BUSY;
447572f0c33SKaike Wan priv->s_flags &=
448572f0c33SKaike Wan ~(HFI1_S_TID_BUSY_SET |
449572f0c33SKaike Wan RVT_S_BUSY);
450572f0c33SKaike Wan } else {
451572f0c33SKaike Wan priv->s_flags &= ~RVT_S_BUSY;
452572f0c33SKaike Wan }
453572f0c33SKaike Wan hfi1_schedule_tid_send(qp);
454572f0c33SKaike Wan }
455572f0c33SKaike Wan
456dd1ed108SMike Marciniszyn spin_unlock_irqrestore(&qp->s_lock, ps->flags);
457dd1ed108SMike Marciniszyn this_cpu_inc(*ps->ppd->dd->send_schedule);
458dd1ed108SMike Marciniszyn trace_hfi1_rc_expired_time_slice(qp, true);
459dd1ed108SMike Marciniszyn return true;
460dd1ed108SMike Marciniszyn }
461dd1ed108SMike Marciniszyn
462dd1ed108SMike Marciniszyn cond_resched();
463dd1ed108SMike Marciniszyn this_cpu_inc(*ps->ppd->dd->send_schedule);
464dd1ed108SMike Marciniszyn ps->timeout = jiffies + ps->timeout_int;
465dd1ed108SMike Marciniszyn }
466dd1ed108SMike Marciniszyn
467dd1ed108SMike Marciniszyn trace_hfi1_rc_expired_time_slice(qp, false);
468dd1ed108SMike Marciniszyn return false;
469dd1ed108SMike Marciniszyn }
470dd1ed108SMike Marciniszyn
hfi1_do_send_from_rvt(struct rvt_qp * qp)471b6eac931SMike Marciniszyn void hfi1_do_send_from_rvt(struct rvt_qp *qp)
472b6eac931SMike Marciniszyn {
473b6eac931SMike Marciniszyn hfi1_do_send(qp, false);
474b6eac931SMike Marciniszyn }
475b6eac931SMike Marciniszyn
_hfi1_do_send(struct work_struct * work)476f48ad614SDennis Dalessandro void _hfi1_do_send(struct work_struct *work)
477f48ad614SDennis Dalessandro {
4785da0fc9dSDennis Dalessandro struct iowait_work *w = container_of(work, struct iowait_work, iowork);
4795da0fc9dSDennis Dalessandro struct rvt_qp *qp = iowait_to_qp(w->iow);
480f48ad614SDennis Dalessandro
481b6eac931SMike Marciniszyn hfi1_do_send(qp, true);
482f48ad614SDennis Dalessandro }
483f48ad614SDennis Dalessandro
484f48ad614SDennis Dalessandro /**
485f48ad614SDennis Dalessandro * hfi1_do_send - perform a send on a QP
486ea752bc5SKaike Wan * @qp: a pointer to the QP
487b6eac931SMike Marciniszyn * @in_thread: true if in a workqueue thread
488f48ad614SDennis Dalessandro *
489f48ad614SDennis Dalessandro * Process entries in the send work queue until credit or queue is
490ca00c62bSDennis Dalessandro * exhausted. Only allow one CPU to send a packet per QP.
491f48ad614SDennis Dalessandro * Otherwise, two threads could send packets out of order.
492f48ad614SDennis Dalessandro */
hfi1_do_send(struct rvt_qp * qp,bool in_thread)493b6eac931SMike Marciniszyn void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
494f48ad614SDennis Dalessandro {
495f48ad614SDennis Dalessandro struct hfi1_pkt_state ps;
496f48ad614SDennis Dalessandro struct hfi1_qp_priv *priv = qp->priv;
497f48ad614SDennis Dalessandro int (*make_req)(struct rvt_qp *qp, struct hfi1_pkt_state *ps);
498f48ad614SDennis Dalessandro
499f48ad614SDennis Dalessandro ps.dev = to_idev(qp->ibqp.device);
500f48ad614SDennis Dalessandro ps.ibp = to_iport(qp->ibqp.device, qp->port_num);
501f48ad614SDennis Dalessandro ps.ppd = ppd_from_ibp(ps.ibp);
502dd1ed108SMike Marciniszyn ps.in_thread = in_thread;
5035da0fc9dSDennis Dalessandro ps.wait = iowait_get_ib_work(&priv->s_iowait);
504dd1ed108SMike Marciniszyn
505dd1ed108SMike Marciniszyn trace_hfi1_rc_do_send(qp, in_thread);
506f48ad614SDennis Dalessandro
507f48ad614SDennis Dalessandro switch (qp->ibqp.qp_type) {
508f48ad614SDennis Dalessandro case IB_QPT_RC:
509d8966fcdSDasaratharaman Chandramouli if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
510d8966fcdSDasaratharaman Chandramouli ~((1 << ps.ppd->lmc) - 1)) ==
511f48ad614SDennis Dalessandro ps.ppd->lid)) {
51215703461SVenkata Sandeep Dhanalakota rvt_ruc_loopback(qp);
513f48ad614SDennis Dalessandro return;
514f48ad614SDennis Dalessandro }
515f48ad614SDennis Dalessandro make_req = hfi1_make_rc_req;
516dd1ed108SMike Marciniszyn ps.timeout_int = qp->timeout_jiffies;
517f48ad614SDennis Dalessandro break;
518f48ad614SDennis Dalessandro case IB_QPT_UC:
519d8966fcdSDasaratharaman Chandramouli if (!loopback && ((rdma_ah_get_dlid(&qp->remote_ah_attr) &
520d8966fcdSDasaratharaman Chandramouli ~((1 << ps.ppd->lmc) - 1)) ==
521f48ad614SDennis Dalessandro ps.ppd->lid)) {
52215703461SVenkata Sandeep Dhanalakota rvt_ruc_loopback(qp);
523f48ad614SDennis Dalessandro return;
524f48ad614SDennis Dalessandro }
525f48ad614SDennis Dalessandro make_req = hfi1_make_uc_req;
526dd1ed108SMike Marciniszyn ps.timeout_int = SEND_RESCHED_TIMEOUT;
527f48ad614SDennis Dalessandro break;
528f48ad614SDennis Dalessandro default:
529f48ad614SDennis Dalessandro make_req = hfi1_make_ud_req;
530dd1ed108SMike Marciniszyn ps.timeout_int = SEND_RESCHED_TIMEOUT;
531f48ad614SDennis Dalessandro }
532f48ad614SDennis Dalessandro
533f48ad614SDennis Dalessandro spin_lock_irqsave(&qp->s_lock, ps.flags);
534f48ad614SDennis Dalessandro
535f48ad614SDennis Dalessandro /* Return if we are already busy processing a work request. */
536f48ad614SDennis Dalessandro if (!hfi1_send_ok(qp)) {
5375da0fc9dSDennis Dalessandro if (qp->s_flags & HFI1_S_ANY_WAIT_IO)
5385da0fc9dSDennis Dalessandro iowait_set_flag(&priv->s_iowait, IOWAIT_PENDING_IB);
539f48ad614SDennis Dalessandro spin_unlock_irqrestore(&qp->s_lock, ps.flags);
540f48ad614SDennis Dalessandro return;
541f48ad614SDennis Dalessandro }
542f48ad614SDennis Dalessandro
543f48ad614SDennis Dalessandro qp->s_flags |= RVT_S_BUSY;
544f48ad614SDennis Dalessandro
545dd1ed108SMike Marciniszyn ps.timeout_int = ps.timeout_int / 8;
546dd1ed108SMike Marciniszyn ps.timeout = jiffies + ps.timeout_int;
547dd1ed108SMike Marciniszyn ps.cpu = priv->s_sde ? priv->s_sde->cpu :
548f48ad614SDennis Dalessandro cpumask_first(cpumask_of_node(ps.ppd->dd->node));
549bcad2913SKaike Wan ps.pkts_sent = false;
550dd1ed108SMike Marciniszyn
551f48ad614SDennis Dalessandro /* insure a pre-built packet is handled */
5525da0fc9dSDennis Dalessandro ps.s_txreq = get_waiting_verbs_txreq(ps.wait);
553f48ad614SDennis Dalessandro do {
554f48ad614SDennis Dalessandro /* Check for a constructed packet to be sent. */
5559636258fSMitko Haralanov if (ps.s_txreq) {
556572f0c33SKaike Wan if (priv->s_flags & HFI1_S_TID_BUSY_SET)
557572f0c33SKaike Wan qp->s_flags |= RVT_S_BUSY;
558f48ad614SDennis Dalessandro spin_unlock_irqrestore(&qp->s_lock, ps.flags);
559f48ad614SDennis Dalessandro /*
560f48ad614SDennis Dalessandro * If the packet cannot be sent now, return and
561ca00c62bSDennis Dalessandro * the send engine will be woken up later.
562f48ad614SDennis Dalessandro */
563f48ad614SDennis Dalessandro if (hfi1_verbs_send(qp, &ps))
564f48ad614SDennis Dalessandro return;
5655da0fc9dSDennis Dalessandro
566f48ad614SDennis Dalessandro /* allow other tasks to run */
567572f0c33SKaike Wan if (hfi1_schedule_send_yield(qp, &ps, false))
568f48ad614SDennis Dalessandro return;
569dd1ed108SMike Marciniszyn
570f48ad614SDennis Dalessandro spin_lock_irqsave(&qp->s_lock, ps.flags);
571f48ad614SDennis Dalessandro }
572f48ad614SDennis Dalessandro } while (make_req(qp, &ps));
573bcad2913SKaike Wan iowait_starve_clear(ps.pkts_sent, &priv->s_iowait);
574f48ad614SDennis Dalessandro spin_unlock_irqrestore(&qp->s_lock, ps.flags);
575f48ad614SDennis Dalessandro }
576