]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/ofed/drivers/infiniband/hw/mlx4/ah.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / ofed / drivers / infiniband / hw / mlx4 / ah.c
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
39 int 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
65 static 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
94 static 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
138 struct 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
166 out:
167         kfree(ah);
168         return ret;
169 }
170
171 int 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
200 int mlx4_ib_destroy_ah(struct ib_ah *ah)
201 {
202         kfree(to_mah(ah));
203         return 0;
204 }
205