1219820Sjeff/* 2219820Sjeff * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff */ 32219820Sjeff 33219820Sjeff#include "mlx4_ib.h" 34219820Sjeff#include <rdma/ib_addr.h> 35219820Sjeff#include <linux/inet.h> 36219820Sjeff#include <linux/string.h> 37219820Sjeff#include <rdma/ib_cache.h> 38219820Sjeff 39219820Sjeffint mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, 40219820Sjeff u8 *mac, int *is_mcast, u8 port) 41219820Sjeff{ 42219820Sjeff struct mlx4_ib_iboe *iboe = &dev->iboe; 43219820Sjeff struct in6_addr in6; 44219820Sjeff 45219820Sjeff *is_mcast = 0; 46219820Sjeff spin_lock(&iboe->lock); 47219820Sjeff if (!iboe->netdevs[port - 1]) { 48219820Sjeff spin_unlock(&iboe->lock); 49219820Sjeff return -EINVAL; 50219820Sjeff } 51219820Sjeff spin_unlock(&iboe->lock); 52219820Sjeff 53219820Sjeff memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6); 54219820Sjeff if (rdma_link_local_addr(&in6)) 55219820Sjeff rdma_get_ll_mac(&in6, mac); 56219820Sjeff else if (rdma_is_multicast_addr(&in6)) { 57219820Sjeff rdma_get_mcast_mac(&in6, mac); 58219820Sjeff *is_mcast = 1; 59219820Sjeff } else 60219820Sjeff return -EINVAL; 61219820Sjeff 62219820Sjeff return 0; 63219820Sjeff} 64219820Sjeff 65219820Sjeffstatic struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, 66219820Sjeff struct mlx4_ib_ah *ah) 67219820Sjeff{ 68219820Sjeff struct mlx4_dev *dev = to_mdev(pd->device)->dev; 69219820Sjeff 70219820Sjeff ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); 71219820Sjeff ah->av.ib.g_slid = ah_attr->src_path_bits; 72219820Sjeff if (ah_attr->ah_flags & IB_AH_GRH) { 73219820Sjeff ah->av.ib.g_slid |= 0x80; 74219820Sjeff ah->av.ib.gid_index = ah_attr->grh.sgid_index; 75219820Sjeff ah->av.ib.hop_limit = ah_attr->grh.hop_limit; 76219820Sjeff ah->av.ib.sl_tclass_flowlabel |= 77219820Sjeff cpu_to_be32((ah_attr->grh.traffic_class << 20) | 78219820Sjeff ah_attr->grh.flow_label); 79219820Sjeff memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); 80219820Sjeff } 81219820Sjeff 82219820Sjeff ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); 83219820Sjeff if (ah_attr->static_rate) { 84219820Sjeff ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; 85219820Sjeff while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && 86219820Sjeff !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) 87219820Sjeff --ah->av.ib.stat_rate; 88219820Sjeff } 89219820Sjeff ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); 90219820Sjeff 91219820Sjeff return &ah->ibah; 92219820Sjeff} 93219820Sjeff 94219820Sjeffstatic struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, 95219820Sjeff struct mlx4_ib_ah *ah) 96219820Sjeff{ 97219820Sjeff struct mlx4_ib_dev *ibdev = to_mdev(pd->device); 98219820Sjeff struct mlx4_dev *dev = ibdev->dev; 99219820Sjeff u8 mac[6]; 100219820Sjeff int err; 101219820Sjeff int is_mcast; 102219820Sjeff u16 vlan_tag; 103219820Sjeff union ib_gid sgid; 104219820Sjeff 105219820Sjeff err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num); 106219820Sjeff if (err) 107219820Sjeff return ERR_PTR(err); 108219820Sjeff 109219820Sjeff memcpy(ah->av.eth.mac, mac, 6); 110219820Sjeff err = ib_get_cached_gid(pd->device, ah_attr->port_num, ah_attr->grh.sgid_index, &sgid); 111219820Sjeff if (err) 112219820Sjeff return ERR_PTR(err); 113219820Sjeff vlan_tag = rdma_get_vlan_id(&sgid); 114219820Sjeff if (vlan_tag < 0x1000) 115219820Sjeff vlan_tag |= (ah_attr->sl & 7) << 13; 116219820Sjeff ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); 117219820Sjeff ah->av.eth.gid_index = ah_attr->grh.sgid_index; 118219820Sjeff ah->av.eth.vlan = cpu_to_be16(vlan_tag); 119219820Sjeff if (ah_attr->static_rate) { 120219820Sjeff ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; 121219820Sjeff while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && 122219820Sjeff !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support)) 123219820Sjeff --ah->av.eth.stat_rate; 124219820Sjeff } 125219820Sjeff 126219820Sjeff /* 127219820Sjeff * HW requires multicast LID so we just choose one. 128219820Sjeff */ 129219820Sjeff if (is_mcast) 130219820Sjeff ah->av.ib.dlid = cpu_to_be16(0xc000); 131219820Sjeff 132219820Sjeff memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); 133219820Sjeff ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); 134219820Sjeff 135219820Sjeff return &ah->ibah; 136219820Sjeff} 137219820Sjeff 138219820Sjeffstruct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) 139219820Sjeff{ 140219820Sjeff struct mlx4_ib_ah *ah; 141219820Sjeff struct ib_ah *ret; 142219820Sjeff 143219820Sjeff ah = kzalloc(sizeof *ah, GFP_ATOMIC); 144219820Sjeff if (!ah) 145219820Sjeff return ERR_PTR(-ENOMEM); 146219820Sjeff 147219820Sjeff if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) { 148219820Sjeff if (!(ah_attr->ah_flags & IB_AH_GRH)) { 149219820Sjeff ret = ERR_PTR(-EINVAL); 150219820Sjeff goto out; 151219820Sjeff } else { 152219820Sjeff /* TBD: need to handle the case when we get called 153219820Sjeff in an atomic context and there we might sleep. We 154219820Sjeff don't expect this currently since we're working with 155219820Sjeff link local addresses which we can translate without 156219820Sjeff going to sleep */ 157219820Sjeff ret = create_iboe_ah(pd, ah_attr, ah); 158219820Sjeff if (IS_ERR(ret)) 159219820Sjeff goto out; 160219820Sjeff else 161219820Sjeff return ret; 162219820Sjeff } 163219820Sjeff } else 164219820Sjeff return create_ib_ah(pd, ah_attr, ah); /* never fails */ 165219820Sjeff 166219820Sjeffout: 167219820Sjeff kfree(ah); 168219820Sjeff return ret; 169219820Sjeff} 170219820Sjeff 171219820Sjeffint mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) 172219820Sjeff{ 173219820Sjeff struct mlx4_ib_ah *ah = to_mah(ibah); 174219820Sjeff enum rdma_link_layer ll; 175219820Sjeff 176219820Sjeff memset(ah_attr, 0, sizeof *ah_attr); 177219820Sjeff ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; 178219820Sjeff ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24; 179219820Sjeff ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num); 180219820Sjeff ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0; 181219820Sjeff if (ah->av.ib.stat_rate) 182219820Sjeff ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; 183219820Sjeff ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F; 184219820Sjeff 185219820Sjeff if (mlx4_ib_ah_grh_present(ah)) { 186219820Sjeff ah_attr->ah_flags = IB_AH_GRH; 187219820Sjeff 188219820Sjeff ah_attr->grh.traffic_class = 189219820Sjeff be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20; 190219820Sjeff ah_attr->grh.flow_label = 191219820Sjeff be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff; 192219820Sjeff ah_attr->grh.hop_limit = ah->av.ib.hop_limit; 193219820Sjeff ah_attr->grh.sgid_index = ah->av.ib.gid_index; 194219820Sjeff memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); 195219820Sjeff } 196219820Sjeff 197219820Sjeff return 0; 198219820Sjeff} 199219820Sjeff 200219820Sjeffint mlx4_ib_destroy_ah(struct ib_ah *ah) 201219820Sjeff{ 202219820Sjeff kfree(to_mah(ah)); 203219820Sjeff return 0; 204219820Sjeff} 205219820Sjeff 206