]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/infiniband/core/smi.c
regulator: max8973: Fix up control flag option for bias control
[karo-tx-linux.git] / drivers / infiniband / core / smi.c
1 /*
2  * Copyright (c) 2004, 2005 Mellanox Technologies Ltd.  All rights reserved.
3  * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved.
4  * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
5  * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved.
6  * Copyright (c) 2004-2007 Voltaire Corporation.  All rights reserved.
7  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
8  * Copyright (c) 2014 Intel Corporation.  All rights reserved.
9  *
10  * This software is available to you under a choice of one of two
11  * licenses.  You may choose to be licensed under the terms of the GNU
12  * General Public License (GPL) Version 2, available from the file
13  * COPYING in the main directory of this source tree, or the
14  * OpenIB.org BSD license below:
15  *
16  *     Redistribution and use in source and binary forms, with or
17  *     without modification, are permitted provided that the following
18  *     conditions are met:
19  *
20  *      - Redistributions of source code must retain the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer.
23  *
24  *      - Redistributions in binary form must reproduce the above
25  *        copyright notice, this list of conditions and the following
26  *        disclaimer in the documentation and/or other materials
27  *        provided with the distribution.
28  *
29  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
33  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
34  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
35  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36  * SOFTWARE.
37  *
38  */
39
40 #include <rdma/ib_smi.h>
41 #include "smi.h"
42 #include "opa_smi.h"
43
44 static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
45                                                 u8 *hop_ptr, u8 hop_cnt,
46                                                 const u8 *initial_path,
47                                                 const u8 *return_path,
48                                                 u8 direction,
49                                                 bool dr_dlid_is_permissive,
50                                                 bool dr_slid_is_permissive)
51 {
52         /* See section 14.2.2.2, Vol 1 IB spec */
53         /* C14-6 -- valid hop_cnt values are from 0 to 63 */
54         if (hop_cnt >= IB_SMP_MAX_PATH_HOPS)
55                 return IB_SMI_DISCARD;
56
57         if (!direction) {
58                 /* C14-9:1 */
59                 if (hop_cnt && *hop_ptr == 0) {
60                         (*hop_ptr)++;
61                         return (initial_path[*hop_ptr] ==
62                                 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
63                 }
64
65                 /* C14-9:2 */
66                 if (*hop_ptr && *hop_ptr < hop_cnt) {
67                         if (node_type != RDMA_NODE_IB_SWITCH)
68                                 return IB_SMI_DISCARD;
69
70                         /* return_path set when received */
71                         (*hop_ptr)++;
72                         return (initial_path[*hop_ptr] ==
73                                 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
74                 }
75
76                 /* C14-9:3 -- We're at the end of the DR segment of path */
77                 if (*hop_ptr == hop_cnt) {
78                         /* return_path set when received */
79                         (*hop_ptr)++;
80                         return (node_type == RDMA_NODE_IB_SWITCH ||
81                                 dr_dlid_is_permissive ?
82                                 IB_SMI_HANDLE : IB_SMI_DISCARD);
83                 }
84
85                 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
86                 /* C14-9:5 -- Fail unreasonable hop pointer */
87                 return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
88
89         } else {
90                 /* C14-13:1 */
91                 if (hop_cnt && *hop_ptr == hop_cnt + 1) {
92                         (*hop_ptr)--;
93                         return (return_path[*hop_ptr] ==
94                                 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
95                 }
96
97                 /* C14-13:2 */
98                 if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) {
99                         if (node_type != RDMA_NODE_IB_SWITCH)
100                                 return IB_SMI_DISCARD;
101
102                         (*hop_ptr)--;
103                         return (return_path[*hop_ptr] ==
104                                 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
105                 }
106
107                 /* C14-13:3 -- at the end of the DR segment of path */
108                 if (*hop_ptr == 1) {
109                         (*hop_ptr)--;
110                         /* C14-13:3 -- SMPs destined for SM shouldn't be here */
111                         return (node_type == RDMA_NODE_IB_SWITCH ||
112                                 dr_slid_is_permissive ?
113                                 IB_SMI_HANDLE : IB_SMI_DISCARD);
114                 }
115
116                 /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */
117                 if (*hop_ptr == 0)
118                         return IB_SMI_HANDLE;
119
120                 /* C14-13:5 -- Check for unreasonable hop pointer */
121                 return IB_SMI_DISCARD;
122         }
123 }
124
125 /*
126  * Fixup a directed route SMP for sending
127  * Return IB_SMI_DISCARD if the SMP should be discarded
128  */
129 enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
130                                        u8 node_type, int port_num)
131 {
132         return __smi_handle_dr_smp_send(node_type, port_num,
133                                         &smp->hop_ptr, smp->hop_cnt,
134                                         smp->initial_path,
135                                         smp->return_path,
136                                         ib_get_smp_direction(smp),
137                                         smp->dr_dlid == IB_LID_PERMISSIVE,
138                                         smp->dr_slid == IB_LID_PERMISSIVE);
139 }
140
141 enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp,
142                                        u8 node_type, int port_num)
143 {
144         return __smi_handle_dr_smp_send(node_type, port_num,
145                                         &smp->hop_ptr, smp->hop_cnt,
146                                         smp->route.dr.initial_path,
147                                         smp->route.dr.return_path,
148                                         opa_get_smp_direction(smp),
149                                         smp->route.dr.dr_dlid ==
150                                         OPA_LID_PERMISSIVE,
151                                         smp->route.dr.dr_slid ==
152                                         OPA_LID_PERMISSIVE);
153 }
154
155 static enum smi_action __smi_handle_dr_smp_recv(u8 node_type, int port_num,
156                                                 int phys_port_cnt,
157                                                 u8 *hop_ptr, u8 hop_cnt,
158                                                 const u8 *initial_path,
159                                                 u8 *return_path,
160                                                 u8 direction,
161                                                 bool dr_dlid_is_permissive,
162                                                 bool dr_slid_is_permissive)
163 {
164         /* See section 14.2.2.2, Vol 1 IB spec */
165         /* C14-6 -- valid hop_cnt values are from 0 to 63 */
166         if (hop_cnt >= IB_SMP_MAX_PATH_HOPS)
167                 return IB_SMI_DISCARD;
168
169         if (!direction) {
170                 /* C14-9:1 -- sender should have incremented hop_ptr */
171                 if (hop_cnt && *hop_ptr == 0)
172                         return IB_SMI_DISCARD;
173
174                 /* C14-9:2 -- intermediate hop */
175                 if (*hop_ptr && *hop_ptr < hop_cnt) {
176                         if (node_type != RDMA_NODE_IB_SWITCH)
177                                 return IB_SMI_DISCARD;
178
179                         return_path[*hop_ptr] = port_num;
180                         /* hop_ptr updated when sending */
181                         return (initial_path[*hop_ptr+1] <= phys_port_cnt ?
182                                 IB_SMI_HANDLE : IB_SMI_DISCARD);
183                 }
184
185                 /* C14-9:3 -- We're at the end of the DR segment of path */
186                 if (*hop_ptr == hop_cnt) {
187                         if (hop_cnt)
188                                 return_path[*hop_ptr] = port_num;
189                         /* hop_ptr updated when sending */
190
191                         return (node_type == RDMA_NODE_IB_SWITCH ||
192                                 dr_dlid_is_permissive ?
193                                 IB_SMI_HANDLE : IB_SMI_DISCARD);
194                 }
195
196                 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
197                 /* C14-9:5 -- fail unreasonable hop pointer */
198                 return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
199
200         } else {
201
202                 /* C14-13:1 */
203                 if (hop_cnt && *hop_ptr == hop_cnt + 1) {
204                         (*hop_ptr)--;
205                         return (return_path[*hop_ptr] ==
206                                 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
207                 }
208
209                 /* C14-13:2 */
210                 if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) {
211                         if (node_type != RDMA_NODE_IB_SWITCH)
212                                 return IB_SMI_DISCARD;
213
214                         /* hop_ptr updated when sending */
215                         return (return_path[*hop_ptr-1] <= phys_port_cnt ?
216                                 IB_SMI_HANDLE : IB_SMI_DISCARD);
217                 }
218
219                 /* C14-13:3 -- We're at the end of the DR segment of path */
220                 if (*hop_ptr == 1) {
221                         if (dr_slid_is_permissive) {
222                                 /* giving SMP to SM - update hop_ptr */
223                                 (*hop_ptr)--;
224                                 return IB_SMI_HANDLE;
225                         }
226                         /* hop_ptr updated when sending */
227                         return (node_type == RDMA_NODE_IB_SWITCH ?
228                                 IB_SMI_HANDLE : IB_SMI_DISCARD);
229                 }
230
231                 /* C14-13:4 -- hop_ptr = 0 -> give to SM */
232                 /* C14-13:5 -- Check for unreasonable hop pointer */
233                 return (*hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
234         }
235 }
236
237 /*
238  * Adjust information for a received SMP
239  * Return IB_SMI_DISCARD if the SMP should be dropped
240  */
241 enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
242                                        int port_num, int phys_port_cnt)
243 {
244         return __smi_handle_dr_smp_recv(node_type, port_num, phys_port_cnt,
245                                         &smp->hop_ptr, smp->hop_cnt,
246                                         smp->initial_path,
247                                         smp->return_path,
248                                         ib_get_smp_direction(smp),
249                                         smp->dr_dlid == IB_LID_PERMISSIVE,
250                                         smp->dr_slid == IB_LID_PERMISSIVE);
251 }
252
253 /*
254  * Adjust information for a received SMP
255  * Return IB_SMI_DISCARD if the SMP should be dropped
256  */
257 enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, u8 node_type,
258                                            int port_num, int phys_port_cnt)
259 {
260         return __smi_handle_dr_smp_recv(node_type, port_num, phys_port_cnt,
261                                         &smp->hop_ptr, smp->hop_cnt,
262                                         smp->route.dr.initial_path,
263                                         smp->route.dr.return_path,
264                                         opa_get_smp_direction(smp),
265                                         smp->route.dr.dr_dlid ==
266                                         OPA_LID_PERMISSIVE,
267                                         smp->route.dr.dr_slid ==
268                                         OPA_LID_PERMISSIVE);
269 }
270
271 static enum smi_forward_action __smi_check_forward_dr_smp(u8 hop_ptr, u8 hop_cnt,
272                                                           u8 direction,
273                                                           bool dr_dlid_is_permissive,
274                                                           bool dr_slid_is_permissive)
275 {
276         if (!direction) {
277                 /* C14-9:2 -- intermediate hop */
278                 if (hop_ptr && hop_ptr < hop_cnt)
279                         return IB_SMI_FORWARD;
280
281                 /* C14-9:3 -- at the end of the DR segment of path */
282                 if (hop_ptr == hop_cnt)
283                         return (dr_dlid_is_permissive ?
284                                 IB_SMI_SEND : IB_SMI_LOCAL);
285
286                 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
287                 if (hop_ptr == hop_cnt + 1)
288                         return IB_SMI_SEND;
289         } else {
290                 /* C14-13:2  -- intermediate hop */
291                 if (2 <= hop_ptr && hop_ptr <= hop_cnt)
292                         return IB_SMI_FORWARD;
293
294                 /* C14-13:3 -- at the end of the DR segment of path */
295                 if (hop_ptr == 1)
296                         return (!dr_slid_is_permissive ?
297                                 IB_SMI_SEND : IB_SMI_LOCAL);
298         }
299         return IB_SMI_LOCAL;
300
301 }
302
303 enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
304 {
305         return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt,
306                                           ib_get_smp_direction(smp),
307                                           smp->dr_dlid == IB_LID_PERMISSIVE,
308                                           smp->dr_slid == IB_LID_PERMISSIVE);
309 }
310
311 enum smi_forward_action opa_smi_check_forward_dr_smp(struct opa_smp *smp)
312 {
313         return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt,
314                                           opa_get_smp_direction(smp),
315                                           smp->route.dr.dr_dlid ==
316                                           OPA_LID_PERMISSIVE,
317                                           smp->route.dr.dr_slid ==
318                                           OPA_LID_PERMISSIVE);
319 }
320
321 /*
322  * Return the forwarding port number from initial_path for outgoing SMP and
323  * from return_path for returning SMP
324  */
325 int smi_get_fwd_port(struct ib_smp *smp)
326 {
327         return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] :
328                 smp->return_path[smp->hop_ptr-1]);
329 }
330
331 /*
332  * Return the forwarding port number from initial_path for outgoing SMP and
333  * from return_path for returning SMP
334  */
335 int opa_smi_get_fwd_port(struct opa_smp *smp)
336 {
337         return !opa_get_smp_direction(smp) ? smp->route.dr.initial_path[smp->hop_ptr+1] :
338                 smp->route.dr.return_path[smp->hop_ptr-1];
339 }