trunk.c (253418B)
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: trunk.c 8 * Purpose: Trident2 resilient hashing and VP LAG implementation. 9 * VP LAG code is enclosed in INCLUDE_L3. 10 */ 11 12 #include <shared/bsl.h> 13 14 #include <soc/defs.h> 15 #include <sal/core/libc.h> 16 #ifdef BCM_TRIDENT2_SUPPORT 17 18 #include <soc/drv.h> 19 #include <soc/scache.h> 20 #include <soc/esw/cancun.h> 21 22 #include <bcm/error.h> 23 #include <bcm/trunk.h> 24 25 #include <bcm_int/esw/vlan.h> 26 #include <bcm_int/esw/virtual.h> 27 #include <bcm_int/esw/niv.h> 28 #include <bcm_int/esw/extender.h> 29 #include <bcm_int/esw/trident2.h> 30 #include <bcm_int/esw/failover.h> 31 #include <bcm_int/esw/triumph3.h> 32 #include <bcm_int/esw/vxlan.h> 33 #include <bcm_int/esw/mim.h> 34 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 35 #include <bcm_int/esw/trident2plus.h> 36 #endif /* BCM_TRIDENT2PLUS_SUPPORT */ 37 #if defined(BCM_TOMAHAWK_SUPPORT) 38 #include <bcm_int/esw/tomahawk.h> 39 #endif 40 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 41 #include <soc/esw/ecmp.h> 42 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 43 #if defined(BCM_TRIDENT3_SUPPORT) 44 #include <bcm_int/esw/trident3.h> 45 #endif 46 #if defined(BCM_HELIX5_SUPPORT) 47 #include <bcm_int/esw/helix5.h> 48 #endif /* BCM_HELIX5_SUPPORT */ 49 #include <bcm_int/esw/l2gre.h> 50 #include <bcm_int/esw/mpls.h> 51 #include <bcm_int/esw/flow.h> 52 53 54 extern int ecmp_mode_hierarchical; 55 extern int ecmp_mode_single; 56 57 /* Bookkeeping info for Higig resilient hashing */ 58 59 typedef struct _td2_hg_rh_info_s { 60 SHR_BITDCL *hg_rh_flowset_block_bitmap; /* Each block corresponds to 61 64 entries */ 62 uint32 hg_rh_rand_seed; /* The seed for pseudo-random number generator */ 63 } _td2_hg_rh_info_t; 64 65 STATIC _td2_hg_rh_info_t *_td2_hg_rh_info[BCM_MAX_NUM_UNITS]; 66 67 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \ 68 SHR_BITGET(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_) 69 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \ 70 SHR_BITSET(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_) 71 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \ 72 SHR_BITCLR(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_) 73 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \ 74 SHR_BITSET_RANGE(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_, _count_) 75 #define _BCM_HG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \ 76 SHR_BITCLR_RANGE(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_, _count_) 77 #define _BCM_HG_RH_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \ 78 SHR_BITTEST_RANGE(_td2_hg_rh_info[_u_]->hg_rh_flowset_block_bitmap, _idx_, _count_, _result_) 79 80 /* Bookkeeping info for LAG resilient hashing */ 81 82 typedef struct _td2_lag_rh_info_s { 83 int num_lag_rh_flowset_blocks; 84 SHR_BITDCL *lag_rh_flowset_block_bitmap; /* Each block corresponds to 85 64 entries */ 86 uint32 lag_rh_rand_seed; /* The seed for pseudo-random number generator */ 87 } _td2_lag_rh_info_t; 88 89 STATIC _td2_lag_rh_info_t *_td2_lag_rh_info[BCM_MAX_NUM_UNITS]; 90 91 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \ 92 SHR_BITGET(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_) 93 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \ 94 SHR_BITSET(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_) 95 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \ 96 SHR_BITCLR(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_) 97 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \ 98 SHR_BITSET_RANGE(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_, _count_) 99 #define _BCM_LAG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \ 100 SHR_BITCLR_RANGE(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_, _count_) 101 #define _BCM_LAG_RH_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \ 102 SHR_BITTEST_RANGE(_td2_lag_rh_info[_u_]->lag_rh_flowset_block_bitmap, _idx_, _count_, _result_) 103 104 #ifdef INCLUDE_L3 105 106 /* VP LAG software state */ 107 typedef struct _td2_vp_lag_member_s{ 108 bcm_gport_t *egr_dis_vp; /* member VPs with BCM_TRUNK_MEMBER_EGRESS_DISABLE */ 109 int num_egr_dis_vp; 110 } _td2_vp_lag_member_t; 111 112 typedef struct _td2_vp_lag_group_s { 113 int vp_id; /* The VP value allocated to VP LAG */ 114 int has_member; /* Indicates if VP LAG has members programmed in L3_ECMP table */ 115 int non_uc_index; /* Index of the non-unicast member */ 116 _td2_vp_lag_member_t vp_lag_member_info; /* info of member VPs */ 117 } _td2_vp_lag_group_t; 118 119 typedef struct _td2_vp_lag_info_s { 120 int max_vp_lags; /* Maximum number of VP LAGs */ 121 int base_ecmp_idx; /* In Riot, ECMP table for underlay does not start at index 0 */ 122 SHR_BITDCL *vp_lag_used_bitmap; /* Bitmap of used VP LAG IDs */ 123 SHR_BITDCL *vp_lag_egr_member_bitmap; /* Bitmap of used entries of 124 EGR_VPLAG_MEMBER table */ 125 _td2_vp_lag_group_t *group_info; /* Array of VP LAG group info */ 126 sal_mutex_t lock; /* VP LAG lock. */ 127 } _td2_vp_lag_info_t; 128 129 STATIC _td2_vp_lag_info_t *_td2_vp_lag_info[BCM_MAX_NUM_UNITS]; 130 131 #define VP_LAG_INIT_CHECK(_u_) \ 132 if (NULL == _td2_vp_lag_info[_u_]) { return BCM_E_INIT; } 133 134 #define MAX_VP_LAGS(_u_) (_td2_vp_lag_info[_u_]->max_vp_lags) 135 136 #define VP_LAG_USED_GET(_u_, _idx_) \ 137 SHR_BITGET(_td2_vp_lag_info[_u_]->vp_lag_used_bitmap, _idx_) 138 #define VP_LAG_USED_SET(_u_, _idx_) \ 139 SHR_BITSET(_td2_vp_lag_info[_u_]->vp_lag_used_bitmap, _idx_) 140 #define VP_LAG_USED_CLR(_u_, _idx_) \ 141 SHR_BITCLR(_td2_vp_lag_info[_u_]->vp_lag_used_bitmap, _idx_) 142 143 #define VP_LAG_EGR_MEMBER_USED_GET(_u_, _idx_) \ 144 SHR_BITGET(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_) 145 #define VP_LAG_EGR_MEMBER_USED_SET(_u_, _idx_) \ 146 SHR_BITSET(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_) 147 #define VP_LAG_EGR_MEMBER_USED_CLR(_u_, _idx_) \ 148 SHR_BITCLR(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_) 149 #define VP_LAG_EGR_MEMBER_USED_SET_RANGE(_u_, _idx_, _count_) \ 150 SHR_BITSET_RANGE(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_, _count_) 151 #define VP_LAG_EGR_MEMBER_USED_CLR_RANGE(_u_, _idx_, _count_) \ 152 SHR_BITCLR_RANGE(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_, _count_) 153 #define VP_LAG_EGR_MEMBER_TEST_RANGE(_u_, _idx_, _count_, _result_) \ 154 SHR_BITTEST_RANGE(_td2_vp_lag_info[_u_]->vp_lag_egr_member_bitmap, _idx_, _count_, _result_) 155 156 #define VP_LAG_GROUP_INFO(_u_, _idx_) (_td2_vp_lag_info[_u_]->group_info[_idx_]) 157 158 #define VP_LAG_MEMBER_INFO(_u_, _lag_idx_) (VP_LAG_GROUP_INFO(_u_, _lag_idx_).vp_lag_member_info) 159 160 161 #endif /* INCLUDE_L3 */ 162 163 /* 164 * Function: 165 * bcm_td2_hg_rh_deinit 166 * Purpose: 167 * Deallocate Higig resilient hashing internal data structures 168 * Parameters: 169 * unit - (IN) SOC unit number. 170 * Returns: 171 * BCM_E_xxx 172 */ 173 void 174 bcm_td2_hg_rh_deinit(int unit) 175 { 176 if (_td2_hg_rh_info[unit]) { 177 if (_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap) { 178 sal_free(_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap); 179 _td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap = NULL; 180 } 181 sal_free(_td2_hg_rh_info[unit]); 182 _td2_hg_rh_info[unit] = NULL; 183 } 184 } 185 186 /* 187 * Function: 188 * bcm_td2_hg_rh_init 189 * Purpose: 190 * Initialize Higig resilient hashing internal data structures 191 * Parameters: 192 * unit - (IN) SOC unit number. 193 * Returns: 194 * BCM_E_xxx 195 */ 196 int 197 bcm_td2_hg_rh_init(int unit) 198 { 199 int num_blocks; 200 201 if (_td2_hg_rh_info[unit] == NULL) { 202 _td2_hg_rh_info[unit] = sal_alloc(sizeof(_td2_hg_rh_info_t), 203 "_td2_hg_rh_info"); 204 if (_td2_hg_rh_info[unit] == NULL) { 205 return BCM_E_MEMORY; 206 } 207 sal_memset(_td2_hg_rh_info[unit], 0, sizeof(_td2_hg_rh_info_t)); 208 } 209 210 /* Each bit in hg_rh_flowset_block_bitmap corresponds to a block of 64 211 * resilient hashing flow set table entries. 212 */ 213 num_blocks = soc_mem_index_count(unit, RH_HGT_FLOWSETm) / 64; 214 if (_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap == NULL) { 215 _td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap = 216 sal_alloc(SHR_BITALLOCSIZE(num_blocks), 217 "hg_rh_flowset_block_bitmap"); 218 if (_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap == NULL) { 219 bcm_td2_hg_rh_deinit(unit); 220 return BCM_E_MEMORY; 221 } 222 sal_memset(_td2_hg_rh_info[unit]->hg_rh_flowset_block_bitmap, 0, 223 SHR_BITALLOCSIZE(num_blocks)); 224 } 225 226 /* Set the seed for the pseudo-random number generator */ 227 _td2_hg_rh_info[unit]->hg_rh_rand_seed = sal_time_usecs(); 228 229 if (!SOC_WARM_BOOT(unit)) { 230 /* Clear Higig resilient hashing group control table */ 231 if (SOC_MEM_IS_VALID(unit, RH_HGT_GROUP_CONTROLm)) { 232 SOC_IF_ERROR_RETURN 233 (soc_mem_clear(unit, RH_HGT_GROUP_CONTROLm, MEM_BLOCK_ALL, 0)); 234 } 235 } 236 return BCM_E_NONE; 237 } 238 239 /* 240 * Function: 241 * bcm_td2_hg_rh_dynamic_size_encode 242 * Purpose: 243 * Encode Higig trunk resilient hashing flow set size. 244 * Parameters: 245 * dynamic_size - (IN) Number of flow sets. 246 * encoded_value - (OUT) Encoded value. 247 * Returns: 248 * BCM_E_xxx 249 */ 250 int 251 bcm_td2_hg_rh_dynamic_size_encode(int unit, int dynamic_size, 252 int *encoded_value) 253 { 254 #ifdef BCM_HELIX5_SUPPORT 255 if (SOC_IS_HELIX5(unit)) { 256 return _bcm_hx5_hg_rh_dynamic_size_encode(dynamic_size, encoded_value); 257 } 258 #endif /* BCM_HELIX5_SUPPORT */ 259 switch (dynamic_size) { 260 case 64: 261 *encoded_value = 1; 262 break; 263 case 128: 264 *encoded_value = 2; 265 break; 266 case 256: 267 *encoded_value = 3; 268 break; 269 case 512: 270 *encoded_value = 4; 271 break; 272 case 1024: 273 *encoded_value = 5; 274 break; 275 case 2048: 276 *encoded_value = 6; 277 break; 278 case 4096: 279 *encoded_value = 7; 280 break; 281 case 8192: 282 *encoded_value = 8; 283 break; 284 case 16384: 285 *encoded_value = 9; 286 break; 287 case 32768: 288 *encoded_value = 10; 289 break; 290 case 65536: 291 *encoded_value = 11; 292 break; 293 default: 294 return BCM_E_PARAM; 295 } 296 297 return BCM_E_NONE; 298 } 299 300 /* 301 * Function: 302 * _bcm_td2_hg_rh_dynamic_size_decode 303 * Purpose: 304 * Decode Higig trunk resilient hashing flow set size. 305 * Parameters: 306 * encoded_value - (IN) Encoded value. 307 * dynamic_size - (OUT) Number of flow sets. 308 * Returns: 309 * BCM_E_xxx 310 */ 311 STATIC int 312 _bcm_td2_hg_rh_dynamic_size_decode(int unit, int encoded_value, 313 int *dynamic_size) 314 { 315 #ifdef BCM_HELIX5_SUPPORT 316 if (SOC_IS_HELIX5(unit)) { 317 return _bcm_hx5_hg_rh_dynamic_size_decode(encoded_value, dynamic_size); 318 } 319 #endif /* BCM_HELIX5_SUPPORT */ 320 switch (encoded_value) { 321 case 1: 322 *dynamic_size = 64; 323 break; 324 case 2: 325 *dynamic_size = 128; 326 break; 327 case 3: 328 *dynamic_size = 256; 329 break; 330 case 4: 331 *dynamic_size = 512; 332 break; 333 case 5: 334 *dynamic_size = 1024; 335 break; 336 case 6: 337 *dynamic_size = 2048; 338 break; 339 case 7: 340 *dynamic_size = 4096; 341 break; 342 case 8: 343 *dynamic_size = 8192; 344 break; 345 case 9: 346 *dynamic_size = 16384; 347 break; 348 case 10: 349 *dynamic_size = 32768; 350 break; 351 case 11: 352 *dynamic_size = 65536; 353 break; 354 default: 355 return BCM_E_INTERNAL; 356 } 357 358 return BCM_E_NONE; 359 } 360 361 /* 362 * Function: 363 * bcm_td2_hg_rh_status_get 364 * Purpose: 365 * Check if resilient hashing is enabled on any Higig trunk group. 366 * Parameters: 367 * unit - (IN) SOC unit number. 368 * rh_status - (OUT) Higig resilient hashing status 369 * Returns: 370 * BCM_E_xxx 371 */ 372 int 373 bcm_td2_hg_rh_status_get(int unit, int *rh_status) 374 { 375 bcm_trunk_chip_info_t chip_info; 376 int i; 377 int psc; 378 int rv; 379 380 *rh_status = FALSE; 381 382 BCM_IF_ERROR_RETURN(bcm_esw_trunk_chip_info_get(unit, &chip_info)); 383 if (chip_info.trunk_fabric_id_min < 0) { 384 /* There are no Higig trunk groups. */ 385 return BCM_E_NOT_FOUND; 386 } 387 388 for (i = chip_info.trunk_fabric_id_min; 389 i <= chip_info.trunk_fabric_id_max; i++) { 390 rv = bcm_esw_trunk_psc_get(unit, i, &psc); 391 if ((rv != BCM_E_NONE) && (rv != BCM_E_NOT_FOUND)) { 392 return rv; 393 } 394 if (psc == BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 395 *rh_status = TRUE; 396 break; 397 } 398 } 399 400 return BCM_E_NONE; 401 } 402 403 /* 404 * Function: 405 * bcm_td2_hg_rh_free_resource 406 * Purpose: 407 * Free resources for a Higig resilient hashing. 408 * Parameters: 409 * unit - (IN) SOC unit number. 410 * hgtid - (IN) Higig group ID. 411 * Returns: 412 * BCM_E_xxx 413 */ 414 int 415 bcm_td2_hg_rh_free_resource(int unit, int hgtid) 416 { 417 int rv = BCM_E_NONE; 418 uint32 rval; 419 rh_hgt_group_control_entry_t rh_hgt_group_control_entry; 420 hg_trunk_group_entry_t hg_trunk_group_entry; 421 int entry_base_ptr; 422 int flow_set_size; 423 int num_entries; 424 int block_base_ptr; 425 int num_blocks; 426 int alloc_size; 427 uint32 *buf_ptr = NULL; 428 int index_min, index_max; 429 hg_trunk_mode_entry_t hg_trunk_mode_entry; 430 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_HGT_ENABLEf)) { 431 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval)); 432 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval, 433 RH_HGT_ENABLEf)) { 434 /* Higig resilient hashing is not enabled chip-wide. */ 435 return BCM_E_NONE; 436 } 437 } else { 438 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval)); 439 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval, 440 RH_DLB_SELECTIONf)) { 441 /* Higig resilient hashing is not enabled chip-wide. */ 442 return BCM_E_NONE; 443 } 444 } 445 446 SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid, 447 &hg_trunk_group_entry)); 448 if (soc_mem_field_valid(unit, HG_TRUNK_GROUPm, ENHANCED_HASHING_ENABLEf)) { 449 if (0 == soc_HG_TRUNK_GROUPm_field32_get(unit, 450 &hg_trunk_group_entry, ENHANCED_HASHING_ENABLEf)) { 451 /* Either (1) resilient hashing is not enabled on this Higig trunk 452 * group, or (2) resilient hahsing is enabled with no members. 453 * In case (2), RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE needs to be cleared. 454 */ 455 SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, 456 hgtid, soc_mem_entry_null(unit, RH_HGT_GROUP_CONTROLm))); 457 return BCM_E_NONE; 458 } 459 /* Clear ENHANCED_HASHING_ENABLE in HG_TRUNK_GROUP */ 460 soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry, 461 ENHANCED_HASHING_ENABLEf, 0); 462 SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid, 463 &hg_trunk_group_entry)); 464 465 /* Clear RH_HGT_GROUP_CONTROL entry */ 466 SOC_IF_ERROR_RETURN(READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, 467 hgtid, &rh_hgt_group_control_entry)); 468 entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 469 &rh_hgt_group_control_entry, FLOW_SET_BASEf); 470 flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 471 &rh_hgt_group_control_entry, FLOW_SET_SIZEf); 472 SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, 473 hgtid, soc_mem_entry_null(unit, RH_HGT_GROUP_CONTROLm))); 474 } else { 475 SOC_IF_ERROR_RETURN(READ_HG_TRUNK_MODEm(unit, MEM_BLOCK_ANY, hgtid, 476 &hg_trunk_mode_entry)); 477 if (1 != soc_HG_TRUNK_MODEm_field32_get(unit, 478 &hg_trunk_mode_entry, HG_TRUNK_LB_MODEf)) { 479 return BCM_E_NONE; 480 } 481 /* Clear ENHANCED_HASHING_ENABLE in HG_TRUNK_MODE */ 482 SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_MODEm(unit, MEM_BLOCK_ALL, 483 hgtid, soc_mem_entry_null(unit, HG_TRUNK_MODEm))); 484 485 entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit, 486 &hg_trunk_group_entry, RH_FLOW_SET_BASEf); 487 flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit, 488 &hg_trunk_group_entry, RH_FLOW_SET_SIZEf); 489 490 491 /* Clear ENHANCED_HASHING_ENABLE in HG_TRUNK_GROUP */ 492 soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry, 493 RH_FLOW_SET_BASEf, 0); 494 soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry, 495 RH_FLOW_SET_SIZEf, 0); 496 SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid, 497 &hg_trunk_group_entry)); 498 } 499 500 501 /* Clear flow set table entries */ 502 BCM_IF_ERROR_RETURN 503 (_bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries)); 504 alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t); 505 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries"); 506 if (NULL == buf_ptr) { 507 return BCM_E_MEMORY; 508 } 509 sal_memset(buf_ptr, 0, alloc_size); 510 index_min = entry_base_ptr; 511 index_max = index_min + num_entries - 1; 512 rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL, 513 index_min, index_max, buf_ptr); 514 if (SOC_FAILURE(rv)) { 515 soc_cm_sfree(unit, buf_ptr); 516 return rv; 517 } 518 soc_cm_sfree(unit, buf_ptr); 519 520 /* Free flow set table resources */ 521 block_base_ptr = entry_base_ptr >> 6; 522 num_blocks = num_entries >> 6; 523 _BCM_HG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks); 524 525 return BCM_E_NONE; 526 } 527 528 /* 529 * Function: 530 * bcm_td2_hg_rh_dynamic_size_set 531 * Purpose: 532 * Set the dynamic size for a Higig resilient hashing group with 533 * no members, so it can be recovered from hardware during warm boot. 534 * Parameters: 535 * unit - (IN) SOC unit number. 536 * hgtid - (IN) Higig group ID. 537 * dynamic_size - (IN) Number of flow sets. 538 * Returns: 539 * BCM_E_xxx 540 */ 541 int 542 bcm_td2_hg_rh_dynamic_size_set(int unit, int hgtid, int dynamic_size) 543 { 544 hg_trunk_group_entry_t hg_trunk_group_entry; 545 rh_hgt_group_control_entry_t rh_hgt_group_control_entry; 546 int flow_set_size; 547 hg_trunk_mode_entry_t hg_trunk_mode_entry; 548 549 SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid, 550 &hg_trunk_group_entry)); 551 552 BCM_IF_ERROR_RETURN 553 (bcm_td2_hg_rh_dynamic_size_encode(unit, dynamic_size, &flow_set_size)); 554 if (soc_mem_field_valid(unit, HG_TRUNK_GROUPm, ENHANCED_HASHING_ENABLEf)) { 555 if (soc_HG_TRUNK_GROUPm_field32_get(unit, &hg_trunk_group_entry, 556 ENHANCED_HASHING_ENABLEf)) { 557 /* Not expecting resilient hashing to be enabled */ 558 return BCM_E_INTERNAL; 559 } 560 SOC_IF_ERROR_RETURN(READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, 561 hgtid, &rh_hgt_group_control_entry)); 562 soc_RH_HGT_GROUP_CONTROLm_field32_set(unit, &rh_hgt_group_control_entry, 563 FLOW_SET_SIZEf, flow_set_size); 564 SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, 565 hgtid, &rh_hgt_group_control_entry)); 566 } else { 567 SOC_IF_ERROR_RETURN(READ_HG_TRUNK_MODEm(unit, MEM_BLOCK_ANY, hgtid, 568 &hg_trunk_mode_entry)); 569 if (1 == soc_HG_TRUNK_MODEm_field32_get(unit, 570 &hg_trunk_mode_entry, HG_TRUNK_LB_MODEf)) { 571 572 /* Not expecting resilient hashing to be enabled */ 573 return BCM_E_INTERNAL; 574 } 575 /* Update HG_TRUNK_GROUP */ 576 soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry, 577 RH_FLOW_SET_SIZEf, flow_set_size); 578 SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid, 579 &hg_trunk_group_entry)); 580 } 581 return BCM_E_NONE; 582 } 583 584 /* 585 * Function: 586 * _bcm_td2_hg_rh_rand_get 587 * Purpose: 588 * Get a random number between 0 and the given max value. 589 * Parameters: 590 * unit - (IN) SOC unit number. 591 * rand_max - (IN) Maximum random number. 592 * rand_num - (OUT) Random number. 593 * Returns: 594 * BCM_E_xxx 595 * Notes: 596 * This procedure uses the pseudo-random number generator algorithm 597 * suggested by the C standard. 598 */ 599 STATIC int 600 _bcm_td2_hg_rh_rand_get(int unit, int rand_max, int *rand_num) 601 { 602 int modulus; 603 int rand_seed_shift; 604 605 if (rand_max < 0) { 606 return BCM_E_PARAM; 607 } 608 609 if (NULL == rand_num) { 610 return BCM_E_PARAM; 611 } 612 613 /* Make sure the modulus does not exceed limit. For instance, 614 * if the 32-bit rand_seed is shifted to the right by 16 bits before 615 * the modulo operation, the modulus should not exceed 1 << 16. 616 */ 617 modulus = rand_max + 1; 618 rand_seed_shift = 16; 619 if (modulus > (1 << (32 - rand_seed_shift))) { 620 return BCM_E_PARAM; 621 } 622 623 _td2_hg_rh_info[unit]->hg_rh_rand_seed = 624 _td2_hg_rh_info[unit]->hg_rh_rand_seed * 1103515245 + 12345; 625 626 *rand_num = (_td2_hg_rh_info[unit]->hg_rh_rand_seed >> rand_seed_shift) % 627 modulus; 628 629 return BCM_E_NONE; 630 } 631 632 /* 633 * Function: 634 * _bcm_td2_hg_rh_member_choose 635 * Purpose: 636 * Choose a member of the Higig trunk group. 637 * Parameters: 638 * unit - (IN) SOC unit number. 639 * num_members - (IN) Number of members to choose from. 640 * entry_count_arr - (IN/OUT) An array keeping track of how many 641 * flow set entries have been assigned 642 * to each member. 643 * max_entry_count - (IN/OUT) The maximum number of flow set entries 644 * that can be assigned to a member. 645 * chosen_index - (OUT) The index of the chosen member. 646 * Returns: 647 * BCM_E_xxx 648 */ 649 STATIC int 650 _bcm_td2_hg_rh_member_choose(int unit, int num_members, int *entry_count_arr, 651 int *max_entry_count, int *chosen_index) 652 { 653 int member_index; 654 int next_index; 655 656 *chosen_index = 0; 657 658 /* Choose a random member index */ 659 BCM_IF_ERROR_RETURN(_bcm_td2_hg_rh_rand_get(unit, num_members - 1, 660 &member_index)); 661 662 if (entry_count_arr[member_index] < *max_entry_count) { 663 entry_count_arr[member_index]++; 664 *chosen_index = member_index; 665 } else { 666 /* The randomly chosen member has reached the maximum 667 * flow set entry count. Choose the next member that 668 * has not reached the maximum entry count. 669 */ 670 next_index = (member_index + 1) % num_members; 671 while (next_index != member_index) { 672 if (entry_count_arr[next_index] < *max_entry_count) { 673 entry_count_arr[next_index]++; 674 *chosen_index = next_index; 675 break; 676 } else { 677 next_index = (next_index + 1) % num_members; 678 } 679 } 680 if (next_index == member_index) { 681 /* All members have reached the maximum flow set entry 682 * count. This scenario occurs when dividing the number of 683 * flow set entries by the number of members results 684 * in a non-zero remainder. The remainder flow set entries 685 * will be distributed among members, at most 1 remainder 686 * entry per member. 687 */ 688 (*max_entry_count)++; 689 if (entry_count_arr[member_index] < *max_entry_count) { 690 entry_count_arr[member_index]++; 691 *chosen_index = member_index; 692 } else { 693 /* It's possible that the member's entry count already equals 694 * to the incremented value of max_entry_count. 695 */ 696 next_index = (member_index + 1) % num_members; 697 while (next_index != member_index) { 698 if (entry_count_arr[next_index] < *max_entry_count) { 699 entry_count_arr[next_index]++; 700 *chosen_index = next_index; 701 break; 702 } else { 703 next_index = (next_index + 1) % num_members; 704 } 705 } 706 if (next_index == member_index) { 707 return BCM_E_INTERNAL; 708 } 709 } 710 } 711 } 712 713 return BCM_E_NONE; 714 } 715 716 717 718 /* 719 * Function: 720 * _bcm_td2_hg_rh_delete_rebalance 721 * Purpose: 722 * Re-balance flow set entries from the leaving member to the remaining 723 * members. For example, if the number of flow set entries is 64, and 724 * the number of members is 6, then each member has between 10 and 11 725 * entries. The entries should be re-assigned from the leaving member to 726 * the remaining 5 members such that each remaining member will end up 727 * with between 12 and 13 entries. 728 * Parameters: 729 * unit - (IN) SOC unit number. 730 * num_entries - (IN) Number of flow set entries. 731 * buf_ptr - (IN/OUT) Flow set entry buffer. 732 * num_members - (IN) Number of entry_count_arr/ member_arr. 733 * entry_count_arr - (IN/OUT) An array keeping track of how many 734 * flow set entries have been assigned 735 * to each member. 736 * member_arr - (IN) Array of new members (staying, joining) 737 * num_leaving - (IN) Number of leaving_port. 738 * leaving_port - (IN) Array of leaving members. 739 * Returns: 740 * BCM_E_xxx 741 */ 742 STATIC int 743 _bcm_td2_hg_rh_delete_rebalance(int unit, int num_entries, uint32 *buf_ptr, 744 int num_members, int *entry_count_arr, int *member_arr, 745 int num_leaving, int *leaving_port) 746 { 747 748 int threshold; 749 int i,j; 750 int chosen_index; 751 int egress_port; 752 rh_hgt_flowset_entry_t *flowset_entry; 753 soc_field_t port_fld = EGRESS_PORTf; 754 755 if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) { 756 port_fld = PORT_NUMf; 757 } 758 threshold = num_entries / num_members; 759 for (i = 0; i < num_entries; i++) { 760 flowset_entry = soc_mem_table_idx_to_pointer(unit, 761 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i); 762 egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry, 763 port_fld); 764 for (j = 0; j < num_leaving ; j++ ) { 765 if (egress_port == leaving_port[j]) { 766 break; 767 } 768 } 769 if (j < num_leaving) { 770 /* Randomly choose a member among the remaining members */ 771 BCM_IF_ERROR_RETURN(_bcm_td2_hg_rh_member_choose(unit, num_members, 772 entry_count_arr, &threshold, &chosen_index)); 773 soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, port_fld, 774 member_arr[chosen_index]); 775 } 776 } 777 return BCM_E_NONE; 778 } 779 780 781 /* 782 * Function: 783 * _bcm_td2_hg_rh_add_rebalance 784 * Purpose: 785 * Re-balance flow set entries from existing members to the new member. 786 * For example, if the number of flow set entries is 64, and the number of 787 * existing members is 6, then each existing member has between 10 and 11 788 * entries. The entries should be re-assigned from the 6 existing members 789 * to the new member such that each member will end up with between 9 and 790 * 10 entries. 791 * Parameters: 792 * unit - (IN) SOC unit number. 793 * num_entries - (IN) Number of flow set entries. 794 * buf_ptr - (IN/OUT) Flow set entry buffer. 795 * num_members - (IN) Number of entry_count_arr, 796 * including the joining member. 797 * entry_count_arr - (IN/OUT) An array keeping track of how many 798 * flow set entries have been assigned 799 * to each member. The last element is 800 * joining member, hence is 0. 801 * joining_port - (IN) Joining member. 802 * member_index_arr - (IN/OUT) Array of member indexes to entry_count_arr 803 * of existing members in Flow Set table. The 804 * element of joining is to be defined. 805 * Returns: 806 * BCM_E_xxx 807 */ 808 809 STATIC int 810 _bcm_td2_hg_rh_add_rebalance(int unit, int num_entries, uint32 *buf_ptr, 811 int num_members, int *entry_count_arr, 812 int joining_port, int *member_index_arr) 813 { 814 rh_hgt_flowset_entry_t *flowset_entry; 815 int member_index = 0; 816 int lower_bound, upper_bound; 817 int threshold; 818 int entry_index, next_entry_index; 819 int egress_port; 820 int num_existing_members = num_members - 1; 821 int new_member_entry_count = 0; 822 soc_field_t port_fld = EGRESS_PORTf; 823 824 if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) { 825 port_fld = PORT_NUMf; 826 } 827 lower_bound = num_entries / num_members; 828 upper_bound = (num_entries % num_members) ? 829 (lower_bound + 1) : lower_bound; 830 threshold = upper_bound; 831 while (new_member_entry_count < lower_bound) { 832 /* Pick a random entry in the flow set buffer */ 833 BCM_IF_ERROR_RETURN(_bcm_td2_hg_rh_rand_get( 834 unit, num_entries - 1, &entry_index)); 835 836 flowset_entry = soc_mem_table_idx_to_pointer(unit, RH_HGT_FLOWSETm, 837 rh_hgt_flowset_entry_t *, buf_ptr, entry_index); 838 egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry, 839 port_fld); 840 member_index = member_index_arr[egress_port]; 841 if ((egress_port != joining_port) && 842 (entry_count_arr[member_index] > threshold)) { 843 soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, 844 port_fld, joining_port); 845 entry_count_arr[member_index]--; 846 new_member_entry_count++; 847 } else { 848 /* Either the member of the randomly chosen entry is 849 * the same as the new member, or the member is an existing 850 * member and its entry count has decreased to threshold. 851 * In both cases, find the next entry that contains a 852 * member that's not the new member and whose entry count 853 * has not decreased to threshold. 854 */ 855 next_entry_index = (entry_index + 1) % num_entries; 856 while (next_entry_index != entry_index) { 857 flowset_entry = soc_mem_table_idx_to_pointer(unit, 858 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, 859 next_entry_index); 860 egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, 861 flowset_entry, port_fld); 862 member_index = member_index_arr[egress_port]; 863 if ((egress_port != joining_port) && 864 (entry_count_arr[member_index] > threshold)) { 865 soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, 866 port_fld, joining_port); 867 entry_count_arr[member_index]--; 868 new_member_entry_count++; 869 break; 870 } else { 871 next_entry_index = (next_entry_index + 1) % num_entries; 872 } 873 } 874 if (next_entry_index == entry_index) { 875 /* The entry count of all existing members has decreased 876 * to threshold. The entry count of the new member has 877 * not yet increased to lower_bound. Lower the threshold. 878 */ 879 threshold--; 880 } 881 } 882 } 883 entry_count_arr[num_existing_members] = new_member_entry_count; 884 member_index_arr[joining_port] = num_existing_members; 885 886 return BCM_E_NONE; 887 } 888 889 890 891 /* 892 * Function: 893 * bcm_td2_hg_rh_set 894 * Purpose: 895 * Configure a Higig resilient hashing group. 896 * Parameters: 897 * unit - (IN) SOC unit number. 898 * hgtid - (IN) Higig trunk group ID. 899 * add_info - (IN) Pointer to trunk add info structure, which contains 900 * all resilient hashing eligible members of the group. 901 * Returns: 902 * BCM_E_xxx 903 */ 904 int 905 bcm_td2_hg_rh_set(int unit, 906 int hgtid, 907 _esw_trunk_add_info_t *add_info) 908 { 909 int rv = BCM_E_NONE; 910 int num_blocks; 911 int total_blocks; 912 int max_block_base_ptr; 913 int block_base_ptr; 914 int entry_base_ptr; 915 SHR_BITDCL occupied; 916 int alloc_size; 917 uint32 *buf_ptr = NULL; 918 int *entry_count_arr = NULL; 919 int max_entry_count; 920 int chosen_index; 921 int i; 922 rh_hgt_flowset_entry_t *flowset_entry; 923 int index_min, index_max; 924 rh_hgt_group_control_entry_t rh_hgt_group_control_entry; 925 int flow_set_size; 926 hg_trunk_group_entry_t hg_trunk_group_entry; 927 hg_trunk_mode_entry_t hg_trunk_mode_entry; 928 929 if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 930 return BCM_E_PARAM; 931 } 932 933 if (add_info->num_ports == 0) { 934 /* Write the dynamic_size to hardware, so it can be 935 * recovered during warm boot. 936 */ 937 BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_set(unit, 938 hgtid, add_info->dynamic_size)); 939 940 return BCM_E_NONE; 941 } 942 943 /* Find a contiguous region of flow set table that's large 944 * enough to hold the requested number of flow sets. 945 * The flow set table is allocated in 64-entry blocks. 946 */ 947 num_blocks = add_info->dynamic_size >> 6; 948 total_blocks = soc_mem_index_count(unit, RH_HGT_FLOWSETm) >> 6; 949 max_block_base_ptr = total_blocks - num_blocks; 950 for (block_base_ptr = 0; 951 block_base_ptr <= max_block_base_ptr; 952 block_base_ptr++) { 953 /* Check if the contiguous region of flow set table from 954 * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 955 */ 956 _BCM_HG_RH_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks, 957 occupied); 958 if (!occupied) { 959 break; 960 } 961 } 962 if (block_base_ptr > max_block_base_ptr) { 963 /* A contiguous region of the desired size could not be found in 964 * flow set table. 965 */ 966 return BCM_E_RESOURCE; 967 } 968 969 /* Configure flow set table */ 970 alloc_size = add_info->dynamic_size * sizeof(rh_hgt_flowset_entry_t); 971 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries"); 972 if (NULL == buf_ptr) { 973 return BCM_E_MEMORY; 974 } 975 sal_memset(buf_ptr, 0, alloc_size); 976 977 entry_count_arr = sal_alloc(sizeof(int) * add_info->num_ports, 978 "RH entry count array"); 979 if (NULL == entry_count_arr) { 980 soc_cm_sfree(unit, buf_ptr); 981 return BCM_E_MEMORY; 982 } 983 sal_memset(entry_count_arr, 0, sizeof(int) * add_info->num_ports); 984 max_entry_count = add_info->dynamic_size / add_info->num_ports; 985 986 for (i = 0; i < add_info->dynamic_size; i++) { 987 /* Choose a member of the Higig trunk group */ 988 rv = _bcm_td2_hg_rh_member_choose(unit, add_info->num_ports, 989 entry_count_arr, &max_entry_count, &chosen_index); 990 if (BCM_FAILURE(rv)) { 991 soc_cm_sfree(unit, buf_ptr); 992 sal_free(entry_count_arr); 993 return rv; 994 } 995 996 /* Set flow set entry */ 997 flowset_entry = soc_mem_table_idx_to_pointer(unit, 998 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i); 999 soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, VALIDf, 1); 1000 if (soc_mem_field_valid(unit, RH_HGT_FLOWSETm, EGRESS_PORTf)) { 1001 soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, EGRESS_PORTf, 1002 add_info->tp[chosen_index]); 1003 } else { 1004 soc_mem_field32_set(unit, RH_HGT_FLOWSETm, flowset_entry, PORT_NUMf, 1005 add_info->tp[chosen_index]); 1006 } 1007 } 1008 1009 entry_base_ptr = block_base_ptr << 6; 1010 index_min = entry_base_ptr; 1011 index_max = index_min + add_info->dynamic_size - 1; 1012 rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL, 1013 index_min, index_max, buf_ptr); 1014 if (SOC_FAILURE(rv)) { 1015 soc_cm_sfree(unit, buf_ptr); 1016 sal_free(entry_count_arr); 1017 return rv; 1018 } 1019 soc_cm_sfree(unit, buf_ptr); 1020 sal_free(entry_count_arr); 1021 1022 _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 1023 BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_encode(unit, 1024 add_info->dynamic_size, &flow_set_size)); 1025 1026 /* Update HG_TRUNK_GROUP */ 1027 SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid, 1028 &hg_trunk_group_entry)); 1029 /* Update Higig RH group control table */ 1030 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 1031 soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry, 1032 RH_FLOW_SET_BASEf, entry_base_ptr); 1033 soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry, 1034 RH_FLOW_SET_SIZEf, flow_set_size); 1035 1036 sal_memset(&hg_trunk_mode_entry, 0, sizeof(hg_trunk_mode_entry_t)); 1037 soc_HG_TRUNK_MODEm_field32_set(unit, &hg_trunk_mode_entry, 1038 HG_TRUNK_LB_MODEf, 1); 1039 SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_MODEm(unit, MEM_BLOCK_ALL, hgtid, 1040 &hg_trunk_mode_entry)); 1041 } else { 1042 sal_memset(&rh_hgt_group_control_entry, 0, 1043 sizeof(rh_hgt_group_control_entry_t)); 1044 soc_RH_HGT_GROUP_CONTROLm_field32_set(unit, &rh_hgt_group_control_entry, 1045 FLOW_SET_BASEf, entry_base_ptr); 1046 BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_encode(unit, 1047 add_info->dynamic_size, &flow_set_size)); 1048 soc_RH_HGT_GROUP_CONTROLm_field32_set(unit, &rh_hgt_group_control_entry, 1049 FLOW_SET_SIZEf, flow_set_size); 1050 SOC_IF_ERROR_RETURN(WRITE_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, 1051 hgtid, &rh_hgt_group_control_entry)); 1052 soc_HG_TRUNK_GROUPm_field32_set(unit, &hg_trunk_group_entry, 1053 ENHANCED_HASHING_ENABLEf, 1); 1054 } 1055 SOC_IF_ERROR_RETURN(WRITE_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, hgtid, 1056 &hg_trunk_group_entry)); 1057 1058 return BCM_E_NONE; 1059 } 1060 1061 1062 /* 1063 * Function: 1064 * bcm_td2_hg_rh_replace 1065 * Purpose: 1066 * Replace Higig resilient hashing group members without flowset table shuffle. 1067 * Parameters: 1068 * unit - (IN) SOC unit number. 1069 * hgtid - (IN) Higig trunk group ID. 1070 * add_info - (IN) Pointer to trunk add info structure, which contains 1071 * all resilient hashing eligible members of the group. 1072 * num_existing - (IN) Number of existing members. 1073 * existing_ports - (IN) Ports of existing members. 1074 * existing_flags - (IN) Flags of existing members. 1075 * Returns: 1076 * BCM_E_xxx 1077 */ 1078 int 1079 bcm_td2_hg_rh_replace(int unit, 1080 int hgtid, 1081 _esw_trunk_add_info_t *add_info, 1082 uint16 num_existing, 1083 uint16 *existing_ports, 1084 uint32 *existing_flags) 1085 { 1086 int rv = BCM_E_NONE; 1087 int *leaving_ports = NULL; 1088 int *staying_ports = NULL; 1089 int *joining_ports = NULL; 1090 int num_leaving = 0; 1091 int num_staying = 0; 1092 int num_joining = 0; 1093 int num_partial; 1094 int num_new; 1095 int *new_ports; 1096 int *rearr_ports = NULL; 1097 int i, j, k; 1098 int index_min= 0; 1099 int index_max= 0; 1100 int num_entries = 0; 1101 int alloc_size; 1102 uint32 *buf_ptr = NULL; 1103 int *entry_count_arr = NULL; 1104 int member; 1105 int *member_index_arr = NULL; 1106 rh_hgt_flowset_entry_t *fs_entry; 1107 rh_hgt_group_control_entry_t hgt_entry; 1108 hg_trunk_group_entry_t hg_trunk_group_entry; 1109 soc_field_t port_fld = EGRESS_PORTf; 1110 1111 if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) { 1112 port_fld = PORT_NUMf; 1113 } 1114 if (add_info == NULL || 1115 add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 1116 return BCM_E_PARAM; 1117 } 1118 1119 num_new = add_info->num_ports; 1120 new_ports = add_info->tp; 1121 if (num_new > 0 && (new_ports == NULL)) { 1122 return BCM_E_PARAM; 1123 } 1124 if (num_existing && 1125 (existing_ports == NULL || existing_flags == NULL)) { 1126 return BCM_E_PARAM; 1127 } 1128 1129 if (num_new == 1 || num_new == 0 || num_existing == 0) { 1130 rv = bcm_td2_hg_rh_free_resource(unit, hgtid); 1131 rv = BCM_FAILURE(rv) ? rv : 1132 bcm_td2_hg_rh_set(unit, hgtid, add_info); 1133 goto cleanup; 1134 } 1135 1136 /* Figure out which members are leaving, staying or joining 1137 * the trunk group. 1138 * Note. For resilient hash, all members are different within a TRUNK. 1139 */ 1140 alloc_size = sizeof(int) * num_existing; 1141 leaving_ports = sal_alloc(alloc_size, "leaving ports"); 1142 if (leaving_ports == NULL) { 1143 rv = BCM_E_MEMORY; 1144 goto cleanup; 1145 } 1146 sal_memset(leaving_ports, 0, alloc_size); 1147 1148 alloc_size = sizeof(int) * num_existing; 1149 staying_ports = sal_alloc(alloc_size, "staying members"); 1150 if (staying_ports == NULL) { 1151 rv = BCM_E_MEMORY; 1152 goto cleanup; 1153 } 1154 sal_memset(staying_ports, 0, alloc_size); 1155 1156 for (i = 0; i < num_existing; i++) { 1157 for (j = 0; j < num_new; j++) { 1158 if (existing_ports[i] == new_ports[j]) { 1159 break; 1160 } 1161 } 1162 if (j == num_new) { 1163 leaving_ports[num_leaving++] = existing_ports[i]; 1164 } else { 1165 staying_ports[num_staying++] = existing_ports[i]; 1166 } 1167 } 1168 1169 alloc_size = sizeof(int) * num_new; 1170 joining_ports = sal_alloc(alloc_size, "joining members"); 1171 if (joining_ports == NULL) { 1172 rv = BCM_E_MEMORY; 1173 goto cleanup; 1174 } 1175 sal_memset(joining_ports, 0, alloc_size); 1176 1177 for (i = 0; i < num_new; i++) { 1178 for (j = 0; j < num_staying; j++) { 1179 if (new_ports[i] == staying_ports[j]) { 1180 break; 1181 } 1182 } 1183 if (j == num_staying) { 1184 joining_ports[num_joining++] = new_ports[i]; 1185 } 1186 } 1187 1188 if (num_staying + num_leaving != num_existing) { 1189 rv = BCM_E_INTERNAL; 1190 goto cleanup; 1191 } 1192 if (num_staying + num_joining != num_new) { 1193 rv = BCM_E_INTERNAL; 1194 goto cleanup; 1195 } 1196 1197 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 1198 rv = READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid, 1199 &hg_trunk_group_entry); 1200 if (SOC_FAILURE(rv)) { 1201 goto cleanup; 1202 } 1203 index_min = soc_HG_TRUNK_GROUPm_field32_get(unit, 1204 &hg_trunk_group_entry, RH_FLOW_SET_BASEf); 1205 num_entries = soc_HG_TRUNK_GROUPm_field32_get(unit, 1206 &hg_trunk_group_entry, RH_FLOW_SET_SIZEf); 1207 1208 } else { 1209 rv = READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, hgtid, 1210 &hgt_entry); 1211 if (SOC_FAILURE(rv)) { 1212 goto cleanup; 1213 } 1214 index_min = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 1215 &hgt_entry, FLOW_SET_BASEf); 1216 num_entries = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 1217 &hgt_entry, FLOW_SET_SIZEf); 1218 } 1219 rv = _bcm_td2_hg_rh_dynamic_size_decode(unit, num_entries, &num_entries); 1220 if (BCM_FAILURE(rv)) { 1221 goto cleanup; 1222 } 1223 1224 index_max = index_min + num_entries - 1; 1225 alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t); 1226 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HG_FLOWSET entries"); 1227 if (NULL == buf_ptr) { 1228 rv = BCM_E_MEMORY; 1229 goto cleanup; 1230 } 1231 sal_memset(buf_ptr, 0, alloc_size); 1232 1233 /* Read various tables through DMA */ 1234 if ((rv = soc_mem_read_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ANY, 1235 index_min, index_max, buf_ptr)) < 0 ) { 1236 goto cleanup; 1237 } 1238 1239 /* Get re-arrange ports */ 1240 num_partial = num_existing > num_new ? num_new : num_existing; 1241 alloc_size = num_partial * sizeof(int); 1242 rearr_ports = sal_alloc(alloc_size, "rearr_ports"); 1243 if (rearr_ports == NULL) { 1244 rv = BCM_E_MEMORY; 1245 goto cleanup; 1246 } 1247 sal_memset(rearr_ports, 0, alloc_size); 1248 1249 for (i = 0; i < num_staying; i++) { 1250 rearr_ports[i] = staying_ports[i]; 1251 } 1252 for (i = num_staying, k = 0; i < num_partial; i++) { 1253 rearr_ports[i] = joining_ports[k]; 1254 k++; 1255 } 1256 1257 /* Get entry count for each staying member port */ 1258 alloc_size = num_new * sizeof(int); 1259 entry_count_arr = sal_alloc(alloc_size, "RH entry count array"); 1260 if (NULL == entry_count_arr) { 1261 rv = BCM_E_MEMORY; 1262 goto cleanup; 1263 } 1264 sal_memset(entry_count_arr, 0, alloc_size); 1265 1266 for (i = 0; i < num_entries; i++) { 1267 fs_entry = soc_mem_table_idx_to_pointer(unit, 1268 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i); 1269 if (!soc_mem_field32_get(unit, RH_HGT_FLOWSETm, fs_entry, 1270 VALIDf)) { 1271 rv = BCM_E_INTERNAL; 1272 goto cleanup; 1273 } 1274 member = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, fs_entry, port_fld); 1275 for (j = 0; j < num_staying; j++) { 1276 if (member == rearr_ports[j]) { 1277 break; 1278 } 1279 } 1280 1281 if (j < num_staying) { 1282 entry_count_arr[j]++; 1283 } 1284 } 1285 1286 /* Get member index for each partial member port */ 1287 alloc_size = SOC_MAX_NUM_PORTS * sizeof(int); 1288 member_index_arr = sal_alloc(alloc_size, "member index array"); 1289 if (NULL == member_index_arr) { 1290 rv = BCM_E_MEMORY; 1291 goto cleanup; 1292 } 1293 for (i = 0; i < SOC_MAX_NUM_PORTS; i++) { 1294 member_index_arr[i] = -1; 1295 } 1296 for (i = 0; i < num_partial; i++) { 1297 member_index_arr[rearr_ports[i]] = i; 1298 } 1299 1300 if (num_leaving > 0) { 1301 rv = _bcm_td2_hg_rh_delete_rebalance(unit, num_entries, buf_ptr, 1302 num_partial, entry_count_arr, rearr_ports, 1303 num_leaving, leaving_ports); 1304 if (BCM_FAILURE(rv)) { 1305 goto cleanup; 1306 } 1307 } 1308 1309 for (j = num_partial; j < num_new; j++) { 1310 rv = _bcm_td2_hg_rh_add_rebalance(unit, num_entries, buf_ptr, 1311 j + 1, entry_count_arr, 1312 joining_ports[k], member_index_arr); 1313 if (BCM_FAILURE(rv)) { 1314 goto cleanup; 1315 } 1316 k++; 1317 } 1318 1319 /* Write re-balanced flow set entries to hardware */ 1320 rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL, 1321 index_min, index_max, buf_ptr); 1322 1323 cleanup: 1324 if(leaving_ports) { 1325 sal_free(leaving_ports); 1326 } 1327 if(staying_ports) { 1328 sal_free(staying_ports); 1329 } 1330 if(joining_ports) { 1331 sal_free(joining_ports); 1332 } 1333 if(rearr_ports) { 1334 sal_free(rearr_ports); 1335 } 1336 if(buf_ptr) { 1337 soc_cm_sfree(unit, buf_ptr); 1338 } 1339 if(entry_count_arr) { 1340 sal_free(entry_count_arr); 1341 } 1342 if(member_index_arr) { 1343 sal_free(member_index_arr); 1344 } 1345 return rv; 1346 1347 } 1348 1349 1350 1351 1352 /* 1353 * Function: 1354 * bcm_td2_hg_rh_add 1355 * Purpose: 1356 * Add a member to a Higig resilient hashing group. 1357 * Parameters: 1358 * unit - (IN) SOC unit number. 1359 * hgtid - (IN) Higig trunk group ID. 1360 * add_info - (IN) Pointer to trunk add info structure, which contains 1361 * all resilient hashing eligible members of the group, 1362 * including the member to be added. 1363 * new_member - (IN) Member to add. 1364 * Returns: 1365 * BCM_E_xxx 1366 */ 1367 int 1368 bcm_td2_hg_rh_add(int unit, 1369 int hgtid, 1370 _esw_trunk_add_info_t *add_info, 1371 bcm_trunk_member_t *new_member) 1372 { 1373 int rv = BCM_E_NONE; 1374 bcm_port_t new_port; 1375 bcm_module_t new_mod; 1376 bcm_port_t tmp_port; 1377 int tmp_index = -1; 1378 int num_existing_members; 1379 int *member_index_arr = NULL; 1380 int i; 1381 rh_hgt_group_control_entry_t rh_hgt_group_control_entry; 1382 int entry_base_ptr; 1383 int flow_set_size; 1384 int num_entries; 1385 int alloc_size; 1386 uint32 *buf_ptr = NULL; 1387 int index_min, index_max; 1388 int *entry_count_arr = NULL; 1389 rh_hgt_flowset_entry_t *flowset_entry; 1390 int egress_port; 1391 int member_index; 1392 int lower_bound, upper_bound; 1393 hg_trunk_group_entry_t hg_trunk_group_entry; 1394 1395 soc_field_t port_fld = EGRESS_PORTf; 1396 1397 if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) { 1398 port_fld = PORT_NUMf; 1399 } 1400 if (add_info == NULL || 1401 add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT || 1402 add_info->num_ports == 0) { 1403 return BCM_E_PARAM; 1404 } 1405 1406 if (new_member == NULL) { 1407 return BCM_E_PARAM; 1408 } 1409 1410 if (add_info->num_ports == 1) { 1411 /* Adding the first member is the same as setting one member */ 1412 return bcm_td2_hg_rh_set(unit, hgtid, add_info); 1413 } 1414 1415 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, TRUE, 1, 1416 &new_member->gport, &new_port, &new_mod)); 1417 1418 /* Swap new member to the last one for BCM_TRUNK_FLAG_MEMBER_SORT */ 1419 if (add_info->flags & BCM_TRUNK_FLAG_MEMBER_SORT) { 1420 for (i = 0; i < add_info->num_ports; i++){ 1421 if (i == (add_info->num_ports - 1)) { 1422 break; 1423 } 1424 if (new_port == add_info->tp[i]) { 1425 tmp_port = add_info->tp[i]; 1426 add_info->tp[i] = add_info->tp[add_info->num_ports - 1]; 1427 add_info->tp[add_info->num_ports - 1] = tmp_port; 1428 tmp_index = i; 1429 break; 1430 } 1431 } 1432 } 1433 1434 /* Check that the new member is the last member of the array */ 1435 if (new_port != add_info->tp[add_info->num_ports - 1]) { 1436 return BCM_E_PARAM; 1437 } 1438 num_existing_members = add_info->num_ports - 1; 1439 1440 /* Get member index for each existing member port */ 1441 member_index_arr = sal_alloc(sizeof(int) * SOC_MAX_NUM_PORTS, 1442 "member index array"); 1443 if (NULL == member_index_arr) { 1444 rv = BCM_E_MEMORY; 1445 goto cleanup; 1446 } 1447 for (i = 0; i < SOC_MAX_NUM_PORTS; i++) { 1448 member_index_arr[i] = -1; 1449 } 1450 for (i = 0; i < num_existing_members; i++) { 1451 member_index_arr[add_info->tp[i]] = i; 1452 } 1453 1454 /* Read all the flow set entries of this Higig resilient hash group, 1455 * and compute the number of entries currently assigned to each 1456 * existing member. 1457 */ 1458 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 1459 rv = READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid, 1460 &hg_trunk_group_entry); 1461 if (SOC_FAILURE(rv)) { 1462 goto cleanup; 1463 } 1464 entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit, 1465 &hg_trunk_group_entry, RH_FLOW_SET_BASEf); 1466 flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit, 1467 &hg_trunk_group_entry, RH_FLOW_SET_SIZEf); 1468 1469 } else { 1470 rv = READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, hgtid, 1471 &rh_hgt_group_control_entry); 1472 if (SOC_FAILURE(rv)) { 1473 goto cleanup; 1474 } 1475 entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 1476 &rh_hgt_group_control_entry, FLOW_SET_BASEf); 1477 flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 1478 &rh_hgt_group_control_entry, FLOW_SET_SIZEf); 1479 } 1480 rv = _bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries); 1481 if (BCM_FAILURE(rv)) { 1482 goto cleanup; 1483 } 1484 1485 alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t); 1486 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries"); 1487 if (NULL == buf_ptr) { 1488 rv = BCM_E_MEMORY; 1489 goto cleanup; 1490 } 1491 sal_memset(buf_ptr, 0, alloc_size); 1492 index_min = entry_base_ptr; 1493 index_max = index_min + num_entries - 1; 1494 rv = soc_mem_read_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ANY, 1495 index_min, index_max, buf_ptr); 1496 if (SOC_FAILURE(rv)) { 1497 goto cleanup; 1498 } 1499 1500 alloc_size = add_info->num_ports * sizeof(int); 1501 entry_count_arr = sal_alloc(alloc_size, "RH entry count array"); 1502 if (NULL == entry_count_arr) { 1503 rv = BCM_E_MEMORY; 1504 goto cleanup; 1505 } 1506 sal_memset(entry_count_arr, 0, alloc_size); 1507 1508 for (i = 0; i < num_entries; i++) { 1509 flowset_entry = soc_mem_table_idx_to_pointer(unit, 1510 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i); 1511 if (!soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry, 1512 VALIDf)) { 1513 rv = BCM_E_INTERNAL; 1514 goto cleanup; 1515 } 1516 egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry, 1517 port_fld); 1518 member_index = member_index_arr[egress_port]; 1519 if (member_index == -1) { 1520 rv = BCM_E_INTERNAL; 1521 goto cleanup; 1522 } 1523 entry_count_arr[member_index]++; 1524 } 1525 1526 /* Check that the distribution of flow set entries among existing members 1527 * is balanced. For instance, if the number of flow set entries is 64, and 1528 * the number of existing members is 6, then every member should have 1529 * between 10 and 11 entries. 1530 */ 1531 lower_bound = num_entries / num_existing_members; 1532 upper_bound = (num_entries % num_existing_members) ? 1533 (lower_bound + 1) : lower_bound; 1534 for (i = 0; i < num_existing_members; i++) { 1535 if (entry_count_arr[i] < lower_bound || 1536 entry_count_arr[i] > upper_bound) { 1537 rv = BCM_E_INTERNAL; 1538 goto cleanup; 1539 } 1540 } 1541 1542 rv = _bcm_td2_hg_rh_add_rebalance(unit, num_entries, buf_ptr, 1543 add_info->num_ports, entry_count_arr, 1544 new_port, member_index_arr); 1545 if (SOC_FAILURE(rv)) { 1546 goto cleanup; 1547 } 1548 1549 /* Write re-balanced flow set entries to hardware */ 1550 rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL, 1551 index_min, index_max, buf_ptr); 1552 1553 cleanup: 1554 if (member_index_arr) { 1555 sal_free(member_index_arr); 1556 } 1557 if (buf_ptr) { 1558 soc_cm_sfree(unit, buf_ptr); 1559 } 1560 if (entry_count_arr) { 1561 sal_free(entry_count_arr); 1562 } 1563 1564 /* Restore the order of trunk members */ 1565 if (tmp_index != -1) { 1566 tmp_port = add_info->tp[tmp_index]; 1567 add_info->tp[tmp_index] = add_info->tp[add_info->num_ports - 1]; 1568 add_info->tp[add_info->num_ports - 1] = tmp_port; 1569 } 1570 1571 return rv; 1572 } 1573 1574 /* 1575 * Function: 1576 * bcm_td2_hg_rh_delete 1577 * Purpose: 1578 * Delete a member from a Higig resilient hashing group. 1579 * Parameters: 1580 * unit - (IN) SOC unit number. 1581 * hgtid - (IN) Higig trunk group ID. 1582 * add_info - (IN) Pointer to trunk add info structure, which contains 1583 * all resilient hashing eligible members of the group, 1584 * except the member to be deleted. 1585 * leaving_member - (IN) Member to delete. 1586 * Returns: 1587 * BCM_E_xxx 1588 */ 1589 int 1590 bcm_td2_hg_rh_delete(int unit, 1591 int hgtid, 1592 _esw_trunk_add_info_t *add_info, 1593 bcm_trunk_member_t *leaving_member) 1594 { 1595 int rv = BCM_E_NONE; 1596 bcm_port_t leaving_port; 1597 bcm_module_t leaving_mod; 1598 int num_remaining_members; 1599 int *member_index_arr = NULL; 1600 int i; 1601 rh_hgt_group_control_entry_t rh_hgt_group_control_entry; 1602 int entry_base_ptr; 1603 int flow_set_size; 1604 int num_entries; 1605 int alloc_size; 1606 uint32 *buf_ptr = NULL; 1607 int index_min, index_max; 1608 int leaving_member_entry_count; 1609 int *entry_count_arr = NULL; 1610 rh_hgt_flowset_entry_t *flowset_entry; 1611 int egress_port; 1612 int member_index; 1613 int lower_bound, upper_bound; 1614 soc_field_t port_fld = EGRESS_PORTf; 1615 hg_trunk_group_entry_t hg_trunk_group_entry; 1616 1617 if (!soc_mem_field_valid(unit, RH_HGT_FLOWSETm, port_fld)) { 1618 port_fld = PORT_NUMf; 1619 } 1620 1621 if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 1622 return BCM_E_PARAM; 1623 } 1624 1625 if (leaving_member == NULL) { 1626 return BCM_E_PARAM; 1627 } 1628 1629 if (add_info->num_ports == 0) { 1630 /* Deleting the last member is the same as freeing all resources */ 1631 BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_free_resource(unit, hgtid)); 1632 1633 /* Write the dynamic_size to hardware, so it can be recovered 1634 * during warm boot. 1635 */ 1636 BCM_IF_ERROR_RETURN(bcm_td2_hg_rh_dynamic_size_set(unit, hgtid, 1637 add_info->dynamic_size)); 1638 1639 return BCM_E_NONE; 1640 } 1641 1642 /* Check that the leaving member is not a member of the array */ 1643 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, TRUE, 1, 1644 &leaving_member->gport, &leaving_port, &leaving_mod)); 1645 for (i = 0; i < add_info->num_ports; i++) { 1646 if (leaving_port == add_info->tp[i]) { 1647 return BCM_E_PARAM; 1648 } 1649 } 1650 num_remaining_members = add_info->num_ports; 1651 1652 /* Get member index for each remaining member port */ 1653 member_index_arr = sal_alloc(sizeof(int) * SOC_MAX_NUM_PORTS, 1654 "member index array"); 1655 if (NULL == member_index_arr) { 1656 rv = BCM_E_MEMORY; 1657 goto cleanup; 1658 } 1659 for (i = 0; i < SOC_MAX_NUM_PORTS; i++) { 1660 member_index_arr[i] = -1; 1661 } 1662 for (i = 0; i < num_remaining_members; i++) { 1663 member_index_arr[add_info->tp[i]] = i; 1664 } 1665 1666 /* Read all the flow set entries of this Higig resilient hash group, 1667 * and compute the number of entries currently assigned to each 1668 * member, including the leaving member. 1669 */ 1670 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 1671 rv = READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid, 1672 &hg_trunk_group_entry); 1673 if (SOC_FAILURE(rv)) { 1674 goto cleanup; 1675 } 1676 entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit, 1677 &hg_trunk_group_entry, RH_FLOW_SET_BASEf); 1678 flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit, 1679 &hg_trunk_group_entry, RH_FLOW_SET_SIZEf); 1680 1681 } else { 1682 rv = READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, hgtid, 1683 &rh_hgt_group_control_entry); 1684 if (SOC_FAILURE(rv)) { 1685 goto cleanup; 1686 } 1687 entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 1688 &rh_hgt_group_control_entry, FLOW_SET_BASEf); 1689 flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 1690 &rh_hgt_group_control_entry, FLOW_SET_SIZEf); 1691 } 1692 rv = _bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries); 1693 if (BCM_FAILURE(rv)) { 1694 goto cleanup; 1695 } 1696 1697 alloc_size = num_entries * sizeof(rh_hgt_flowset_entry_t); 1698 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_HGT_FLOWSET entries"); 1699 if (NULL == buf_ptr) { 1700 rv = BCM_E_MEMORY; 1701 goto cleanup; 1702 } 1703 sal_memset(buf_ptr, 0, alloc_size); 1704 index_min = entry_base_ptr; 1705 index_max = index_min + num_entries - 1; 1706 rv = soc_mem_read_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ANY, 1707 index_min, index_max, buf_ptr); 1708 if (SOC_FAILURE(rv)) { 1709 goto cleanup; 1710 } 1711 1712 alloc_size = num_remaining_members * sizeof(int); 1713 entry_count_arr = sal_alloc(alloc_size, "RH entry count array"); 1714 if (NULL == entry_count_arr) { 1715 rv = BCM_E_MEMORY; 1716 goto cleanup; 1717 } 1718 sal_memset(entry_count_arr, 0, alloc_size); 1719 1720 leaving_member_entry_count = 0; 1721 for (i = 0; i < num_entries; i++) { 1722 flowset_entry = soc_mem_table_idx_to_pointer(unit, 1723 RH_HGT_FLOWSETm, rh_hgt_flowset_entry_t *, buf_ptr, i); 1724 if (!soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry, 1725 VALIDf)) { 1726 rv = BCM_E_INTERNAL; 1727 goto cleanup; 1728 } 1729 egress_port = soc_mem_field32_get(unit, RH_HGT_FLOWSETm, flowset_entry, 1730 port_fld); 1731 if (egress_port == leaving_port) { 1732 leaving_member_entry_count++; 1733 } else { 1734 member_index = member_index_arr[egress_port]; 1735 if (member_index == -1) { 1736 rv = BCM_E_INTERNAL; 1737 goto cleanup; 1738 } 1739 entry_count_arr[member_index]++; 1740 } 1741 } 1742 1743 /* Check that the distribution of flow set entries among all members 1744 * is balanced. For instance, if the number of flow set entries is 64, and 1745 * the number of members is 6, then every member should have 1746 * between 10 and 11 entries. 1747 */ 1748 lower_bound = num_entries / (num_remaining_members + 1); 1749 upper_bound = (num_entries % (num_remaining_members + 1)) ? 1750 (lower_bound + 1) : lower_bound; 1751 for (i = 0; i < num_remaining_members; i++) { 1752 if (entry_count_arr[i] < lower_bound || 1753 entry_count_arr[i] > upper_bound) { 1754 rv = BCM_E_INTERNAL; 1755 goto cleanup; 1756 } 1757 } 1758 if (leaving_member_entry_count < lower_bound || 1759 leaving_member_entry_count > upper_bound) { 1760 rv = BCM_E_INTERNAL; 1761 goto cleanup; 1762 } 1763 1764 rv = _bcm_td2_hg_rh_delete_rebalance(unit, num_entries, buf_ptr, 1765 num_remaining_members, entry_count_arr, add_info->tp, 1766 1, &leaving_port); 1767 if (SOC_FAILURE(rv)) { 1768 goto cleanup; 1769 } 1770 1771 /* Write re-balanced flow set entries to hardware */ 1772 rv = soc_mem_write_range(unit, RH_HGT_FLOWSETm, MEM_BLOCK_ALL, 1773 index_min, index_max, buf_ptr); 1774 cleanup: 1775 if (member_index_arr) { 1776 sal_free(member_index_arr); 1777 } 1778 if (buf_ptr) { 1779 soc_cm_sfree(unit, buf_ptr); 1780 } 1781 if (entry_count_arr) { 1782 sal_free(entry_count_arr); 1783 } 1784 1785 return rv; 1786 } 1787 1788 /* 1789 * Function: 1790 * bcm_td2_hg_rh_ethertype_set 1791 * Purpose: 1792 * Set the Ethertypes that are eligible or ineligible for 1793 * Higig resilient hashing. 1794 * Parameters: 1795 * unit - (IN) Unit number. 1796 * flags - (IN) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags. 1797 * ethertype_count - (IN) Number of elements in ethertype_array. 1798 * ethertype_array - (IN) Array of Ethertypes. 1799 * Returns: 1800 * BCM_E_XXX 1801 */ 1802 int 1803 bcm_td2_hg_rh_ethertype_set( 1804 int unit, 1805 uint32 flags, 1806 int ethertype_count, 1807 int *ethertype_array) 1808 { 1809 uint32 control_reg; 1810 int i, j; 1811 rh_hgt_ethertype_eligibility_map_entry_t ethertype_entry; 1812 1813 /* Input check */ 1814 if (ethertype_count > soc_mem_index_count(unit, 1815 RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm)) { 1816 return BCM_E_RESOURCE; 1817 } 1818 1819 /* Update ethertype eligibility control register */ 1820 SOC_IF_ERROR_RETURN 1821 (READ_RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg)); 1822 soc_reg_field_set(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr, 1823 &control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf, 1824 flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0); 1825 soc_reg_field_set(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr, 1826 &control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf, 1827 flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER ? 1 : 0); 1828 SOC_IF_ERROR_RETURN 1829 (WRITE_RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, control_reg)); 1830 1831 /* Update Ethertype eligibility map table */ 1832 for (i = 0; i < ethertype_count; i++) { 1833 sal_memset(ðertype_entry, 0, 1834 sizeof(rh_hgt_ethertype_eligibility_map_entry_t)); 1835 soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 1836 ðertype_entry, VALIDf, 1); 1837 soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 1838 ðertype_entry, ETHERTYPEf, ethertype_array[i]); 1839 SOC_IF_ERROR_RETURN(WRITE_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm(unit, 1840 MEM_BLOCK_ALL, i, ðertype_entry)); 1841 } 1842 1843 /* Zero out remaining entries of Ethertype eligibility map table */ 1844 for (j = i; j < soc_mem_index_count(unit, 1845 RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm); j++) { 1846 SOC_IF_ERROR_RETURN(WRITE_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm(unit, 1847 MEM_BLOCK_ALL, j, soc_mem_entry_null(unit, 1848 RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm))); 1849 } 1850 1851 return BCM_E_NONE; 1852 } 1853 1854 /* 1855 * Function: 1856 * bcm_td2_hg_rh_ethertype_get 1857 * Purpose: 1858 * Get the Ethertypes that are eligible or ineligible for 1859 * Higig resilient hashing. 1860 * Parameters: 1861 * unit - (IN) Unit number. 1862 * flags - (INOUT) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags. 1863 * ethertype_max - (IN) Number of elements in ethertype_array. 1864 * ethertype_array - (OUT) Array of Ethertypes. 1865 * ethertype_count - (OUT) Number of elements returned in ethertype_array. 1866 * Returns: 1867 * BCM_E_XXX 1868 */ 1869 int 1870 bcm_td2_hg_rh_ethertype_get( 1871 int unit, 1872 uint32 *flags, 1873 int ethertype_max, 1874 int *ethertype_array, 1875 int *ethertype_count) 1876 { 1877 uint32 control_reg; 1878 int i; 1879 int ethertype; 1880 rh_hgt_ethertype_eligibility_map_entry_t ethertype_entry; 1881 1882 *ethertype_count = 0; 1883 1884 /* Get flags */ 1885 SOC_IF_ERROR_RETURN 1886 (READ_RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg)); 1887 if (soc_reg_field_get(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr, 1888 control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) { 1889 *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE; 1890 } 1891 if (soc_reg_field_get(unit, RH_HGT_ETHERTYPE_ELIGIBILITY_CONTROLr, 1892 control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) { 1893 *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER; 1894 } 1895 1896 /* Get Ethertypes */ 1897 for (i = 0; i < soc_mem_index_count(unit, 1898 RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm); i++) { 1899 SOC_IF_ERROR_RETURN(READ_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm(unit, 1900 MEM_BLOCK_ANY, i, ðertype_entry)); 1901 if (soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 1902 ðertype_entry, VALIDf)) { 1903 ethertype = soc_RH_HGT_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 1904 ðertype_entry, ETHERTYPEf); 1905 if (NULL != ethertype_array) { 1906 ethertype_array[*ethertype_count] = ethertype; 1907 } 1908 (*ethertype_count)++; 1909 if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) { 1910 break; 1911 } 1912 } 1913 } 1914 1915 return BCM_E_NONE; 1916 } 1917 1918 /* 1919 * Function: 1920 * bcm_td2_lag_rh_deinit 1921 * Purpose: 1922 * Deallocate LAG resilient hashing internal data structures 1923 * Parameters: 1924 * unit - (IN) SOC unit number. 1925 * Returns: 1926 * BCM_E_xxx 1927 */ 1928 void 1929 bcm_td2_lag_rh_deinit(int unit) 1930 { 1931 if (_td2_lag_rh_info[unit]) { 1932 if (_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap) { 1933 sal_free(_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap); 1934 _td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap = NULL; 1935 } 1936 sal_free(_td2_lag_rh_info[unit]); 1937 _td2_lag_rh_info[unit] = NULL; 1938 } 1939 } 1940 1941 /* 1942 * Function: 1943 * bcm_td2_lag_rh_init 1944 * Purpose: 1945 * Initialize LAG resilient hashing internal data structures 1946 * Parameters: 1947 * unit - (IN) SOC unit number. 1948 * Returns: 1949 * BCM_E_xxx 1950 */ 1951 int 1952 bcm_td2_lag_rh_init(int unit) 1953 { 1954 int num_lag_rh_flowset_entries; 1955 1956 if (_td2_lag_rh_info[unit] == NULL) { 1957 _td2_lag_rh_info[unit] = sal_alloc(sizeof(_td2_lag_rh_info_t), 1958 "_td2_lag_rh_info"); 1959 if (_td2_lag_rh_info[unit] == NULL) { 1960 return BCM_E_MEMORY; 1961 } 1962 sal_memset(_td2_lag_rh_info[unit], 0, sizeof(_td2_lag_rh_info_t)); 1963 } 1964 1965 /* The LAG and ECMP resilient hash features share the same flow set table. 1966 * The table can be configured in one of 3 modes: 1967 * - dedicated to LAG resilient hashing, 1968 * - dedicated to ECMP resilient hashing, 1969 * - split evenly between LAG and ECMP resilient hashing. 1970 * The mode was configured during Trident2 initialization. 1971 */ 1972 num_lag_rh_flowset_entries = soc_mem_index_count(unit, RH_LAG_FLOWSETm); 1973 1974 /* Each bit in lag_rh_flowset_block_bitmap corresponds to a block of 64 1975 * resilient hashing flow set table entries. 1976 */ 1977 _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks = 1978 num_lag_rh_flowset_entries / 64; 1979 if (_td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks > 0) { 1980 if (_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap == NULL) { 1981 _td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap = 1982 sal_alloc(SHR_BITALLOCSIZE(_td2_lag_rh_info[unit]-> 1983 num_lag_rh_flowset_blocks), 1984 "lag_rh_flowset_block_bitmap"); 1985 if (_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap == NULL) { 1986 bcm_td2_lag_rh_deinit(unit); 1987 return BCM_E_MEMORY; 1988 } 1989 sal_memset(_td2_lag_rh_info[unit]->lag_rh_flowset_block_bitmap, 0, 1990 SHR_BITALLOCSIZE(_td2_lag_rh_info[unit]-> 1991 num_lag_rh_flowset_blocks)); 1992 } 1993 } 1994 1995 /* Set the seed for the pseudo-random number generator */ 1996 _td2_lag_rh_info[unit]->lag_rh_rand_seed = sal_time_usecs(); 1997 1998 return BCM_E_NONE; 1999 } 2000 2001 /* 2002 * Function: 2003 * bcm_td2_lag_rh_dynamic_size_encode 2004 * Purpose: 2005 * Encode LAG trunk resilient hashing flow set size. 2006 * Parameters: 2007 * dynamic_size - (IN) Number of flow sets. 2008 * encoded_value - (OUT) Encoded value. 2009 * Returns: 2010 * BCM_E_xxx 2011 */ 2012 int 2013 bcm_td2_lag_rh_dynamic_size_encode(int unit, int dynamic_size, 2014 int *encoded_value) 2015 { 2016 #ifdef BCM_HELIX5_SUPPORT 2017 if (SOC_IS_HELIX5(unit)) { 2018 return _bcm_hx5_lag_rh_dynamic_size_encode(dynamic_size, encoded_value); 2019 } 2020 #endif /* BCM_HELIX5_SUPPORT */ 2021 switch (dynamic_size) { 2022 case 64: 2023 *encoded_value = 1; 2024 break; 2025 case 128: 2026 *encoded_value = 2; 2027 break; 2028 case 256: 2029 *encoded_value = 3; 2030 break; 2031 case 512: 2032 *encoded_value = 4; 2033 break; 2034 case 1024: 2035 *encoded_value = 5; 2036 break; 2037 case 2048: 2038 *encoded_value = 6; 2039 break; 2040 case 4096: 2041 *encoded_value = 7; 2042 break; 2043 case 8192: 2044 *encoded_value = 8; 2045 break; 2046 case 16384: 2047 *encoded_value = 9; 2048 break; 2049 case 32768: 2050 *encoded_value = 10; 2051 break; 2052 case 65536: 2053 *encoded_value = 11; 2054 break; 2055 default: 2056 return BCM_E_PARAM; 2057 } 2058 2059 return BCM_E_NONE; 2060 } 2061 2062 /* 2063 * Function: 2064 * _bcm_td2_lag_rh_dynamic_size_decode 2065 * Purpose: 2066 * Decode LAG trunk resilient hashing flow set size. 2067 * Parameters: 2068 * encoded_value - (IN) Encoded value. 2069 * dynamic_size - (OUT) Number of flow sets. 2070 * Returns: 2071 * BCM_E_xxx 2072 */ 2073 STATIC int 2074 _bcm_td2_lag_rh_dynamic_size_decode(int unit, int encoded_value, 2075 int *dynamic_size) 2076 { 2077 #ifdef BCM_HELIX5_SUPPORT 2078 if (SOC_IS_HELIX5(unit)) { 2079 return _bcm_hx5_lag_rh_dynamic_size_decode(encoded_value, dynamic_size); 2080 } 2081 #endif /* BCM_HELIX5_SUPPORT */ 2082 switch (encoded_value) { 2083 case 1: 2084 *dynamic_size = 64; 2085 break; 2086 case 2: 2087 *dynamic_size = 128; 2088 break; 2089 case 3: 2090 *dynamic_size = 256; 2091 break; 2092 case 4: 2093 *dynamic_size = 512; 2094 break; 2095 case 5: 2096 *dynamic_size = 1024; 2097 break; 2098 case 6: 2099 *dynamic_size = 2048; 2100 break; 2101 case 7: 2102 *dynamic_size = 4096; 2103 break; 2104 case 8: 2105 *dynamic_size = 8192; 2106 break; 2107 case 9: 2108 *dynamic_size = 16384; 2109 break; 2110 case 10: 2111 *dynamic_size = 32768; 2112 break; 2113 case 11: 2114 *dynamic_size = 65536; 2115 break; 2116 default: 2117 return BCM_E_INTERNAL; 2118 } 2119 2120 return BCM_E_NONE; 2121 } 2122 2123 /* 2124 * Function: 2125 * bcm_td2_lag_rh_free_resource 2126 * Purpose: 2127 * Free resources for a LAG resilient hashing. 2128 * Parameters: 2129 * unit - (IN) SOC unit number. 2130 * tid - (IN) LAG group ID. 2131 * Returns: 2132 * BCM_E_xxx 2133 */ 2134 int 2135 bcm_td2_lag_rh_free_resource(int unit, int tid) 2136 { 2137 int rv = BCM_E_NONE; 2138 trunk_group_entry_t trunk_group_entry; 2139 int entry_base_ptr; 2140 int flow_set_size; 2141 int num_entries; 2142 int alloc_size; 2143 uint32 *buf_ptr = NULL; 2144 int index_min, index_max; 2145 int block_base_ptr; 2146 int num_blocks, rh_enable = 0; 2147 soc_field_t lbmode_fld = ENHANCED_HASHING_ENABLEf; 2148 uint32 rval; 2149 2150 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROL_2r, RH_DLB_SELECTIONf)) { 2151 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval)); 2152 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval, 2153 RH_DLB_SELECTIONf)) { 2154 /* LAG resilient hashing is not enabled chip-wide. */ 2155 return BCM_E_NONE; 2156 } 2157 } 2158 2159 if (!soc_mem_field_valid(unit, TRUNK_GROUPm, lbmode_fld)) { 2160 lbmode_fld = TRUNK_MODEf; 2161 } 2162 2163 SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, 2164 tid, &trunk_group_entry)); 2165 2166 if (lbmode_fld == ENHANCED_HASHING_ENABLEf) { 2167 rh_enable = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 2168 lbmode_fld); 2169 } else { 2170 rh_enable = (soc_TRUNK_GROUPm_field32_get(unit, 2171 &trunk_group_entry, lbmode_fld) == 3) ? 1 :0; 2172 } 2173 2174 if (rh_enable == 0) { 2175 /* Either (1) resilient hashing is not enabled on this trunk 2176 * group, or (2) resilient hahsing is enabled with no members. 2177 * In case (2), TRUNK_GROUP.FLOW_SET_SIZE needs to be cleared. 2178 */ 2179 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2180 RH_FLOW_SET_SIZEf, 0); 2181 SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, 2182 &trunk_group_entry)); 2183 return BCM_E_NONE; 2184 } 2185 flow_set_size = soc_TRUNK_GROUPm_field32_get(unit, 2186 &trunk_group_entry, RH_FLOW_SET_SIZEf); 2187 entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit, 2188 &trunk_group_entry, RH_FLOW_SET_BASEf); 2189 2190 /* Clear resilient hashing fields in TRUNK_GROUP */ 2191 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2192 lbmode_fld, 0); 2193 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2194 RH_FLOW_SET_BASEf, 0); 2195 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2196 RH_FLOW_SET_SIZEf, 0); 2197 SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, 2198 &trunk_group_entry)); 2199 2200 /* Clear flow set table entries */ 2201 BCM_IF_ERROR_RETURN 2202 (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size, 2203 &num_entries)); 2204 alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t); 2205 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries"); 2206 if (NULL == buf_ptr) { 2207 return BCM_E_MEMORY; 2208 } 2209 sal_memset(buf_ptr, 0, alloc_size); 2210 index_min = entry_base_ptr; 2211 index_max = index_min + num_entries - 1; 2212 rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL, 2213 index_min, index_max, buf_ptr); 2214 if (SOC_FAILURE(rv)) { 2215 soc_cm_sfree(unit, buf_ptr); 2216 return rv; 2217 } 2218 soc_cm_sfree(unit, buf_ptr); 2219 2220 /* Free flow set table resources */ 2221 block_base_ptr = entry_base_ptr >> 6; 2222 num_blocks = num_entries >> 6; 2223 _BCM_LAG_RH_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, num_blocks); 2224 2225 return BCM_E_NONE; 2226 } 2227 2228 /* 2229 * Function: 2230 * bcm_td2_lag_rh_dynamic_size_set 2231 * Purpose: 2232 * Set the dynamic size for a LAG resilient hashing group with 2233 * no members, so it can be recovered from hardware during warm boot. 2234 * Parameters: 2235 * unit - (IN) SOC unit number. 2236 * tid - (IN) Trunk group ID. 2237 * dynamic_size - (IN) Number of flow sets. 2238 * Returns: 2239 * BCM_E_xxx 2240 */ 2241 int 2242 bcm_td2_lag_rh_dynamic_size_set(int unit, int tid, int dynamic_size) 2243 { 2244 trunk_group_entry_t trunk_group_entry; 2245 int flow_set_size, lb_enabled =1; 2246 soc_field_t lb_fld = ENHANCED_HASHING_ENABLEf; 2247 2248 if (!soc_mem_field_valid(unit, TRUNK_GROUPm, lb_fld)) { 2249 lb_fld = TRUNK_MODEf; 2250 lb_enabled = 3; 2251 } 2252 SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, 2253 &trunk_group_entry)); 2254 if (soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 2255 lb_fld) == lb_enabled) { 2256 /* Not expecting resilient hashing to be enabled */ 2257 return BCM_E_INTERNAL; 2258 } 2259 2260 BCM_IF_ERROR_RETURN 2261 (bcm_td2_lag_rh_dynamic_size_encode(unit, dynamic_size, 2262 &flow_set_size)); 2263 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, RH_FLOW_SET_SIZEf, 2264 flow_set_size); 2265 SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, 2266 &trunk_group_entry)); 2267 2268 return BCM_E_NONE; 2269 } 2270 2271 /* 2272 * Function: 2273 * _bcm_td2_lag_rh_rand_get 2274 * Purpose: 2275 * Get a random number between 0 and the given max value. 2276 * Parameters: 2277 * unit - (IN) SOC unit number. 2278 * rand_max - (IN) Maximum random number. 2279 * rand_num - (OUT) Random number. 2280 * Returns: 2281 * BCM_E_xxx 2282 * Notes: 2283 * This procedure uses the pseudo-random number generator algorithm 2284 * suggested by the C standard. 2285 */ 2286 STATIC int 2287 _bcm_td2_lag_rh_rand_get(int unit, int rand_max, int *rand_num) 2288 { 2289 int modulus; 2290 int rand_seed_shift; 2291 2292 if (rand_max < 0) { 2293 return BCM_E_PARAM; 2294 } 2295 2296 if (NULL == rand_num) { 2297 return BCM_E_PARAM; 2298 } 2299 2300 /* Make sure the modulus does not exceed limit. For instance, 2301 * if the 32-bit rand_seed is shifted to the right by 16 bits before 2302 * the modulo operation, the modulus should not exceed 1 << 16. 2303 */ 2304 modulus = rand_max + 1; 2305 rand_seed_shift = 16; 2306 if (modulus > (1 << (32 - rand_seed_shift))) { 2307 return BCM_E_PARAM; 2308 } 2309 2310 _td2_lag_rh_info[unit]->lag_rh_rand_seed = 2311 _td2_lag_rh_info[unit]->lag_rh_rand_seed * 1103515245 + 12345; 2312 2313 *rand_num = (_td2_lag_rh_info[unit]->lag_rh_rand_seed >> rand_seed_shift) % 2314 modulus; 2315 2316 return BCM_E_NONE; 2317 } 2318 2319 /* 2320 * Function: 2321 * _bcm_td2_lag_rh_member_choose 2322 * Purpose: 2323 * Choose a member of the LAG trunk group. 2324 * Parameters: 2325 * unit - (IN) SOC unit number. 2326 * num_members - (IN) Number of members to choose from. 2327 * entry_count_arr - (IN/OUT) An array keeping track of how many 2328 * flow set entries have been assigned 2329 * to each member. 2330 * max_entry_count - (IN/OUT) The maximum number of flow set entries 2331 * that can be assigned to a member. 2332 * chosen_index - (OUT) The index of the chosen member. 2333 * Returns: 2334 * BCM_E_xxx 2335 */ 2336 STATIC int 2337 _bcm_td2_lag_rh_member_choose(int unit, int num_members, int *entry_count_arr, 2338 int *max_entry_count, int *chosen_index) 2339 { 2340 int member_index; 2341 int next_index; 2342 2343 *chosen_index = 0; 2344 2345 /* Choose a random member index */ 2346 BCM_IF_ERROR_RETURN(_bcm_td2_lag_rh_rand_get(unit, num_members - 1, 2347 &member_index)); 2348 2349 if (entry_count_arr[member_index] < *max_entry_count) { 2350 entry_count_arr[member_index]++; 2351 *chosen_index = member_index; 2352 } else { 2353 /* The randomly chosen member has reached the maximum 2354 * flow set entry count. Choose the next member that 2355 * has not reached the maximum entry count. 2356 */ 2357 next_index = (member_index + 1) % num_members; 2358 while (next_index != member_index) { 2359 if (entry_count_arr[next_index] < *max_entry_count) { 2360 entry_count_arr[next_index]++; 2361 *chosen_index = next_index; 2362 break; 2363 } else { 2364 next_index = (next_index + 1) % num_members; 2365 } 2366 } 2367 if (next_index == member_index) { 2368 /* All members have reached the maximum flow set entry 2369 * count. This scenario occurs when dividing the number of 2370 * flow set entries by the number of members results 2371 * in a non-zero remainder. The remainder flow set entries 2372 * will be distributed among members, at most 1 remainder 2373 * entry per member. 2374 */ 2375 (*max_entry_count)++; 2376 if (entry_count_arr[member_index] < *max_entry_count) { 2377 entry_count_arr[member_index]++; 2378 *chosen_index = member_index; 2379 } else { 2380 /* It's possible that the member's entry count already equals 2381 * to the incremented value of max_entry_count. 2382 */ 2383 next_index = (member_index + 1) % num_members; 2384 while (next_index != member_index) { 2385 if (entry_count_arr[next_index] < *max_entry_count) { 2386 entry_count_arr[next_index]++; 2387 *chosen_index = next_index; 2388 break; 2389 } else { 2390 next_index = (next_index + 1) % num_members; 2391 } 2392 } 2393 if (next_index == member_index) { 2394 return BCM_E_INTERNAL; 2395 } 2396 } 2397 } 2398 } 2399 2400 return BCM_E_NONE; 2401 } 2402 2403 2404 /* 2405 * Function: 2406 * _bcm_td2_lag_rh_delete_rebalance 2407 * Purpose: 2408 * Re-balance flow set entries from the leaving member to the remaining 2409 * members. For example, if the number of flow set entries is 64, and 2410 * the number of members is 6, then each member has between 10 and 11 2411 * entries. The entries should be re-assigned from the leaving member to 2412 * the remaining 5 members such that each remaining member will end up 2413 * with between 12 and 13 entries. 2414 * Parameters: 2415 * unit - (IN) SOC unit number. 2416 * num_entries - (IN) Number of flow set entries. 2417 * buf_ptr - (IN/OUT) Flow set entry buffer. 2418 * num_members - (IN) Number of mod_arr/ port_arr/ entry_count_arr. 2419 * entry_count_arr - (IN/OUT) An array keeping track of how many 2420 * flow set entries have been assigned 2421 * to each member. 2422 * mod_arr - (IN) Array of module IDs of new members (staying, joining) 2423 * port_arr - (IN) Array of port IDs of new members (staying, joining) 2424 * num_leaving - (IN) Number of leaving_gport. 2425 * leaving_gport - (IN) Array of leaving members. 2426 * Returns: 2427 * BCM_E_xxx 2428 */ 2429 STATIC int 2430 _bcm_td2_lag_rh_delete_rebalance(int unit, int num_entries, uint32 *buf_ptr, 2431 int num_members, int *entry_count_arr, int *mod_arr, int *port_arr, 2432 int num_leaving, bcm_gport_t *leaving_gport) 2433 { 2434 2435 int threshold; 2436 int i,j; 2437 int mod, port; 2438 bcm_gport_t gport; 2439 int chosen_index; 2440 rh_lag_flowset_entry_t *flowset_entry; 2441 2442 threshold = num_entries / num_members; 2443 for (i = 0; i < num_entries; i++) { 2444 flowset_entry = soc_mem_table_idx_to_pointer(unit, 2445 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i); 2446 mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2447 MODULE_IDf); 2448 port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2449 PORT_NUMf); 2450 BCM_GPORT_MODPORT_SET(gport, mod, port); 2451 for (j = 0; j < num_leaving ; j++ ) { 2452 if (gport == leaving_gport[j]) { 2453 break; 2454 } 2455 } 2456 /* Replace the ones are leaving */ 2457 if (j < num_leaving) { 2458 /* Randomly choose a gport among the remaining members */ 2459 BCM_IF_ERROR_RETURN( _bcm_td2_lag_rh_member_choose( 2460 unit, num_members, entry_count_arr, 2461 &threshold, &chosen_index)); 2462 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, MODULE_IDf, 2463 mod_arr[chosen_index]); 2464 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, PORT_NUMf, 2465 port_arr[chosen_index]); 2466 } 2467 } 2468 return BCM_E_NONE; 2469 } 2470 2471 /* 2472 * Function: 2473 * _bcm_td2_lag_rh_add_rebalance 2474 * Purpose: 2475 * Re-balance flow set entries from existing members to the new member. 2476 * For example, if the number of flow set entries is 64, and the number of 2477 * existing members is 6, then each existing member has between 10 and 11 2478 * entries. The entries should be re-assigned from the 6 existing members 2479 * to the new member such that each member will end up with between 9 and 2480 * 10 entries. 2481 * Parameters: 2482 * unit - (IN) SOC unit number. 2483 * num_entries - (IN) Number of flow set entries. 2484 * buf_ptr - (IN/OUT) Flow set entry buffer. 2485 * num_members - (IN) Number of mod_arr/ port_arr/ entry_count_arr. 2486 * entry_count_arr - (IN/OUT) An array keeping track of how many 2487 * flow set entries have been assigned 2488 * to each member. 2489 * mod_arr - (IN) Array of module IDs of new members (staying, joining) 2490 * port_arr - (IN) Array of port IDs of new members (staying, joining) 2491 * Returns: 2492 * BCM_E_xxx 2493 */ 2494 2495 STATIC int 2496 _bcm_td2_lag_rh_add_rebalance(int unit, int num_entries, uint32 *buf_ptr, 2497 int num_members, int *entry_count_arr, 2498 int *mod_arr, int *port_arr) 2499 { 2500 int i; 2501 int new_mod, new_port; 2502 int mod, port; 2503 rh_lag_flowset_entry_t *flowset_entry; 2504 int member_index = 0; 2505 int lower_bound, upper_bound; 2506 int threshold; 2507 int entry_index, next_entry_index; 2508 int is_new_member; 2509 int num_existing_members = num_members - 1; 2510 int new_member_entry_count = 0; 2511 2512 new_mod = mod_arr[num_members - 1]; 2513 new_port = port_arr[num_members - 1]; 2514 lower_bound = num_entries / num_members; 2515 upper_bound = (num_entries % num_members) ? 2516 (lower_bound + 1) : lower_bound; 2517 threshold = upper_bound; 2518 while (new_member_entry_count < lower_bound) { 2519 /* Pick a random entry in the flow set buffer */ 2520 BCM_IF_ERROR_RETURN(_bcm_td2_lag_rh_rand_get( 2521 unit, num_entries - 1, &entry_index)); 2522 flowset_entry = soc_mem_table_idx_to_pointer(unit, RH_LAG_FLOWSETm, 2523 rh_lag_flowset_entry_t *, buf_ptr, entry_index); 2524 mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2525 MODULE_IDf); 2526 port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2527 PORT_NUMf); 2528 2529 /* Determine if the randomly picked entry contains the new member. 2530 * If not, determine the existing member index. 2531 */ 2532 if (mod == new_mod && port == new_port) { 2533 is_new_member = TRUE; 2534 } else { 2535 is_new_member = FALSE; 2536 } 2537 if (!is_new_member) { 2538 for (i = 0; i < num_existing_members; i++) { 2539 if (mod == mod_arr[i] && port == port_arr[i]) { 2540 break; 2541 } 2542 } 2543 if (i == num_existing_members) { 2544 return BCM_E_INTERNAL; 2545 } 2546 member_index = i; 2547 } 2548 2549 if (!is_new_member && (entry_count_arr[member_index] > threshold)) { 2550 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, 2551 MODULE_IDf, new_mod); 2552 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, 2553 PORT_NUMf, new_port); 2554 entry_count_arr[member_index]--; 2555 new_member_entry_count++; 2556 } else { 2557 /* Either the member of the randomly chosen entry is 2558 * the same as the new member, or the member is an existing 2559 * member and its entry count has decreased to threshold. 2560 * In both cases, find the next entry that contains a 2561 * member that's not the new member and whose entry count 2562 * has not decreased to threshold. 2563 */ 2564 next_entry_index = (entry_index + 1) % num_entries; 2565 while (next_entry_index != entry_index) { 2566 flowset_entry = soc_mem_table_idx_to_pointer(unit, 2567 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, 2568 next_entry_index); 2569 mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2570 MODULE_IDf); 2571 port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2572 PORT_NUMf); 2573 2574 /* Determine if the entry contains the new member. 2575 * If not, determine the existing member index. 2576 */ 2577 if (mod == new_mod && port == new_port) { 2578 is_new_member = TRUE; 2579 } else { 2580 is_new_member = FALSE; 2581 } 2582 if (!is_new_member) { 2583 for (i = 0; i < num_existing_members; i++) { 2584 if (mod == mod_arr[i] && port == port_arr[i]) { 2585 break; 2586 } 2587 } 2588 if (i == num_existing_members) { 2589 return BCM_E_INTERNAL; 2590 } 2591 member_index = i; 2592 } 2593 2594 if (!is_new_member && 2595 (entry_count_arr[member_index] > threshold)) { 2596 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, 2597 MODULE_IDf, new_mod); 2598 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, 2599 PORT_NUMf, new_port); 2600 entry_count_arr[member_index]--; 2601 new_member_entry_count++; 2602 break; 2603 } else { 2604 next_entry_index = (next_entry_index + 1) % num_entries; 2605 } 2606 } 2607 if (next_entry_index == entry_index) { 2608 /* The entry count of all existing members has decreased 2609 * to threshold. The entry count of the new member has 2610 * not yet increased to lower_bound. Lower the threshold. 2611 */ 2612 threshold--; 2613 } 2614 } 2615 } 2616 entry_count_arr[num_existing_members] = new_member_entry_count; 2617 2618 return BCM_E_NONE; 2619 } 2620 2621 2622 /* 2623 * Function: 2624 * bcm_td2_lag_rh_set 2625 * Purpose: 2626 * Configure a LAG resilient hashing group. 2627 * Parameters: 2628 * unit - (IN) SOC unit number. 2629 * tid - (IN) LAG trunk group ID. 2630 * add_info - (IN) Pointer to trunk add info structure. 2631 * num_rh_ports - (IN) Number of resilient hashing eligible members in 2632 * the group. 2633 * mod_array - (IN) Array of module IDs of resilient hashing eligible 2634 * members. 2635 * port_array - (IN) Array of port IDs of resilient hashing eligible 2636 * members. 2637 * Returns: 2638 * BCM_E_xxx 2639 */ 2640 int 2641 bcm_td2_lag_rh_set(int unit, 2642 int tid, 2643 _esw_trunk_add_info_t *add_info, 2644 int num_rh_ports, 2645 int *mod_array, 2646 int *port_array) 2647 { 2648 int rv = BCM_E_NONE; 2649 int num_blocks; 2650 int total_blocks; 2651 int max_block_base_ptr; 2652 int block_base_ptr; 2653 int entry_base_ptr; 2654 SHR_BITDCL occupied; 2655 int alloc_size; 2656 uint32 *buf_ptr = NULL; 2657 int *entry_count_arr = NULL; 2658 int max_entry_count; 2659 int chosen_index; 2660 int i; 2661 rh_lag_flowset_entry_t *flowset_entry; 2662 int index_min, index_max; 2663 trunk_group_entry_t trunk_group_entry; 2664 int flow_set_size; 2665 2666 2667 if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 2668 return BCM_E_PARAM; 2669 } 2670 2671 if (num_rh_ports > 0 && (mod_array == NULL || port_array == NULL)) { 2672 return BCM_E_PARAM; 2673 } 2674 2675 if (num_rh_ports == 0) { 2676 /* Write the dynamic_size to hardware, so it can be 2677 * recovered during warm boot. 2678 */ 2679 BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_dynamic_size_set(unit, 2680 tid, add_info->dynamic_size)); 2681 return BCM_E_NONE; 2682 } 2683 2684 /* Find a contiguous region of flow set table that's large 2685 * enough to hold the requested number of flow sets. 2686 * The flow set table is allocated in 64-entry blocks. 2687 */ 2688 num_blocks = add_info->dynamic_size >> 6; 2689 total_blocks = _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks; 2690 if (num_blocks > total_blocks) { 2691 return BCM_E_RESOURCE; 2692 } 2693 max_block_base_ptr = total_blocks - num_blocks; 2694 for (block_base_ptr = 0; 2695 block_base_ptr <= max_block_base_ptr; 2696 block_base_ptr++) { 2697 /* Check if the contiguous region of flow set table from 2698 * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 2699 */ 2700 _BCM_LAG_RH_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks, 2701 occupied); 2702 if (!occupied) { 2703 break; 2704 } 2705 } 2706 if (block_base_ptr > max_block_base_ptr) { 2707 /* A contiguous region of the desired size could not be found in 2708 * flow set table. 2709 */ 2710 return BCM_E_RESOURCE; 2711 } 2712 2713 /* Configure flow set table */ 2714 alloc_size = add_info->dynamic_size * sizeof(rh_lag_flowset_entry_t); 2715 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries"); 2716 if (NULL == buf_ptr) { 2717 return BCM_E_MEMORY; 2718 } 2719 sal_memset(buf_ptr, 0, alloc_size); 2720 2721 entry_count_arr = sal_alloc(sizeof(int) * num_rh_ports, 2722 "RH entry count array"); 2723 if (NULL == entry_count_arr) { 2724 soc_cm_sfree(unit, buf_ptr); 2725 return BCM_E_MEMORY; 2726 } 2727 sal_memset(entry_count_arr, 0, sizeof(int) * num_rh_ports); 2728 max_entry_count = add_info->dynamic_size / num_rh_ports; 2729 2730 for (i = 0; i < add_info->dynamic_size; i++) { 2731 /* Choose a member of the LAG */ 2732 rv = _bcm_td2_lag_rh_member_choose(unit, num_rh_ports, 2733 entry_count_arr, &max_entry_count, &chosen_index); 2734 if (BCM_FAILURE(rv)) { 2735 soc_cm_sfree(unit, buf_ptr); 2736 sal_free(entry_count_arr); 2737 return rv; 2738 } 2739 2740 /* Set flow set entry */ 2741 flowset_entry = soc_mem_table_idx_to_pointer(unit, 2742 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i); 2743 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, VALIDf, 1); 2744 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, MODULE_IDf, 2745 mod_array[chosen_index]); 2746 soc_mem_field32_set(unit, RH_LAG_FLOWSETm, flowset_entry, PORT_NUMf, 2747 port_array[chosen_index]); 2748 } 2749 2750 entry_base_ptr = block_base_ptr << 6; 2751 index_min = entry_base_ptr; 2752 index_max = index_min + add_info->dynamic_size - 1; 2753 rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL, 2754 index_min, index_max, buf_ptr); 2755 if (SOC_FAILURE(rv)) { 2756 soc_cm_sfree(unit, buf_ptr); 2757 sal_free(entry_count_arr); 2758 return rv; 2759 } 2760 soc_cm_sfree(unit, buf_ptr); 2761 sal_free(entry_count_arr); 2762 2763 _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 2764 2765 /* Update TRUNK_GROUP */ 2766 SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, 2767 &trunk_group_entry)); 2768 2769 if (soc_mem_field_valid(unit, TRUNK_GROUPm, ENHANCED_HASHING_ENABLEf)) { 2770 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2771 ENHANCED_HASHING_ENABLEf, 1); 2772 } else { 2773 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2774 TRUNK_MODEf, 3); 2775 } 2776 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2777 RH_FLOW_SET_BASEf, entry_base_ptr); 2778 BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_dynamic_size_encode(unit, 2779 add_info->dynamic_size, &flow_set_size)); 2780 soc_TRUNK_GROUPm_field32_set(unit, &trunk_group_entry, 2781 RH_FLOW_SET_SIZEf, flow_set_size); 2782 SOC_IF_ERROR_RETURN(WRITE_TRUNK_GROUPm(unit, MEM_BLOCK_ALL, tid, 2783 &trunk_group_entry)); 2784 2785 return BCM_E_NONE; 2786 } 2787 2788 2789 /* 2790 * Function: 2791 * bcm_td2_lag_rh_add 2792 * Purpose: 2793 * Add a member to a LAG resilient hashing group. 2794 * Parameters: 2795 * unit - (IN) SOC unit number. 2796 * tid - (IN) LAG trunk group ID. 2797 * add_info - (IN) Pointer to trunk add info structure. 2798 * num_rh_ports - (IN) Number of resilient hashing eligible members in 2799 * the group, including the member to be added. 2800 * mod_array - (IN) Array of module IDs of resilient hashing eligible 2801 * members, including the member to be added. 2802 * port_array - (IN) Array of port IDs of resilient hashing eligible 2803 * members, including the member to be added. 2804 * new_member - (IN) Member to add. 2805 * Returns: 2806 * BCM_E_xxx 2807 */ 2808 int 2809 bcm_td2_lag_rh_add(int unit, 2810 int tid, 2811 _esw_trunk_add_info_t *add_info, 2812 int num_rh_ports, 2813 int *mod_array, 2814 int *port_array, 2815 bcm_trunk_member_t *new_member) 2816 { 2817 int rv = BCM_E_NONE; 2818 bcm_port_t new_port; 2819 bcm_module_t new_mod; 2820 int num_existing_members; 2821 int i, j; 2822 trunk_group_entry_t trunk_group_entry; 2823 int entry_base_ptr; 2824 int flow_set_size; 2825 int num_entries; 2826 int alloc_size; 2827 uint32 *buf_ptr = NULL; 2828 int index_min, index_max; 2829 int *entry_count_arr = NULL; 2830 rh_lag_flowset_entry_t *flowset_entry; 2831 bcm_module_t mod; 2832 bcm_port_t port; 2833 int lower_bound, upper_bound; 2834 2835 if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 2836 return BCM_E_PARAM; 2837 } 2838 2839 if (num_rh_ports == 0 || mod_array == NULL || port_array == NULL) { 2840 return BCM_E_PARAM; 2841 } 2842 2843 if (new_member == NULL) { 2844 return BCM_E_PARAM; 2845 } 2846 2847 if (num_rh_ports == 1) { 2848 /* Adding the first member is the same as setting one member */ 2849 return bcm_td2_lag_rh_set(unit, tid, add_info, num_rh_ports, mod_array, 2850 port_array); 2851 } 2852 2853 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, FALSE, 1, 2854 &new_member->gport, &new_port, &new_mod)); 2855 2856 /* Swap new member to the last one for BCM_TRUNK_FLAG_MEMBER_SORT */ 2857 if (add_info->flags & BCM_TRUNK_FLAG_MEMBER_SORT) { 2858 for (i = 0; i < num_rh_ports; i++){ 2859 if (i == (num_rh_ports - 1)) { 2860 break; 2861 } 2862 if (new_mod == mod_array[i] && 2863 new_port == port_array[i]) { 2864 mod = mod_array[i]; 2865 port = port_array[i]; 2866 mod_array[i] = mod_array[num_rh_ports - 1]; 2867 port_array[i] = port_array[num_rh_ports - 1]; 2868 mod_array[num_rh_ports - 1] = mod; 2869 port_array[num_rh_ports - 1] = port; 2870 break; 2871 } 2872 } 2873 } 2874 2875 /* Check that the new member is the last element of the array of 2876 * resilient hashing eligible members. 2877 */ 2878 if (new_mod != mod_array[num_rh_ports - 1] || 2879 new_port != port_array[num_rh_ports - 1]) { 2880 return BCM_E_PARAM; 2881 } 2882 num_existing_members = num_rh_ports - 1; 2883 2884 /* Read all the flow set entries of this LAG resilient hash group, 2885 * and compute the number of entries currently assigned to each 2886 * existing member. 2887 */ 2888 SOC_IF_ERROR_RETURN 2889 (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &trunk_group_entry)); 2890 entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 2891 RH_FLOW_SET_BASEf); 2892 flow_set_size = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 2893 RH_FLOW_SET_SIZEf); 2894 BCM_IF_ERROR_RETURN 2895 (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size, 2896 &num_entries)); 2897 2898 alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t); 2899 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries"); 2900 if (NULL == buf_ptr) { 2901 return BCM_E_MEMORY; 2902 } 2903 sal_memset(buf_ptr, 0, alloc_size); 2904 index_min = entry_base_ptr; 2905 index_max = index_min + num_entries - 1; 2906 rv = soc_mem_read_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ANY, 2907 index_min, index_max, buf_ptr); 2908 if (SOC_FAILURE(rv)) { 2909 goto cleanup; 2910 } 2911 2912 alloc_size = num_rh_ports * sizeof(int); 2913 entry_count_arr = sal_alloc(alloc_size, "LAG RH entry count array"); 2914 if (NULL == entry_count_arr) { 2915 rv = BCM_E_MEMORY; 2916 goto cleanup; 2917 } 2918 sal_memset(entry_count_arr, 0, alloc_size); 2919 2920 for (i = 0; i < num_entries; i++) { 2921 flowset_entry = soc_mem_table_idx_to_pointer(unit, 2922 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i); 2923 if (!soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2924 VALIDf)) { 2925 rv = BCM_E_INTERNAL; 2926 goto cleanup; 2927 } 2928 mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2929 MODULE_IDf); 2930 port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 2931 PORT_NUMf); 2932 for (j = 0; j < num_existing_members; j++) { 2933 if (mod == mod_array[j] && port == port_array[j]) { 2934 break; 2935 } 2936 } 2937 if (j == num_existing_members) { 2938 rv = BCM_E_INTERNAL; 2939 goto cleanup; 2940 } 2941 entry_count_arr[j]++; 2942 } 2943 2944 /* Check that the distribution of flow set entries among existing members 2945 * is balanced. For instance, if the number of flow set entries is 64, and 2946 * the number of existing members is 6, then every member should have 2947 * between 10 and 11 entries. 2948 */ 2949 lower_bound = num_entries / num_existing_members; 2950 upper_bound = (num_entries % num_existing_members) ? 2951 (lower_bound + 1) : lower_bound; 2952 for (i = 0; i < num_existing_members; i++) { 2953 if (entry_count_arr[i] < lower_bound || 2954 entry_count_arr[i] > upper_bound) { 2955 rv = BCM_E_INTERNAL; 2956 goto cleanup; 2957 } 2958 } 2959 2960 rv = _bcm_td2_lag_rh_add_rebalance(unit, num_entries, buf_ptr, 2961 num_rh_ports, entry_count_arr, mod_array, port_array); 2962 if (SOC_FAILURE(rv)) { 2963 goto cleanup; 2964 } 2965 2966 /* Write re-balanced flow set entries to hardware */ 2967 rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL, 2968 index_min, index_max, buf_ptr); 2969 2970 cleanup: 2971 if (buf_ptr) { 2972 soc_cm_sfree(unit, buf_ptr); 2973 } 2974 if (entry_count_arr) { 2975 sal_free(entry_count_arr); 2976 } 2977 2978 return rv; 2979 } 2980 2981 /* 2982 * Function: 2983 * bcm_td2_lag_rh_delete 2984 * Purpose: 2985 * Delete a member from a LAG resilient hashing group. 2986 * Parameters: 2987 * unit - (IN) SOC unit number. 2988 * tid - (IN) LAG trunk group ID. 2989 * add_info - (IN) Pointer to trunk add info structure. 2990 * num_rh_ports - (IN) Number of resilient hashing eligible members in 2991 * the group, except the member to be deleted. 2992 * mod_array - (IN) Array of module IDs of resilient hashing eligible 2993 * members, except the member to be deleted. 2994 * port_array - (IN) Array of port IDs of resilient hashing eligible 2995 * members, except the member to be deleted. 2996 * leaving_member - (IN) Member to delete. 2997 * Returns: 2998 * BCM_E_xxx 2999 */ 3000 int 3001 bcm_td2_lag_rh_delete(int unit, 3002 int tid, 3003 _esw_trunk_add_info_t *add_info, 3004 int num_rh_ports, 3005 int *mod_array, 3006 int *port_array, 3007 bcm_trunk_member_t *leaving_member) 3008 { 3009 int rv = BCM_E_NONE; 3010 bcm_port_t leaving_port; 3011 bcm_module_t leaving_mod; 3012 bcm_gport_t leaving_gport; 3013 int num_remaining_members; 3014 int i, j; 3015 trunk_group_entry_t trunk_group_entry; 3016 int entry_base_ptr; 3017 int flow_set_size; 3018 int num_entries; 3019 int alloc_size; 3020 uint32 *buf_ptr = NULL; 3021 int index_min, index_max; 3022 int leaving_member_entry_count; 3023 int *entry_count_arr = NULL; 3024 rh_lag_flowset_entry_t *flowset_entry; 3025 bcm_module_t mod; 3026 bcm_port_t port; 3027 int lower_bound, upper_bound; 3028 3029 if (add_info == NULL || add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 3030 return BCM_E_PARAM; 3031 } 3032 3033 if (num_rh_ports > 0 && (mod_array == NULL || port_array == NULL)) { 3034 return BCM_E_PARAM; 3035 } 3036 3037 if (leaving_member == NULL) { 3038 return BCM_E_PARAM; 3039 } 3040 3041 if (num_rh_ports == 0) { 3042 /* Deleting the last member is the same as freeing all resources */ 3043 BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_free_resource(unit, tid)); 3044 3045 /* Write the dynamic_size to hardware, so it can be recovered 3046 * during warm boot. 3047 */ 3048 BCM_IF_ERROR_RETURN(bcm_td2_lag_rh_dynamic_size_set(unit, tid, 3049 add_info->dynamic_size)); 3050 3051 return BCM_E_NONE; 3052 } 3053 3054 /* Check that the leaving member is not a member of the array */ 3055 BCM_IF_ERROR_RETURN(_bcm_esw_trunk_gport_array_resolve(unit, FALSE, 1, 3056 &leaving_member->gport, &leaving_port, &leaving_mod)); 3057 for (i = 0; i < num_rh_ports; i++) { 3058 if (leaving_mod == mod_array[i] && leaving_port == port_array[i]) { 3059 return BCM_E_PARAM; 3060 } 3061 } 3062 num_remaining_members = num_rh_ports; 3063 3064 /* Read all the flow set entries of this LAG resilient hash group, 3065 * and compute the number of entries currently assigned to each 3066 * member, including the leaving member. 3067 */ 3068 SOC_IF_ERROR_RETURN 3069 (READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &trunk_group_entry)); 3070 entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 3071 RH_FLOW_SET_BASEf); 3072 flow_set_size = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 3073 RH_FLOW_SET_SIZEf); 3074 BCM_IF_ERROR_RETURN 3075 (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size, 3076 &num_entries)); 3077 3078 alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t); 3079 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries"); 3080 if (NULL == buf_ptr) { 3081 return BCM_E_MEMORY; 3082 } 3083 sal_memset(buf_ptr, 0, alloc_size); 3084 index_min = entry_base_ptr; 3085 index_max = index_min + num_entries - 1; 3086 rv = soc_mem_read_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ANY, 3087 index_min, index_max, buf_ptr); 3088 if (SOC_FAILURE(rv)) { 3089 goto cleanup; 3090 } 3091 3092 alloc_size = num_remaining_members * sizeof(int); 3093 entry_count_arr = sal_alloc(alloc_size, "RH entry count array"); 3094 if (NULL == entry_count_arr) { 3095 rv = BCM_E_MEMORY; 3096 goto cleanup; 3097 } 3098 sal_memset(entry_count_arr, 0, alloc_size); 3099 3100 leaving_member_entry_count = 0; 3101 for (i = 0; i < num_entries; i++) { 3102 flowset_entry = soc_mem_table_idx_to_pointer(unit, 3103 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i); 3104 if (!soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 3105 VALIDf)) { 3106 rv = BCM_E_INTERNAL; 3107 goto cleanup; 3108 } 3109 mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 3110 MODULE_IDf); 3111 port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, flowset_entry, 3112 PORT_NUMf); 3113 if (mod == leaving_mod && port == leaving_port) { 3114 leaving_member_entry_count++; 3115 } else { 3116 for (j = 0; j < num_remaining_members; j++) { 3117 if (mod == mod_array[j] && port == port_array[j]) { 3118 break; 3119 } 3120 } 3121 if (j == num_remaining_members) { 3122 rv = BCM_E_INTERNAL; 3123 goto cleanup; 3124 } 3125 entry_count_arr[j]++; 3126 } 3127 } 3128 3129 /* Check that the distribution of flow set entries among all members 3130 * is balanced. For instance, if the number of flow set entries is 64, and 3131 * the number of members is 6, then every member should have 3132 * between 10 and 11 entries. 3133 */ 3134 lower_bound = num_entries / (num_remaining_members + 1); 3135 upper_bound = (num_entries % (num_remaining_members + 1)) ? 3136 (lower_bound + 1) : lower_bound; 3137 for (i = 0; i < num_remaining_members; i++) { 3138 if (entry_count_arr[i] < lower_bound || 3139 entry_count_arr[i] > upper_bound) { 3140 rv = BCM_E_INTERNAL; 3141 goto cleanup; 3142 } 3143 } 3144 if (leaving_member_entry_count < lower_bound || 3145 leaving_member_entry_count > upper_bound) { 3146 rv = BCM_E_INTERNAL; 3147 goto cleanup; 3148 } 3149 3150 BCM_GPORT_MODPORT_SET(leaving_gport, leaving_mod, leaving_port); 3151 rv = _bcm_td2_lag_rh_delete_rebalance(unit, num_entries, buf_ptr, 3152 num_remaining_members, entry_count_arr, mod_array,port_array, 3153 1, &leaving_gport); 3154 if (SOC_FAILURE(rv)) { 3155 goto cleanup; 3156 } 3157 3158 /* Write re-balanced flow set entries to hardware */ 3159 rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL, 3160 index_min, index_max, buf_ptr); 3161 3162 cleanup: 3163 if (buf_ptr) { 3164 soc_cm_sfree(unit, buf_ptr); 3165 } 3166 if (entry_count_arr) { 3167 sal_free(entry_count_arr); 3168 } 3169 3170 return rv; 3171 } 3172 3173 3174 3175 3176 /* 3177 * Function: 3178 * bcm_td2_lag_rh_replace 3179 * Purpose: 3180 * Replace TRUNK resilient hashing group members without flowset table shuffle. 3181 * Parameters: 3182 * unit - (IN) SOC unit number. 3183 * tid - (IN) LAG trunk group ID. 3184 * add_info - (IN) Pointer to trunk add info structure. 3185 * num_rh_ports - (IN) Number of resilient hashing eligible members in 3186 * the group, except the member to be deleted. 3187 * mod_array - (IN) Array of module IDs of resilient hashing eligible 3188 * members, except the member to be deleted. 3189 * port_array - (IN) Array of port IDs of resilient hashing eligible 3190 * members, except the member to be deleted. 3191 * num_existing - (IN) Number of existing members. 3192 * existing_ports - (IN) Ports of existing members. 3193 * existing_flags - (IN) Flags of existing members. 3194 * Returns: 3195 * BCM_E_xxx 3196 */ 3197 int 3198 bcm_td2_lag_rh_replace(int unit, 3199 int tid, 3200 _esw_trunk_add_info_t *add_info, 3201 int num_rh_ports, 3202 int *mod_array, 3203 int *port_array, 3204 uint16 num_existing, 3205 uint16 *existing_modports, 3206 uint32 *existing_flags) 3207 { 3208 int rv = BCM_E_NONE; 3209 bcm_gport_t gport; 3210 bcm_gport_t *existing_gports = NULL; 3211 bcm_gport_t *leaving_gports = NULL; 3212 bcm_gport_t *staying_gports = NULL; 3213 bcm_gport_t *joining_gports = NULL; 3214 int num_leaving = 0; 3215 int num_staying = 0; 3216 int num_joining = 0; 3217 int num_partial; 3218 int *rearr_mod = NULL; 3219 int *rearr_port = NULL; 3220 int i, j, k; 3221 int index_min= 0; 3222 int index_max= 0; 3223 int num_entries = 0; 3224 int alloc_size; 3225 uint32 *buf_ptr = NULL; 3226 int *entry_count_arr = NULL; 3227 int mod; 3228 int port; 3229 rh_lag_flowset_entry_t *fs_entry; 3230 trunk_group_entry_t tg_entry; 3231 3232 if (add_info == NULL || 3233 add_info->psc != BCM_TRUNK_PSC_DYNAMIC_RESILIENT) { 3234 return BCM_E_PARAM; 3235 } 3236 3237 if (num_rh_ports > 0 && (mod_array == NULL || port_array == NULL)) { 3238 return BCM_E_PARAM; 3239 } 3240 3241 if (num_existing > 0 && 3242 (existing_modports == NULL || existing_flags == NULL)) { 3243 return BCM_E_PARAM; 3244 } 3245 3246 /* Get gports of existing members */ 3247 alloc_size = sizeof(bcm_gport_t) * num_existing; 3248 existing_gports = sal_alloc(alloc_size, "existing_gports"); 3249 if (existing_gports == NULL) { 3250 rv = BCM_E_MEMORY; 3251 goto cleanup; 3252 } 3253 sal_memset(existing_gports, 0, alloc_size); 3254 for (i = 0, j = 0; i < num_existing; i++) { 3255 mod = existing_modports[i] >> 8; 3256 port = existing_modports[i] & 0xff; 3257 3258 if ((existing_flags[i] & BCM_TRUNK_MEMBER_EGRESS_DISABLE) || 3259 (existing_flags[i] & BCM_TRUNK_MEMBER_UNICAST_EGRESS_DISABLE)) { 3260 continue; 3261 } 3262 BCM_GPORT_MODPORT_SET(existing_gports[j], mod, port); 3263 j++; 3264 } 3265 num_existing = j; 3266 3267 if (num_rh_ports == 0 || num_rh_ports == 1 || num_existing == 0) { 3268 rv = bcm_td2_lag_rh_free_resource(unit, tid); 3269 rv = BCM_FAILURE(rv) ? rv : 3270 bcm_td2_lag_rh_set(unit, tid, add_info, num_rh_ports, mod_array, 3271 port_array); 3272 goto cleanup; 3273 } 3274 3275 /* Figure out which members are leaving, staying or joining 3276 * the trunk group. 3277 * Note. For resilient hash, all members are different within a TRUNK. 3278 */ 3279 alloc_size = sizeof(bcm_gport_t) * num_existing; 3280 leaving_gports = sal_alloc(alloc_size, "leaving members"); 3281 if (leaving_gports == NULL) { 3282 rv = BCM_E_MEMORY; 3283 goto cleanup; 3284 } 3285 sal_memset(leaving_gports, 0, alloc_size); 3286 3287 alloc_size = sizeof(bcm_gport_t) * num_existing; 3288 staying_gports = sal_alloc(alloc_size, "staying members"); 3289 if (staying_gports == NULL) { 3290 rv = BCM_E_MEMORY; 3291 goto cleanup; 3292 } 3293 sal_memset(staying_gports, 0, alloc_size); 3294 3295 for (i = 0; i < num_existing; i++) { 3296 mod = BCM_GPORT_MODPORT_MODID_GET(existing_gports[i]); 3297 port = BCM_GPORT_MODPORT_PORT_GET(existing_gports[i]); 3298 for (j = 0; j < num_rh_ports; j++) { 3299 if (mod == mod_array[j] && port == port_array[j]) { 3300 break; 3301 } 3302 } 3303 if (j == num_rh_ports) { 3304 leaving_gports[num_leaving++] = existing_gports[i]; 3305 } else { 3306 staying_gports[num_staying++] = existing_gports[i]; 3307 } 3308 } 3309 3310 alloc_size = sizeof(bcm_gport_t) * num_rh_ports; 3311 joining_gports = sal_alloc(alloc_size, "joining members"); 3312 if (joining_gports == NULL) { 3313 rv = BCM_E_MEMORY; 3314 goto cleanup; 3315 } 3316 sal_memset(joining_gports, 0, alloc_size); 3317 for (i = 0; i < num_rh_ports; i++) { 3318 BCM_GPORT_MODPORT_SET(gport, mod_array[i], port_array[i]); 3319 for (j = 0; j < num_staying; j++) { 3320 if (gport == staying_gports[j]) { 3321 break; 3322 } 3323 } 3324 if (j == num_staying) { 3325 joining_gports[num_joining++] = gport; 3326 } 3327 } 3328 3329 if (num_staying + num_leaving != num_existing) { 3330 rv = BCM_E_INTERNAL; 3331 goto cleanup; 3332 } 3333 3334 if (num_staying + num_joining != num_rh_ports) { 3335 rv = BCM_E_INTERNAL; 3336 goto cleanup; 3337 } 3338 3339 rv = READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, tid, &tg_entry); 3340 if (BCM_FAILURE(rv)) { 3341 goto cleanup; 3342 } 3343 index_min = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 3344 RH_FLOW_SET_BASEf); 3345 num_entries = soc_TRUNK_GROUPm_field32_get(unit, &tg_entry, 3346 RH_FLOW_SET_SIZEf); 3347 rv = _bcm_td2_lag_rh_dynamic_size_decode(unit, num_entries, &num_entries); 3348 if (BCM_FAILURE(rv)) { 3349 goto cleanup; 3350 } 3351 3352 index_max = index_min + num_entries - 1; 3353 3354 alloc_size = num_entries * sizeof(rh_lag_flowset_entry_t); 3355 buf_ptr = soc_cm_salloc(unit, alloc_size, "RH_LAG_FLOWSET entries"); 3356 if (NULL == buf_ptr) { 3357 rv = BCM_E_MEMORY; 3358 goto cleanup; 3359 } 3360 sal_memset(buf_ptr, 0, alloc_size); 3361 3362 /* Read various tables through DMA */ 3363 if ((rv = soc_mem_read_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ANY, 3364 index_min, index_max, buf_ptr)) < 0 ) { 3365 goto cleanup; 3366 } 3367 3368 alloc_size = num_rh_ports * sizeof(int); 3369 rearr_mod = sal_alloc(alloc_size, "rearr_mod"); 3370 if (rearr_mod == NULL) { 3371 rv = BCM_E_MEMORY; 3372 goto cleanup; 3373 } 3374 sal_memset(rearr_mod, 0, alloc_size); 3375 3376 rearr_port = sal_alloc(alloc_size, "rearr_port"); 3377 if (rearr_port == NULL) { 3378 rv = BCM_E_MEMORY; 3379 goto cleanup; 3380 } 3381 sal_memset(rearr_port, 0, alloc_size); 3382 3383 3384 for (i = 0; i < num_staying; i++) { 3385 rearr_mod[i] = BCM_GPORT_MODPORT_MODID_GET(staying_gports[i]); 3386 rearr_port[i] = BCM_GPORT_MODPORT_PORT_GET(staying_gports[i]); 3387 } 3388 3389 num_partial = num_existing > num_rh_ports ? num_rh_ports : num_existing; 3390 for (i = num_staying, k = 0; i < num_partial; i++) { 3391 rearr_mod[i] = BCM_GPORT_MODPORT_MODID_GET(joining_gports[k]); 3392 rearr_port[i] = BCM_GPORT_MODPORT_PORT_GET(joining_gports[k]); 3393 k++; 3394 } 3395 3396 /* Get entry count for each staying member port */ 3397 alloc_size = num_rh_ports * sizeof(int); 3398 entry_count_arr = sal_alloc(alloc_size, "RH entry count array"); 3399 if (NULL == entry_count_arr) { 3400 rv = BCM_E_MEMORY; 3401 goto cleanup; 3402 } 3403 sal_memset(entry_count_arr, 0, alloc_size); 3404 3405 for (i = 0; i < num_entries; i++) { 3406 fs_entry = soc_mem_table_idx_to_pointer(unit, 3407 RH_LAG_FLOWSETm, rh_lag_flowset_entry_t *, buf_ptr, i); 3408 if (!soc_mem_field32_get(unit, RH_LAG_FLOWSETm, fs_entry, 3409 VALIDf)) { 3410 rv = BCM_E_INTERNAL; 3411 goto cleanup; 3412 } 3413 mod = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, fs_entry, 3414 MODULE_IDf); 3415 port = soc_mem_field32_get(unit, RH_LAG_FLOWSETm, fs_entry, 3416 PORT_NUMf); 3417 for (j = 0; j < num_staying; j++) { 3418 if (mod == rearr_mod[j] && port == rearr_port[j]) { 3419 break; 3420 } 3421 } 3422 3423 if (j < num_staying) { 3424 entry_count_arr[j]++; 3425 } 3426 } 3427 3428 if (num_leaving > 0) { 3429 rv = _bcm_td2_lag_rh_delete_rebalance(unit, num_entries, buf_ptr, 3430 num_partial, entry_count_arr,rearr_mod,rearr_port, 3431 num_leaving, leaving_gports); 3432 if (BCM_FAILURE(rv)) { 3433 goto cleanup; 3434 } 3435 } 3436 3437 for (j = num_partial; j < num_rh_ports; j++) { 3438 rearr_mod[j] = BCM_GPORT_MODPORT_MODID_GET(joining_gports[k]); 3439 rearr_port[j] = BCM_GPORT_MODPORT_PORT_GET(joining_gports[k]); 3440 3441 rv = _bcm_td2_lag_rh_add_rebalance(unit, num_entries, buf_ptr, 3442 j + 1, entry_count_arr, rearr_mod, rearr_port); 3443 if (BCM_FAILURE(rv)) { 3444 goto cleanup; 3445 } 3446 k++; 3447 } 3448 3449 /* Write re-balanced flow set entries to hardware */ 3450 rv = soc_mem_write_range(unit, RH_LAG_FLOWSETm, MEM_BLOCK_ALL, 3451 index_min, index_max, buf_ptr); 3452 3453 cleanup: 3454 if(existing_gports) { 3455 sal_free(existing_gports); 3456 } 3457 if(leaving_gports) { 3458 sal_free(leaving_gports); 3459 } 3460 if(staying_gports) { 3461 sal_free(staying_gports); 3462 } 3463 if(joining_gports) { 3464 sal_free(joining_gports); 3465 } 3466 if(rearr_mod) { 3467 sal_free(rearr_mod); 3468 } 3469 if(rearr_port) { 3470 sal_free(rearr_port); 3471 } 3472 if(buf_ptr) { 3473 soc_cm_sfree(unit, buf_ptr); 3474 } 3475 if(entry_count_arr) { 3476 sal_free(entry_count_arr); 3477 } 3478 return rv; 3479 3480 } 3481 3482 3483 /* 3484 * Function: 3485 * bcm_td2_lag_rh_ethertype_set 3486 * Purpose: 3487 * Set the Ethertypes that are eligible or ineligible for 3488 * LAG resilient hashing. 3489 * Parameters: 3490 * unit - (IN) Unit number. 3491 * flags - (IN) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags. 3492 * ethertype_count - (IN) Number of elements in ethertype_array. 3493 * ethertype_array - (IN) Array of Ethertypes. 3494 * Returns: 3495 * BCM_E_XXX 3496 */ 3497 int 3498 bcm_td2_lag_rh_ethertype_set( 3499 int unit, 3500 uint32 flags, 3501 int ethertype_count, 3502 int *ethertype_array) 3503 { 3504 uint32 control_reg; 3505 int i, j; 3506 rh_lag_ethertype_eligibility_map_entry_t ethertype_entry; 3507 3508 /* Input check */ 3509 if (ethertype_count > soc_mem_index_count(unit, 3510 RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm)) { 3511 return BCM_E_RESOURCE; 3512 } 3513 3514 /* Update ethertype eligibility control register */ 3515 SOC_IF_ERROR_RETURN 3516 (READ_RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg)); 3517 soc_reg_field_set(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr, 3518 &control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf, 3519 flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0); 3520 soc_reg_field_set(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr, 3521 &control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf, 3522 flags & BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER ? 1 : 0); 3523 SOC_IF_ERROR_RETURN 3524 (WRITE_RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, control_reg)); 3525 3526 /* Update Ethertype eligibility map table */ 3527 for (i = 0; i < ethertype_count; i++) { 3528 sal_memset(ðertype_entry, 0, 3529 sizeof(rh_lag_ethertype_eligibility_map_entry_t)); 3530 soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 3531 ðertype_entry, VALIDf, 1); 3532 soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 3533 ðertype_entry, ETHERTYPEf, ethertype_array[i]); 3534 SOC_IF_ERROR_RETURN(WRITE_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm(unit, 3535 MEM_BLOCK_ALL, i, ðertype_entry)); 3536 } 3537 3538 /* Zero out remaining entries of Ethertype eligibility map table */ 3539 for (j = i; j < soc_mem_index_count(unit, 3540 RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm); j++) { 3541 SOC_IF_ERROR_RETURN(WRITE_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm(unit, 3542 MEM_BLOCK_ALL, j, soc_mem_entry_null(unit, 3543 RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm))); 3544 } 3545 3546 return BCM_E_NONE; 3547 } 3548 3549 /* 3550 * Function: 3551 * bcm_td2_lag_rh_ethertype_get 3552 * Purpose: 3553 * Get the Ethertypes that are eligible or ineligible for 3554 * LAG resilient hashing. 3555 * Parameters: 3556 * unit - (IN) Unit number. 3557 * flags - (INOUT) BCM_TRUNK_DYNAMIC_ETHERTYPE_xxx flags. 3558 * ethertype_max - (IN) Number of elements in ethertype_array. 3559 * ethertype_array - (OUT) Array of Ethertypes. 3560 * ethertype_count - (OUT) Number of elements returned in ethertype_array. 3561 * Returns: 3562 * BCM_E_XXX 3563 */ 3564 int 3565 bcm_td2_lag_rh_ethertype_get( 3566 int unit, 3567 uint32 *flags, 3568 int ethertype_max, 3569 int *ethertype_array, 3570 int *ethertype_count) 3571 { 3572 uint32 control_reg; 3573 int i; 3574 int ethertype; 3575 rh_lag_ethertype_eligibility_map_entry_t ethertype_entry; 3576 3577 *ethertype_count = 0; 3578 3579 /* Get flags */ 3580 SOC_IF_ERROR_RETURN 3581 (READ_RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, &control_reg)); 3582 if (soc_reg_field_get(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr, 3583 control_reg, ETHERTYPE_ELIGIBILITY_CONFIGf)) { 3584 *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_ELIGIBLE; 3585 } 3586 if (soc_reg_field_get(unit, RH_LAG_ETHERTYPE_ELIGIBILITY_CONTROLr, 3587 control_reg, INNER_OUTER_ETHERTYPE_SELECTIONf)) { 3588 *flags |= BCM_TRUNK_DYNAMIC_ETHERTYPE_INNER; 3589 } 3590 3591 /* Get Ethertypes */ 3592 for (i = 0; i < soc_mem_index_count(unit, 3593 RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm); i++) { 3594 SOC_IF_ERROR_RETURN(READ_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm(unit, 3595 MEM_BLOCK_ANY, i, ðertype_entry)); 3596 if (soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 3597 ðertype_entry, VALIDf)) { 3598 ethertype = soc_RH_LAG_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 3599 ðertype_entry, ETHERTYPEf); 3600 if (NULL != ethertype_array) { 3601 ethertype_array[*ethertype_count] = ethertype; 3602 } 3603 (*ethertype_count)++; 3604 if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) { 3605 break; 3606 } 3607 } 3608 } 3609 3610 return BCM_E_NONE; 3611 } 3612 3613 #ifdef BCM_WARM_BOOT_SUPPORT 3614 3615 /* 3616 * Function: 3617 * bcm_td2_hg_rh_recover 3618 * Purpose: 3619 * Recover Higig resilient hashing software state. 3620 * Parameters: 3621 * unit - (IN) SOC unit number. 3622 * hgtid - (IN) Higig trunk ID. 3623 * trunk_info - (OUT) Pointer to trunk info. 3624 * Returns: 3625 * BCM_E_xxx 3626 */ 3627 int 3628 bcm_td2_hg_rh_recover(int unit, int hgtid, trunk_private_t *trunk_info) 3629 { 3630 rh_hgt_group_control_entry_t rh_hgt_group_control_entry; 3631 hg_trunk_group_entry_t hg_trunk_group_entry; 3632 int flow_set_size; 3633 int entry_base_ptr; 3634 int num_entries; 3635 int block_base_ptr; 3636 int num_blocks; 3637 hg_trunk_mode_entry_t hg_trunk_mode_entry; 3638 uint32 rval; 3639 3640 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 3641 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval)); 3642 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval, 3643 RH_DLB_SELECTIONf)) { 3644 /* trunk resilient hashing is not enabled chip-wide. */ 3645 return BCM_E_NONE; 3646 } 3647 } 3648 3649 /* A Higig trunk group can be in one of 3 resilient hashing states: 3650 * (1) RH not enabled: RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE = 0. 3651 * (2) RH enabled but without any members: 3652 * RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE is non-zero, 3653 * HG_TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 0. 3654 * (3) RH enabled with members: 3655 * RH_HGT_GROUP_CONTROL.FLOW_SET_SIZE is non-zero, 3656 * HG_TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 1. 3657 */ 3658 3659 SOC_IF_ERROR_RETURN(READ_HG_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, hgtid, 3660 &hg_trunk_group_entry)); 3661 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 3662 flow_set_size = soc_HG_TRUNK_GROUPm_field32_get(unit, 3663 &hg_trunk_group_entry, RH_FLOW_SET_SIZEf); 3664 } else { 3665 SOC_IF_ERROR_RETURN(READ_RH_HGT_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, 3666 hgtid, &rh_hgt_group_control_entry)); 3667 flow_set_size = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 3668 &rh_hgt_group_control_entry, FLOW_SET_SIZEf); 3669 } 3670 if (0 == flow_set_size) { 3671 /* Resilient hashing is not enabled on this Higig trunk group. 3672 * Nothing to do. 3673 */ 3674 return BCM_E_NONE; 3675 } 3676 3677 /* Recover dynamic size */ 3678 BCM_IF_ERROR_RETURN 3679 (_bcm_td2_hg_rh_dynamic_size_decode(unit, flow_set_size, &num_entries)); 3680 trunk_info->dynamic_size = num_entries; 3681 3682 /* Recover PSC */ 3683 trunk_info->psc = BCM_TRUNK_PSC_DYNAMIC_RESILIENT; 3684 3685 /* Recover Higig resilient hashing flow set block usage */ 3686 3687 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 3688 SOC_IF_ERROR_RETURN(READ_HG_TRUNK_MODEm(unit, MEM_BLOCK_ANY, 3689 hgtid, &hg_trunk_mode_entry)); 3690 if (1 == soc_HG_TRUNK_MODEm_field32_get(unit, 3691 &hg_trunk_mode_entry, HG_TRUNK_LB_MODEf)) { 3692 entry_base_ptr = soc_HG_TRUNK_GROUPm_field32_get(unit, 3693 &hg_trunk_group_entry, RH_FLOW_SET_BASEf); 3694 block_base_ptr = entry_base_ptr >> 6; 3695 num_blocks = num_entries >> 6; 3696 _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 3697 } 3698 } else { 3699 if (soc_HG_TRUNK_GROUPm_field32_get(unit, &hg_trunk_group_entry, 3700 ENHANCED_HASHING_ENABLEf)) { 3701 entry_base_ptr = soc_RH_HGT_GROUP_CONTROLm_field32_get(unit, 3702 &rh_hgt_group_control_entry, FLOW_SET_BASEf); 3703 block_base_ptr = entry_base_ptr >> 6; 3704 num_blocks = num_entries >> 6; 3705 _BCM_HG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 3706 } 3707 } 3708 return BCM_E_NONE; 3709 } 3710 3711 /* 3712 * Function: 3713 * bcm_td2_lag_rh_recover 3714 * Purpose: 3715 * Recover LAG resilient hashing software state. 3716 * Parameters: 3717 * unit - (IN) SOC unit number. 3718 * tid - (IN) Trunk group ID. 3719 * trunk_info - (OUT) Pointer to trunk info. 3720 * Returns: 3721 * BCM_E_xxx 3722 */ 3723 int 3724 bcm_td2_lag_rh_recover(int unit, int tid, trunk_private_t *trunk_info) 3725 { 3726 trunk_group_entry_t trunk_group_entry; 3727 int flow_set_size; 3728 int entry_base_ptr; 3729 int num_entries; 3730 int block_base_ptr; 3731 int num_blocks; 3732 int members_any = 0; 3733 uint32 rval; 3734 3735 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 3736 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROL_2r(unit, &rval)); 3737 if (0 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROL_2r, rval, 3738 RH_DLB_SELECTIONf)) { 3739 /* trunk resilient hashing is not enabled chip-wide. */ 3740 return BCM_E_NONE; 3741 } 3742 } 3743 3744 /* A trunk group can be in one of 3 resilient hashing states: 3745 * (1) RH not enabled: TRUNK_GROUP.RH_FLOW_SET_SIZE = 0. 3746 * (2) RH enabled but without any members: 3747 * TRUNK_GROUP.RH_FLOW_SET_SIZE is non-zero, 3748 * TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 0. 3749 * (3) RH enabled with members: 3750 * TRUNK_GROUP.RH_FLOW_SET_SIZE is non-zero, 3751 * TRUNK_GROUP.ENHANCED_HASHING_ENABLE = 1. 3752 */ 3753 3754 SOC_IF_ERROR_RETURN(READ_TRUNK_GROUPm(unit, MEM_BLOCK_ANY, 3755 tid, &trunk_group_entry)); 3756 flow_set_size = soc_TRUNK_GROUPm_field32_get(unit, 3757 &trunk_group_entry, RH_FLOW_SET_SIZEf); 3758 if (0 == flow_set_size) { 3759 /* Resilient hashing is not enabled on this LAG. 3760 * Nothing to do. 3761 */ 3762 return BCM_E_NONE; 3763 } 3764 3765 /* Recover dynamic size */ 3766 BCM_IF_ERROR_RETURN 3767 (_bcm_td2_lag_rh_dynamic_size_decode(unit, flow_set_size, 3768 &num_entries)); 3769 trunk_info->dynamic_size = num_entries; 3770 3771 /* Recover PSC */ 3772 trunk_info->psc = BCM_TRUNK_PSC_DYNAMIC_RESILIENT; 3773 3774 if (soc_feature(unit, soc_feature_td3_style_dlb_rh)) { 3775 if ((soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 3776 TRUNK_MODEf) == 3)) { 3777 members_any = 1; 3778 } 3779 } else { 3780 members_any = soc_TRUNK_GROUPm_field32_get(unit, &trunk_group_entry, 3781 ENHANCED_HASHING_ENABLEf); 3782 } 3783 if (members_any > 0) { 3784 /* Recover LAG resilient hashing flow set block usage */ 3785 entry_base_ptr = soc_TRUNK_GROUPm_field32_get(unit, 3786 &trunk_group_entry, RH_FLOW_SET_BASEf); 3787 block_base_ptr = entry_base_ptr >> 6; 3788 num_blocks = num_entries >> 6; 3789 _BCM_LAG_RH_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 3790 } 3791 3792 return BCM_E_NONE; 3793 } 3794 3795 #endif /* BCM_WARM_BOOT_SUPPORT */ 3796 3797 #ifndef BCM_SW_STATE_DUMP_DISABLE 3798 3799 /* 3800 * Function: 3801 * bcm_td2_hg_rh_sw_dump 3802 * Purpose: 3803 * Displays Higig resilient hashing state maintained by software. 3804 * Parameters: 3805 * unit - Device unit number 3806 * Returns: 3807 * None 3808 */ 3809 void bcm_td2_hg_rh_sw_dump(int unit) 3810 { 3811 int i, j; 3812 3813 LOG_CLI((BSL_META_U(unit, 3814 "Higig Resilient Hashing Info -\n"))); 3815 3816 /* Print Higig RH flowset table usage */ 3817 LOG_CLI((BSL_META_U(unit, 3818 " Higig RH Flowset Table Blocks Used:"))); 3819 j = 0; 3820 for (i = 0; i < soc_mem_index_count(unit, RH_HGT_FLOWSETm) >> 6; i++) { 3821 if (_BCM_HG_RH_FLOWSET_BLOCK_USED_GET(unit, i)) { 3822 j++; 3823 if (j % 15 == 1) { 3824 LOG_CLI((BSL_META_U(unit, 3825 "\n "))); 3826 } 3827 LOG_CLI((BSL_META_U(unit, 3828 " %4d"), i)); 3829 } 3830 } 3831 LOG_CLI((BSL_META_U(unit, 3832 "\n"))); 3833 3834 return; 3835 } 3836 3837 /* 3838 * Function: 3839 * bcm_td2_lag_rh_sw_dump 3840 * Purpose: 3841 * Displays LAG resilient hashing state maintained by software. 3842 * Parameters: 3843 * unit - Device unit number 3844 * Returns: 3845 * None 3846 */ 3847 void bcm_td2_lag_rh_sw_dump(int unit) 3848 { 3849 int i, j; 3850 3851 LOG_CLI((BSL_META_U(unit, 3852 "LAG Resilient Hashing Info -\n"))); 3853 LOG_CLI((BSL_META_U(unit, 3854 " LAG RH Flowset Table Blocks Total: %d\n"), 3855 _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks)); 3856 3857 /* Print LAG RH flowset table usage */ 3858 LOG_CLI((BSL_META_U(unit, 3859 " LAG RH Flowset Table Blocks Used:"))); 3860 j = 0; 3861 for (i = 0; i < _td2_lag_rh_info[unit]->num_lag_rh_flowset_blocks; i++) { 3862 if (_BCM_LAG_RH_FLOWSET_BLOCK_USED_GET(unit, i)) { 3863 j++; 3864 if (j % 15 == 1) { 3865 LOG_CLI((BSL_META_U(unit, 3866 "\n "))); 3867 } 3868 LOG_CLI((BSL_META_U(unit, 3869 " %4d"), i)); 3870 } 3871 } 3872 LOG_CLI((BSL_META_U(unit, 3873 "\n"))); 3874 3875 return; 3876 } 3877 3878 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 3879 3880 #ifdef INCLUDE_L3 3881 3882 /* 3883 * Function: 3884 * bcm_td2_vp_lag_deinit 3885 * Purpose: 3886 * Deallocate internal data structures 3887 * Parameters: 3888 * unit - (IN) SOC unit number. 3889 * Returns: 3890 * BCM_E_xxx 3891 */ 3892 void 3893 bcm_td2_vp_lag_deinit(int unit) 3894 { 3895 if (_td2_vp_lag_info[unit]) { 3896 if (_td2_vp_lag_info[unit]->vp_lag_used_bitmap) { 3897 sal_free(_td2_vp_lag_info[unit]->vp_lag_used_bitmap); 3898 _td2_vp_lag_info[unit]->vp_lag_used_bitmap = NULL; 3899 } 3900 if (_td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap) { 3901 sal_free(_td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap); 3902 _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap = NULL; 3903 } 3904 if (_td2_vp_lag_info[unit]->group_info) { 3905 sal_free(_td2_vp_lag_info[unit]->group_info); 3906 _td2_vp_lag_info[unit]->group_info = NULL; 3907 } 3908 /* Destroy protection mutex. */ 3909 if (_td2_vp_lag_info[unit]->lock) { 3910 sal_mutex_destroy(_td2_vp_lag_info[unit]->lock); 3911 _td2_vp_lag_info[unit]->lock = NULL; 3912 } 3913 sal_free(_td2_vp_lag_info[unit]); 3914 _td2_vp_lag_info[unit] = NULL; 3915 } 3916 } 3917 3918 /* 3919 * Function: 3920 * bcm_td2_vp_lag_init 3921 * Purpose: 3922 * Initialize internal data structures 3923 * Parameters: 3924 * unit - (IN) SOC unit number. 3925 * Returns: 3926 * BCM_E_xxx 3927 */ 3928 int 3929 bcm_td2_vp_lag_init(int unit) 3930 { 3931 int rv = BCM_E_NONE; 3932 int egr_member_table_size; 3933 3934 bcm_td2_vp_lag_deinit(unit); 3935 3936 if (NULL == _td2_vp_lag_info[unit]) { 3937 _td2_vp_lag_info[unit] = sal_alloc(sizeof(_td2_vp_lag_info_t), 3938 "VP LAG info"); 3939 if (NULL == _td2_vp_lag_info[unit]) { 3940 bcm_td2_vp_lag_deinit(unit); 3941 return BCM_E_MEMORY; 3942 } 3943 } 3944 sal_memset(_td2_vp_lag_info[unit], 0, sizeof(_td2_vp_lag_info_t)); 3945 3946 /* Get maximum number of VP LAGs configured by user */ 3947 MAX_VP_LAGS(unit) = soc_property_get(unit, spn_MAX_VP_LAGS, 3948 soc_mem_index_count(unit, EGR_VPLAG_GROUPm)); 3949 if (0 == MAX_VP_LAGS(unit)) { 3950 /* User configured zero VP LAGS, nothing more to do. */ 3951 return BCM_E_NONE; 3952 } 3953 3954 /* Allocate a bitmap tracking which VP LAG IDs are used */ 3955 if (NULL == _td2_vp_lag_info[unit]->vp_lag_used_bitmap) { 3956 _td2_vp_lag_info[unit]->vp_lag_used_bitmap = 3957 sal_alloc(SHR_BITALLOCSIZE(MAX_VP_LAGS(unit)), "VP LAG used bitmap"); 3958 if (NULL == _td2_vp_lag_info[unit]->vp_lag_used_bitmap) { 3959 bcm_td2_vp_lag_deinit(unit); 3960 return BCM_E_MEMORY; 3961 } 3962 } 3963 sal_memset(_td2_vp_lag_info[unit]->vp_lag_used_bitmap, 0, 3964 SHR_BITALLOCSIZE(MAX_VP_LAGS(unit))); 3965 3966 /* Allocate a bitmap tracking which EGR_VPLAG_MEMBER table entries are used */ 3967 egr_member_table_size = soc_mem_index_count(unit, EGR_VPLAG_MEMBERm); 3968 if (NULL == _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap) { 3969 _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap = 3970 sal_alloc(SHR_BITALLOCSIZE(egr_member_table_size), 3971 "EGR_VPLAG_MEMBER table used bitmap"); 3972 if (NULL == _td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap) { 3973 bcm_td2_vp_lag_deinit(unit); 3974 return BCM_E_MEMORY; 3975 } 3976 } 3977 sal_memset(_td2_vp_lag_info[unit]->vp_lag_egr_member_bitmap, 0, 3978 SHR_BITALLOCSIZE(egr_member_table_size)); 3979 3980 3981 /* Allocate an array containing info for each VP LAG */ 3982 if (NULL == _td2_vp_lag_info[unit]->group_info) { 3983 _td2_vp_lag_info[unit]->group_info = sal_alloc 3984 (MAX_VP_LAGS(unit) * sizeof(_td2_vp_lag_group_t), 3985 "VP LAG group info array"); 3986 if (NULL == _td2_vp_lag_info[unit]->group_info) { 3987 bcm_td2_vp_lag_deinit(unit); 3988 return BCM_E_MEMORY; 3989 } 3990 } 3991 sal_memset(_td2_vp_lag_info[unit]->group_info, 0, 3992 MAX_VP_LAGS(unit) * sizeof(_td2_vp_lag_group_t)); 3993 3994 #if defined(BCM_RIOT_SUPPORT) || defined(BCM_MULTI_LEVEL_ECMP_SUPPORT) 3995 /* 3996 * In RioT flow, ECMP table is divided in half for overlay 3997 * and underlay. 3998 * first half is for overlay and second for underlay. 3999 * All the vp_lag ECMP groups will fall in underlay. 4000 * therefore, base_offset is added here to make sure 4001 * that all the vp_lag groups go to underlay space. 4002 */ 4003 if (soc_feature(unit, soc_feature_riot) || 4004 soc_feature(unit, soc_feature_multi_level_ecmp)) { 4005 int ecmp_group_count = 0; 4006 int l3_ecmp_level = soc_property_get(unit, spn_L3_ECMP_LEVELS, 1); 4007 if (l3_ecmp_level > BCMI_L3_ECMP_SINGLE_LEVEL) { 4008 #if defined(BCM_TRIDENT3_SUPPORT) 4009 if (SOC_IS_TRIDENT3X(unit)) { 4010 int num_banks = 0; 4011 int l3_ecmp_group_first_lkup_mem_size = soc_property_get(unit, spn_L3_ECMP_GROUP_FIRST_LKUP_MEM_SIZE, 0); 4012 num_banks = l3_ecmp_group_first_lkup_mem_size / BCMI_L3_ECMP_GROUP_PER_BANK(unit) + 4013 ((l3_ecmp_group_first_lkup_mem_size % BCMI_L3_ECMP_GROUP_PER_BANK(unit))?1:0); 4014 4015 _td2_vp_lag_info[unit]->base_ecmp_idx = num_banks * BCMI_L3_ECMP_GROUP_PER_BANK(unit); 4016 } 4017 4018 if (_td2_vp_lag_info[unit]->base_ecmp_idx == 0) 4019 #endif 4020 { 4021 if (SOC_MEM_IS_VALID(unit, L3_ECMP_COUNTm)) { 4022 ecmp_group_count = soc_mem_index_count(unit, L3_ECMP_COUNTm); 4023 } 4024 _td2_vp_lag_info[unit]->base_ecmp_idx = ecmp_group_count/2; 4025 } 4026 } 4027 } else 4028 #endif 4029 { 4030 _td2_vp_lag_info[unit]->base_ecmp_idx = 0; 4031 } 4032 4033 /* Create protection mutex. */ 4034 if (NULL == _td2_vp_lag_info[unit]->lock) { 4035 _td2_vp_lag_info[unit]->lock = sal_mutex_create("VP LAG mutex"); 4036 } 4037 return rv; 4038 } 4039 4040 /* 4041 * Function: 4042 * bcm_td2_vp_lag_info_get 4043 * Purpose: 4044 * Get VP LAG info. 4045 * Parameters: 4046 * unit - SOC unit number 4047 * ngroups_vp_lag - (OUT) Number of VP LAGs 4048 * nports_vp_lag - (OUT) Maximum number of VPs per VP LAG 4049 * Returns: 4050 * BCM_E_xxx 4051 */ 4052 int 4053 bcm_td2_vp_lag_info_get(int unit, int *ngroups_vp_lag, int *nports_vp_lag) 4054 { 4055 VP_LAG_INIT_CHECK(unit); 4056 4057 *ngroups_vp_lag = MAX_VP_LAGS(unit); 4058 *nports_vp_lag = 1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, COUNTf); 4059 4060 return BCM_E_NONE; 4061 } 4062 4063 /* 4064 * Function: 4065 * _bcm_td2_tid_to_vp_lag_id 4066 * Purpose: 4067 * Convert trunk ID to VP LAG ID. 4068 * Parameters: 4069 * unit - SOC unit number 4070 * tid - Trunk ID 4071 * vp_lag_id - (OUT) VP LAG ID 4072 * Returns: 4073 * BCM_E_xxx 4074 */ 4075 STATIC int 4076 _bcm_td2_tid_to_vp_lag_id(int unit, bcm_trunk_t tid, int *vp_lag_id) 4077 { 4078 int vp_id_min = -1, vp_id_max = -1; 4079 4080 if (tid < 0) { 4081 return BCM_E_PARAM; 4082 } 4083 4084 BCM_IF_ERROR_RETURN( 4085 _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min, 4086 &vp_id_max, NULL)); 4087 4088 if (tid >= vp_id_min && tid <= vp_id_max) { 4089 *vp_lag_id = tid - vp_id_min; 4090 } else { 4091 return BCM_E_PARAM; 4092 } 4093 4094 return BCM_E_NONE; 4095 } 4096 4097 /* 4098 * Function: 4099 * bcm_td2_vp_lag_create 4100 * Purpose: 4101 * Create a VP LAG. 4102 * Parameters: 4103 * unit - SOC unit number 4104 * flags - Flags 4105 * tid - (IN/OUT) Trunk ID 4106 * Returns: 4107 * BCM_E_xxx 4108 */ 4109 int 4110 bcm_td2_vp_lag_create(int unit, uint32 flags, bcm_trunk_t *tid, 4111 bcm_gport_t *vplag_port_id) 4112 { 4113 int rv = BCM_E_NONE; 4114 int vp_lag_id = 0; 4115 int i; 4116 int vp; 4117 int vp_alloc_mode = 0; 4118 egr_vplag_group_entry_t egr_vplag_group_entry; 4119 ecmp_count_entry_t l3_ecmp_count_entry; 4120 initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry; 4121 ing_dvp_2_table_entry_t ing_dvp_2_entry; 4122 ing_dvp_table_entry_t ing_dvp_entry; 4123 source_vp_entry_t svp_entry; 4124 int cml_default_enable = 0, cml_default_new = 0, cml_default_move = 0; 4125 int vp_id_min = -1; 4126 _bcm_vp_info_t vp_info; 4127 4128 int ecmp_idx = 0; 4129 VP_LAG_INIT_CHECK(unit); 4130 4131 if (MAX_VP_LAGS(unit) == 0) { 4132 return BCM_E_FULL; 4133 } 4134 4135 if (flags & BCM_TRUNK_FLAG_WITH_ID) { 4136 BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, *tid, &vp_lag_id)); 4137 if (soc_feature(unit, soc_feature_reserve_vp_lag_resource_index_zero) && 4138 (0 == vp_lag_id)) { 4139 /* 4140 * EGR_VPLAG_GROUP 0 is reserved for passing LAG resolution 4141 * of DVP 0. 4142 */ 4143 return BCM_E_PARAM; 4144 } 4145 if (VP_LAG_USED_GET(unit, vp_lag_id)) { 4146 return BCM_E_EXISTS; 4147 } 4148 VP_LAG_USED_SET(unit, vp_lag_id); 4149 } else if (flags & BCM_TRUNK_FLAG_VP) { 4150 if (soc_feature(unit, soc_feature_reserve_vp_lag_resource_index_zero)) { 4151 /* 4152 * EGR_VPLAG_GROUP 0 is reserved for passing LAG resolution 4153 * of DVP 0. 4154 */ 4155 i = 1; 4156 } else { 4157 i = 0; 4158 } 4159 for (; i < MAX_VP_LAGS(unit); i++) { 4160 if (!VP_LAG_USED_GET(unit, i)) { 4161 vp_lag_id = i; 4162 VP_LAG_USED_SET(unit, i); 4163 break; 4164 } 4165 } 4166 if (i == MAX_VP_LAGS(unit)) { 4167 return BCM_E_FULL; 4168 } 4169 } else { 4170 return BCM_E_PARAM; 4171 } 4172 4173 /* In Trident2, VP LAGs and VPs share the same namespace. 4174 * A VP value needs to be allocated to represent a VP LAG, and this 4175 * VP value is not available to be used as a VP. 4176 */ 4177 vp_alloc_mode = soc_property_get(unit, spn_VPLAG_VP_ALLOC_MODE, 0); 4178 _bcm_vp_info_init(&vp_info); 4179 vp_info.vp_type = _bcmVpTypeVpLag; 4180 if ((flags & BCM_TRUNK_FLAG_WITH_VPLAG_ID) && (vplag_port_id != NULL)) { 4181 /* Cannot have both - vp allocation from bottom of SVP table and 4182 * also use the vp Id passed at same time */ 4183 if (vp_alloc_mode) { 4184 return BCM_E_PARAM; 4185 } 4186 vp = BCM_GPORT_VPLAG_PORT_ID_GET(*vplag_port_id); 4187 rv = _bcm_vp_alloc(unit, vp, vp, 1, SOURCE_VPm, vp_info, &vp); 4188 } else { 4189 if (vp_alloc_mode) { 4190 rv = _bcm_vp_alloc(unit, soc_mem_index_count(unit, SOURCE_VPm)-1, 4191 0, 1, SOURCE_VPm, vp_info, &vp); 4192 } else { 4193 rv = _bcm_vp_alloc(unit, 0, soc_mem_index_count(unit, SOURCE_VPm)-1, 4194 1, SOURCE_VPm, vp_info, &vp); 4195 } 4196 } 4197 if (BCM_FAILURE(rv)) { 4198 VP_LAG_USED_CLR(unit, vp_lag_id); 4199 return rv; 4200 } 4201 if (vplag_port_id != NULL) { 4202 BCM_GPORT_VPLAG_PORT_ID_SET(*vplag_port_id, vp); 4203 } 4204 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id = vp; 4205 4206 /* Configure SVP table */ 4207 sal_memset(&svp_entry, 0, sizeof(source_vp_entry_t)); 4208 /* Set the CML */ 4209 rv = _bcm_vp_default_cml_mode_get(unit, &cml_default_enable, 4210 &cml_default_new, &cml_default_move); 4211 if (BCM_FAILURE(rv)) { 4212 VP_LAG_USED_CLR(unit, vp_lag_id); 4213 (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp); 4214 return rv; 4215 } 4216 if (cml_default_enable) { 4217 /* Set the CML to default values */ 4218 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, 4219 cml_default_new); 4220 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, 4221 cml_default_move); 4222 } else { 4223 /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */ 4224 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, 0x8); 4225 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, 0x8); 4226 } 4227 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry); 4228 if (BCM_FAILURE(rv)) { 4229 VP_LAG_USED_CLR(unit, vp_lag_id); 4230 (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp); 4231 return rv; 4232 } 4233 4234 /* Trident2 supports up to 256 VP LAGs that are capable of performing 4235 * both unicast and multicast VP LAG resolution. Trident2 supports an 4236 * additional 768 VP LAGs that are capable of performing only unicast 4237 * VP LAG resolution. The VP LAG tables responsible for multicast 4238 * resolution are located in the egress pipeline; these tables 4239 * should be configured only for VP LAGs < 256. The VP LAGs tables 4240 * responsible for unicast resolution are located in the ingress 4241 * pipeline; these tables should be configured for all VP LAGs. 4242 */ 4243 4244 /* Configure EGR_VP_LAG_GROUP entry. Set base pointer and count 4245 * fields to all ones, indicating no members. 4246 */ 4247 if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) { 4248 SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id, 4249 &egr_vplag_group_entry)); 4250 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, 4251 DVP_LAG_IDf, vp); 4252 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, BASE_PTRf, 4253 (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, BASE_PTRf)) - 1); 4254 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, COUNTf, 4255 (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, COUNTf)) - 1); 4256 rv = WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL, vp_lag_id, 4257 &egr_vplag_group_entry); 4258 if (BCM_FAILURE(rv)) { 4259 VP_LAG_USED_CLR(unit, vp_lag_id); 4260 (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp); 4261 return rv; 4262 } 4263 } 4264 4265 /* Set base pointer and count fields in L3_ECMP_COUNT 4266 * to all ones, to indicate there are no members in this VP LAG. 4267 */ 4268 ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 4269 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx, 4270 &l3_ecmp_count_entry)); 4271 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf, 4272 (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, BASE_PTRf)) - 1); 4273 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf, 4274 (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, COUNTf)) - 1); 4275 rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx, 4276 &l3_ecmp_count_entry); 4277 if (BCM_FAILURE(rv)) { 4278 VP_LAG_USED_CLR(unit, vp_lag_id); 4279 (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp); 4280 return rv; 4281 } 4282 4283 /* Set base pointer and count fields in INITIAL_L3_ECMP_GROUP 4284 * to all ones, to indicate there are no members in this VP LAG. 4285 */ 4286 SOC_IF_ERROR_RETURN(READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY, 4287 ecmp_idx, &initial_l3_ecmp_group_entry)); 4288 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 4289 BASE_PTRf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm, 4290 BASE_PTRf)) - 1); 4291 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 4292 COUNTf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm, 4293 COUNTf)) - 1); 4294 rv = WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL, 4295 ecmp_idx, &initial_l3_ecmp_group_entry); 4296 if (BCM_FAILURE(rv)) { 4297 VP_LAG_USED_CLR(unit, vp_lag_id); 4298 (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp); 4299 return rv; 4300 } 4301 4302 /* Configure ING_DVP_2_TABLE */ 4303 SOC_IF_ERROR_RETURN(READ_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ANY, vp, 4304 &ing_dvp_2_entry)); 4305 soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry, 4306 ENABLE_VPLAG_RESOLUTIONf, 1); 4307 soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry, 4308 DVP_GROUP_PTRf, ecmp_idx); 4309 rv = WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL, vp, &ing_dvp_2_entry); 4310 if (BCM_FAILURE(rv)) { 4311 VP_LAG_USED_CLR(unit, vp_lag_id); 4312 (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp); 4313 return rv; 4314 } 4315 4316 /* Configure ING_DVP_TABLE */ 4317 SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, 4318 &ing_dvp_entry)); 4319 soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry, 4320 ENABLE_VPLAG_RESOLUTIONf, 1); 4321 soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry, 4322 DVP_GROUP_PTRf, ecmp_idx); 4323 rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &ing_dvp_entry); 4324 if (BCM_FAILURE(rv)) { 4325 VP_LAG_USED_CLR(unit, vp_lag_id); 4326 (void) _bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp); 4327 return rv; 4328 } 4329 4330 /* Convert VP LAG ID to trunk ID */ 4331 BCM_IF_ERROR_RETURN( 4332 _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min, 4333 NULL, NULL)); 4334 *tid = vp_lag_id + vp_id_min; 4335 4336 return BCM_E_NONE; 4337 } 4338 4339 /* 4340 * Function: 4341 * _bcm_td2_vp_lag_member_ingress_set 4342 * Purpose: 4343 * Set members of a VP LAG in ingress pipeline. 4344 * Parameters: 4345 * unit - SOC unit number. 4346 * vp_lag_id - VP LAG ID. 4347 * trunk_info - Information on the trunk group. 4348 * vp_count - Number of VPs. 4349 * vp_array - Array of VPs. 4350 * Returns: 4351 * BCM_E_XXX 4352 */ 4353 STATIC int 4354 _bcm_td2_vp_lag_member_ingress_set(int unit, int vp_lag_id, 4355 bcm_trunk_info_t *trunk_info, int vp_count, int *vp_array) 4356 { 4357 _bcm_l3_tbl_op_t tbl_op_data; 4358 int base_ptr; 4359 int i; 4360 ing_dvp_table_entry_t ing_dvp_entry; 4361 int next_hop_index; 4362 ecmp_entry_t l3_ecmp_entry; 4363 initial_l3_ecmp_entry_t initial_l3_ecmp_entry; 4364 ecmp_count_entry_t l3_ecmp_count_entry; 4365 int old_base_ptr, old_vp_count; 4366 initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry; 4367 int ecmp_idx = 0; 4368 #if defined(BCM_TOMAHAWK_SUPPORT) 4369 int ecmp_flag = 0; 4370 int hi_ecmp_mode = 0; 4371 int ecmp_ptr = -1; 4372 #endif 4373 int vp_type = 0, lag_vp = 0; 4374 ing_dvp_table_entry_t lag_ing_dvp_entry; 4375 ing_dvp_2_table_entry_t lag_ing_dvp_2_entry; 4376 int rv = BCM_E_NONE; 4377 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 4378 #if defined(BCM_TRIDENT3_SUPPORT) 4379 uint8 protected_ecmp = 0; 4380 uint32 alloc_sz = 0; 4381 soc_esw_ecmp_group_info_t grp_info = {0}; 4382 soc_esw_ecmp_member_info_t *mem_array = NULL; 4383 #endif /* BCM_TRIDENT3_SUPPORT */ 4384 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 4385 4386 /* Find a contiguous region of L3_ECMP table that's large 4387 * enough to hold all of the members. 4388 */ 4389 sal_memset(&tbl_op_data, 0, sizeof(_bcm_l3_tbl_op_t)); 4390 tbl_op_data.width = vp_count; 4391 tbl_op_data.tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp); 4392 tbl_op_data.oper_flags = _BCM_L3_SHR_TABLE_TRAVERSE_CONTROL; 4393 tbl_op_data.entry_index = -1; 4394 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 4395 #if defined(BCM_TRIDENT3_SUPPORT) 4396 if (soc_esw_ecmp_protected_enabled(unit)) { 4397 protected_ecmp = 1; 4398 SOC_ESW_ECMP_LOCK(unit); 4399 rv = bcm_td3x_l3_ecmp_free_idx_get(unit, 4400 socEswEcmpBankLkupLevelUnderlay, 4401 vp_count, 4402 &tbl_op_data.entry_index); 4403 if (BCM_FAILURE(rv)) { 4404 goto exit; 4405 } 4406 4407 alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t)); 4408 mem_array = sal_alloc(alloc_sz, "NH array"); 4409 if (NULL == mem_array) { 4410 rv = BCM_E_MEMORY; 4411 goto exit; 4412 } 4413 sal_memset(mem_array, 0, alloc_sz); 4414 } else 4415 #endif /* BCM_TRIDENT3_SUPPORT */ 4416 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 4417 { 4418 rv = _bcm_xgs3_tbl_free_idx_get(unit, &tbl_op_data); 4419 if (BCM_FAILURE(rv)) { 4420 goto exit; 4421 } 4422 } 4423 base_ptr = tbl_op_data.entry_index; 4424 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_op_data.tbl_ptr, base_ptr, vp_count); 4425 4426 /* Write members to L3_ECMP and INITIAL_L3_ECMP tables */ 4427 for (i = 0; i < vp_count; i++) { 4428 /* Get VP's next hop index */ 4429 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, 4430 vp_array[i], &ing_dvp_entry); 4431 if (BCM_FAILURE(rv)) { 4432 goto exit; 4433 } 4434 next_hop_index = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 4435 NEXT_HOP_INDEXf); 4436 #if defined(BCM_TOMAHAWK_SUPPORT) 4437 if (soc_feature(unit, soc_feature_hierarchical_ecmp) && 4438 (BCM_XGS3_L3_TBL(unit, ecmp_info).ecmp_mode == 4439 ecmp_mode_hierarchical)) { 4440 hi_ecmp_mode = 0; 4441 ecmp_flag = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 4442 ECMPf); 4443 if (ecmp_flag) { 4444 _bcm_l3_tbl_t *tbl_ptr = BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp); 4445 ecmp_ptr = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 4446 ECMP_PTRf); 4447 if (!BCM_XGS3_L3_ENT_REF_CNT(BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), 4448 ecmp_ptr)) { 4449 rv = BCM_E_NOT_FOUND; 4450 goto exit; 4451 } 4452 if (BCM_XGS3_L3_ECMP_GROUP_FLAGS_ISSET(unit, ecmp_ptr, 4453 BCM_L3_ECMP_OVERLAY)) { 4454 rv = BCM_E_PARAM; 4455 goto exit; 4456 } 4457 if (ecmp_ptr < (tbl_ptr->idx_max/2 + 1)) { 4458 rv = BCM_E_PARAM; 4459 goto exit; 4460 } 4461 hi_ecmp_mode = 1; 4462 next_hop_index = ecmp_ptr; 4463 } 4464 } 4465 #endif 4466 4467 if (i == 0 && (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan) || 4468 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre) || 4469 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow))) { 4470 vp_type = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 4471 VP_TYPEf); 4472 lag_vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id; 4473 4474 /* For Vxlan VP lag, inherit VP_TYPE from member, ortherwise DVP 4475 * cann't be passed to EPIPE. Assumed that all members has the same 4476 * vp_type. 4477 */ 4478 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, 4479 lag_vp, &lag_ing_dvp_entry); 4480 if (BCM_FAILURE(rv)) { 4481 goto exit; 4482 } 4483 soc_ING_DVP_TABLEm_field32_set(unit, &lag_ing_dvp_entry, 4484 VP_TYPEf, vp_type); 4485 rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, 4486 lag_vp, &lag_ing_dvp_entry); 4487 if (BCM_FAILURE(rv)) { 4488 goto exit; 4489 } 4490 rv = READ_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ANY, 4491 lag_vp, &lag_ing_dvp_2_entry); 4492 if (BCM_FAILURE(rv)) { 4493 goto exit; 4494 } 4495 soc_ING_DVP_2_TABLEm_field32_set(unit, &lag_ing_dvp_2_entry, 4496 VP_TYPEf, vp_type); 4497 rv = WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL, 4498 lag_vp, &lag_ing_dvp_2_entry); 4499 if (BCM_FAILURE(rv)) { 4500 goto exit; 4501 } 4502 } 4503 4504 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 4505 #if defined(BCM_TRIDENT3_SUPPORT) 4506 if (protected_ecmp == 1) { 4507 mem_array[i].nh = next_hop_index; 4508 mem_array[i].dvp = vp_array[i]; 4509 } else 4510 #endif /* BCM_TRIDENT3_SUPPORT */ 4511 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 4512 { 4513 /* Write L3_ECMP table */ 4514 sal_memset(&l3_ecmp_entry, 0, sizeof(l3_ecmp_entry)); 4515 soc_L3_ECMPm_field32_set(unit, &l3_ecmp_entry, DVPf, 4516 vp_array[i]); 4517 if (soc_feature(unit, soc_feature_generic_dest)) { 4518 #if defined(BCM_TOMAHAWK_SUPPORT) 4519 if (hi_ecmp_mode) { 4520 soc_mem_field32_dest_set(unit, L3_ECMPm, &l3_ecmp_entry, DESTINATIONf, 4521 SOC_MEM_FIF_DEST_ECMP, next_hop_index); 4522 } else { 4523 soc_mem_field32_dest_set(unit, L3_ECMPm, &l3_ecmp_entry, DESTINATIONf, 4524 SOC_MEM_FIF_DEST_NEXTHOP, next_hop_index); 4525 } 4526 #endif 4527 } else { 4528 soc_L3_ECMPm_field32_set(unit, &l3_ecmp_entry, NEXT_HOP_INDEXf, 4529 next_hop_index); 4530 #if defined(BCM_TOMAHAWK_SUPPORT) 4531 if (hi_ecmp_mode) { 4532 soc_L3_ECMPm_field32_set(unit, &l3_ecmp_entry, ECMP_FLAGf, 1); 4533 } 4534 #endif 4535 } 4536 rv = WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL, 4537 base_ptr + i, &l3_ecmp_entry); 4538 if (BCM_FAILURE(rv)) { 4539 goto exit; 4540 } 4541 4542 /* Write INITIAL_L3_ECMP table */ 4543 if (soc_feature(unit, soc_feature_generic_dest)) { 4544 sal_memset(&initial_l3_ecmp_entry, 0, sizeof(initial_l3_ecmp_entry)); 4545 #if defined(BCM_TOMAHAWK_SUPPORT) 4546 if (hi_ecmp_mode) { 4547 soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm, &initial_l3_ecmp_entry, DESTINATIONf, 4548 SOC_MEM_FIF_DEST_ECMP, next_hop_index); 4549 } else { 4550 soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm, &initial_l3_ecmp_entry, DESTINATIONf, 4551 SOC_MEM_FIF_DEST_NEXTHOP, next_hop_index); 4552 } 4553 #endif 4554 } else { 4555 sal_memset(&initial_l3_ecmp_entry, 0, sizeof(initial_l3_ecmp_entry)); 4556 soc_INITIAL_L3_ECMPm_field32_set(unit, &initial_l3_ecmp_entry, 4557 NEXT_HOP_INDEXf, next_hop_index); 4558 #if defined(BCM_TOMAHAWK_SUPPORT) 4559 if (hi_ecmp_mode) { 4560 soc_INITIAL_L3_ECMPm_field32_set(unit, &initial_l3_ecmp_entry, 4561 ECMP_FLAGf, 1); 4562 } 4563 #endif 4564 } 4565 rv = WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL, 4566 base_ptr + i, &initial_l3_ecmp_entry); 4567 if (BCM_FAILURE(rv)) { 4568 goto exit; 4569 } 4570 } 4571 } 4572 4573 ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 4574 4575 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 4576 #if defined(BCM_TRIDENT3_SUPPORT) 4577 if (protected_ecmp == 1) { 4578 grp_info.ecmp_grp = ecmp_idx; 4579 grp_info.ecmp_member_base = base_ptr; 4580 grp_info.max_paths = vp_count; 4581 grp_info.vp_lag = 1; 4582 rv = soc_esw_ecmp_protected_grp_add(unit, &grp_info, mem_array); 4583 if (BCM_FAILURE(rv)) { 4584 BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_op_data.tbl_ptr, base_ptr, vp_count); 4585 goto exit; 4586 } 4587 sal_free(mem_array); 4588 mem_array = NULL; 4589 if (base_ptr != grp_info.ecmp_member_base) { 4590 BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_op_data.tbl_ptr, base_ptr, vp_count); 4591 base_ptr = grp_info.ecmp_member_base; 4592 BCM_XGS3_L3_ENT_REF_CNT_INC(tbl_op_data.tbl_ptr, base_ptr, vp_count); 4593 } 4594 } 4595 #endif /* BCM_TRIDENT3_SUPPORT */ 4596 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 4597 4598 /* Write base pointer and counter to L3_ECMP_COUNT table */ 4599 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx, 4600 &l3_ecmp_count_entry); 4601 if (BCM_FAILURE(rv)) { 4602 goto exit; 4603 } 4604 old_base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, 4605 &l3_ecmp_count_entry, BASE_PTRf); 4606 old_vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit, 4607 &l3_ecmp_count_entry, COUNTf); 4608 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf, 4609 base_ptr); 4610 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf, 4611 vp_count - 1); 4612 rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx, 4613 &l3_ecmp_count_entry); 4614 if (BCM_FAILURE(rv)) { 4615 goto exit; 4616 } 4617 4618 /* Write base pointer and counter to INITIAL_L3_ECMP_GROUP table */ 4619 rv = READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY, 4620 ecmp_idx, &initial_l3_ecmp_group_entry); 4621 if (BCM_FAILURE(rv)) { 4622 goto exit; 4623 } 4624 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 4625 BASE_PTRf, base_ptr); 4626 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 4627 COUNTf, vp_count - 1); 4628 rv = WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL, 4629 ecmp_idx, &initial_l3_ecmp_group_entry); 4630 if (BCM_FAILURE(rv)) { 4631 goto exit; 4632 } 4633 4634 /* If VP LAG had members, free old entries in L3_ECMP and 4635 * INITIAL_L3_ECMP tables. 4636 */ 4637 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) { 4638 BCM_XGS3_L3_ENT_REF_CNT_DEC(tbl_op_data.tbl_ptr, old_base_ptr, 4639 old_vp_count); 4640 } 4641 4642 exit: 4643 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 4644 #if defined(BCM_TRIDENT3_SUPPORT) 4645 if (soc_esw_ecmp_protected_enabled(unit)) { 4646 if (mem_array != NULL) { 4647 sal_free(mem_array); 4648 } 4649 SOC_ESW_ECMP_UNLOCK(unit); 4650 } 4651 #endif 4652 #endif 4653 return rv; 4654 } 4655 4656 /* 4657 * Function: 4658 * _bcm_td2_vp_lag_member_egress_set 4659 * Purpose: 4660 * Set members of a VP LAG in egress pipeline. 4661 * Parameters: 4662 * unit - SOC unit number. 4663 * vp_lag_id - VP LAG ID. 4664 * trunk_info - Information on the trunk group. 4665 * vp_count - Number of VPs. 4666 * vp_array - Array of VPs. 4667 * Returns: 4668 * BCM_E_XXX 4669 */ 4670 STATIC int 4671 _bcm_td2_vp_lag_member_egress_set(int unit, int vp_lag_id, 4672 bcm_trunk_info_t *trunk_info, int vp_count, int *vp_array) 4673 { 4674 int num_entries; 4675 int max_base_ptr, base_ptr; 4676 SHR_BITDCL occupied; 4677 int i; 4678 egr_vplag_member_entry_t egr_member_entry; 4679 egr_vplag_group_entry_t egr_vplag_group_entry; 4680 egr_dvp_attribute_entry_t egr_dvp_attr_entry; 4681 int old_base_ptr, old_num_entries; 4682 4683 if (trunk_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) { 4684 /* Only one member of the VP LAG is eligible to receive non-unicast 4685 * traffic. 4686 */ 4687 if (trunk_info->dlf_index >= vp_count) { 4688 return BCM_E_PARAM; 4689 } 4690 num_entries = 1; 4691 } else { 4692 num_entries = vp_count; 4693 } 4694 4695 /* Find a contiguous region of EGR_VPLAG_MEMBER table that's large 4696 * enough to hold all of the members. 4697 */ 4698 max_base_ptr = soc_mem_index_count(unit, EGR_VPLAG_MEMBERm) - num_entries; 4699 if (soc_feature(unit, soc_feature_reserve_vp_lag_resource_index_zero)) { 4700 /* 4701 * EGR_VPLAG_MEMBER 0 is reserved for passing LAG resolution 4702 * of DVP 0. 4703 */ 4704 base_ptr = 1; 4705 } else { 4706 base_ptr = 0; 4707 } 4708 for (; base_ptr <= max_base_ptr; base_ptr++) { 4709 /* Check if the contiguous region from base_ptr to 4710 * (base_ptr + num_entries - 1) is free. 4711 */ 4712 VP_LAG_EGR_MEMBER_TEST_RANGE(unit, base_ptr, num_entries, occupied); 4713 if (!occupied) { 4714 break; 4715 } 4716 } 4717 if (base_ptr > max_base_ptr) { 4718 /* A contiguous region of the desired size could not be found. */ 4719 return BCM_E_RESOURCE; 4720 } 4721 4722 /* Write members to EGR_VPLAG_MEMBER table */ 4723 for (i = 0; i < num_entries; i++) { 4724 sal_memset(&egr_member_entry, 0, sizeof(egr_member_entry)); 4725 if (trunk_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) { 4726 soc_EGR_VPLAG_MEMBERm_field32_set(unit, &egr_member_entry, DVPf, 4727 vp_array[trunk_info->dlf_index]); 4728 } else { 4729 soc_EGR_VPLAG_MEMBERm_field32_set(unit, &egr_member_entry, DVPf, 4730 vp_array[i]); 4731 } 4732 SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_MEMBERm(unit, MEM_BLOCK_ALL, 4733 base_ptr + i, &egr_member_entry)); 4734 } 4735 4736 /* Set vp_lag_egr_member_bitmap */ 4737 VP_LAG_EGR_MEMBER_USED_SET_RANGE(unit, base_ptr, num_entries); 4738 4739 /* Write base pointer and count to EGR_VPLAG_GROUP table */ 4740 SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id, 4741 &egr_vplag_group_entry)); 4742 old_base_ptr = soc_EGR_VPLAG_GROUPm_field32_get(unit, 4743 &egr_vplag_group_entry, BASE_PTRf); 4744 old_num_entries = 1 + soc_EGR_VPLAG_GROUPm_field32_get(unit, 4745 &egr_vplag_group_entry, COUNTf); 4746 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, BASE_PTRf, 4747 base_ptr); 4748 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, COUNTf, 4749 num_entries - 1); 4750 SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL, vp_lag_id, 4751 &egr_vplag_group_entry)); 4752 4753 /* If VP LAG had members, free old entries in EGR_VPLAG_MEMBER table */ 4754 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) { 4755 VP_LAG_EGR_MEMBER_USED_CLR_RANGE(unit, old_base_ptr, old_num_entries); 4756 } 4757 4758 /* Configure EGR_DVP_ATTRIBUTE for each vp */ 4759 for (i = 0; i < vp_count; i++) { 4760 if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan) || 4761 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre) || 4762 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMpls) || 4763 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow)) { 4764 continue; 4765 } 4766 SOC_IF_ERROR_RETURN(READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, 4767 vp_array[i], &egr_dvp_attr_entry)); 4768 if (soc_mem_field_valid(unit, EGR_DVP_ATTRIBUTEm, DATA_TYPEf)) { 4769 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 4770 DATA_TYPEf, 0); 4771 } else { 4772 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 4773 VP_TYPEf, 0); 4774 } 4775 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 4776 COMMON__ENABLE_VPLAG_SRC_PRUNINGf, TRUE); 4777 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 4778 COMMON__ENABLE_VPLAG_RESOLUTIONf, TRUE); 4779 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 4780 COMMON__VPLAG_GROUP_PTRf, vp_lag_id); 4781 SOC_IF_ERROR_RETURN(WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL, 4782 vp_array[i], &egr_dvp_attr_entry)); 4783 } 4784 4785 return BCM_E_NONE; 4786 } 4787 4788 /* 4789 * Function: 4790 * _bcm_td2_vp_lag_member_check 4791 * Purpose: 4792 * Check if members of a VP LAG share the same properties. 4793 * Parameters: 4794 * unit - SOC unit number. 4795 * member_count - Number of members. 4796 * member_array - Array of members. 4797 * member_port_info - pointer to last member's port info. 4798 * Returns: 4799 * BCM_E_XXX 4800 */ 4801 STATIC int 4802 _bcm_td2_vp_lag_member_check(int unit, int member_count, 4803 bcm_trunk_member_t *member_array, void *member_port_info) 4804 { 4805 int rv = BCM_E_NONE, i; 4806 bcm_gport_t gport = 0; 4807 bcm_niv_port_t niv_port; 4808 bcm_niv_port_t *niv_port_info; 4809 uint16 match_service_tpid = 0, match_service_tpid_temp = 0; 4810 uint32 if_class = 0, if_class_temp = 0; 4811 4812 for (i = 0; i < member_count; i++) { 4813 gport = member_array[i].gport; 4814 4815 if (BCM_GPORT_IS_NIV_PORT(gport)) { 4816 sal_memset(&niv_port, 0, sizeof(niv_port)); 4817 niv_port.niv_port_id = gport; 4818 4819 rv = bcm_esw_niv_port_get(unit, &niv_port); 4820 if (BCM_FAILURE(rv)) { 4821 return rv; 4822 } 4823 4824 match_service_tpid_temp = niv_port.match_service_tpid; 4825 if_class_temp = niv_port.if_class; 4826 4827 if (i == 0) { 4828 match_service_tpid = match_service_tpid_temp; 4829 if_class = if_class_temp; 4830 } else { 4831 if ((match_service_tpid_temp != match_service_tpid) || 4832 (if_class_temp != if_class)) { 4833 return BCM_E_FAIL; 4834 } 4835 } 4836 } 4837 } 4838 4839 /*Save the member's port information*/ 4840 if (BCM_GPORT_IS_NIV_PORT(gport)) { 4841 niv_port_info = (bcm_niv_port_t *)member_port_info; 4842 if (niv_port_info != NULL) { 4843 sal_memcpy(niv_port_info, &niv_port, sizeof(niv_port)); 4844 } 4845 } 4846 4847 return rv; 4848 } 4849 4850 /* 4851 * Function: 4852 * _bcm_td2_vp_lag_member_set 4853 * Purpose: 4854 * Set members of a VP LAG. 4855 * Parameters: 4856 * unit - SOC unit number. 4857 * vp_lag_id - VP LAG ID. 4858 * trunk_info - Information on the trunk group. 4859 * member_count - Number of members. 4860 * member_array - Array of members. 4861 * Returns: 4862 * BCM_E_XXX 4863 * Notes: 4864 * The existing ports in the VP LAG will be replaced with new ones. 4865 */ 4866 STATIC int 4867 _bcm_td2_vp_lag_member_set(int unit, int vp_lag_id, 4868 bcm_trunk_info_t *trunk_info, int member_count, 4869 bcm_trunk_member_t *member_array) 4870 { 4871 int rv = BCM_E_NONE; 4872 bcm_gport_t *vp_array = NULL; 4873 int i, vp; 4874 int j; 4875 uint32 vfi = 0; 4876 uint32 network_port = 0; 4877 bcm_gport_t gport = 0; 4878 source_vp_entry_t svp_entry; 4879 source_vp_entry_t svp_entry1; 4880 uint32 network_group = 0; 4881 #if defined(CANCUN_SUPPORT) 4882 uint32 svp_profile_idx = 0; 4883 #endif 4884 int ent_tp_val = -1; 4885 4886 /* Convert member_array to vp_array. For each member, 4887 * convert its source VP into source VP LAG in hardware. 4888 */ 4889 vp_array = sal_alloc(member_count * sizeof(int), "VP array"); 4890 if (NULL == vp_array) { 4891 return BCM_E_MEMORY; 4892 } 4893 for (i = 0, j = 0; i < member_count; i++) { 4894 gport = member_array[i].gport; 4895 if (BCM_GPORT_IS_VLAN_PORT(gport)) { 4896 vp_array[j] = BCM_GPORT_VLAN_PORT_ID_GET(gport); 4897 } else if (BCM_GPORT_IS_NIV_PORT(gport)) { 4898 vp_array[j] = BCM_GPORT_NIV_PORT_ID_GET(gport); 4899 } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) { 4900 vp_array[j] = BCM_GPORT_EXTENDER_PORT_ID_GET(gport); 4901 } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) { 4902 vp_array[j] = BCM_GPORT_VXLAN_PORT_ID_GET(gport); 4903 } else if (BCM_GPORT_IS_MIM_PORT(gport)) { 4904 vp_array[j] = BCM_GPORT_MIM_PORT_ID_GET(gport); 4905 } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) { 4906 vp_array[j] = BCM_GPORT_L2GRE_PORT_ID_GET(gport); 4907 } else if (BCM_GPORT_IS_FLOW_PORT(gport)) { 4908 vp_array[j] = BCM_GPORT_FLOW_PORT_ID_GET(gport); 4909 } else if (BCM_GPORT_IS_MPLS_PORT(gport)) { 4910 vp_array[j] = BCM_GPORT_MPLS_PORT_ID_GET(gport); 4911 } else { 4912 sal_free(vp_array); 4913 return BCM_E_PARAM; 4914 } 4915 4916 if (!(member_array[i].flags & BCM_TRUNK_MEMBER_EGRESS_DISABLE)) { 4917 j++; /* number of member VPs to be programmed to egress. */ 4918 } 4919 } 4920 4921 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp_array[0], &svp_entry1); 4922 if (SOC_FAILURE(rv)) { 4923 sal_free(vp_array); 4924 return rv; 4925 } 4926 vfi = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, VFIf); 4927 if (soc_mem_field_valid(unit, SOURCE_VPm, NETWORK_PORTf)) { 4928 network_port = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, NETWORK_PORTf); 4929 } 4930 if (soc_feature(unit, soc_feature_multiple_split_horizon_group)) { 4931 network_group = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, NETWORK_GROUPf); 4932 } 4933 #if defined(CANCUN_SUPPORT) 4934 if (soc_mem_field_valid(unit, SOURCE_VPm, SVP_PROFILE_INDEXf)) { 4935 svp_profile_idx = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, SVP_PROFILE_INDEXf); 4936 } 4937 #endif 4938 4939 /* According to the member type, set some default value for vp_lag svp */ 4940 vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id; 4941 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry); 4942 if (SOC_FAILURE(rv)) { 4943 sal_free(vp_array); 4944 return rv; 4945 } 4946 4947 if (BCM_GPORT_IS_EXTENDER_PORT(gport)) { 4948 ent_tp_val = 3; 4949 /* Set the TPID_SOURCE based on SGLP */ 4950 if (soc_mem_field_valid(unit, SOURCE_VPm, TPID_SOURCEf)) { 4951 soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_SOURCEf, 2); 4952 } 4953 } else if (BCM_GPORT_IS_NIV_PORT(gport)) { 4954 bcm_niv_port_t niv_port; 4955 int tpid_index, tpid_enable=0; 4956 4957 bcm_niv_port_t_init(&niv_port); 4958 rv = _bcm_td2_vp_lag_member_check(unit, member_count, member_array, (void *)&niv_port); 4959 if (SOC_FAILURE(rv)) { 4960 sal_free(vp_array); 4961 return rv; 4962 } 4963 4964 /* Set the SD-tag mode and TPID */ 4965 if (niv_port.match_service_tpid) { 4966 rv = _bcm_fb2_outer_tpid_entry_add(unit, niv_port.match_service_tpid, 4967 &tpid_index); 4968 if (SOC_FAILURE(rv)) { 4969 sal_free(vp_array); 4970 return rv; 4971 } 4972 4973 tpid_enable = 1 << tpid_index; 4974 4975 if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) { 4976 rv = soc_mem_field32_modify(unit, SVP_ATTRS_1m, vp, TPID_ENABLEf, 4977 tpid_enable); 4978 if (SOC_FAILURE(rv)) { 4979 sal_free(vp_array); 4980 return rv; 4981 } 4982 } 4983 4984 soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf, 4985 tpid_enable); 4986 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 1); 4987 } else { 4988 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0); 4989 } 4990 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CLASS_IDf, niv_port.if_class); 4991 ent_tp_val = 3; 4992 } else if (BCM_GPORT_IS_VXLAN_PORT(gport) || 4993 BCM_GPORT_IS_MPLS_PORT(gport)) { 4994 uint32 tpid_enable = 0; 4995 uint32 sd_tag_mode = 0; 4996 ent_tp_val = 1; 4997 4998 sd_tag_mode = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, SD_TAG_MODEf); 4999 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, sd_tag_mode); 5000 #if defined(BCM_TRIDENT3_SUPPORT) 5001 if (SOC_IS_TRIDENT3X(unit)) { 5002 uint32 svp1[SOC_MAX_MEM_WORDS]; 5003 uint32 svp2[SOC_MAX_MEM_WORDS]; 5004 rv = READ_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp_array[0], svp1); 5005 if (SOC_FAILURE(rv)) { 5006 sal_free(vp_array); 5007 return rv; 5008 } 5009 rv = READ_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp, svp2); 5010 if (SOC_FAILURE(rv)) { 5011 sal_free(vp_array); 5012 return rv; 5013 } 5014 soc_SVP_ATTRS_1m_field_get(unit, &svp1, TPID_ENABLEf, &tpid_enable); 5015 soc_SVP_ATTRS_1m_field_set(unit, &svp2, TPID_ENABLEf, &tpid_enable); 5016 rv = WRITE_SVP_ATTRS_1m(unit, MEM_BLOCK_ALL, vp, &svp2); 5017 if (SOC_FAILURE(rv)) { 5018 sal_free(vp_array); 5019 return rv; 5020 } 5021 } else 5022 #endif 5023 { 5024 tpid_enable = soc_SOURCE_VPm_field32_get(unit, &svp_entry1, TPID_ENABLEf); 5025 soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf, tpid_enable); 5026 } 5027 } else if (BCM_GPORT_IS_VLAN_PORT(gport)) { 5028 ent_tp_val = 3; 5029 } else if (BCM_GPORT_IS_MIM_PORT(gport)) { 5030 ent_tp_val = 1; 5031 } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) { 5032 ent_tp_val = 1; 5033 } else if (BCM_GPORT_IS_FLOW_PORT(gport)) { 5034 ent_tp_val = 1; 5035 } 5036 5037 if (ent_tp_val != -1) { 5038 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, ent_tp_val); 5039 } 5040 5041 soc_SOURCE_VPm_field32_set(unit, &svp_entry, VFIf, vfi); 5042 if (soc_mem_field_valid(unit, SOURCE_VPm, NETWORK_PORTf)) { 5043 soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_PORTf, network_port); 5044 } 5045 if (soc_feature(unit, soc_feature_multiple_split_horizon_group)) { 5046 soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_GROUPf, network_group); 5047 } 5048 5049 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry); 5050 if (BCM_FAILURE(rv)) { 5051 sal_free(vp_array); 5052 return rv; 5053 } 5054 5055 #if defined(CANCUN_SUPPORT) 5056 if (soc_feature(unit, soc_feature_cancun) && 5057 (ent_tp_val == 1 || ent_tp_val == 2) && 5058 svp_profile_idx != 0) { 5059 rv = soc_cancun_app_dest_entry_set(unit, SOURCE_VPm, 5060 vp, ENTRY_TYPEf, CANCUN_APP__SOURCE_VP__No_Control_Word, 5061 ent_tp_val); 5062 if (BCM_FAILURE(rv)) { 5063 LOG_ERROR(BSL_LS_BCM_TRUNK, 5064 (BSL_META_U(unit, 5065 "CANCUN_APP SVP set error, vp %d ent_ty_val %d\n"), 5066 vp, ent_tp_val)); 5067 } 5068 } 5069 #endif 5070 5071 /* Set members in egress pipeline for VP LAGs < 256 */ 5072 if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) { 5073 if (j > 0) { 5074 rv = _bcm_td2_vp_lag_member_egress_set(unit, vp_lag_id, trunk_info, 5075 j, vp_array); 5076 if (BCM_FAILURE(rv)) { 5077 sal_free(vp_array); 5078 return rv; 5079 } 5080 } 5081 } else { 5082 /* VP LAGs <= 256 can only be unicast-only VP LAGs */ 5083 if (trunk_info->dlf_index != BCM_TRUNK_UNSPEC_INDEX) { 5084 sal_free(vp_array); 5085 return BCM_E_PARAM; 5086 } 5087 } 5088 5089 if (j > 0) { 5090 rv = _bcm_td2_vp_lag_member_ingress_set(unit, vp_lag_id, trunk_info, 5091 j, vp_array); 5092 if (BCM_FAILURE(rv)) { 5093 sal_free(vp_array); 5094 return rv; 5095 } 5096 } 5097 5098 sal_free(vp_array); 5099 return rv; 5100 } 5101 5102 /* 5103 * Function: 5104 * _bcm_td2_vp_lag_member_ingress_clear 5105 * Purpose: 5106 * Clear members of a VP LAG in ingress pipeline. 5107 * Parameters: 5108 * unit - SOC unit number. 5109 * vp_lag_id - VP LAG ID. 5110 * Returns: 5111 * BCM_E_XXX 5112 */ 5113 STATIC int 5114 _bcm_td2_vp_lag_member_ingress_clear(int unit, int vp_lag_id) 5115 { 5116 initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry; 5117 ecmp_count_entry_t l3_ecmp_count_entry; 5118 int base_ptr, vp_count; 5119 int i; 5120 int ecmp_idx; 5121 5122 /* Set base pointer and count fields in INITIAL_L3_ECMP_GROUP 5123 * to all ones, to indicate that there are no members. 5124 */ 5125 ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 5126 SOC_IF_ERROR_RETURN(READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY, 5127 ecmp_idx, &initial_l3_ecmp_group_entry)); 5128 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 5129 BASE_PTRf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm, 5130 BASE_PTRf)) - 1); 5131 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 5132 COUNTf, (1 << soc_mem_field_length(unit, INITIAL_L3_ECMP_GROUPm, 5133 COUNTf)) - 1); 5134 SOC_IF_ERROR_RETURN(WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL, 5135 ecmp_idx, &initial_l3_ecmp_group_entry)); 5136 5137 /* Set base pointer and count fields in L3_ECMP_COUNT 5138 * to all ones, to indicate that there are no members. 5139 */ 5140 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx, 5141 &l3_ecmp_count_entry)); 5142 base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, 5143 BASE_PTRf); 5144 vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, 5145 COUNTf); 5146 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf, 5147 (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, BASE_PTRf)) - 1); 5148 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf, 5149 (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, COUNTf)) - 1); 5150 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx, 5151 &l3_ecmp_count_entry)); 5152 5153 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 5154 #if defined(BCM_TRIDENT3_SUPPORT) 5155 if (soc_esw_ecmp_protected_enabled(unit)) { 5156 int rv = BCM_E_NONE; 5157 soc_esw_ecmp_group_info_t grp_info = {0}; 5158 5159 SOC_ESW_ECMP_LOCK(unit); 5160 5161 grp_info.ecmp_grp = ecmp_idx; 5162 rv = soc_esw_ecmp_protected_grp_delete(unit, &grp_info); 5163 if (BCM_FAILURE(rv)) { 5164 SOC_ESW_ECMP_UNLOCK(unit); 5165 return rv; 5166 } 5167 SOC_ESW_ECMP_UNLOCK(unit); 5168 } else 5169 #endif /* BCM_TRIDENT3_SUPPORT */ 5170 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 5171 { 5172 /* Clear INITIAL_L3_ECMP and L3_ECMP entries */ 5173 for (i = 0; i < vp_count; i++) { 5174 SOC_IF_ERROR_RETURN( 5175 WRITE_INITIAL_L3_ECMPm(unit, MEM_BLOCK_ALL, 5176 base_ptr + i, 5177 soc_mem_entry_null(unit, 5178 INITIAL_L3_ECMPm))); 5179 SOC_IF_ERROR_RETURN( 5180 WRITE_L3_ECMPm(unit, MEM_BLOCK_ALL, 5181 base_ptr + i, 5182 soc_mem_entry_null(unit, 5183 L3_ECMPm))); 5184 } 5185 } 5186 5187 /* Decrement reference count of INITIAL_L3_ECMP and L3_ECMP entries */ 5188 BCM_XGS3_L3_ENT_REF_CNT_DEC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), base_ptr, 5189 vp_count); 5190 5191 return BCM_E_NONE; 5192 } 5193 5194 /* 5195 * Function: 5196 * _bcm_td2_vp_lag_member_egress_clear 5197 * Purpose: 5198 * Clear members of a VP LAG in egress pipeline. 5199 * Parameters: 5200 * unit - SOC unit number. 5201 * vp_lag_id - VP LAG ID. 5202 * vp_count - Number of elements in vp_array. 5203 * vp_array - Array of VPs in VP LAG. 5204 * Returns: 5205 * BCM_E_XXX 5206 */ 5207 STATIC int 5208 _bcm_td2_vp_lag_member_egress_clear(int unit, int vp_lag_id, 5209 int vp_count, int *vp_array) 5210 { 5211 int i; 5212 egr_dvp_attribute_entry_t egr_dvp_attr_entry; 5213 egr_vplag_group_entry_t egr_vplag_group_entry; 5214 int base_ptr, num_entries; 5215 5216 /* Clear EGR_DVP_ATTRIBUTE entry for each vp */ 5217 for (i = 0; i < vp_count; i++) { 5218 if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan) || 5219 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre) || 5220 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMpls) || 5221 _bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow)) { 5222 continue; 5223 } 5224 SOC_IF_ERROR_RETURN(READ_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ANY, 5225 vp_array[i], &egr_dvp_attr_entry)); 5226 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 5227 COMMON__ENABLE_VPLAG_SRC_PRUNINGf, FALSE); 5228 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 5229 COMMON__ENABLE_VPLAG_RESOLUTIONf, FALSE); 5230 soc_EGR_DVP_ATTRIBUTEm_field32_set(unit, &egr_dvp_attr_entry, 5231 COMMON__VPLAG_GROUP_PTRf, 0); 5232 SOC_IF_ERROR_RETURN(WRITE_EGR_DVP_ATTRIBUTEm(unit, MEM_BLOCK_ALL, 5233 vp_array[i], &egr_dvp_attr_entry)); 5234 } 5235 5236 /* Set base pointer and count fields in EGR_VPLAG_GROUP 5237 * to all ones, to indicate that there are no members. 5238 */ 5239 SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id, 5240 &egr_vplag_group_entry)); 5241 base_ptr = soc_EGR_VPLAG_GROUPm_field32_get(unit, 5242 &egr_vplag_group_entry, BASE_PTRf); 5243 num_entries = 1 + soc_EGR_VPLAG_GROUPm_field32_get(unit, 5244 &egr_vplag_group_entry, COUNTf); 5245 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, BASE_PTRf, 5246 (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, BASE_PTRf)) - 1); 5247 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, COUNTf, 5248 (1 << soc_mem_field_length(unit, EGR_VPLAG_GROUPm, COUNTf)) - 1); 5249 SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL, vp_lag_id, 5250 &egr_vplag_group_entry)); 5251 5252 /* Clear EGR_VPLAG_MEMBER entries */ 5253 for (i = 0; i < num_entries; i++) { 5254 SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_MEMBERm(unit, MEM_BLOCK_ALL, 5255 base_ptr + i, soc_mem_entry_null(unit, EGR_VPLAG_MEMBERm))); 5256 } 5257 5258 VP_LAG_EGR_MEMBER_USED_CLR_RANGE(unit, base_ptr, num_entries); 5259 5260 return BCM_E_NONE; 5261 } 5262 5263 /* 5264 * Function: 5265 * _bcm_td2_vp_lag_member_clear 5266 * Purpose: 5267 * Clear members of a VP LAG. 5268 * Parameters: 5269 * unit - SOC unit number. 5270 * vp_lag_id - VP LAG ID. 5271 * Returns: 5272 * BCM_E_XXX 5273 */ 5274 STATIC int 5275 _bcm_td2_vp_lag_member_clear(int unit, int vp_lag_id) 5276 { 5277 int rv = BCM_E_NONE; 5278 ecmp_entry_t l3_ecmp_entry; 5279 ecmp_count_entry_t l3_ecmp_count_entry; 5280 int base_ptr, vp_count; 5281 int *vp_array = NULL; 5282 int i, vp; 5283 bcm_gport_t gport = 0; 5284 source_vp_entry_t svp_entry; 5285 int ecmp_idx; 5286 int rv_2 = BCM_E_NONE; 5287 bcm_gport_t *egr_dis_vp; 5288 int num_egr_dis_vp; 5289 int protected_ecmp = 0; 5290 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 5291 #if defined(BCM_TRIDENT3_SUPPORT) 5292 uint32 alloc_sz = 0; 5293 soc_esw_ecmp_group_info_t grp_info = {0}; 5294 soc_esw_ecmp_member_info_t *mem_array = NULL; 5295 #endif /* BCM_TRIDENT3_SUPPORT */ 5296 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 5297 5298 /* Get VP LAG's members. For each member, convert its source VP LAG back 5299 * to source VP in hardware. 5300 */ 5301 ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 5302 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx, 5303 &l3_ecmp_count_entry)); 5304 base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, 5305 BASE_PTRf); 5306 vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, 5307 COUNTf); 5308 if (vp_count < 1) { 5309 return BCM_E_INTERNAL; 5310 } 5311 vp_array = sal_alloc(vp_count * sizeof(int), "VP array"); 5312 if (NULL == vp_array) { 5313 return BCM_E_MEMORY; 5314 } 5315 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 5316 #if defined(BCM_TRIDENT3_SUPPORT) 5317 if (soc_esw_ecmp_protected_enabled(unit)) { 5318 protected_ecmp = 1; 5319 alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t)); 5320 mem_array = sal_alloc(alloc_sz, "NH array"); 5321 if (NULL == mem_array) { 5322 sal_free(vp_array); 5323 return BCM_E_MEMORY; 5324 } 5325 5326 SOC_ESW_ECMP_LOCK(unit); 5327 sal_memset(mem_array, 0, alloc_sz); 5328 grp_info.ecmp_grp = ecmp_idx; 5329 grp_info.vp_lag = 1; 5330 rv = soc_esw_ecmp_protected_grp_get(unit, &grp_info, mem_array); 5331 if (BCM_FAILURE(rv)) { 5332 sal_free(vp_array); 5333 sal_free(mem_array); 5334 SOC_ESW_ECMP_UNLOCK(unit); 5335 return rv; 5336 } 5337 5338 SOC_ESW_ECMP_UNLOCK(unit); 5339 for (i= 0; i < vp_count; i++) { 5340 vp_array[i] = mem_array[i].dvp; 5341 } 5342 5343 sal_free(mem_array); 5344 } 5345 #endif /* BCM_TRIDENT3_SUPPORT */ 5346 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 5347 5348 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) { 5349 /* processing member VPs that are really programmed in H/W L3_ECMP table */ 5350 for (i = 0; i < vp_count; i++) { 5351 if (protected_ecmp == 0) { 5352 rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY, base_ptr + i, 5353 &l3_ecmp_entry); 5354 if (BCM_FAILURE(rv)) { 5355 sal_free(vp_array); 5356 return rv; 5357 } 5358 vp_array[i] = soc_L3_ECMPm_field32_get(unit, &l3_ecmp_entry, DVPf); 5359 } 5360 5361 /* Convert source VP LAG back to source VP in harware. */ 5362 if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVlan)) { 5363 BCM_GPORT_VLAN_PORT_ID_SET(gport, vp_array[i]); 5364 rv = _bcm_esw_vlan_port_source_vp_lag_clear(unit, gport, 5365 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5366 if (BCM_FAILURE(rv)) { 5367 sal_free(vp_array); 5368 return rv; 5369 } 5370 } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeNiv)) { 5371 BCM_GPORT_NIV_PORT_ID_SET(gport, vp_array[i]); 5372 rv = _bcm_esw_niv_port_source_vp_lag_clear(unit, gport, 5373 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5374 if (BCM_FAILURE(rv)) { 5375 sal_free(vp_array); 5376 return rv; 5377 } 5378 } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeExtender)) { 5379 BCM_GPORT_EXTENDER_PORT_ID_SET(gport, vp_array[i]); 5380 rv = _bcm_esw_extender_port_source_vp_lag_clear(unit, gport, 5381 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5382 if (BCM_FAILURE(rv)) { 5383 sal_free(vp_array); 5384 return rv; 5385 } 5386 } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeVxlan)) { 5387 BCM_GPORT_VXLAN_PORT_ID_SET(gport, vp_array[i]); 5388 rv = _bcm_esw_vxlan_port_source_vp_lag_clear(unit, gport, 5389 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5390 if (BCM_FAILURE(rv)) { 5391 sal_free(vp_array); 5392 return rv; 5393 } 5394 } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMim)) { 5395 BCM_GPORT_MIM_PORT_ID_SET(gport, vp_array[i]); 5396 rv = _bcm_esw_mim_port_source_vp_lag_clear(unit, gport, 5397 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5398 if (BCM_FAILURE(rv)) { 5399 sal_free(vp_array); 5400 return rv; 5401 } 5402 } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeL2Gre)) { 5403 BCM_GPORT_L2GRE_PORT_ID_SET(gport, vp_array[i]); 5404 rv = _bcm_esw_l2gre_port_source_vp_lag_clear( 5405 unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5406 if (BCM_FAILURE(rv)) { 5407 sal_free(vp_array); 5408 return rv; 5409 } 5410 } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeMpls)) { 5411 BCM_GPORT_MPLS_PORT_ID_SET(gport, vp_array[i]); 5412 rv = _bcm_esw_mpls_port_source_vp_lag_clear( 5413 unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5414 if (BCM_FAILURE(rv)) { 5415 sal_free(vp_array); 5416 return rv; 5417 } 5418 } else if (_bcm_vp_used_get(unit, vp_array[i], _bcmVpTypeFlow)) { 5419 BCM_GPORT_FLOW_PORT_ID_SET(gport, vp_array[i]); 5420 rv = _bcm_esw_flow_port_source_vp_lag_clear( 5421 unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5422 if (BCM_FAILURE(rv)) { 5423 sal_free(vp_array); 5424 return rv; 5425 } 5426 } else { 5427 /* in order to free vp lag when member has been deleted by mistake */ 5428 rv_2 = BCM_E_INTERNAL; 5429 continue; 5430 } 5431 } 5432 } 5433 /* 5434 * Member VPs with BCM_TRUNK_MEMBER_EGRESS_DISABLE are not programmed in H/W 5435 * L3 ECMP table, however, their VP mappings also need to be updated. 5436 */ 5437 egr_dis_vp = VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp; 5438 num_egr_dis_vp = VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp; 5439 for (i = 0; i < num_egr_dis_vp; i++) { 5440 gport = egr_dis_vp[i]; 5441 /* Convert source VP LAG back to source VP in harware. */ 5442 if (BCM_GPORT_IS_VLAN_PORT(gport)) { 5443 rv = _bcm_esw_vlan_port_source_vp_lag_clear(unit, gport, 5444 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5445 if (BCM_FAILURE(rv)) { 5446 sal_free(vp_array); 5447 return rv; 5448 } 5449 } else if (BCM_GPORT_IS_NIV_PORT(gport)) { 5450 rv = _bcm_esw_niv_port_source_vp_lag_clear(unit, gport, 5451 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5452 if (BCM_FAILURE(rv)) { 5453 sal_free(vp_array); 5454 return rv; 5455 } 5456 } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) { 5457 rv = _bcm_esw_extender_port_source_vp_lag_clear(unit, gport, 5458 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5459 if (BCM_FAILURE(rv)) { 5460 sal_free(vp_array); 5461 return rv; 5462 } 5463 } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) { 5464 rv = _bcm_esw_vxlan_port_source_vp_lag_clear(unit, gport, 5465 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5466 if (BCM_FAILURE(rv)) { 5467 sal_free(vp_array); 5468 return rv; 5469 } 5470 } else if (BCM_GPORT_IS_MIM_PORT(gport)) { 5471 rv = _bcm_esw_mim_port_source_vp_lag_clear(unit, gport, 5472 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5473 if (BCM_FAILURE(rv)) { 5474 sal_free(vp_array); 5475 return rv; 5476 } 5477 } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) { 5478 rv = _bcm_esw_l2gre_port_source_vp_lag_clear( 5479 unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5480 if (BCM_FAILURE(rv)) { 5481 sal_free(vp_array); 5482 return rv; 5483 } 5484 } else if (BCM_GPORT_IS_MPLS_PORT(gport)) { 5485 rv = _bcm_esw_mpls_port_source_vp_lag_clear( 5486 unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5487 if (BCM_FAILURE(rv)) { 5488 sal_free(vp_array); 5489 return rv; 5490 } 5491 } else if (BCM_GPORT_IS_FLOW_PORT(gport)) { 5492 rv = _bcm_esw_flow_port_source_vp_lag_clear( 5493 unit, gport, VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id); 5494 if (BCM_FAILURE(rv)) { 5495 sal_free(vp_array); 5496 return rv; 5497 } 5498 } else { 5499 /* in order to free vp lag when member has been deleted by mistake */ 5500 rv_2 = BCM_E_INTERNAL; 5501 continue; 5502 } 5503 } 5504 5505 /* According to the member type, clear some default value for vp_lag svp */ 5506 vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id; 5507 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry); 5508 if (SOC_FAILURE(rv)) { 5509 sal_free(vp_array); 5510 return rv; 5511 } 5512 5513 if (BCM_GPORT_IS_EXTENDER_PORT(gport)) { 5514 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5515 /* Set the TPID_SOURCE based on SGLP */ 5516 if (soc_mem_field_valid(unit, SOURCE_VPm, TPID_SOURCEf)) { 5517 soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_SOURCEf, 0); 5518 } 5519 } else if (BCM_GPORT_IS_NIV_PORT(gport)) { 5520 int tpid_enb_len; 5521 int old_tpid_enable, j; 5522 svp_attrs_1_entry_t sa1_ent; 5523 5524 sal_memset(&sa1_ent, 0, sizeof(sa1_ent)); 5525 if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) { 5526 rv = READ_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp, &sa1_ent); 5527 if (SOC_FAILURE(rv)) { 5528 sal_free(vp_array); 5529 return rv; 5530 } 5531 old_tpid_enable = soc_mem_field32_get(unit, SVP_ATTRS_1m, &sa1_ent, 5532 TPID_ENABLEf); 5533 tpid_enb_len = soc_mem_field_length(unit, SVP_ATTRS_1m, TPID_ENABLEf); 5534 soc_mem_field32_set(unit, SVP_ATTRS_1m, &sa1_ent, TPID_ENABLEf, 0); 5535 } else { 5536 old_tpid_enable = soc_SOURCE_VPm_field32_get(unit, &svp_entry, 5537 TPID_ENABLEf); 5538 tpid_enb_len = soc_mem_field_length(unit, SOURCE_VPm, TPID_ENABLEf); 5539 soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf, 0); 5540 } 5541 5542 if (old_tpid_enable) { 5543 for (j = 0; j < tpid_enb_len; j++) { 5544 if (old_tpid_enable & (1 << j)) { 5545 rv = _bcm_fb2_outer_tpid_entry_delete(unit, j); 5546 if (BCM_FAILURE(rv)) { 5547 sal_free(vp_array); 5548 return rv; 5549 } 5550 } 5551 } 5552 } 5553 5554 if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) { 5555 rv = WRITE_SVP_ATTRS_1m(unit, MEM_BLOCK_ALL, vp, &sa1_ent); 5556 if (BCM_FAILURE(rv)) { 5557 sal_free(vp_array); 5558 return rv; 5559 } 5560 } 5561 5562 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0); 5563 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CLASS_IDf, 0); 5564 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5565 } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) { 5566 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5567 } else if (BCM_GPORT_IS_VLAN_PORT(gport)) { 5568 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5569 } else if (BCM_GPORT_IS_MIM_PORT(gport)) { 5570 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5571 } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) { 5572 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5573 } else if (BCM_GPORT_IS_MPLS_PORT(gport)) { 5574 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5575 } else if (BCM_GPORT_IS_FLOW_PORT(gport)) { 5576 soc_SOURCE_VPm_field32_set(unit, &svp_entry, ENTRY_TYPEf, 0); 5577 } 5578 5579 #if defined(CANCUN_SUPPORT) 5580 if (soc_feature(unit, soc_feature_cancun)) { 5581 if (BCM_GPORT_IS_VXLAN_PORT(gport) || 5582 BCM_GPORT_IS_MIM_PORT(gport) || 5583 BCM_GPORT_IS_L2GRE_PORT(gport) || 5584 BCM_GPORT_IS_MPLS_PORT(gport) || 5585 BCM_GPORT_IS_FLOW_PORT(gport)) { 5586 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SVP_PROFILE_INDEXf, 0); 5587 } 5588 } 5589 #endif 5590 5591 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry); 5592 if (BCM_FAILURE(rv)) { 5593 sal_free(vp_array); 5594 return rv; 5595 } 5596 5597 /* clear L3_ECMP and EGR_VPLAG tables only when there are member VPs actually programmed */ 5598 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) { 5599 /* Clear members in ingress pipeline */ 5600 rv = _bcm_td2_vp_lag_member_ingress_clear(unit, vp_lag_id); 5601 if (BCM_FAILURE(rv)) { 5602 sal_free(vp_array); 5603 return rv; 5604 } 5605 5606 /* Clear members in egress pipeline for VP LAGs < 256 */ 5607 if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) { 5608 rv = _bcm_td2_vp_lag_member_egress_clear(unit, vp_lag_id, vp_count, 5609 vp_array); 5610 if (BCM_FAILURE(rv)) { 5611 sal_free(vp_array); 5612 return rv; 5613 } 5614 } 5615 } 5616 5617 sal_free(vp_array); 5618 if (rv_2 != BCM_E_NONE) { 5619 return rv_2; 5620 } 5621 return rv; 5622 } 5623 5624 /* 5625 * Function: 5626 * _bcm_td2_vp_lag_member_is_vfi_type 5627 * Purpose: 5628 * Finds out if member of VP-LAG is VFI type virtual port. 5629 * Parameters: 5630 * unit - SOC device unit number 5631 * tid - trunk id provided 5632 * vfi_type - TRUE for VFI type, otherwise FALSE 5633 * Returns: 5634 * BCM_E_XXX 5635 */ 5636 int 5637 _bcm_td2_vp_lag_member_is_vfi_type(int unit, bcm_trunk_t tid, 5638 int *vfi_type) 5639 { 5640 int rv = BCM_E_NONE; 5641 int vp; 5642 int vp_lag_id; 5643 int ecmp_idx; 5644 ecmp_entry_t l3_ecmp_entry; 5645 ecmp_count_entry_t l3_ecmp_count_entry; 5646 int base_ptr; 5647 5648 VP_LAG_INIT_CHECK(unit); 5649 5650 BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 5651 if (!VP_LAG_USED_GET(unit, vp_lag_id)) { 5652 return BCM_E_NOT_FOUND; 5653 } 5654 5655 /* Get first member of VP LAG and check VFI type */ 5656 ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 5657 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx, 5658 &l3_ecmp_count_entry)); 5659 base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, BASE_PTRf); 5660 5661 rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY, base_ptr , &l3_ecmp_entry); 5662 if (SOC_SUCCESS(rv)) { 5663 vp = soc_L3_ECMPm_field32_get(unit, &l3_ecmp_entry, DVPf); 5664 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan) 5665 || _bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre) 5666 || _bcm_vp_used_get(unit, vp, _bcmVpTypeMpls) 5667 || _bcm_vp_used_get(unit, vp, _bcmVpTypeMim)) { 5668 *vfi_type = TRUE; 5669 } 5670 } 5671 5672 return rv; 5673 } 5674 5675 /* 5676 * Function: 5677 * _bcm_td2_vp_lag_match_vp_set 5678 * Purpose: 5679 * Set match vp of a VP LAG. 5680 * Parameters: 5681 * unit - SOC unit number. 5682 * vp_lag_id - VP LAG ID. 5683 * member_count - Number of members. 5684 * member_array - Array of members. 5685 * Returns: 5686 * BCM_E_XXX 5687 */ 5688 int 5689 _bcm_td2_vp_lag_match_vp_set(int unit, int vp_lag_id, 5690 int member_count, bcm_trunk_member_t *member_array) 5691 { 5692 int i = 0; 5693 int rv = BCM_E_NONE; 5694 int vp_id = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id; 5695 bcm_gport_t gport = 0; 5696 5697 for (i = 0; i < member_count; i++) { 5698 gport = member_array[i].gport; 5699 if (BCM_GPORT_IS_VLAN_PORT(gport)) { 5700 rv = _bcm_esw_vlan_port_source_vp_lag_set(unit, gport, vp_id); 5701 if (BCM_FAILURE(rv)) { 5702 return rv; 5703 } 5704 } else if (BCM_GPORT_IS_NIV_PORT(gport)) { 5705 rv = _bcm_esw_niv_port_source_vp_lag_set(unit, gport, vp_id); 5706 if (BCM_FAILURE(rv)) { 5707 return rv; 5708 } 5709 } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) { 5710 rv = _bcm_esw_extender_port_source_vp_lag_set(unit, gport, vp_id); 5711 if (BCM_FAILURE(rv)) { 5712 return rv; 5713 } 5714 } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) { 5715 rv = _bcm_esw_vxlan_port_source_vp_lag_set(unit, gport, vp_id); 5716 if (BCM_FAILURE(rv)) { 5717 return rv; 5718 } 5719 } else if (BCM_GPORT_IS_MIM_PORT(gport)) { 5720 rv = _bcm_esw_mim_port_source_vp_lag_set(unit, gport, vp_id); 5721 if (BCM_FAILURE(rv)) { 5722 return rv; 5723 } 5724 } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) { 5725 rv = _bcm_esw_l2gre_port_source_vp_lag_set(unit, gport, vp_id); 5726 if (BCM_FAILURE(rv)) { 5727 return rv; 5728 } 5729 } else if (BCM_GPORT_IS_MPLS_PORT(gport)) { 5730 rv = _bcm_esw_mpls_port_source_vp_lag_set(unit, gport, vp_id); 5731 if (BCM_FAILURE(rv)) { 5732 return rv; 5733 } 5734 } else if (BCM_GPORT_IS_FLOW_PORT(gport)) { 5735 rv = _bcm_esw_flow_port_source_vp_lag_set(unit, gport, vp_id); 5736 if (BCM_FAILURE(rv)) { 5737 return rv; 5738 } 5739 } else { 5740 return BCM_E_PARAM; 5741 } 5742 } 5743 5744 return rv; 5745 } 5746 5747 /* 5748 * Function: 5749 * bcm_td2_vp_lag_set 5750 * Purpose: 5751 * Set properties and members of a VP LAG. 5752 * Parameters: 5753 * unit - SOC unit number. 5754 * tid - The trunk ID to be affected. 5755 * trunk_info - Information on the trunk group. 5756 * member_count - Number of members. 5757 * member_array - Array of members. 5758 * Returns: 5759 * BCM_E_XXX 5760 */ 5761 int 5762 bcm_td2_vp_lag_set(int unit, bcm_trunk_t tid, bcm_trunk_info_t *trunk_info, 5763 int member_count, bcm_trunk_member_t *member_array) 5764 { 5765 bcm_trunk_chip_info_t trunk_chip_info; 5766 int vp_lag_id; 5767 int i; 5768 bcm_gport_t gport; 5769 bcm_gport_t *egr_dis_vp = NULL; 5770 int num_egr_dis_vp = 0; 5771 int rv = BCM_E_NONE; 5772 5773 VP_LAG_INIT_CHECK(unit); 5774 5775 BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 5776 if (!VP_LAG_USED_GET(unit, vp_lag_id)) { 5777 return BCM_E_NOT_FOUND; 5778 } 5779 5780 if (NULL == trunk_info) { 5781 return BCM_E_PARAM; 5782 } 5783 if (trunk_info->psc != BCM_TRUNK_PSC_PORTFLOW) { 5784 /* Only RTAG7 is supported for VP LAG */ 5785 return BCM_E_PARAM; 5786 } 5787 if ((trunk_info->dlf_index != trunk_info->mc_index) || 5788 (trunk_info->dlf_index != trunk_info->ipmc_index)) { 5789 return BCM_E_PARAM; 5790 } 5791 if ((trunk_info->flags != 0) || 5792 (trunk_info->ipmc_psc != 0) || 5793 (trunk_info->dynamic_size != 0) || 5794 (trunk_info->dynamic_age != 0) || 5795 (trunk_info->dynamic_load_exponent != 0) || 5796 (trunk_info->dynamic_expected_load_exponent != 0)) { 5797 /* These fields should be zeroes */ 5798 return BCM_E_PARAM; 5799 } 5800 5801 BCM_IF_ERROR_RETURN(bcm_esw_trunk_chip_info_get(unit, &trunk_chip_info)); 5802 if (member_count > trunk_chip_info.vp_ports_max) { 5803 return BCM_E_PARAM; 5804 } else if (member_count > 0) { 5805 if (trunk_info->dlf_index >= member_count) { 5806 /* dlf_index out of range */ 5807 return BCM_E_PARAM; 5808 } 5809 if (NULL == member_array) { 5810 return BCM_E_PARAM; 5811 } 5812 } else { 5813 if (NULL != member_array) { 5814 return BCM_E_PARAM; 5815 } 5816 } 5817 5818 if (member_count > 0) { 5819 egr_dis_vp = (bcm_gport_t*)sal_alloc(sizeof(bcm_gport_t) * member_count, 5820 "VP LAG Member info"); 5821 if (egr_dis_vp == NULL) { 5822 rv = BCM_E_MEMORY; 5823 return rv; 5824 } 5825 sal_memset(egr_dis_vp, 0, sizeof(bcm_gport_t) * member_count); 5826 } 5827 5828 for (i = 0; i < member_count; i++) { 5829 gport = member_array[i].gport; 5830 if (!BCM_GPORT_IS_VLAN_PORT(gport) && 5831 !BCM_GPORT_IS_NIV_PORT(gport) && 5832 !BCM_GPORT_IS_EXTENDER_PORT(gport) && 5833 !BCM_GPORT_IS_VXLAN_PORT(gport) && 5834 !BCM_GPORT_IS_MIM_PORT(gport) && 5835 !BCM_GPORT_IS_L2GRE_PORT(gport) && 5836 !BCM_GPORT_IS_MPLS_PORT(gport) && 5837 !BCM_GPORT_IS_FLOW_PORT(gport)) { 5838 sal_free(egr_dis_vp); 5839 return BCM_E_PARAM; 5840 } 5841 5842 if (member_array[i].flags & BCM_TRUNK_MEMBER_EGRESS_DISABLE) { 5843 egr_dis_vp[num_egr_dis_vp++] = member_array[i].gport; 5844 } 5845 } 5846 5847 /* Clear existing members */ 5848 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member || 5849 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp) { 5850 rv = _bcm_td2_vp_lag_member_clear(unit, vp_lag_id); 5851 if (rv != BCM_E_NONE) { 5852 sal_free(egr_dis_vp); 5853 return rv; 5854 } 5855 VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = FALSE; 5856 if (VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp != NULL) { 5857 sal_free(VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp); 5858 } 5859 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = 0; 5860 } 5861 5862 /* Set new members */ 5863 if (member_count > 0) { 5864 rv = _bcm_td2_vp_lag_member_set(unit, vp_lag_id, 5865 trunk_info, member_count, member_array); 5866 if (rv != BCM_E_NONE) { 5867 sal_free(egr_dis_vp); 5868 return rv; 5869 } 5870 rv = _bcm_td2_vp_lag_match_vp_set(unit, vp_lag_id, 5871 member_count, member_array); 5872 if (rv != BCM_E_NONE) { 5873 sal_free(egr_dis_vp); 5874 return rv; 5875 } 5876 VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = 5877 (member_count - num_egr_dis_vp) ? TRUE:FALSE; 5878 } 5879 5880 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = trunk_info->dlf_index; 5881 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = num_egr_dis_vp; 5882 VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp = egr_dis_vp; 5883 5884 return BCM_E_NONE; 5885 } 5886 5887 /* 5888 * Function: 5889 * bcm_td2_vp_lag_destroy 5890 * Purpose: 5891 * Destroy a VP LAG. 5892 * Parameters: 5893 * unit - SOC unit number 5894 * tid - Trunk ID 5895 * Returns: 5896 * BCM_E_xxx 5897 */ 5898 int 5899 bcm_td2_vp_lag_destroy(int unit, bcm_trunk_t tid) 5900 { 5901 int vp_lag_id; 5902 int vp; 5903 ecmp_count_entry_t l3_ecmp_count_entry; 5904 initial_l3_ecmp_group_entry_t initial_l3_ecmp_group_entry; 5905 ing_dvp_table_entry_t ing_dvp_entry; 5906 ing_dvp_2_table_entry_t ing_dvp_2_entry; 5907 egr_vplag_group_entry_t egr_vplag_group_entry; 5908 source_vp_entry_t svp_entry; 5909 int ecmp_idx; 5910 int rv_2 = BCM_E_NONE; 5911 5912 VP_LAG_INIT_CHECK(unit); 5913 5914 BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 5915 if (!VP_LAG_USED_GET(unit, vp_lag_id)) { 5916 return BCM_E_NOT_FOUND; 5917 } 5918 5919 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member || 5920 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp) { 5921 rv_2 = _bcm_td2_vp_lag_member_clear(unit, vp_lag_id); 5922 VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = FALSE; 5923 if (VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp != NULL) { 5924 sal_free(VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp); 5925 } 5926 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = 0;; 5927 } 5928 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = 0; 5929 5930 /* Get the VP used to represent this VP LAG */ 5931 vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id; 5932 5933 /* Clear VP LAG info in SOURCE_VP */ 5934 SOC_IF_ERROR_RETURN(READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp_entry)); 5935 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_NEWf, 0x0); 5936 soc_SOURCE_VPm_field32_set(unit, &svp_entry, CML_FLAGS_MOVEf, 0x0); 5937 soc_SOURCE_VPm_field32_set(unit, &svp_entry, VFIf, 0x0); 5938 soc_SOURCE_VPm_field32_set(unit, &svp_entry, SD_TAG_MODEf, 0); 5939 if (soc_mem_field_valid(unit, SOURCE_VPm, NETWORK_PORTf)) { 5940 soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_PORTf, 0x0); 5941 } 5942 if (soc_feature(unit, soc_feature_multiple_split_horizon_group)) { 5943 soc_SOURCE_VPm_field32_set(unit, &svp_entry, NETWORK_GROUPf, 0x0); 5944 } 5945 if (soc_mem_field_valid(unit, SVP_ATTRS_1m, TPID_ENABLEf)) { 5946 svp_attrs_1_entry_t svp_attrs; 5947 sal_memset(&svp_attrs, 0, sizeof(svp_attrs)); 5948 SOC_IF_ERROR_RETURN( 5949 WRITE_SVP_ATTRS_1m(unit, MEM_BLOCK_ANY, vp, &svp_attrs)); 5950 } else if (soc_mem_field_valid(unit, SOURCE_VPm, TPID_ENABLEf)) { 5951 soc_SOURCE_VPm_field32_set(unit, &svp_entry, TPID_ENABLEf, 0); 5952 } 5953 5954 SOC_IF_ERROR_RETURN(WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp_entry)); 5955 5956 /* Clear VP LAG info in ING_DVP_TABLE */ 5957 SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp, 5958 &ing_dvp_entry)); 5959 soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry, 5960 ENABLE_VPLAG_RESOLUTIONf, 0); 5961 soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry, 5962 DVP_GROUP_PTRf, 0); 5963 soc_ING_DVP_TABLEm_field32_set(unit, &ing_dvp_entry, 5964 VP_TYPEf, 0); 5965 SOC_IF_ERROR_RETURN(WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, 5966 &ing_dvp_entry)); 5967 5968 /* Clear VP LAG info in ING_DVP_2_TABLE */ 5969 SOC_IF_ERROR_RETURN(READ_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ANY, vp, 5970 &ing_dvp_2_entry)); 5971 soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry, 5972 ENABLE_VPLAG_RESOLUTIONf, 0); 5973 soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry, 5974 DVP_GROUP_PTRf, 0); 5975 soc_ING_DVP_2_TABLEm_field32_set(unit, &ing_dvp_2_entry, 5976 VP_TYPEf, 0); 5977 SOC_IF_ERROR_RETURN(WRITE_ING_DVP_2_TABLEm(unit, MEM_BLOCK_ALL, vp, 5978 &ing_dvp_2_entry)); 5979 5980 /* Clear VP LAG info in INITIAL_L3_ECMP_GROUP entry */ 5981 ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 5982 SOC_IF_ERROR_RETURN(READ_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ANY, 5983 ecmp_idx, &initial_l3_ecmp_group_entry)); 5984 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 5985 BASE_PTRf, 0); 5986 soc_INITIAL_L3_ECMP_GROUPm_field32_set(unit, &initial_l3_ecmp_group_entry, 5987 COUNTf, 0); 5988 SOC_IF_ERROR_RETURN(WRITE_INITIAL_L3_ECMP_GROUPm(unit, MEM_BLOCK_ALL, 5989 ecmp_idx, &initial_l3_ecmp_group_entry)); 5990 5991 /* Clear VP LAG info in L3_ECMP_COUNT entry */ 5992 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx, 5993 &l3_ecmp_count_entry)); 5994 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, BASE_PTRf, 0); 5995 soc_L3_ECMP_COUNTm_field32_set(unit, &l3_ecmp_count_entry, COUNTf, 0); 5996 SOC_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ALL, ecmp_idx, 5997 &l3_ecmp_count_entry)); 5998 5999 /* Clear VP LAG info in EGR_VPLAG_GROUP entry */ 6000 if (vp_lag_id < soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) { 6001 SOC_IF_ERROR_RETURN(READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, 6002 vp_lag_id, &egr_vplag_group_entry)); 6003 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, 6004 DVP_LAG_IDf, 0); 6005 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, 6006 BASE_PTRf, 0); 6007 soc_EGR_VPLAG_GROUPm_field32_set(unit, &egr_vplag_group_entry, 6008 COUNTf, 0); 6009 SOC_IF_ERROR_RETURN(WRITE_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ALL, 6010 vp_lag_id, &egr_vplag_group_entry)); 6011 } 6012 6013 /* Free the VP used to represent the VP LAG */ 6014 BCM_IF_ERROR_RETURN(_bcm_vp_free(unit, _bcmVpTypeVpLag, 1, vp)); 6015 6016 /* Free the VP LAG ID */ 6017 VP_LAG_USED_CLR(unit, vp_lag_id); 6018 6019 if (rv_2 != BCM_E_NONE) { 6020 return rv_2; 6021 } 6022 return BCM_E_NONE; 6023 } 6024 6025 /* 6026 * Function: 6027 * _bcm_td2_vp_lag_match_multi_get 6028 * Purpose: 6029 * Get all the matches for an existing vp lag. 6030 * Parameters: 6031 * unit - (IN) Unit number. 6032 * tid - (IN) Trunk Id 6033 * size - (IN) Number of elements in match array 6034 * match_array - (OUT) Match array 6035 * count - (OUT) Match count 6036 * Returns: 6037 * BCM_X_XXX 6038 */ 6039 int 6040 _bcm_td2_vp_lag_match_multi_get( 6041 int unit, 6042 bcm_trunk_t tid, 6043 int size, 6044 bcm_port_match_info_t *match_array, 6045 int *count) 6046 { 6047 int rv; 6048 int vp, tmp_vp; 6049 uint8 *vt_buf = NULL; /* VLAN_XLATE DMA buffer */ 6050 soc_mem_t mem = VLAN_XLATEm; 6051 int index, index_min, index_max, idx; 6052 bcm_trunk_member_t *member_array = NULL; 6053 int member_count; 6054 void *vent; 6055 uint32 *vent_member_array = NULL; 6056 int action; 6057 bcm_gport_t match_gport = 0, gport; 6058 int key_type_value, key_type; 6059 int cnt = 0; 6060 int alloc_size, ent_size; 6061 bcm_module_t mod_out, mod_in; 6062 bcm_port_t port_out, port_in; 6063 uint16 src_vif = 0; 6064 bcm_vlan_t match_vlan = BCM_VLAN_NONE; 6065 int matched = 0; 6066 int vp_lag_id; 6067 6068 if (soc_mem_is_valid(unit, VLAN_XLATE_1_DOUBLEm)) { 6069 mem = VLAN_XLATE_1_DOUBLEm; 6070 ent_size = sizeof(vlan_xlate_1_double_entry_t); 6071 } else { 6072 ent_size = sizeof(vlan_xlate_entry_t); 6073 } 6074 6075 /* Parameter checks */ 6076 if ((size < 0) || (count == NULL)) { 6077 return BCM_E_PARAM; 6078 } 6079 if ((size > 0) && (match_array == NULL)) { 6080 return BCM_E_PARAM; 6081 } 6082 6083 VP_LAG_INIT_CHECK(unit); 6084 6085 BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 6086 if (!VP_LAG_USED_GET(unit, vp_lag_id)) { 6087 return BCM_E_NOT_FOUND; 6088 } 6089 BCM_IF_ERROR_RETURN( 6090 _bcm_esw_trunk_tid_to_vp_lag_vp(unit, tid, &vp)); 6091 if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) { 6092 return BCM_E_NOT_FOUND; 6093 } 6094 6095 vt_buf = soc_cm_salloc(unit, SOC_MEM_TABLE_BYTES(unit, mem), 6096 "VLAN_XLATE buffer"); 6097 if (NULL == vt_buf) { 6098 return BCM_E_MEMORY; 6099 } 6100 index_min = soc_mem_index_min(unit, mem); 6101 index_max = soc_mem_index_max(unit, mem); 6102 6103 soc_mem_lock(unit, mem); 6104 if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 6105 index_min, index_max, vt_buf)) < 0) { 6106 goto cleanup; 6107 } 6108 rv = bcm_td2_vp_lag_get(unit, tid, NULL, 0, NULL, &member_count); 6109 if (BCM_FAILURE(rv)) { 6110 goto cleanup; 6111 } 6112 if (member_count > 0) { 6113 alloc_size = member_count * sizeof(bcm_trunk_member_t); 6114 member_array = sal_alloc(alloc_size, "vplag member array"); 6115 if (member_array == NULL) { 6116 rv = BCM_E_MEMORY; 6117 goto cleanup; 6118 } 6119 sal_memset(member_array, 0, alloc_size); 6120 rv = bcm_td2_vp_lag_get(unit, tid, NULL, member_count, 6121 member_array, &member_count); 6122 if (BCM_FAILURE(rv)) { 6123 goto cleanup; 6124 } 6125 alloc_size = member_count * ent_size; 6126 vent_member_array = sal_alloc(alloc_size, "extender port array"); 6127 if (vent_member_array == NULL) { 6128 rv = BCM_E_MEMORY; 6129 goto cleanup; 6130 } 6131 sal_memset(vent_member_array, 0, alloc_size); 6132 for (idx = 0; idx < member_count; idx++) { 6133 gport = member_array[idx].gport; 6134 if (BCM_GPORT_IS_EXTENDER_PORT(gport)) { 6135 rv = bcm_tr3_extender_match_key_get( 6136 unit, gport, (void *)&vent_member_array[idx]); 6137 if (BCM_FAILURE(rv)) { 6138 goto cleanup; 6139 } 6140 } else { 6141 rv = BCM_E_PORT; 6142 goto cleanup; 6143 } 6144 } 6145 } 6146 6147 cnt = 0; 6148 for (index = index_min; index <= index_max; index++) { 6149 int is_valid = 0; 6150 vent = soc_mem_table_idx_to_pointer( 6151 unit, mem, void *, vt_buf, index); 6152 6153 if (soc_feature(unit, soc_feature_base_valid)) { 6154 is_valid = soc_mem_field32_get(unit, mem, vent, BASE_VALID_0f) == 3 6155 && soc_mem_field32_get(unit, mem, vent, BASE_VALID_1f) == 7; 6156 } else { 6157 is_valid = soc_mem_field32_get(unit, mem, vent, VALIDf); 6158 } 6159 if (!is_valid) { 6160 continue; 6161 } 6162 action = soc_mem_field32_get(unit, mem, vent, VIF__MPLS_ACTIONf); 6163 if (action != 1) { 6164 continue; /* Entry is not for an SVP */ 6165 } 6166 tmp_vp = soc_mem_field32_get(unit, mem, vent, VIF__SOURCE_VPf); 6167 if (vp != tmp_vp) { 6168 continue; 6169 } 6170 6171 matched = 1; 6172 for (idx = 0; idx < member_count; idx++) { 6173 rv = _soc_mem_cmp_vlan_xlate_tr(unit, (void *)vent, 6174 (void *)&vent_member_array[idx]); 6175 /* 6176 * the key of vent is equl to the key of one entry of vp lag member. 6177 * So, this vent is not a matched entry. 6178 */ 6179 if (rv == 0) { 6180 matched = 0; 6181 break; 6182 } 6183 } 6184 if (!matched) { 6185 continue; 6186 } 6187 6188 if ((size > 0) && (size > cnt)) { 6189 key_type_value = (int)soc_mem_field32_get(unit, mem, vent, 6190 KEY_TYPEf); 6191 rv = _bcm_esw_vlan_xlate_key_type_get(unit, key_type_value, 6192 &key_type); 6193 if (BCM_FAILURE(rv)) { 6194 goto cleanup; 6195 } 6196 sal_memset(match_array, 0, sizeof(bcm_port_match_info_t)); 6197 match_array->match = BCM_PORT_MATCH_INVALID; 6198 switch(key_type) { 6199 case VLXLT_HASH_KEY_TYPE_VIF_VLAN: 6200 if (match_array->match == BCM_PORT_MATCH_INVALID) { 6201 match_array->match = 6202 BCM_PORT_MATCH_PORT_EXTENDED_PORT_VID_VLAN; 6203 match_vlan = soc_mem_field32_get(unit, mem, vent, 6204 VIF__VLANf); 6205 match_array->match_vlan = match_vlan; 6206 } 6207 case VLXLT_HASH_KEY_TYPE_VIF: 6208 if (match_array->match == BCM_PORT_MATCH_INVALID) { 6209 match_array->match = 6210 BCM_PORT_MATCH_PORT_EXTENDED_PORT_VID; 6211 match_array->match_vlan = BCM_VLAN_NONE; 6212 } 6213 6214 src_vif = soc_mem_field32_get(unit, mem, vent, 6215 VIF__SRC_VIFf); 6216 if (soc_mem_field32_get(unit, mem, vent, VIF__Tf)) { 6217 BCM_GPORT_TRUNK_SET( 6218 match_gport, 6219 soc_mem_field32_get(unit, mem, vent, VIF__TGIDf)); 6220 } else { 6221 mod_in = soc_mem_field32_get(unit, mem, vent, 6222 VIF__MODULE_IDf); 6223 port_in = soc_mem_field32_get(unit, mem, vent, 6224 VIF__PORT_NUMf); 6225 rv = _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 6226 mod_in,port_in, 6227 &mod_out, &port_out); 6228 BCM_GPORT_MODPORT_SET(match_gport, mod_out, port_out); 6229 } 6230 match_array->port = match_gport; 6231 match_array->extended_port_vid = src_vif; 6232 match_array++; 6233 break; 6234 default: 6235 rv = BCM_E_PARAM; 6236 goto cleanup; 6237 } 6238 } 6239 cnt++; 6240 } 6241 *count = cnt; 6242 cleanup: 6243 if (vt_buf != NULL) { 6244 soc_cm_sfree(unit, vt_buf); 6245 } 6246 if (member_array != NULL) { 6247 sal_free(member_array); 6248 } 6249 if (vent_member_array != NULL) { 6250 sal_free(vent_member_array); 6251 } 6252 soc_mem_unlock(unit, mem); 6253 return rv; 6254 } 6255 6256 /* 6257 * Function: 6258 * bcm_td2_vp_lag_get 6259 * Purpose: 6260 * Return information of given VP LAG. 6261 * Parameters: 6262 * unit - SOC unit number. 6263 * tid - Trunk ID. 6264 * trunk_info - (OUT) Place to store returned VP LAG info. 6265 * member_max - (IN) Size of member_array. 6266 * member_array - (OUT) Place to store returned VP LAG members. 6267 * member_count - (OUT) Place to store returned number of VP LAG members. 6268 * Returns: 6269 * BCM_E_XXX 6270 */ 6271 int 6272 bcm_td2_vp_lag_get(int unit, bcm_trunk_t tid, bcm_trunk_info_t *trunk_info, 6273 int member_max, bcm_trunk_member_t *member_array, int *member_count) 6274 { 6275 int vp_lag_id; 6276 ecmp_count_entry_t l3_ecmp_count_entry; 6277 ecmp_entry_t l3_ecmp_entry; 6278 int base_ptr, vp_count; 6279 int i; 6280 int vp; 6281 bcm_gport_t gport; 6282 int ecmp_idx; 6283 int rv = BCM_E_NONE; 6284 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 6285 #if defined(BCM_TRIDENT3_SUPPORT) 6286 uint8 protected_ecmp = 0; 6287 uint32 alloc_sz = 0; 6288 soc_esw_ecmp_group_info_t grp_info = {0}; 6289 soc_esw_ecmp_member_info_t *mem_array = NULL; 6290 #endif /* BCM_TRIDENT3_SUPPORT */ 6291 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 6292 6293 VP_LAG_INIT_CHECK(unit); 6294 6295 BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 6296 if (!VP_LAG_USED_GET(unit, vp_lag_id)) { 6297 return BCM_E_NOT_FOUND; 6298 } 6299 6300 if ((member_max > 0) && (NULL == member_array)) { 6301 return BCM_E_PARAM; 6302 } 6303 if ((member_max > 0) && (NULL == member_count)) { 6304 return BCM_E_PARAM; 6305 } 6306 6307 if (NULL != trunk_info) { 6308 bcm_trunk_info_t_init(trunk_info); 6309 trunk_info->psc = BCM_TRUNK_PSC_PORTFLOW; 6310 trunk_info->dlf_index = VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index; 6311 trunk_info->mc_index = VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index; 6312 trunk_info->ipmc_index = VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index; 6313 } 6314 6315 /* Get VP LAG members */ 6316 if ((VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) || 6317 (VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp)) { 6318 ecmp_idx = _td2_vp_lag_info[unit]->base_ecmp_idx + vp_lag_id; 6319 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) { 6320 SOC_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_idx, 6321 &l3_ecmp_count_entry)); 6322 base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, 6323 BASE_PTRf); 6324 vp_count = 1 + soc_L3_ECMP_COUNTm_field32_get(unit, &l3_ecmp_count_entry, 6325 COUNTf); 6326 if (vp_count < 1) { 6327 return BCM_E_INTERNAL; 6328 } 6329 } else { 6330 vp_count = 0; 6331 base_ptr = (1 << soc_mem_field_length(unit, L3_ECMP_COUNTm, BASE_PTRf)) - 1; 6332 } 6333 6334 if (member_max == 0) { 6335 if (NULL != member_count) { 6336 *member_count = vp_count + 6337 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp; 6338 } 6339 } else { 6340 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 6341 #if defined(BCM_TRIDENT3_SUPPORT) 6342 if (soc_esw_ecmp_protected_enabled(unit)) { 6343 protected_ecmp = 1; 6344 alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t)); 6345 mem_array = sal_alloc(alloc_sz, "NH array"); 6346 if (NULL == mem_array) { 6347 goto exit; 6348 } 6349 6350 SOC_ESW_ECMP_LOCK(unit); 6351 sal_memset(mem_array, 0, alloc_sz); 6352 grp_info.ecmp_grp = ecmp_idx; 6353 grp_info.vp_lag = 1; 6354 rv = soc_esw_ecmp_protected_grp_get(unit, &grp_info, mem_array); 6355 if (BCM_FAILURE(rv)) { 6356 SOC_ESW_ECMP_UNLOCK(unit); 6357 goto exit; 6358 } 6359 SOC_ESW_ECMP_UNLOCK(unit); 6360 } 6361 #endif /* BCM_TRIDENT3_SUPPORT */ 6362 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 6363 6364 *member_count = 0; 6365 for (i = 0; i < vp_count && i < member_max; i++) { 6366 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 6367 #if defined(BCM_TRIDENT3_SUPPORT) 6368 if (protected_ecmp == 1) { 6369 vp = mem_array[i].dvp; 6370 } else 6371 #endif /* BCM_TRIDENT3_SUPPORT */ 6372 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 6373 { 6374 rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY, 6375 base_ptr + i, &l3_ecmp_entry); 6376 if (BCM_FAILURE(rv)) { 6377 goto exit; 6378 } 6379 vp = soc_L3_ECMPm_field32_get(unit, &l3_ecmp_entry, DVPf); 6380 } 6381 6382 /* Derive VP's GPORT ID */ 6383 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVlan)) { 6384 BCM_GPORT_VLAN_PORT_ID_SET(gport, vp); 6385 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeNiv)) { 6386 BCM_GPORT_NIV_PORT_ID_SET(gport, vp); 6387 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeExtender)) { 6388 BCM_GPORT_EXTENDER_PORT_ID_SET(gport, vp); 6389 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeVxlan)) { 6390 BCM_GPORT_VXLAN_PORT_ID_SET(gport, vp); 6391 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMim)) { 6392 BCM_GPORT_MIM_PORT_ID_SET(gport, vp); 6393 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeL2Gre)) { 6394 BCM_GPORT_L2GRE_PORT_ID_SET(gport, vp); 6395 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeMpls)) { 6396 BCM_GPORT_MPLS_PORT_ID_SET(gport, vp); 6397 } else if (_bcm_vp_used_get(unit, vp, _bcmVpTypeFlow)) { 6398 BCM_GPORT_FLOW_PORT_ID_SET(gport, vp); 6399 } else { 6400 rv = BCM_E_INTERNAL; 6401 goto exit; 6402 } 6403 6404 bcm_trunk_member_t_init(&member_array[i]); 6405 member_array[i].gport = gport; 6406 (*member_count)++; 6407 } 6408 6409 /* retrieve member VPs which are not programmed to L3_ECMP table */ 6410 for (i = 0; i < VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp; i++) { 6411 if (*member_count >= member_max) { 6412 break; 6413 } 6414 bcm_trunk_member_t_init(&member_array[*member_count]); 6415 member_array[*member_count].gport 6416 = VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp[i]; 6417 member_array[*member_count].flags = BCM_TRUNK_MEMBER_EGRESS_DISABLE; 6418 (*member_count)++; 6419 } 6420 } 6421 } else { /* VP LAG has no members */ 6422 if (NULL != member_count) { 6423 *member_count = 0; 6424 } 6425 } 6426 6427 exit: 6428 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 6429 #if defined(BCM_TRIDENT3_SUPPORT) 6430 if (protected_ecmp == 1) { 6431 if (mem_array != NULL) { 6432 sal_free(mem_array); 6433 } 6434 } 6435 #endif /* BCM_TRIDENT3_SUPPORT */ 6436 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 6437 6438 return rv; 6439 } 6440 6441 /* 6442 * Function: 6443 * bcm_td2_vp_lag_find 6444 * Description: 6445 * Get trunk id that contains the given VP 6446 * Parameters: 6447 * unit - SOC unit number 6448 * gport - VP GPORT ID 6449 * tid - (OUT) Trunk id 6450 * Returns: 6451 * BCM_E_xxxx 6452 */ 6453 int 6454 bcm_td2_vp_lag_find(int unit, bcm_gport_t gport, bcm_trunk_t *tid) 6455 { 6456 int vp_lag_vp; 6457 ing_dvp_table_entry_t ing_dvp_entry; 6458 int vp_lag_valid; 6459 int vp_lag_id; 6460 int vp_id_min = -1; 6461 6462 VP_LAG_INIT_CHECK(unit); 6463 6464 if (!BCM_GPORT_IS_SET(gport)) { 6465 return BCM_E_PORT; 6466 } 6467 6468 /* Get the VP value representing VP LAG from VP's match entry, instead of 6469 * getting the VP LAG from EGR_DVP_ATTRIBUTE table, since only the 6470 * multicast capable VP LAGs can be retrieved from EGR_DVP_ATTRIBUTE. 6471 */ 6472 if (BCM_GPORT_IS_VLAN_PORT(gport)) { 6473 BCM_IF_ERROR_RETURN 6474 (_bcm_esw_vlan_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6475 } else if (BCM_GPORT_IS_NIV_PORT(gport)) { 6476 BCM_IF_ERROR_RETURN 6477 (_bcm_esw_niv_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6478 } else if (BCM_GPORT_IS_EXTENDER_PORT(gport)) { 6479 BCM_IF_ERROR_RETURN 6480 (_bcm_esw_extender_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6481 } else if (BCM_GPORT_IS_VXLAN_PORT(gport)) { 6482 BCM_IF_ERROR_RETURN 6483 (_bcm_esw_vxlan_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6484 } else if (BCM_GPORT_IS_MIM_PORT(gport)) { 6485 BCM_IF_ERROR_RETURN 6486 (_bcm_esw_mim_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6487 } else if (BCM_GPORT_IS_L2GRE_PORT(gport)) { 6488 BCM_IF_ERROR_RETURN( 6489 _bcm_esw_l2gre_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6490 } else if (BCM_GPORT_IS_MPLS_PORT(gport)) { 6491 BCM_IF_ERROR_RETURN( 6492 _bcm_esw_mpls_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6493 } else if (BCM_GPORT_IS_FLOW_PORT(gport)) { 6494 BCM_IF_ERROR_RETURN( 6495 _bcm_esw_flow_port_source_vp_lag_get(unit, gport, &vp_lag_vp)); 6496 } else { 6497 return BCM_E_PORT; 6498 } 6499 6500 /* Get VP LAG ID from ING_DVP_TABLE */ 6501 SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp_lag_vp, 6502 &ing_dvp_entry)); 6503 vp_lag_valid = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 6504 ENABLE_VPLAG_RESOLUTIONf); 6505 if (!vp_lag_valid) { 6506 return BCM_E_INTERNAL; 6507 } 6508 vp_lag_id = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 6509 DVP_GROUP_PTRf); 6510 vp_lag_id -= _td2_vp_lag_info[unit]->base_ecmp_idx; 6511 6512 /* Convert VP LAG ID to trunk ID */ 6513 BCM_IF_ERROR_RETURN( 6514 _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min, 6515 NULL, NULL)); 6516 *tid = vp_lag_id + vp_id_min; 6517 6518 return BCM_E_NONE; 6519 } 6520 6521 /* 6522 * Function: 6523 * bcm_td2_tid_to_vp_lag_vp 6524 * Purpose: 6525 * Convert trunk ID to the VP value representing VP LAG. 6526 * Parameters: 6527 * unit - SOC unit number 6528 * tid - Trunk ID 6529 * vp_lag_vp - (OUT) VP value 6530 * Returns: 6531 * BCM_E_xxx 6532 */ 6533 int 6534 bcm_td2_tid_to_vp_lag_vp(int unit, bcm_trunk_t tid, int *vp_lag_vp) 6535 { 6536 int vp_lag_id; 6537 6538 VP_LAG_INIT_CHECK(unit); 6539 6540 BCM_IF_ERROR_RETURN(_bcm_td2_tid_to_vp_lag_id(unit, tid, &vp_lag_id)); 6541 if (!VP_LAG_USED_GET(unit, vp_lag_id)) { 6542 return BCM_E_NOT_FOUND; 6543 } 6544 6545 *vp_lag_vp = VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id; 6546 6547 return BCM_E_NONE; 6548 } 6549 6550 /* 6551 * Function: 6552 * bcm_td2_vp_lag_vp_to_tid 6553 * Purpose: 6554 * Convert the VP value representing a VP LAG to trunk ID. 6555 * Parameters: 6556 * unit - SOC unit number 6557 * vp_lag_vp - VP value 6558 * tid - (OUT) Trunk ID 6559 * Returns: 6560 * BCM_E_xxx 6561 */ 6562 int 6563 bcm_td2_vp_lag_vp_to_tid(int unit, int vp_lag_vp, bcm_trunk_t *tid) 6564 { 6565 ing_dvp_table_entry_t ing_dvp_entry; 6566 int vp_lag_valid; 6567 int vp_lag_id; 6568 int vp_id_min = -1; 6569 6570 VP_LAG_INIT_CHECK(unit); 6571 6572 if (!_bcm_vp_used_get(unit, vp_lag_vp, _bcmVpTypeVpLag)) { 6573 return BCM_E_NOT_FOUND; 6574 } 6575 6576 /* Get VP LAG ID from ING_DVP_TABLE */ 6577 SOC_IF_ERROR_RETURN(READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ANY, vp_lag_vp, 6578 &ing_dvp_entry)); 6579 vp_lag_valid = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 6580 ENABLE_VPLAG_RESOLUTIONf); 6581 if (!vp_lag_valid) { 6582 return BCM_E_INTERNAL; 6583 } 6584 vp_lag_id = soc_ING_DVP_TABLEm_field32_get(unit, &ing_dvp_entry, 6585 DVP_GROUP_PTRf); 6586 vp_lag_id -= _td2_vp_lag_info[unit]->base_ecmp_idx; 6587 6588 /* Convert VP LAG ID to trunk ID */ 6589 BCM_IF_ERROR_RETURN( 6590 _bcm_esw_trunk_chip_info_vp_resource_get(unit, &vp_id_min, 6591 NULL, NULL)); 6592 *tid = vp_lag_id + vp_id_min; 6593 6594 return BCM_E_NONE; 6595 } 6596 6597 /* 6598 * Function: 6599 * bcm_td2_vp_lag_status_get 6600 * Purpose: 6601 * Get VP LAG status. 6602 * Parameters: 6603 * unit - SOC unit number 6604 * vp_lag_id - VP LAG ID 6605 * is_vp_lag - (OUT) Indicates if the given vp_lag_id is a valid VP LAG ID. 6606 * is_used - (OUT) Indicates if the given vp_lag_id is being used. 6607 * has_member - (OUT) Indicates if the given vp_lag_id has members. 6608 * Returns: 6609 * BCM_E_xxx 6610 */ 6611 int 6612 bcm_td2_vp_lag_status_get(int unit, int vp_lag_id, int *is_vp_lag, 6613 int *is_used, int *has_member) 6614 { 6615 if (NULL == is_vp_lag || NULL == is_used || NULL == has_member) { 6616 return BCM_E_PARAM; 6617 } 6618 6619 *is_vp_lag = FALSE; 6620 *is_used = FALSE; 6621 *has_member = FALSE; 6622 6623 if (vp_lag_id >= 0 && vp_lag_id < MAX_VP_LAGS(unit)) { 6624 *is_vp_lag = TRUE; 6625 if (VP_LAG_USED_GET(unit, vp_lag_id)) { 6626 *is_used = TRUE; 6627 if (VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) { 6628 *has_member = TRUE; 6629 } 6630 } 6631 } 6632 6633 return BCM_E_NONE; 6634 } 6635 6636 /* 6637 * Function: 6638 * _bcm_esw_num_vp_trunk_groups 6639 * Purpose: 6640 * Get Number of VP LAG groups supported. 6641 * Parameters: 6642 * unit - SOC unit number 6643 * Returns: 6644 * Number of VP LAG groups supported. 6645 */ 6646 int _bcm_esw_num_vp_trunk_groups(int unit) 6647 { 6648 return MAX_VP_LAGS(unit); 6649 } 6650 6651 /* 6652 * Function: 6653 * bcm_td2_vp_lag_port_learn_set 6654 * Purpose: 6655 * Set the CML bits for a vp_lag port. 6656 * Parameters: 6657 * unit - SOC unit number 6658 * tid - Trunk ID 6659 * flags - learning control flags 6660 * Returns: 6661 * BCM_E_XXX 6662 */ 6663 int 6664 bcm_td2_vp_lag_port_learn_set(int unit, bcm_trunk_t tid, uint32 flags) 6665 { 6666 int vp, cml = 0, rv = BCM_E_NONE; 6667 source_vp_entry_t svp; 6668 6669 cml = 0; 6670 if (!(flags & BCM_PORT_LEARN_FWD)) { 6671 cml |= (1 << 0); 6672 } 6673 if (flags & BCM_PORT_LEARN_CPU) { 6674 cml |= (1 << 1); 6675 } 6676 if (flags & BCM_PORT_LEARN_PENDING) { 6677 cml |= (1 << 2); 6678 } 6679 if (flags & BCM_PORT_LEARN_ARL) { 6680 cml |= (1 << 3); 6681 } 6682 6683 /* Get the VP index from the gport */ 6684 BCM_IF_ERROR_RETURN( 6685 bcm_td2_tid_to_vp_lag_vp(unit, tid, &vp)); 6686 6687 MEM_LOCK(unit, SOURCE_VPm); 6688 /* Be sure the entry is used and is set for Vp Lag */ 6689 if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) { 6690 MEM_UNLOCK(unit, SOURCE_VPm); 6691 return BCM_E_NOT_FOUND; 6692 } 6693 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp); 6694 if (rv < 0) { 6695 MEM_UNLOCK(unit, SOURCE_VPm); 6696 return rv; 6697 } 6698 6699 soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, cml); 6700 soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, cml); 6701 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp, &svp); 6702 MEM_UNLOCK(unit, SOURCE_VPm); 6703 return rv; 6704 } 6705 6706 /* 6707 * Function: 6708 * bcm_td2_vp_lag_port_learn_get 6709 * Purpose: 6710 * Get the CML bits for a VxLAN port 6711 * Parameters: 6712 * unit - SOC unit number 6713 * tid - Trunk ID 6714 * flags - learning control flags (OUT) 6715 * Returns: 6716 * BCM_E_XXX 6717 */ 6718 int 6719 bcm_td2_vp_lag_port_learn_get(int unit, bcm_trunk_t tid, uint32 *flags) 6720 { 6721 int rv, vp, cml = 0; 6722 source_vp_entry_t svp; 6723 6724 /* Get the VP index from the gport */ 6725 BCM_IF_ERROR_RETURN( 6726 bcm_td2_tid_to_vp_lag_vp(unit, tid, &vp)); 6727 6728 /* Be sure the entry is used and is set for VP Lag */ 6729 if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) { 6730 return BCM_E_NOT_FOUND; 6731 } 6732 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ANY, vp, &svp); 6733 if (rv < 0) { 6734 return rv; 6735 } 6736 6737 cml = soc_SOURCE_VPm_field32_get(unit, &svp, CML_FLAGS_NEWf); 6738 6739 *flags = 0; 6740 if (!(cml & (1 << 0))) { 6741 *flags |= BCM_PORT_LEARN_FWD; 6742 } 6743 if (cml & (1 << 1)) { 6744 *flags |= BCM_PORT_LEARN_CPU; 6745 } 6746 if (cml & (1 << 2)) { 6747 *flags |= BCM_PORT_LEARN_PENDING; 6748 } 6749 if (cml & (1 << 3)) { 6750 *flags |= BCM_PORT_LEARN_ARL; 6751 } 6752 return BCM_E_NONE; 6753 } 6754 6755 #ifdef BCM_WARM_BOOT_SUPPORT 6756 6757 /* 6758 * Function: 6759 * _bcm_td2_vp_lag_egr_dis_vp_scache_size_get 6760 * Purpose: 6761 * Get VP LAGs' egress disabled member VPs' software state size. 6762 * Parameters: 6763 * unit - (IN) SOC unit number. 6764 * size - (out) Number of bytes 6765 * Returns: 6766 * BCM_E_xxx 6767 */ 6768 int 6769 _bcm_td2_vp_lag_egr_dis_vp_scache_size_get(int unit, int *size) 6770 { 6771 int num_egr_dis_vp = 0; 6772 int i; 6773 6774 if (size == NULL) { 6775 return BCM_E_PARAM; 6776 } 6777 6778 /* num of egr_dis_vp for each VP LAG */ 6779 *size += MAX_VP_LAGS(unit) * sizeof(int); 6780 6781 for (i = 0; i < MAX_VP_LAGS(unit); i++) { 6782 /* space for egr_dis_vp list */ 6783 if (VP_LAG_USED_GET(unit, i)) { 6784 num_egr_dis_vp += VP_LAG_MEMBER_INFO(unit, i).num_egr_dis_vp; 6785 } 6786 } 6787 6788 *size += num_egr_dis_vp * sizeof(bcm_gport_t); 6789 6790 return BCM_E_NONE; 6791 } 6792 6793 /* 6794 * Function: 6795 * _bcm_td2_vp_lag_egr_dis_vp_scache_recover 6796 * Purpose: 6797 * Recover VP LAGs' egress disabled member VPs' state from scache. 6798 * Parameters: 6799 * unit - (IN) SOC unit number. 6800 * Returns: 6801 * BCM_E_xxx 6802 */ 6803 int 6804 _bcm_td2_vp_lag_egr_dis_vp_scache_recover(int unit, uint8 **scache_ptr) 6805 { 6806 int vp_lag_id; 6807 int num_egr_dis_vp; 6808 bcm_gport_t *egr_dis_vp; 6809 int i; 6810 6811 if (scache_ptr == NULL || *scache_ptr == NULL) { 6812 return BCM_E_PARAM; 6813 } 6814 6815 for (vp_lag_id = 0; vp_lag_id < MAX_VP_LAGS(unit); vp_lag_id++) { 6816 if (VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp != NULL) { 6817 sal_free(VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp); 6818 } 6819 6820 num_egr_dis_vp = *(int*)*scache_ptr; 6821 *scache_ptr += sizeof(int); 6822 VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp = num_egr_dis_vp; 6823 if (num_egr_dis_vp == 0) { 6824 VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp = NULL; 6825 continue; 6826 } 6827 6828 egr_dis_vp = sal_alloc(num_egr_dis_vp * sizeof(bcm_gport_t), 6829 "VP LAG egress disabled member VP"); 6830 if (egr_dis_vp == NULL) { 6831 return BCM_E_MEMORY; 6832 } 6833 VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp = egr_dis_vp; 6834 6835 /* recover egr_dis_vp list */ 6836 for (i = 0; i < num_egr_dis_vp; i++) { 6837 egr_dis_vp[i] = *(bcm_gport_t*)*scache_ptr; 6838 *scache_ptr += sizeof(bcm_gport_t); 6839 } 6840 } 6841 6842 return BCM_E_NONE; 6843 } 6844 6845 6846 /* 6847 * Function: 6848 * _bcm_td2_vp_lag_egr_dis_vp_sync 6849 * Purpose: 6850 * Record VP LAGs' egress disabled member VPs' state to scache. 6851 * Parameters: 6852 * unit - (IN) SOC unit number. 6853 * Returns: 6854 * BCM_E_xxx 6855 */ 6856 int 6857 _bcm_td2_vp_lag_egr_dis_vp_sync(int unit, uint8 **scache_ptr) 6858 { 6859 int vp_lag_id; 6860 int i; 6861 6862 if (scache_ptr == NULL || *scache_ptr == NULL) { 6863 return BCM_E_PARAM; 6864 } 6865 6866 for (vp_lag_id = 0; vp_lag_id < MAX_VP_LAGS(unit); vp_lag_id++) { 6867 *(int*)*scache_ptr = VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp; 6868 *scache_ptr += sizeof(int); 6869 6870 for (i = 0; i < VP_LAG_MEMBER_INFO(unit, vp_lag_id).num_egr_dis_vp; i++) { 6871 *(bcm_gport_t*)*scache_ptr = VP_LAG_MEMBER_INFO(unit, vp_lag_id).egr_dis_vp[i]; 6872 *scache_ptr += sizeof(bcm_gport_t); 6873 } 6874 } 6875 6876 return BCM_E_NONE; 6877 } 6878 6879 /* 6880 * Function: 6881 * bcm_td2_vp_lag_reinit 6882 * Purpose: 6883 * Recover VP LAG software state. 6884 * Parameters: 6885 * unit - (IN) SOC unit number. 6886 * Returns: 6887 * BCM_E_xxx 6888 */ 6889 int 6890 bcm_td2_vp_lag_reinit(int unit) 6891 { 6892 int rv = BCM_E_NONE; 6893 soc_mem_t mem; 6894 int entry_size; 6895 int chunk_size, num_chunks, chunk_index; 6896 int alloc_size; 6897 uint8 *buf = NULL; 6898 int i, j, entry_index_min, entry_index_max; 6899 uint32 *buf_entry; 6900 int vp_lag_id; 6901 int vp; 6902 int dvp; 6903 ecmp_count_entry_t l3_ecmp_count_entry; 6904 ecmp_entry_t l3_ecmp_entry; 6905 int base_ptr; 6906 int count_field; 6907 int vp_count; 6908 egr_vplag_member_entry_t egr_member_entry; 6909 egr_vplag_group_entry_t egr_vplag_group_entry; 6910 int egr_base_ptr; 6911 int egr_vp_count; 6912 int non_uc_member; 6913 int stable_size; 6914 _bcm_vp_info_t vp_info; 6915 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 6916 #if defined(BCM_TRIDENT3_SUPPORT) 6917 uint8 protected_ecmp = 0; 6918 uint32 alloc_sz = 0; 6919 soc_esw_ecmp_group_info_t grp_info = {0}; 6920 soc_esw_ecmp_member_info_t *mem_array = NULL; 6921 #endif /* BCM_TRIDENT3_SUPPORT */ 6922 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 6923 6924 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 6925 6926 /* Traverse ING_DVP_TABLE to find valid VP LAGs */ 6927 mem = ING_DVP_TABLEm; 6928 entry_size = sizeof(ing_dvp_table_entry_t); 6929 6930 chunk_size = 1024; 6931 num_chunks = soc_mem_index_count(unit, mem) / chunk_size; 6932 if (soc_mem_index_count(unit, mem) % chunk_size) { 6933 num_chunks++; 6934 } 6935 6936 alloc_size = entry_size * chunk_size; 6937 buf = soc_cm_salloc(unit, alloc_size, "ING_DVP_TABLE buffer"); 6938 if (NULL == buf) { 6939 rv = BCM_E_MEMORY; 6940 goto cleanup; 6941 } 6942 6943 for (chunk_index = 0; chunk_index < num_chunks; chunk_index++) { 6944 6945 /* Get a chunk of entries */ 6946 entry_index_min = chunk_index * chunk_size; 6947 entry_index_max = entry_index_min + chunk_size - 1; 6948 if (entry_index_max > soc_mem_index_max(unit, mem)) { 6949 entry_index_max = soc_mem_index_max(unit, mem); 6950 } 6951 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 6952 entry_index_min, entry_index_max, buf); 6953 if (SOC_FAILURE(rv)) { 6954 goto cleanup; 6955 } 6956 6957 /* Read each entry of the chunk to extract VP LAG info */ 6958 for (i = 0; i < (entry_index_max - entry_index_min + 1); i++) { 6959 buf_entry = soc_mem_table_idx_to_pointer(unit, 6960 mem, uint32 *, buf, i); 6961 if (soc_mem_field32_get(unit, mem, buf_entry, 6962 ENABLE_VPLAG_RESOLUTIONf) == 0) { 6963 continue; 6964 } 6965 vp_lag_id = soc_mem_field32_get(unit, mem, buf_entry, 6966 DVP_GROUP_PTRf); 6967 vp_lag_id -= _td2_vp_lag_info[unit]->base_ecmp_idx; 6968 if (vp_lag_id >= MAX_VP_LAGS(unit)) { 6969 /* The configuration property MAX_VP_LAGS was not 6970 * set correctly. 6971 */ 6972 rv = BCM_E_CONFIG; 6973 goto cleanup; 6974 } 6975 6976 /* Recover bitmap of VP LAG IDs */ 6977 VP_LAG_USED_SET(unit, vp_lag_id); 6978 6979 /* Recover VP LAG's VP value */ 6980 vp = entry_index_min + i; 6981 VP_LAG_GROUP_INFO(unit, vp_lag_id).vp_id = vp; 6982 if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) { 6983 _bcm_vp_info_init(&vp_info); 6984 vp_info.vp_type = _bcmVpTypeVpLag; 6985 rv = _bcm_vp_used_set(unit, vp, vp_info); 6986 if (BCM_FAILURE(rv)) { 6987 goto cleanup; 6988 } 6989 } else { 6990 /* In level 2 warm boot, the VP LAG VP bitmap should have been 6991 * recovered by virtual_init. 6992 */ 6993 if (!_bcm_vp_used_get(unit, vp, _bcmVpTypeVpLag)) { 6994 rv = BCM_E_INTERNAL; 6995 goto cleanup; 6996 } 6997 } 6998 6999 /* Recover if VP LAG has any members */ 7000 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, vp_lag_id, 7001 &l3_ecmp_count_entry); 7002 if (SOC_FAILURE(rv)) { 7003 goto cleanup; 7004 } 7005 base_ptr = soc_L3_ECMP_COUNTm_field32_get(unit, 7006 &l3_ecmp_count_entry, BASE_PTRf); 7007 count_field = soc_L3_ECMP_COUNTm_field32_get(unit, 7008 &l3_ecmp_count_entry, COUNTf); 7009 vp_count = count_field + 1; 7010 if (base_ptr == ((1 << soc_mem_field_length(unit, 7011 L3_ECMP_COUNTm, BASE_PTRf)) - 1) && 7012 count_field == ((1 << soc_mem_field_length(unit, 7013 L3_ECMP_COUNTm, COUNTf)) - 1)) { 7014 /* BASE_PTR and COUNT fields being all ones indicates 7015 * this VP LAG has no members. 7016 */ 7017 VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = FALSE; 7018 } else { 7019 VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member = TRUE; 7020 BCM_XGS3_L3_ENT_REF_CNT_INC(BCM_XGS3_L3_TBL_PTR(unit, ecmp), 7021 base_ptr, vp_count); 7022 } 7023 7024 if (!VP_LAG_GROUP_INFO(unit, vp_lag_id).has_member) { 7025 /* obviously no vp specified since H/W is empty */ 7026 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = 7027 BCM_TRUNK_UNSPEC_INDEX; 7028 continue; 7029 } 7030 7031 /* Recover non-unicast member index and bitmap of 7032 * used entries of EGR_VPLAG_MEMBER table 7033 */ 7034 if (vp_lag_id >= soc_mem_index_count(unit, EGR_VPLAG_GROUPm)) { 7035 /* VP LAG is unicast only */ 7036 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = 7037 BCM_TRUNK_UNSPEC_INDEX; 7038 } else { 7039 rv = READ_EGR_VPLAG_GROUPm(unit, MEM_BLOCK_ANY, vp_lag_id, 7040 &egr_vplag_group_entry); 7041 if (SOC_FAILURE(rv)) { 7042 goto cleanup; 7043 } 7044 egr_base_ptr = soc_EGR_VPLAG_GROUPm_field32_get(unit, 7045 &egr_vplag_group_entry, BASE_PTRf); 7046 egr_vp_count = 1 + soc_EGR_VPLAG_GROUPm_field32_get(unit, 7047 &egr_vplag_group_entry, COUNTf); 7048 VP_LAG_EGR_MEMBER_USED_SET_RANGE(unit, egr_base_ptr, 7049 egr_vp_count); 7050 if (egr_vp_count == 1 && vp_count > egr_vp_count) { 7051 rv = READ_EGR_VPLAG_MEMBERm(unit, MEM_BLOCK_ANY, 7052 egr_base_ptr, &egr_member_entry); 7053 if (SOC_FAILURE(rv)) { 7054 goto cleanup; 7055 } 7056 7057 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 7058 #if defined(BCM_TRIDENT3_SUPPORT) 7059 if (soc_esw_ecmp_protected_enabled(unit)) { 7060 protected_ecmp = 1; 7061 alloc_sz = (vp_count * sizeof(soc_esw_ecmp_member_info_t)); 7062 mem_array = sal_alloc(alloc_sz, "NH array"); 7063 if (NULL == mem_array) { 7064 goto cleanup; 7065 } 7066 7067 SOC_ESW_ECMP_LOCK(unit); 7068 sal_memset(mem_array, 0, alloc_sz); 7069 grp_info.ecmp_grp = vp_lag_id; 7070 grp_info.vp_lag = 1; 7071 rv = soc_esw_ecmp_protected_grp_get(unit, &grp_info, mem_array); 7072 if (BCM_FAILURE(rv)) { 7073 SOC_ESW_ECMP_UNLOCK(unit); 7074 goto cleanup; 7075 } 7076 SOC_ESW_ECMP_UNLOCK(unit); 7077 } 7078 #endif /* BCM_TRIDENT3_SUPPORT */ 7079 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 7080 7081 non_uc_member = soc_EGR_VPLAG_MEMBERm_field32_get(unit, 7082 &egr_member_entry, DVPf); 7083 for (j = 0; j < vp_count; j++) { 7084 7085 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 7086 #if defined(BCM_TRIDENT3_SUPPORT) 7087 if (protected_ecmp == 1) { 7088 dvp = mem_array[i].dvp; 7089 } else 7090 #endif /* BCM_TRIDENT3_SUPPORT */ 7091 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 7092 { 7093 rv = READ_L3_ECMPm(unit, MEM_BLOCK_ANY, base_ptr + j, 7094 &l3_ecmp_entry); 7095 if (SOC_FAILURE(rv)) { 7096 goto cleanup; 7097 } 7098 7099 dvp = soc_L3_ECMPm_field32_get(unit, 7100 &l3_ecmp_entry, DVPf); 7101 } 7102 if (non_uc_member == dvp) { 7103 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = j; 7104 break; 7105 } 7106 } 7107 if (j == vp_count) { 7108 /* non_uc_member not found */ 7109 rv = BCM_E_INTERNAL; 7110 goto cleanup; 7111 } 7112 } else { 7113 VP_LAG_GROUP_INFO(unit, vp_lag_id).non_uc_index = 7114 BCM_TRUNK_UNSPEC_INDEX; 7115 } 7116 } 7117 } 7118 } 7119 7120 cleanup: 7121 if (buf) { 7122 soc_cm_sfree(unit, buf); 7123 } 7124 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 7125 #if defined(BCM_TRIDENT3_SUPPORT) 7126 if (protected_ecmp == 1) { 7127 if (mem_array != NULL) { 7128 sal_free(mem_array); 7129 } 7130 } 7131 #endif /* BCM_TRIDENT3_SUPPORT */ 7132 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 7133 7134 return rv; 7135 } 7136 7137 #endif /* BCM_WARM_BOOT_SUPPORT */ 7138 7139 #ifndef BCM_SW_STATE_DUMP_DISABLE 7140 /* 7141 * Function: 7142 * bcm_td2_vp_lag_sw_dump 7143 * Purpose: 7144 * Displays VP LAG information maintained by software. 7145 * Parameters: 7146 * unit - SOC unit number 7147 * Returns: 7148 * None 7149 */ 7150 void 7151 bcm_td2_vp_lag_sw_dump(int unit) 7152 { 7153 bcm_trunk_chip_info_t trunk_chip_info; 7154 int i; 7155 int j; 7156 7157 LOG_CLI((BSL_META_U(unit, 7158 "VP LAG Information:\n"))); 7159 LOG_CLI((BSL_META_U(unit, 7160 " Max number of VP LAGs: %d\n"), MAX_VP_LAGS(unit))); 7161 7162 (void)bcm_esw_trunk_chip_info_get(unit, &trunk_chip_info); 7163 LOG_CLI((BSL_META_U(unit, 7164 " VP LAG trunk ID min: %d\n"), trunk_chip_info.vp_id_min)); 7165 LOG_CLI((BSL_META_U(unit, 7166 " VP LAG trunk ID max: %d\n"), trunk_chip_info.vp_id_max)); 7167 LOG_CLI((BSL_META_U(unit, 7168 " VP LAG max members: %d\n"), trunk_chip_info.vp_ports_max)); 7169 7170 for (i = 0; i < MAX_VP_LAGS(unit); i++) { 7171 if (VP_LAG_USED_GET(unit, i)) { 7172 LOG_CLI((BSL_META_U(unit, 7173 " VP LAG %d: vp_id = %d, "), i, 7174 VP_LAG_GROUP_INFO(unit, i).vp_id)); 7175 LOG_CLI((BSL_META_U(unit, 7176 "has_member = %d, "), 7177 VP_LAG_GROUP_INFO(unit, i).has_member)); 7178 LOG_CLI((BSL_META_U(unit, 7179 "num_egr_dis_vp = %d, "), 7180 VP_LAG_MEMBER_INFO(unit, i).num_egr_dis_vp)); 7181 LOG_CLI((BSL_META_U(unit, 7182 "non_uc_index = %d"), 7183 VP_LAG_GROUP_INFO(unit, i).non_uc_index)); 7184 for (j = 0; j < VP_LAG_MEMBER_INFO(unit, i).num_egr_dis_vp; j++) { 7185 LOG_CLI((BSL_META_U(unit, 7186 ", egr_dis_vp[%d] = %x"), j, 7187 VP_LAG_MEMBER_INFO(unit, i).egr_dis_vp[j])); 7188 } 7189 LOG_CLI((BSL_META_U(unit, "\n"))); 7190 7191 } 7192 } 7193 7194 return; 7195 } 7196 7197 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 7198 7199 /* 7200 * Function: 7201 * _bcm_esw_vplag_lock 7202 * Purpose: 7203 * Lock VPLAG - if module was not initialized NOOP 7204 * 7205 * Parameters: 7206 * unit - (IN) Unit number. 7207 * Returns: 7208 * BCM_E_XXX 7209 * Notes: 7210 */ 7211 int 7212 _bcm_esw_vplag_lock(int unit) 7213 { 7214 if ((NULL != _td2_vp_lag_info[unit]) && 7215 (NULL != _td2_vp_lag_info[unit]->lock)) { 7216 return sal_mutex_take(_td2_vp_lag_info[unit]->lock, 7217 sal_mutex_FOREVER); 7218 } 7219 return (BCM_E_NONE); 7220 } 7221 7222 /* 7223 * Function: 7224 * _bcm_esw_vplag_unlock 7225 * Purpose: 7226 * Unlock VPLAG - if module was not initialized NOOP 7227 * 7228 * Parameters: 7229 * unit - (IN) Unit number. 7230 * Returns: 7231 * BCM_E_XXX 7232 * Notes: 7233 */ 7234 int 7235 _bcm_esw_vplag_unlock(int unit) 7236 { 7237 if ((NULL != _td2_vp_lag_info[unit]) && 7238 (NULL != _td2_vp_lag_info[unit]->lock)) { 7239 return sal_mutex_give(_td2_vp_lag_info[unit]->lock); 7240 } 7241 return (BCM_E_NONE); 7242 } 7243 #endif /* INCLUDE_L3 */ 7244 7245 #endif /* BCM_TRIDENT2_SUPPORT */