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