162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "rxe.h" 862306a36Sopenharmony_ci#include "rxe_loc.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_civoid rxe_init_av(struct rdma_ah_attr *attr, struct rxe_av *av) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci rxe_av_from_attr(rdma_ah_get_port_num(attr), av, attr); 1362306a36Sopenharmony_ci rxe_av_fill_ip_info(av, attr); 1462306a36Sopenharmony_ci memcpy(av->dmac, attr->roce.dmac, ETH_ALEN); 1562306a36Sopenharmony_ci} 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic int chk_attr(void *obj, struct rdma_ah_attr *attr, bool obj_is_ah) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci const struct ib_global_route *grh = rdma_ah_read_grh(attr); 2062306a36Sopenharmony_ci struct rxe_port *port; 2162306a36Sopenharmony_ci struct rxe_dev *rxe; 2262306a36Sopenharmony_ci struct rxe_qp *qp; 2362306a36Sopenharmony_ci struct rxe_ah *ah; 2462306a36Sopenharmony_ci int type; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (obj_is_ah) { 2762306a36Sopenharmony_ci ah = obj; 2862306a36Sopenharmony_ci rxe = to_rdev(ah->ibah.device); 2962306a36Sopenharmony_ci } else { 3062306a36Sopenharmony_ci qp = obj; 3162306a36Sopenharmony_ci rxe = to_rdev(qp->ibqp.device); 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci port = &rxe->port; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (rdma_ah_get_ah_flags(attr) & IB_AH_GRH) { 3762306a36Sopenharmony_ci if (grh->sgid_index > port->attr.gid_tbl_len) { 3862306a36Sopenharmony_ci if (obj_is_ah) 3962306a36Sopenharmony_ci rxe_dbg_ah(ah, "invalid sgid index = %d\n", 4062306a36Sopenharmony_ci grh->sgid_index); 4162306a36Sopenharmony_ci else 4262306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid sgid index = %d\n", 4362306a36Sopenharmony_ci grh->sgid_index); 4462306a36Sopenharmony_ci return -EINVAL; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci type = rdma_gid_attr_network_type(grh->sgid_attr); 4862306a36Sopenharmony_ci if (type < RDMA_NETWORK_IPV4 || 4962306a36Sopenharmony_ci type > RDMA_NETWORK_IPV6) { 5062306a36Sopenharmony_ci if (obj_is_ah) 5162306a36Sopenharmony_ci rxe_dbg_ah(ah, "invalid network type for rdma_rxe = %d\n", 5262306a36Sopenharmony_ci type); 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci rxe_dbg_qp(qp, "invalid network type for rdma_rxe = %d\n", 5562306a36Sopenharmony_ci type); 5662306a36Sopenharmony_ci return -EINVAL; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciint rxe_av_chk_attr(struct rxe_qp *qp, struct rdma_ah_attr *attr) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci return chk_attr(qp, attr, false); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciint rxe_ah_chk_attr(struct rxe_ah *ah, struct rdma_ah_attr *attr) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci return chk_attr(ah, attr, true); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_civoid rxe_av_from_attr(u8 port_num, struct rxe_av *av, 7462306a36Sopenharmony_ci struct rdma_ah_attr *attr) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci const struct ib_global_route *grh = rdma_ah_read_grh(attr); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci memset(av, 0, sizeof(*av)); 7962306a36Sopenharmony_ci memcpy(av->grh.dgid.raw, grh->dgid.raw, sizeof(grh->dgid.raw)); 8062306a36Sopenharmony_ci av->grh.flow_label = grh->flow_label; 8162306a36Sopenharmony_ci av->grh.sgid_index = grh->sgid_index; 8262306a36Sopenharmony_ci av->grh.hop_limit = grh->hop_limit; 8362306a36Sopenharmony_ci av->grh.traffic_class = grh->traffic_class; 8462306a36Sopenharmony_ci av->port_num = port_num; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_civoid rxe_av_to_attr(struct rxe_av *av, struct rdma_ah_attr *attr) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct ib_global_route *grh = rdma_ah_retrieve_grh(attr); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci attr->type = RDMA_AH_ATTR_TYPE_ROCE; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci memcpy(grh->dgid.raw, av->grh.dgid.raw, sizeof(av->grh.dgid.raw)); 9462306a36Sopenharmony_ci grh->flow_label = av->grh.flow_label; 9562306a36Sopenharmony_ci grh->sgid_index = av->grh.sgid_index; 9662306a36Sopenharmony_ci grh->hop_limit = av->grh.hop_limit; 9762306a36Sopenharmony_ci grh->traffic_class = av->grh.traffic_class; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci rdma_ah_set_ah_flags(attr, IB_AH_GRH); 10062306a36Sopenharmony_ci rdma_ah_set_port_num(attr, av->port_num); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_civoid rxe_av_fill_ip_info(struct rxe_av *av, struct rdma_ah_attr *attr) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr = attr->grh.sgid_attr; 10662306a36Sopenharmony_ci int ibtype; 10762306a36Sopenharmony_ci int type; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci rdma_gid2ip((struct sockaddr *)&av->sgid_addr, &sgid_attr->gid); 11062306a36Sopenharmony_ci rdma_gid2ip((struct sockaddr *)&av->dgid_addr, 11162306a36Sopenharmony_ci &rdma_ah_read_grh(attr)->dgid); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ibtype = rdma_gid_attr_network_type(sgid_attr); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci switch (ibtype) { 11662306a36Sopenharmony_ci case RDMA_NETWORK_IPV4: 11762306a36Sopenharmony_ci type = RXE_NETWORK_TYPE_IPV4; 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case RDMA_NETWORK_IPV6: 12062306a36Sopenharmony_ci type = RXE_NETWORK_TYPE_IPV6; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci default: 12362306a36Sopenharmony_ci /* not reached - checked in rxe_av_chk_attr */ 12462306a36Sopenharmony_ci type = 0; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci av->network_type = type; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt, struct rxe_ah **ahp) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct rxe_ah *ah; 13462306a36Sopenharmony_ci u32 ah_num; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (ahp) 13762306a36Sopenharmony_ci *ahp = NULL; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!pkt || !pkt->qp) 14062306a36Sopenharmony_ci return NULL; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (qp_type(pkt->qp) == IB_QPT_RC || qp_type(pkt->qp) == IB_QPT_UC) 14362306a36Sopenharmony_ci return &pkt->qp->pri_av; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!pkt->wqe) 14662306a36Sopenharmony_ci return NULL; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ah_num = pkt->wqe->wr.wr.ud.ah_num; 14962306a36Sopenharmony_ci if (ah_num) { 15062306a36Sopenharmony_ci /* only new user provider or kernel client */ 15162306a36Sopenharmony_ci ah = rxe_pool_get_index(&pkt->rxe->ah_pool, ah_num); 15262306a36Sopenharmony_ci if (!ah) { 15362306a36Sopenharmony_ci rxe_dbg_qp(pkt->qp, "Unable to find AH matching ah_num\n"); 15462306a36Sopenharmony_ci return NULL; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (rxe_ah_pd(ah) != pkt->qp->pd) { 15862306a36Sopenharmony_ci rxe_dbg_qp(pkt->qp, "PDs don't match for AH and QP\n"); 15962306a36Sopenharmony_ci rxe_put(ah); 16062306a36Sopenharmony_ci return NULL; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (ahp) 16462306a36Sopenharmony_ci *ahp = ah; 16562306a36Sopenharmony_ci else 16662306a36Sopenharmony_ci rxe_put(ah); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return &ah->av; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* only old user provider for UD sends*/ 17262306a36Sopenharmony_ci return &pkt->wqe->wr.wr.ud.av; 17362306a36Sopenharmony_ci} 174