18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2012 - 2019 Intel Corporation. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <rdma/ib_smi.h> 368c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "qib.h" 398c2ecf20Sopenharmony_ci#include "qib_mad.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/** 428c2ecf20Sopenharmony_ci * qib_ud_loopback - handle send on loopback QPs 438c2ecf20Sopenharmony_ci * @sqp: the sending QP 448c2ecf20Sopenharmony_ci * @swqe: the send work request 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * This is called from qib_make_ud_req() to forward a WQE addressed 478c2ecf20Sopenharmony_ci * to the same HCA. 488c2ecf20Sopenharmony_ci * Note that the receive interrupt handler may be calling qib_ud_rcv() 498c2ecf20Sopenharmony_ci * while this is being called. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct qib_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num); 548c2ecf20Sopenharmony_ci struct qib_pportdata *ppd = ppd_from_ibp(ibp); 558c2ecf20Sopenharmony_ci struct qib_devdata *dd = ppd->dd; 568c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = &dd->verbs_dev.rdi; 578c2ecf20Sopenharmony_ci struct rvt_qp *qp; 588c2ecf20Sopenharmony_ci struct rdma_ah_attr *ah_attr; 598c2ecf20Sopenharmony_ci unsigned long flags; 608c2ecf20Sopenharmony_ci struct rvt_sge_state ssge; 618c2ecf20Sopenharmony_ci struct rvt_sge *sge; 628c2ecf20Sopenharmony_ci struct ib_wc wc; 638c2ecf20Sopenharmony_ci u32 length; 648c2ecf20Sopenharmony_ci enum ib_qp_type sqptype, dqptype; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci rcu_read_lock(); 678c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(rdi, &ibp->rvp, rvt_get_swqe_remote_qpn(swqe)); 688c2ecf20Sopenharmony_ci if (!qp) { 698c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 708c2ecf20Sopenharmony_ci goto drop; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci sqptype = sqp->ibqp.qp_type == IB_QPT_GSI ? 748c2ecf20Sopenharmony_ci IB_QPT_UD : sqp->ibqp.qp_type; 758c2ecf20Sopenharmony_ci dqptype = qp->ibqp.qp_type == IB_QPT_GSI ? 768c2ecf20Sopenharmony_ci IB_QPT_UD : qp->ibqp.qp_type; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (dqptype != sqptype || 798c2ecf20Sopenharmony_ci !(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK)) { 808c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 818c2ecf20Sopenharmony_ci goto drop; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ah_attr = rvt_get_swqe_ah_attr(swqe); 858c2ecf20Sopenharmony_ci ppd = ppd_from_ibp(ibp); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num > 1) { 888c2ecf20Sopenharmony_ci u16 pkey1; 898c2ecf20Sopenharmony_ci u16 pkey2; 908c2ecf20Sopenharmony_ci u16 lid; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pkey1 = qib_get_pkey(ibp, sqp->s_pkey_index); 938c2ecf20Sopenharmony_ci pkey2 = qib_get_pkey(ibp, qp->s_pkey_index); 948c2ecf20Sopenharmony_ci if (unlikely(!qib_pkey_ok(pkey1, pkey2))) { 958c2ecf20Sopenharmony_ci lid = ppd->lid | (rdma_ah_get_path_bits(ah_attr) & 968c2ecf20Sopenharmony_ci ((1 << ppd->lmc) - 1)); 978c2ecf20Sopenharmony_ci qib_bad_pkey(ibp, pkey1, 988c2ecf20Sopenharmony_ci rdma_ah_get_sl(ah_attr), 998c2ecf20Sopenharmony_ci sqp->ibqp.qp_num, qp->ibqp.qp_num, 1008c2ecf20Sopenharmony_ci cpu_to_be16(lid), 1018c2ecf20Sopenharmony_ci cpu_to_be16(rdma_ah_get_dlid(ah_attr))); 1028c2ecf20Sopenharmony_ci goto drop; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * Check that the qkey matches (except for QP0, see 9.6.1.4.1). 1088c2ecf20Sopenharmony_ci * Qkeys with the high order bit set mean use the 1098c2ecf20Sopenharmony_ci * qkey from the QP context instead of the WR (see 10.2.5). 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num) { 1128c2ecf20Sopenharmony_ci u32 qkey; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci qkey = (int)rvt_get_swqe_remote_qkey(swqe) < 0 ? 1158c2ecf20Sopenharmony_ci sqp->qkey : rvt_get_swqe_remote_qkey(swqe); 1168c2ecf20Sopenharmony_ci if (unlikely(qkey != qp->qkey)) 1178c2ecf20Sopenharmony_ci goto drop; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * A GRH is expected to precede the data even if not 1228c2ecf20Sopenharmony_ci * present on the wire. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci length = swqe->length; 1258c2ecf20Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 1268c2ecf20Sopenharmony_ci wc.byte_len = length + sizeof(struct ib_grh); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) { 1298c2ecf20Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 1308c2ecf20Sopenharmony_ci wc.ex.imm_data = swqe->wr.ex.imm_data; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->r_lock, flags); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* 1368c2ecf20Sopenharmony_ci * Get the next work request entry to find where to put the data. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci if (qp->r_flags & RVT_R_REUSE_SGE) 1398c2ecf20Sopenharmony_ci qp->r_flags &= ~RVT_R_REUSE_SGE; 1408c2ecf20Sopenharmony_ci else { 1418c2ecf20Sopenharmony_ci int ret; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ret = rvt_get_rwqe(qp, false); 1448c2ecf20Sopenharmony_ci if (ret < 0) { 1458c2ecf20Sopenharmony_ci rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR); 1468c2ecf20Sopenharmony_ci goto bail_unlock; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci if (!ret) { 1498c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num == 0) 1508c2ecf20Sopenharmony_ci ibp->rvp.n_vl15_dropped++; 1518c2ecf20Sopenharmony_ci goto bail_unlock; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci /* Silently drop packets which are too big. */ 1558c2ecf20Sopenharmony_ci if (unlikely(wc.byte_len > qp->r_len)) { 1568c2ecf20Sopenharmony_ci qp->r_flags |= RVT_R_REUSE_SGE; 1578c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 1588c2ecf20Sopenharmony_ci goto bail_unlock; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) { 1628c2ecf20Sopenharmony_ci struct ib_grh grh; 1638c2ecf20Sopenharmony_ci const struct ib_global_route *grd = rdma_ah_read_grh(ah_attr); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci qib_make_grh(ibp, &grh, grd, 0, 0); 1668c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, &grh, 1678c2ecf20Sopenharmony_ci sizeof(grh), true, false); 1688c2ecf20Sopenharmony_ci wc.wc_flags |= IB_WC_GRH; 1698c2ecf20Sopenharmony_ci } else 1708c2ecf20Sopenharmony_ci rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true); 1718c2ecf20Sopenharmony_ci ssge.sg_list = swqe->sg_list + 1; 1728c2ecf20Sopenharmony_ci ssge.sge = *swqe->sg_list; 1738c2ecf20Sopenharmony_ci ssge.num_sge = swqe->wr.num_sge; 1748c2ecf20Sopenharmony_ci sge = &ssge.sge; 1758c2ecf20Sopenharmony_ci while (length) { 1768c2ecf20Sopenharmony_ci u32 len = rvt_get_sge_length(sge, length); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, len, true, false); 1798c2ecf20Sopenharmony_ci sge->vaddr += len; 1808c2ecf20Sopenharmony_ci sge->length -= len; 1818c2ecf20Sopenharmony_ci sge->sge_length -= len; 1828c2ecf20Sopenharmony_ci if (sge->sge_length == 0) { 1838c2ecf20Sopenharmony_ci if (--ssge.num_sge) 1848c2ecf20Sopenharmony_ci *sge = *ssge.sg_list++; 1858c2ecf20Sopenharmony_ci } else if (sge->length == 0 && sge->mr->lkey) { 1868c2ecf20Sopenharmony_ci if (++sge->n >= RVT_SEGSZ) { 1878c2ecf20Sopenharmony_ci if (++sge->m >= sge->mr->mapsz) 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci sge->n = 0; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci sge->vaddr = 1928c2ecf20Sopenharmony_ci sge->mr->map[sge->m]->segs[sge->n].vaddr; 1938c2ecf20Sopenharmony_ci sge->length = 1948c2ecf20Sopenharmony_ci sge->mr->map[sge->m]->segs[sge->n].length; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci length -= len; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci rvt_put_ss(&qp->r_sge); 1998c2ecf20Sopenharmony_ci if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) 2008c2ecf20Sopenharmony_ci goto bail_unlock; 2018c2ecf20Sopenharmony_ci wc.wr_id = qp->r_wr_id; 2028c2ecf20Sopenharmony_ci wc.status = IB_WC_SUCCESS; 2038c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV; 2048c2ecf20Sopenharmony_ci wc.qp = &qp->ibqp; 2058c2ecf20Sopenharmony_ci wc.src_qp = sqp->ibqp.qp_num; 2068c2ecf20Sopenharmony_ci wc.pkey_index = qp->ibqp.qp_type == IB_QPT_GSI ? 2078c2ecf20Sopenharmony_ci rvt_get_swqe_pkey_index(swqe) : 0; 2088c2ecf20Sopenharmony_ci wc.slid = ppd->lid | (rdma_ah_get_path_bits(ah_attr) & 2098c2ecf20Sopenharmony_ci ((1 << ppd->lmc) - 1)); 2108c2ecf20Sopenharmony_ci wc.sl = rdma_ah_get_sl(ah_attr); 2118c2ecf20Sopenharmony_ci wc.dlid_path_bits = rdma_ah_get_dlid(ah_attr) & ((1 << ppd->lmc) - 1); 2128c2ecf20Sopenharmony_ci wc.port_num = qp->port_num; 2138c2ecf20Sopenharmony_ci /* Signal completion event if the solicited bit is set. */ 2148c2ecf20Sopenharmony_ci rvt_recv_cq(qp, &wc, swqe->wr.send_flags & IB_SEND_SOLICITED); 2158c2ecf20Sopenharmony_ci ibp->rvp.n_loop_pkts++; 2168c2ecf20Sopenharmony_cibail_unlock: 2178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 2188c2ecf20Sopenharmony_cidrop: 2198c2ecf20Sopenharmony_ci rcu_read_unlock(); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/** 2238c2ecf20Sopenharmony_ci * qib_make_ud_req - construct a UD request packet 2248c2ecf20Sopenharmony_ci * @qp: the QP 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Assumes the s_lock is held. 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Return 1 if constructed; otherwise, return 0. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ciint qib_make_ud_req(struct rvt_qp *qp, unsigned long *flags) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct qib_qp_priv *priv = qp->priv; 2338c2ecf20Sopenharmony_ci struct ib_other_headers *ohdr; 2348c2ecf20Sopenharmony_ci struct rdma_ah_attr *ah_attr; 2358c2ecf20Sopenharmony_ci struct qib_pportdata *ppd; 2368c2ecf20Sopenharmony_ci struct qib_ibport *ibp; 2378c2ecf20Sopenharmony_ci struct rvt_swqe *wqe; 2388c2ecf20Sopenharmony_ci u32 nwords; 2398c2ecf20Sopenharmony_ci u32 extra_bytes; 2408c2ecf20Sopenharmony_ci u32 bth0; 2418c2ecf20Sopenharmony_ci u16 lrh0; 2428c2ecf20Sopenharmony_ci u16 lid; 2438c2ecf20Sopenharmony_ci int ret = 0; 2448c2ecf20Sopenharmony_ci int next_cur; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_NEXT_SEND_OK)) { 2478c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_FLUSH_SEND)) 2488c2ecf20Sopenharmony_ci goto bail; 2498c2ecf20Sopenharmony_ci /* We are in the error state, flush the work request. */ 2508c2ecf20Sopenharmony_ci if (qp->s_last == READ_ONCE(qp->s_head)) 2518c2ecf20Sopenharmony_ci goto bail; 2528c2ecf20Sopenharmony_ci /* If DMAs are in progress, we can't flush immediately. */ 2538c2ecf20Sopenharmony_ci if (atomic_read(&priv->s_dma_busy)) { 2548c2ecf20Sopenharmony_ci qp->s_flags |= RVT_S_WAIT_DMA; 2558c2ecf20Sopenharmony_ci goto bail; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_last); 2588c2ecf20Sopenharmony_ci rvt_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); 2598c2ecf20Sopenharmony_ci goto done; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* see post_one_send() */ 2638c2ecf20Sopenharmony_ci if (qp->s_cur == READ_ONCE(qp->s_head)) 2648c2ecf20Sopenharmony_ci goto bail; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_cur); 2678c2ecf20Sopenharmony_ci next_cur = qp->s_cur + 1; 2688c2ecf20Sopenharmony_ci if (next_cur >= qp->s_size) 2698c2ecf20Sopenharmony_ci next_cur = 0; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Construct the header. */ 2728c2ecf20Sopenharmony_ci ibp = to_iport(qp->ibqp.device, qp->port_num); 2738c2ecf20Sopenharmony_ci ppd = ppd_from_ibp(ibp); 2748c2ecf20Sopenharmony_ci ah_attr = rvt_get_swqe_ah_attr(wqe); 2758c2ecf20Sopenharmony_ci if (rdma_ah_get_dlid(ah_attr) >= be16_to_cpu(IB_MULTICAST_LID_BASE)) { 2768c2ecf20Sopenharmony_ci if (rdma_ah_get_dlid(ah_attr) != 2778c2ecf20Sopenharmony_ci be16_to_cpu(IB_LID_PERMISSIVE)) 2788c2ecf20Sopenharmony_ci this_cpu_inc(ibp->pmastats->n_multicast_xmit); 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci this_cpu_inc(ibp->pmastats->n_unicast_xmit); 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci this_cpu_inc(ibp->pmastats->n_unicast_xmit); 2838c2ecf20Sopenharmony_ci lid = rdma_ah_get_dlid(ah_attr) & ~((1 << ppd->lmc) - 1); 2848c2ecf20Sopenharmony_ci if (unlikely(lid == ppd->lid)) { 2858c2ecf20Sopenharmony_ci unsigned long tflags = *flags; 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * If DMAs are in progress, we can't generate 2888c2ecf20Sopenharmony_ci * a completion for the loopback packet since 2898c2ecf20Sopenharmony_ci * it would be out of order. 2908c2ecf20Sopenharmony_ci * XXX Instead of waiting, we could queue a 2918c2ecf20Sopenharmony_ci * zero length descriptor so we get a callback. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (atomic_read(&priv->s_dma_busy)) { 2948c2ecf20Sopenharmony_ci qp->s_flags |= RVT_S_WAIT_DMA; 2958c2ecf20Sopenharmony_ci goto bail; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci qp->s_cur = next_cur; 2988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->s_lock, tflags); 2998c2ecf20Sopenharmony_ci qib_ud_loopback(qp, wqe); 3008c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->s_lock, tflags); 3018c2ecf20Sopenharmony_ci *flags = tflags; 3028c2ecf20Sopenharmony_ci rvt_send_complete(qp, wqe, IB_WC_SUCCESS); 3038c2ecf20Sopenharmony_ci goto done; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci qp->s_cur = next_cur; 3088c2ecf20Sopenharmony_ci extra_bytes = -wqe->length & 3; 3098c2ecf20Sopenharmony_ci nwords = (wqe->length + extra_bytes) >> 2; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ 3128c2ecf20Sopenharmony_ci qp->s_hdrwords = 7; 3138c2ecf20Sopenharmony_ci qp->s_cur_size = wqe->length; 3148c2ecf20Sopenharmony_ci qp->s_cur_sge = &qp->s_sge; 3158c2ecf20Sopenharmony_ci qp->s_srate = rdma_ah_get_static_rate(ah_attr); 3168c2ecf20Sopenharmony_ci qp->s_wqe = wqe; 3178c2ecf20Sopenharmony_ci qp->s_sge.sge = wqe->sg_list[0]; 3188c2ecf20Sopenharmony_ci qp->s_sge.sg_list = wqe->sg_list + 1; 3198c2ecf20Sopenharmony_ci qp->s_sge.num_sge = wqe->wr.num_sge; 3208c2ecf20Sopenharmony_ci qp->s_sge.total_len = wqe->length; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) { 3238c2ecf20Sopenharmony_ci /* Header size in 32-bit words. */ 3248c2ecf20Sopenharmony_ci qp->s_hdrwords += qib_make_grh(ibp, &priv->s_hdr->u.l.grh, 3258c2ecf20Sopenharmony_ci rdma_ah_read_grh(ah_attr), 3268c2ecf20Sopenharmony_ci qp->s_hdrwords, nwords); 3278c2ecf20Sopenharmony_ci lrh0 = QIB_LRH_GRH; 3288c2ecf20Sopenharmony_ci ohdr = &priv->s_hdr->u.l.oth; 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * Don't worry about sending to locally attached multicast 3318c2ecf20Sopenharmony_ci * QPs. It is unspecified by the spec. what happens. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci /* Header size in 32-bit words. */ 3358c2ecf20Sopenharmony_ci lrh0 = QIB_LRH_BTH; 3368c2ecf20Sopenharmony_ci ohdr = &priv->s_hdr->u.oth; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) { 3398c2ecf20Sopenharmony_ci qp->s_hdrwords++; 3408c2ecf20Sopenharmony_ci ohdr->u.ud.imm_data = wqe->wr.ex.imm_data; 3418c2ecf20Sopenharmony_ci bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24; 3428c2ecf20Sopenharmony_ci } else 3438c2ecf20Sopenharmony_ci bth0 = IB_OPCODE_UD_SEND_ONLY << 24; 3448c2ecf20Sopenharmony_ci lrh0 |= rdma_ah_get_sl(ah_attr) << 4; 3458c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_SMI) 3468c2ecf20Sopenharmony_ci lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */ 3478c2ecf20Sopenharmony_ci else 3488c2ecf20Sopenharmony_ci lrh0 |= ibp->sl_to_vl[rdma_ah_get_sl(ah_attr)] << 12; 3498c2ecf20Sopenharmony_ci priv->s_hdr->lrh[0] = cpu_to_be16(lrh0); 3508c2ecf20Sopenharmony_ci priv->s_hdr->lrh[1] = 3518c2ecf20Sopenharmony_ci cpu_to_be16(rdma_ah_get_dlid(ah_attr)); /* DEST LID */ 3528c2ecf20Sopenharmony_ci priv->s_hdr->lrh[2] = 3538c2ecf20Sopenharmony_ci cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC); 3548c2ecf20Sopenharmony_ci lid = ppd->lid; 3558c2ecf20Sopenharmony_ci if (lid) { 3568c2ecf20Sopenharmony_ci lid |= rdma_ah_get_path_bits(ah_attr) & 3578c2ecf20Sopenharmony_ci ((1 << ppd->lmc) - 1); 3588c2ecf20Sopenharmony_ci priv->s_hdr->lrh[3] = cpu_to_be16(lid); 3598c2ecf20Sopenharmony_ci } else 3608c2ecf20Sopenharmony_ci priv->s_hdr->lrh[3] = IB_LID_PERMISSIVE; 3618c2ecf20Sopenharmony_ci if (wqe->wr.send_flags & IB_SEND_SOLICITED) 3628c2ecf20Sopenharmony_ci bth0 |= IB_BTH_SOLICITED; 3638c2ecf20Sopenharmony_ci bth0 |= extra_bytes << 20; 3648c2ecf20Sopenharmony_ci bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? QIB_DEFAULT_P_KEY : 3658c2ecf20Sopenharmony_ci qib_get_pkey(ibp, qp->ibqp.qp_type == IB_QPT_GSI ? 3668c2ecf20Sopenharmony_ci rvt_get_swqe_pkey_index(wqe) : qp->s_pkey_index); 3678c2ecf20Sopenharmony_ci ohdr->bth[0] = cpu_to_be32(bth0); 3688c2ecf20Sopenharmony_ci /* 3698c2ecf20Sopenharmony_ci * Use the multicast QP if the destination LID is a multicast LID. 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci ohdr->bth[1] = rdma_ah_get_dlid(ah_attr) >= 3728c2ecf20Sopenharmony_ci be16_to_cpu(IB_MULTICAST_LID_BASE) && 3738c2ecf20Sopenharmony_ci rdma_ah_get_dlid(ah_attr) != be16_to_cpu(IB_LID_PERMISSIVE) ? 3748c2ecf20Sopenharmony_ci cpu_to_be32(QIB_MULTICAST_QPN) : 3758c2ecf20Sopenharmony_ci cpu_to_be32(rvt_get_swqe_remote_qpn(wqe)); 3768c2ecf20Sopenharmony_ci ohdr->bth[2] = cpu_to_be32(wqe->psn & QIB_PSN_MASK); 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * Qkeys with the high order bit set mean use the 3798c2ecf20Sopenharmony_ci * qkey from the QP context instead of the WR (see 10.2.5). 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_ci ohdr->u.ud.deth[0] = 3828c2ecf20Sopenharmony_ci cpu_to_be32((int)rvt_get_swqe_remote_qkey(wqe) < 0 ? qp->qkey : 3838c2ecf20Sopenharmony_ci rvt_get_swqe_remote_qkey(wqe)); 3848c2ecf20Sopenharmony_ci ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cidone: 3878c2ecf20Sopenharmony_ci return 1; 3888c2ecf20Sopenharmony_cibail: 3898c2ecf20Sopenharmony_ci qp->s_flags &= ~RVT_S_BUSY; 3908c2ecf20Sopenharmony_ci return ret; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic unsigned qib_lookup_pkey(struct qib_ibport *ibp, u16 pkey) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct qib_pportdata *ppd = ppd_from_ibp(ibp); 3968c2ecf20Sopenharmony_ci struct qib_devdata *dd = ppd->dd; 3978c2ecf20Sopenharmony_ci unsigned ctxt = ppd->hw_pidx; 3988c2ecf20Sopenharmony_ci unsigned i; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci pkey &= 0x7fff; /* remove limited/full membership bit */ 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dd->rcd[ctxt]->pkeys); ++i) 4038c2ecf20Sopenharmony_ci if ((dd->rcd[ctxt]->pkeys[i] & 0x7fff) == pkey) 4048c2ecf20Sopenharmony_ci return i; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* 4078c2ecf20Sopenharmony_ci * Should not get here, this means hardware failed to validate pkeys. 4088c2ecf20Sopenharmony_ci * Punt and return index 0. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/** 4148c2ecf20Sopenharmony_ci * qib_ud_rcv - receive an incoming UD packet 4158c2ecf20Sopenharmony_ci * @ibp: the port the packet came in on 4168c2ecf20Sopenharmony_ci * @hdr: the packet header 4178c2ecf20Sopenharmony_ci * @has_grh: true if the packet has a GRH 4188c2ecf20Sopenharmony_ci * @data: the packet data 4198c2ecf20Sopenharmony_ci * @tlen: the packet length 4208c2ecf20Sopenharmony_ci * @qp: the QP the packet came on 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * This is called from qib_qp_rcv() to process an incoming UD packet 4238c2ecf20Sopenharmony_ci * for the given QP. 4248c2ecf20Sopenharmony_ci * Called at interrupt level. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_civoid qib_ud_rcv(struct qib_ibport *ibp, struct ib_header *hdr, 4278c2ecf20Sopenharmony_ci int has_grh, void *data, u32 tlen, struct rvt_qp *qp) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct ib_other_headers *ohdr; 4308c2ecf20Sopenharmony_ci int opcode; 4318c2ecf20Sopenharmony_ci u32 hdrsize; 4328c2ecf20Sopenharmony_ci u32 pad; 4338c2ecf20Sopenharmony_ci struct ib_wc wc; 4348c2ecf20Sopenharmony_ci u32 qkey; 4358c2ecf20Sopenharmony_ci u32 src_qp; 4368c2ecf20Sopenharmony_ci u16 dlid; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Check for GRH */ 4398c2ecf20Sopenharmony_ci if (!has_grh) { 4408c2ecf20Sopenharmony_ci ohdr = &hdr->u.oth; 4418c2ecf20Sopenharmony_ci hdrsize = 8 + 12 + 8; /* LRH + BTH + DETH */ 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci ohdr = &hdr->u.l.oth; 4448c2ecf20Sopenharmony_ci hdrsize = 8 + 40 + 12 + 8; /* LRH + GRH + BTH + DETH */ 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci qkey = be32_to_cpu(ohdr->u.ud.deth[0]); 4478c2ecf20Sopenharmony_ci src_qp = be32_to_cpu(ohdr->u.ud.deth[1]) & RVT_QPN_MASK; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * Get the number of bytes the message was padded by 4518c2ecf20Sopenharmony_ci * and drop incomplete packets. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; 4548c2ecf20Sopenharmony_ci if (unlikely(tlen < (hdrsize + pad + 4))) 4558c2ecf20Sopenharmony_ci goto drop; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci tlen -= hdrsize + pad + 4; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* 4608c2ecf20Sopenharmony_ci * Check that the permissive LID is only used on QP0 4618c2ecf20Sopenharmony_ci * and the QKEY matches (see 9.6.1.4.1 and 9.6.1.5.1). 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num) { 4648c2ecf20Sopenharmony_ci if (unlikely(hdr->lrh[1] == IB_LID_PERMISSIVE || 4658c2ecf20Sopenharmony_ci hdr->lrh[3] == IB_LID_PERMISSIVE)) 4668c2ecf20Sopenharmony_ci goto drop; 4678c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num > 1) { 4688c2ecf20Sopenharmony_ci u16 pkey1, pkey2; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci pkey1 = be32_to_cpu(ohdr->bth[0]); 4718c2ecf20Sopenharmony_ci pkey2 = qib_get_pkey(ibp, qp->s_pkey_index); 4728c2ecf20Sopenharmony_ci if (unlikely(!qib_pkey_ok(pkey1, pkey2))) { 4738c2ecf20Sopenharmony_ci qib_bad_pkey(ibp, 4748c2ecf20Sopenharmony_ci pkey1, 4758c2ecf20Sopenharmony_ci (be16_to_cpu(hdr->lrh[0]) >> 4) & 4768c2ecf20Sopenharmony_ci 0xF, 4778c2ecf20Sopenharmony_ci src_qp, qp->ibqp.qp_num, 4788c2ecf20Sopenharmony_ci hdr->lrh[3], hdr->lrh[1]); 4798c2ecf20Sopenharmony_ci return; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci if (unlikely(qkey != qp->qkey)) 4838c2ecf20Sopenharmony_ci return; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Drop invalid MAD packets (see 13.5.3.1). */ 4868c2ecf20Sopenharmony_ci if (unlikely(qp->ibqp.qp_num == 1 && 4878c2ecf20Sopenharmony_ci (tlen != 256 || 4888c2ecf20Sopenharmony_ci (be16_to_cpu(hdr->lrh[0]) >> 12) == 15))) 4898c2ecf20Sopenharmony_ci goto drop; 4908c2ecf20Sopenharmony_ci } else { 4918c2ecf20Sopenharmony_ci struct ib_smp *smp; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* Drop invalid MAD packets (see 13.5.3.1). */ 4948c2ecf20Sopenharmony_ci if (tlen != 256 || (be16_to_cpu(hdr->lrh[0]) >> 12) != 15) 4958c2ecf20Sopenharmony_ci goto drop; 4968c2ecf20Sopenharmony_ci smp = (struct ib_smp *) data; 4978c2ecf20Sopenharmony_ci if ((hdr->lrh[1] == IB_LID_PERMISSIVE || 4988c2ecf20Sopenharmony_ci hdr->lrh[3] == IB_LID_PERMISSIVE) && 4998c2ecf20Sopenharmony_ci smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 5008c2ecf20Sopenharmony_ci goto drop; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* 5048c2ecf20Sopenharmony_ci * The opcode is in the low byte when its in network order 5058c2ecf20Sopenharmony_ci * (top byte when in host order). 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci opcode = be32_to_cpu(ohdr->bth[0]) >> 24; 5088c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num > 1 && 5098c2ecf20Sopenharmony_ci opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) { 5108c2ecf20Sopenharmony_ci wc.ex.imm_data = ohdr->u.ud.imm_data; 5118c2ecf20Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 5128c2ecf20Sopenharmony_ci } else if (opcode == IB_OPCODE_UD_SEND_ONLY) { 5138c2ecf20Sopenharmony_ci wc.ex.imm_data = 0; 5148c2ecf20Sopenharmony_ci wc.wc_flags = 0; 5158c2ecf20Sopenharmony_ci } else 5168c2ecf20Sopenharmony_ci goto drop; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* 5198c2ecf20Sopenharmony_ci * A GRH is expected to precede the data even if not 5208c2ecf20Sopenharmony_ci * present on the wire. 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_ci wc.byte_len = tlen + sizeof(struct ib_grh); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* 5258c2ecf20Sopenharmony_ci * Get the next work request entry to find where to put the data. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci if (qp->r_flags & RVT_R_REUSE_SGE) 5288c2ecf20Sopenharmony_ci qp->r_flags &= ~RVT_R_REUSE_SGE; 5298c2ecf20Sopenharmony_ci else { 5308c2ecf20Sopenharmony_ci int ret; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci ret = rvt_get_rwqe(qp, false); 5338c2ecf20Sopenharmony_ci if (ret < 0) { 5348c2ecf20Sopenharmony_ci rvt_rc_error(qp, IB_WC_LOC_QP_OP_ERR); 5358c2ecf20Sopenharmony_ci return; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci if (!ret) { 5388c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num == 0) 5398c2ecf20Sopenharmony_ci ibp->rvp.n_vl15_dropped++; 5408c2ecf20Sopenharmony_ci return; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci /* Silently drop packets which are too big. */ 5448c2ecf20Sopenharmony_ci if (unlikely(wc.byte_len > qp->r_len)) { 5458c2ecf20Sopenharmony_ci qp->r_flags |= RVT_R_REUSE_SGE; 5468c2ecf20Sopenharmony_ci goto drop; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci if (has_grh) { 5498c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, &hdr->u.l.grh, 5508c2ecf20Sopenharmony_ci sizeof(struct ib_grh), true, false); 5518c2ecf20Sopenharmony_ci wc.wc_flags |= IB_WC_GRH; 5528c2ecf20Sopenharmony_ci } else 5538c2ecf20Sopenharmony_ci rvt_skip_sge(&qp->r_sge, sizeof(struct ib_grh), true); 5548c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), 5558c2ecf20Sopenharmony_ci true, false); 5568c2ecf20Sopenharmony_ci rvt_put_ss(&qp->r_sge); 5578c2ecf20Sopenharmony_ci if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) 5588c2ecf20Sopenharmony_ci return; 5598c2ecf20Sopenharmony_ci wc.wr_id = qp->r_wr_id; 5608c2ecf20Sopenharmony_ci wc.status = IB_WC_SUCCESS; 5618c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV; 5628c2ecf20Sopenharmony_ci wc.vendor_err = 0; 5638c2ecf20Sopenharmony_ci wc.qp = &qp->ibqp; 5648c2ecf20Sopenharmony_ci wc.src_qp = src_qp; 5658c2ecf20Sopenharmony_ci wc.pkey_index = qp->ibqp.qp_type == IB_QPT_GSI ? 5668c2ecf20Sopenharmony_ci qib_lookup_pkey(ibp, be32_to_cpu(ohdr->bth[0])) : 0; 5678c2ecf20Sopenharmony_ci wc.slid = be16_to_cpu(hdr->lrh[3]); 5688c2ecf20Sopenharmony_ci wc.sl = (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF; 5698c2ecf20Sopenharmony_ci dlid = be16_to_cpu(hdr->lrh[1]); 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * Save the LMC lower bits if the destination LID is a unicast LID. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci wc.dlid_path_bits = dlid >= be16_to_cpu(IB_MULTICAST_LID_BASE) ? 0 : 5748c2ecf20Sopenharmony_ci dlid & ((1 << ppd_from_ibp(ibp)->lmc) - 1); 5758c2ecf20Sopenharmony_ci wc.port_num = qp->port_num; 5768c2ecf20Sopenharmony_ci /* Signal completion event if the solicited bit is set. */ 5778c2ecf20Sopenharmony_ci rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr)); 5788c2ecf20Sopenharmony_ci return; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cidrop: 5818c2ecf20Sopenharmony_ci ibp->rvp.n_pkt_drops++; 5828c2ecf20Sopenharmony_ci} 583