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