1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include "mlx5_ib.h"
34
35static struct ib_ah *create_ib_ah(struct mlx5_ib_dev *dev,
36 struct mlx5_ib_ah *ah,
37 struct ib_ah_attr *ah_attr,
38 enum rdma_link_layer ll)
39{
40 if (ah_attr->ah_flags & IB_AH_GRH) {
41 memcpy(ah->av.rgid, &ah_attr->grh.dgid, 16);
42 ah->av.grh_gid_fl = cpu_to_be32(ah_attr->grh.flow_label |
43 (1 << 30) |
44 ah_attr->grh.sgid_index << 20);
45 ah->av.hop_limit = ah_attr->grh.hop_limit;
46 ah->av.tclass = ah_attr->grh.traffic_class;
47 }
48
49 ah->av.stat_rate_sl = (ah_attr->static_rate << 4);
50
51 if (ll == IB_LINK_LAYER_ETHERNET) {
52 memcpy(ah->av.rmac, ah_attr->dmac, sizeof(ah_attr->dmac));
53 ah->av.udp_sport =
54 mlx5_get_roce_udp_sport(dev,
55 ah_attr->port_num,
56 ah_attr->grh.sgid_index);
57 ah->av.stat_rate_sl |= (ah_attr->sl & 0x7) << 1;
58 } else {
59 ah->av.rlid = cpu_to_be16(ah_attr->dlid);
60 ah->av.fl_mlid = ah_attr->src_path_bits & 0x7f;
61 ah->av.stat_rate_sl |= (ah_attr->sl & 0xf);
62 }
63
64 return &ah->ibah;
65}
66
67struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
68 struct ib_udata *udata)
69
70{
71 struct mlx5_ib_ah *ah;
72 struct mlx5_ib_dev *dev = to_mdev(pd->device);
73 enum rdma_link_layer ll;
74
75 ll = pd->device->get_link_layer(pd->device, ah_attr->port_num);
76
77 if (ll == IB_LINK_LAYER_ETHERNET && !(ah_attr->ah_flags & IB_AH_GRH))
78 return ERR_PTR(-EINVAL);
79
80 if (ll == IB_LINK_LAYER_ETHERNET && udata) {
81 int err;
82 struct mlx5_ib_create_ah_resp resp = {};
83 u32 min_resp_len = offsetof(typeof(resp), dmac) +
84 sizeof(resp.dmac);
85
86 if (udata->outlen < min_resp_len)
87 return ERR_PTR(-EINVAL);
88
89 resp.response_length = min_resp_len;
90
91 err = ib_resolve_eth_dmac(pd->device, ah_attr);
92 if (err)
93 return ERR_PTR(err);
94
95 memcpy(resp.dmac, ah_attr->dmac, ETH_ALEN);
96 err = ib_copy_to_udata(udata, &resp, resp.response_length);
97 if (err)
98 return ERR_PTR(err);
99 }
100
101 ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
102 if (!ah)
103 return ERR_PTR(-ENOMEM);
104
105 return create_ib_ah(dev, ah, ah_attr, ll);
106}
107
108int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
109{
110 struct mlx5_ib_ah *ah = to_mah(ibah);
111 u32 tmp;
112
113 memset(ah_attr, 0, sizeof(*ah_attr));
114
115 tmp = be32_to_cpu(ah->av.grh_gid_fl);
116 if (tmp & (1 << 30)) {
117 ah_attr->ah_flags = IB_AH_GRH;
118 ah_attr->grh.sgid_index = (tmp >> 20) & 0xff;
119 ah_attr->grh.flow_label = tmp & 0xfffff;
120 memcpy(&ah_attr->grh.dgid, ah->av.rgid, 16);
121 ah_attr->grh.hop_limit = ah->av.hop_limit;
122 ah_attr->grh.traffic_class = ah->av.tclass;
123 }
124 ah_attr->dlid = be16_to_cpu(ah->av.rlid);
125 ah_attr->static_rate = ah->av.stat_rate_sl >> 4;
126 ah_attr->sl = ah->av.stat_rate_sl & 0xf;
127
128 return 0;
129}
130
131int mlx5_ib_destroy_ah(struct ib_ah *ah)
132{
133 kfree(to_mah(ah));
134 return 0;
135}
136