1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff *    Implementation of osm_mcast_tbl_t.
39219820Sjeff * This object represents an multicast forwarding table.
40219820Sjeff * This object is part of the opensm family of objects.
41219820Sjeff */
42219820Sjeff
43219820Sjeff#if HAVE_CONFIG_H
44219820Sjeff#  include <config.h>
45219820Sjeff#endif				/* HAVE_CONFIG_H */
46219820Sjeff
47219820Sjeff#include <stdlib.h>
48219820Sjeff#include <string.h>
49219820Sjeff#include <complib/cl_math.h>
50219820Sjeff#include <iba/ib_types.h>
51219820Sjeff#include <opensm/osm_mcast_tbl.h>
52219820Sjeff
53219820Sjeff/**********************************************************************
54219820Sjeff **********************************************************************/
55219820Sjeffib_api_status_t
56219820Sjeffosm_mcast_tbl_init(IN osm_mcast_tbl_t * const p_tbl,
57219820Sjeff		   IN uint8_t const num_ports, IN uint16_t const capacity)
58219820Sjeff{
59219820Sjeff	CL_ASSERT(p_tbl);
60219820Sjeff	CL_ASSERT(num_ports);
61219820Sjeff
62219820Sjeff	memset(p_tbl, 0, sizeof(*p_tbl));
63219820Sjeff
64219820Sjeff	p_tbl->max_block_in_use = -1;
65219820Sjeff
66219820Sjeff	if (capacity == 0) {
67219820Sjeff		/*
68219820Sjeff		   This switch apparently doesn't support multicast.
69219820Sjeff		   Everything is initialized to zero already, so return.
70219820Sjeff		 */
71219820Sjeff		return (IB_SUCCESS);
72219820Sjeff	}
73219820Sjeff
74219820Sjeff	p_tbl->num_entries = capacity;
75219820Sjeff	p_tbl->num_ports = num_ports;
76219820Sjeff	p_tbl->max_position =
77219820Sjeff	    (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) /
78219820Sjeff			IB_MCAST_MASK_SIZE) - 1);
79219820Sjeff
80219820Sjeff	p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries,
81219820Sjeff						IB_MCAST_BLOCK_SIZE) /
82219820Sjeff					IB_MCAST_BLOCK_SIZE) - 1);
83219820Sjeff
84219820Sjeff	p_tbl->max_mlid_ho = (uint16_t) (IB_LID_MCAST_START_HO + capacity - 1);
85219820Sjeff
86219820Sjeff	/*
87219820Sjeff	   The number of bytes needed in the mask table is:
88219820Sjeff	   The (maximum bit mask 'position' + 1) times the
89219820Sjeff	   number of bytes in each bit mask times the
90219820Sjeff	   number of MLIDs supported by the table.
91219820Sjeff
92219820Sjeff	   We must always allocate the array with the maximum position
93219820Sjeff	   since it is (and must be) defined that way the table structure
94219820Sjeff	   in order to create a pointer to a two dimensional array.
95219820Sjeff	 */
96219820Sjeff	p_tbl->p_mask_tbl = malloc(p_tbl->num_entries *
97219820Sjeff				   (IB_MCAST_POSITION_MAX +
98219820Sjeff				    1) * IB_MCAST_MASK_SIZE / 8);
99219820Sjeff
100219820Sjeff	if (p_tbl->p_mask_tbl == NULL)
101219820Sjeff		return (IB_INSUFFICIENT_MEMORY);
102219820Sjeff
103219820Sjeff	memset(p_tbl->p_mask_tbl, 0,
104219820Sjeff	       p_tbl->num_entries * (IB_MCAST_POSITION_MAX +
105219820Sjeff				     1) * IB_MCAST_MASK_SIZE / 8);
106219820Sjeff	return (IB_SUCCESS);
107219820Sjeff}
108219820Sjeff
109219820Sjeff/**********************************************************************
110219820Sjeff **********************************************************************/
111219820Sjeffvoid osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * const p_tbl)
112219820Sjeff{
113219820Sjeff	free(p_tbl->p_mask_tbl);
114219820Sjeff}
115219820Sjeff
116219820Sjeff/**********************************************************************
117219820Sjeff **********************************************************************/
118219820Sjeffvoid
119219820Sjeffosm_mcast_tbl_set(IN osm_mcast_tbl_t * const p_tbl,
120219820Sjeff		  IN const uint16_t mlid_ho, IN const uint8_t port)
121219820Sjeff{
122219820Sjeff	uintn_t mlid_offset;
123219820Sjeff	uintn_t mask_offset;
124219820Sjeff	uintn_t bit_mask;
125219820Sjeff	int16_t block_num;
126219820Sjeff
127219820Sjeff	CL_ASSERT(p_tbl);
128219820Sjeff	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
129219820Sjeff	CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
130219820Sjeff	CL_ASSERT(p_tbl->p_mask_tbl);
131219820Sjeff
132219820Sjeff	mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
133219820Sjeff	mask_offset = port / IB_MCAST_MASK_SIZE;
134219820Sjeff	bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE)));
135219820Sjeff	(*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask;
136219820Sjeff
137219820Sjeff	block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE);
138219820Sjeff
139219820Sjeff	if (block_num > p_tbl->max_block_in_use)
140219820Sjeff		p_tbl->max_block_in_use = (uint16_t) block_num;
141219820Sjeff}
142219820Sjeff
143219820Sjeff/**********************************************************************
144219820Sjeff **********************************************************************/
145219820Sjeffboolean_t
146219820Sjeffosm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * const p_tbl,
147219820Sjeff		      IN const uint16_t mlid_ho, IN const uint8_t port_num)
148219820Sjeff{
149219820Sjeff	uintn_t mlid_offset;
150219820Sjeff	uintn_t mask_offset;
151219820Sjeff	uintn_t bit_mask;
152219820Sjeff
153219820Sjeff	CL_ASSERT(p_tbl);
154219820Sjeff
155219820Sjeff	if (p_tbl->p_mask_tbl) {
156219820Sjeff		CL_ASSERT(port_num <=
157219820Sjeff			  (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE);
158219820Sjeff		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
159219820Sjeff		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
160219820Sjeff
161219820Sjeff		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
162219820Sjeff		mask_offset = port_num / IB_MCAST_MASK_SIZE;
163219820Sjeff		bit_mask = cl_ntoh16((uint16_t)
164219820Sjeff				     (1 << (port_num % IB_MCAST_MASK_SIZE)));
165219820Sjeff		return (((*p_tbl->
166219820Sjeff			  p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) ==
167219820Sjeff			bit_mask);
168219820Sjeff	}
169219820Sjeff
170219820Sjeff	return (FALSE);
171219820Sjeff}
172219820Sjeff
173219820Sjeff/**********************************************************************
174219820Sjeff **********************************************************************/
175219820Sjeffboolean_t
176219820Sjeffosm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * const p_tbl,
177219820Sjeff			  IN const uint16_t mlid_ho)
178219820Sjeff{
179219820Sjeff	uintn_t mlid_offset;
180219820Sjeff	uint8_t position;
181219820Sjeff	uint16_t result = 0;
182219820Sjeff
183219820Sjeff	CL_ASSERT(p_tbl);
184219820Sjeff
185219820Sjeff	if (p_tbl->p_mask_tbl) {
186219820Sjeff		CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
187219820Sjeff		CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho);
188219820Sjeff
189219820Sjeff		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
190219820Sjeff
191219820Sjeff		for (position = 0; position <= p_tbl->max_position; position++)
192219820Sjeff			result |= (*p_tbl->p_mask_tbl)[mlid_offset][position];
193219820Sjeff	}
194219820Sjeff
195219820Sjeff	return (result != 0);
196219820Sjeff}
197219820Sjeff
198219820Sjeff/**********************************************************************
199219820Sjeff **********************************************************************/
200219820Sjeffib_api_status_t
201219820Sjeffosm_mcast_tbl_set_block(IN osm_mcast_tbl_t * const p_tbl,
202219820Sjeff			IN const ib_net16_t * const p_block,
203219820Sjeff			IN const int16_t block_num, IN const uint8_t position)
204219820Sjeff{
205219820Sjeff	uint32_t i;
206219820Sjeff	uint16_t mlid_start_ho;
207219820Sjeff
208219820Sjeff	CL_ASSERT(p_tbl);
209219820Sjeff	CL_ASSERT(p_block);
210219820Sjeff
211219820Sjeff	if (block_num > p_tbl->max_block)
212219820Sjeff		return (IB_INVALID_PARAMETER);
213219820Sjeff
214219820Sjeff	if (position > p_tbl->max_position)
215219820Sjeff		return (IB_INVALID_PARAMETER);
216219820Sjeff
217219820Sjeff	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
218219820Sjeff
219219820Sjeff	if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->max_mlid_ho)
220219820Sjeff		return (IB_INVALID_PARAMETER);
221219820Sjeff
222219820Sjeff	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
223219820Sjeff		(*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i];
224219820Sjeff
225219820Sjeff	if (block_num > p_tbl->max_block_in_use)
226219820Sjeff		p_tbl->max_block_in_use = (uint16_t) block_num;
227219820Sjeff
228219820Sjeff	return (IB_SUCCESS);
229219820Sjeff}
230219820Sjeff
231219820Sjeff/**********************************************************************
232219820Sjeff **********************************************************************/
233219820Sjeffvoid
234219820Sjeffosm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * const p_tbl,
235219820Sjeff			 IN const uint16_t mlid_ho)
236219820Sjeff{
237219820Sjeff	uint8_t i;
238219820Sjeff	uintn_t mlid_offset;
239219820Sjeff
240219820Sjeff	CL_ASSERT(p_tbl);
241219820Sjeff	CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO);
242219820Sjeff
243219820Sjeff	if (p_tbl->p_mask_tbl && (mlid_ho <= p_tbl->max_mlid_ho)) {
244219820Sjeff		mlid_offset = mlid_ho - IB_LID_MCAST_START_HO;
245219820Sjeff		for (i = 0; i <= p_tbl->max_position; i++)
246219820Sjeff			(*p_tbl->p_mask_tbl)[mlid_offset][i] = 0;
247219820Sjeff	}
248219820Sjeff}
249219820Sjeff
250219820Sjeff/**********************************************************************
251219820Sjeff **********************************************************************/
252219820Sjeffboolean_t
253219820Sjeffosm_mcast_tbl_get_block(IN osm_mcast_tbl_t * const p_tbl,
254219820Sjeff			IN int16_t const block_num,
255219820Sjeff			IN uint8_t const position,
256219820Sjeff			OUT ib_net16_t * const p_block)
257219820Sjeff{
258219820Sjeff	uint32_t i;
259219820Sjeff	uint16_t mlid_start_ho;
260219820Sjeff
261219820Sjeff	CL_ASSERT(p_tbl);
262219820Sjeff	CL_ASSERT(p_block);
263219820Sjeff
264219820Sjeff	if (block_num > p_tbl->max_block_in_use)
265219820Sjeff		return (FALSE);
266219820Sjeff
267219820Sjeff	if (position > p_tbl->max_position) {
268219820Sjeff		/*
269219820Sjeff		   Caller shouldn't do this for efficiency's sake...
270219820Sjeff		 */
271219820Sjeff		memset(p_block, 0, IB_SMP_DATA_SIZE);
272219820Sjeff		return (TRUE);
273219820Sjeff	}
274219820Sjeff
275219820Sjeff	mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE);
276219820Sjeff
277219820Sjeff	if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->max_mlid_ho)
278219820Sjeff		return (IB_INVALID_PARAMETER);
279219820Sjeff
280219820Sjeff	for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++)
281219820Sjeff		p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position];
282219820Sjeff
283219820Sjeff	return (TRUE);
284219820Sjeff}
285