]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_mcast_tbl.c
MFV r348548: 9617 too-frequent TXG sync causes excessive write inflation
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_mcast_tbl.c
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  * Copyright (c) 2009 HNR Consulting. All rights reserved.
6  *
7  * This software is available to you under a choice of one of two
8  * licenses.  You may choose to be licensed under the terms of the GNU
9  * General Public License (GPL) Version 2, available from the file
10  * COPYING in the main directory of this source tree, or the
11  * OpenIB.org BSD license below:
12  *
13  *     Redistribution and use in source and binary forms, with or
14  *     without modification, are permitted provided that the following
15  *     conditions are met:
16  *
17  *      - Redistributions of source code must retain the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer.
20  *
21  *      - Redistributions in binary form must reproduce the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer in the documentation and/or other materials
24  *        provided with the distribution.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33  * SOFTWARE.
34  *
35  */
36
37 /*
38  * Abstract:
39  *    Implementation of osm_mcast_tbl_t.
40  * This object represents a multicast forwarding table.
41  * This object is part of the opensm family of objects.
42  */
43
44 #if HAVE_CONFIG_H
45 #  include <config.h>
46 #endif                          /* HAVE_CONFIG_H */
47
48 #include <stdlib.h>
49 #include <string.h>
50 #include <complib/cl_math.h>
51 #include <iba/ib_types.h>
52 #include <opensm/osm_file_ids.h>
53 #define FILE_ID OSM_FILE_MCAST_TBL_C
54 #include <opensm/osm_mcast_tbl.h>
55
56 void osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports,
57                         IN uint16_t capacity)
58 {
59         CL_ASSERT(p_tbl);
60         CL_ASSERT(num_ports);
61
62         memset(p_tbl, 0, sizeof(*p_tbl));
63
64         p_tbl->max_block_in_use = -1;
65
66         if (capacity == 0) {
67                 /*
68                    This switch apparently doesn't support multicast.
69                    Everything is initialized to zero already, so return.
70                  */
71                 return;
72         }
73
74         p_tbl->num_entries = capacity;
75         p_tbl->num_ports = num_ports;
76         p_tbl->max_position =
77             (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) /
78                         IB_MCAST_MASK_SIZE) - 1);
79
80         p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries,
81                                                 IB_MCAST_BLOCK_SIZE) /
82                                         IB_MCAST_BLOCK_SIZE) - 1);
83 }
84
85 void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)
86 {
87         free(p_tbl->p_mask_tbl);
88 }
89
90 void osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho,
91                        IN uint8_t port)
92 {
93         unsigned mlid_offset, mask_offset, bit_mask;
94         int16_t block_num;
95
96         CL_ASSERT(p_tbl && p_tbl->p_mask_tbl);
97         CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
98         CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
99
100         mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
101         mask_offset = port / IB_MCAST_MASK_SIZE;
102         bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE)));
103         (*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask;
104
105         block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE);
106
107         if (block_num > p_tbl->max_block_in_use)
108                 p_tbl->max_block_in_use = (uint16_t) block_num;
109 }
110
111 int osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset)
112 {
113         size_t mft_depth, size;
114         uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1];
115
116         if (mlid_offset < p_tbl->mft_depth)
117                 goto done;
118
119         /*
120            The number of bytes needed in the mask table is:
121            The (maximum bit mask 'position' + 1) times the
122            number of bytes in each bit mask times the
123            number of MLIDs supported by the table.
124
125            We must always allocate the array with the maximum position
126            since it is (and must be) defined that way the table structure
127            in order to create a pointer to a two dimensional array.
128          */
129         mft_depth = (mlid_offset / IB_MCAST_BLOCK_SIZE + 1) * IB_MCAST_BLOCK_SIZE;
130         size = mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8;
131         p_mask_tbl = realloc(p_tbl->p_mask_tbl, size);
132         if (!p_mask_tbl)
133                 return -1;
134         memset((uint8_t *)p_mask_tbl + p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
135                0,
136                size - p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
137         p_tbl->p_mask_tbl = p_mask_tbl;
138         p_tbl->mft_depth = mft_depth;
139 done:
140         p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO;
141         return 0;
142 }
143
144 boolean_t osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * p_tbl,
145                                 IN uint16_t mlid_ho, IN uint8_t port_num)
146 {
147         unsigned mlid_offset, mask_offset, bit_mask;
148
149         CL_ASSERT(p_tbl);
150
151         if (p_tbl->p_mask_tbl) {
152                 CL_ASSERT(port_num <=
153                           (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE);
154                 CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
155                 CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
156
157                 mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
158                 mask_offset = port_num / IB_MCAST_MASK_SIZE;
159                 bit_mask = cl_ntoh16((uint16_t)
160                                      (1 << (port_num % IB_MCAST_MASK_SIZE)));
161                 return (((*p_tbl->
162                           p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) ==
163                         bit_mask);
164         }
165
166         return FALSE;
167 }
168
169 boolean_t osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * p_tbl,
170                                     IN uint16_t mlid_ho)
171 {
172         unsigned mlid_offset;
173         uint8_t position;
174         uint16_t result = 0;
175
176         CL_ASSERT(p_tbl);
177
178         if (p_tbl->p_mask_tbl) {
179                 CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
180                 CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
181
182                 mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
183
184                 for (position = 0; position <= p_tbl->max_position; position++)
185                         result |= (*p_tbl->p_mask_tbl)[mlid_offset][position];
186         }
187
188         return (result != 0);
189 }
190
191 ib_api_status_t osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * p_tbl,
192                                         IN const ib_net16_t * p_block,
193                                         IN int16_t block_num,
194                                         IN uint8_t position)
195 {
196         uint32_t i;
197         uint16_t mlid_start_ho;
198
199         CL_ASSERT(p_tbl);
200         CL_ASSERT(p_block);
201
202         if (block_num > p_tbl->max_block)
203                 return IB_INVALID_PARAMETER;
204
205         if (position > p_tbl->max_position)
206                 return IB_INVALID_PARAMETER;
207
208         mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
209
210         if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->mft_depth)
211                 return IB_INVALID_PARAMETER;
212
213         for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
214                 (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i];
215
216         if (block_num > p_tbl->max_block_in_use)
217                 p_tbl->max_block_in_use = (uint16_t) block_num;
218
219         return IB_SUCCESS;
220 }
221
222 void osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho)
223 {
224         unsigned mlid_offset;
225
226         CL_ASSERT(p_tbl);
227         CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
228
229         mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
230         if (p_tbl->p_mask_tbl && mlid_offset < p_tbl->mft_depth)
231                 memset((uint8_t *)p_tbl->p_mask_tbl + mlid_offset * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
232                        0,
233                        (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
234 }
235
236 boolean_t osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * p_tbl,
237                                   IN int16_t block_num, IN uint8_t position,
238                                   OUT ib_net16_t * p_block)
239 {
240         uint32_t i;
241         uint16_t mlid_start_ho;
242
243         CL_ASSERT(p_tbl);
244         CL_ASSERT(p_block);
245
246         if (block_num > p_tbl->max_block_in_use)
247                 return FALSE;
248
249         if (position > p_tbl->max_position) {
250                 /*
251                    Caller shouldn't do this for efficiency's sake...
252                  */
253                 memset(p_block, 0, IB_SMP_DATA_SIZE);
254                 return TRUE;
255         }
256
257         CL_ASSERT(block_num * IB_MCAST_BLOCK_SIZE <= p_tbl->mft_depth);
258
259         mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
260
261         for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
262                 p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position];
263
264         return TRUE;
265 }