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