1321936Shselasky/*
2321936Shselasky * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3321936Shselasky * Copyright (c) 2002-2009 Mellanox Technologies LTD. All rights reserved.
4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5321936Shselasky * Copyright (c) 2009 HNR Consulting. All rights reserved.
6321936Shselasky *
7321936Shselasky * This software is available to you under a choice of one of two
8321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
9321936Shselasky * General Public License (GPL) Version 2, available from the file
10321936Shselasky * COPYING in the main directory of this source tree, or the
11321936Shselasky * OpenIB.org BSD license below:
12321936Shselasky *
13321936Shselasky *     Redistribution and use in source and binary forms, with or
14321936Shselasky *     without modification, are permitted provided that the following
15321936Shselasky *     conditions are met:
16321936Shselasky *
17321936Shselasky *      - Redistributions of source code must retain the above
18321936Shselasky *        copyright notice, this list of conditions and the following
19321936Shselasky *        disclaimer.
20321936Shselasky *
21321936Shselasky *      - Redistributions in binary form must reproduce the above
22321936Shselasky *        copyright notice, this list of conditions and the following
23321936Shselasky *        disclaimer in the documentation and/or other materials
24321936Shselasky *        provided with the distribution.
25321936Shselasky *
26321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33321936Shselasky * SOFTWARE.
34321936Shselasky *
35321936Shselasky */
36321936Shselasky
37321936Shselasky/*
38321936Shselasky * Abstract:
39321936Shselasky *    Implementation of osm_mcast_tbl_t.
40321936Shselasky * This object represents a multicast forwarding table.
41321936Shselasky * This object is part of the opensm family of objects.
42321936Shselasky */
43321936Shselasky
44321936Shselasky#if HAVE_CONFIG_H
45321936Shselasky#  include <config.h>
46321936Shselasky#endif				/* HAVE_CONFIG_H */
47321936Shselasky
48321936Shselasky#include <stdlib.h>
49321936Shselasky#include <string.h>
50321936Shselasky#include <complib/cl_math.h>
51321936Shselasky#include <iba/ib_types.h>
52321936Shselasky#include <opensm/osm_file_ids.h>
53321936Shselasky#define FILE_ID OSM_FILE_MCAST_TBL_C
54321936Shselasky#include <opensm/osm_mcast_tbl.h>
55321936Shselasky
56321936Shselaskyvoid osm_mcast_tbl_init(IN osm_mcast_tbl_t * p_tbl, IN uint8_t num_ports,
57321936Shselasky			IN uint16_t capacity)
58321936Shselasky{
59321936Shselasky	CL_ASSERT(p_tbl);
60321936Shselasky	CL_ASSERT(num_ports);
61321936Shselasky
62321936Shselasky	memset(p_tbl, 0, sizeof(*p_tbl));
63321936Shselasky
64321936Shselasky	p_tbl->max_block_in_use = -1;
65321936Shselasky
66321936Shselasky	if (capacity == 0) {
67321936Shselasky		/*
68321936Shselasky		   This switch apparently doesn't support multicast.
69321936Shselasky		   Everything is initialized to zero already, so return.
70321936Shselasky		 */
71321936Shselasky		return;
72321936Shselasky	}
73321936Shselasky
74321936Shselasky	p_tbl->num_entries = capacity;
75321936Shselasky	p_tbl->num_ports = num_ports;
76321936Shselasky	p_tbl->max_position =
77321936Shselasky	    (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) /
78321936Shselasky			IB_MCAST_MASK_SIZE) - 1);
79321936Shselasky
80321936Shselasky	p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries,
81321936Shselasky						IB_MCAST_BLOCK_SIZE) /
82321936Shselasky					IB_MCAST_BLOCK_SIZE) - 1);
83321936Shselasky}
84321936Shselasky
85321936Shselaskyvoid osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * p_tbl)
86321936Shselasky{
87321936Shselasky	free(p_tbl->p_mask_tbl);
88321936Shselasky}
89321936Shselasky
90321936Shselaskyvoid osm_mcast_tbl_set(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho,
91321936Shselasky		       IN uint8_t port)
92321936Shselasky{
93321936Shselasky	unsigned mlid_offset, mask_offset, bit_mask;
94321936Shselasky	int16_t block_num;
95321936Shselasky
96321936Shselasky	CL_ASSERT(p_tbl && p_tbl->p_mask_tbl);
97321936Shselasky	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
98321936Shselasky	CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
99321936Shselasky
100321936Shselasky	mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
101321936Shselasky	mask_offset = port / IB_MCAST_MASK_SIZE;
102321936Shselasky	bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE)));
103321936Shselasky	(*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask;
104321936Shselasky
105321936Shselasky	block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE);
106321936Shselasky
107321936Shselasky	if (block_num > p_tbl->max_block_in_use)
108321936Shselasky		p_tbl->max_block_in_use = (uint16_t) block_num;
109321936Shselasky}
110321936Shselasky
111321936Shselaskyint osm_mcast_tbl_realloc(IN osm_mcast_tbl_t * p_tbl, IN unsigned mlid_offset)
112321936Shselasky{
113321936Shselasky	size_t mft_depth, size;
114321936Shselasky	uint16_t (*p_mask_tbl)[][IB_MCAST_POSITION_MAX + 1];
115321936Shselasky
116321936Shselasky	if (mlid_offset < p_tbl->mft_depth)
117321936Shselasky		goto done;
118321936Shselasky
119321936Shselasky	/*
120321936Shselasky	   The number of bytes needed in the mask table is:
121321936Shselasky	   The (maximum bit mask 'position' + 1) times the
122321936Shselasky	   number of bytes in each bit mask times the
123321936Shselasky	   number of MLIDs supported by the table.
124321936Shselasky
125321936Shselasky	   We must always allocate the array with the maximum position
126321936Shselasky	   since it is (and must be) defined that way the table structure
127321936Shselasky	   in order to create a pointer to a two dimensional array.
128321936Shselasky	 */
129321936Shselasky	mft_depth = (mlid_offset / IB_MCAST_BLOCK_SIZE + 1) * IB_MCAST_BLOCK_SIZE;
130321936Shselasky	size = mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8;
131321936Shselasky	p_mask_tbl = realloc(p_tbl->p_mask_tbl, size);
132321936Shselasky	if (!p_mask_tbl)
133321936Shselasky		return -1;
134321936Shselasky	memset((uint8_t *)p_mask_tbl + p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
135321936Shselasky	       0,
136321936Shselasky	       size - p_tbl->mft_depth * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
137321936Shselasky	p_tbl->p_mask_tbl = p_mask_tbl;
138321936Shselasky	p_tbl->mft_depth = mft_depth;
139321936Shselaskydone:
140321936Shselasky	p_tbl->max_mlid_ho = mlid_offset + IB_LID_MCAST_START_HO;
141321936Shselasky	return 0;
142321936Shselasky}
143321936Shselasky
144321936Shselaskyboolean_t osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * p_tbl,
145321936Shselasky				IN uint16_t mlid_ho, IN uint8_t port_num)
146321936Shselasky{
147321936Shselasky	unsigned mlid_offset, mask_offset, bit_mask;
148321936Shselasky
149321936Shselasky	CL_ASSERT(p_tbl);
150321936Shselasky
151321936Shselasky	if (p_tbl->p_mask_tbl) {
152321936Shselasky		CL_ASSERT(port_num <=
153321936Shselasky			  (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE);
154321936Shselasky		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
155321936Shselasky		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
156321936Shselasky
157321936Shselasky		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
158321936Shselasky		mask_offset = port_num / IB_MCAST_MASK_SIZE;
159321936Shselasky		bit_mask = cl_ntoh16((uint16_t)
160321936Shselasky				     (1 << (port_num % IB_MCAST_MASK_SIZE)));
161321936Shselasky		return (((*p_tbl->
162321936Shselasky			  p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) ==
163321936Shselasky			bit_mask);
164321936Shselasky	}
165321936Shselasky
166321936Shselasky	return FALSE;
167321936Shselasky}
168321936Shselasky
169321936Shselaskyboolean_t osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * p_tbl,
170321936Shselasky				    IN uint16_t mlid_ho)
171321936Shselasky{
172321936Shselasky	unsigned mlid_offset;
173321936Shselasky	uint8_t position;
174321936Shselasky	uint16_t result = 0;
175321936Shselasky
176321936Shselasky	CL_ASSERT(p_tbl);
177321936Shselasky
178321936Shselasky	if (p_tbl->p_mask_tbl) {
179321936Shselasky		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
180321936Shselasky		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
181321936Shselasky
182321936Shselasky		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
183321936Shselasky
184321936Shselasky		for (position = 0; position <= p_tbl->max_position; position++)
185321936Shselasky			result |= (*p_tbl->p_mask_tbl)[mlid_offset][position];
186321936Shselasky	}
187321936Shselasky
188321936Shselasky	return (result != 0);
189321936Shselasky}
190321936Shselasky
191321936Shselaskyib_api_status_t osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * p_tbl,
192321936Shselasky					IN const ib_net16_t * p_block,
193321936Shselasky					IN int16_t block_num,
194321936Shselasky					IN uint8_t position)
195321936Shselasky{
196321936Shselasky	uint32_t i;
197321936Shselasky	uint16_t mlid_start_ho;
198321936Shselasky
199321936Shselasky	CL_ASSERT(p_tbl);
200321936Shselasky	CL_ASSERT(p_block);
201321936Shselasky
202321936Shselasky	if (block_num > p_tbl->max_block)
203321936Shselasky		return IB_INVALID_PARAMETER;
204321936Shselasky
205321936Shselasky	if (position > p_tbl->max_position)
206321936Shselasky		return IB_INVALID_PARAMETER;
207321936Shselasky
208321936Shselasky	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
209321936Shselasky
210321936Shselasky	if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->mft_depth)
211321936Shselasky		return IB_INVALID_PARAMETER;
212321936Shselasky
213321936Shselasky	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
214321936Shselasky		(*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i];
215321936Shselasky
216321936Shselasky	if (block_num > p_tbl->max_block_in_use)
217321936Shselasky		p_tbl->max_block_in_use = (uint16_t) block_num;
218321936Shselasky
219321936Shselasky	return IB_SUCCESS;
220321936Shselasky}
221321936Shselasky
222321936Shselaskyvoid osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * p_tbl, IN uint16_t mlid_ho)
223321936Shselasky{
224321936Shselasky	unsigned mlid_offset;
225321936Shselasky
226321936Shselasky	CL_ASSERT(p_tbl);
227321936Shselasky	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
228321936Shselasky
229321936Shselasky	mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
230321936Shselasky	if (p_tbl->p_mask_tbl && mlid_offset < p_tbl->mft_depth)
231321936Shselasky		memset((uint8_t *)p_tbl->p_mask_tbl + mlid_offset * (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8,
232321936Shselasky		       0,
233321936Shselasky		       (IB_MCAST_POSITION_MAX + 1) * IB_MCAST_MASK_SIZE / 8);
234321936Shselasky}
235321936Shselasky
236321936Shselaskyboolean_t osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * p_tbl,
237321936Shselasky				  IN int16_t block_num, IN uint8_t position,
238321936Shselasky				  OUT ib_net16_t * p_block)
239321936Shselasky{
240321936Shselasky	uint32_t i;
241321936Shselasky	uint16_t mlid_start_ho;
242321936Shselasky
243321936Shselasky	CL_ASSERT(p_tbl);
244321936Shselasky	CL_ASSERT(p_block);
245321936Shselasky
246321936Shselasky	if (block_num > p_tbl->max_block_in_use)
247321936Shselasky		return FALSE;
248321936Shselasky
249321936Shselasky	if (position > p_tbl->max_position) {
250321936Shselasky		/*
251321936Shselasky		   Caller shouldn't do this for efficiency's sake...
252321936Shselasky		 */
253321936Shselasky		memset(p_block, 0, IB_SMP_DATA_SIZE);
254321936Shselasky		return TRUE;
255321936Shselasky	}
256321936Shselasky
257321936Shselasky	CL_ASSERT(block_num * IB_MCAST_BLOCK_SIZE <= p_tbl->mft_depth);
258321936Shselasky
259321936Shselasky	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
260321936Shselasky
261321936Shselasky	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
262321936Shselasky		p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position];
263321936Shselasky
264321936Shselasky	return TRUE;
265321936Shselasky}
266