0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <rdma/ib_addr.h>
0034 #include <rdma/ib_cache.h>
0035
0036 #include <linux/slab.h>
0037 #include <linux/inet.h>
0038 #include <linux/string.h>
0039 #include <linux/mlx4/driver.h>
0040
0041 #include "mlx4_ib.h"
0042
0043 static void create_ib_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr)
0044 {
0045 struct mlx4_ib_ah *ah = to_mah(ib_ah);
0046 struct mlx4_dev *dev = to_mdev(ib_ah->device)->dev;
0047
0048 ah->av.ib.port_pd = cpu_to_be32(to_mpd(ib_ah->pd)->pdn |
0049 (rdma_ah_get_port_num(ah_attr) << 24));
0050 ah->av.ib.g_slid = rdma_ah_get_path_bits(ah_attr);
0051 ah->av.ib.sl_tclass_flowlabel =
0052 cpu_to_be32(rdma_ah_get_sl(ah_attr) << 28);
0053 if (rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH) {
0054 const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
0055
0056 ah->av.ib.g_slid |= 0x80;
0057 ah->av.ib.gid_index = grh->sgid_index;
0058 ah->av.ib.hop_limit = grh->hop_limit;
0059 ah->av.ib.sl_tclass_flowlabel |=
0060 cpu_to_be32((grh->traffic_class << 20) |
0061 grh->flow_label);
0062 memcpy(ah->av.ib.dgid, grh->dgid.raw, 16);
0063 }
0064
0065 ah->av.ib.dlid = cpu_to_be16(rdma_ah_get_dlid(ah_attr));
0066 if (rdma_ah_get_static_rate(ah_attr)) {
0067 u8 static_rate = rdma_ah_get_static_rate(ah_attr) +
0068 MLX4_STAT_RATE_OFFSET;
0069
0070 while (static_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
0071 !(1 << static_rate & dev->caps.stat_rate_support))
0072 --static_rate;
0073 ah->av.ib.stat_rate = static_rate;
0074 }
0075 }
0076
0077 static int create_iboe_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr)
0078 {
0079 struct mlx4_ib_dev *ibdev = to_mdev(ib_ah->device);
0080 struct mlx4_ib_ah *ah = to_mah(ib_ah);
0081 const struct ib_gid_attr *gid_attr;
0082 struct mlx4_dev *dev = ibdev->dev;
0083 int is_mcast = 0;
0084 struct in6_addr in6;
0085 u16 vlan_tag = 0xffff;
0086 const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
0087 int ret;
0088
0089 memcpy(&in6, grh->dgid.raw, sizeof(in6));
0090 if (rdma_is_multicast_addr(&in6))
0091 is_mcast = 1;
0092
0093 memcpy(ah->av.eth.mac, ah_attr->roce.dmac, ETH_ALEN);
0094 eth_zero_addr(ah->av.eth.s_mac);
0095
0096
0097
0098
0099
0100 gid_attr = ah_attr->grh.sgid_attr;
0101 if (gid_attr) {
0102 ret = rdma_read_gid_l2_fields(gid_attr, &vlan_tag,
0103 &ah->av.eth.s_mac[0]);
0104 if (ret)
0105 return ret;
0106
0107 ret = mlx4_ib_gid_index_to_real_index(ibdev, gid_attr);
0108 if (ret < 0)
0109 return ret;
0110 ah->av.eth.gid_index = ret;
0111 } else {
0112
0113 ah->av.eth.gid_index = ah_attr->grh.sgid_index;
0114 }
0115
0116 if (vlan_tag < 0x1000)
0117 vlan_tag |= (rdma_ah_get_sl(ah_attr) & 7) << 13;
0118 ah->av.eth.port_pd = cpu_to_be32(to_mpd(ib_ah->pd)->pdn |
0119 (rdma_ah_get_port_num(ah_attr) << 24));
0120 ah->av.eth.vlan = cpu_to_be16(vlan_tag);
0121 ah->av.eth.hop_limit = grh->hop_limit;
0122 if (rdma_ah_get_static_rate(ah_attr)) {
0123 ah->av.eth.stat_rate = rdma_ah_get_static_rate(ah_attr) +
0124 MLX4_STAT_RATE_OFFSET;
0125 while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
0126 !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
0127 --ah->av.eth.stat_rate;
0128 }
0129 ah->av.eth.sl_tclass_flowlabel |=
0130 cpu_to_be32((grh->traffic_class << 20) |
0131 grh->flow_label);
0132
0133
0134
0135 if (is_mcast)
0136 ah->av.ib.dlid = cpu_to_be16(0xc000);
0137
0138 memcpy(ah->av.eth.dgid, grh->dgid.raw, 16);
0139 ah->av.eth.sl_tclass_flowlabel |= cpu_to_be32(rdma_ah_get_sl(ah_attr)
0140 << 29);
0141 return 0;
0142 }
0143
0144 int mlx4_ib_create_ah(struct ib_ah *ib_ah, struct rdma_ah_init_attr *init_attr,
0145 struct ib_udata *udata)
0146 {
0147 struct rdma_ah_attr *ah_attr = init_attr->ah_attr;
0148
0149 if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) {
0150 if (!(rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH))
0151 return -EINVAL;
0152
0153
0154
0155
0156
0157
0158
0159
0160 return create_iboe_ah(ib_ah, ah_attr);
0161 }
0162
0163 create_ib_ah(ib_ah, ah_attr);
0164 return 0;
0165 }
0166
0167 int mlx4_ib_create_ah_slave(struct ib_ah *ah, struct rdma_ah_attr *ah_attr,
0168 int slave_sgid_index, u8 *s_mac, u16 vlan_tag)
0169 {
0170 struct rdma_ah_attr slave_attr = *ah_attr;
0171 struct rdma_ah_init_attr init_attr = {};
0172 struct mlx4_ib_ah *mah = to_mah(ah);
0173 int ret;
0174
0175 slave_attr.grh.sgid_attr = NULL;
0176 slave_attr.grh.sgid_index = slave_sgid_index;
0177 init_attr.ah_attr = &slave_attr;
0178 ret = mlx4_ib_create_ah(ah, &init_attr, NULL);
0179 if (ret)
0180 return ret;
0181
0182 ah->type = ah_attr->type;
0183
0184
0185 mah->av.ib.port_pd &= cpu_to_be32(0x7FFFFFFF);
0186
0187 if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE)
0188 memcpy(mah->av.eth.s_mac, s_mac, 6);
0189
0190 if (vlan_tag < 0x1000)
0191 vlan_tag |= (rdma_ah_get_sl(ah_attr) & 7) << 13;
0192 mah->av.eth.vlan = cpu_to_be16(vlan_tag);
0193
0194 return 0;
0195 }
0196
0197 int mlx4_ib_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *ah_attr)
0198 {
0199 struct mlx4_ib_ah *ah = to_mah(ibah);
0200 int port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24;
0201
0202 memset(ah_attr, 0, sizeof *ah_attr);
0203 ah_attr->type = ibah->type;
0204
0205 if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) {
0206 rdma_ah_set_dlid(ah_attr, 0);
0207 rdma_ah_set_sl(ah_attr,
0208 be32_to_cpu(ah->av.eth.sl_tclass_flowlabel)
0209 >> 29);
0210 } else {
0211 rdma_ah_set_dlid(ah_attr, be16_to_cpu(ah->av.ib.dlid));
0212 rdma_ah_set_sl(ah_attr,
0213 be32_to_cpu(ah->av.ib.sl_tclass_flowlabel)
0214 >> 28);
0215 }
0216
0217 rdma_ah_set_port_num(ah_attr, port_num);
0218 if (ah->av.ib.stat_rate)
0219 rdma_ah_set_static_rate(ah_attr,
0220 ah->av.ib.stat_rate -
0221 MLX4_STAT_RATE_OFFSET);
0222 rdma_ah_set_path_bits(ah_attr, ah->av.ib.g_slid & 0x7F);
0223 if (mlx4_ib_ah_grh_present(ah)) {
0224 u32 tc_fl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel);
0225
0226 rdma_ah_set_grh(ah_attr, NULL,
0227 tc_fl & 0xfffff, ah->av.ib.gid_index,
0228 ah->av.ib.hop_limit,
0229 tc_fl >> 20);
0230 rdma_ah_set_dgid_raw(ah_attr, ah->av.ib.dgid);
0231 }
0232
0233 return 0;
0234 }