ipmc.c (238046B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: ipmc.c 8 * Purpose: Tomahawk multicast replication implementation. 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <soc/defs.h> 14 #include <sal/core/libc.h> 15 16 #if defined(BCM_TOMAHAWK_SUPPORT) && defined(INCLUDE_L3) 17 18 #include <soc/drv.h> 19 #include <soc/mem.h> 20 21 #include <bcm/types.h> 22 #include <bcm/error.h> 23 24 #include <bcm_int/esw_dispatch.h> 25 #include <bcm_int/esw/ipmc.h> 26 #include <bcm_int/esw/tomahawk.h> 27 #include <bcm_int/esw/firebolt.h> 28 29 #include <bcm_int/esw/stack.h> 30 #include <bcm_int/esw/l3.h> 31 #include <soc/tomahawk.h> 32 #include <soc/trident3.h> 33 34 #ifdef BCM_TOMAHAWK3_SUPPORT 35 #include <bcm_int/esw/tomahawk3.h> 36 #include <soc/tomahawk3.h> 37 #include <bcm_int/esw/multicast.h> 38 #endif 39 #if defined(BCM_HGPROXY_COE_SUPPORT) 40 #include <bcm_int/esw/xgs5.h> 41 #endif /* BCM_HGPROXY_COE_SUPPORT */ 42 43 #if defined(BCM_TRIDENT3_SUPPORT) 44 #include <bcm_int/esw/multicast.h> 45 #include <bcm_int/common/multicast.h> 46 #endif 47 48 /* Structures for managing REPL_HEAD table resources */ 49 50 typedef struct _th_repl_head_free_block_s { 51 int index; /* Starting index of a free block of REPL_HEAD table entries */ 52 int size; /* Number of entries in the free block */ 53 struct _th_repl_head_free_block_s *next; /* Pointer to next free block */ 54 } _th_repl_head_free_block_t; 55 56 typedef struct _th_repl_head_info_s { 57 _th_repl_head_free_block_t **free_list_array; 58 /* Array of lists of free blocks */ 59 int array_size; /* Number of lists in the array */ 60 } _th_repl_head_info_t; 61 62 STATIC _th_repl_head_info_t *_th_repl_head_info[BCM_MAX_NUM_UNITS]; 63 64 #define REPL_HEAD_FREE_LIST(_u_, _pipe_, _index_) \ 65 _th_repl_head_info[_u_][_pipe_].free_list_array[_index_] 66 67 /* Structures for managing REPL_LIST table resources */ 68 69 typedef struct _th_repl_list_entry_info_s { 70 SHR_BITDCL *bitmap_entries_used; /* A bitmap indicating which REPL_LIST 71 entries are used */ 72 int num_entries; /* Total number of entries in REPL_LIST table */ 73 } _th_repl_list_entry_info_t; 74 75 STATIC _th_repl_list_entry_info_t \ 76 *_th_repl_list_entry_info[BCM_MAX_NUM_UNITS]; 77 78 #define REPL_LIST_ENTRY_USED_GET(_u_, _pipe_, _i_) \ 79 SHR_BITGET(_th_repl_list_entry_info[_u_][_pipe_].bitmap_entries_used, _i_) 80 #define REPL_LIST_ENTRY_USED_SET(_u_, _pipe_, _i_) \ 81 SHR_BITSET(_th_repl_list_entry_info[_u_][_pipe_].bitmap_entries_used, _i_) 82 #define REPL_LIST_ENTRY_USED_CLR(_u_, _pipe_, _i_) \ 83 SHR_BITCLR(_th_repl_list_entry_info[_u_][_pipe_].bitmap_entries_used, _i_) 84 85 #define TH_IPMC_NO_SRC_CHECK_PORT 0xFF 86 87 /* Structures containing replication info */ 88 89 typedef struct _th_repl_port_info_s { 90 int *intf_count; /* Array of interface counts, one per replication group */ 91 } _th_repl_port_info_t; 92 93 typedef struct _th_repl_info_s { 94 int num_pipes; /* Number of pipelines */ 95 int num_repl_groups; /* Number of replication groups on this device */ 96 uint32 num_intf; /* Number of interfaces on this device */ 97 _bcm_repl_list_info_t **repl_list_info_array; 98 /* Array of linked list of replication list info */ 99 _th_repl_port_info_t *port_info[SOC_MAX_NUM_PORTS]; 100 /* Per port replication info */ 101 int *l3_intf_next_hop_ipmc; /* Array of next hop indices, one for each 102 L3 interface that's added to an IPMC group */ 103 int *l3_intf_next_hop_trill; /* Array of next hop indices, one for each 104 L3 interface that's added to a Trill group */ 105 } _th_repl_info_t; 106 107 static _th_repl_info_t *_th_repl_info[BCM_MAX_NUM_UNITS]; 108 static int mmu_port_stride[BCM_MAX_NUM_UNITS]; 109 #ifdef BCM_TOMAHAWK3_SUPPORT 110 static _bcm_repl_list_info_t *_repl_list_recycle_array[BCM_MAX_NUM_UNITS]; 111 #endif 112 113 #define REPL_LOCK(_u_) \ 114 { \ 115 soc_mem_lock(_u_, MMU_REPL_LIST_TBLm); \ 116 } 117 #define REPL_UNLOCK(_u_) \ 118 { \ 119 soc_mem_unlock(_u_, MMU_REPL_LIST_TBLm); \ 120 } 121 122 #define REPL_INIT(_u_) \ 123 if (_th_repl_info[_u_] == NULL) { return BCM_E_INIT; } 124 125 #define NUM_PIPES(_u_) _th_repl_info[_u_]->num_pipes 126 127 #define REPL_GROUP_ID(_u_, _id_) \ 128 if ((_id_ < 0) || (_id_ >= _th_repl_info[_u_]->num_repl_groups)) \ 129 { return BCM_E_PARAM; } 130 131 #define REPL_INTF_TOTAL(_u_) _th_repl_info[_u_]->num_intf 132 133 #define REPL_LIST_INFO(_u_, _pipe_) \ 134 _th_repl_info[_u_]->repl_list_info_array[_pipe_] 135 136 #define REPL_PORT_GROUP_INFO(_u_, _port_) \ 137 _th_repl_info[_u_]->port_info[_port_] 138 139 #define REPL_PORT_GROUP_INTF_COUNT(_u_, _port_, _group_id_) \ 140 _th_repl_info[_u_]->port_info[_port_]->intf_count[_group_id_] 141 142 #define REPL_L3_INTF_NEXT_HOP_IPMC(_u_, _intf_) \ 143 _th_repl_info[_u_]->l3_intf_next_hop_ipmc[_intf_] 144 #define REPL_L3_INTF_NEXT_HOP_TRILL(_u_, _intf_) \ 145 _th_repl_info[_u_]->l3_intf_next_hop_trill[_intf_] 146 147 #define REPL_PORT_CHECK(_u_, _port_) \ 148 if (!IS_PORT(_u_, _port_) && !IS_AXP_PORT(_u_, _port_)) { \ 149 return BCM_E_PARAM; \ 150 } 151 152 #define REPL_HEAD_TBL_PIPE(_u_, _pipe_) \ 153 ((SOC_IS_TOMAHAWK3(_u_)) ? MMU_REPL_HEAD_TBLm : \ 154 (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_HEAD_TBLm)[_pipe_])) 155 156 #define REPL_HEAD_TBL(_u_) (MMU_REPL_HEAD_TBLm) 157 158 #define REPL_HEAD_TBL_SPLIT_PIPE(_u_, _split, _pipe_) \ 159 (_split == 0 ? \ 160 SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_HEAD_TBL_SPLIT0m)[_pipe_] : \ 161 SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_HEAD_TBL_SPLIT1m)[_pipe_]) 162 163 #define REPL_HEAD_TBL_SPLIT(_u_, _split) \ 164 (_split == 0 ? MMU_REPL_HEAD_TBL_SPLIT0m : MMU_REPL_HEAD_TBL_SPLIT1m) 165 166 #define REPL_LIST_TBL_PIPE(_u_, _pipe_) \ 167 (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_LIST_TBLm)[_pipe_]) 168 169 #define REPL_LIST_TBL(_u_) (MMU_REPL_LIST_TBLm) 170 171 #define REPL_GROUP_INITIAL_COPY_COUNT_TBL_SLICE(_u_, _slice_) \ 172 (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_GROUP_INITIAL_COPY_COUNTm)[_slice_]) 173 174 #define REPL_GROUP_INITIAL_COPY_COUNT_TBL(_u_) \ 175 (MMU_REPL_GROUP_INITIAL_COPY_COUNTm) 176 177 #define REPL_GROUP_INFO_TBL_PIPE(_u_, _pipe_) \ 178 (SOC_MEM_UNIQUE_ACC(_u_, MMU_REPL_GROUP_INFO_TBLm)[_pipe_]) 179 180 #define REPL_GROUP_INFO_TBL(_u_) (MMU_REPL_GROUP_INFO_TBLm) 181 182 #define REPL_NH_INDEX_UNALLOCATED -1 183 #define REPL_NH_INDEX_L3_EGRESS_ALLOCATED -2 184 185 STATIC void _bcm_th_repl_head_info_deinit(int unit); 186 187 STATIC int 188 _bcm_th_repl_list_entry_alloc(int unit, int pipe, int *entry_index); 189 190 STATIC int 191 _bcm_th_repl_list_free(int unit, int pipe, int start_ptr); 192 193 STATIC int 194 _bcm_th_repl_list_entry_free(int unit, int pipe, int entry_index); 195 196 #ifdef BCM_TOMAHAWK3_SUPPORT 197 198 #define _TH3_IPMC_MIN_INTF_COUNT 4 199 200 #define _TH3_IPMC_UINT32_LEN 32 201 #define _TH3_NUM_NH_SPARSE_MODE 4 202 #define _TH3_NUM_REPL_QUEUE 9 203 #define _TH3_REPL_LIST_ENTRY_UINT32_TOTAL 128 204 205 /* 206 * Function: 207 * bcm_th3_ipmc_repl_port_attach 208 * Purpose: 209 * Initialize replication per-port configuration in the runtime. 210 * Parameters: 211 * unit - (IN) BCM device number. 212 * port - local port number 213 * Returns: 214 * BCM_E_XXX 215 */ 216 int 217 bcm_th3_ipmc_repl_port_attach(int unit, bcm_port_t port) 218 { 219 int rv = BCM_E_NONE; 220 int alloc_size; 221 uint32 regval; 222 soc_reg_t reg = MMU_RQE_REPL_PORT_AGG_MAPr; 223 if (_th_repl_info[unit] == NULL) { 224 return BCM_E_INIT; 225 } 226 227 /* Detach the IPMC REPL in case it is already attached. */ 228 SOC_IF_ERROR_RETURN 229 (bcm_th3_ipmc_repl_port_detach(unit, port)); 230 231 _th_repl_info[unit]->port_info[port] = 232 sal_alloc(sizeof(_th_repl_port_info_t), "repl port info"); 233 if (NULL == _th_repl_info[unit]->port_info[port]) { 234 return BCM_E_MEMORY; 235 } 236 sal_memset(_th_repl_info[unit]->port_info[port], 0, 237 sizeof(_th_repl_port_info_t)); 238 239 alloc_size = sizeof(int) * _th_repl_info[unit]->num_repl_groups; 240 _th_repl_info[unit]->port_info[port]->intf_count = 241 sal_alloc(alloc_size, "repl port intf count"); 242 if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) { 243 sal_free(_th_repl_info[unit]->port_info[port]); 244 return BCM_E_MEMORY; 245 } 246 sal_memset(_th_repl_info[unit]->port_info[port]->intf_count, 0, alloc_size); 247 248 /* configure device port to repl aggregateId map */ 249 regval = 0; 250 soc_reg_field_set(unit, reg, ®val, L3MC_PORT_AGG_IDf, 251 BCM_MC_PER_TRUNK_REPL_MODE(unit) ? 252 TH3_AGG_ID_HW_INVALID : port); 253 rv = soc_reg32_set(unit, reg, port, 0, regval); 254 if (BCM_FAILURE(rv)) { 255 (void)bcm_th3_ipmc_repl_port_detach(unit, port); 256 } 257 258 return rv; 259 } 260 261 /* 262 * Function: 263 * bcm_th3_ipmc_repl_port_detach 264 * Purpose: 265 * Clear replication per-port configuration in the runtime. 266 * Parameters: 267 * unit - (IN) BCM device number. 268 * port - local port number 269 * Returns: 270 * BCM_E_XXX 271 */ 272 int 273 bcm_th3_ipmc_repl_port_detach(int unit, bcm_port_t port) 274 { 275 if (_th_repl_info[unit] == NULL) { 276 return BCM_E_INIT; 277 } 278 279 if (_th_repl_info[unit]->port_info[port] != NULL) { 280 if (_th_repl_info[unit]->port_info[port]->intf_count != NULL) { 281 sal_free(_th_repl_info[unit]->port_info[port]->intf_count); 282 _th_repl_info[unit]->port_info[port]->intf_count = NULL; 283 } 284 sal_free(_th_repl_info[unit]->port_info[port]); 285 _th_repl_info[unit]->port_info[port] = NULL; 286 } 287 288 /* Reset L3MC_PORT_AGG_IDf to HW invalid */ 289 SOC_IF_ERROR_RETURN 290 (soc_reg32_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, port, 0, 291 TH3_AGG_ID_HW_INVALID)); 292 293 return BCM_E_NONE; 294 } 295 296 STATIC void 297 _bcm_th3_repl_list_recycle_candidate_deinit(int unit) 298 { 299 _bcm_repl_list_info_t *rli_current, *rli_free; 300 rli_current = _repl_list_recycle_array[unit]; 301 while(rli_current != NULL) { 302 rli_free = rli_current; 303 rli_current = rli_current->next; 304 sal_free(rli_free); 305 } 306 _repl_list_recycle_array[unit] = NULL; 307 } 308 309 STATIC int 310 _bcm_th3_repl_list_hw_in_use_check(int unit, 311 SHR_BITDCL *entry_vec, int *in_use) 312 { 313 314 int i, j, list_ptr_used; 315 uint32 entry_done, list_ptr; 316 mmu_repl_state_tbl_entry_t entry; 317 soc_mem_t repl_q_mem[] = {MMU_REPL_STATE_TBL_ITM0m, MMU_REPL_STATE_TBL_ITM1m}; 318 soc_info_t *si = &SOC_INFO(unit); 319 uint32 itm_map = si->itm_map; 320 321 for(i = 0; i < NUM_ITM(unit); i++) { 322 if (itm_map & (1U << i)) { 323 for(j = 0; j < _TH3_NUM_REPL_QUEUE; j++) { 324 list_ptr_used = 0; 325 SOC_IF_ERROR_RETURN(soc_mem_read(unit, repl_q_mem[i], 326 MEM_BLOCK_ANY, j, &entry)); 327 entry_done = soc_MMU_REPL_STATE_TBLm_field32_get(unit, &entry, 328 ENTRY_DONEf); 329 if(entry_done) { 330 continue; 331 } else { 332 list_ptr = soc_MMU_REPL_STATE_TBLm_field32_get(unit, 333 &entry, LIST_PTRf); 334 if(SHR_BITGET(entry_vec, list_ptr)) { 335 list_ptr_used = 1; 336 } 337 338 } 339 if(list_ptr_used) { 340 *in_use = list_ptr_used; 341 return BCM_E_NONE; 342 } 343 } 344 } 345 } 346 *in_use = 0; 347 return BCM_E_NONE; 348 } 349 350 STATIC int 351 _bcm_th3_repl_list_entry_vec_construct(int unit, SHR_BITDCL *entry_vec, 352 int start_ptr) 353 { 354 int prev_repl_entry_ptr, repl_entry_ptr; 355 soc_mem_t repl_list_table; 356 mmu_repl_list_tbl_entry_t repl_list_entry; 357 358 prev_repl_entry_ptr = -1; 359 repl_entry_ptr = start_ptr; 360 repl_list_table = MMU_REPL_LIST_TBLm; 361 /* get the entry vector based on the current candidate list */ 362 while (repl_entry_ptr != prev_repl_entry_ptr) { 363 SHR_BITSET(entry_vec, repl_entry_ptr); 364 SOC_IF_ERROR_RETURN 365 (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 366 repl_entry_ptr, &repl_list_entry)); 367 368 prev_repl_entry_ptr = repl_entry_ptr; 369 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 370 &repl_list_entry, NEXTPTRf); 371 } 372 return BCM_E_NONE; 373 374 } 375 376 STATIC int 377 _bcm_th3_repl_list_recycle(int unit, int *entry_id) 378 { 379 380 _bcm_repl_list_info_t *rli_current, *rli_prev; 381 int in_use; 382 383 rli_current = _repl_list_recycle_array[unit]->next; 384 rli_prev = NULL; 385 while (rli_current != NULL) { 386 387 SHR_BITDCL entry_vec[_TH3_REPL_LIST_ENTRY_UINT32_TOTAL] = {0}; 388 389 /* get the entry vector based on the current candidate list */ 390 BCM_IF_ERROR_RETURN 391 (_bcm_th3_repl_list_entry_vec_construct(unit, entry_vec, 392 rli_current->index)); 393 394 /* check if this list is still being used by HW */ 395 SOC_IF_ERROR_RETURN(_bcm_th3_repl_list_hw_in_use_check 396 (unit, entry_vec, &in_use)); 397 if(!in_use) { 398 /* recycle list */ 399 SOC_IF_ERROR_RETURN(_bcm_th_repl_list_free(unit, 0, 400 rli_current->index)); 401 *entry_id = rli_current->index; 402 if(rli_prev == NULL) { 403 _repl_list_recycle_array[unit]->next = rli_current->next; 404 } else { 405 rli_prev->next = rli_current->next; 406 } 407 (_repl_list_recycle_array[unit]->list_size)--; 408 sal_free(rli_current); 409 return BCM_E_NONE; 410 } 411 rli_prev = rli_current; 412 rli_current = rli_current->next; 413 } 414 *entry_id = -1; 415 return BCM_E_RESOURCE; 416 } 417 /* 418 * Function: 419 * _bcm_th3_repl_head_info_init 420 * Purpose: 421 * Initialize replication head info. 422 * Parameters: 423 * unit - (IN)SOC unit number. 424 * Returns: 425 * BCM_E_xxx 426 */ 427 STATIC int 428 _bcm_th3_repl_head_info_init(int unit) 429 { 430 int alloc_size; 431 int repl_head_tbl_size; 432 int max_array_index = 0; 433 soc_mem_t repl_head_table = MMU_REPL_HEAD_TBLm; 434 435 436 mmu_port_stride[unit] = SOC_TH3_MMU_PORT_STRIDE; 437 438 /* REPL_HEAD table is pipeline independent */ 439 alloc_size = sizeof(_th_repl_head_info_t); 440 if (NULL == _th_repl_head_info[unit]) { 441 _th_repl_head_info[unit] = sal_alloc(alloc_size, "repl_head_info"); 442 if (NULL == _th_repl_head_info[unit]) { 443 _bcm_th_repl_head_info_deinit(unit); 444 return BCM_E_MEMORY; 445 } 446 } 447 sal_memset(_th_repl_head_info[unit], 0, alloc_size); 448 449 450 if (NULL == _th_repl_head_info[unit][0].free_list_array) { 451 /* Each element of the array is a linked list of free blocks. 452 * Array element N is a linked list of free blocks of size N. 453 * When allocating a block of REPL_HEAD table entries, the max 454 * number of entries needed is equal to the max number of members 455 * in a replication group. This will also be the max index of the 456 * array. Of course, the REPL_HEAD table may contain bigger blocks 457 * of free entries. Array element 0 wil be a linked list of free 458 * blocks with size greater than the max number of members in a 459 * replication group. 460 */ 461 max_array_index = soc_mem_field_length(unit, 462 MMU_REPL_GROUP_INFO_TBLm, MEMBER_BMPf); 463 alloc_size = (max_array_index + 1) * 464 sizeof(_th_repl_head_free_block_t *); 465 _th_repl_head_info[unit][0].free_list_array = 466 sal_alloc(alloc_size, "repl head free list array"); 467 if (NULL == _th_repl_head_info[unit][0].free_list_array) { 468 _bcm_th_repl_head_info_deinit(unit); 469 return BCM_E_MEMORY; 470 } 471 _th_repl_head_info[unit][0].array_size = max_array_index + 1; 472 } 473 sal_memset(_th_repl_head_info[unit][0].free_list_array, 0, 474 alloc_size); 475 476 REPL_HEAD_FREE_LIST(unit, 0, 0) = 477 sal_alloc(sizeof(_th_repl_head_free_block_t), "repl head free block"); 478 if (NULL == REPL_HEAD_FREE_LIST(unit, 0, 0)) { 479 _bcm_th_repl_head_info_deinit(unit); 480 return BCM_E_MEMORY; 481 } 482 483 /* Initially, there is only one free block, starting at entry 1 of 484 * REPL_HEAD table and ending at the last entry. Entry 0 is reserved. 485 */ 486 REPL_HEAD_FREE_LIST(unit, 0, 0)->index = 1; 487 repl_head_tbl_size = 1 << soc_mem_field_length(unit, 488 MMU_REPL_GROUP_INFO_TBLm, BASE_PTRf); 489 REPL_HEAD_FREE_LIST(unit, 0, 0)->size = repl_head_tbl_size - 1; 490 REPL_HEAD_FREE_LIST(unit, 0, 0)->next = NULL; 491 492 /* Clear entry 0 of REPL_HEAD table */ 493 SOC_IF_ERROR_RETURN 494 (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0, 495 soc_mem_entry_null(unit, repl_head_table))); 496 497 return BCM_E_NONE; 498 } 499 500 STATIC int 501 _bcm_th3_repl_list_compare(int unit, int pipe, int start_ptr, 502 SHR_BITDCL *intf_vec) 503 { 504 505 soc_mem_t repl_list_table; 506 uint32 hw_msb; 507 uint32 hw_ls_bits[2]; 508 mmu_repl_list_tbl_entry_t repl_list_entry; 509 int i, repl_entry_ptr, prev_repl_entry_ptr; 510 SHR_BITDCL *hw_intf_vec = NULL; 511 int alloc_size; 512 int max_msb = -1; 513 uint32 repl_mode, mode_bitmap; 514 soc_field_t nh_fields[_TH3_NUM_NH_SPARSE_MODE] = { 515 NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f, 516 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f 517 }; 518 repl_list_table = MMU_REPL_LIST_TBLm; 519 prev_repl_entry_ptr = -1; 520 repl_entry_ptr = start_ptr; 521 522 alloc_size = SHR_BITALLOCSIZE(REPL_INTF_TOTAL(unit)); 523 hw_intf_vec = sal_alloc(alloc_size, "HW repl interface vector"); 524 if(hw_intf_vec == NULL) { 525 return BCM_E_MEMORY; 526 } 527 if(start_ptr < 0 ) { 528 return BCM_E_PARAM; 529 } 530 sal_memset(hw_intf_vec, 0, alloc_size); 531 /* first read out the entire repl list */ 532 while(repl_entry_ptr != prev_repl_entry_ptr) { 533 SOC_IF_ERROR_RETURN 534 (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 535 repl_entry_ptr, &repl_list_entry)); 536 repl_mode = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 537 &repl_list_entry, MODEf); 538 if(repl_mode) { 539 /* sparse mode */ 540 mode_bitmap = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 541 &repl_list_entry, MODE_1_BITMAPf); 542 for(i = 0; i < _TH3_NUM_NH_SPARSE_MODE; i++) { 543 if(mode_bitmap & (1U << i)) { 544 uint32 temp_nh = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 545 &repl_list_entry, nh_fields[i]); 546 SHR_BITSET(hw_intf_vec, temp_nh); 547 max_msb = (max_msb > (temp_nh / 64)) ? max_msb : 548 (temp_nh / 64); 549 } 550 } 551 } else { 552 /* dense mode */ 553 hw_msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 554 &repl_list_entry, MSB_VLANf); 555 max_msb = max_msb > hw_msb ? max_msb : hw_msb; 556 soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry, 557 LSB_VLAN_BMf, hw_ls_bits); 558 hw_intf_vec[2 * hw_msb + 0] |= hw_ls_bits[0]; 559 hw_intf_vec[2 * hw_msb + 1] |= hw_ls_bits[1]; 560 } 561 prev_repl_entry_ptr = repl_entry_ptr; 562 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 563 &repl_list_entry, NEXTPTRf); 564 565 } 566 /* compare two lists */ 567 for(i = 0; i < max_msb; i++) { 568 if((hw_intf_vec[2 * i] != intf_vec[2 * i]) 569 ||(hw_intf_vec[2 * i + 1] != intf_vec[2 * i + 1])) { 570 return BCM_E_NOT_FOUND; 571 } 572 } 573 return BCM_E_NONE; 574 } 575 576 /* return the pos of first bit 1 within an unsigned integer */ 577 STATIC int 578 _bcm_th3_uint32_first_bit_get(int unit, uint32 val) { 579 int i; 580 for(i = 0; i < 32; i++) { 581 if(val & (1U << i)) { 582 return i; 583 } 584 } 585 return -1; 586 } 587 588 STATIC void 589 _bcm_th3_nh_list_get(int unit, mmu_repl_list_tbl_entry_t *entry, int max_count, 590 uint32 *nh_list, uint32 *count) 591 { 592 uint32 l_count = 0; 593 uint32 ls_bits[2]; 594 uint32 msb, mode, mode_1_bm; 595 int i, ls_pos; 596 soc_field_t nh_fields[_TH3_NUM_NH_SPARSE_MODE] = { 597 NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f, 598 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f 599 }; 600 mode = soc_MMU_REPL_LIST_TBLm_field32_get(unit, entry, MODEf); 601 if(mode) { 602 /* sparse mode */ 603 mode_1_bm = soc_MMU_REPL_LIST_TBLm_field32_get(unit, entry, 604 MODE_1_BITMAPf); 605 for(i = 0; i < _TH3_NUM_NH_SPARSE_MODE; i++) { 606 if(mode_1_bm & (1U << i)) { 607 nh_list[l_count++] = soc_MMU_REPL_LIST_TBLm_field32_get 608 (unit, entry, nh_fields[i]); 609 } 610 if(l_count >= max_count) { 611 break; 612 } 613 } 614 615 } else { 616 /* dense mode */ 617 soc_MMU_REPL_LIST_TBLm_field_get(unit, entry, LSB_VLAN_BMf, ls_bits); 618 msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit, entry, 619 MSB_VLANf); 620 for (ls_pos = 0; ls_pos < 64; ls_pos++) { 621 if (ls_bits[ls_pos / 32] & (1 << (ls_pos % 32))) { 622 623 nh_list[l_count++] = msb * 64 + ls_pos; 624 } 625 if(l_count >= max_count) { 626 break; 627 } 628 } 629 } 630 *count = l_count; 631 } 632 633 STATIC void 634 _bcm_th3_ls_bit_pos_get(int unit, uint32 ls_bits[2], int *ls_bit_pos) 635 { 636 *ls_bit_pos = -1; 637 if (ls_bits[0] != 0) { 638 *ls_bit_pos = _bcm_th3_uint32_first_bit_get(unit, 639 ls_bits[0]); 640 } 641 else if (ls_bits[1] != 0) { 642 *ls_bit_pos = _TH3_IPMC_UINT32_LEN 643 + _bcm_th3_uint32_first_bit_get(unit, 644 ls_bits[1]); 645 } 646 } 647 /* 648 * Function: 649 * _bcm_th3_repl_list_write 650 * Purpose: 651 * Write the replication list contained in intf_vec into REPL_LIST table. 652 * Return the start_ptr and total interface count. 653 * Parameters: 654 * unit - StrataSwitch PCI device unit number. 655 * pipe - Pipeline number. 656 * start_ptr - (OUT) Replication list's start pointer to 657 * REPL_LIST table. 658 * intf_count - (OUT) Interface count. 659 * intf_vec - (IN) Vector of interfaces. 660 * Returns: 661 * BCM_E_XXX 662 */ 663 STATIC int 664 _bcm_th3_repl_list_write(int unit, int pipe, int *start_ptr, int *intf_count, 665 SHR_BITDCL *intf_vec) 666 { 667 int i; 668 int remaining_count; 669 int prev_repl_entry_ptr, repl_entry_ptr; 670 uint32 msb_max, msb; 671 uint32 ls_bits[2]; 672 int rv = BCM_E_NONE; 673 int no_more_free_repl_entries; 674 mmu_repl_list_tbl_entry_t repl_list_entry; 675 soc_mem_t repl_list_table; 676 int max_rem_count = 31; 677 int ls_bit_pos, nh_id; 678 uint32 nh_list[_TH3_IPMC_MIN_INTF_COUNT]; 679 uint32 prev_count = 0; 680 soc_field_t nh_fields[_TH3_NUM_NH_SPARSE_MODE] = { 681 NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f, 682 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f 683 }; 684 685 *intf_count = 0; 686 for (i = 0; i < _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)); i++) { 687 *intf_count += _shr_popcount(intf_vec[i]); 688 } 689 690 if (*intf_count == 0) { 691 return BCM_E_NONE; 692 } 693 repl_list_table = MMU_REPL_LIST_TBLm; 694 pipe = 0; 695 remaining_count = *intf_count; 696 prev_repl_entry_ptr = -1; 697 msb_max = _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)) / 2; /* 32 -> 64 */ 698 for (msb = 0; msb < msb_max; msb++) { 699 ls_bits[0] = intf_vec[2 * msb + 0]; 700 ls_bits[1] = intf_vec[2 * msb + 1]; 701 if ((ls_bits[0] != 0) || (ls_bits[1] != 0)) { 702 rv = _bcm_th_repl_list_entry_alloc(unit, pipe, &repl_entry_ptr); 703 if (rv == BCM_E_RESOURCE) { 704 no_more_free_repl_entries = TRUE; 705 } else if (BCM_FAILURE(rv)) { 706 return rv; 707 } else { 708 no_more_free_repl_entries = FALSE; 709 } 710 if (prev_repl_entry_ptr == -1) { 711 if (no_more_free_repl_entries) { 712 return BCM_E_RESOURCE; 713 } 714 *start_ptr = repl_entry_ptr; 715 } else { 716 if (no_more_free_repl_entries) { 717 /* Terminate replication list */ 718 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 719 NEXTPTRf, prev_repl_entry_ptr); 720 } else { 721 /* check the intf count in the previous list */ 722 uint32 mode_bitmap = 0; 723 _bcm_th3_nh_list_get(unit, &repl_list_entry, 724 _TH3_IPMC_MIN_INTF_COUNT, nh_list, &prev_count); 725 726 if (prev_count < _TH3_IPMC_MIN_INTF_COUNT) { 727 /* convert to sparse mode when count < 4 */ 728 /* rewrite previous entry */ 729 for(i = 0; i < prev_count; i++) { 730 soc_MMU_REPL_LIST_TBLm_field32_set(unit, 731 &repl_list_entry, nh_fields[i], nh_list[i]); 732 mode_bitmap |= (1U << i); 733 } 734 /* borrow NH ids from the current list */ 735 for(i = prev_count; i < _TH3_NUM_NH_SPARSE_MODE; i++) { 736 _bcm_th3_ls_bit_pos_get(unit, ls_bits, &ls_bit_pos); 737 if(ls_bit_pos == -1) { 738 /* no more NH id in the current list */ 739 break; 740 } 741 nh_id = msb * TH3_IPMC_MAX_INTF_COUNT_PER_ENTRY 742 + ls_bit_pos; 743 744 mode_bitmap |= (1U << i); 745 soc_MMU_REPL_LIST_TBLm_field32_set(unit, 746 &repl_list_entry, nh_fields[i], nh_id); 747 /* remove borrowed NH id from current lists */ 748 ls_bits[ls_bit_pos / 32] &= 749 ~(1U << (ls_bit_pos % 32)); 750 751 } 752 753 soc_MMU_REPL_LIST_TBLm_field32_set(unit, 754 &repl_list_entry, MODE_1_BITMAPf, mode_bitmap); 755 soc_MMU_REPL_LIST_TBLm_field32_set(unit, 756 &repl_list_entry, MODEf, 0x1); 757 /*update remaining count */ 758 remaining_count = remaining_count - (i - prev_count); 759 if ( remaining_count > max_rem_count) { 760 /* Set the RMNG_REPS field to all zeroes */ 761 soc_MMU_REPL_LIST_TBLm_field32_set(unit, 762 &repl_list_entry, RMNG_REPSf, 0); 763 } else if(remaining_count > 0){ 764 soc_MMU_REPL_LIST_TBLm_field32_set(unit, 765 &repl_list_entry, 766 RMNG_REPSf, remaining_count); 767 } else { 768 break; 769 } 770 if(i < _TH3_NUM_NH_SPARSE_MODE) { 771 /* no NH id in the current list */ 772 _bcm_th_repl_list_entry_free(unit, pipe, repl_entry_ptr); 773 continue; 774 } 775 776 } 777 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 778 NEXTPTRf, repl_entry_ptr); 779 780 } 781 SOC_IF_ERROR_RETURN 782 (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL, 783 prev_repl_entry_ptr, &repl_list_entry)); 784 if (no_more_free_repl_entries) { 785 /* Free the list already written */ 786 _bcm_th_repl_list_free(unit, pipe, *start_ptr); 787 return BCM_E_RESOURCE; 788 } 789 } 790 prev_repl_entry_ptr = repl_entry_ptr; 791 sal_memset(&repl_list_entry, 0, sizeof(repl_list_entry)); 792 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 793 MSB_VLANf, msb); 794 soc_MMU_REPL_LIST_TBLm_field_set(unit, &repl_list_entry, 795 LSB_VLAN_BMf, ls_bits); 796 797 remaining_count -= (_shr_popcount(ls_bits[0]) + 798 _shr_popcount(ls_bits[1])); 799 if (remaining_count > max_rem_count) { 800 /* Set the RMNG_REPS field to all zeroes */ 801 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 802 RMNG_REPSf, 0); 803 } else if (remaining_count > 0) { 804 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 805 RMNG_REPSf, remaining_count); 806 } else { /* No more intefaces left to be written */ 807 break; 808 } 809 } 810 } 811 812 if (prev_repl_entry_ptr > 0) { 813 /* Write final entry */ 814 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, NEXTPTRf, 815 prev_repl_entry_ptr); 816 SOC_IF_ERROR_RETURN 817 (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL, 818 prev_repl_entry_ptr, &repl_list_entry)); 819 } 820 821 return BCM_E_NONE; 822 } 823 824 STATIC int 825 _bcm_th3_sparse_mode_egress_intf_get(int unit, int repl_entry_ptr, 826 int nh_id, bcm_if_t *if_array, int *if_count) 827 { 828 soc_mem_t mem = MMU_REPL_LIST_TBLm; 829 int entry_type; 830 uint32 mode_bitmap, nh_val, l3_intf; 831 mmu_repl_list_tbl_entry_t repl_list_entry; 832 egr_l3_next_hop_2_entry_t egr_nh2; 833 egr_l3_next_hop_entry_t egr_nh; 834 soc_field_t nh_fields[4] = {NEXT_HOP_INDEX_0f, NEXT_HOP_INDEX_1f, 835 NEXT_HOP_INDEX_2f, NEXT_HOP_INDEX_3f}; 836 837 SOC_IF_ERROR_RETURN 838 (soc_mem_read(unit, mem, MEM_BLOCK_ANY, 839 repl_entry_ptr, &repl_list_entry)); 840 841 mode_bitmap = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 842 &repl_list_entry, MODE_1_BITMAPf); 843 if(mode_bitmap & (1U << nh_id)) { 844 nh_val = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 845 &repl_list_entry, nh_fields[nh_id]); 846 if_array[*if_count] = nh_val + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 847 848 SOC_IF_ERROR_RETURN( 849 READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, 850 nh_val, &egr_nh)); 851 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, 852 &egr_nh, ENTRY_TYPEf); 853 854 SOC_IF_ERROR_RETURN( 855 READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY, 856 nh_val, &egr_nh2)); 857 858 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, 859 &egr_nh2, INTF_NUMf); 860 if(entry_type == 0) { 861 if (REPL_L3_INTF_NEXT_HOP_TRILL(unit, l3_intf) == 862 nh_val) { 863 if_array[*if_count] = l3_intf; 864 } 865 } else if (entry_type == 3) { 866 867 if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) == nh_val) { 868 if_array[*if_count] = l3_intf; 869 } 870 871 } 872 (*if_count)++; 873 } 874 875 return BCM_E_NONE; 876 } 877 878 STATIC int 879 _bcm_th3_ipmc_egress_intf_add_for_trunk(int unit, int repl_group, 880 bcm_trunk_t tgid, int encap_id, int is_l3) 881 { 882 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) 883 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0}; 884 int max_num_ports = SOC_MAX_NUM_PP_PORTS; 885 #else 886 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0}; 887 int max_num_ports = SOC_MAX_NUM_PORTS; 888 #endif 889 890 int idx; 891 int member_count, port_iter; 892 int aggid; 893 int old_intf_count, new_intf_count, diff_count = 0; 894 BCM_IF_ERROR_RETURN( 895 _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports, 896 trunk_local_member_ports, 897 &member_count)); 898 899 for (idx = 0; idx < member_count; idx++) { 900 port_iter = trunk_local_member_ports[idx]; 901 if (REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) == 0) { 902 BCM_IF_ERROR_RETURN( 903 bcm_th_port_aggid_add(unit, port_iter, tgid, &aggid)); 904 } 905 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group); 906 907 if(idx == 0) { 908 /* all ports within the trunk should mapped to the same AGG_ID 909 * encap ID only needs to be inserted once 910 */ 911 BCM_IF_ERROR_RETURN( 912 _bcm_th_ipmc_egress_intf_add( 913 unit, repl_group, port_iter, encap_id, is_l3)); 914 new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group); 915 diff_count = new_intf_count - old_intf_count; 916 } else { 917 new_intf_count = old_intf_count + diff_count; 918 REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) = 919 new_intf_count; 920 } 921 922 } 923 924 return BCM_E_NONE; 925 } 926 927 STATIC int 928 _bcm_th3_ipmc_egress_intf_del_for_trunk(int unit, int repl_group, 929 bcm_trunk_t tgid, int if_max, int encap_id, int is_l3) 930 { 931 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) 932 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0}; 933 int max_num_ports = SOC_MAX_NUM_PP_PORTS; 934 #else 935 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0}; 936 int max_num_ports = SOC_MAX_NUM_PORTS; 937 #endif 938 939 int idx; 940 int member_count, port_iter; 941 int old_intf_count, new_intf_count, diff_count = 0; 942 943 BCM_IF_ERROR_RETURN( 944 _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports, 945 trunk_local_member_ports, 946 &member_count)); 947 948 for (idx = 0; idx < member_count; idx++) { 949 port_iter = trunk_local_member_ports[idx]; 950 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group); 951 if (idx == 0) { 952 BCM_IF_ERROR_RETURN( 953 _bcm_th_ipmc_egress_intf_delete( 954 unit, repl_group, trunk_local_member_ports[idx], 955 if_max, encap_id, is_l3)); 956 new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group); 957 diff_count = old_intf_count - new_intf_count; 958 } else { 959 new_intf_count = old_intf_count - diff_count; 960 REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) = 961 new_intf_count; 962 } 963 if (new_intf_count == 0 && old_intf_count > 0) { 964 BCM_IF_ERROR_RETURN( 965 bcm_th_port_aggid_del(unit, port_iter)); 966 } 967 968 } 969 970 return BCM_E_NONE; 971 } 972 973 STATIC int 974 _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member( 975 int unit, int repl_group, bcm_port_t port, 976 bcm_port_t first_port, bcm_trunk_t tgid) 977 { 978 int aggid; 979 int old_intf_count, new_intf_count; 980 981 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 982 new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, first_port, repl_group); 983 if (old_intf_count == new_intf_count) { 984 return BCM_E_NONE; 985 } 986 987 if ((old_intf_count == 0) && (new_intf_count > 0)) { 988 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_add(unit, port, tgid, &aggid)); 989 } else if ((old_intf_count > 0) && (new_intf_count == 0)) { 990 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port)); 991 } 992 993 REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = new_intf_count; 994 995 return BCM_E_NONE; 996 } 997 #endif 998 999 /* -------------------------------------------------------------- 1000 * The following set of routines manage REPL_HEAD table resource. 1001 * -------------------------------------------------------------- 1002 */ 1003 1004 /* 1005 * Function: 1006 * _bcm_th_repl_head_info_deinit 1007 * Purpose: 1008 * De-initialize replication head info. 1009 * Parameters: 1010 * unit - (IN)SOC unit number. 1011 * Returns: 1012 * None 1013 */ 1014 STATIC void 1015 _bcm_th_repl_head_info_deinit(int unit) 1016 { 1017 int pipe, i; 1018 _th_repl_head_free_block_t *block_ptr; 1019 _th_repl_head_free_block_t *next_block_ptr; 1020 1021 if (NULL != _th_repl_head_info[unit]) { 1022 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 1023 if (NULL != _th_repl_head_info[unit][pipe].free_list_array) { 1024 for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) { 1025 block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i); 1026 while (NULL != block_ptr) { 1027 next_block_ptr = block_ptr->next; 1028 sal_free(block_ptr); 1029 block_ptr = next_block_ptr; 1030 } 1031 REPL_HEAD_FREE_LIST(unit, pipe, i) = NULL; 1032 } 1033 sal_free(_th_repl_head_info[unit][pipe].free_list_array); 1034 _th_repl_head_info[unit][pipe].free_list_array = NULL; 1035 _th_repl_head_info[unit][pipe].array_size = 0; 1036 } 1037 1038 } 1039 sal_free(_th_repl_head_info[unit]); 1040 _th_repl_head_info[unit] = NULL; 1041 } 1042 } 1043 1044 /* 1045 * Function: 1046 * _bcm_th_repl_head_info_init 1047 * Purpose: 1048 * Initialize replication head info. 1049 * Parameters: 1050 * unit - (IN)SOC unit number. 1051 * Returns: 1052 * BCM_E_xxx 1053 */ 1054 STATIC int 1055 _bcm_th_repl_head_info_init(int unit) 1056 { 1057 int alloc_size; 1058 int pipe; 1059 int max_array_index = 0; 1060 int per_pipe_repl_head_tbl_size; 1061 soc_mem_t repl_head_table; 1062 1063 #ifdef BCM_TRIDENT3_SUPPORT 1064 if (SOC_IS_TRIDENT3X(unit)) { 1065 mmu_port_stride[unit] = _TD3_TDM_MMU_PORTS_PER_DEV; 1066 } else 1067 #endif /* BCM_TRIDENT3_SUPPORT */ 1068 { 1069 mmu_port_stride[unit] = SOC_TH_MMU_PORT_STRIDE; 1070 } 1071 1072 /* Each pipeline has its own REPL_HEAD table. */ 1073 alloc_size = NUM_PIPES(unit) * sizeof(_th_repl_head_info_t); 1074 if (NULL == _th_repl_head_info[unit]) { 1075 _th_repl_head_info[unit] = sal_alloc(alloc_size, "repl_head_info"); 1076 if (NULL == _th_repl_head_info[unit]) { 1077 _bcm_th_repl_head_info_deinit(unit); 1078 return BCM_E_MEMORY; 1079 } 1080 } 1081 sal_memset(_th_repl_head_info[unit], 0, alloc_size); 1082 1083 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 1084 1085 if (NULL == _th_repl_head_info[unit][pipe].free_list_array) { 1086 /* Each element of the array is a linked list of free blocks. 1087 * Array element N is a linked list of free blocks of size N. 1088 * When allocating a block of REPL_HEAD table entries, the max 1089 * number of entries needed is equal to the max number of members 1090 * in a replication group. This will also be the max index of the 1091 * array. Of course, the REPL_HEAD table may contain bigger blocks 1092 * of free entries. Array element 0 wil be a linked list of free 1093 * blocks with size greater than the max number of members in a 1094 * replication group. 1095 */ 1096 max_array_index = soc_mem_field_length(unit, 1097 MMU_REPL_GROUP_INFO_TBLm, PIPE_MEMBER_BMPf); 1098 alloc_size = (max_array_index + 1) * 1099 sizeof(_th_repl_head_free_block_t *); 1100 _th_repl_head_info[unit][pipe].free_list_array = 1101 sal_alloc(alloc_size, "repl head free list array"); 1102 if (NULL == _th_repl_head_info[unit][pipe].free_list_array) { 1103 _bcm_th_repl_head_info_deinit(unit); 1104 return BCM_E_MEMORY; 1105 } 1106 _th_repl_head_info[unit][pipe].array_size = max_array_index + 1; 1107 } 1108 sal_memset(_th_repl_head_info[unit][pipe].free_list_array, 0, 1109 alloc_size); 1110 1111 REPL_HEAD_FREE_LIST(unit, pipe, 0) = 1112 sal_alloc(sizeof(_th_repl_head_free_block_t), "repl head free block"); 1113 if (NULL == REPL_HEAD_FREE_LIST(unit, pipe, 0)) { 1114 _bcm_th_repl_head_info_deinit(unit); 1115 return BCM_E_MEMORY; 1116 } 1117 1118 /* Initially, there is only one free block, starting at entry 1 of 1119 * REPL_HEAD table and ending at the last entry. Entry 0 is reserved. 1120 */ 1121 REPL_HEAD_FREE_LIST(unit, pipe, 0)->index = 1; 1122 per_pipe_repl_head_tbl_size = 1 << soc_mem_field_length(unit, 1123 MMU_REPL_GROUP_INFO_TBLm, PIPE_BASE_PTRf); 1124 REPL_HEAD_FREE_LIST(unit, pipe, 0)->size = 1125 per_pipe_repl_head_tbl_size - 1; 1126 REPL_HEAD_FREE_LIST(unit, pipe, 0)->next = NULL; 1127 1128 if (soc_feature(unit, soc_feature_split_repl_head_table)) { 1129 repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe); 1130 SOC_IF_ERROR_RETURN 1131 (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0, 1132 soc_mem_entry_null(unit, repl_head_table))); 1133 repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe); 1134 SOC_IF_ERROR_RETURN 1135 (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0, 1136 soc_mem_entry_null(unit, repl_head_table))); 1137 1138 } else { 1139 repl_head_table = REPL_HEAD_TBL_PIPE(unit, pipe); 1140 /* Clear entry 0 of REPL_HEAD table */ 1141 SOC_IF_ERROR_RETURN 1142 (soc_mem_write(unit, repl_head_table, MEM_BLOCK_ALL, 0, 1143 soc_mem_entry_null(unit, repl_head_table))); 1144 } 1145 } 1146 1147 return BCM_E_NONE; 1148 } 1149 1150 /* 1151 * Function: 1152 * _bcm_th_repl_head_block_free 1153 * Purpose: 1154 * Free a block of REPL_HEAD table entries. 1155 * Parameters: 1156 * unit - (IN) SOC unit number. 1157 * pipe - (IN) Pipeline number. 1158 * index - (IN) Index of the first entry of the block. 1159 * size - (IN) Size of the block. 1160 * Returns: 1161 * BCM_E_xxx 1162 */ 1163 STATIC int 1164 _bcm_th_repl_head_block_free(int unit, int pipe, int index, int size) 1165 { 1166 int i; 1167 int block_index, block_size; 1168 int coalesced_index, coalesced_size; 1169 _th_repl_head_free_block_t *block_ptr; 1170 _th_repl_head_free_block_t *prev_block_ptr; 1171 _th_repl_head_free_block_t *next_block_ptr; 1172 _th_repl_head_free_block_t *coalesced_block_ptr; 1173 1174 if (size <= 0) { 1175 return BCM_E_INTERNAL; 1176 } 1177 1178 /* First, coalesce the block with any existing free blocks 1179 * that are contiguous with the block. 1180 */ 1181 coalesced_index = index; 1182 coalesced_size = size; 1183 for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) { 1184 block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i); 1185 prev_block_ptr = NULL; 1186 while (NULL != block_ptr) { 1187 block_index = block_ptr->index; 1188 block_size = block_ptr->size; 1189 next_block_ptr = block_ptr->next; 1190 if ((block_index + block_size) == coalesced_index) { 1191 coalesced_index = block_index; 1192 coalesced_size += block_size; 1193 if (block_ptr == REPL_HEAD_FREE_LIST(unit, pipe, i)) { 1194 REPL_HEAD_FREE_LIST(unit, pipe, i) = next_block_ptr; 1195 } else { 1196 /* 1197 * In the following line of code, Coverity thinks the 1198 * prev_block_ptr may still be NULL when dereferenced. 1199 * This situation will never occur because 1200 * if block_ptr is not pointing to the head of the 1201 * linked list, prev_block_ptr would not be NULL. 1202 */ 1203 /* coverity[var_deref_op : FALSE] */ 1204 prev_block_ptr->next = next_block_ptr; 1205 } 1206 sal_free(block_ptr); 1207 } else if ((coalesced_index + coalesced_size) == block_index) { 1208 coalesced_size += block_size; 1209 if (block_ptr == REPL_HEAD_FREE_LIST(unit, pipe, i)) { 1210 REPL_HEAD_FREE_LIST(unit, pipe, i) = next_block_ptr; 1211 } else { 1212 /* 1213 * In the following line of code, Coverity thinks the 1214 * prev_block_ptr may still be NULL when dereferenced. 1215 * This situation will never occur because 1216 * if block_ptr is not pointing to the head of the 1217 * linked list, prev_block_ptr would not be NULL. 1218 */ 1219 /* coverity[var_deref_op : FALSE] */ 1220 prev_block_ptr->next = next_block_ptr; 1221 } 1222 sal_free(block_ptr); 1223 } else { 1224 prev_block_ptr = block_ptr; 1225 } 1226 block_ptr = next_block_ptr; 1227 } 1228 } 1229 1230 /* Insert coalesced free block */ 1231 coalesced_block_ptr = sal_alloc(sizeof(_th_repl_head_free_block_t), 1232 "coalesced repl head free block"); 1233 if (NULL == coalesced_block_ptr) { 1234 return BCM_E_MEMORY; 1235 } 1236 coalesced_block_ptr->index = coalesced_index; 1237 coalesced_block_ptr->size = coalesced_size; 1238 if (coalesced_size > (_th_repl_head_info[unit][pipe].array_size - 1)) { 1239 /* Insert into free list 0 */ 1240 coalesced_block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe, 0); 1241 REPL_HEAD_FREE_LIST(unit, pipe, 0) = coalesced_block_ptr; 1242 } else { 1243 coalesced_block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe, 1244 coalesced_size); 1245 REPL_HEAD_FREE_LIST(unit, pipe, coalesced_size) = coalesced_block_ptr; 1246 } 1247 1248 return BCM_E_NONE; 1249 } 1250 1251 /* 1252 * Function: 1253 * _bcm_th_repl_head_block_alloc 1254 * Purpose: 1255 * Allocate a free block of REPL_HEAD table entries. 1256 * Parameters: 1257 * unit - (IN) SOC unit number. 1258 * pipe - (IN) Pipeline number. 1259 * size - (IN) Size of free block requested. 1260 * index - (OUT) Index of the first entry of the free block. 1261 * Returns: 1262 * BCM_E_xxx 1263 */ 1264 STATIC int 1265 _bcm_th_repl_head_block_alloc(int unit, int pipe, int size, int *index) 1266 { 1267 int max_array_index; 1268 int i; 1269 int block_index, block_size; 1270 _th_repl_head_free_block_t *next_block_ptr; 1271 1272 if (size == 0) { 1273 return BCM_E_PARAM; 1274 } 1275 if (NULL == index) { 1276 return BCM_E_PARAM; 1277 } 1278 1279 max_array_index = _th_repl_head_info[unit][pipe].array_size - 1; 1280 for (i = size; i <= max_array_index; i++) { 1281 if (NULL != REPL_HEAD_FREE_LIST(unit, pipe, i)) { 1282 block_index = REPL_HEAD_FREE_LIST(unit, pipe, i)->index; 1283 block_size = REPL_HEAD_FREE_LIST(unit, pipe, i)->size; 1284 next_block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i)->next; 1285 sal_free(REPL_HEAD_FREE_LIST(unit, pipe, i)); 1286 REPL_HEAD_FREE_LIST(unit, pipe, i) = next_block_ptr; 1287 1288 /* If the obtained free block contains more entries 1289 * than requested, insert the remainder back into 1290 * the free list array. 1291 */ 1292 if (block_size > size) { 1293 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit, 1294 pipe, block_index + size, block_size - size)); 1295 } 1296 1297 *index = block_index; 1298 return BCM_E_NONE; 1299 } 1300 } 1301 1302 /* Get free block from free list 0 */ 1303 if (NULL != REPL_HEAD_FREE_LIST(unit, pipe, 0)) { 1304 block_index = REPL_HEAD_FREE_LIST(unit, pipe, 0)->index; 1305 block_size = REPL_HEAD_FREE_LIST(unit, pipe, 0)->size; 1306 next_block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, 0)->next; 1307 if (block_size < size) { 1308 /* Free blocks on list 0 should never be 1309 * smaller than requested size. 1310 */ 1311 return BCM_E_INTERNAL; 1312 } 1313 1314 sal_free(REPL_HEAD_FREE_LIST(unit, pipe, 0)); 1315 REPL_HEAD_FREE_LIST(unit, pipe, 0) = next_block_ptr; 1316 1317 /* If the obtained free block contains more entries 1318 * than requested, insert the remainder back into 1319 * the free list array. 1320 */ 1321 if (block_size > size) { 1322 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit, 1323 pipe, block_index + size, block_size - size)); 1324 } 1325 1326 *index = block_index; 1327 return BCM_E_NONE; 1328 } 1329 1330 /* No free block of sufficient size can be found */ 1331 return BCM_E_RESOURCE; 1332 } 1333 1334 #ifdef BCM_WARM_BOOT_SUPPORT 1335 1336 /* 1337 * Function: 1338 * _bcm_th_ipmc_repl_l3_intf_scache_size_get 1339 * Purpose: 1340 * Get the required scache size for storing a bitmap 1341 * of L3 interfaces. 1342 * Parameters: 1343 * unit - StrataSwitch unit # 1344 * size - (OUT) Number of bytes 1345 * Returns: 1346 * BCM_E_xxx 1347 */ 1348 int 1349 _bcm_th_ipmc_repl_l3_intf_scache_size_get( 1350 int unit, 1351 uint32 *size) 1352 { 1353 int num_l3_intf; 1354 1355 *size = 0; 1356 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1357 *size += SHR_BITALLOCSIZE(num_l3_intf); 1358 1359 return BCM_E_NONE; 1360 } 1361 1362 /* 1363 * Function: 1364 * _bcm_th_ipmc_repl_l3_intf_sync 1365 * Purpose: 1366 * Record L3 interface bitmap into the scache. 1367 * Parameters: 1368 * unit - StrataSwitch unit # 1369 * scache_ptr - (IN/OUT) Scache pointer 1370 * Returns: 1371 * BCM_E_xxx 1372 */ 1373 int 1374 _bcm_th_ipmc_repl_l3_intf_sync( 1375 int unit, 1376 uint8 **scache_ptr) 1377 { 1378 int num_l3_intf, i; 1379 SHR_BITDCL *l3_intf_bitmap = NULL; 1380 1381 REPL_INIT(unit); 1382 /* Create a bitmap of L3 interfaces */ 1383 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1384 l3_intf_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_intf), 1385 "L3 interface bitmap"); 1386 if (NULL == l3_intf_bitmap) { 1387 return BCM_E_MEMORY; 1388 } 1389 sal_memset(l3_intf_bitmap, 0, SHR_BITALLOCSIZE(num_l3_intf)); 1390 1391 /* For the L3 interfaces that were allocated next hop indices by 1392 * bcm_l3_egress_create API, set the bit in the bitmap. 1393 */ 1394 for (i = 0; i < num_l3_intf; i++) { 1395 if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, i) == 1396 REPL_NH_INDEX_L3_EGRESS_ALLOCATED) { 1397 SHR_BITSET(l3_intf_bitmap, i); 1398 } 1399 } 1400 1401 /* Store the bitmap into scache */ 1402 sal_memcpy((*scache_ptr), l3_intf_bitmap, SHR_BITALLOCSIZE(num_l3_intf)); 1403 (*scache_ptr) += SHR_BITALLOCSIZE(num_l3_intf); 1404 1405 sal_free(l3_intf_bitmap); 1406 return BCM_E_NONE; 1407 } 1408 1409 /* 1410 * Function: 1411 * _bcm_th_ipmc_repl_l3_intf_scache_recover 1412 * Purpose: 1413 * Recover L3 interface bitmap from scache. 1414 * Parameters: 1415 * unit - (IN) SOC unit number. 1416 * scache_ptr - (IN/OUT) Scache pointer 1417 * Returns: 1418 * BCM_E_XXX 1419 */ 1420 int 1421 _bcm_th_ipmc_repl_l3_intf_scache_recover(int unit, uint8 **scache_ptr) 1422 { 1423 int num_l3_intf, i; 1424 SHR_BITDCL *l3_intf_bitmap = NULL; 1425 1426 /* Recover L3 interface bitmap */ 1427 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1428 l3_intf_bitmap = sal_alloc(SHR_BITALLOCSIZE(num_l3_intf), 1429 "L3 interface bitmap"); 1430 if (NULL == l3_intf_bitmap) { 1431 return BCM_E_MEMORY; 1432 } 1433 sal_memcpy(l3_intf_bitmap, (*scache_ptr), SHR_BITALLOCSIZE(num_l3_intf)); 1434 (*scache_ptr) += SHR_BITALLOCSIZE(num_l3_intf); 1435 1436 for (i = 0; i < num_l3_intf; i++) { 1437 if (SHR_BITGET(l3_intf_bitmap, i)) { 1438 REPL_L3_INTF_NEXT_HOP_IPMC(unit, i) = 1439 REPL_NH_INDEX_L3_EGRESS_ALLOCATED; 1440 } 1441 } 1442 1443 sal_free(l3_intf_bitmap); 1444 return BCM_E_NONE; 1445 } 1446 1447 /* 1448 * Function: 1449 * _bcm_th_ipmc_repl_l3_intf_nh_map_scache_size_get 1450 * Purpose: 1451 * Get the required scache size for storing map from L3 interfaces 1452 * to SDK managed next hop. 1453 * Parameters: 1454 * unit - StrataSwitch unit # 1455 * size - (OUT) Number of bytes 1456 * Returns: 1457 * BCM_E_xxx 1458 */ 1459 int 1460 _bcm_th_ipmc_repl_l3_intf_nh_map_scache_size_get( 1461 int unit, 1462 uint32 *size) 1463 { 1464 int num_l3_intf; 1465 1466 *size = 0; 1467 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1468 *size += (num_l3_intf * sizeof(int)); 1469 1470 return BCM_E_NONE; 1471 } 1472 1473 /* 1474 * Function: 1475 * _bcm_th_ipmc_repl_l3_intf_nh_map_sync 1476 * Purpose: 1477 * Record L3 interface map to SDK managed nexthop into the scache. 1478 * Parameters: 1479 * unit - StrataSwitch unit # 1480 * scache_ptr - (IN/OUT) Scache pointer 1481 * Returns: 1482 * BCM_E_xxx 1483 */ 1484 int 1485 _bcm_th_ipmc_repl_l3_intf_nh_map_sync( 1486 int unit, 1487 uint8 **scache_ptr) 1488 { 1489 int num_l3_intf, i; 1490 1491 REPL_INIT(unit); 1492 1493 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1494 1495 for (i = 0; i < num_l3_intf; i++) { 1496 *(int *) (*scache_ptr) = REPL_L3_INTF_NEXT_HOP_IPMC(unit, i); 1497 (*scache_ptr) += sizeof(int); 1498 } 1499 1500 return BCM_E_NONE; 1501 } 1502 1503 /* 1504 * Function: 1505 * _bcm_th_ipmc_repl_l3_intf_nh_map_scache_recover 1506 * Purpose: 1507 * Recover L3 interface nexthop map from scache. 1508 * Parameters: 1509 * unit - (IN) SOC unit number. 1510 * scache_ptr - (IN/OUT) Scache pointer 1511 * Returns: 1512 * BCM_E_XXX 1513 */ 1514 int 1515 _bcm_th_ipmc_repl_l3_intf_nh_map_scache_recover(int unit, uint8 **scache_ptr) 1516 { 1517 int num_l3_intf, i; 1518 1519 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1520 1521 for (i = 0; i < num_l3_intf; i++) { 1522 REPL_L3_INTF_NEXT_HOP_IPMC(unit, i) = *(int *)(*scache_ptr); 1523 (*scache_ptr) += sizeof(int); 1524 } 1525 1526 return BCM_E_NONE; 1527 } 1528 1529 /* 1530 * Function: 1531 * _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_size_get 1532 * Purpose: 1533 * Get the required scache size for storing map from L3 interfaces 1534 * to SDK managed trill next hop. 1535 * Parameters: 1536 * unit - StrataSwitch unit # 1537 * size - (OUT) Number of bytes 1538 * Returns: 1539 * BCM_E_xxx 1540 */ 1541 int 1542 _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_size_get( 1543 int unit, 1544 uint32 *size) 1545 { 1546 int num_l3_intf; 1547 1548 *size = 0; 1549 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1550 *size += (num_l3_intf * sizeof(int)); 1551 1552 return BCM_E_NONE; 1553 } 1554 1555 /* 1556 * Function: 1557 * _bcm_th_ipmc_repl_l3_intf_trill_nh_map_sync 1558 * Purpose: 1559 * Record L3 interface map to SDK managed trill nexthop into the scache. 1560 * Parameters: 1561 * unit - StrataSwitch unit # 1562 * scache_ptr - (IN/OUT) Scache pointer 1563 * Returns: 1564 * BCM_E_xxx 1565 */ 1566 int 1567 _bcm_th_ipmc_repl_l3_intf_trill_nh_map_sync( 1568 int unit, 1569 uint8 **scache_ptr) 1570 { 1571 int num_l3_intf, i; 1572 1573 REPL_INIT(unit); 1574 1575 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1576 1577 for (i = 0; i < num_l3_intf; i++) { 1578 *(int *) (*scache_ptr) = REPL_L3_INTF_NEXT_HOP_TRILL(unit, i); 1579 (*scache_ptr) += sizeof(int); 1580 } 1581 1582 return BCM_E_NONE; 1583 } 1584 1585 /* 1586 * Function: 1587 * _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_recover 1588 * Purpose: 1589 * Recover L3 interface trill nexthop map from scache. 1590 * Parameters: 1591 * unit - (IN) SOC unit number. 1592 * scache_ptr - (IN/OUT) Scache pointer 1593 * Returns: 1594 * BCM_E_XXX 1595 */ 1596 int 1597 _bcm_th_ipmc_repl_l3_intf_trill_nh_map_scache_recover(int unit, uint8 **scache_ptr) 1598 { 1599 int num_l3_intf, i; 1600 1601 num_l3_intf = soc_mem_index_count(unit, EGR_L3_INTFm); 1602 1603 for (i = 0; i < num_l3_intf; i++) { 1604 REPL_L3_INTF_NEXT_HOP_TRILL(unit, i) = *(int *)(*scache_ptr); 1605 (*scache_ptr) += sizeof(int); 1606 } 1607 1608 return BCM_E_NONE; 1609 } 1610 1611 /* 1612 * Function: 1613 * _bcm_th_repl_head_block_insert 1614 * Purpose: 1615 * Insert a free block of REPL_HEAD table entries into free array list. 1616 * Parameters: 1617 * unit - (IN) SOC unit number. 1618 * pipe - (IN) Pipeline number. 1619 * index - (IN) Index of the first entry of the block. 1620 * size - (IN) Size of block. 1621 * Returns: 1622 * BCM_E_xxx 1623 */ 1624 STATIC int 1625 _bcm_th_repl_head_block_insert(int unit, int pipe, int index, int size) 1626 { 1627 _th_repl_head_free_block_t *block_ptr; 1628 1629 block_ptr = sal_alloc(sizeof(_th_repl_head_free_block_t), 1630 "repl head free block"); 1631 if (NULL == block_ptr) { 1632 return BCM_E_MEMORY; 1633 } 1634 block_ptr->index = index; 1635 block_ptr->size = size; 1636 if (size > (_th_repl_head_info[unit][pipe].array_size - 1)) { 1637 /* Insert into free list 0 */ 1638 block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe, 0); 1639 REPL_HEAD_FREE_LIST(unit, pipe, 0) = block_ptr; 1640 } else { 1641 block_ptr->next = REPL_HEAD_FREE_LIST(unit, pipe, size); 1642 REPL_HEAD_FREE_LIST(unit, pipe, size) = block_ptr; 1643 } 1644 1645 return BCM_E_NONE; 1646 } 1647 1648 /* 1649 * Function: 1650 * _bcm_th_repl_head_block_used_set 1651 * Purpose: 1652 * Mark a block of REPL_HEAD table entries as used. 1653 * Parameters: 1654 * unit - (IN) SOC unit number. 1655 * pipe - (IN) Pipeline number. 1656 * index - (IN) Index of the first entry of the block. 1657 * size - (IN) Size of block. 1658 * Returns: 1659 * BCM_E_xxx 1660 */ 1661 STATIC int 1662 _bcm_th_repl_head_block_used_set(int unit, int pipe, int index, int size) 1663 { 1664 int i; 1665 _th_repl_head_free_block_t *prev_block_ptr; 1666 _th_repl_head_free_block_t *block_ptr; 1667 int block_index, block_size, sub_block_size; 1668 1669 for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) { 1670 block_ptr = REPL_HEAD_FREE_LIST(unit, pipe, i); 1671 prev_block_ptr = NULL; 1672 while (NULL != block_ptr) { 1673 block_index = block_ptr->index; 1674 block_size = block_ptr->size; 1675 if ((index >= block_index) && 1676 ((index + size) <= (block_index + block_size))) { 1677 1678 /* This free block contains the block to be marked as used. 1679 * Remove this free block from linked list. 1680 */ 1681 if (block_ptr == REPL_HEAD_FREE_LIST(unit, pipe, i)) { 1682 REPL_HEAD_FREE_LIST(unit, pipe, i) = block_ptr->next; 1683 } else { 1684 /* 1685 * In the following line of code, Coverity thinks the 1686 * prev_block_ptr may still be NULL when dereferenced. 1687 * This situation will never occur because 1688 * if block_ptr is not pointing to the head of the 1689 * linked list, prev_block_ptr would not be NULL. 1690 */ 1691 /* coverity[var_deref_op : FALSE] */ 1692 prev_block_ptr->next = block_ptr->next; 1693 } 1694 sal_free(block_ptr); 1695 1696 /* This free block contains up to 3 sub-blocks: the sub-block 1697 * to be marked as used, and the sub-blocks before and after 1698 * it. The sub-blocks before and after the used sub-block 1699 * need to be inserted back into the free list array. 1700 */ 1701 1702 /* Insert the sub-block before the used sub-block back into 1703 * the free list array. 1704 */ 1705 sub_block_size = index - block_index; 1706 if (sub_block_size > 0) { 1707 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_insert(unit, 1708 pipe, block_index, sub_block_size)); 1709 } 1710 1711 /* Insert the sub-block after the used sub-block back into 1712 * the free list array. 1713 */ 1714 sub_block_size = (block_index + block_size) - (index + size); 1715 if (sub_block_size > 0) { 1716 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_insert(unit, 1717 pipe, index + size, sub_block_size)); 1718 } 1719 1720 return BCM_E_NONE; 1721 } 1722 1723 prev_block_ptr = block_ptr; 1724 block_ptr = block_ptr->next; 1725 } 1726 } 1727 1728 /* The block to be marked used is not found among the free blocks. */ 1729 return BCM_E_NOT_FOUND; 1730 } 1731 #endif /* BCM_WARM_BOOT_SUPPORT */ 1732 1733 /* -------------------------------------------------------------- 1734 * The following set of routines manage REPL_LIST table resource. 1735 * -------------------------------------------------------------- 1736 */ 1737 1738 /* 1739 * Function: 1740 * _bcm_th_repl_list_entry_info_deinit 1741 * Purpose: 1742 * De-initialize replication list entry info. 1743 * Parameters: 1744 * unit - (IN)SOC unit number. 1745 * Returns: 1746 * None 1747 */ 1748 STATIC void 1749 _bcm_th_repl_list_entry_info_deinit(int unit) 1750 { 1751 int pipe; 1752 1753 if (NULL != _th_repl_list_entry_info[unit]) { 1754 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 1755 if (NULL != _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) { 1756 sal_free(_th_repl_list_entry_info[unit][pipe].bitmap_entries_used); 1757 _th_repl_list_entry_info[unit][pipe].bitmap_entries_used = NULL; 1758 } 1759 } 1760 sal_free(_th_repl_list_entry_info[unit]); 1761 _th_repl_list_entry_info[unit] = NULL; 1762 } 1763 } 1764 1765 /* 1766 * Function: 1767 * _bcm_th_repl_list_entry_info_init 1768 * Purpose: 1769 * Initialize replication list entry info. 1770 * Parameters: 1771 * unit - (IN)SOC unit number. 1772 * Returns: 1773 * BCM_E_xxx 1774 */ 1775 STATIC int 1776 _bcm_th_repl_list_entry_info_init(int unit) 1777 { 1778 int alloc_size; 1779 int pipe; 1780 soc_mem_t repl_list_table; 1781 1782 alloc_size = NUM_PIPES(unit) * sizeof(_th_repl_list_entry_info_t); 1783 1784 if (NULL == _th_repl_list_entry_info[unit]) { 1785 _th_repl_list_entry_info[unit] = sal_alloc(alloc_size, 1786 "repl_list_entry_info"); 1787 if (NULL == _th_repl_list_entry_info[unit]) { 1788 _bcm_th_repl_list_entry_info_deinit(unit); 1789 return BCM_E_MEMORY; 1790 } 1791 } 1792 sal_memset(_th_repl_list_entry_info[unit], 0, alloc_size); 1793 1794 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 1795 soc_mem_t repl_head_tbl = REPL_HEAD_TBL(unit); 1796 if (soc_feature(unit, soc_feature_split_repl_head_table)) { 1797 repl_head_tbl = REPL_HEAD_TBL_SPLIT(unit, 0); 1798 } 1799 if(SOC_IS_TOMAHAWK3(unit)) { 1800 repl_list_table = MMU_REPL_LIST_TBLm; 1801 } else { 1802 repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe); 1803 } 1804 _th_repl_list_entry_info[unit][pipe].num_entries = 1 << 1805 soc_mem_field_length(unit, repl_head_tbl, HEAD_PTRf); 1806 alloc_size = SHR_BITALLOCSIZE(_th_repl_list_entry_info[unit][pipe].num_entries); 1807 if (NULL == _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) { 1808 _th_repl_list_entry_info[unit][pipe].bitmap_entries_used = 1809 sal_alloc(alloc_size, "repl list bitmap_entries_used"); 1810 if (NULL == _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) { 1811 _bcm_th_repl_list_entry_info_deinit(unit); 1812 return BCM_E_MEMORY; 1813 } 1814 } 1815 sal_memset(_th_repl_list_entry_info[unit][pipe].bitmap_entries_used, 0, 1816 alloc_size); 1817 1818 /* Reserve REPL_LIST table entry 0 */ 1819 REPL_LIST_ENTRY_USED_SET(unit, pipe, 0); 1820 1821 /* Clear entry 0 of REPL_LIST table */ 1822 SOC_IF_ERROR_RETURN 1823 (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL, 1824 0, soc_mem_entry_null(unit, REPL_LIST_TBL(unit)))); 1825 1826 } 1827 1828 return BCM_E_NONE; 1829 } 1830 1831 /* 1832 * Function: 1833 * _bcm_th_repl_list_entry_free 1834 * Purpose: 1835 * Free a REPL_LIST table entry. 1836 * Parameters: 1837 * unit - (IN) SOC unit number. 1838 * pipe - (IN) Pipeline number. 1839 * entry_index - (IN) Index of the entry to be freed. 1840 * Returns: 1841 * BCM_E_xxx 1842 */ 1843 STATIC int 1844 _bcm_th_repl_list_entry_free(int unit, int pipe, int entry_index) 1845 { 1846 if (!REPL_LIST_ENTRY_USED_GET(unit, pipe, entry_index)) { 1847 return BCM_E_INTERNAL; 1848 } 1849 1850 REPL_LIST_ENTRY_USED_CLR(unit, pipe, entry_index); 1851 return BCM_E_NONE; 1852 } 1853 1854 /* 1855 * Function: 1856 * _bcm_th_repl_list_entry_alloc 1857 * Purpose: 1858 * Allocate a free entry from REPL_LIST table. 1859 * Parameters: 1860 * unit - (IN) SOC unit number. 1861 * pipe - (IN) Pipeline number. 1862 * entry_index - (OUT) Index of a free entry. 1863 * Returns: 1864 * BCM_E_xxx 1865 */ 1866 STATIC int 1867 _bcm_th_repl_list_entry_alloc(int unit, int pipe, int *entry_index) 1868 { 1869 int i; 1870 #ifdef BCM_TOMAHAWK3_SUPPORT 1871 if(SOC_IS_TOMAHAWK3(unit)) { 1872 #define _TH3_IPMC_MAX_RECYCLE_POOL_SIZE 18 1873 /* try to reclycle from candidate pool if pool_size > 18 1874 * in the worst case, 18 replicatoin list will be used 1875 */ 1876 if(_repl_list_recycle_array[unit]->list_size > _TH3_IPMC_MAX_RECYCLE_POOL_SIZE) { 1877 int rv; 1878 rv = _bcm_th3_repl_list_recycle(unit, entry_index); 1879 if (rv == BCM_E_NONE) { 1880 REPL_LIST_ENTRY_USED_SET(unit, pipe, *entry_index); 1881 return rv; 1882 } 1883 } 1884 #undef _TH3_IPMC_MAX_RECYCLE_POOL_SIZE 1885 } 1886 #endif 1887 for (i = 0; i < _th_repl_list_entry_info[unit][pipe].num_entries; i++) { 1888 if (!REPL_LIST_ENTRY_USED_GET(unit, pipe, i)) { 1889 *entry_index = i; 1890 REPL_LIST_ENTRY_USED_SET(unit, pipe, i); 1891 return BCM_E_NONE; 1892 } 1893 } 1894 1895 #ifdef BCM_TOMAHAWK3_SUPPORT 1896 /* try to do the recylce again before returning BCM_E_RESOURCE */ 1897 if(SOC_IS_TOMAHAWK3(unit) && _repl_list_recycle_array[unit]->list_size != 0) { 1898 int rv; 1899 rv = _bcm_th3_repl_list_recycle(unit, entry_index); 1900 if (BCM_FAILURE(rv)) { 1901 *entry_index = -1; 1902 return BCM_E_RESOURCE; 1903 } else { 1904 REPL_LIST_ENTRY_USED_SET(unit, pipe, *entry_index); 1905 return BCM_E_NONE; 1906 } 1907 } 1908 #endif 1909 *entry_index = -1; 1910 return BCM_E_RESOURCE; 1911 } 1912 1913 #ifdef BCM_WARM_BOOT_SUPPORT 1914 /* 1915 * Function: 1916 * _bcm_th_repl_list_entry_used_set 1917 * Purpose: 1918 * Mark the REPL_LIST table entry as used. 1919 * Parameters: 1920 * unit - (IN) SOC unit number. 1921 * pipe - (IN) Pipeline number. 1922 * entry_index - (IN) Index of the entry to be marked. 1923 * Returns: 1924 * BCM_E_xxx 1925 */ 1926 STATIC int 1927 _bcm_th_repl_list_entry_used_set(int unit, int pipe, int entry_index) 1928 { 1929 REPL_LIST_ENTRY_USED_SET(unit, pipe, entry_index); 1930 return BCM_E_NONE; 1931 } 1932 1933 /* 1934 * Function: 1935 * _bcm_th_repl_list_entry_used_get 1936 * Purpose: 1937 * Get used status of a REPL_LIST table entry. 1938 * Parameters: 1939 * unit - (IN) SOC unit number. 1940 * pipe - (IN) Pipeline number. 1941 * entry_index - (IN) Index of the entry. 1942 * used - (OUT) Used status. 1943 * Returns: 1944 * TRUE if used, else FALSE. 1945 */ 1946 STATIC int 1947 _bcm_th_repl_list_entry_used_get(int unit, int pipe, int entry_index) 1948 { 1949 if (REPL_LIST_ENTRY_USED_GET(unit, pipe, entry_index)) { 1950 return TRUE; 1951 } 1952 return FALSE; 1953 } 1954 #endif /* BCM_WARM_BOOT_SUPPORT */ 1955 1956 /* -------------------------------------------------------------- 1957 * The following set of routines manage replication lists. 1958 * -------------------------------------------------------------- 1959 */ 1960 /* 1961 * Function: 1962 * bcm_th_ipmc_repl_detach 1963 * Purpose: 1964 * Deinitialize replication. 1965 * Parameters: 1966 * unit - SOC unit # 1967 * Returns: 1968 * BCM_E_XXX 1969 */ 1970 int 1971 bcm_th_ipmc_repl_detach(int unit) 1972 { 1973 int pipe, num_ports; 1974 _bcm_repl_list_info_t *rli_current, *rli_free; 1975 bcm_port_t port; 1976 1977 _bcm_th_repl_list_entry_info_deinit(unit); 1978 1979 _bcm_th_repl_head_info_deinit(unit); 1980 #ifdef BCM_TOMAHAWK3_SUPPORT 1981 _bcm_th3_repl_list_recycle_candidate_deinit(unit); 1982 #endif 1983 if (_th_repl_info[unit] != NULL) { 1984 if (_th_repl_info[unit]->repl_list_info_array != NULL) { 1985 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 1986 rli_current = _th_repl_info[unit]->repl_list_info_array[pipe]; 1987 while (rli_current != NULL) { 1988 rli_free = rli_current; 1989 rli_current = rli_current->next; 1990 sal_free(rli_free); 1991 } 1992 } 1993 sal_free(_th_repl_info[unit]->repl_list_info_array); 1994 } 1995 1996 #ifdef BCM_MAVERICK2_SUPPORT 1997 if (SOC_IS_MAVERICK2(unit)) { 1998 /* MV2 is single pipe TD3, but regsfile has same 1999 port count as TD3 for this memory.Hence dividing by 2*/ 2000 num_ports = (soc_mem_index_count(unit, ING_DEVICE_PORTm) - 1)/2; 2001 } else 2002 #endif 2003 if (SOC_IS_TRIDENT3X(unit)) { 2004 num_ports = soc_mem_index_count(unit, ING_DEVICE_PORTm) - 1; 2005 } else { 2006 num_ports = soc_mem_index_count(unit, PORT_TABm) - 1; 2007 } 2008 for (port = 0; port < num_ports; port++) { 2009 if (_th_repl_info[unit]->port_info[port] != NULL) { 2010 if (_th_repl_info[unit]-> 2011 port_info[port]->intf_count != NULL) { 2012 sal_free(_th_repl_info[unit]-> 2013 port_info[port]->intf_count); 2014 } 2015 sal_free(_th_repl_info[unit]->port_info[port]); 2016 } 2017 } 2018 if (_th_repl_info[unit]->l3_intf_next_hop_ipmc != NULL) { 2019 sal_free(_th_repl_info[unit]->l3_intf_next_hop_ipmc); 2020 } 2021 if (_th_repl_info[unit]->l3_intf_next_hop_trill != NULL) { 2022 sal_free(_th_repl_info[unit]->l3_intf_next_hop_trill); 2023 } 2024 sal_free(_th_repl_info[unit]); 2025 _th_repl_info[unit] = NULL; 2026 2027 if (soc_property_get(unit, spn_MULTICAST_PER_TRUNK_REPLICATION, 0)) { 2028 BCM_IF_ERROR_RETURN(bcm_th_aggid_info_detach(unit)); 2029 } 2030 } 2031 2032 return BCM_E_NONE; 2033 } 2034 #ifdef BCM_TOMAHAWK3_SUPPORT 2035 2036 STATIC int 2037 _bcm_th3_repl_init(int unit) 2038 { 2039 bcm_port_t port; 2040 uint32 regval; 2041 soc_reg_t reg = MMU_RQE_REPL_PORT_AGG_MAPr; 2042 _bcm_repl_list_info_t *recycle_head = NULL; 2043 /* init repl head */ 2044 BCM_IF_ERROR_RETURN(_bcm_th3_repl_head_info_init(unit)); 2045 2046 /* init repl list entry*/ 2047 BCM_IF_ERROR_RETURN(_bcm_th_repl_list_entry_info_init(unit)); 2048 2049 /* enable per trunk replication mode */ 2050 if (soc_property_get(unit, spn_MULTICAST_PER_TRUNK_REPLICATION, 0)) { 2051 BCM_MC_PER_TRUNK_REPL_MODE(unit) = TRUE; 2052 BCM_IF_ERROR_RETURN(bcm_th_aggid_info_init(unit)); 2053 } else { 2054 BCM_MC_PER_TRUNK_REPL_MODE(unit) = FALSE; 2055 BCM_IF_ERROR_RETURN(bcm_th_aggid_info_detach(unit)); 2056 } 2057 /* init repl list recyclye candidate pool with a dummy node*/ 2058 recycle_head = (_bcm_repl_list_info_t *) 2059 sal_alloc(sizeof(_bcm_repl_list_info_t), "recycle head"); 2060 2061 if (NULL == recycle_head) { 2062 return BCM_E_MEMORY; 2063 } 2064 sal_memset(recycle_head, 0, sizeof(_bcm_repl_list_info_t)); 2065 recycle_head->list_size = 0; 2066 _repl_list_recycle_array[unit] = recycle_head; 2067 /* map device port to agg_id */ 2068 PBMP_ITER(PBMP_ALL(unit), port) { 2069 regval = 0; 2070 soc_reg_field_set(unit, reg, ®val, L3MC_PORT_AGG_IDf, 2071 BCM_MC_PER_TRUNK_REPL_MODE(unit) ? 2072 TH3_AGG_ID_HW_INVALID : port); 2073 SOC_IF_ERROR_RETURN( 2074 soc_reg32_set(unit, reg, port, 0, regval)); 2075 2076 } 2077 if (!SOC_WARM_BOOT(unit)) { 2078 /* Only clear if not cold boot */ 2079 if (!SOC_HW_RESET(unit) || SAL_BOOT_BCMSIM) { 2080 /* clear */ 2081 SOC_IF_ERROR_RETURN 2082 (soc_mem_clear(unit, MMU_REPL_MEMBER_ICCm, MEM_BLOCK_ALL, 0)); 2083 2084 SOC_IF_ERROR_RETURN 2085 (soc_mem_clear(unit, MMU_REPL_GROUP_INFO_TBLm, MEM_BLOCK_ALL, 0)); 2086 2087 SOC_IF_ERROR_RETURN 2088 (soc_mem_clear(unit, MMU_REPL_HEAD_TBLm, MEM_BLOCK_ALL, 0)); 2089 2090 SOC_IF_ERROR_RETURN 2091 (soc_mem_clear(unit, MMU_REPL_LIST_TBLm, MEM_BLOCK_ALL, 0)); 2092 2093 } 2094 } 2095 return BCM_E_NONE; 2096 } 2097 2098 #endif 2099 /* 2100 * Function: 2101 * bcm_th_ipmc_repl_init 2102 * Purpose: 2103 * Initialize replication. 2104 * Parameters: 2105 * unit - SOC unit # 2106 * Returns: 2107 * BCM_E_XXX 2108 */ 2109 int 2110 bcm_th_ipmc_repl_init(int unit) 2111 { 2112 int rv = BCM_E_NONE; 2113 int alloc_size; 2114 int i; 2115 bcm_port_t port; 2116 int phy_port, mmu_port; 2117 int port_speed, count_width; 2118 uint32 regval; 2119 soc_mem_t ipmc_mem_inst; 2120 int pipe, slice; 2121 soc_info_t *si; 2122 soc_reg_t reg = MMU_DQS_REPL_PORT_AGG_MAPr; 2123 2124 bcm_th_ipmc_repl_detach(unit); 2125 2126 if (NULL == _th_repl_info[unit]) { 2127 _th_repl_info[unit] = sal_alloc(sizeof(_th_repl_info_t), "repl info"); 2128 if (NULL == _th_repl_info[unit]) { 2129 bcm_th_ipmc_repl_detach(unit); 2130 return BCM_E_MEMORY; 2131 } 2132 } 2133 sal_memset(_th_repl_info[unit], 0, sizeof(_th_repl_info_t)); 2134 2135 /* There are 4 pipelines in Tomahawk. Each pipeline has its own 2136 * multicast replication tables. 2137 */ 2138 _th_repl_info[unit]->num_pipes = NUM_PIPE(unit); 2139 2140 #ifdef BCM_TOMAHAWK3_SUPPORT 2141 /* There are 8 pipelines in Tomahawk3, but 2142 * multicast replication tables are pipeline independent. 2143 */ 2144 if(SOC_IS_TOMAHAWK3(unit)) { 2145 _th_repl_info[unit]->num_pipes = 1; 2146 } 2147 #endif 2148 _th_repl_info[unit]->num_repl_groups = soc_mem_index_count(unit, L3_IPMCm); 2149 2150 /* The total number of replication interfaces equals to the total 2151 * number of next hops. Unlike previous XGS3 devices, each L3 inteface 2152 * will be associated with a next hop index. 2153 */ 2154 _th_repl_info[unit]->num_intf = soc_mem_index_count(unit, 2155 EGR_L3_NEXT_HOPm); 2156 2157 alloc_size = _th_repl_info[unit]->num_pipes * 2158 sizeof(_bcm_repl_list_info_t *); 2159 if (NULL == _th_repl_info[unit]->repl_list_info_array) { 2160 _th_repl_info[unit]->repl_list_info_array = sal_alloc(alloc_size, 2161 "array of linked list of replication list info"); 2162 if (NULL == _th_repl_info[unit]->repl_list_info_array) { 2163 bcm_th_ipmc_repl_detach(unit); 2164 return BCM_E_MEMORY; 2165 } 2166 } 2167 sal_memset(_th_repl_info[unit]->repl_list_info_array, 0, alloc_size); 2168 2169 PBMP_ITER(PBMP_ALL(unit), port) { 2170 /* coverity[overrun-local : FALSE] */ 2171 if (NULL == _th_repl_info[unit]->port_info[port]) { 2172 _th_repl_info[unit]->port_info[port] = 2173 sal_alloc(sizeof(_th_repl_port_info_t), "repl port info"); 2174 if (NULL == _th_repl_info[unit]->port_info[port]) { 2175 bcm_th_ipmc_repl_detach(unit); 2176 return BCM_E_MEMORY; 2177 } 2178 } 2179 sal_memset(_th_repl_info[unit]->port_info[port], 0, 2180 sizeof(_th_repl_port_info_t)); 2181 2182 alloc_size = sizeof(int) * _th_repl_info[unit]->num_repl_groups; 2183 if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) { 2184 _th_repl_info[unit]->port_info[port]->intf_count = 2185 sal_alloc(alloc_size, "repl port intf count"); 2186 if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) { 2187 bcm_th_ipmc_repl_detach(unit); 2188 return BCM_E_MEMORY; 2189 } 2190 } 2191 sal_memset(_th_repl_info[unit]->port_info[port]->intf_count, 0, 2192 alloc_size); 2193 } 2194 2195 if (NULL == _th_repl_info[unit]->l3_intf_next_hop_ipmc) { 2196 _th_repl_info[unit]->l3_intf_next_hop_ipmc = 2197 sal_alloc(sizeof(int) * soc_mem_index_count(unit, EGR_L3_INTFm), 2198 "l3_intf_next_hop_ipmc"); 2199 if (NULL == _th_repl_info[unit]->l3_intf_next_hop_ipmc) { 2200 bcm_th_ipmc_repl_detach(unit); 2201 return BCM_E_MEMORY; 2202 } 2203 } 2204 for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) { 2205 _th_repl_info[unit]->l3_intf_next_hop_ipmc[i] = -1; 2206 } 2207 2208 if (NULL == _th_repl_info[unit]->l3_intf_next_hop_trill) { 2209 _th_repl_info[unit]->l3_intf_next_hop_trill = 2210 sal_alloc(sizeof(int) * soc_mem_index_count(unit, EGR_L3_INTFm), 2211 "l3_intf_next_hop_trill"); 2212 if (NULL == _th_repl_info[unit]->l3_intf_next_hop_trill) { 2213 bcm_th_ipmc_repl_detach(unit); 2214 return BCM_E_MEMORY; 2215 } 2216 } 2217 for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) { 2218 _th_repl_info[unit]->l3_intf_next_hop_trill[i] = -1; 2219 } 2220 #ifdef BCM_TOMAHAWK3_SUPPORT 2221 if(SOC_IS_TOMAHAWK3(unit)) { 2222 rv = _bcm_th3_repl_init(unit); 2223 if(BCM_FAILURE(rv)) { 2224 bcm_th_ipmc_repl_detach(unit); 2225 } 2226 return BCM_E_NONE; 2227 } 2228 #endif 2229 rv = _bcm_th_repl_head_info_init(unit); 2230 if (BCM_FAILURE(rv)) { 2231 bcm_th_ipmc_repl_detach(unit); 2232 return rv; 2233 } 2234 2235 rv = _bcm_th_repl_list_entry_info_init(unit); 2236 if (BCM_FAILURE(rv)) { 2237 bcm_th_ipmc_repl_detach(unit); 2238 return rv; 2239 } 2240 2241 /* enable per trunk replication mode */ 2242 if (soc_property_get(unit, spn_MULTICAST_PER_TRUNK_REPLICATION, 0)) { 2243 BCM_MC_PER_TRUNK_REPL_MODE(unit) = TRUE; 2244 BCM_IF_ERROR_RETURN(bcm_th_aggid_info_init(unit)); 2245 } else { 2246 BCM_MC_PER_TRUNK_REPL_MODE(unit) = FALSE; 2247 } 2248 2249 if (!SOC_WARM_BOOT(unit)) { 2250 si = &SOC_INFO(unit); 2251 for (slice = 0; slice < NUM_SLICE(unit); slice++) { 2252 if (!si->sc_epipe_map[slice]) { 2253 continue; 2254 } 2255 /* Clear replication group initial count table */ 2256 ipmc_mem_inst = REPL_GROUP_INITIAL_COPY_COUNT_TBL_SLICE(unit, slice); 2257 SOC_IF_ERROR_RETURN 2258 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2259 #if defined(BCM_TOMAHAWK2_SUPPORT) 2260 if (SOC_IS_TOMAHAWK2(unit)) { 2261 ipmc_mem_inst = 2262 SOC_MEM_UNIQUE_ACC(unit, 2263 MMU_REPL_GROUP_INITIAL_COPY_COUNT0m)[slice]; 2264 SOC_IF_ERROR_RETURN 2265 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2266 ipmc_mem_inst = 2267 SOC_MEM_UNIQUE_ACC(unit, 2268 MMU_REPL_GROUP_INITIAL_COPY_COUNT1m)[slice]; 2269 SOC_IF_ERROR_RETURN 2270 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2271 } 2272 #endif /* BCM_TOMAHAWK2_SUPPORT */ 2273 } 2274 /* Only clear if not cold boot */ 2275 if (!SOC_HW_RESET(unit) || SAL_BOOT_BCMSIM) { 2276 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 2277 /* Clear replication group table */ 2278 ipmc_mem_inst = REPL_GROUP_INFO_TBL_PIPE(unit, pipe); 2279 SOC_IF_ERROR_RETURN 2280 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2281 2282 /* Clear replication head table */ 2283 if (soc_feature(unit, soc_feature_split_repl_head_table)) { 2284 ipmc_mem_inst = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe); 2285 SOC_IF_ERROR_RETURN 2286 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2287 ipmc_mem_inst = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe); 2288 SOC_IF_ERROR_RETURN 2289 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2290 } else { 2291 ipmc_mem_inst = REPL_HEAD_TBL_PIPE(unit, pipe); 2292 SOC_IF_ERROR_RETURN 2293 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2294 } 2295 2296 /* Clear replication list table */ 2297 ipmc_mem_inst = REPL_LIST_TBL_PIPE(unit, pipe); 2298 SOC_IF_ERROR_RETURN 2299 (soc_mem_clear(unit, ipmc_mem_inst, MEM_BLOCK_ALL, 0)); 2300 } 2301 } 2302 2303 /* Initialize PORT_INITIAL_COPY_COUNT_WIDTH registers */ 2304 PBMP_ITER(PBMP_ALL(unit), port) { 2305 /* coverity[overrun-local : FALSE] */ 2306 phy_port = SOC_INFO(unit).port_l2p_mapping[port]; 2307 /* coverity[overrun-local : FALSE] */ 2308 mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port]; 2309 /* coverity[illegal_address : FALSE] */ 2310 if (IS_CPU_PORT(unit, port) || IS_LB_PORT(unit, port) || 2311 IS_MANAGEMENT_PORT(unit, port) || IS_FAE_PORT(unit, port)) { 2312 /* For CPU, loopback, and management ports, 2313 * the copy count width is fixed at 2/3 bits 2314 * (encoded value of 0/1). 2315 * Pysical ports 129 and 131 are management ports. 2316 */ 2317 count_width = 1; 2318 if (phy_port == 129 || phy_port == 131 || 2319 (phy_port == 128 && SOC_IS_TRIDENT3(unit)) || (phy_port == 81 && SOC_IS_MAVERICK2(unit))) { 2320 if (soc_mem_field_length(unit, 2321 MMU_REPL_GROUP_INITIAL_COPY_COUNTm, ICC_BIT_MPf) <= 2) { 2322 count_width = 0; 2323 } 2324 } 2325 } else { 2326 if (SOC_IS_TOMAHAWK2(unit)) { 2327 /* Single-lane ports are allocated 2 bits, while 2 or 4 2328 * lane ports are allocated 3 bits. */ 2329 count_width = (si->port_num_lanes[port] > 1) ? 1 : 0; 2330 } else { 2331 /* For ports with speed 40G and above the copy count width 2332 * is 3 bits (encoded value of 1) for lower speeds its 2333 * 2 bits (encoded value of 0). 2334 */ 2335 BCM_IF_ERROR_RETURN 2336 (bcm_esw_port_speed_get(unit, port, &port_speed)); 2337 count_width = (port_speed >= 40000) ? 1 : 0; 2338 } 2339 } 2340 2341 /* If the port_initial_copy_count is not skipped, update the same */ 2342 if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) { 2343 regval = 0; 2344 soc_reg_field_set(unit, PORT_INITIAL_COPY_COUNT_WIDTHr, ®val, 2345 BIT_WIDTHf, count_width); 2346 SOC_IF_ERROR_RETURN(WRITE_PORT_INITIAL_COPY_COUNT_WIDTHr(unit, 2347 port, regval)); 2348 } 2349 2350 /* configure mmu port to repl aggregateId map */ 2351 regval = 0; 2352 2353 #ifdef BCM_TOMAHAWK3_SUPPORT 2354 reg = (SOC_IS_TOMAHAWK3(unit)) ? MMU_RQE_REPL_PORT_AGG_MAPr : 2355 MMU_DQS_REPL_PORT_AGG_MAPr; 2356 #endif 2357 2358 soc_reg_field_set(unit, reg, ®val, 2359 L3MC_PORT_AGG_IDf, 2360 BCM_MC_PER_TRUNK_REPL_MODE(unit) ? 2361 TH_AGG_ID_HW_INVALID : (mmu_port % mmu_port_stride[unit])); 2362 SOC_IF_ERROR_RETURN( 2363 soc_reg32_set(unit, reg, port, 0, regval)); 2364 } 2365 } 2366 2367 2368 return rv; 2369 } 2370 2371 2372 /* Function: 2373 * _bcm_th_port_pipe_get 2374 * Purpose: 2375 * Get pipeline to which the given port belongs. 2376 * Parameters: 2377 * unit - SOC unit number. 2378 * port - Port number. 2379 * pipe - (OUT) Pipeline number. 2380 * Returns: 2381 * BCM_E_XXX 2382 */ 2383 STATIC int 2384 _bcm_th_port_pipe_get(int unit, int port, int *pipe) 2385 { 2386 soc_info_t *si = &SOC_INFO(unit); 2387 2388 if (si->port_pipe[port] == -1) { 2389 return BCM_E_PORT; 2390 } 2391 2392 *pipe = si->port_pipe[port]; 2393 2394 return BCM_E_NONE; 2395 } 2396 2397 /* Function: 2398 * _bcm_th_port_slice_get 2399 * Purpose: 2400 * Get MMU slice to which the given port belongs. 2401 * Parameters: 2402 * unit - SOC unit number. 2403 * port - Port number. 2404 * slice - (OUT) Slice number. 2405 * Returns: 2406 * BCM_E_XXX 2407 */ 2408 STATIC int 2409 _bcm_td3_port_slice_get(int unit, int port, int *slice) 2410 { 2411 *slice = 0; 2412 2413 return BCM_E_NONE; 2414 } 2415 2416 /* Function: 2417 * _bcm_th_port_slice_get 2418 * Purpose: 2419 * Get MMU slice to which the given port belongs. 2420 * Parameters: 2421 * unit - SOC unit number. 2422 * port - Port number. 2423 * slice - (OUT) Slice number. 2424 * Returns: 2425 * BCM_E_XXX 2426 */ 2427 STATIC int 2428 _bcm_th_port_slice_get(int unit, int port, int *slice) 2429 { 2430 int pipe; 2431 2432 if (SOC_IS_TRIDENT3X(unit)) { 2433 return _bcm_td3_port_slice_get(unit, port, slice); 2434 } 2435 /* Get pipeline number */ 2436 BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe)); 2437 2438 /* Derive slice number */ 2439 if (pipe <= 1) { 2440 *slice = 0; 2441 } else { 2442 *slice = 1; 2443 } 2444 2445 return BCM_E_NONE; 2446 } 2447 2448 /* Function: 2449 * _bcm_td3_repl_icc_set 2450 * Purpose: 2451 * Set replication initial copy count. 2452 * Parameters: 2453 * unit - StrataSwitch PCI device unit number. 2454 * repl_group - The replication group number. 2455 * port - Port. 2456 * intf_count - Replication list's interface count. 2457 * count_width - count_width 2458 * copy_count - copy_count 2459 * Returns: 2460 * BCM_E_XXX 2461 */ 2462 STATIC int 2463 _bcm_td3_repl_icc_set(int unit, int repl_group, bcm_port_t port, 2464 int intf_count, int count_width, int copy_count) 2465 { 2466 soc_info_t *si; 2467 bcm_port_t phy_port; 2468 mmu_repl_group_initial_copy_count_entry_t initial_copy_count_entry; 2469 uint32 count_mask, count_shift; 2470 SHR_BITDCL copy_count_buf[12]; 2471 int slice = 0; /* Only 1 slice in TD3 */ 2472 soc_mem_t repl_group_icc_table; 2473 2474 #if defined(BCM_HELIX5_SUPPORT) 2475 int bit = 0; 2476 #endif 2477 2478 /* TD3TBD: 2479 * PORT_INITIAL_COPY_COUNT_WIDTHr NEEDS to be updated while 2480 * Chaging lanes or speed */ 2481 2482 /* Update REPL_GROUP_INITIAL_COPY_COUNT table */ 2483 repl_group_icc_table = 2484 REPL_GROUP_INITIAL_COPY_COUNT_TBL_SLICE(unit, slice); 2485 SOC_IF_ERROR_RETURN 2486 (soc_mem_read(unit, repl_group_icc_table, MEM_BLOCK_ANY, 2487 repl_group, &initial_copy_count_entry)); 2488 si = &SOC_INFO(unit); 2489 phy_port = si->port_l2p_mapping[port]; 2490 if (SOC_IS_TRIDENT3(unit)) { 2491 if (slice == 0) { 2492 if (phy_port == 128 && 2493 SOC_PORT_BLOCK(unit, phy_port) == SOC_PORT_BLOCK(unit, 129)) { 2494 /* Second management port */ 2495 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2496 &initial_copy_count_entry, ICC_BIT_2ND_MPf, copy_count); 2497 } else if (phy_port == 131) { 2498 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2499 &initial_copy_count_entry, ICC_BIT_LP_PYf, copy_count); 2500 } else if (phy_port == 130) { 2501 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2502 &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count); 2503 } else if (phy_port == 129) { 2504 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2505 &initial_copy_count_entry, ICC_BIT_MPf, copy_count); 2506 } else if (IS_CPU_PORT(unit, port)) { 2507 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2508 &initial_copy_count_entry, ICC_BIT_CPUf, copy_count); 2509 } else if (phy_port <= 128 && phy_port >= 65) { 2510 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit, 2511 &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf); 2512 count_mask = (1 << count_width) - 1; 2513 count_shift = (phy_port - 65) * 2 % 32; 2514 copy_count_buf[(phy_port - 65) * 2 / 32] &= ~(count_mask << count_shift); 2515 copy_count_buf[(phy_port - 65) * 2 / 32] |= (copy_count << count_shift); 2516 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit, 2517 &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf); 2518 } else if (phy_port <= 64 && phy_port >= 1) { 2519 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit, 2520 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2521 count_mask = (1 << count_width) - 1; 2522 count_shift = (phy_port - 1) * 2 % 32; 2523 copy_count_buf[(phy_port - 1) * 2 / 32] &= ~(count_mask << count_shift); 2524 copy_count_buf[(phy_port - 1) * 2 / 32] |= (copy_count << count_shift); 2525 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit, 2526 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2527 } else { 2528 return BCM_E_PORT; 2529 } 2530 } 2531 } 2532 2533 #if defined(BCM_MAVERICK2_SUPPORT) 2534 if (SOC_IS_MAVERICK2(unit)) { 2535 if (slice == 0) { 2536 if (IS_LB_PORT(unit, port)) { 2537 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2538 &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count); 2539 } else if (IS_MANAGEMENT_PORT(unit, port)) { 2540 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2541 &initial_copy_count_entry, ICC_BIT_MPf, copy_count); 2542 } else if (IS_CPU_PORT(unit, port)) { 2543 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2544 &initial_copy_count_entry, ICC_BIT_CPUf, copy_count); 2545 } else if (IS_E_PORT(unit, port) || IS_HG_PORT(unit, port)) { 2546 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit, 2547 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2548 count_mask = (1 << count_width) - 1; 2549 count_shift = (phy_port - 1) * 2 % 32; 2550 copy_count_buf[(phy_port - 1) * 2 / 32] &= ~(count_mask << count_shift); 2551 copy_count_buf[(phy_port - 1) * 2 / 32] |= (copy_count << count_shift); 2552 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit, 2553 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2554 } else { 2555 return BCM_E_PORT; 2556 } 2557 } 2558 } 2559 #endif 2560 2561 #if defined(BCM_HELIX5_SUPPORT) 2562 if (SOC_IS_HELIX5(unit)) { 2563 if (slice == 0) { 2564 if (IS_LB_PORT(unit, port)) { 2565 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2566 &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count); 2567 } else if (IS_CPU_PORT(unit, port)) { 2568 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2569 &initial_copy_count_entry, ICC_BIT_CPUf, copy_count); 2570 } else if (IS_E_PORT(unit, port) || IS_HG_PORT(unit, port)) { 2571 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit, 2572 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2573 count_shift = (phy_port - 1) * 3; 2574 for (bit = 0; bit < count_width; bit++) { 2575 if (copy_count & (1 << bit)) { 2576 SHR_BITSET(copy_count_buf, count_shift + bit); 2577 } else { 2578 SHR_BITCLR(copy_count_buf, count_shift + bit); 2579 } 2580 } 2581 2582 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit, 2583 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2584 } else { 2585 return BCM_E_PORT; 2586 } 2587 } 2588 } 2589 #endif 2590 2591 SOC_IF_ERROR_RETURN 2592 (soc_mem_write(unit, repl_group_icc_table, MEM_BLOCK_ALL, 2593 repl_group, &initial_copy_count_entry)); 2594 return BCM_E_NONE; 2595 } 2596 2597 /* Function: 2598 * _bcm_th_repl_initial_copy_count_set 2599 * Purpose: 2600 * Set replication initial copy count. 2601 * Parameters: 2602 * unit - StrataSwitch PCI device unit number. 2603 * repl_group - The replication group number. 2604 * port - Port. 2605 * intf_count - Replication list's interface count. 2606 * Returns: 2607 * BCM_E_XXX 2608 */ 2609 STATIC int 2610 _bcm_th_repl_initial_copy_count_set(int unit, int repl_group, bcm_port_t port, 2611 int intf_count) 2612 { 2613 soc_info_t *si; 2614 bcm_port_t phy_port; 2615 uint32 regval; 2616 int count_width, copy_count; 2617 mmu_repl_group_initial_copy_count_entry_t initial_copy_count_entry; 2618 uint32 count_mask, count_shift, count_column; 2619 uint32 copy_count_buf[4]; 2620 int pipe, slice; 2621 soc_mem_t repl_group_icc_table; 2622 #if defined(BCM_TOMAHAWK2_SUPPORT) 2623 soc_mem_t repl_group_icc_table0 = INVALIDm; 2624 soc_mem_t repl_group_icc_table1 = INVALIDm; 2625 #endif /* BCM_TOMAHAWK2_SUPPORT */ 2626 2627 /* Get port's copy count width */ 2628 if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) { 2629 SOC_IF_ERROR_RETURN(READ_PORT_INITIAL_COPY_COUNT_WIDTHr(unit, 2630 port, ®val)); 2631 count_width = 2 + soc_reg_field_get(unit, 2632 PORT_INITIAL_COPY_COUNT_WIDTHr, regval, BIT_WIDTHf); 2633 } else { 2634 /* In HX5, the above reg is marked as reserved, since for all 2635 * front-panel ports the initial-copy-count-width has been setup as 3. 2636 */ 2637 count_width = 3; 2638 } 2639 /* Compute port's initial copy count */ 2640 copy_count = 0; 2641 switch (count_width) { 2642 case 2: 2643 if (intf_count <= 3) { 2644 copy_count = intf_count; 2645 } 2646 break; 2647 case 3: 2648 if (intf_count <= 5) { 2649 copy_count = intf_count; 2650 } 2651 break; 2652 default: 2653 return BCM_E_INTERNAL; 2654 break; 2655 } 2656 2657 if (SOC_IS_TRIDENT3X(unit)) { 2658 return _bcm_td3_repl_icc_set(unit, repl_group, port, intf_count, 2659 count_width, copy_count); 2660 } 2661 2662 /* Get pipeline number */ 2663 BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe)); 2664 /* Update REPL_GROUP_INITIAL_COPY_COUNT table */ 2665 BCM_IF_ERROR_RETURN(_bcm_th_port_slice_get(unit, port, &slice)); 2666 2667 repl_group_icc_table = 2668 SOC_MEM_UNIQUE_ACC(unit, MMU_REPL_GROUP_INITIAL_COPY_COUNTm)[slice]; 2669 #if defined(BCM_TOMAHAWK2_SUPPORT) 2670 if (SOC_IS_TOMAHAWK2(unit)) { 2671 repl_group_icc_table0 = 2672 SOC_MEM_UNIQUE_ACC(unit, MMU_REPL_GROUP_INITIAL_COPY_COUNT0m)[slice]; 2673 repl_group_icc_table1 = 2674 SOC_MEM_UNIQUE_ACC(unit, MMU_REPL_GROUP_INITIAL_COPY_COUNT1m)[slice]; 2675 } 2676 #endif /* BCM_TOMAHAWK2_SUPPORT */ 2677 SOC_IF_ERROR_RETURN 2678 (soc_mem_read(unit, repl_group_icc_table, MEM_BLOCK_ANY, 2679 repl_group, &initial_copy_count_entry)); 2680 si = &SOC_INFO(unit); 2681 phy_port = si->port_l2p_mapping[port]; 2682 2683 # define IS_X_PIPE(_pipe_) ((_pipe_ & 1) == 0) 2684 # define IS_Y_PIPE(_pipe_) ((_pipe_ & 1) == 1) 2685 # define PORT_NUM_PER_PIPE(_u_) (SOC_IS_TOMAHAWK2(_u_) ? 64 : 32) 2686 # define PHY_PORT_ID_PER_PIPE(_u_, _pp_) ((_pp_ - 1) % PORT_NUM_PER_PIPE(_u_)) 2687 2688 if (IS_LB_PORT(unit, port) && IS_Y_PIPE(pipe)) { 2689 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2690 &initial_copy_count_entry, ICC_BIT_LP_PYf, copy_count); 2691 } else if (IS_LB_PORT(unit, port) && IS_X_PIPE(pipe)) { 2692 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2693 &initial_copy_count_entry, ICC_BIT_LP_PXf, copy_count); 2694 } else if (IS_MANAGEMENT_PORT(unit, port)) { 2695 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2696 &initial_copy_count_entry, ICC_BIT_MPf, copy_count); 2697 } else if (IS_CPU_PORT(unit, port)) { 2698 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field32_set(unit, 2699 &initial_copy_count_entry, ICC_BIT_CPUf, copy_count); 2700 } else if (IS_Y_PIPE(pipe)) { 2701 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit, 2702 &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf); 2703 count_mask = (1 << count_width) - 1; 2704 count_shift = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 % 32; 2705 count_column = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 / 32; 2706 copy_count_buf[count_column] &= ~(count_mask << count_shift); 2707 copy_count_buf[count_column] |= (copy_count << count_shift); 2708 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit, 2709 &initial_copy_count_entry, ICC_BIT_FP_PYf, copy_count_buf); 2710 } else if (IS_X_PIPE(pipe)) { 2711 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_get(unit, 2712 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2713 count_mask = (1 << count_width) - 1; 2714 count_shift = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 % 32; 2715 count_column = PHY_PORT_ID_PER_PIPE(unit, phy_port) * 2 / 32; 2716 copy_count_buf[count_column] &= ~(count_mask << count_shift); 2717 copy_count_buf[count_column] |= (copy_count << count_shift); 2718 soc_MMU_REPL_GROUP_INITIAL_COPY_COUNTm_field_set(unit, 2719 &initial_copy_count_entry, ICC_BIT_FP_PXf, copy_count_buf); 2720 } else { 2721 return BCM_E_PORT; 2722 } 2723 SOC_IF_ERROR_RETURN 2724 (soc_mem_write(unit, repl_group_icc_table, MEM_BLOCK_ALL, 2725 repl_group, &initial_copy_count_entry)); 2726 #if defined(BCM_TOMAHAWK2_SUPPORT) 2727 if (SOC_IS_TOMAHAWK2(unit)) { 2728 /* coverity[negative_returns : FALSE] */ 2729 SOC_IF_ERROR_RETURN 2730 (soc_mem_write(unit, repl_group_icc_table0, MEM_BLOCK_ALL, 2731 repl_group, &initial_copy_count_entry)); 2732 /* coverity[negative_returns : FALSE] */ 2733 SOC_IF_ERROR_RETURN 2734 (soc_mem_write(unit, repl_group_icc_table1, MEM_BLOCK_ALL, 2735 repl_group, &initial_copy_count_entry)); 2736 } 2737 #endif /* BCM_TOMAHAWK2_SUPPORT */ 2738 return BCM_E_NONE; 2739 } 2740 2741 STATIC int 2742 _bcm_td3_repl_head_tbl_write(int unit, int pipe, int index, uint32 *entry) 2743 { 2744 soc_mem_t repl_hd_tbl; 2745 int max_index_offset = 0; 2746 2747 if (SOC_IS_HELIX5(unit)) { 2748 max_index_offset = 32; 2749 } else { 2750 max_index_offset = 64; 2751 } 2752 2753 if (soc_feature(unit, soc_feature_split_repl_head_table)) { 2754 repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe); 2755 if (index >= max_index_offset * 1024) { 2756 index -= max_index_offset * 1024; 2757 repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe); 2758 } 2759 SOC_IF_ERROR_RETURN(soc_mem_write(unit, repl_hd_tbl, MEM_BLOCK_ALL, 2760 index, entry)); 2761 } else { 2762 repl_hd_tbl = REPL_HEAD_TBL_PIPE(unit, pipe); 2763 SOC_IF_ERROR_RETURN(soc_mem_write(unit, repl_hd_tbl, MEM_BLOCK_ALL, 2764 index, entry)); 2765 } 2766 2767 return BCM_E_NONE; 2768 } 2769 2770 STATIC int 2771 _bcm_td3_repl_head_tbl_read(int unit, int pipe, int index, uint32 *entry, uint32 *head_ptr) 2772 { 2773 soc_mem_t repl_hd_tbl; 2774 int max_index_offset = 0; 2775 2776 if (SOC_IS_HELIX5(unit)) { 2777 max_index_offset = 32; 2778 } else { 2779 max_index_offset = 64; 2780 } 2781 2782 if (soc_feature(unit, soc_feature_split_repl_head_table)) { 2783 repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe); 2784 if (index >= max_index_offset * 1024) { 2785 index -= max_index_offset * 1024; 2786 repl_hd_tbl = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe); 2787 } 2788 SOC_IF_ERROR_RETURN(soc_mem_read(unit, repl_hd_tbl, MEM_BLOCK_ALL, 2789 index, entry)); 2790 if (head_ptr) { 2791 *head_ptr = soc_mem_field32_get(unit, repl_hd_tbl, entry, 2792 HEAD_PTRf); 2793 } 2794 } else { 2795 2796 #if defined(BCM_TOMAHAWK3_SUPPORT) 2797 if (SOC_IS_TOMAHAWK3(unit)) { 2798 repl_hd_tbl = MMU_REPL_HEAD_TBLm; 2799 } else 2800 #endif 2801 { 2802 repl_hd_tbl = REPL_HEAD_TBL_PIPE(unit, pipe); 2803 } 2804 2805 SOC_IF_ERROR_RETURN(soc_mem_read(unit, repl_hd_tbl, MEM_BLOCK_ALL, 2806 index, entry)); 2807 if (head_ptr) { 2808 *head_ptr = soc_mem_field32_get(unit, repl_hd_tbl, entry, HEAD_PTRf); 2809 } 2810 } 2811 2812 return BCM_E_NONE; 2813 } 2814 2815 /* Function: 2816 * _bcm_th_repl_list_start_ptr_set 2817 * Purpose: 2818 * Set replication list start pointer for given (repl_group, port). 2819 * Parameters: 2820 * unit - StrataSwitch PCI device unit number. 2821 * repl_group - The replication group number. 2822 * port - Port. 2823 * start_ptr - Replication list's start pointer. 2824 * intf_count - Replication list's interface count. 2825 * Returns: 2826 * BCM_E_XXX 2827 */ 2828 STATIC int 2829 _bcm_th_repl_list_start_ptr_set(int unit, int repl_group, bcm_port_t port, 2830 int start_ptr, int intf_count) 2831 { 2832 int add_member; 2833 soc_mem_t repl_group_table; 2834 soc_mem_t repl_head_table; 2835 soc_field_t member_bitmap_f, head_index_f; 2836 soc_info_t *si; 2837 bcm_port_t phy_port, mmu_port; 2838 int member_bitmap_index; 2839 int pipe; 2840 mmu_repl_group_info_tbl_entry_t repl_group_entry; 2841 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 2842 int i; 2843 soc_pbmp_t old_member_bitmap; 2844 soc_pbmp_t new_member_bitmap; 2845 int old_member_count, new_member_count; 2846 int old_head_index, new_head_index; 2847 int member_id, member, old_member_id, new_member_id; 2848 uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS]; 2849 uint32 old_repl_head_entry[SOC_MAX_MEM_FIELD_WORDS]; 2850 int member_bitmap_len; 2851 2852 if (start_ptr > 0) { 2853 add_member = TRUE; 2854 } else { 2855 add_member = FALSE; 2856 } 2857 2858 member_bitmap_f = PIPE_MEMBER_BMPf; 2859 head_index_f = PIPE_BASE_PTRf; 2860 2861 2862 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 2863 int aggid = TH_AGG_ID_INVALID; 2864 BCM_IF_ERROR_RETURN(bcm_th_port_to_aggid(unit, port, &aggid)); 2865 member_bitmap_index = aggid; 2866 } else { 2867 /* Get member bitmap index */ 2868 si = &SOC_INFO(unit); 2869 phy_port = si->port_l2p_mapping[port]; 2870 mmu_port = si->port_p2m_mapping[phy_port]; 2871 member_bitmap_index = mmu_port % mmu_port_stride[unit]; 2872 } 2873 2874 member_bitmap_len = soc_mem_field_length(unit, MMU_REPL_GROUP_INFO_TBLm, 2875 member_bitmap_f); 2876 if (member_bitmap_index >= member_bitmap_len) { 2877 return BCM_E_PARAM; 2878 } 2879 2880 /* Get old member bitmap and old head index */ 2881 BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe)); 2882 if (soc_feature(unit, soc_feature_split_repl_head_table)) { 2883 if (member_bitmap_index < 32) { 2884 repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 0, pipe); 2885 } else { 2886 repl_head_table = REPL_HEAD_TBL_SPLIT_PIPE(unit, 1, pipe); 2887 } 2888 } else { 2889 repl_head_table = REPL_HEAD_TBL_PIPE(unit, pipe); 2890 } 2891 repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe); 2892 2893 SOC_IF_ERROR_RETURN 2894 (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY, 2895 repl_group, &repl_group_entry)); 2896 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 2897 soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry, 2898 member_bitmap_f, fldbuf); 2899 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 2900 SOC_PBMP_WORD_SET(old_member_bitmap, i, fldbuf[i]); 2901 } 2902 SOC_PBMP_ASSIGN(new_member_bitmap, old_member_bitmap); 2903 SOC_PBMP_COUNT(old_member_bitmap, old_member_count); 2904 old_head_index = soc_mem_field32_get(unit, repl_group_table, 2905 &repl_group_entry, head_index_f); 2906 2907 if (add_member) { 2908 /* Update REPL_HEAD table */ 2909 sal_memset(repl_head_entry, 0, sizeof(repl_head_entry)); 2910 soc_mem_field32_set(unit, repl_head_table, repl_head_entry, 2911 HEAD_PTRf, start_ptr); 2912 if (SOC_PBMP_MEMBER(old_member_bitmap, member_bitmap_index)) { 2913 /* Port is already a member of the group */ 2914 member_id = 0; 2915 SOC_PBMP_ITER(old_member_bitmap, member) { 2916 if (member == member_bitmap_index) { 2917 break; 2918 } 2919 member_id++; 2920 } 2921 SOC_IF_ERROR_RETURN 2922 (_bcm_td3_repl_head_tbl_write(unit, pipe, 2923 (old_head_index + member_id), repl_head_entry)); 2924 new_head_index = old_head_index; 2925 } else { 2926 SOC_PBMP_PORT_ADD(new_member_bitmap, member_bitmap_index); 2927 new_member_count = old_member_count + 1; 2928 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_alloc(unit, 2929 pipe, new_member_count, &new_head_index)); 2930 old_member_id = 0; 2931 new_member_id = 0; 2932 SOC_PBMP_ITER(new_member_bitmap, member) { 2933 if (member == member_bitmap_index) { 2934 SOC_IF_ERROR_RETURN 2935 (_bcm_td3_repl_head_tbl_write(unit, pipe, 2936 (new_head_index + new_member_id), 2937 repl_head_entry)); 2938 } else { 2939 SOC_IF_ERROR_RETURN 2940 (_bcm_td3_repl_head_tbl_read(unit, pipe, 2941 (old_head_index + old_member_id), 2942 old_repl_head_entry, NULL)); 2943 SOC_IF_ERROR_RETURN 2944 (_bcm_td3_repl_head_tbl_write(unit, pipe, 2945 (new_head_index + new_member_id), 2946 old_repl_head_entry)); 2947 old_member_id++; 2948 } 2949 new_member_id++; 2950 } 2951 } 2952 2953 /* Update REPL_GROUP_INITIAL_COPY_COUNT entry */ 2954 BCM_IF_ERROR_RETURN(_bcm_th_repl_initial_copy_count_set(unit, 2955 repl_group, port, intf_count)); 2956 2957 /* Update REPL_GROUP entry */ 2958 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 2959 fldbuf[i] = SOC_PBMP_WORD_GET(new_member_bitmap, i); 2960 } 2961 soc_mem_field_set(unit, repl_group_table, (uint32 *)&repl_group_entry, 2962 member_bitmap_f, fldbuf); 2963 soc_mem_field32_set(unit, repl_group_table, &repl_group_entry, 2964 head_index_f, new_head_index); 2965 repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe); 2966 2967 SOC_IF_ERROR_RETURN 2968 (soc_mem_write(unit, repl_group_table, MEM_BLOCK_ALL, 2969 repl_group, &repl_group_entry)); 2970 2971 /* Release old block of REPL_HEAD entries */ 2972 if (old_member_count > 0 && old_head_index != new_head_index) { 2973 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit, 2974 pipe, old_head_index, old_member_count)); 2975 } 2976 2977 } else { /* Remove member from replication group */ 2978 2979 if (!SOC_PBMP_MEMBER(old_member_bitmap, member_bitmap_index)) { 2980 /* Port is not a member. Nothing more to do. */ 2981 return BCM_E_NONE; 2982 } 2983 2984 /* Update REPL_HEAD table */ 2985 new_member_count = old_member_count - 1; 2986 if (new_member_count > 0) { 2987 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_alloc(unit, 2988 pipe, new_member_count, &new_head_index)); 2989 old_member_id = 0; 2990 new_member_id = 0; 2991 SOC_PBMP_ITER(old_member_bitmap, member) { 2992 if (member != member_bitmap_index) { 2993 SOC_IF_ERROR_RETURN 2994 (_bcm_td3_repl_head_tbl_read(unit, pipe, 2995 (old_head_index + old_member_id), 2996 old_repl_head_entry, NULL)); 2997 SOC_IF_ERROR_RETURN 2998 (_bcm_td3_repl_head_tbl_write(unit, pipe, 2999 (new_head_index + new_member_id), 3000 old_repl_head_entry)); 3001 new_member_id++; 3002 } 3003 old_member_id++; 3004 } 3005 } else { 3006 new_head_index = 0; 3007 } 3008 3009 /* Update REPL_GROUP_INITIAL_COPY_COUNT entry. MMU spec 3010 * recommends setting the initial copy count to 1 for 3011 * ports that are being removed from a replication group. 3012 */ 3013 BCM_IF_ERROR_RETURN(_bcm_th_repl_initial_copy_count_set(unit, 3014 repl_group, port, 1)); 3015 3016 /* Update REPL_GROUP entry */ 3017 SOC_PBMP_PORT_REMOVE(new_member_bitmap, member_bitmap_index); 3018 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 3019 fldbuf[i] = SOC_PBMP_WORD_GET(new_member_bitmap, i); 3020 } 3021 soc_mem_field_set(unit, repl_group_table, (uint32 *)&repl_group_entry, 3022 member_bitmap_f, fldbuf); 3023 soc_mem_field32_set(unit, repl_group_table, &repl_group_entry, 3024 head_index_f, new_head_index); 3025 repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe); 3026 3027 SOC_IF_ERROR_RETURN 3028 (soc_mem_write(unit, repl_group_table, MEM_BLOCK_ALL, 3029 repl_group, &repl_group_entry)); 3030 3031 /* Release old block of REPL_HEAD entries */ 3032 BCM_IF_ERROR_RETURN(_bcm_th_repl_head_block_free(unit, 3033 pipe, old_head_index, old_member_count)); 3034 } 3035 3036 return BCM_E_NONE; 3037 } 3038 3039 /* 3040 * Function: 3041 * _bcm_th_repl_list_start_ptr_get 3042 * Purpose: 3043 * Get replication list start pointer for given (repl_group, port). 3044 * Parameters: 3045 * unit - StrataSwitch PCI device unit number. 3046 * repl_group - The replication group number. 3047 * port - Port. 3048 * start_ptr - (OUT) Replication list's start pointer to 3049 * REPL_LIST table. 3050 * Returns: 3051 * BCM_E_XXX 3052 */ 3053 STATIC int 3054 _bcm_th_repl_list_start_ptr_get(int unit, int repl_group, bcm_port_t port, 3055 int *start_ptr) 3056 { 3057 soc_mem_t repl_group_table; 3058 soc_field_t member_bitmap_f, head_index_f; 3059 soc_info_t *si; 3060 bcm_port_t phy_port, mmu_port; 3061 int member_bitmap_index; 3062 int pipe; 3063 mmu_repl_group_info_tbl_entry_t repl_group_entry; 3064 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 3065 int i; 3066 soc_pbmp_t member_bitmap; 3067 int member_id, member; 3068 int head_index; 3069 uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS]; 3070 3071 member_bitmap_f = PIPE_MEMBER_BMPf; 3072 head_index_f = PIPE_BASE_PTRf; 3073 3074 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 3075 int aggid = TH_AGG_ID_INVALID; 3076 BCM_IF_ERROR_RETURN(bcm_th_port_to_aggid(unit, port, &aggid)); 3077 member_bitmap_index = aggid; 3078 } else { 3079 /* Get member bitmap index */ 3080 si = &SOC_INFO(unit); 3081 phy_port = si->port_l2p_mapping[port]; 3082 mmu_port = si->port_p2m_mapping[phy_port]; 3083 member_bitmap_index = mmu_port % mmu_port_stride[unit]; 3084 } 3085 3086 /* Get member bitmap */ 3087 BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe)); 3088 3089 repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe); 3090 3091 SOC_IF_ERROR_RETURN 3092 (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY, 3093 repl_group, &repl_group_entry)); 3094 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 3095 soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry, 3096 member_bitmap_f, fldbuf); 3097 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 3098 SOC_PBMP_WORD_SET(member_bitmap, i, fldbuf[i]); 3099 } 3100 3101 /* Check if port is in member bitmap */ 3102 if (!SOC_PBMP_MEMBER(member_bitmap, member_bitmap_index)) { 3103 *start_ptr = 0; 3104 return BCM_E_NONE; 3105 } 3106 3107 /* Get replication list start pointer */ 3108 member_id = 0; 3109 SOC_PBMP_ITER(member_bitmap, member) { 3110 if (member == member_bitmap_index) { 3111 break; 3112 } 3113 member_id++; 3114 } 3115 head_index = member_id + soc_mem_field32_get(unit, repl_group_table, 3116 &repl_group_entry, head_index_f); 3117 SOC_IF_ERROR_RETURN 3118 (_bcm_td3_repl_head_tbl_read(unit, pipe, 3119 head_index, repl_head_entry, (uint32 *)start_ptr)); 3120 3121 return BCM_E_NONE; 3122 } 3123 3124 /* 3125 * Function: 3126 * _bcm_th_repl_list_free 3127 * Purpose: 3128 * Free the REPL_LIST entries in the HW list starting at start_ptr. 3129 * Parameters: 3130 * unit - StrataSwitch PCI device unit number. 3131 * pipe - Pipeline number. 3132 * start_ptr - Replication list's start pointer to 3133 * REPL_LIST table. 3134 * Returns: 3135 * BCM_E_XXX 3136 */ 3137 STATIC int 3138 _bcm_th_repl_list_free(int unit, int pipe, int start_ptr) 3139 { 3140 mmu_repl_list_tbl_entry_t repl_list_entry; 3141 int prev_repl_entry_ptr, repl_entry_ptr; 3142 soc_mem_t repl_list_table; 3143 3144 prev_repl_entry_ptr = -1; 3145 repl_entry_ptr = start_ptr; 3146 if(SOC_IS_TOMAHAWK3(unit)) { 3147 repl_list_table = MMU_REPL_LIST_TBLm; 3148 pipe = 0; 3149 } else { 3150 repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe); 3151 } 3152 while (repl_entry_ptr != prev_repl_entry_ptr) { 3153 SOC_IF_ERROR_RETURN 3154 (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 3155 repl_entry_ptr, &repl_list_entry)); 3156 BCM_IF_ERROR_RETURN 3157 (_bcm_th_repl_list_entry_free(unit, pipe, repl_entry_ptr)); 3158 prev_repl_entry_ptr = repl_entry_ptr; 3159 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 3160 &repl_list_entry, NEXTPTRf); 3161 } 3162 3163 return BCM_E_NONE; 3164 } 3165 3166 /* 3167 * Function: 3168 * _bcm_th_repl_list_write 3169 * Purpose: 3170 * Write the replication list contained in intf_vec into REPL_LIST table. 3171 * Return the start_ptr and total interface count. 3172 * Parameters: 3173 * unit - StrataSwitch PCI device unit number. 3174 * pipe - Pipeline number. 3175 * start_ptr - (OUT) Replication list's start pointer to 3176 * REPL_LIST table. 3177 * intf_count - (OUT) Interface count. 3178 * intf_vec - (IN) Vector of interfaces. 3179 * Returns: 3180 * BCM_E_XXX 3181 */ 3182 STATIC int 3183 _bcm_th_repl_list_write(int unit, int pipe, int *start_ptr, int *intf_count, 3184 SHR_BITDCL *intf_vec) 3185 { 3186 int i; 3187 int remaining_count; 3188 int prev_repl_entry_ptr, repl_entry_ptr; 3189 uint32 msb_max, msb; 3190 uint32 ls_bits[2]; 3191 int rv = BCM_E_NONE; 3192 int no_more_free_repl_entries; 3193 mmu_repl_list_tbl_entry_t repl_list_entry; 3194 soc_mem_t repl_list_table; 3195 int max_rem_count = 5; 3196 3197 *intf_count = 0; 3198 for (i = 0; i < _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)); i++) { 3199 *intf_count += _shr_popcount(intf_vec[i]); 3200 } 3201 3202 if (*intf_count == 0) { 3203 return BCM_E_NONE; 3204 } 3205 repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe); 3206 remaining_count = *intf_count; 3207 prev_repl_entry_ptr = -1; 3208 msb_max = _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)) / 2; /* 32 -> 64 */ 3209 for (msb = 0; msb < msb_max; msb++) { 3210 ls_bits[0] = intf_vec[2 * msb + 0]; 3211 ls_bits[1] = intf_vec[2 * msb + 1]; 3212 if ((ls_bits[0] != 0) || (ls_bits[1] != 0)) { 3213 rv = _bcm_th_repl_list_entry_alloc(unit, pipe, &repl_entry_ptr); 3214 if (rv == BCM_E_RESOURCE) { 3215 no_more_free_repl_entries = TRUE; 3216 } else if (BCM_FAILURE(rv)) { 3217 return rv; 3218 } else { 3219 no_more_free_repl_entries = FALSE; 3220 } 3221 if (prev_repl_entry_ptr == -1) { 3222 if (no_more_free_repl_entries) { 3223 return BCM_E_RESOURCE; 3224 } 3225 *start_ptr = repl_entry_ptr; 3226 } else { 3227 if (no_more_free_repl_entries) { 3228 /* Terminate replication list */ 3229 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 3230 NEXTPTRf, prev_repl_entry_ptr); 3231 } else { 3232 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 3233 NEXTPTRf, repl_entry_ptr); 3234 } 3235 SOC_IF_ERROR_RETURN 3236 (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL, 3237 prev_repl_entry_ptr, &repl_list_entry)); 3238 if (no_more_free_repl_entries) { 3239 /* Free the list already written */ 3240 _bcm_th_repl_list_free(unit, pipe, *start_ptr); 3241 return BCM_E_RESOURCE; 3242 } 3243 } 3244 prev_repl_entry_ptr = repl_entry_ptr; 3245 3246 sal_memset(&repl_list_entry, 0, sizeof(repl_list_entry)); 3247 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 3248 MSB_VLANf, msb); 3249 soc_MMU_REPL_LIST_TBLm_field_set(unit, &repl_list_entry, 3250 LSB_VLAN_BMf, ls_bits); 3251 3252 remaining_count -= (_shr_popcount(ls_bits[0]) + 3253 _shr_popcount(ls_bits[1])); 3254 if (remaining_count > max_rem_count) { 3255 /* Set the RMNG_REPS field to all zeroes */ 3256 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 3257 RMNG_REPSf, 0); 3258 } else if (remaining_count > 0) { 3259 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, 3260 RMNG_REPSf, remaining_count); 3261 } else { /* No more intefaces left to be written */ 3262 break; 3263 } 3264 } 3265 } 3266 3267 if (prev_repl_entry_ptr > 0) { 3268 /* Write final entry */ 3269 soc_MMU_REPL_LIST_TBLm_field32_set(unit, &repl_list_entry, NEXTPTRf, 3270 prev_repl_entry_ptr); 3271 SOC_IF_ERROR_RETURN 3272 (soc_mem_write(unit, repl_list_table, MEM_BLOCK_ALL, 3273 prev_repl_entry_ptr, &repl_list_entry)); 3274 } 3275 3276 return BCM_E_NONE; 3277 } 3278 3279 /* 3280 * Function: 3281 * _bcm_th_repl_list_compare 3282 * Purpose: 3283 * Compare replication list starting at given pointer to 3284 * the interface list contained in intf_vec. 3285 * Parameters: 3286 * unit - StrataSwitch PCI device unit number. 3287 * pipe - Pipeline number. 3288 * start_ptr - Replication list's start pointer to REPL_LIST table. 3289 * intf_vec - Vector of interfaces. 3290 * Returns: 3291 * BCM_E_XXX 3292 */ 3293 STATIC int 3294 _bcm_th_repl_list_compare(int unit, int pipe, int start_ptr, 3295 SHR_BITDCL *intf_vec) 3296 { 3297 soc_mem_t repl_list_table; 3298 uint32 msb, hw_msb, msb_max; 3299 uint32 ls_bits[2], hw_ls_bits[2]; 3300 mmu_repl_list_tbl_entry_t repl_list_entry; 3301 int repl_entry_ptr, prev_repl_entry_ptr; 3302 3303 repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe); 3304 prev_repl_entry_ptr = -1; 3305 repl_entry_ptr = start_ptr; 3306 msb_max = _SHR_BITDCLSIZE(REPL_INTF_TOTAL(unit)) / 2; /* 32 -> 64 */ 3307 3308 for (msb = 0; msb < msb_max; msb++) { 3309 ls_bits[0] = intf_vec[2 * msb + 0]; 3310 ls_bits[1] = intf_vec[2 * msb + 1]; 3311 if ((ls_bits[0] != 0) || (ls_bits[1] != 0)) { 3312 if (repl_entry_ptr == prev_repl_entry_ptr) { /* HW list end */ 3313 return BCM_E_NOT_FOUND; 3314 } 3315 SOC_IF_ERROR_RETURN 3316 (soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 3317 repl_entry_ptr, &repl_list_entry)); 3318 hw_msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 3319 &repl_list_entry, MSB_VLANf); 3320 soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry, 3321 LSB_VLAN_BMf, hw_ls_bits); 3322 if ((hw_msb != msb) || (ls_bits[0] != hw_ls_bits[0]) || 3323 (ls_bits[1] != hw_ls_bits[1])) { 3324 return BCM_E_NOT_FOUND; 3325 } 3326 prev_repl_entry_ptr = repl_entry_ptr; 3327 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 3328 &repl_list_entry, NEXTPTRf); 3329 } 3330 } 3331 3332 return BCM_E_NONE; 3333 } 3334 3335 /* 3336 * Function: 3337 * _bcm_th_repl_intf_vec_construct 3338 * Purpose: 3339 * Construct replication interface vector. 3340 * Parameters: 3341 * unit - StrataSwitch PCI device unit number. 3342 * port - Port. 3343 * if_count - Number of interfaces in replication list. 3344 * if_array - (IN) List of interface numbers. 3345 * is_l3 - (IN) Indicates if interfaces are IPMC interfaces. 3346 * check_port - If if_array consists of L3 interfaces, this parameter 3347 * controls whether to check the given port is a member 3348 * in each L3 interface's VLAN. This check should be 3349 * disabled when not needed, in order to improve 3350 * performance. 3351 * intf_vec - (OUT) Vector of interfaces. 3352 * Returns: 3353 * BCM_E_XXX 3354 */ 3355 STATIC int 3356 _bcm_th_repl_intf_vec_construct(int unit, bcm_port_t port, int if_count, 3357 bcm_if_t *if_array, int is_l3, int check_port, SHR_BITDCL *intf_vec) 3358 { 3359 int if_num; 3360 bcm_l3_intf_t l3_intf; 3361 pbmp_t pbmp, ubmp; 3362 uint32 nh_flags; 3363 bcm_l3_egress_t nh_info; 3364 int nh_index; 3365 egr_l3_next_hop_entry_t egr_nh; 3366 int mac_oui, mac_non_oui; 3367 bcm_mac_t rbridge_mac; 3368 soc_field_t ent_type_fld = ENTRY_TYPEf; 3369 uint32 ent_type_val = 7; 3370 3371 #if defined(BCM_HGPROXY_COE_SUPPORT) 3372 bcm_port_t port_in = port; 3373 #endif 3374 3375 #ifdef BCM_TOMAHAWK3_SUPPORT 3376 egr_l3_next_hop_2_entry_t egr_nh2; 3377 if(SOC_IS_TOMAHAWK3(unit)) { 3378 ent_type_val = 3; 3379 } 3380 #endif 3381 3382 3383 #if defined(BCM_HGPROXY_COE_SUPPORT) 3384 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 3385 BCM_GPORT_IS_SET(port) && 3386 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) { 3387 BCM_IF_ERROR_RETURN( 3388 _bcmi_coe_subport_physical_port_get(unit, port, &port)); 3389 } 3390 #endif 3391 3392 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 3393 ent_type_fld = DATA_TYPEf; 3394 } 3395 3396 for (if_num = 0; if_num < if_count; if_num++) { 3397 if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, if_array[if_num])) { 3398 /* L3 interface is used */ 3399 3400 if (if_array[if_num] > soc_mem_index_max(unit, EGR_L3_INTFm)) { 3401 return BCM_E_PARAM; 3402 } 3403 3404 if (check_port) { 3405 bcm_l3_intf_t_init(&l3_intf); 3406 l3_intf.l3a_intf_id = if_array[if_num]; 3407 BCM_IF_ERROR_RETURN(bcm_esw_l3_intf_get(unit, &l3_intf)); 3408 if (!SOC_IS_TRIDENT3X(unit)) { 3409 BCM_IF_ERROR_RETURN(bcm_esw_vlan_port_get(unit, 3410 l3_intf.l3a_vid, &pbmp, &ubmp)); 3411 if (!BCM_PBMP_MEMBER(pbmp, port)) { 3412 return BCM_E_PARAM; 3413 } 3414 } 3415 } 3416 3417 /* Get a next hop index if the L3 inteface is not already 3418 * associated with one. 3419 */ 3420 if (is_l3) { /* L3 interface is being added to IPMC group */ 3421 if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, if_array[if_num]) == -1) { 3422 bcm_l3_egress_t_init(&nh_info); 3423 nh_flags = _BCM_L3_SHR_MATCH_DISABLE | 3424 _BCM_L3_SHR_WRITE_DISABLE; 3425 BCM_IF_ERROR_RETURN 3426 (bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index)); 3427 3428 sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t)); 3429 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3430 ent_type_fld, ent_type_val); 3431 if(soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3432 L3MC__INTF_NUMf)) { 3433 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3434 L3MC__INTF_NUMf, if_array[if_num]); 3435 } 3436 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3437 L3MC__HG_MODIFY_ENABLEf)) { 3438 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3439 L3MC__HG_MODIFY_ENABLEf, 0x1); 3440 } 3441 3442 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3443 L3MC__L2_MC_DA_DISABLEf)) { 3444 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3445 L3MC__L2_MC_DA_DISABLEf, 1); 3446 } 3447 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3448 L3MC__L2_MC_SA_DISABLEf)) { 3449 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3450 L3MC__L2_MC_SA_DISABLEf, 1); 3451 } 3452 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3453 L3MC__L2_MC_VLAN_DISABLEf)) { 3454 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3455 L3MC__L2_MC_VLAN_DISABLEf, 1); 3456 } 3457 3458 #if defined(BCM_HGPROXY_COE_SUPPORT) 3459 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 3460 BCM_GPORT_IS_SET(port_in) && 3461 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port_in)) { 3462 bcm_module_t mod_out; 3463 bcm_port_t port_out; 3464 bcm_trunk_t trunk_id; 3465 int local_id; 3466 3467 BCM_IF_ERROR_RETURN( 3468 _bcm_esw_gport_resolve(unit, port_in, 3469 &mod_out, &port_out, 3470 &trunk_id, &local_id)); 3471 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3472 L3MC__USE_MAC_DA_PROFILEf)) { 3473 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3474 L3MC__USE_MAC_DA_PROFILEf, 3475 TRUE); 3476 } 3477 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3478 L3MC__HG_MC_DST_PORT_NUMf)) { 3479 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3480 L3MC__HG_MC_DST_PORT_NUMf, 3481 port_out); 3482 } 3483 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, 3484 L3MC__HG_MC_DST_MODIDf)) { 3485 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3486 L3MC__HG_MC_DST_MODIDf, 3487 mod_out); 3488 } 3489 } 3490 #endif 3491 SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOPm, 3492 MEM_BLOCK_ALL, nh_index, &egr_nh)); 3493 3494 #ifdef BCM_TOMAHAWK3_SUPPORT 3495 if(SOC_IS_TOMAHAWK3(unit)) { 3496 SOC_IF_ERROR_RETURN( 3497 READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY, 3498 nh_index, &egr_nh2) ); 3499 3500 soc_mem_field32_set(unit, EGR_L3_NEXT_HOP_2m, &egr_nh2, 3501 INTF_NUMf, if_array[if_num]); 3502 3503 SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOP_2m, 3504 MEM_BLOCK_ALL, nh_index, &egr_nh2)); 3505 } 3506 #endif 3507 REPL_L3_INTF_NEXT_HOP_IPMC(unit, if_array[if_num]) = 3508 nh_index; 3509 } 3510 SHR_BITSET(intf_vec, 3511 REPL_L3_INTF_NEXT_HOP_IPMC(unit, if_array[if_num])); 3512 3513 } else { /* L3 interface is being added to Trill group */ 3514 if (REPL_L3_INTF_NEXT_HOP_TRILL(unit, if_array[if_num]) == -1) { 3515 bcm_l3_egress_t_init(&nh_info); 3516 nh_flags = _BCM_L3_SHR_MATCH_DISABLE | 3517 _BCM_L3_SHR_WRITE_DISABLE; 3518 BCM_IF_ERROR_RETURN 3519 (bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index)); 3520 3521 sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t)); 3522 if (SOC_IS_TD2_TT2(unit)) { 3523 /* 3524 * TD2 needs to set the entry_type to 0x7 (L3MC) 3525 * in order to use trill_all_rbridges_macda as the DA 3526 * in TRILL header 3527 */ 3528 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3529 ent_type_fld, ent_type_val); 3530 } else 3531 { 3532 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3533 ent_type_fld, 0); 3534 } 3535 #ifdef BCM_TOMAHAWK3_SUPPORT 3536 if(SOC_IS_TOMAHAWK3(unit)) { 3537 SOC_IF_ERROR_RETURN( 3538 READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY, 3539 nh_index, &egr_nh2) ); 3540 soc_mem_field32_set(unit, EGR_L3_NEXT_HOP_2m, &egr_nh2, 3541 INTF_NUMf, if_array[if_num]); 3542 3543 SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOP_2m, 3544 MEM_BLOCK_ALL, nh_index, &egr_nh2)); 3545 } else 3546 #endif 3547 { 3548 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3549 L3__INTF_NUMf, if_array[if_num]); 3550 } 3551 /* Get and Set rbridge mac */ 3552 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 3553 bcmSwitchTrillBroadcastDestMacOui, &mac_oui)); 3554 BCM_IF_ERROR_RETURN(bcm_esw_switch_control_get(unit, 3555 bcmSwitchTrillBroadcastDestMacNonOui, &mac_non_oui)); 3556 rbridge_mac[0] = (mac_oui >> 16) & 0xff; 3557 rbridge_mac[1] = (mac_oui >> 8) & 0xff; 3558 rbridge_mac[2] = mac_oui & 0xff; 3559 rbridge_mac[3] = (mac_non_oui >> 16) & 0xff; 3560 rbridge_mac[4] = (mac_non_oui >> 8) & 0xff; 3561 rbridge_mac[5] = mac_non_oui & 0xff; 3562 soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 3563 L3__MAC_ADDRESSf, rbridge_mac); 3564 3565 SOC_IF_ERROR_RETURN(soc_mem_write(unit, EGR_L3_NEXT_HOPm, 3566 MEM_BLOCK_ALL, nh_index, &egr_nh)); 3567 3568 REPL_L3_INTF_NEXT_HOP_TRILL(unit, if_array[if_num]) = 3569 nh_index; 3570 } 3571 SHR_BITSET(intf_vec, 3572 REPL_L3_INTF_NEXT_HOP_TRILL(unit, if_array[if_num])); 3573 } 3574 } else { 3575 /* Next hop is used */ 3576 SHR_BITSET(intf_vec, 3577 if_array[if_num] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit)); 3578 } 3579 } 3580 3581 return BCM_E_NONE; 3582 } 3583 3584 /* 3585 * Function: 3586 * _bcm_th_ipmc_cut_through_eligibility_set 3587 * Purpose: 3588 * Check cut-through eligibility for a given replication group. 3589 * Parameters: 3590 * unit - StrataSwitch PCI device unit number. 3591 * repl_group - The replication group number. 3592 * port - Port to assign replication list. 3593 * Returns: 3594 * BCM_E_XXX 3595 */ 3596 int 3597 _bcm_th_ipmc_cut_through_eligibility_set(int unit, int repl_group) 3598 { 3599 int rv = BCM_E_NONE; 3600 int i, pipe, member_bitmap_width; 3601 int member = 0; 3602 soc_mem_t repl_group_table; 3603 soc_field_t member_bitmap_f; 3604 mmu_repl_group_info_tbl_entry_t repl_group_entry; 3605 soc_pbmp_t old_member_bitmap[4]; 3606 soc_pbmp_t new_member_bitmap[4]; 3607 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 3608 soc_info_t *si; 3609 soc_pbmp_t l3_pbmp; 3610 bcm_port_t mmu_port, phy_port, logical_port; 3611 int cut_through_eligible = TRUE; 3612 ipmc_entry_t l3_ipmc_entry; 3613 #if defined(BCM_TRIDENT3_SUPPORT) 3614 bcm_multicast_t ipmc_group = 0; 3615 #endif 3616 3617 member_bitmap_f = PIPE_MEMBER_BMPf; 3618 member_bitmap_width = soc_mem_field_length(unit, MMU_REPL_GROUP_INFO_TBLm, 3619 member_bitmap_f); 3620 si = &SOC_INFO(unit); 3621 SOC_PBMP_CLEAR(l3_pbmp); 3622 3623 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 3624 SOC_PBMP_CLEAR(old_member_bitmap[pipe]); 3625 SOC_PBMP_CLEAR(new_member_bitmap[pipe]); 3626 /* Read pipeline's replication group table */ 3627 repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe); 3628 3629 SOC_IF_ERROR_RETURN 3630 (soc_mem_read(unit, repl_group_table, MEM_BLOCK_ANY, 3631 repl_group, &repl_group_entry)); 3632 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 3633 soc_mem_field_get(unit, repl_group_table, (uint32 *)&repl_group_entry, 3634 member_bitmap_f, fldbuf); 3635 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 3636 SOC_PBMP_WORD_SET(old_member_bitmap[pipe], i, fldbuf[i]); 3637 } 3638 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 3639 int aggid = TH_AGG_ID_INVALID; 3640 PBMP_ITER(PBMP_PIPE(unit, pipe), logical_port) { 3641 rv = bcm_th_port_to_aggid(unit, logical_port, &aggid); 3642 if (rv == BCM_E_NONE) { 3643 if (SOC_PBMP_MEMBER(old_member_bitmap[pipe], aggid)) { 3644 SOC_PBMP_PORT_ADD(new_member_bitmap[pipe], logical_port); 3645 } 3646 } 3647 } 3648 } else { 3649 for (i = 0; i < member_bitmap_width; i++) { 3650 if (SOC_PBMP_MEMBER(old_member_bitmap[pipe], i)) { 3651 mmu_port = i + mmu_port_stride[unit] * pipe; 3652 phy_port = si->port_m2p_mapping[mmu_port]; 3653 logical_port = si->port_p2l_mapping[phy_port]; 3654 SOC_PBMP_PORT_ADD(new_member_bitmap[pipe], logical_port); 3655 } 3656 } 3657 } 3658 SOC_PBMP_OR(l3_pbmp, new_member_bitmap[pipe]); 3659 } 3660 #if defined(BCM_TRIDENT3_SUPPORT) 3661 /* For VXLAN IPMC, cut-through is always disabled. 3662 * The IP header for the tunnel needs the entire length of 3663 * the IP payload. This implies that the MMU must store the 3664 * entire packet, determining its length and then forward it 3665 * to the EP. 3666 */ 3667 (void)_bcm_tr_multicast_ipmc_group_type_get(unit, repl_group, &ipmc_group); 3668 if (SOC_IS_TRIDENT3X(unit) && 3669 (_BCM_MULTICAST_TYPE_VXLAN == _BCM_MULTICAST_TYPE_GET(ipmc_group))){ 3670 cut_through_eligible = FALSE; 3671 } else 3672 #endif 3673 { 3674 SOC_PBMP_ITER(l3_pbmp, member) { 3675 /* 3676 * Packets with a single logical replication per port are 3677 * eligible for cut-through consideration. If the IPMC group has more 3678 * than 1 switch copy per egress port, DO_NOT_CUT_THROUGH bit in 3679 * L3_IPMC table must be set for the ipmc group. 3680 */ 3681 /* Coverity issue ignored: 3682 * Maximum port number used in l3_pbmp 3683 * should never exceed SOC_MAX_NUM_PP_PORTS */ 3684 /* coverity[overrun-local : FALSE] */ 3685 if (REPL_PORT_GROUP_INTF_COUNT(unit, member, repl_group) > 1) { 3686 cut_through_eligible = FALSE; 3687 break; 3688 } 3689 } 3690 } 3691 3692 soc_mem_lock(unit, L3_IPMCm); 3693 rv = READ_L3_IPMCm(unit, MEM_BLOCK_ANY, repl_group, &l3_ipmc_entry); 3694 if (BCM_SUCCESS(rv)) { 3695 if (!cut_through_eligible) { 3696 soc_L3_IPMCm_field32_set(unit, &l3_ipmc_entry, DO_NOT_CUT_THROUGHf, 3697 !cut_through_eligible); 3698 } else { 3699 /* This is needed to set the mode back to cut-through when 3700 * intf_count <= 1 after bcm_th_ipmc_egress_intf_delete is called. 3701 */ 3702 soc_L3_IPMCm_field32_set(unit, &l3_ipmc_entry, DO_NOT_CUT_THROUGHf, 3703 !cut_through_eligible); 3704 } 3705 rv = WRITE_L3_IPMCm(unit, MEM_BLOCK_ALL, repl_group, &l3_ipmc_entry); 3706 } 3707 soc_mem_unlock(unit, L3_IPMCm); 3708 3709 return rv; 3710 3711 } 3712 3713 /* 3714 * Function: 3715 * bcm_th_ipmc_egress_intf_set 3716 * Purpose: 3717 * Assign set of egress interfaces to port's replication list for chosen 3718 * replication group. 3719 * Parameters: 3720 * unit - StrataSwitch PCI device unit number. 3721 * repl_group - The replication group number. 3722 * port - Port to assign replication list. 3723 * if_count - Number of interfaces in replication list. 3724 * if_array - (IN) List of interface numbers. 3725 * is_l3 - (IN) Indicates if multicast group is of type IPMC. 3726 * check_port - (IN) If if_array consists of L3 interfaces, this parameter 3727 * controls whether to check the given port is a member 3728 * in each L3 interface's VLAN. This check should be 3729 * disabled when not needed, in order to improve 3730 * performance. 3731 * Returns: 3732 * BCM_E_XXX 3733 */ 3734 int 3735 bcm_th_ipmc_egress_intf_set(int unit, int repl_group, bcm_port_t port, 3736 int if_count, bcm_if_t *if_array, int is_l3, 3737 int check_port) 3738 { 3739 int rv = BCM_E_NONE; 3740 int pipe; 3741 int set_repl_list; 3742 int prev_start_ptr, list_start_ptr=0; 3743 int alloc_size; 3744 SHR_BITDCL *intf_vec = NULL; 3745 int repl_hash; 3746 _bcm_repl_list_info_t *rli_current, *rli_prev; 3747 int intf_count; 3748 int new_repl_list = FALSE; 3749 bcm_port_t port_in = port; 3750 3751 REPL_INIT(unit); 3752 REPL_GROUP_ID(unit, repl_group); 3753 #if defined(BCM_HGPROXY_COE_SUPPORT) 3754 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 3755 BCM_GPORT_IS_SET(port) && 3756 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) { 3757 BCM_IF_ERROR_RETURN( 3758 _bcmi_coe_subport_physical_port_get(unit, port, &port)); 3759 } 3760 #endif 3761 3762 3763 if (!IS_CPU_PORT(unit, port)) { 3764 REPL_PORT_CHECK(unit, port); 3765 } 3766 BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe)); 3767 3768 #ifdef BCM_TOMAHAWK3_SUPPORT 3769 if (SOC_IS_TOMAHAWK3(unit)) { 3770 if (if_count > TH3_IPMC_MAX_INTF_COUNT) { 3771 return BCM_E_PARAM; 3772 } 3773 } 3774 #endif 3775 if (if_count > REPL_INTF_TOTAL(unit)) { 3776 return BCM_E_PARAM; 3777 } else if (if_count > 0) { 3778 set_repl_list = TRUE; 3779 } else { 3780 set_repl_list = FALSE; 3781 } 3782 3783 if (REPL_PORT_GROUP_INFO(unit, port) == NULL) { 3784 return BCM_E_PORT; 3785 } 3786 3787 if ((if_count == 0) && 3788 (REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) == 0)) { 3789 return BCM_E_NONE; 3790 } 3791 3792 REPL_LOCK(unit); 3793 #ifdef BCM_TOMAHAWK3_SUPPORT 3794 if(SOC_IS_TOMAHAWK3(unit)) { 3795 rv = bcm_th3_repl_list_start_ptr_get(unit, repl_group, port, 3796 &prev_start_ptr); 3797 pipe = 0; 3798 } else 3799 #endif 3800 { 3801 /* Get current replication list start pointer of (repl_group, port) */ 3802 rv = _bcm_th_repl_list_start_ptr_get(unit, repl_group, port, 3803 &prev_start_ptr); 3804 } 3805 if (BCM_FAILURE(rv)) { 3806 goto intf_set_done; 3807 } 3808 3809 if (set_repl_list) { 3810 /* Set new replication list for given (repl_group, port) */ 3811 3812 /* Interface validation and vector construction */ 3813 alloc_size = SHR_BITALLOCSIZE(REPL_INTF_TOTAL(unit)); 3814 intf_vec = sal_alloc(alloc_size, "Repl interface vector"); 3815 if (intf_vec == NULL) { 3816 rv = BCM_E_MEMORY; 3817 goto intf_set_done; 3818 } 3819 sal_memset(intf_vec, 0, alloc_size); 3820 rv = _bcm_th_repl_intf_vec_construct(unit, port_in, if_count, if_array, 3821 is_l3, check_port, intf_vec); 3822 if (BCM_FAILURE(rv)) { 3823 goto intf_set_done; 3824 } 3825 3826 /* Search for matching replication list */ 3827 repl_hash = _shr_crc32b(0, (uint8 *)intf_vec, REPL_INTF_TOTAL(unit)); 3828 for (rli_current = REPL_LIST_INFO(unit, pipe); rli_current != NULL; 3829 rli_current = rli_current->next) { 3830 if (repl_hash == rli_current->hash) { 3831 #ifdef BCM_TOMAHAWK3_SUPPORT 3832 if(SOC_IS_TOMAHAWK3(unit)) { 3833 rv = _bcm_th3_repl_list_compare(unit, pipe, 3834 rli_current->index, intf_vec); 3835 3836 } else 3837 #endif 3838 { 3839 rv = _bcm_th_repl_list_compare(unit, pipe, rli_current->index, 3840 intf_vec); 3841 } 3842 if (rv == BCM_E_NOT_FOUND) { 3843 continue; /* Not a match */ 3844 } else if (BCM_FAILURE(rv)) { 3845 goto intf_set_done; 3846 } else { 3847 break; /* Match */ 3848 } 3849 } 3850 } 3851 3852 if (rli_current != NULL) { 3853 /* Found a match */ 3854 if (prev_start_ptr == rli_current->index) { 3855 /* (repl_group, port) already points to this list, so done */ 3856 rv = BCM_E_NONE; 3857 goto intf_set_done; 3858 } else { 3859 list_start_ptr = rli_current->index; 3860 intf_count = rli_current->list_size; 3861 } 3862 } else { 3863 /* Not a match, make a new chain */ 3864 #ifdef BCM_TOMAHAWK3_SUPPORT 3865 if(SOC_IS_TOMAHAWK3(unit)) { 3866 rv = _bcm_th3_repl_list_write(unit, pipe, &list_start_ptr, 3867 &intf_count, intf_vec); 3868 } else 3869 #endif 3870 { 3871 rv = _bcm_th_repl_list_write(unit, pipe, &list_start_ptr, 3872 &intf_count, intf_vec); 3873 } 3874 if (BCM_FAILURE(rv)) { 3875 goto intf_set_done; 3876 } 3877 3878 if (intf_count > 0) { 3879 /* Update data structures */ 3880 alloc_size = sizeof(_bcm_repl_list_info_t); 3881 rli_current = sal_alloc(alloc_size, "IPMC repl list info"); 3882 if (rli_current == NULL) { 3883 /* Release list */ 3884 _bcm_th_repl_list_free(unit, pipe, list_start_ptr); 3885 rv = BCM_E_MEMORY; 3886 goto intf_set_done; 3887 } 3888 sal_memset(rli_current, 0, alloc_size); 3889 rli_current->index = list_start_ptr; 3890 rli_current->hash = repl_hash; 3891 rli_current->list_size = intf_count; 3892 rli_current->next = REPL_LIST_INFO(unit, pipe); 3893 REPL_LIST_INFO(unit, pipe) = rli_current; 3894 new_repl_list = TRUE; 3895 } else { 3896 rv = BCM_E_INTERNAL; 3897 goto intf_set_done; 3898 } 3899 } 3900 3901 /* Update replication list start pointer */ 3902 #ifdef BCM_TOMAHAWK3_SUPPORT 3903 if (SOC_IS_TOMAHAWK3(unit)) { 3904 rv = bcm_th3_repl_list_start_ptr_set(unit, repl_group, port, 3905 list_start_ptr, intf_count); 3906 3907 } else 3908 3909 #endif 3910 { 3911 rv = _bcm_th_repl_list_start_ptr_set(unit, repl_group, port, 3912 list_start_ptr, intf_count); 3913 } 3914 if (BCM_FAILURE(rv)) { 3915 if (new_repl_list) { 3916 _bcm_th_repl_list_free(unit, pipe, list_start_ptr); 3917 REPL_LIST_INFO(unit, pipe) = rli_current->next; 3918 sal_free(rli_current); 3919 } 3920 goto intf_set_done; 3921 } 3922 (rli_current->refcount)++; 3923 REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = intf_count; 3924 3925 } else { 3926 /* Delete replication list for given (repl_group, port) */ 3927 3928 if (prev_start_ptr != 0) { 3929 #ifdef BCM_TOMAHAWK3_SUPPORT 3930 if (SOC_IS_TOMAHAWK3(unit)) { 3931 rv = bcm_th3_repl_list_start_ptr_set(unit, repl_group, 3932 port, 0, 0); 3933 3934 } else 3935 #endif 3936 { 3937 rv = _bcm_th_repl_list_start_ptr_set(unit, repl_group, 3938 port, 0, 0); 3939 } 3940 if (BCM_FAILURE(rv)) { 3941 goto intf_set_done; 3942 } 3943 } 3944 REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = 0; 3945 } 3946 3947 /* Delete old replication list */ 3948 if (prev_start_ptr != 0) { 3949 rli_prev = NULL; 3950 for (rli_current = REPL_LIST_INFO(unit, pipe); rli_current != NULL; 3951 rli_current = rli_current->next) { 3952 if (prev_start_ptr == rli_current->index) { 3953 (rli_current->refcount)--; 3954 if (rli_current->refcount == 0) { 3955 /* Free these linked list entries */ 3956 if (rli_prev == NULL) { 3957 REPL_LIST_INFO(unit, pipe) = rli_current->next; 3958 } else { 3959 rli_prev->next = rli_current->next; 3960 } 3961 #ifdef BCM_TOMAHAWK3_SUPPORT 3962 /* the repl list is first put into a recycle candidate pool */ 3963 if(SOC_IS_TOMAHAWK3(unit)) { 3964 3965 rli_current->next = _repl_list_recycle_array[unit]->next; 3966 _repl_list_recycle_array[unit]->next = rli_current; 3967 (_repl_list_recycle_array[unit]->list_size)++; 3968 3969 } else 3970 #endif 3971 { 3972 _bcm_th_repl_list_free(unit, pipe, prev_start_ptr); 3973 sal_free(rli_current); 3974 } 3975 } 3976 break; 3977 } 3978 rli_prev = rli_current; 3979 } 3980 } 3981 #ifdef BCM_TOMAHAWK3_SUPPORT 3982 if(SOC_IS_TOMAHAWK3(unit)) { 3983 goto intf_set_done; 3984 } 3985 #endif 3986 /* 3987 * Packets with a single logical replication per port are 3988 * eligible for cut-through consideration. If the IPMC group has more 3989 * than 1 switch copy per egress port, DO_NOT_CUT_THROUGH bit in 3990 * L3_IPMC table must be set for the ipmc group. 3991 */ 3992 rv = _bcm_th_ipmc_cut_through_eligibility_set(unit, repl_group); 3993 3994 intf_set_done: 3995 3996 REPL_UNLOCK(unit); 3997 3998 if (intf_vec != NULL) { 3999 sal_free(intf_vec); 4000 } 4001 4002 return rv; 4003 } 4004 4005 /* 4006 * Function: 4007 * bcm_th_ipmc_egress_intf_get 4008 * Purpose: 4009 * Retrieve set of egress interfaces to port's replication list for chosen 4010 * replication group. 4011 * Parameters: 4012 * unit - StrataSwitch PCI device unit number. 4013 * repl_group - The replication group number. 4014 * port - Port from which to get replication list. 4015 * if_max - Maximum number of interfaces in replication list. 4016 * if_array - (OUT) List of interface numbers. 4017 * if_count - (OUT) Number of interfaces in replication list. 4018 * Returns: 4019 * BCM_E_XXX 4020 * Notes: 4021 * If the input parameter if_max = 0, return in the output parameter 4022 * if_count the total number of interfaces in the specified multicast 4023 * group's replication list. 4024 */ 4025 int 4026 bcm_th_ipmc_egress_intf_get(int unit, int repl_group, bcm_port_t port, 4027 int if_max, bcm_if_t *if_array, int *if_count) 4028 { 4029 int rv = BCM_E_NONE; 4030 int pipe; 4031 int prev_repl_entry_ptr, repl_entry_ptr; 4032 int intf_count; 4033 int l3_intf, intf_base; 4034 int ls_pos; 4035 uint32 ls_bits[2]; 4036 mmu_repl_list_tbl_entry_t repl_list_entry; 4037 int next_hop_index; 4038 int entry_type; 4039 egr_l3_next_hop_entry_t egr_nh; 4040 #ifdef BCM_TOMAHAWK3_SUPPORT 4041 egr_l3_next_hop_2_entry_t egr_nh2; 4042 #endif 4043 soc_mem_t repl_list_table; 4044 soc_field_t ent_type_fld = ENTRY_TYPEf; 4045 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 4046 ent_type_fld = DATA_TYPEf; 4047 } 4048 4049 REPL_INIT(unit); 4050 REPL_GROUP_ID(unit, repl_group); 4051 if (!IS_CPU_PORT(unit, port)) { 4052 REPL_PORT_CHECK(unit, port); 4053 } 4054 BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe)); 4055 4056 if (if_max < 0) { 4057 return BCM_E_PARAM; 4058 } else if (if_max > 0 && NULL == if_array) { 4059 return BCM_E_PARAM; 4060 } 4061 4062 if (NULL == if_count) { 4063 return BCM_E_PARAM; 4064 } 4065 4066 if(SOC_IS_TOMAHAWK3(unit)) { 4067 repl_list_table = MMU_REPL_LIST_TBLm; 4068 } else { 4069 repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe); 4070 } 4071 4072 REPL_LOCK(unit); 4073 if (REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) == 0) { 4074 *if_count = 0; 4075 REPL_UNLOCK(unit); 4076 return BCM_E_NONE; 4077 } 4078 4079 #ifdef BCM_TOMAHAWK3_SUPPORT 4080 if(SOC_IS_TOMAHAWK3(unit)) { 4081 rv = bcm_th3_repl_list_start_ptr_get(unit, repl_group, port, 4082 &repl_entry_ptr); 4083 } else 4084 #endif 4085 { 4086 rv = _bcm_th_repl_list_start_ptr_get(unit, repl_group, port, 4087 &repl_entry_ptr); 4088 } 4089 if (BCM_FAILURE(rv)) { 4090 goto intf_get_done; 4091 } 4092 4093 prev_repl_entry_ptr = -1; 4094 intf_count = 0; 4095 while (repl_entry_ptr != prev_repl_entry_ptr) { 4096 rv = soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 4097 repl_entry_ptr, &repl_list_entry); 4098 4099 if (BCM_FAILURE(rv)) { 4100 goto intf_get_done; 4101 } 4102 #ifdef BCM_TOMAHAWK3_SUPPORT 4103 if(SOC_IS_TOMAHAWK3(unit)) { 4104 uint32 nh_mode; 4105 4106 nh_mode = soc_MMU_REPL_LIST_TBLm_field32_get(unit, &repl_list_entry, 4107 MODEf); 4108 if(nh_mode) { 4109 /* sparse mode */ 4110 int i; 4111 for(i = 0; i < 4; i++) { 4112 rv = _bcm_th3_sparse_mode_egress_intf_get(unit, 4113 repl_entry_ptr, i, if_array, &intf_count); 4114 if(BCM_FAILURE(rv)) { 4115 goto intf_get_done; 4116 } 4117 if (intf_count == if_max) { 4118 *if_count = intf_count; 4119 goto intf_get_done; 4120 } 4121 4122 } 4123 prev_repl_entry_ptr = repl_entry_ptr; 4124 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 4125 &repl_list_entry, NEXTPTRf); 4126 if (intf_count >= REPL_PORT_GROUP_INTF_COUNT(unit, 4127 port, repl_group)) { 4128 break; 4129 } 4130 4131 continue; 4132 } 4133 } 4134 #endif 4135 /* Each MSB represents 64 entries in LSB bitmap */ 4136 intf_base = soc_MMU_REPL_LIST_TBLm_field32_get(unit, &repl_list_entry, 4137 MSB_VLANf) * 64; 4138 soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry, 4139 LSB_VLAN_BMf, ls_bits); 4140 4141 for (ls_pos = 0; ls_pos < 64; ls_pos++) { 4142 if (ls_bits[ls_pos / 32] & (1 << (ls_pos % 32))) { 4143 if (if_max == 0) { 4144 intf_count++; 4145 } else { 4146 next_hop_index = intf_base + ls_pos; 4147 if_array[intf_count] = next_hop_index + 4148 BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 4149 4150 /* Check if next hop index corresponds to 4151 * an IPMC or Trill interface. 4152 */ 4153 rv = READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, 4154 next_hop_index, &egr_nh); 4155 if (BCM_FAILURE(rv)) { 4156 goto intf_get_done; 4157 } 4158 #ifdef BCM_TOMAHAWK3_SUPPORT 4159 if (SOC_IS_TOMAHAWK3(unit)) { 4160 rv = READ_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ANY, 4161 next_hop_index, &egr_nh2); 4162 if (BCM_FAILURE(rv)) { 4163 goto intf_get_done; 4164 } 4165 } 4166 #endif 4167 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, 4168 &egr_nh, ent_type_fld); 4169 if (entry_type == 0) { 4170 #ifdef BCM_TOMAHAWK3_SUPPORT 4171 if (SOC_IS_TOMAHAWK3(unit)) { 4172 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, 4173 &egr_nh2, INTF_NUMf); 4174 4175 } else 4176 #endif 4177 { 4178 l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, 4179 &egr_nh, L3__INTF_NUMf); 4180 } 4181 if (REPL_L3_INTF_NEXT_HOP_TRILL(unit, l3_intf) == 4182 next_hop_index) { 4183 if_array[intf_count] = l3_intf; 4184 } 4185 } else if (entry_type == 7) { 4186 #ifdef BCM_TOMAHAWK3_SUPPORT 4187 if (SOC_IS_TOMAHAWK3(unit)) { 4188 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, 4189 &egr_nh2, INTF_NUMf); 4190 4191 } else 4192 #endif 4193 { 4194 l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, 4195 &egr_nh, L3MC__INTF_NUMf); 4196 } 4197 if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) == 4198 next_hop_index) { 4199 if_array[intf_count] = l3_intf; 4200 } 4201 } 4202 #ifdef BCM_TOMAHAWK3_SUPPORT 4203 else if ((entry_type == 3) && 4204 (SOC_IS_TOMAHAWK3(unit))) { 4205 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, 4206 &egr_nh2, INTF_NUMf); 4207 if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) == 4208 next_hop_index) { 4209 if_array[intf_count] = l3_intf; 4210 } 4211 4212 } 4213 #endif 4214 4215 intf_count++; 4216 if (intf_count == if_max) { 4217 *if_count = intf_count; 4218 goto intf_get_done; 4219 } 4220 } 4221 } 4222 } 4223 prev_repl_entry_ptr = repl_entry_ptr; 4224 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 4225 &repl_list_entry, NEXTPTRf); 4226 if (intf_count >= REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group)) { 4227 break; 4228 } 4229 } 4230 4231 *if_count = intf_count; 4232 4233 intf_get_done: 4234 REPL_UNLOCK(unit); 4235 return rv; 4236 } 4237 4238 /* 4239 * Function: 4240 * bcm_th_ipmc_egress_intf_add 4241 * Purpose: 4242 * Add L3 interface to selected ports' replication list for chosen 4243 * IPMC group. 4244 * Parameters: 4245 * unit - StrataSwitch PCI device unit number. 4246 * ipmc_id - IPMC group number. 4247 * port - port to add. 4248 * l3_intf - L3 interface to replicate. 4249 * Returns: 4250 * BCM_E_XXX 4251 */ 4252 int 4253 bcm_th_ipmc_egress_intf_add(int unit, int ipmc_id, bcm_port_t port, 4254 bcm_l3_intf_t *l3_intf) 4255 { 4256 bcm_if_t *if_array = NULL; 4257 int intf_num, intf_max, alloc_size, rv = BCM_E_NONE; 4258 pbmp_t pbmp, ubmp; 4259 #ifdef BCM_TOMAHAWK3_SUPPORT 4260 bcm_pbmp_t l2_pbmp, l3_pbmp; 4261 bcm_port_t port_idx; 4262 int th3_if_count = 0; 4263 #endif 4264 4265 REPL_INIT(unit); 4266 REPL_GROUP_ID(unit, ipmc_id); 4267 REPL_PORT_CHECK(unit, port); 4268 4269 /* Check if port belongs to this VLAN */ 4270 if (!SOC_IS_TRIDENT3X(unit)) { 4271 BCM_IF_ERROR_RETURN 4272 (bcm_esw_vlan_port_get(unit, l3_intf->l3a_vid, &pbmp, &ubmp)); 4273 if (!SOC_PBMP_MEMBER(pbmp, port)) { 4274 return BCM_E_PARAM; 4275 } 4276 } 4277 4278 intf_max = REPL_INTF_TOTAL(unit); 4279 #ifdef BCM_TOMAHAWK3_SUPPORT 4280 if (SOC_IS_TOMAHAWK3(unit)) { 4281 intf_max = TH3_IPMC_MAX_INTF_COUNT; 4282 /* Retrieve the number of replications for this MC group across all 4283 * ports */ 4284 rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp); 4285 /* Add any L2 copies for the MC group */ 4286 BCM_PBMP_COUNT(l2_pbmp, th3_if_count); 4287 /* Iterate among all L3 ports to get the sum of interface counts */ 4288 alloc_size = intf_max * sizeof(bcm_if_t); 4289 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4290 if (if_array == NULL) { 4291 return BCM_E_MEMORY; 4292 } 4293 4294 REPL_LOCK(unit); 4295 BCM_PBMP_ITER(l3_pbmp, port_idx) { 4296 if (port_idx == 158) { 4297 /* Skip checke for spare port used in B0 WAR*/ 4298 continue; 4299 } 4300 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port_idx, intf_max, 4301 if_array, &intf_num); 4302 if (!BCM_SUCCESS(rv)) { 4303 REPL_UNLOCK(unit); 4304 sal_free(if_array); 4305 return rv; 4306 } 4307 th3_if_count += intf_num; 4308 } 4309 REPL_UNLOCK(unit); 4310 sal_free(if_array); 4311 if (th3_if_count >= intf_max) { 4312 return BCM_E_EXISTS; 4313 } 4314 } 4315 #endif 4316 4317 alloc_size = intf_max * sizeof(bcm_if_t); 4318 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4319 if (if_array == NULL) { 4320 return BCM_E_MEMORY; 4321 } 4322 4323 REPL_LOCK(unit); 4324 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max, 4325 if_array, &intf_num); 4326 if (BCM_SUCCESS(rv)) { 4327 if (intf_num < intf_max) { 4328 if_array[intf_num++] = l3_intf->l3a_intf_id; 4329 rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 4330 intf_num, if_array, TRUE, FALSE); 4331 } else { 4332 rv = BCM_E_EXISTS; 4333 } 4334 } 4335 4336 REPL_UNLOCK(unit); 4337 sal_free(if_array); 4338 return rv; 4339 } 4340 4341 /* 4342 * Function: 4343 * bcm_th_ipmc_egress_intf_delete 4344 * Purpose: 4345 * Remove L3 interface from selected ports' replication list for chosen 4346 * IPMC group. 4347 * Parameters: 4348 * unit - StrataSwitch PCI device unit number. 4349 * ipmc_id - IPMC group number. 4350 * port - port to remove. 4351 * l3_intf - L3 interface to delete from replication. 4352 * Returns: 4353 * BCM_E_XXX 4354 */ 4355 int 4356 bcm_th_ipmc_egress_intf_delete(int unit, int ipmc_id, bcm_port_t port, 4357 bcm_l3_intf_t *l3_intf) 4358 { 4359 bcm_if_t *if_array = NULL; 4360 int alloc_size, intf_max, if_count, if_cur, match, rv = BCM_E_NONE; 4361 4362 REPL_INIT(unit); 4363 REPL_GROUP_ID(unit, ipmc_id); 4364 REPL_PORT_CHECK(unit, port); 4365 4366 if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) { 4367 return BCM_E_NOT_FOUND; 4368 } 4369 4370 intf_max = REPL_INTF_TOTAL(unit); 4371 #ifdef BCM_TOMAHAWK3_SUPPORT 4372 if (SOC_IS_TOMAHAWK3(unit)) { 4373 intf_max = TH3_IPMC_MAX_INTF_COUNT; 4374 } 4375 #endif 4376 alloc_size = intf_max * sizeof(bcm_if_t); 4377 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4378 if (if_array == NULL) { 4379 return BCM_E_MEMORY; 4380 } 4381 4382 REPL_LOCK(unit); 4383 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max, 4384 if_array, &if_count); 4385 if (BCM_SUCCESS(rv)) { 4386 match = FALSE; 4387 for (if_cur = 0; if_cur < if_count; if_cur++) { 4388 if (match) { 4389 if_array[if_cur - 1] = if_array[if_cur]; 4390 } else { 4391 if (if_array[if_cur] == l3_intf->l3a_intf_id) { 4392 match = TRUE; 4393 } 4394 } 4395 } 4396 if (match) { 4397 if_count--; 4398 rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 4399 if_count, if_array, TRUE, FALSE); 4400 } else { 4401 rv = BCM_E_NOT_FOUND; 4402 } 4403 } 4404 4405 REPL_UNLOCK(unit); 4406 sal_free(if_array); 4407 return rv; 4408 } 4409 4410 /* 4411 * Function: 4412 * _bcm_th_ipmc_repl_get 4413 * Purpose: 4414 * Return set of VLANs selected for port's replication list for chosen 4415 * IPMC group. 4416 * Parameters: 4417 * unit - StrataSwitch PCI device unit number. 4418 * ipmc_id - IPMC group number. 4419 * port - port to list. 4420 * vlan_vec - (OUT) vector of replicated VLANs common to selected ports. 4421 * Returns: 4422 * BCM_E_XXX 4423 */ 4424 int 4425 bcm_th_ipmc_repl_get(int unit, int ipmc_id, bcm_port_t port, 4426 bcm_vlan_vector_t vlan_vec) 4427 { 4428 int rv = BCM_E_NONE; 4429 int pipe; 4430 uint32 ls_bits[2]; 4431 int prev_repl_entry_ptr, repl_entry_ptr; 4432 int intf_base; 4433 int ls_pos; 4434 mmu_repl_list_tbl_entry_t repl_list_entry; 4435 int next_hop_index; 4436 int entry_type; 4437 bcm_l3_intf_t l3_intf; 4438 bcm_l3_egress_t egress_object; 4439 bcm_if_t egr_if; 4440 int vlan_count; 4441 egr_l3_next_hop_entry_t egr_nh; 4442 soc_mem_t repl_list_table; 4443 soc_field_t ent_type_fld = ENTRY_TYPEf; 4444 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 4445 ent_type_fld = DATA_TYPEf; 4446 } 4447 4448 REPL_INIT(unit); 4449 REPL_GROUP_ID(unit, ipmc_id); 4450 REPL_PORT_CHECK(unit, port); 4451 BCM_IF_ERROR_RETURN(_bcm_th_port_pipe_get(unit, port, &pipe)); 4452 4453 BCM_VLAN_VEC_ZERO(vlan_vec); 4454 4455 repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe); 4456 REPL_LOCK(unit); 4457 if (REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id) == 0) { 4458 REPL_UNLOCK(unit); 4459 return BCM_E_NONE; 4460 } 4461 4462 rv = _bcm_th_repl_list_start_ptr_get(unit, ipmc_id, port, 4463 &repl_entry_ptr); 4464 if (BCM_FAILURE(rv)) { 4465 goto vlan_get_done; 4466 } 4467 4468 prev_repl_entry_ptr = -1; 4469 vlan_count = 0; 4470 while (repl_entry_ptr != prev_repl_entry_ptr) { 4471 rv = soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 4472 repl_entry_ptr, &repl_list_entry); 4473 if (BCM_FAILURE(rv)) { 4474 goto vlan_get_done; 4475 } 4476 /* Each MSB represents 64 entries in LSB bitmap */ 4477 intf_base = soc_MMU_REPL_LIST_TBLm_field32_get(unit, &repl_list_entry, 4478 MSB_VLANf) * 64; 4479 soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry, 4480 LSB_VLAN_BMf, ls_bits); 4481 for (ls_pos = 0; ls_pos < 64; ls_pos++) { 4482 if (ls_bits[ls_pos / 32] & (1 << (ls_pos % 32))) { 4483 next_hop_index = intf_base + ls_pos; 4484 rv = READ_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, 4485 next_hop_index, &egr_nh); 4486 if (BCM_FAILURE(rv)) { 4487 goto vlan_get_done; 4488 } 4489 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, 4490 &egr_nh, ent_type_fld); 4491 bcm_l3_intf_t_init(&l3_intf); 4492 if (entry_type == 7) { 4493 l3_intf.l3a_intf_id = soc_EGR_L3_NEXT_HOPm_field32_get(unit, 4494 &egr_nh, L3MC__INTF_NUMf); 4495 } else { 4496 egr_if = next_hop_index + BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 4497 rv = bcm_esw_l3_egress_get(unit, egr_if, &egress_object); 4498 if (BCM_FAILURE(rv)) { 4499 goto vlan_get_done; 4500 } 4501 l3_intf.l3a_intf_id = egress_object.intf; 4502 } 4503 rv = bcm_esw_l3_intf_get(unit, &l3_intf); 4504 if (BCM_FAILURE(rv)) { 4505 goto vlan_get_done; 4506 } 4507 BCM_VLAN_VEC_SET(vlan_vec, l3_intf.l3a_vid); 4508 vlan_count++; 4509 } 4510 } 4511 prev_repl_entry_ptr = repl_entry_ptr; 4512 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 4513 &repl_list_entry, NEXTPTRf); 4514 if (vlan_count >= REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) { 4515 break; 4516 } 4517 } 4518 4519 vlan_get_done: 4520 REPL_UNLOCK(unit); 4521 return rv; 4522 } 4523 4524 /* 4525 * Function: 4526 * _bcm_th_ipmc_repl_add 4527 * Purpose: 4528 * Add VLAN to selected ports' replication list for chosen 4529 * IPMC group. 4530 *Parameters: 4531 * unit - StrataSwitch PCI device unit number. 4532 * ipmc_id - IPMC group number. 4533 * port - port to add. 4534 * vlan - VLAN to replicate. 4535 * Returns: 4536 * BCM_E_XXX 4537 */ 4538 int 4539 bcm_th_ipmc_repl_add(int unit, int ipmc_id, bcm_port_t port, 4540 bcm_vlan_t vlan) 4541 { 4542 int alloc_size, intf_max, if_count, rv = BCM_E_NONE; 4543 bcm_if_t *if_array = NULL; 4544 pbmp_t pbmp, ubmp; 4545 bcm_l3_intf_t l3_intf; 4546 4547 REPL_INIT(unit); 4548 REPL_GROUP_ID(unit, ipmc_id); 4549 REPL_PORT_CHECK(unit, port); 4550 4551 /* Check if port belongs to this VLAN */ 4552 BCM_IF_ERROR_RETURN 4553 (bcm_esw_vlan_port_get(unit, vlan, &pbmp, &ubmp)); 4554 if (!SOC_PBMP_MEMBER(pbmp, port)) { 4555 return BCM_E_PARAM; 4556 } 4557 4558 bcm_l3_intf_t_init(&l3_intf); 4559 l3_intf.l3a_vid = vlan; 4560 if (bcm_esw_l3_intf_find_vlan(unit, &l3_intf) < 0) { 4561 return BCM_E_PARAM; 4562 } 4563 4564 REPL_LOCK(unit); 4565 4566 intf_max = 1 + REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id); 4567 alloc_size = intf_max * sizeof(bcm_if_t); 4568 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4569 if (if_array == NULL) { 4570 REPL_UNLOCK(unit); 4571 return BCM_E_MEMORY; 4572 } 4573 4574 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max, 4575 if_array, &if_count); 4576 if (BCM_SUCCESS(rv)) { 4577 if (if_count < intf_max) { 4578 if_array[if_count++] = l3_intf.l3a_intf_id; 4579 rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 4580 if_count, if_array, TRUE, FALSE); 4581 } else { 4582 rv = BCM_E_EXISTS; 4583 } 4584 } 4585 4586 REPL_UNLOCK(unit); 4587 sal_free(if_array); 4588 return rv; 4589 } 4590 4591 /* 4592 * Function: 4593 * _bcm_th_ipmc_repl_delete 4594 * Purpose: 4595 * Remove VLAN from selected ports' replication list for chosen 4596 * IPMC group. 4597 * Parameters: 4598 * unit - StrataSwitch PCI device unit number. 4599 * ipmc_id - IPMC group number. 4600 * port - port to remove. 4601 * vlan - VLAN to delete from replication. 4602 * Returns: 4603 * BCM_E_XXX 4604 */ 4605 4606 int 4607 bcm_th_ipmc_repl_delete(int unit, int ipmc_id, bcm_port_t port, 4608 bcm_vlan_t vlan) 4609 { 4610 int alloc_size, intf_max, if_count, if_cur, match, rv = BCM_E_NONE; 4611 bcm_if_t *if_array = NULL; 4612 bcm_l3_intf_t l3_intf; 4613 4614 REPL_INIT(unit); 4615 REPL_GROUP_ID(unit, ipmc_id); 4616 REPL_PORT_CHECK(unit, port); 4617 4618 if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) { 4619 return BCM_E_NOT_FOUND; 4620 } 4621 4622 bcm_l3_intf_t_init(&l3_intf); 4623 l3_intf.l3a_vid = vlan; 4624 if (bcm_esw_l3_intf_find_vlan(unit, &l3_intf) < 0) { 4625 return BCM_E_PARAM; 4626 } 4627 4628 REPL_LOCK(unit); 4629 intf_max = REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id); 4630 alloc_size = intf_max * sizeof(bcm_if_t); 4631 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4632 if (if_array == NULL) { 4633 REPL_UNLOCK(unit); 4634 return BCM_E_MEMORY; 4635 } 4636 4637 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max, 4638 if_array, &if_count); 4639 if (BCM_SUCCESS(rv)) { 4640 match = FALSE; 4641 for (if_cur = 0; if_cur < if_count; if_cur++) { 4642 if (match) { 4643 if_array[if_cur - 1] = if_array[if_cur]; 4644 } else { 4645 if (if_array[if_cur] == l3_intf.l3a_intf_id) { 4646 match = TRUE; 4647 } 4648 } 4649 } 4650 if (match) { 4651 if_count--; 4652 rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 4653 if_count, if_array, TRUE, FALSE); 4654 } else { 4655 rv = BCM_E_NOT_FOUND; 4656 } 4657 } 4658 REPL_UNLOCK(unit); 4659 sal_free(if_array); 4660 return rv; 4661 } 4662 4663 /* 4664 * Function: 4665 * bcm_th_ipmc_repl_delete_all 4666 * Purpose: 4667 * Remove all VLANs from selected ports' replication list for chosen 4668 * IPMC group. 4669 * Parameters: 4670 * unit - StrataSwitch PCI device unit number. 4671 * ipmc_id - The MC index number. 4672 * port - port from which to remove VLANs. 4673 * Returns: 4674 * BCM_E_XXX 4675 */ 4676 int 4677 bcm_th_ipmc_repl_delete_all(int unit, int ipmc_id, bcm_port_t port) 4678 { 4679 REPL_INIT(unit); 4680 REPL_GROUP_ID(unit, ipmc_id); 4681 REPL_PORT_CHECK(unit, port); 4682 4683 if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) { 4684 /* Nothing to do */ 4685 return BCM_E_NONE; 4686 } 4687 4688 return bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 0, NULL, 4689 TRUE, FALSE); 4690 } 4691 4692 /* 4693 * Function: 4694 * bcm_th_ipmc_repl_set 4695 * Purpose: 4696 * Assign set of VLANs provided to port's replication list for chosen 4697 * IPMC group. 4698 * Parameters: 4699 * unit - StrataSwitch PCI device unit number. 4700 * ipmc_id - The index number. 4701 * port - port to list. 4702 * vlan_vec - (IN) vector of replicated VLANs common to selected ports. 4703 * Returns: 4704 * BCM_E_XXX 4705 */ 4706 int 4707 bcm_th_ipmc_repl_set(int unit, int ipmc_id, bcm_port_t port, 4708 bcm_vlan_vector_t vlan_vec) 4709 { 4710 int rv = BCM_E_NONE; 4711 bcm_if_t *if_array = NULL; 4712 bcm_l3_intf_t l3_intf; 4713 pbmp_t pbmp, ubmp; 4714 int intf_num, intf_max, alloc_size, vid; 4715 4716 REPL_INIT(unit); 4717 REPL_GROUP_ID(unit, ipmc_id); 4718 REPL_PORT_CHECK(unit, port); 4719 4720 intf_max = BCM_VLAN_MAX - BCM_VLAN_MIN + 1; 4721 alloc_size = intf_max * sizeof(bcm_if_t); 4722 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4723 if (if_array == NULL) { 4724 return BCM_E_MEMORY; 4725 } 4726 4727 sal_memset(if_array, 0, alloc_size); 4728 intf_num = 0; 4729 for (vid = BCM_VLAN_MIN; vid < BCM_VLAN_MAX; vid++) { 4730 if (BCM_VLAN_VEC_GET(vlan_vec, vid)) { 4731 rv = bcm_esw_vlan_port_get(unit, vid, &pbmp, &ubmp); 4732 if (BCM_FAILURE(rv)) { 4733 sal_free(if_array); 4734 return rv; 4735 } 4736 if (!BCM_PBMP_MEMBER(pbmp, port)) { 4737 sal_free(if_array); 4738 return BCM_E_PARAM; 4739 } 4740 bcm_l3_intf_t_init(&l3_intf); 4741 l3_intf.l3a_vid = vid; 4742 if ((rv = bcm_esw_l3_intf_find_vlan(unit, &l3_intf)) < 0) { 4743 sal_free(if_array); 4744 return rv; 4745 } 4746 if_array[intf_num++] = l3_intf.l3a_intf_id; 4747 } 4748 } 4749 4750 rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 4751 intf_num, if_array, TRUE, FALSE); 4752 4753 sal_free(if_array); 4754 return rv; 4755 } 4756 4757 /* 4758 * Function: 4759 * _bcm_th_ipmc_egress_intf_add 4760 * Purpose: 4761 * Add encap ID to selected ports' replication list for chosen 4762 * IPMC group. 4763 * Parameters: 4764 * unit - StrataSwitch PCI device unit number. 4765 * ipmc_id - IPMC group number. 4766 * port - port to add. 4767 * encap_id - Encap ID. 4768 * is_l3 - Indicates if multicast group type is IPMC. 4769 * Returns: 4770 * BCM_E_XXX 4771 */ 4772 int 4773 _bcm_th_ipmc_egress_intf_add(int unit, int ipmc_id, bcm_port_t port, 4774 int encap_id, int is_l3) 4775 { 4776 bcm_if_t *if_array = NULL; 4777 int intf_num, intf_max, alloc_size, rv = BCM_E_NONE; 4778 pbmp_t pbmp, ubmp; 4779 bcm_l3_intf_t l3_intf; 4780 bcm_port_t port_in = port; 4781 4782 #ifdef BCM_TOMAHAWK3_SUPPORT 4783 bcm_pbmp_t l2_pbmp, l3_pbmp; 4784 bcm_port_t port_idx; 4785 int th3_if_count = 0; 4786 #endif 4787 4788 REPL_INIT(unit); 4789 REPL_GROUP_ID(unit, ipmc_id); 4790 4791 #if defined(BCM_HGPROXY_COE_SUPPORT) 4792 if (soc_feature(unit, soc_feature_hgproxy_subtag_coe) && 4793 BCM_GPORT_IS_SET(port) && 4794 _BCM_COE_GPORT_IS_SUBTAG_SUBPORT_PORT(unit, port)) { 4795 BCM_IF_ERROR_RETURN( 4796 _bcmi_coe_subport_physical_port_get(unit, port, &port)); 4797 } 4798 #endif 4799 4800 if (!IS_CPU_PORT(unit, port)) { 4801 REPL_PORT_CHECK(unit, port); 4802 } 4803 4804 if ((BCM_MC_PER_TRUNK_REPL_MODE(unit)) && 4805 encap_id == BCM_ENCAP_TRUNK_MEMBER) { 4806 /* For TH_MC_PER_TRUNK_REPL mode, indentical replication list is set 4807 * for all the members of a trunk. 4808 */ 4809 return BCM_E_NONE; 4810 } 4811 4812 intf_max = REPL_INTF_TOTAL(unit); 4813 #ifdef BCM_TOMAHAWK3_SUPPORT 4814 if (SOC_IS_TOMAHAWK3(unit)) { 4815 intf_max = TH3_IPMC_MAX_INTF_COUNT; 4816 /* Retrieve the number of replications for this MC group across all 4817 * ports */ 4818 rv = _bcm_esw_multicast_ipmc_read(unit, ipmc_id, &l2_pbmp, &l3_pbmp); 4819 /* Add any L2 copies for the MC group */ 4820 BCM_PBMP_COUNT(l2_pbmp, th3_if_count); 4821 /* Iterate among all L3 ports to get the sum of interface counts */ 4822 alloc_size = intf_max * sizeof(bcm_if_t); 4823 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4824 if (if_array == NULL) { 4825 return BCM_E_MEMORY; 4826 } 4827 4828 REPL_LOCK(unit); 4829 BCM_PBMP_ITER(l3_pbmp, port_idx) { 4830 if (port_idx == 158) { 4831 /* Skip checke for spare port used in B0 WAR*/ 4832 continue; 4833 } 4834 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port_idx, intf_max, 4835 if_array, &intf_num); 4836 if (!BCM_SUCCESS(rv)) { 4837 goto intf_add_done; 4838 } 4839 th3_if_count += intf_num; 4840 } 4841 REPL_UNLOCK(unit); 4842 sal_free(if_array); 4843 if (th3_if_count >= intf_max) { 4844 return BCM_E_EXISTS; 4845 } 4846 } 4847 #endif 4848 alloc_size = intf_max * sizeof(bcm_if_t); 4849 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4850 if (if_array == NULL) { 4851 return BCM_E_MEMORY; 4852 } 4853 4854 REPL_LOCK(unit); 4855 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, intf_max, 4856 if_array, &intf_num); 4857 if (BCM_SUCCESS(rv)) { 4858 if (intf_num < intf_max) { 4859 if_array[intf_num++] = encap_id; 4860 4861 /* For IPMC and Trill, check port is a member of the L3 interface's 4862 * VLAN. Performing this check here is more efficient than doing 4863 * it in bcm_th_ipmc_egress_intf_set. 4864 */ 4865 if (!BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, encap_id)) { 4866 /* L3 interface is used */ 4867 4868 if (encap_id > soc_mem_index_max(unit, EGR_L3_INTFm)) { 4869 rv = BCM_E_PARAM; 4870 goto intf_add_done; 4871 } 4872 4873 bcm_l3_intf_t_init(&l3_intf); 4874 l3_intf.l3a_intf_id = encap_id; 4875 rv = bcm_esw_l3_intf_get(unit, &l3_intf); 4876 if (BCM_FAILURE(rv)) { 4877 goto intf_add_done; 4878 } 4879 4880 if (!SOC_IS_TRIDENT3X(unit)) { 4881 rv = bcm_esw_vlan_port_get(unit, l3_intf.l3a_vid, 4882 &pbmp, &ubmp); 4883 if (BCM_FAILURE(rv)) { 4884 goto intf_add_done; 4885 } 4886 if (!BCM_PBMP_MEMBER(pbmp, port)) { 4887 rv = BCM_E_PARAM; 4888 goto intf_add_done; 4889 } 4890 } 4891 } 4892 4893 rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port_in, 4894 intf_num, if_array, is_l3, FALSE); 4895 } else { 4896 rv = BCM_E_EXISTS; 4897 } 4898 } 4899 4900 intf_add_done: 4901 4902 REPL_UNLOCK(unit); 4903 sal_free(if_array); 4904 return rv; 4905 } 4906 4907 /* 4908 * Function: 4909 * _bcm_th_ipmc_egress_intf_delete 4910 * Purpose: 4911 * Remove encap ID from selected ports' replication list for chosen 4912 * IPMC group. 4913 * Parameters: 4914 * unit - StrataSwitch PCI device unit number. 4915 * ipmc_id - IPMC group number. 4916 * port - port to remove. 4917 * if_max - Maximal interface. 4918 * encap_id - Encap ID to delete from replication. 4919 * is_l3 - Indicates if multicast group type is IPMC. 4920 * Returns: 4921 * BCM_E_XXX 4922 */ 4923 int 4924 _bcm_th_ipmc_egress_intf_delete(int unit, int ipmc_id, bcm_port_t port, 4925 int if_max, int encap_id, int is_l3) 4926 { 4927 bcm_if_t *if_array = NULL; 4928 int alloc_size, if_count, if_cur, match, rv = BCM_E_NONE; 4929 4930 REPL_INIT(unit); 4931 REPL_GROUP_ID(unit, ipmc_id); 4932 if (!IS_CPU_PORT(unit, port)) { 4933 REPL_PORT_CHECK(unit, port); 4934 } 4935 4936 if ((BCM_MC_PER_TRUNK_REPL_MODE(unit)) && 4937 encap_id == BCM_ENCAP_TRUNK_MEMBER) { 4938 /* For MC_PER_TRUNK_REPL mode, indentical replication list is set 4939 * for all the members of a trunk. 4940 */ 4941 return BCM_E_NONE; 4942 } 4943 4944 if (!REPL_PORT_GROUP_INTF_COUNT(unit, port, ipmc_id)) { 4945 return BCM_E_NOT_FOUND; 4946 } 4947 4948 if ((if_max <= 0) || ((uint32)if_max > REPL_INTF_TOTAL(unit))) { 4949 return BCM_E_PARAM; 4950 } 4951 #ifdef BCM_TOMAHAWK3_SUPPORT 4952 if (SOC_IS_TOMAHAWK3(unit)) { 4953 if((uint32)if_max > TH3_IPMC_MAX_INTF_COUNT) { 4954 return BCM_E_PARAM; 4955 } 4956 } 4957 #endif 4958 4959 alloc_size = if_max * sizeof(bcm_if_t); 4960 if_array = sal_alloc(alloc_size, "IPMC repl interface array"); 4961 if (if_array == NULL) { 4962 return BCM_E_MEMORY; 4963 } 4964 4965 REPL_LOCK(unit); 4966 rv = bcm_th_ipmc_egress_intf_get(unit, ipmc_id, port, if_max, 4967 if_array, &if_count); 4968 if (BCM_SUCCESS(rv)) { 4969 match = FALSE; 4970 for (if_cur = 0; if_cur < if_count; if_cur++) { 4971 if (match) { 4972 if_array[if_cur - 1] = if_array[if_cur]; 4973 } else { 4974 if (if_array[if_cur] == encap_id) { 4975 match = TRUE; 4976 } 4977 } 4978 } 4979 if (match) { 4980 if_count--; 4981 rv = bcm_th_ipmc_egress_intf_set(unit, ipmc_id, port, 4982 if_count, if_array, is_l3, FALSE); 4983 } else { 4984 rv = BCM_E_NOT_FOUND; 4985 } 4986 } 4987 4988 REPL_UNLOCK(unit); 4989 sal_free(if_array); 4990 return rv; 4991 } 4992 4993 /* 4994 * Function: 4995 * bcm_th_ipmc_trill_mac_update 4996 * Purpose: 4997 * Update the Trill MAC address in next hop entries that are 4998 * in Trill multicast replication list. 4999 * Parameters: 5000 * unit - (IN) SOC unit # 5001 * mac_field - (IN) MAC address 5002 * flag - (IN) 0 = Set the lower 24 bits of MAC address, 5003 * 1 = Set the higher 24 bits of MAC address. 5004 * Returns: 5005 * BCM_E_XXX 5006 */ 5007 int 5008 bcm_th_ipmc_trill_mac_update(int unit, uint32 mac_field, uint8 flag) 5009 { 5010 int intf, nh_index; 5011 egr_l3_next_hop_entry_t egr_nh; 5012 uint32 entry_type; 5013 bcm_mac_t mac; 5014 soc_field_t ent_type_fld = ENTRY_TYPEf; 5015 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 5016 ent_type_fld = DATA_TYPEf; 5017 } 5018 5019 for (intf = 0; intf < soc_mem_index_count(unit, EGR_L3_INTFm); intf++) { 5020 nh_index = REPL_L3_INTF_NEXT_HOP_TRILL(unit, intf); 5021 if (nh_index >= 0) { 5022 SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_NEXT_HOPm, 5023 MEM_BLOCK_ANY, nh_index, &egr_nh)); 5024 entry_type = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, 5025 &egr_nh, ent_type_fld); 5026 if (entry_type == 0) { /* normal entry type */ 5027 soc_mem_mac_addr_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, 5028 L3__MAC_ADDRESSf, mac); 5029 if (!flag) { 5030 /* Set the low-order bytes */ 5031 mac[3] = (uint8) (mac_field >> 16 & 0xff); 5032 mac[4] = (uint8) (mac_field >> 8 & 0xff); 5033 mac[5] = (uint8) (mac_field & 0xff); 5034 } else { 5035 /* Set the High-order bytes */ 5036 mac[0] = (uint8) (mac_field >> 16 & 0xff); 5037 mac[1] = (uint8) (mac_field >> 8 & 0xff); 5038 mac[2] = (uint8) (mac_field & 0xff); 5039 } 5040 soc_mem_mac_addr_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, 5041 L3__MAC_ADDRESSf, mac); 5042 } 5043 } 5044 } 5045 5046 return BCM_E_NONE; 5047 } 5048 5049 /* 5050 * Function: 5051 * bcm_th_ipmc_l3_intf_next_hop_free 5052 * Purpose: 5053 * Free the next hop index associated with the given L3 interface. 5054 * Parameters: 5055 * unit - (IN) SOC unit # 5056 * intf - (IN) L3 interface ID 5057 * Returns: 5058 * BCM_E_XXX 5059 */ 5060 int 5061 bcm_th_ipmc_l3_intf_next_hop_free(int unit, int intf) 5062 { 5063 int nh_index; 5064 5065 if (_th_repl_info[unit] == NULL) { 5066 /* IPMC replication is not initialized. There is no next hop 5067 * index to free. 5068 */ 5069 return BCM_E_NONE; 5070 } 5071 5072 nh_index = REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf); 5073 if (nh_index >= 0) { 5074 #ifdef BCM_TOMAHAWK3_SUPPORT 5075 if (SOC_IS_TOMAHAWK3(unit)) { 5076 SOC_IF_ERROR_RETURN 5077 (WRITE_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ALL, nh_index, 5078 soc_mem_entry_null(unit, 5079 EGR_L3_NEXT_HOP_2m))); 5080 } 5081 #endif 5082 SOC_IF_ERROR_RETURN 5083 (WRITE_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ALL, nh_index, 5084 soc_mem_entry_null(unit, EGR_L3_NEXT_HOPm))); 5085 BCM_IF_ERROR_RETURN 5086 (bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index)); 5087 REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf) = -1; 5088 } 5089 5090 nh_index = REPL_L3_INTF_NEXT_HOP_TRILL(unit, intf); 5091 if (nh_index >= 0) { 5092 #ifdef BCM_TOMAHAWK3_SUPPORT 5093 if (SOC_IS_TOMAHAWK3(unit)) { 5094 SOC_IF_ERROR_RETURN 5095 (WRITE_EGR_L3_NEXT_HOP_2m(unit, MEM_BLOCK_ALL, nh_index, 5096 soc_mem_entry_null(unit, 5097 EGR_L3_NEXT_HOP_2m))); 5098 } 5099 5100 #endif 5101 SOC_IF_ERROR_RETURN 5102 (WRITE_EGR_L3_NEXT_HOPm(unit, MEM_BLOCK_ALL, nh_index, 5103 soc_mem_entry_null(unit, EGR_L3_NEXT_HOPm))); 5104 BCM_IF_ERROR_RETURN 5105 (bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index)); 5106 REPL_L3_INTF_NEXT_HOP_TRILL(unit, intf) = -1; 5107 } 5108 5109 return BCM_E_NONE; 5110 } 5111 5112 #ifdef BCM_WARM_BOOT_SUPPORT 5113 STATIC int 5114 bcm_th_set_port_intf_cnt(int unit, int pipe,int aggid, 5115 int repl_group, int intf_cnt) 5116 { 5117 int port_iter, aggid_iter, pipe_iter=0; 5118 uint32 regval; 5119 bcm_pbmp_t pbmp_all; 5120 5121 BCM_PBMP_CLEAR(pbmp_all); 5122 BCM_PBMP_ASSIGN(pbmp_all, PBMP_ALL(unit)); 5123 5124 PBMP_ITER(pbmp_all, port_iter) { 5125 5126 if (SOC_IS_TOMAHAWK3(unit)) { 5127 BCM_IF_ERROR_RETURN( 5128 READ_MMU_RQE_REPL_PORT_AGG_MAPr(unit, port_iter, ®val)); 5129 aggid_iter = soc_reg_field_get(unit, MMU_RQE_REPL_PORT_AGG_MAPr, regval, 5130 L3MC_PORT_AGG_IDf); 5131 } else { 5132 BCM_IF_ERROR_RETURN( 5133 READ_MMU_DQS_REPL_PORT_AGG_MAPr(unit, port_iter, ®val)); 5134 aggid_iter = soc_reg_field_get(unit, MMU_DQS_REPL_PORT_AGG_MAPr, regval, 5135 L3MC_PORT_AGG_IDf); 5136 5137 /* coverity[overrun-local:FALSE] */ 5138 pipe_iter = SOC_INFO(unit).port_pipe[port_iter]; 5139 } 5140 5141 if ((aggid_iter == aggid) && (pipe_iter == pipe)) { 5142 /* coverity[overrun-local:FALSE] */ 5143 REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) = intf_cnt; 5144 } 5145 } 5146 5147 return BCM_E_NONE; 5148 } 5149 5150 STATIC int 5151 bcm_th_add_port_intf_cnt(int unit, int pipe, int aggid, 5152 int repl_group, int intf_cnt) 5153 { 5154 int port_iter, aggid_iter, pipe_iter=0; 5155 uint32 regval; 5156 bcm_pbmp_t pbmp_all; 5157 5158 BCM_PBMP_CLEAR(pbmp_all); 5159 BCM_PBMP_ASSIGN(pbmp_all, PBMP_ALL(unit)); 5160 5161 PBMP_ITER(pbmp_all, port_iter) { 5162 if (SOC_IS_TOMAHAWK3(unit)) { 5163 BCM_IF_ERROR_RETURN( 5164 READ_MMU_RQE_REPL_PORT_AGG_MAPr(unit, port_iter, ®val)); 5165 aggid_iter = soc_reg_field_get(unit, MMU_RQE_REPL_PORT_AGG_MAPr, regval, 5166 L3MC_PORT_AGG_IDf); 5167 } else { 5168 BCM_IF_ERROR_RETURN( 5169 READ_MMU_DQS_REPL_PORT_AGG_MAPr(unit, port_iter, ®val)); 5170 aggid_iter = soc_reg_field_get(unit, MMU_DQS_REPL_PORT_AGG_MAPr, regval, 5171 L3MC_PORT_AGG_IDf); 5172 /* coverity[overrun-local:FALSE] */ 5173 pipe_iter = SOC_INFO(unit).port_pipe[port_iter]; 5174 } 5175 5176 if ((aggid_iter == aggid) && (pipe_iter == pipe)) { 5177 /* coverity[overrun-local:FALSE] */ 5178 REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) += intf_cnt; 5179 } 5180 } 5181 5182 return BCM_E_NONE; 5183 } 5184 5185 /* 5186 * Function: 5187 * _bcm_th_ipmc_repl_reload 5188 * Purpose: 5189 * Re-Initialize replication software to state consistent with 5190 * hardware. 5191 * Parameters: 5192 * unit - SOC unit # 5193 * Returns: 5194 * BCM_E_XXX 5195 */ 5196 int 5197 _bcm_th_ipmc_repl_reload(int unit) 5198 { 5199 int rv = BCM_E_NONE; 5200 soc_mem_t repl_group_table; 5201 soc_field_t base_idx_f; 5202 soc_field_t member_bitmap_f; 5203 int alloc_size; 5204 int intf_vec_alloc_size; 5205 uint8 *repl_group_buf = NULL; 5206 SHR_BITDCL *intf_vec = NULL; 5207 int pipe; 5208 int index_min, index_max; 5209 int i, j; 5210 uint32 *repl_group_entry; 5211 int head_index; 5212 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 5213 soc_pbmp_t member_bitmap; 5214 int member_count; 5215 int member_id, member; 5216 soc_info_t *si; 5217 bcm_port_t mmu_port, phy_port, port = -1; 5218 uint32 repl_head_entry[SOC_MAX_MEM_FIELD_WORDS]; 5219 int start_ptr; 5220 _bcm_repl_list_info_t *rli_current; 5221 int prev_repl_entry_ptr, repl_entry_ptr; 5222 mmu_repl_list_tbl_entry_t repl_list_entry; 5223 int msb; 5224 uint32 ls_bits[2]; 5225 uint8 *egr_nh_buf = NULL; 5226 egr_l3_next_hop_entry_t *egr_nh_entry; 5227 #ifdef BCM_TOMAHAWK3_SUPPORT 5228 uint8 *egr_nh2_buf = NULL; 5229 egr_l3_next_hop_2_entry_t *egr_nh2_entry = NULL; 5230 #endif 5231 int entry_type; 5232 int l3_intf; 5233 uint8 flags; 5234 soc_mem_t repl_list_table; 5235 int aggid = -1, intf_cnt = 0; 5236 5237 soc_field_t ent_type_fld = ENTRY_TYPEf; 5238 if (soc_mem_field_valid(unit, EGR_L3_NEXT_HOPm, DATA_TYPEf)) { 5239 ent_type_fld = DATA_TYPEf; 5240 } 5241 5242 /* Initialize internal data structures */ 5243 BCM_IF_ERROR_RETURN(bcm_th_ipmc_repl_init(unit)); 5244 5245 /* Recover internal state by traversing replication lists 5246 * in each pipeline. 5247 */ 5248 #ifdef BCM_TOMAHAWK3_SUPPORT 5249 if(SOC_IS_TOMAHAWK3(unit)) { 5250 base_idx_f = BASE_PTRf; 5251 member_bitmap_f = MEMBER_BMPf; 5252 } else 5253 #endif 5254 { 5255 base_idx_f = PIPE_BASE_PTRf; 5256 member_bitmap_f = PIPE_MEMBER_BMPf; 5257 } 5258 5259 alloc_size = 4 * SOC_MEM_WORDS(unit, MMU_REPL_GROUP_INFO_TBLm) * 5260 _th_repl_info[unit]->num_repl_groups; 5261 repl_group_buf = soc_cm_salloc(unit, alloc_size, "repl group buf"); 5262 if (NULL == repl_group_buf) { 5263 rv = BCM_E_MEMORY; 5264 goto cleanup; 5265 } 5266 5267 intf_vec_alloc_size = SHR_BITALLOCSIZE(REPL_INTF_TOTAL(unit)); 5268 intf_vec = sal_alloc(intf_vec_alloc_size, "Repl interface vector"); 5269 if (intf_vec == NULL) { 5270 rv = BCM_E_MEMORY; 5271 goto cleanup; 5272 } 5273 sal_memset(intf_vec, 0, intf_vec_alloc_size); 5274 5275 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 5276 /* Read pipeline's replication group table */ 5277 if(SOC_IS_TOMAHAWK3(unit)) { 5278 repl_list_table = MMU_REPL_LIST_TBLm; 5279 repl_group_table = MMU_REPL_GROUP_INFO_TBLm; 5280 } else { 5281 repl_list_table = REPL_LIST_TBL_PIPE(unit, pipe); 5282 repl_group_table = REPL_GROUP_INFO_TBL_PIPE(unit, pipe); 5283 } 5284 5285 index_min = 0; 5286 index_max = _th_repl_info[unit]->num_repl_groups - 1; 5287 rv = soc_mem_read_range(unit, repl_group_table, MEM_BLOCK_ANY, 5288 index_min, index_max, repl_group_buf); 5289 if (SOC_FAILURE(rv)) { 5290 goto cleanup; 5291 } 5292 5293 for (i = index_min; i <= index_max; i++) { 5294 repl_group_entry = soc_mem_table_idx_to_pointer(unit, 5295 repl_group_table, uint32 *, repl_group_buf, i); 5296 5297 /* Get the head index */ 5298 head_index = soc_mem_field32_get(unit, repl_group_table, 5299 repl_group_entry, base_idx_f); 5300 if (0 == head_index) { 5301 continue; /* with next replication group */ 5302 } 5303 5304 /* Get the member bitmap */ 5305 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 5306 soc_mem_field_get(unit, repl_group_table, repl_group_entry, 5307 member_bitmap_f, fldbuf); 5308 for (j = 0; j < SOC_PBMP_WORD_MAX; j++) { 5309 SOC_PBMP_WORD_SET(member_bitmap, j, fldbuf[j]); 5310 } 5311 SOC_PBMP_COUNT(member_bitmap, member_count); 5312 if (0 == member_count) { 5313 continue; /* with next replication group */ 5314 } 5315 5316 member_id = 0; 5317 SOC_PBMP_ITER(member_bitmap, member) { 5318 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 5319 aggid = member; 5320 } else { 5321 if (SOC_IS_TOMAHAWK3(unit)) { 5322 port = member; 5323 } else { 5324 /* Convert member to mmu port, then to physical port, and 5325 * finally to logical port */ 5326 mmu_port = pipe * mmu_port_stride[unit] + member; 5327 si = &SOC_INFO(unit); 5328 phy_port = si->port_m2p_mapping[mmu_port]; 5329 port = si->port_p2l_mapping[phy_port]; 5330 } 5331 } 5332 5333 /* Get replication list start pointer */ 5334 rv = _bcm_td3_repl_head_tbl_read(unit, pipe, 5335 (head_index + member_id), repl_head_entry, 5336 (uint32 *)&start_ptr); 5337 if (SOC_FAILURE(rv)) { 5338 goto cleanup; 5339 } 5340 member_id++; 5341 if (0 == start_ptr) { 5342 continue; /* with next member */ 5343 } 5344 5345 if (_bcm_th_repl_list_entry_used_get(unit, pipe, start_ptr)) { 5346 /* Already traversed this replication list */ 5347 for (rli_current = REPL_LIST_INFO(unit, pipe); 5348 rli_current != NULL; 5349 rli_current = rli_current->next) { 5350 if (rli_current->index == start_ptr) { 5351 (rli_current->refcount)++; 5352 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 5353 intf_cnt = rli_current->list_size; 5354 bcm_th_set_port_intf_cnt(unit, pipe, aggid, 5355 i, intf_cnt); 5356 } else { 5357 REPL_PORT_GROUP_INTF_COUNT(unit, port, i) = 5358 rli_current->list_size; 5359 } 5360 break; 5361 } 5362 } 5363 if (rli_current == NULL) { 5364 /* Unexpected */ 5365 rv = BCM_E_INTERNAL; 5366 goto cleanup; 5367 } else { 5368 continue; /* with next member */ 5369 } 5370 } 5371 5372 /* Traverse the replication list table */ 5373 sal_memset(intf_vec, 0, intf_vec_alloc_size); 5374 prev_repl_entry_ptr = -1; 5375 repl_entry_ptr = start_ptr; 5376 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 5377 intf_cnt = 0; 5378 } 5379 while (repl_entry_ptr != prev_repl_entry_ptr) { 5380 rv = soc_mem_read(unit, repl_list_table, MEM_BLOCK_ANY, 5381 repl_entry_ptr, &repl_list_entry); 5382 if (BCM_FAILURE(rv)) { 5383 goto cleanup; 5384 } 5385 msb = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 5386 &repl_list_entry, MSB_VLANf); 5387 soc_MMU_REPL_LIST_TBLm_field_get(unit, &repl_list_entry, 5388 LSB_VLAN_BMf, ls_bits); 5389 intf_vec[2 * msb + 0] = ls_bits[0]; 5390 intf_vec[2 * msb + 1] = ls_bits[1]; 5391 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 5392 intf_cnt += (_shr_popcount(ls_bits[0]) + 5393 _shr_popcount(ls_bits[1])); 5394 } else { 5395 REPL_PORT_GROUP_INTF_COUNT(unit, port, i) += 5396 _shr_popcount(ls_bits[0]) + _shr_popcount(ls_bits[1]); 5397 } 5398 rv = _bcm_th_repl_list_entry_used_set(unit, pipe, 5399 repl_entry_ptr); 5400 if (BCM_FAILURE(rv)) { 5401 goto cleanup; 5402 } 5403 prev_repl_entry_ptr = repl_entry_ptr; 5404 repl_entry_ptr = soc_MMU_REPL_LIST_TBLm_field32_get(unit, 5405 &repl_list_entry, NEXTPTRf); 5406 } 5407 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 5408 bcm_th_add_port_intf_cnt(unit, pipe, aggid, i, intf_cnt); 5409 } 5410 5411 /* Insert a new replication list into linked list */ 5412 rli_current = sal_alloc(sizeof(_bcm_repl_list_info_t), 5413 "repl list info"); 5414 if (rli_current == NULL) { 5415 rv = BCM_E_MEMORY; 5416 goto cleanup; 5417 } 5418 sal_memset(rli_current, 0, sizeof(_bcm_repl_list_info_t)); 5419 rli_current->index = start_ptr; 5420 rli_current->hash = _shr_crc32b(0, (uint8 *)intf_vec, 5421 REPL_INTF_TOTAL(unit)); 5422 if (BCM_MC_PER_TRUNK_REPL_MODE(unit)) { 5423 rli_current->list_size = intf_cnt; 5424 } else { 5425 rli_current->list_size = REPL_PORT_GROUP_INTF_COUNT(unit, port, i); 5426 } 5427 (rli_current->refcount)++; 5428 rli_current->next = REPL_LIST_INFO(unit, pipe); 5429 REPL_LIST_INFO(unit, pipe) = rli_current; 5430 } 5431 5432 /* Update REPL_HEAD table usage */ 5433 rv = _bcm_th_repl_head_block_used_set(unit, pipe, head_index, 5434 member_count); 5435 if (BCM_FAILURE(rv)) { 5436 goto cleanup; 5437 } 5438 } 5439 } 5440 soc_cm_sfree(unit, repl_group_buf); 5441 repl_group_buf = NULL; 5442 sal_free(intf_vec); 5443 intf_vec = NULL; 5444 5445 /* Recover array of next hop indices for L3 interfaces */ 5446 egr_nh_buf = soc_cm_salloc(unit, 5447 SOC_MEM_TABLE_BYTES(unit, EGR_L3_NEXT_HOPm), "egr nh buf"); 5448 if (NULL == egr_nh_buf) { 5449 rv = BCM_E_MEMORY; 5450 goto cleanup; 5451 } 5452 index_min = soc_mem_index_min(unit, EGR_L3_NEXT_HOPm); 5453 index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOPm); 5454 rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOPm, MEM_BLOCK_ANY, 5455 index_min, index_max, egr_nh_buf); 5456 if (SOC_FAILURE(rv)) { 5457 goto cleanup; 5458 } 5459 5460 #ifdef BCM_TOMAHAWK3_SUPPORT 5461 if (SOC_IS_TOMAHAWK3(unit)) { 5462 /* Recover array of next hop indices for L3 interfaces */ 5463 egr_nh2_buf = soc_cm_salloc(unit, 5464 SOC_MEM_TABLE_BYTES(unit, EGR_L3_NEXT_HOP_2m), 5465 "egr nh_2 buf"); 5466 if (NULL == egr_nh2_buf) { 5467 rv = BCM_E_MEMORY; 5468 goto cleanup; 5469 } 5470 index_min = soc_mem_index_min(unit, EGR_L3_NEXT_HOP_2m); 5471 index_max = soc_mem_index_max(unit, EGR_L3_NEXT_HOP_2m); 5472 rv = soc_mem_read_range(unit, EGR_L3_NEXT_HOP_2m, MEM_BLOCK_ANY, 5473 index_min, index_max, egr_nh2_buf); 5474 if (SOC_FAILURE(rv)) { 5475 goto cleanup; 5476 } 5477 } 5478 #endif 5479 5480 for (i = index_min; i <= index_max; i++) { 5481 egr_nh_entry = soc_mem_table_idx_to_pointer 5482 (unit, EGR_L3_NEXT_HOPm, egr_l3_next_hop_entry_t *, 5483 egr_nh_buf, i); 5484 #ifdef BCM_TOMAHAWK3_SUPPORT 5485 if (SOC_IS_TOMAHAWK3(unit)) { 5486 egr_nh2_entry = soc_mem_table_idx_to_pointer 5487 (unit, EGR_L3_NEXT_HOP_2m, egr_l3_next_hop_2_entry_t *, 5488 egr_nh2_buf, i); 5489 } 5490 #endif 5491 entry_type = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry, 5492 ent_type_fld); 5493 if (entry_type == 0) { 5494 #ifdef BCM_TOMAHAWK3_SUPPORT 5495 if (SOC_IS_TOMAHAWK3(unit)) { 5496 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, egr_nh2_entry, 5497 INTF_NUMf); 5498 } else 5499 #endif 5500 { 5501 l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry, 5502 L3__INTF_NUMf); 5503 } 5504 REPL_L3_INTF_NEXT_HOP_TRILL(unit, l3_intf) = i; 5505 } else if (entry_type == 7) { 5506 #ifdef BCM_TOMAHAWK3_SUPPORT 5507 if (SOC_IS_TOMAHAWK3(unit)) { 5508 l3_intf = soc_EGR_L3_NEXT_HOP_2m_field32_get(unit, egr_nh2_entry, 5509 INTF_NUMf); 5510 } else 5511 #endif 5512 { 5513 l3_intf = soc_EGR_L3_NEXT_HOPm_field32_get(unit, egr_nh_entry, 5514 L3MC__INTF_NUMf); 5515 } 5516 REPL_L3_INTF_NEXT_HOP_IPMC(unit, l3_intf) = i; 5517 } else { 5518 continue; 5519 } 5520 } 5521 soc_cm_sfree(unit, egr_nh_buf); 5522 egr_nh_buf = NULL; 5523 #ifdef BCM_TOMAHAWK3_SUPPORT 5524 if (SOC_IS_TOMAHAWK3(unit)) { 5525 soc_cm_sfree(unit, egr_nh2_buf); 5526 egr_nh2_buf = NULL; 5527 } 5528 #endif 5529 5530 /* Recover REPL list mode from HW cache */ 5531 rv = _bcm_esw_ipmc_repl_wb_flags_get(unit, 5532 _BCM_IPMC_WB_REPL_LIST, &flags); 5533 if (flags) { 5534 SOC_IPMCREPLSHR_SET(unit, 1); 5535 } 5536 5537 cleanup: 5538 if (repl_group_buf) { 5539 soc_cm_sfree(unit, repl_group_buf); 5540 } 5541 if (intf_vec) { 5542 sal_free(intf_vec); 5543 } 5544 5545 if (egr_nh_buf) { 5546 soc_cm_sfree(unit, egr_nh_buf); 5547 } 5548 5549 #ifdef BCM_TOMAHAWK3_SUPPORT 5550 if (SOC_IS_TOMAHAWK3(unit)) { 5551 if (egr_nh2_buf) { 5552 soc_cm_sfree(unit, egr_nh2_buf); 5553 } 5554 } 5555 #endif 5556 5557 if (BCM_FAILURE(rv)) { 5558 bcm_th_ipmc_repl_detach(unit); 5559 } 5560 5561 return rv; 5562 } 5563 #endif /* BCM_WARM_BOOT_SUPPORT */ 5564 5565 #ifndef BCM_SW_STATE_DUMP_DISABLE 5566 /* 5567 * Function: 5568 * _bcm_th_ipmc_repl_sw_dump 5569 * Purpose: 5570 * Displays IPMC replication information maintained by software. 5571 * Parameters: 5572 * unit - Device unit number 5573 * Returns: 5574 * None 5575 */ 5576 void 5577 _bcm_th_ipmc_repl_sw_dump(int unit) 5578 { 5579 _th_repl_info_t *repl_info; 5580 int pipe; 5581 bcm_port_t port; 5582 _th_repl_port_info_t *port_info; 5583 int i, j; 5584 _bcm_repl_list_info_t *rli_start, *rli_current; 5585 SHR_BITDCL *bitmap; 5586 _th_repl_head_free_block_t *free_block; 5587 5588 LOG_CLI((BSL_META_U(unit, 5589 " IPMC REPL Info -\n"))); 5590 repl_info = _th_repl_info[unit]; 5591 if (repl_info != NULL) { 5592 LOG_CLI((BSL_META_U(unit, 5593 " Number of Pipelines : %d\n"), 5594 repl_info->num_pipes)); 5595 LOG_CLI((BSL_META_U(unit, 5596 " Replication Group Size : %d\n"), 5597 repl_info->num_repl_groups)); 5598 LOG_CLI((BSL_META_U(unit, 5599 " Replication Intf Size : %d\n"), 5600 repl_info->num_intf)); 5601 5602 LOG_CLI((BSL_META_U(unit, 5603 " Port Info -\n"))); 5604 LOG_CLI((BSL_META_U(unit, 5605 " port (index:intf-count) :\n"))); 5606 for (port = 0; port < SOC_MAX_NUM_PORTS; port++) { 5607 port_info = repl_info->port_info[port]; 5608 LOG_CLI((BSL_META_U(unit, 5609 " %3d -"), port)); 5610 if (port_info == NULL) { 5611 LOG_CLI((BSL_META_U(unit, 5612 " null\n"))); 5613 continue; 5614 } 5615 for (i = 0, j = 0; i < repl_info->num_repl_groups; i++) { 5616 /* If zero, skip print */ 5617 if (port_info->intf_count[i] == 0) { 5618 continue; 5619 } 5620 if ((j > 0) && !(j % 4)) { 5621 LOG_CLI((BSL_META_U(unit, 5622 "\n "))); 5623 } 5624 LOG_CLI((BSL_META_U(unit, 5625 " %5d:%-5d"), i, port_info->intf_count[i])); 5626 j++; 5627 } 5628 LOG_CLI((BSL_META_U(unit, 5629 "\n"))); 5630 } 5631 5632 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 5633 rli_start = REPL_LIST_INFO(unit, pipe); 5634 LOG_CLI((BSL_META_U(unit, 5635 " Pipeline %d List Info -\n"), pipe)); 5636 for (rli_current = rli_start; rli_current != NULL; 5637 rli_current = rli_current->next) { 5638 LOG_CLI((BSL_META_U(unit, 5639 " Hash: 0x%08x\n"), rli_current->hash)); 5640 LOG_CLI((BSL_META_U(unit, 5641 " Index: %5d\n"), rli_current->index)); 5642 LOG_CLI((BSL_META_U(unit, 5643 " Size: %5d\n"), rli_current->list_size)); 5644 LOG_CLI((BSL_META_U(unit, 5645 " Refs: %5d\n"), rli_current->refcount)); 5646 } 5647 } 5648 5649 LOG_CLI((BSL_META_U(unit, 5650 " L3 Interface Next Hop IPMC Info -\n"))); 5651 for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) { 5652 if (repl_info->l3_intf_next_hop_ipmc[i] == -1) { 5653 continue; 5654 } 5655 LOG_CLI((BSL_META_U(unit, 5656 " L3 Interface %4d: Next Hop Index %5d\n"), i, 5657 repl_info->l3_intf_next_hop_ipmc[i])); 5658 } 5659 5660 LOG_CLI((BSL_META_U(unit, 5661 " L3 Interface Next Hop Trill Info -\n"))); 5662 for (i = 0; i < soc_mem_index_count(unit, EGR_L3_INTFm); i++) { 5663 if (repl_info->l3_intf_next_hop_trill[i] == -1) { 5664 continue; 5665 } 5666 LOG_CLI((BSL_META_U(unit, 5667 " L3 Interface %4d: Next Hop Index %5d\n"), i, 5668 repl_info->l3_intf_next_hop_trill[i])); 5669 } 5670 } 5671 5672 if (_th_repl_list_entry_info[unit] != NULL) { 5673 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 5674 LOG_CLI((BSL_META_U(unit, 5675 " Pipeline %d Replication List Table Size : %d\n"), 5676 pipe, _th_repl_list_entry_info[unit][pipe].num_entries)); 5677 LOG_CLI((BSL_META_U(unit, 5678 " Pipeline %d Replication List Table Usage Bitmap (index:value-hex) :"), 5679 pipe)); 5680 if (NULL != 5681 _th_repl_list_entry_info[unit][pipe].bitmap_entries_used) { 5682 bitmap = _th_repl_list_entry_info[unit][pipe].bitmap_entries_used; 5683 for (i = 0, j = 0; 5684 i < _SHR_BITDCLSIZE(_th_repl_list_entry_info[unit][pipe].num_entries); 5685 i++) { 5686 /* If zero, skip print */ 5687 if (bitmap[i] == 0) { 5688 continue; 5689 } 5690 if (!(j % 4)) { 5691 LOG_CLI((BSL_META_U(unit, 5692 "\n "))); 5693 } 5694 LOG_CLI((BSL_META_U(unit, 5695 " %5d:%8.8x"), i, bitmap[i])); 5696 j++; 5697 } 5698 } 5699 LOG_CLI((BSL_META_U(unit, 5700 "\n"))); 5701 } 5702 } 5703 5704 if (_th_repl_head_info[unit] != NULL) { 5705 for (pipe = 0; pipe < NUM_PIPES(unit); pipe++) { 5706 LOG_CLI((BSL_META_U(unit, 5707 " Pipeline %d Replication Head Table Size : %d\n"), 5708 pipe, 1 << soc_mem_field_length(unit, 5709 MMU_REPL_GROUP_INFO_TBLm, PIPE_BASE_PTRf))); 5710 LOG_CLI((BSL_META_U(unit, 5711 " Pipeline %d Replication Head Free List Array:\n"), 5712 pipe)); 5713 if (_th_repl_head_info[unit][pipe].free_list_array != NULL) { 5714 for (i = 0; i < _th_repl_head_info[unit][pipe].array_size; i++) { 5715 LOG_CLI((BSL_META_U(unit, 5716 " Free List %2d:"), i)); 5717 free_block = REPL_HEAD_FREE_LIST(unit, pipe, i); 5718 j = 0; 5719 while (NULL != free_block) { 5720 if (j > 0 && !(j % 4)) { 5721 LOG_CLI((BSL_META_U(unit, 5722 "\n "))); 5723 } 5724 LOG_CLI((BSL_META_U(unit, 5725 " %7d:%-7d"), free_block->index, 5726 free_block->size)); 5727 free_block = free_block->next; 5728 j++; 5729 } 5730 LOG_CLI((BSL_META_U(unit, 5731 "\n"))); 5732 } 5733 } 5734 } 5735 } 5736 5737 return; 5738 } 5739 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 5740 5741 /* 5742 * Function: 5743 * _th_ipmc_glp_get 5744 * Purpose: 5745 * Fill information in bcm_ipmc_addr_t struct. 5746 */ 5747 5748 bcm_error_t 5749 _th_ipmc_glp_get(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *l3cfg) 5750 { 5751 5752 int no_src_check = FALSE; 5753 int is_trunk = 0; 5754 _bcm_l3_cfg_t l3cfg_local; 5755 int rv = BCM_E_NONE; 5756 5757 l3cfg_local = *l3cfg; 5758 if (l3cfg_local.l3c_tunnel) { 5759 is_trunk = 1; 5760 if ((((l3cfg_local.l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT) == 5761 TH_IPMC_NO_SRC_CHECK_PORT)) && 5762 (l3cfg_local.l3c_modid == SOC_MODID_MAX(unit))) { 5763 no_src_check = TRUE; 5764 is_trunk = 0; 5765 } 5766 } 5767 5768 #ifdef BCM_TRIDENT3_SUPPORT 5769 if (SOC_IS_TRIDENT3X(unit)) { 5770 if ((((l3cfg_local.l3c_port_tgid & TH_IPMC_NO_SRC_CHECK_PORT) == 5771 TH_IPMC_NO_SRC_CHECK_PORT)) && 5772 (l3cfg_local.l3c_modid == SOC_MODID_MAX(unit))) { 5773 no_src_check = TRUE; 5774 is_trunk = 0; 5775 } 5776 } 5777 #endif /* BCM_TRIDENT3_SUPPORT */ 5778 5779 if (no_src_check) { 5780 ipmc->ts = 0; 5781 ipmc->mod_id = -1; 5782 ipmc->port_tgid = -1; 5783 ipmc->flags |= BCM_IPMC_SOURCE_PORT_NOCHECK; 5784 } else if (is_trunk) { 5785 ipmc->ts = 1; 5786 ipmc->mod_id = 0; 5787 ipmc->port_tgid = l3cfg_local.l3c_port_tgid; 5788 } else { 5789 bcm_module_t mod_in, mod_out; 5790 bcm_port_t port_in, port_out; 5791 5792 mod_in = l3cfg_local.l3c_modid; 5793 port_in = l3cfg_local.l3c_port_tgid; 5794 BCM_IF_ERROR_RETURN 5795 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 5796 mod_in, port_in, 5797 &mod_out, &port_out)); 5798 /* Check parameters, since above is an application callback */ 5799 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 5800 return BCM_E_BADID; 5801 } 5802 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 5803 return BCM_E_PORT; 5804 } 5805 ipmc->ts = 0; 5806 ipmc->mod_id = mod_out; 5807 ipmc->port_tgid = port_out; 5808 } 5809 5810 return rv; 5811 } 5812 5813 /* 5814 * Function: 5815 * _th_ipmc_info_get 5816 * Purpose: 5817 * Fill information in bcm_ipmc_addr_t struct. 5818 */ 5819 5820 bcm_error_t 5821 _th_ipmc_info_get(int unit, int ipmc_index, bcm_ipmc_addr_t *ipmc, 5822 ipmc_entry_t *entry, _bcm_esw_ipmc_l3entry_t *use_ipmc_l3entry) 5823 { 5824 5825 ipmc->v = soc_L3_IPMCm_field32_get(unit, entry, VALIDf); 5826 5827 if (ipmc->v) { 5828 _bcm_l3_cfg_t l3cfg; 5829 _bcm_esw_ipmc_l3entry_t *ipmc_l3entry; 5830 5831 if (use_ipmc_l3entry != NULL) { 5832 /* use the passed in l3 info */ 5833 ipmc_l3entry = use_ipmc_l3entry; 5834 } else { 5835 /* Note: this simply picks up the first l3 info */ 5836 ipmc_l3entry = IPMC_GROUP_INFO(unit, ipmc_index)->l3entry_list; 5837 if (NULL == ipmc_l3entry) { 5838 /* No entries in Multicast host table */ 5839 return BCM_E_EMPTY; 5840 } 5841 } 5842 sal_memset(&l3cfg, 0, sizeof(_bcm_l3_cfg_t)); 5843 l3cfg.l3c_flags = BCM_L3_IPMC; 5844 l3cfg.l3c_vrf = ipmc_l3entry->l3info.vrf; 5845 l3cfg.l3c_vid = ipmc_l3entry->l3info.vid; 5846 l3cfg.l3c_ing_intf = ipmc_l3entry->l3info.ing_intf; 5847 5848 if (ipmc_l3entry->ip6) { 5849 ipmc->flags |= BCM_IPMC_IP6; 5850 } else { 5851 ipmc->flags &= ~BCM_IPMC_IP6; 5852 } 5853 if (ipmc->flags & BCM_IPMC_HIT_CLEAR) { 5854 l3cfg.l3c_flags |= BCM_L3_HIT_CLEAR; 5855 } 5856 5857 /* need to get current l3 info from h/w like hit bits */ 5858 if (ipmc->flags & BCM_IPMC_IP6) { 5859 sal_memcpy(ipmc->s_ip6_addr, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN); 5860 sal_memcpy(ipmc->mc_ip6_addr, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN); 5861 sal_memcpy(l3cfg.l3c_sip6, &ipmc_l3entry->l3info.sip6, BCM_IP6_ADDRLEN); 5862 sal_memcpy(l3cfg.l3c_ip6, &ipmc_l3entry->l3info.ip6, BCM_IP6_ADDRLEN); 5863 l3cfg.l3c_flags |= BCM_L3_IP6; 5864 BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip6_get(unit, &l3cfg)); 5865 } else { 5866 ipmc->s_ip_addr = ipmc_l3entry->l3info.src_ip_addr; 5867 ipmc->mc_ip_addr = ipmc_l3entry->l3info.ipmc_group; 5868 l3cfg.l3c_src_ip_addr = ipmc_l3entry->l3info.src_ip_addr; 5869 l3cfg.l3c_ipmc_group = ipmc_l3entry->l3info.ipmc_group; 5870 BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l3_ip4_get(unit, &l3cfg)); 5871 } 5872 5873 if (l3cfg.l3c_flags & BCM_L3_HIT) { 5874 ipmc->flags |= BCM_IPMC_HIT; 5875 } 5876 5877 if (l3cfg.l3c_flags & BCM_IPMC_POST_LOOKUP_RPF_CHECK) { 5878 ipmc->flags |= BCM_IPMC_POST_LOOKUP_RPF_CHECK; 5879 ipmc->l3a_intf = l3cfg.l3c_intf; 5880 if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_DROP) { 5881 ipmc->flags |= BCM_IPMC_RPF_FAIL_DROP; 5882 } 5883 if (l3cfg.l3c_flags & BCM_IPMC_RPF_FAIL_TOCPU) { 5884 ipmc->flags |= BCM_IPMC_RPF_FAIL_TOCPU; 5885 } 5886 } 5887 5888 if (ipmc_l3entry->l3info.flags & BCM_L3_RPE) { 5889 ipmc->cos = ipmc_l3entry->l3info.prio; 5890 ipmc->flags |= BCM_IPMC_SETPRI; 5891 } else { 5892 ipmc->cos = -1; 5893 ipmc->flags &= ~BCM_IPMC_SETPRI; 5894 } 5895 ipmc->group = ipmc_index; 5896 ipmc->group_l2 = ipmc_l3entry->l3info.ipmc_ptr_l2; 5897 ipmc->lookup_class = ipmc_l3entry->l3info.lookup_class; 5898 ipmc->vrf = ipmc_l3entry->l3info.vrf; 5899 ipmc->vid = ipmc_l3entry->l3info.vid; 5900 ipmc->ing_intf = ipmc_l3entry->l3info.ing_intf; 5901 ipmc->rp_id = ipmc_l3entry->l3info.rp_id; 5902 BCM_IF_ERROR_RETURN 5903 (_th_ipmc_glp_get(unit, ipmc, &l3cfg)); 5904 5905 } 5906 5907 return BCM_E_NONE; 5908 } 5909 5910 /* 5911 * Function: 5912 * _th_ipmc_glp_set 5913 * Purpose: 5914 * Fill information in bcm_ipmc_addr_t struct. 5915 */ 5916 5917 bcm_error_t 5918 _th_ipmc_glp_set(int unit, bcm_ipmc_addr_t *ipmc, _bcm_l3_cfg_t *l3cfg) 5919 { 5920 5921 int mod, port_tgid, is_trunk, no_src_check = FALSE; 5922 int rv = BCM_E_NONE; 5923 5924 if ((ipmc->flags & BCM_IPMC_SOURCE_PORT_NOCHECK) || 5925 (ipmc->port_tgid < 0)) { /* no source port */ 5926 no_src_check = TRUE; 5927 is_trunk = 0; 5928 mod = SOC_MODID_MAX(unit); 5929 port_tgid = TH_IPMC_NO_SRC_CHECK_PORT; 5930 } else if (ipmc->ts) { /* trunk source port */ 5931 is_trunk = 1; 5932 mod = 0; 5933 port_tgid = ipmc->port_tgid; 5934 } else { /* source port */ 5935 bcm_module_t mod_in, mod_out; 5936 bcm_port_t port_in, port_out; 5937 5938 mod_in = ipmc->mod_id; 5939 port_in = ipmc->port_tgid; 5940 BCM_IF_ERROR_RETURN 5941 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 5942 mod_in, port_in, 5943 &mod_out, &port_out)); 5944 /* Check parameters, since above is an application callback */ 5945 if (!SOC_MODID_ADDRESSABLE(unit, mod_out)) { 5946 return BCM_E_BADID; 5947 } 5948 if (!SOC_PORT_ADDRESSABLE(unit, port_out)) { 5949 return BCM_E_PORT; 5950 } 5951 is_trunk = 0; 5952 mod = mod_out; 5953 port_tgid = port_out; 5954 } 5955 5956 if (is_trunk) { 5957 l3cfg->l3c_tunnel = 1; 5958 l3cfg->l3c_modid = 0; 5959 l3cfg->l3c_port_tgid = port_tgid; 5960 } else { 5961 l3cfg->l3c_modid = mod; 5962 if (no_src_check) { 5963 l3cfg->l3c_tunnel = 1; 5964 if (SOC_IS_TRIDENT3X(unit)) { 5965 l3cfg->l3c_tunnel = 0; 5966 } 5967 } else { 5968 l3cfg->l3c_tunnel = 0; 5969 } 5970 l3cfg->l3c_port_tgid = port_tgid; 5971 } 5972 5973 return rv; 5974 } 5975 5976 5977 /* 5978 * Function: 5979 * _bcm_th_ipmc_l3_intf_next_hop_get 5980 * Purpose: 5981 * Get the next hop index that was silently allocated to the L3 interface. 5982 * Parameters: 5983 * unit - (IN) SOC unit # 5984 * intf - (IN) L3 interface ID 5985 * nh_index - (OUT) Next hop index 5986 * Returns: 5987 * BCM_E_XXX 5988 */ 5989 int 5990 _bcm_th_ipmc_l3_intf_next_hop_get(int unit, int intf, int *nh_index) 5991 { 5992 *nh_index = REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf); 5993 5994 if (*nh_index == REPL_NH_INDEX_UNALLOCATED || 5995 *nh_index == REPL_NH_INDEX_L3_EGRESS_ALLOCATED) { 5996 return BCM_E_NOT_FOUND; 5997 } 5998 5999 return BCM_E_NONE; 6000 } 6001 6002 /* 6003 * Function: 6004 * _bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear 6005 * Purpose: 6006 * Inform the IPMC module that a next hop index has been deleted 6007 * for the given L3 interface by the bcm_l3_egress_destroy API. 6008 * Parameters: 6009 * unit - SOC device unit number 6010 * nh_idx - next hop index 6011 * Returns: 6012 * BCM_E_NONE Success 6013 * BCM_E_XXX ERROR 6014 */ 6015 int _bcm_th_ipmc_l3_intf_next_hop_l3_egress_clear(int unit, int nh_idx) 6016 { 6017 soc_mem_t mem; /* Table location memory. */ 6018 egr_l3_next_hop_entry_t egr_entry; /* Egress next hop entry. */ 6019 int ent_type, intf_num; 6020 6021 mem = EGR_L3_NEXT_HOPm; 6022 sal_memset(&egr_entry, 0, sizeof(egr_l3_next_hop_entry_t)); 6023 6024 SOC_IF_ERROR_RETURN(BCM_XGS3_MEM_READ(unit, EGR_L3_NEXT_HOPm, 6025 nh_idx, &egr_entry)); 6026 6027 if (soc_feature(unit, soc_feature_mem_access_data_type)) { 6028 ent_type = soc_mem_field32_get(unit, mem, &egr_entry, DATA_TYPEf); 6029 } else { 6030 ent_type = soc_mem_field32_get(unit, mem, &egr_entry, ENTRY_TYPEf); 6031 } 6032 6033 /* chk if the entry is L3MC */ 6034 if (ent_type == 7) { 6035 intf_num = soc_mem_field32_get 6036 (unit, mem, &egr_entry, L3MC__INTF_NUMf); 6037 if (REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf_num) == 6038 REPL_NH_INDEX_L3_EGRESS_ALLOCATED) { 6039 REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf_num) = 6040 REPL_NH_INDEX_UNALLOCATED; 6041 } 6042 } 6043 6044 return BCM_E_NONE; 6045 } 6046 6047 6048 /* 6049 * Function: 6050 * _bcm_th_ipmc_l3_intf_next_hop_l3_egress_set 6051 * Purpose: 6052 * Inform the IPMC module that a next hop index has been allocated 6053 * for the given L3 interface by the bcm_l3_egress_create API. 6054 * Parameters: 6055 * unit - (IN) SOC unit # 6056 * intf - (IN) L3 interface ID 6057 * Returns: 6058 * BCM_E_XXX 6059 */ 6060 int 6061 _bcm_th_ipmc_l3_intf_next_hop_l3_egress_set(int unit, int intf) 6062 { 6063 int nh_index; 6064 6065 nh_index = REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf); 6066 6067 if (nh_index == REPL_NH_INDEX_UNALLOCATED) { 6068 REPL_L3_INTF_NEXT_HOP_IPMC(unit, intf) = 6069 REPL_NH_INDEX_L3_EGRESS_ALLOCATED; 6070 } else if (nh_index == REPL_NH_INDEX_L3_EGRESS_ALLOCATED) { 6071 /* Do nothing. Users are allowed to create multiple L3 6072 * egress objects based on the same L3 interface. 6073 */ 6074 } else { 6075 /* IPMC module had already silently allocated a next hop index 6076 * for this L3 interface. 6077 */ 6078 return BCM_E_CONFIG; 6079 } 6080 6081 return BCM_E_NONE; 6082 } 6083 6084 STATIC int 6085 _bcm_th_ipmc_egress_intf_set_for_trunk_first_member( 6086 int unit, int repl_group, bcm_port_t port, 6087 int if_count, bcm_if_t *if_array, int is_l3, 6088 int check_port, bcm_trunk_t tgid) 6089 { 6090 int old_intf_count, new_intf_count; 6091 int aggid; 6092 6093 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 6094 if ((old_intf_count == 0) && (if_count > 0)) { 6095 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_add(unit, port, tgid, &aggid)); 6096 } 6097 6098 BCM_IF_ERROR_RETURN( 6099 _bcm_esw_ipmc_egress_intf_set( 6100 unit, repl_group, port, if_count, if_array, is_l3, check_port)); 6101 6102 new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 6103 if ((old_intf_count > 0) && (new_intf_count == 0)) { 6104 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port)); 6105 } 6106 6107 return BCM_E_NONE; 6108 } 6109 6110 6111 STATIC int 6112 _bcm_th_ipmc_egress_intf_set_for_same_pipe_member( 6113 int unit, int repl_group, bcm_port_t port, 6114 bcm_port_t first_port, bcm_trunk_t tgid) 6115 { 6116 int aggid; 6117 int old_intf_count, new_intf_count; 6118 6119 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 6120 new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, first_port, repl_group); 6121 if (old_intf_count == new_intf_count) { 6122 return BCM_E_NONE; 6123 } 6124 6125 BCM_IF_ERROR_RETURN( 6126 _bcm_th_repl_initial_copy_count_set(unit, repl_group, 6127 port, new_intf_count)); 6128 6129 if ((old_intf_count == 0) && (new_intf_count > 0)) { 6130 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_add(unit, port, tgid, &aggid)); 6131 } else if ((old_intf_count > 0) && (new_intf_count == 0)) { 6132 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port)); 6133 } 6134 6135 REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = new_intf_count; 6136 6137 return BCM_E_NONE; 6138 } 6139 6140 STATIC int 6141 _bcm_th_ipmc_egress_intf_add_in_per_trunk_mode(int unit, int repl_group, 6142 bcm_port_t port, int encap_id, int is_l3) 6143 { 6144 int aggid; 6145 6146 if (REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) == 0) { 6147 BCM_IF_ERROR_RETURN( 6148 bcm_th_port_aggid_add(unit, port, BCM_TRUNK_INVALID, &aggid)); 6149 } 6150 6151 BCM_IF_ERROR_RETURN( 6152 _bcm_th_ipmc_egress_intf_add( 6153 unit, repl_group, port, encap_id, is_l3)); 6154 6155 return BCM_E_NONE; 6156 } 6157 6158 STATIC int 6159 _bcm_th_ipmc_egress_intf_del_in_per_trunk_mode(int unit, int repl_group, 6160 bcm_port_t port, int if_max, int encap_id, int is_l3) 6161 { 6162 6163 int old_intf_count, new_intf_count; 6164 6165 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 6166 BCM_IF_ERROR_RETURN( 6167 _bcm_th_ipmc_egress_intf_delete( 6168 unit, repl_group, port, if_max, encap_id, is_l3)); 6169 new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 6170 if (new_intf_count == 0 && old_intf_count > 0) { 6171 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port)); 6172 } 6173 6174 return BCM_E_NONE; 6175 } 6176 6177 6178 STATIC int 6179 _bcm_th_ipmc_egress_intf_add_for_trunk(int unit, int repl_group, 6180 bcm_trunk_t tgid, int encap_id, int is_l3) 6181 { 6182 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) 6183 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0}; 6184 int max_num_ports = SOC_MAX_NUM_PP_PORTS; 6185 #else 6186 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0}; 6187 int max_num_ports = SOC_MAX_NUM_PORTS; 6188 #endif 6189 6190 int idx; 6191 int member_count, port_iter; 6192 bcm_port_t trunk_pipe_first_port_array[BCM_PIPES_MAX]; 6193 int aggid, pipe; 6194 6195 BCM_IF_ERROR_RETURN( 6196 _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports, 6197 trunk_local_member_ports, 6198 &member_count)); 6199 6200 for (idx = 0; idx < BCM_PIPES_MAX; idx++) { 6201 trunk_pipe_first_port_array[idx] = -1; 6202 } 6203 for (idx = 0; idx < member_count; idx++) { 6204 port_iter = trunk_local_member_ports[idx]; 6205 pipe = SOC_INFO(unit).port_pipe[port_iter]; 6206 if (trunk_pipe_first_port_array[pipe] == -1) { 6207 if (REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group) == 0) { 6208 BCM_IF_ERROR_RETURN( 6209 bcm_th_port_aggid_add(unit, port_iter, tgid, &aggid)); 6210 } 6211 BCM_IF_ERROR_RETURN( 6212 _bcm_th_ipmc_egress_intf_add( 6213 unit, repl_group, port_iter, encap_id, is_l3)); 6214 trunk_pipe_first_port_array[pipe] = port_iter; 6215 } else { 6216 BCM_IF_ERROR_RETURN( 6217 _bcm_th_ipmc_egress_intf_set_for_same_pipe_member( 6218 unit, repl_group, port_iter, 6219 trunk_pipe_first_port_array[pipe], tgid)); 6220 } 6221 } 6222 6223 return BCM_E_NONE; 6224 } 6225 6226 STATIC int 6227 _bcm_th_ipmc_egress_intf_del_for_trunk(int unit, int repl_group, 6228 bcm_trunk_t tgid, int if_max, int encap_id, int is_l3) 6229 { 6230 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) 6231 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0}; 6232 int max_num_ports = SOC_MAX_NUM_PP_PORTS; 6233 #else 6234 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0}; 6235 int max_num_ports = SOC_MAX_NUM_PORTS; 6236 #endif 6237 6238 int idx; 6239 int member_count, port_iter; 6240 bcm_port_t trunk_pipe_first_port_array[BCM_PIPES_MAX]; 6241 int pipe; 6242 int old_intf_count, new_intf_count; 6243 6244 BCM_IF_ERROR_RETURN( 6245 _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports, 6246 trunk_local_member_ports, 6247 &member_count)); 6248 6249 for (idx = 0; idx < BCM_PIPES_MAX; idx++) { 6250 trunk_pipe_first_port_array[idx] = -1; 6251 } 6252 6253 for (idx = 0; idx < member_count; idx++) { 6254 port_iter = trunk_local_member_ports[idx]; 6255 pipe = SOC_INFO(unit).port_pipe[port_iter]; 6256 if (trunk_pipe_first_port_array[pipe] == -1) { 6257 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group); 6258 BCM_IF_ERROR_RETURN( 6259 _bcm_th_ipmc_egress_intf_delete( 6260 unit, repl_group, trunk_local_member_ports[idx], 6261 if_max, encap_id, is_l3)); 6262 new_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group); 6263 if (new_intf_count == 0 && old_intf_count > 0) { 6264 BCM_IF_ERROR_RETURN( 6265 bcm_th_port_aggid_del(unit, port_iter)); 6266 } 6267 trunk_pipe_first_port_array[pipe] = port_iter; 6268 } else { 6269 BCM_IF_ERROR_RETURN( 6270 _bcm_th_ipmc_egress_intf_set_for_same_pipe_member( 6271 unit, repl_group, port_iter, 6272 trunk_pipe_first_port_array[pipe], tgid)); 6273 } 6274 } 6275 6276 return BCM_E_NONE; 6277 } 6278 6279 STATIC int 6280 _bcm_th_ipmc_egress_intf_add_trunk_member(int unit, int repl_group, 6281 bcm_port_t port) 6282 { 6283 #if defined(BCM_ESW_SUPPORT) && (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) 6284 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PP_PORTS] = {0}; 6285 int max_num_ports = SOC_MAX_NUM_PP_PORTS; 6286 #else 6287 bcm_port_t trunk_local_member_ports[SOC_MAX_NUM_PORTS] = {0}; 6288 int max_num_ports = SOC_MAX_NUM_PORTS; 6289 #endif 6290 6291 int local_modid; 6292 int trunk_local_ports; 6293 int intf_count, if_count, old_intf_count; 6294 int same_pipe_port = -1, diff_pipe_port = -1; 6295 int i, rv; 6296 bcm_port_t port_iter; 6297 bcm_if_t *if_array = NULL; 6298 bcm_trunk_t tgid; 6299 int aggid; 6300 6301 /* Member port belongs to an existing trunk, it needs to share 6302 * identical replication list as other members of this trunk in 6303 * same pipe. 6304 */ 6305 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get (unit, &local_modid)); 6306 BCM_IF_ERROR_RETURN( 6307 bcm_esw_trunk_find(unit, local_modid, port, &tgid)); 6308 BCM_IF_ERROR_RETURN( 6309 _bcm_esw_trunk_local_members_get(unit, tgid, max_num_ports, 6310 trunk_local_member_ports, 6311 &trunk_local_ports)); 6312 6313 for (i = 0; i < trunk_local_ports; i++) { 6314 port_iter = trunk_local_member_ports[i]; 6315 if (port != port_iter) { 6316 intf_count = 6317 REPL_PORT_GROUP_INTF_COUNT(unit, port_iter, repl_group); 6318 if (intf_count > 0) { 6319 if (SOC_INFO(unit).port_pipe[port] == 6320 SOC_INFO(unit).port_pipe[port_iter]) { 6321 same_pipe_port = port_iter; 6322 break; 6323 } else { 6324 if (diff_pipe_port == -1) { 6325 diff_pipe_port = port_iter; 6326 } 6327 } 6328 } 6329 } 6330 } 6331 6332 #ifdef BCM_TOMAHAWK3_SUPPORT 6333 if (SOC_IS_TOMAHAWK3(unit)) { 6334 if(same_pipe_port == -1 && diff_pipe_port == -1) { 6335 return BCM_E_PARAM; 6336 } 6337 if (same_pipe_port != -1) { 6338 BCM_IF_ERROR_RETURN( 6339 _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member( 6340 unit, repl_group, port, same_pipe_port, tgid)); 6341 } else { 6342 BCM_IF_ERROR_RETURN( 6343 _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member( 6344 unit, repl_group, port, diff_pipe_port, tgid)); 6345 6346 } 6347 return BCM_E_NONE; 6348 } 6349 #endif 6350 6351 /* or return BCM_E_PARAM jinghuan */ 6352 if (same_pipe_port == -1 && diff_pipe_port == -1) { 6353 return BCM_E_NONE; 6354 } 6355 6356 if (same_pipe_port != -1) { 6357 BCM_IF_ERROR_RETURN( 6358 _bcm_th_ipmc_egress_intf_set_for_same_pipe_member( 6359 unit, repl_group, port, same_pipe_port, tgid)); 6360 } else { 6361 intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, diff_pipe_port, 6362 repl_group); 6363 if_array = sal_alloc(sizeof(bcm_if_t) * intf_count, 6364 "if_array pointers"); 6365 if (if_array == NULL) { 6366 return BCM_E_MEMORY; 6367 } 6368 6369 rv = bcm_th_ipmc_egress_intf_get(unit, repl_group, diff_pipe_port, 6370 intf_count, if_array, &if_count); 6371 if (BCM_FAILURE(rv)) { 6372 sal_free(if_array); 6373 return rv; 6374 } 6375 6376 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 6377 if ((old_intf_count == 0) && (intf_count > 0)) { 6378 rv = bcm_th_port_aggid_add(unit, port, tgid, &aggid); 6379 if (BCM_FAILURE(rv)) { 6380 sal_free(if_array); 6381 return rv; 6382 } 6383 } 6384 rv = _bcm_esw_ipmc_egress_intf_set(unit, repl_group, port, 6385 if_count, if_array, TRUE, FALSE); 6386 if (BCM_FAILURE(rv)) { 6387 sal_free(if_array); 6388 return rv; 6389 } 6390 sal_free(if_array); 6391 } 6392 6393 return BCM_E_NONE; 6394 } 6395 6396 STATIC int 6397 _bcm_th_ipmc_egress_intf_del_trunk_member(int unit, int repl_group, 6398 bcm_port_t port) 6399 { 6400 int is_last_member; 6401 int old_intf_count; 6402 6403 BCM_IF_ERROR_RETURN( 6404 bcm_th_port_last_member_check(unit, port, &is_last_member)); 6405 6406 old_intf_count = REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group); 6407 if (is_last_member) { 6408 BCM_IF_ERROR_RETURN( 6409 bcm_th_ipmc_egress_intf_set( 6410 unit, repl_group, port, 0, NULL, TRUE, FALSE)); 6411 } else { 6412 #ifdef BCM_TOMAHAWK3_SUPPORT 6413 if (SOC_IS_TOMAHAWK3(unit)) { 6414 REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = 0; 6415 } else 6416 #endif 6417 { 6418 BCM_IF_ERROR_RETURN( 6419 _bcm_th_repl_initial_copy_count_set( 6420 unit, repl_group, port, 0)); 6421 REPL_PORT_GROUP_INTF_COUNT(unit, port, repl_group) = 0; 6422 } 6423 } 6424 6425 if (old_intf_count > 0) { 6426 BCM_IF_ERROR_RETURN(bcm_th_port_aggid_del(unit, port)); 6427 } 6428 6429 return BCM_E_NONE; 6430 } 6431 6432 /* 6433 * Function: 6434 * bcm_th_ipmc_egress_intf_set_for_trunk_first_member 6435 * Purpose: 6436 * Assign set of egress interfaces to the first port of a trunk. 6437 * or to the only one non-trunk port. 6438 * Parameters: 6439 * unit - (IN) StrataSwitch PCI device unit number. 6440 * repl_group - (IN) The replication group number. 6441 * port - (IN) Port to assign replication list. 6442 * if_count - (IN) Number of interfaces in replication list. 6443 * if_array - (IN) List of interface numbers. 6444 * if_updated - (IN) interfaces info to be updated including 6445 * interfaces which is new to the group and port 6446 * and interfaces to be deleted. 6447 * is_l3 - (IN) Indicates if multicast group is of type IPMC. 6448 * check_port - (IN) If if_array consists of L3 interfaces, this parameter 6449 * controls whether to check the given port is a member 6450 * in each L3 interface's VLAN. This check should be 6451 * disabled when not needed, in order to improve 6452 * performance. 6453 * tgid - (IN) trunk id or BCM_TRUNK_INVALID for non-trunk port. 6454 * 6455 * Returns: 6456 * BCM_E_XXX 6457 */ 6458 int 6459 bcm_th_ipmc_egress_intf_set_for_trunk_first_member( 6460 int unit, int repl_group, bcm_port_t port, 6461 int if_count, bcm_if_t *if_array, int is_l3, 6462 int check_port, bcm_trunk_t tgid) 6463 { 6464 int rv = BCM_E_NONE; 6465 6466 IPMC_LOCK(unit); 6467 rv = _bcm_th_ipmc_egress_intf_set_for_trunk_first_member( 6468 unit, repl_group, port, if_count, if_array, 6469 is_l3, check_port, tgid); 6470 IPMC_UNLOCK(unit); 6471 6472 return rv; 6473 } 6474 6475 /* 6476 * Function: 6477 * bcm_th_ipmc_egress_intf_set_for_same_pipe_member 6478 * Purpose: 6479 * Align egress intf of same pipe port with the first port of trunk. 6480 * Parameters: 6481 * unit - (IN) StrataSwitch PCI device unit number. 6482 * repl_group - (IN) The replication group number. 6483 * port - (IN) Port to assign replication list. 6484 * first_port - (IN) The first member port of the trunk. 6485 * tgid - (IN) trunk id. 6486 * 6487 * Returns: 6488 * BCM_E_XXX 6489 */ 6490 int 6491 bcm_th_ipmc_egress_intf_set_for_same_pipe_member( 6492 int unit, int repl_group, bcm_port_t port, 6493 bcm_port_t first_port, bcm_trunk_t tgid) 6494 { 6495 int rv = BCM_E_NONE; 6496 6497 IPMC_LOCK(unit); 6498 #ifdef BCM_TOMAHAWK3_SUPPORT 6499 if (SOC_IS_TOMAHAWK3(unit)) { 6500 rv = _bcm_th3_ipmc_egress_intf_set_for_same_trunk_member( 6501 unit, repl_group, port, first_port, tgid); 6502 } else 6503 #endif 6504 { 6505 rv = _bcm_th_ipmc_egress_intf_set_for_same_pipe_member( 6506 unit, repl_group, port, first_port, tgid); 6507 } 6508 IPMC_UNLOCK(unit); 6509 6510 return rv; 6511 } 6512 6513 /* 6514 * Function: 6515 * bcm_th_ipmc_egress_intf_add_in_per_trunk_mode 6516 * Purpose: 6517 * Add encap ID to selected ports' replication list for chosen 6518 * IPMC group in mc per trunk repl mode. 6519 * It is used for non-trunk port. 6520 * Parameters: 6521 * unit - (IN) StrataSwitch PCI device unit number. 6522 * repl_group - (IN) The replication group number. 6523 * port - (IN) Port to assign replication list. 6524 * encap_id - (IN) Encap ID. 6525 * is_l3 - (IN) Indicates if multicast group type is IPMC. 6526 * 6527 * Returns: 6528 * BCM_E_XXX 6529 */ 6530 int 6531 bcm_th_ipmc_egress_intf_add_in_per_trunk_mode(int unit, int repl_group, 6532 bcm_port_t port, int encap_id, int is_l3) 6533 { 6534 int rv = BCM_E_NONE; 6535 6536 IPMC_LOCK(unit); 6537 rv = _bcm_th_ipmc_egress_intf_add_in_per_trunk_mode( 6538 unit, repl_group, port, encap_id, is_l3); 6539 IPMC_UNLOCK(unit); 6540 6541 return rv; 6542 } 6543 6544 /* 6545 * Function: 6546 * bcm_th_ipmc_egress_intf_del_in_per_trunk_mode 6547 * Purpose: 6548 * Remove encap ID from selected ports' replication list for chosen 6549 * IPMC group in mc per trunk repl mode. 6550 * It is used for non-trunk port. 6551 * Parameters: 6552 * unit - (IN) StrataSwitch PCI device unit number. 6553 * repl_group - (IN) The replication group number. 6554 * port - (IN) Port to assign replication list. 6555 * if_max - (IN) Maximal interface. 6556 * encap_id - (IN) Encap ID. 6557 * is_l3 - (IN) Indicates if multicast group type is IPMC. 6558 * Returns: 6559 * BCM_E_XXX 6560 */ 6561 int 6562 bcm_th_ipmc_egress_intf_del_in_per_trunk_mode(int unit, int repl_group, 6563 bcm_port_t port, int if_max, int encap_id, int is_l3) 6564 { 6565 int rv = BCM_E_NONE; 6566 6567 IPMC_LOCK(unit); 6568 rv = _bcm_th_ipmc_egress_intf_del_in_per_trunk_mode( 6569 unit, repl_group, port, if_max, encap_id, is_l3); 6570 IPMC_UNLOCK(unit); 6571 6572 return rv; 6573 } 6574 6575 /* 6576 * Function: 6577 * bcm_th_ipmc_egress_intf_add_for_trunk 6578 * Purpose: 6579 * Add encap ID to a trunk. 6580 * Parameters: 6581 * unit - (IN) StrataSwitch PCI device unit number. 6582 * repl_group - (IN) The replication group number. 6583 * tgid - (IN) Trunk ID. 6584 * encap_id - (IN) Encap ID. 6585 * is_l3 - (IN) Indicates if multicast group type is IPMC. 6586 * 6587 * Returns: 6588 * BCM_E_XXX 6589 */ 6590 int 6591 bcm_th_ipmc_egress_intf_add_for_trunk(int unit, int repl_group, 6592 bcm_trunk_t tgid, int encap_id, int is_l3) 6593 { 6594 int rv = BCM_E_NONE; 6595 6596 IPMC_LOCK(unit); 6597 #ifdef BCM_TOMAHAWK3_SUPPORT 6598 if(SOC_IS_TOMAHAWK3(unit)) { 6599 rv = _bcm_th3_ipmc_egress_intf_add_for_trunk( 6600 unit, repl_group, tgid, encap_id, is_l3); 6601 6602 } else 6603 #endif 6604 { 6605 rv = _bcm_th_ipmc_egress_intf_add_for_trunk( 6606 unit, repl_group, tgid, encap_id, is_l3); 6607 } 6608 IPMC_UNLOCK(unit); 6609 6610 return rv; 6611 } 6612 6613 /* 6614 * Function: 6615 * bcm_th_ipmc_egress_intf_del_for_trunk 6616 * Purpose: 6617 * Remove encap ID from a trunk. 6618 * Parameters: 6619 * unit - (IN) StrataSwitch PCI device unit number. 6620 * repl_group - (IN) The replication group number. 6621 * tgid - (IN) Trunk ID. 6622 * if_max - (IN) Maximal interface. 6623 * encap_id - (IN) Encap ID. 6624 * is_l3 - (IN) Indicates if multicast group type is IPMC. 6625 * 6626 * Returns: 6627 * BCM_E_XXX 6628 */ 6629 int 6630 bcm_th_ipmc_egress_intf_del_for_trunk(int unit, int repl_group, 6631 bcm_trunk_t tgid, int if_max, int encap_id, int is_l3) 6632 { 6633 int rv = BCM_E_NONE; 6634 6635 IPMC_LOCK(unit); 6636 6637 #ifdef BCM_TOMAHAWK3_SUPPORT 6638 if(SOC_IS_TOMAHAWK3(unit)) { 6639 rv = _bcm_th3_ipmc_egress_intf_del_for_trunk( 6640 unit, repl_group, tgid, if_max, encap_id, is_l3); 6641 } else 6642 #endif 6643 { 6644 rv = _bcm_th_ipmc_egress_intf_del_for_trunk( 6645 unit, repl_group, tgid, if_max, encap_id, is_l3); 6646 } 6647 IPMC_UNLOCK(unit); 6648 6649 return rv; 6650 } 6651 6652 /* 6653 * Function: 6654 * bcm_th_ipmc_egress_intf_add_trunk_member 6655 * Purpose: 6656 * Add a port member to a trunk for chosen IPMC group. 6657 * Parameters: 6658 * unit - (IN) StrataSwitch PCI device unit number. 6659 * repl_group - (IN) The replication group number. 6660 * port - (IN) Trunk member port. 6661 * 6662 * Returns: 6663 * BCM_E_XXX 6664 */ 6665 int 6666 bcm_th_ipmc_egress_intf_add_trunk_member(int unit, int repl_group, 6667 bcm_port_t port) 6668 { 6669 int rv = BCM_E_NONE; 6670 6671 IPMC_LOCK(unit); 6672 rv = _bcm_th_ipmc_egress_intf_add_trunk_member( 6673 unit, repl_group, port); 6674 IPMC_UNLOCK(unit); 6675 6676 return rv; 6677 } 6678 6679 6680 /* 6681 * Function: 6682 * bcm_th_ipmc_egress_intf_del_trunk_member 6683 * Purpose: 6684 * Remove a port member from a trunk for chosen IPMC group. 6685 * Parameters: 6686 * unit - (IN) StrataSwitch PCI device unit number. 6687 * repl_group - (IN) The replication group number. 6688 * port - (IN) Trunk member port. 6689 * 6690 * Returns: 6691 * BCM_E_XXX 6692 */ 6693 int 6694 bcm_th_ipmc_egress_intf_del_trunk_member(int unit, int repl_group, 6695 bcm_port_t port) 6696 { 6697 int rv = BCM_E_NONE; 6698 6699 IPMC_LOCK(unit); 6700 rv = _bcm_th_ipmc_egress_intf_del_trunk_member( 6701 unit, repl_group, port); 6702 IPMC_UNLOCK(unit); 6703 6704 return rv; 6705 } 6706 6707 /* 6708 * Function: 6709 * bcm_th_ipmc_repl_port_attach 6710 * Purpose: 6711 * Initialize replication per-port configuration in the runtime. 6712 * Parameters: 6713 * unit - (IN) BCM device number. 6714 * port - local port number 6715 * Returns: 6716 * BCM_E_XXX 6717 */ 6718 int 6719 bcm_th_ipmc_repl_port_attach(int unit, bcm_port_t port) 6720 { 6721 int rv = BCM_E_NONE; 6722 int alloc_size; 6723 int phy_port, mmu_port; 6724 int port_speed, count_width; 6725 uint32 regval; 6726 soc_info_t *si; 6727 6728 6729 if (_th_repl_info[unit] == NULL) { 6730 return BCM_E_INIT; 6731 } 6732 6733 /* Detach the IPMC REPL in case it is already attached. */ 6734 SOC_IF_ERROR_RETURN 6735 (bcm_th_ipmc_repl_port_detach(unit, port)); 6736 6737 _th_repl_info[unit]->port_info[port] = 6738 sal_alloc(sizeof(_th_repl_port_info_t), "repl port info"); 6739 if (NULL == _th_repl_info[unit]->port_info[port]) { 6740 return BCM_E_MEMORY; 6741 } 6742 sal_memset(_th_repl_info[unit]->port_info[port], 0, 6743 sizeof(_th_repl_port_info_t)); 6744 6745 alloc_size = sizeof(int) * _th_repl_info[unit]->num_repl_groups; 6746 _th_repl_info[unit]->port_info[port]->intf_count = 6747 sal_alloc(alloc_size, "repl port intf count"); 6748 if (NULL == _th_repl_info[unit]->port_info[port]->intf_count) { 6749 sal_free(_th_repl_info[unit]->port_info[port]); 6750 return BCM_E_MEMORY; 6751 } 6752 sal_memset(_th_repl_info[unit]->port_info[port]->intf_count, 0, alloc_size); 6753 6754 si = &SOC_INFO(unit); 6755 6756 /* Initialize PORT_INITIAL_COPY_COUNT_WIDTH registers */ 6757 phy_port = si->port_l2p_mapping[port]; 6758 mmu_port = si->port_p2m_mapping[phy_port]; 6759 6760 if (SOC_IS_TOMAHAWK2(unit)) { 6761 /* Single-lane ports are allocated 2 bits, while 2 or 4 6762 * lane ports are allocated 3 bits. */ 6763 count_width = (si->port_num_lanes[port] > 1) ? 1 : 0; 6764 } else { 6765 /* For ports with speed 40G and above the copy count width 6766 * is 3 bits (encoded value of 1) for lower speeds its 6767 * 2 bits (encoded value of 0). 6768 */ 6769 rv = bcm_esw_port_speed_get(unit, port, &port_speed); 6770 if (BCM_FAILURE(rv)) { 6771 (void)bcm_th_ipmc_repl_port_detach(unit, port); 6772 return rv; 6773 } 6774 6775 count_width = (port_speed >= 40000) ? 1 : 0; 6776 } 6777 6778 if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) { 6779 regval = 0; 6780 soc_reg_field_set(unit, PORT_INITIAL_COPY_COUNT_WIDTHr, ®val, 6781 BIT_WIDTHf, count_width); 6782 rv = WRITE_PORT_INITIAL_COPY_COUNT_WIDTHr(unit, port, regval); 6783 if (BCM_FAILURE(rv)) { 6784 (void)bcm_th_ipmc_repl_port_detach(unit, port); 6785 return rv; 6786 } 6787 } 6788 6789 /* configure mmu port to repl aggregateId map */ 6790 regval = 0; 6791 if(SOC_IS_TOMAHAWK3(unit)) { 6792 soc_reg_field_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, ®val, 6793 L3MC_PORT_AGG_IDf, mmu_port % mmu_port_stride[unit]); 6794 rv = soc_reg32_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, port,0,regval); 6795 } else { 6796 soc_reg_field_set(unit, MMU_DQS_REPL_PORT_AGG_MAPr, ®val, 6797 L3MC_PORT_AGG_IDf, mmu_port % mmu_port_stride[unit]); 6798 rv = soc_reg32_set(unit, MMU_DQS_REPL_PORT_AGG_MAPr, port,0,regval); 6799 } 6800 if (BCM_FAILURE(rv)) { 6801 (void)bcm_th_ipmc_repl_port_detach(unit, port); 6802 } 6803 6804 return rv; 6805 } 6806 6807 /* 6808 * Function: 6809 * bcm_th_ipmc_repl_port_detach 6810 * Purpose: 6811 * Clear replication per-port configuration in the runtime. 6812 * Parameters: 6813 * unit - (IN) BCM device number. 6814 * port - local port number 6815 * Returns: 6816 * BCM_E_XXX 6817 */ 6818 int 6819 bcm_th_ipmc_repl_port_detach(int unit, bcm_port_t port) 6820 { 6821 if (_th_repl_info[unit] == NULL) { 6822 return BCM_E_INIT; 6823 } 6824 6825 if (_th_repl_info[unit]->port_info[port] != NULL) { 6826 if (_th_repl_info[unit]->port_info[port]->intf_count != NULL) { 6827 sal_free(_th_repl_info[unit]->port_info[port]->intf_count); 6828 _th_repl_info[unit]->port_info[port]->intf_count = NULL; 6829 } 6830 sal_free(_th_repl_info[unit]->port_info[port]); 6831 _th_repl_info[unit]->port_info[port] = NULL; 6832 } 6833 6834 if (!soc_feature(unit, soc_feature_skip_port_initial_copy_count)) { 6835 /* Reset the BIT_WIDTHf to 0 */ 6836 SOC_IF_ERROR_RETURN 6837 (WRITE_PORT_INITIAL_COPY_COUNT_WIDTHr(unit, port, 0)); 6838 } 6839 6840 /* Reset L3MC_PORT_AGG_IDf to 0 */ 6841 if(SOC_IS_TOMAHAWK3(unit)) { 6842 SOC_IF_ERROR_RETURN 6843 (soc_reg32_set(unit, MMU_RQE_REPL_PORT_AGG_MAPr, port, 0, 0)); 6844 6845 } else { 6846 SOC_IF_ERROR_RETURN 6847 (soc_reg32_set(unit, MMU_DQS_REPL_PORT_AGG_MAPr, port, 0, 0)); 6848 } 6849 6850 6851 return BCM_E_NONE; 6852 } 6853 6854 #ifdef BCM_TOMAHAWK3_SUPPORT 6855 bcm_th3_repl_head_alloc_f bcm_th3_repl_head_alloc 6856 = &_bcm_th_repl_head_block_alloc; 6857 bcm_th3_repl_head_free_f bcm_th3_repl_head_free 6858 = &_bcm_th_repl_head_block_free; 6859 #endif 6860 6861 #endif /* BCM_TOMAHAWK_SUPPORT && INCLUDE_L3 */