1/* 2 * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include "mlx4_ib.h" 34#include <rdma/ib_addr.h> 35#include <linux/inet.h> 36#include <linux/string.h> 37#include <rdma/ib_cache.h> 38 39int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, 40 u8 *mac, int *is_mcast, u8 port) 41{ 42 struct mlx4_ib_iboe *iboe = &dev->iboe; 43 struct in6_addr in6; 44 45 *is_mcast = 0; 46 spin_lock(&iboe->lock); 47 if (!iboe->netdevs[port - 1]) { 48 spin_unlock(&iboe->lock); 49 return -EINVAL; 50 } 51 spin_unlock(&iboe->lock); 52 53 memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6); 54 if (rdma_link_local_addr(&in6)) 55 rdma_get_ll_mac(&in6, mac); 56 else if (rdma_is_multicast_addr(&in6)) { 57 rdma_get_mcast_mac(&in6, mac); 58 *is_mcast = 1; 59 } else 60 return -EINVAL; 61 62 return 0; 63} 64 65static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, 66 struct mlx4_ib_ah *ah) 67{ 68 struct mlx4_dev *dev = to_mdev(pd->device)->dev; 69 70 ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); 71 ah->av.ib.g_slid = ah_attr->src_path_bits; 72 if (ah_attr->ah_flags & IB_AH_GRH) { 73 ah->av.ib.g_slid |= 0x80; 74 ah->av.ib.gid_index = ah_attr->grh.sgid_index; 75 ah->av.ib.hop_limit = ah_attr->grh.hop_limit; 76 ah->av.ib.sl_tclass_flowlabel |= 77 cpu_to_be32((ah_attr->grh.traffic_class << 20) | 78 ah_attr->grh.flow_label); 79 memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); 80 } 81 82 ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); 83 if (ah_attr->static_rate) { 84 ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; 85 while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && 86 !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) 87 --ah->av.ib.stat_rate; 88 } 89 ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); 90 91 return &ah->ibah; 92} 93 94static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, 95 struct mlx4_ib_ah *ah) 96{ 97 struct mlx4_ib_dev *ibdev = to_mdev(pd->device); 98 struct mlx4_dev *dev = ibdev->dev; 99 u8 mac[6]; 100 int err; 101 int is_mcast; 102 u16 vlan_tag; 103 union ib_gid sgid; 104 105 err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num); 106 if (err) 107 return ERR_PTR(err); 108 109 memcpy(ah->av.eth.mac, mac, 6); 110 err = ib_get_cached_gid(pd->device, ah_attr->port_num, ah_attr->grh.sgid_index, &sgid); 111 if (err) 112 return ERR_PTR(err); 113 vlan_tag = rdma_get_vlan_id(&sgid); 114 if (vlan_tag < 0x1000) 115 vlan_tag |= (ah_attr->sl & 7) << 13; 116 ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); 117 ah->av.eth.gid_index = ah_attr->grh.sgid_index; 118 ah->av.eth.vlan = cpu_to_be16(vlan_tag); 119 if (ah_attr->static_rate) { 120 ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; 121 while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && 122 !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support)) 123 --ah->av.eth.stat_rate; 124 } 125 126 /* 127 * HW requires multicast LID so we just choose one. 128 */ 129 if (is_mcast) 130 ah->av.ib.dlid = cpu_to_be16(0xc000); 131 132 memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); 133 ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); 134 135 return &ah->ibah; 136} 137 138struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) 139{ 140 struct mlx4_ib_ah *ah; 141 struct ib_ah *ret; 142 143 ah = kzalloc(sizeof *ah, GFP_ATOMIC); 144 if (!ah) 145 return ERR_PTR(-ENOMEM); 146 147 if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) { 148 if (!(ah_attr->ah_flags & IB_AH_GRH)) { 149 ret = ERR_PTR(-EINVAL); 150 goto out; 151 } else { 152 /* TBD: need to handle the case when we get called 153 in an atomic context and there we might sleep. We 154 don't expect this currently since we're working with 155 link local addresses which we can translate without 156 going to sleep */ 157 ret = create_iboe_ah(pd, ah_attr, ah); 158 if (IS_ERR(ret)) 159 goto out; 160 else 161 return ret; 162 } 163 } else 164 return create_ib_ah(pd, ah_attr, ah); /* never fails */ 165 166out: 167 kfree(ah); 168 return ret; 169} 170 171int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) 172{ 173 struct mlx4_ib_ah *ah = to_mah(ibah); 174 enum rdma_link_layer ll; 175 176 memset(ah_attr, 0, sizeof *ah_attr); 177 ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; 178 ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24; 179 ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num); 180 ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0; 181 if (ah->av.ib.stat_rate) 182 ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; 183 ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F; 184 185 if (mlx4_ib_ah_grh_present(ah)) { 186 ah_attr->ah_flags = IB_AH_GRH; 187 188 ah_attr->grh.traffic_class = 189 be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20; 190 ah_attr->grh.flow_label = 191 be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff; 192 ah_attr->grh.hop_limit = ah->av.ib.hop_limit; 193 ah_attr->grh.sgid_index = ah->av.ib.gid_index; 194 memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); 195 } 196 197 return 0; 198} 199 200int mlx4_ib_destroy_ah(struct ib_ah *ah) 201{ 202 kfree(to_mah(ah)); 203 return 0; 204} 205 206