l3.c (277895B)
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: l3.c 8 * Purpose: Tomahawk2 L3 function implementations 9 */ 10 11 #include <soc/defs.h> 12 #include <shared/bsl.h> 13 #if defined(INCLUDE_L3) && (defined(BCM_TOMAHAWK2_SUPPORT) || \ 14 defined(BCM_TOMAHAWK3_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT)) 15 #include <soc/drv.h> 16 #include <soc/tomahawk2.h> 17 #include <soc/profile_mem.h> 18 19 #include <bcm/vlan.h> 20 #include <bcm/error.h> 21 #include <bcm/l3.h> 22 #include <bcm/debug.h> 23 #include <bcm/error.h> 24 #include <bcm/stack.h> 25 26 #include <bcm_int/esw/firebolt.h> 27 #include <bcm_int/esw/stack.h> 28 #include <bcm_int/esw_dispatch.h> 29 #include <bcm_int/esw/tomahawk2.h> 30 #include <bcm_int/esw/tomahawk3.h> 31 32 _th2_ecmp_dlb_bookkeeping_t *_th2_ecmp_dlb_bk[BCM_MAX_NUM_UNITS]; 33 34 /* per ecmp group enhanced hashing enabled info */ 35 #ifdef BCM_TRIDENT3_SUPPORT 36 extern uint8 ecmp_grp_enhanced_hashing[BCM_MAX_NUM_UNITS][4096]; 37 #endif 38 #define ECMP_DLB_INFO(_unit_) (_th2_ecmp_dlb_bk[_unit_]) 39 #define ECMP_DLB_PORT_INFO(_unit_, _idx_) \ 40 (_th2_ecmp_dlb_bk[_unit_]->ecmp_dlb_port_info[_idx_]) 41 #define ECMP_DLB_PORT_LIST(_unit_, _idx_) \ 42 ECMP_DLB_PORT_INFO(unit, _idx_).port_membership_list 43 44 #define _BCM_ECMP_DLB_ID_USED_GET(_u_, _idx_) \ 45 SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_) 46 #define _BCM_ECMP_DLB_ID_USED_SET(_u_, _idx_) \ 47 SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_) 48 #define _BCM_ECMP_DLB_ID_USED_CLR(_u_, _idx_) \ 49 SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_used_bitmap, _idx_) 50 51 #define _BCM_ECMP_DLB_ID_DGM_GET(_u_, _idx_) \ 52 SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_dgm_bitmap, _idx_) 53 #define _BCM_ECMP_DLB_ID_DGM_SET(_u_, _idx_) \ 54 SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_dgm_bitmap, _idx_) 55 #define _BCM_ECMP_DLB_ID_DGM_CLR(_u_, _idx_) \ 56 SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_id_dgm_bitmap, _idx_) 57 58 59 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(_u_, _idx_) \ 60 SHR_BITGET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_) 61 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET(_u_, _idx_) \ 62 SHR_BITSET(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_) 63 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR(_u_, _idx_) \ 64 SHR_BITCLR(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_) 65 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(_u_, _idx_, _count_) \ 66 SHR_BITSET_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_) 67 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(_u_, _idx_, _count_) \ 68 SHR_BITCLR_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_) 69 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(_u_, _idx_, _count_, _result_) \ 70 SHR_BITTEST_RANGE(ECMP_DLB_INFO(_u_)->ecmp_dlb_flowset_block_bitmap, _idx_, _count_, _result_) 71 72 #define _BCM_ECMP_DLB_CELL_BYTES 208 73 #define _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT 8 74 #define _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR 10 75 #define _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT 100 76 #define _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT 0 77 78 79 80 /*----- ECMP DLB FUNCS ----- */ 81 82 83 /* 84 * Function: 85 * _bcm_th2_ecmp_dlb_quality_assign 86 * Purpose: 87 * Assign quality based on loading, total queue size and physical queue size. 88 * Parameters: 89 * unit - (IN) SOC unit number. 90 * tx_load_percent - (IN) Percent weight of loading in determing quality. 91 * qsize_percent - (IN) Percent weight of total queue size in determing 92 * quality. 93 * The remaining percentage is the weight of physical 94 * queue size. 95 * entry_arr - (IN) Array of 512 quality map table entries. 96 * Returns: 97 * BCM_X_XXX 98 */ 99 STATIC int 100 _bcm_th2_ecmp_dlb_quality_assign(int unit, int tx_load_percent, 101 int qsize_percent, uint32 *entry_arr) 102 { 103 int quantized_tx_load; 104 int quantized_qsize; 105 int quantized_physical_qsize; 106 int quality; 107 int entry_index; 108 int physical_qsize_percent = 100 - tx_load_percent - qsize_percent; 109 110 if (entry_arr == NULL) { 111 return BCM_E_PARAM; 112 } 113 114 #ifdef BCM_TRIDENT3_SUPPORT 115 if (SOC_IS_TRIDENT3X(unit)) { 116 for (quantized_tx_load = 0; quantized_tx_load < 8; quantized_tx_load++) { 117 for (quantized_qsize = 0; quantized_qsize < 8; quantized_qsize++) { 118 quality = (quantized_tx_load * tx_load_percent + 119 quantized_qsize * qsize_percent) / 100; 120 entry_index = (quantized_tx_load << 6) + 121 (quantized_qsize << 3); 122 soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_set(unit, 123 &entry_arr[entry_index], ASSIGNED_QUALITYf, quality); 124 } 125 } 126 } else 127 #endif 128 { 129 for (quantized_tx_load = 0; quantized_tx_load < 8; quantized_tx_load++) { 130 for (quantized_physical_qsize = 0; quantized_physical_qsize < 8; 131 quantized_physical_qsize++) { 132 for (quantized_qsize = 0; quantized_qsize < 8; quantized_qsize++) { 133 quality = (quantized_tx_load * tx_load_percent + 134 quantized_qsize * qsize_percent + 135 quantized_physical_qsize * physical_qsize_percent) / 136 100; 137 entry_index = (quantized_tx_load << 6) + 138 (quantized_physical_qsize << 3) + 139 quantized_qsize; 140 soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_set(unit, 141 &entry_arr[entry_index], ASSIGNED_QUALITYf, quality); 142 } 143 } 144 } 145 } 146 147 return BCM_E_NONE; 148 } 149 150 /* 151 * Function: 152 * _bcm_th2_ecmp_dlb_port_quality_map_set 153 * Purpose: 154 * Set per-member ECMP DLB quality mapping table. 155 * Parameters: 156 * unit - (IN) SOC unit number. 157 * port - (IN) Port, not Gport. 158 * tx_load_percent - (IN) Percent weight of loading in determing quality. 159 * qsize_percent - (IN) Percent weight of total queue size in determing 160 * quality. 161 * The remaining percentage is the weight of physical 162 * queue size. 163 * Returns: 164 * BCM_E_xxx 165 */ 166 STATIC int 167 _bcm_th2_ecmp_dlb_port_quality_map_set(int unit, int port, 168 int tx_load_percent, int qsize_percent) 169 { 170 soc_profile_mem_t *profile; 171 soc_mem_t mem; 172 int entry_bytes; 173 int entries_per_profile; 174 int alloc_size; 175 uint32 *entry_arr; 176 int rv = BCM_E_NONE; 177 void *entries; 178 uint32 base_index; 179 uint32 old_base_index; 180 dlb_ecmp_quantize_control_entry_t quantize_control_entry; 181 int num_quality_map_profiles; 182 183 profile = ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile; 184 num_quality_map_profiles = 1 << soc_mem_field_length(unit, 185 DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf); 186 entries_per_profile = 187 soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) / 188 num_quality_map_profiles; 189 190 entry_bytes = sizeof(dlb_ecmp_quality_mapping_entry_t); 191 alloc_size = entries_per_profile * entry_bytes; 192 entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries"); 193 if (entry_arr == NULL) { 194 return BCM_E_MEMORY; 195 } 196 sal_memset(entry_arr, 0, alloc_size); 197 198 /* Assign quality in the entry array */ 199 rv = _bcm_th2_ecmp_dlb_quality_assign(unit, tx_load_percent, 200 qsize_percent, entry_arr); 201 if (BCM_FAILURE(rv)) { 202 sal_free(entry_arr); 203 return rv; 204 } 205 206 mem = DLB_ECMP_PORT_QUALITY_MAPPINGm; 207 soc_mem_lock(unit, mem); 208 209 /* Add profile */ 210 entries = entry_arr; 211 rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile, 212 &base_index); 213 sal_free(entry_arr); 214 if (BCM_FAILURE(rv)) { 215 soc_mem_unlock(unit, mem); 216 return rv; 217 } 218 219 /* Update member profile pointer */ 220 rv = READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY, port, 221 &quantize_control_entry); 222 if (BCM_FAILURE(rv)) { 223 soc_mem_unlock(unit, mem); 224 return rv; 225 } 226 old_base_index = entries_per_profile * soc_mem_field32_get(unit, 227 DLB_ECMP_QUANTIZE_CONTROLm, &quantize_control_entry, 228 PORT_QUALITY_MAPPING_PROFILE_PTRf); 229 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, &quantize_control_entry, 230 PORT_QUALITY_MAPPING_PROFILE_PTRf, base_index / entries_per_profile); 231 rv = WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL, port, 232 &quantize_control_entry); 233 if (BCM_FAILURE(rv)) { 234 soc_mem_unlock(unit, mem); 235 return rv; 236 } 237 238 /* Delete old profile */ 239 rv = soc_profile_mem_delete(unit, profile, old_base_index); 240 soc_mem_unlock(unit, mem); 241 242 ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[base_index/entries_per_profile] = 243 tx_load_percent; 244 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[base_index/entries_per_profile] = 245 qsize_percent; 246 247 return rv; 248 } 249 250 /* 251 * Function: 252 * _bcm_th2_ecmp_dlb_scaling_factor_encode 253 * Purpose: 254 * Check valid scaling factors, and encode them. 255 * Parameters: 256 * unit - (IN) SOC unit number. 257 * scaling_factor - (IN) Threshold scaling factor. 258 * Returns: 259 * 1: check success 260 * 0: check fail 261 */ 262 STATIC int 263 _bcm_th2_ecmp_dlb_scaling_factor_encode(int unit, int scaling_factor, 264 int *scaling_factor_hw) 265 { 266 int bcm_factors[] = {10, 25, 40, 50, 75, 100}; 267 int hw_factors[] = { 0, 1, 2, 3, 4, 5}; 268 int i; 269 270 #if defined(BCM_TOMAHAWK3_SUPPORT) 271 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 272 return _bcm_th3_l3_ecmp_dlb_scaling_factor_encode(unit, scaling_factor, 273 scaling_factor_hw); 274 } 275 #endif 276 277 for (i = 0; i < COUNTOF(bcm_factors); i++ ) { 278 if (scaling_factor == bcm_factors[i]) { 279 break; 280 } 281 } 282 283 if (i < COUNTOF(hw_factors)) { 284 if (scaling_factor_hw) { 285 *scaling_factor_hw = hw_factors[i]; 286 } 287 return 1; 288 } 289 return 0; 290 } 291 292 293 /* 294 * Function: 295 * _bcm_th2_ecmp_dlb_scaling_factor_decode 296 * Purpose: 297 * Decode scaling factors. 298 * Parameters: 299 * unit - (IN) SOC unit number. 300 * scaling_factor - (IN) Threshold scaling factor. 301 * Returns: 302 * BCM_E_xxx 303 */ 304 STATIC int 305 _bcm_th2_ecmp_dlb_scaling_factor_decode(int unit, int scaling_factor_hw, 306 int *scaling_factor) 307 { 308 int bcm_factors[] = {10, 25, 40, 50, 75, 100}; 309 int hw_factors[] = { 0, 1, 2, 3, 4, 5}; 310 int i; 311 312 #if defined(BCM_TOMAHAWK3_SUPPORT) 313 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 314 return _bcm_th3_l3_ecmp_dlb_scaling_factor_decode(unit, scaling_factor_hw, 315 scaling_factor); 316 } 317 #endif 318 for (i = 0; i < COUNTOF(hw_factors); i++ ) { 319 if (scaling_factor_hw == hw_factors[i]) { 320 break; 321 } 322 } 323 324 if (i == COUNTOF(hw_factors)) { 325 return BCM_E_INTERNAL; 326 } 327 328 *scaling_factor = bcm_factors[i]; 329 return BCM_E_NONE; 330 } 331 332 333 /* 334 * Function: 335 * _bcm_th2_ecmp_dlb_port_attr_set 336 * Purpose: 337 * Set ECMP dynamic load balancing attributes for a member. 338 * Parameters: 339 * unit - (IN) SOC unit number. 340 * port - (IN) Port, not Gport. 341 * nh_index - (IN) Next hop index. 342 * scaling_factor - (IN) Threshold scaling factor. 343 * load_weight - (IN) Weighting of load in determining member quality. 344 * qsize_weight - (IN) Weighting of total qsize in determining member quality. 345 * Returns: 346 * BCM_E_XXX 347 */ 348 STATIC int 349 _bcm_th2_ecmp_dlb_port_attr_set(int unit, bcm_port_t port, 350 int scaling_factor, int load_weight, int qsize_weight) 351 { 352 dlb_ecmp_quantize_control_entry_t quantize_control_entry; 353 int scaling_factor_hw; 354 soc_field_t qsf_field = XPE_PORT_QSIZE_THRESHOLD_SCALING_FACTORf; 355 356 #if defined(BCM_TOMAHAWK3_SUPPORT) 357 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 358 qsf_field = ITM_PORT_QSIZE_THRESHOLD_SCALING_FACTORf; 359 } 360 #endif 361 362 /* Set load weight, qsize weight */ 363 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_port_quality_map_set(unit, 364 port, 365 load_weight, 366 qsize_weight)); 367 368 if (!_bcm_th2_ecmp_dlb_scaling_factor_encode(unit, 369 scaling_factor, &scaling_factor_hw)) { 370 return BCM_E_PARAM; 371 } 372 /* Set scaling factor */ 373 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY, 374 port, &quantize_control_entry)); 375 376 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, 377 &quantize_control_entry, 378 PORT_LOADING_THRESHOLD_SCALING_FACTORf, 379 scaling_factor_hw); 380 if (!soc_feature(unit, soc_feature_td3_dlb)) { 381 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, 382 &quantize_control_entry, 383 TOTAL_PORT_QSIZE_THRESHOLD_SCALING_FACTORf, 384 scaling_factor_hw); 385 } 386 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, 387 &quantize_control_entry, 388 qsf_field, 389 scaling_factor_hw); 390 BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL, 391 port, &quantize_control_entry)); 392 393 return BCM_E_NONE; 394 } 395 396 /* 397 * Function: 398 * _bcm_th2_ecmp_dlb_port_attr_get 399 * Purpose: 400 * Get ECMP dynamic load balancing attributes for a member. 401 * Parameters: 402 * unit - (IN) SOC unit number. 403 * port - (IN) Port, not Gport. 404 * scaling_factor - (OUT) Threshold scaling factor. 405 * load_weight - (OUT) Weighting of load in determining member quality. 406 * qsize_weight - (OUT) Weighting of total qsize in determining member quality. 407 * Returns: 408 * BCM_E_XXX 409 */ 410 STATIC int 411 _bcm_th2_ecmp_dlb_port_attr_get(int unit, bcm_port_t port, int *scaling_factor, 412 int *load_weight, int *qsize_weight) 413 { 414 dlb_ecmp_quantize_control_entry_t quantize_control_entry; 415 int profile_ptr; 416 int scaling_factor_hw; 417 418 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY, 419 port, &quantize_control_entry)); 420 421 /* Get load weight, qsize weight*/ 422 profile_ptr = soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_get(unit, 423 &quantize_control_entry, PORT_QUALITY_MAPPING_PROFILE_PTRf); 424 *load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr]; 425 *qsize_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[profile_ptr]; 426 427 /* Get scaling factor */ 428 scaling_factor_hw = soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_get(unit, 429 &quantize_control_entry, PORT_LOADING_THRESHOLD_SCALING_FACTORf); 430 431 BCM_IF_ERROR_RETURN 432 (_bcm_th2_ecmp_dlb_scaling_factor_decode(unit, scaling_factor_hw, 433 scaling_factor)); 434 435 return BCM_E_NONE; 436 } 437 438 /* 439 * Function: 440 * bcm_th2_l3_egress_dlb_attr_set 441 * Purpose: 442 * Set ECMP dynamic load balancing attributes for a next hop index. 443 * Parameters: 444 * unit - (IN) SOC unit number. 445 * nh_index - (IN) Next hop index. 446 * egr - (IN) L3 egress info. 447 * old_egr - (IN) Old L3 egress info. 448 * Returns: 449 * BCM_E_XXX 450 */ 451 int 452 bcm_th2_l3_egress_dlb_attr_set(int unit, int nh_index, 453 bcm_l3_egress_t *egr, bcm_l3_egress_t *old_egr) 454 { 455 int scaling_factor_valid = 1; 456 int load_weight_valid = 1; 457 int qsize_weight_valid = 1; 458 int sum_valid; 459 _th2_ecmp_dlb_port_membership_t *membership = NULL; 460 int new_mod, new_port; /* not GPORT */ 461 int mod, port; /* not GPORT */ 462 int is_local; 463 int move_dlb_count; 464 int search_old_qualified; 465 _th2_ecmp_dlb_port_membership_t *current_ptr, *prev_ptr; 466 _th2_ecmp_dlb_port_membership_t *current_next; 467 _th2_ecmp_dlb_port_membership_t *first_ptr, *prev_first_ptr; 468 _th2_ecmp_dlb_port_membership_t *last_ptr; 469 _th2_ecmp_dlb_port_membership_t *record_ptr; 470 if (egr->dynamic_scaling_factor == 471 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) { 472 scaling_factor_valid = 0; 473 } 474 if (egr->dynamic_load_weight == 475 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID) { 476 load_weight_valid = 0; 477 } 478 if (egr->dynamic_queue_size_weight == 479 BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID) { 480 qsize_weight_valid = 0; 481 } 482 sum_valid = scaling_factor_valid + 483 load_weight_valid + qsize_weight_valid; 484 485 if ((sum_valid != 0) && (sum_valid != 3)) { 486 /* The scaling factor, load weight and qsize weight must 487 * be all invalid or all valid. 488 */ 489 return BCM_E_PARAM; 490 } 491 492 /* Verify DLB parameters */ 493 if (sum_valid == 3) { 494 if (!_bcm_th2_ecmp_dlb_scaling_factor_encode(unit, 495 egr->dynamic_scaling_factor, NULL)) { 496 return BCM_E_PARAM; 497 } 498 if (egr->dynamic_load_weight < 0 || 499 egr->dynamic_load_weight > 100) { 500 return BCM_E_PARAM; 501 } 502 if (egr->dynamic_queue_size_weight < 0 || 503 egr->dynamic_queue_size_weight > 100) { 504 return BCM_E_PARAM; 505 } 506 if ((egr->dynamic_load_weight + egr->dynamic_queue_size_weight) < 0 || 507 (egr->dynamic_load_weight + egr->dynamic_queue_size_weight) > 100) { 508 return BCM_E_PARAM; 509 } 510 /* ECMP DLB members shouldn't be LAG */ 511 if (egr->flags & BCM_L3_TGID) { 512 return BCM_E_PARAM; 513 } else { 514 /* ECMP DLB members should be local */ 515 BCM_IF_ERROR_RETURN 516 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 517 egr->module, egr->port, 518 &new_mod, &new_port)); 519 if (new_port < 0 || 520 new_port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) { 521 return BCM_E_PARAM; 522 } 523 524 (void) _bcm_esw_modid_is_local(unit, new_mod, &is_local); 525 if (!is_local) { 526 return BCM_E_PARAM; 527 } 528 } 529 } 530 531 532 search_old_qualified = 0; 533 if (old_egr && 534 !(old_egr->flags & BCM_L3_TGID)) { 535 BCM_IF_ERROR_RETURN 536 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 537 old_egr->module, old_egr->port, 538 &mod, &port)); 539 (void) _bcm_esw_modid_is_local(unit, mod, &is_local); 540 if (port < 0 || 541 port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) { 542 return BCM_E_PARAM; 543 } 544 545 search_old_qualified = is_local; 546 } 547 548 current_ptr = NULL; 549 prev_ptr = NULL; 550 if (search_old_qualified) { 551 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 552 while (current_ptr) { 553 if (nh_index == current_ptr->nh_index) { 554 break; 555 } else { 556 prev_ptr = current_ptr; 557 } 558 current_ptr = current_ptr->next; 559 } 560 } 561 562 if (current_ptr) { 563 /* This Nexthop existed with DLB attributes, which means it 564 * must have DLB attributes before. 565 */ 566 567 record_ptr = current_ptr; 568 if (egr->dynamic_scaling_factor == 569 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) { 570 /* Now remove its DLB attributes. This node should be removed 571 * from port list. 572 */ 573 574 /* Check that the given next hop index is currently not a member of 575 * any ECMP DLB group. 576 */ 577 while (current_ptr) { 578 if (nh_index == current_ptr->nh_index && 579 -1 != current_ptr->dlb_id) { 580 return BCM_E_BUSY; 581 } 582 current_ptr = current_ptr->next; 583 } 584 585 current_ptr = record_ptr; 586 while (current_ptr) { 587 current_next = current_ptr->next; 588 if (nh_index == current_ptr->nh_index) { 589 if (prev_ptr == NULL) { 590 ECMP_DLB_PORT_LIST(unit, port) = current_next; 591 } else { 592 prev_ptr->next = current_next; 593 } 594 sal_free(current_ptr); 595 } else { 596 break; 597 } 598 current_ptr = current_next; 599 } 600 /* must do and only do once */ 601 ECMP_DLB_PORT_INFO(unit, port).nh_count--; 602 603 /* Reset the DLB attributes */ 604 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) { 605 /* Verify nh_count consistent with port_list and dlb_count */ 606 if (ECMP_DLB_PORT_LIST(unit, port) != NULL || 607 ECMP_DLB_PORT_INFO(unit, port).dlb_count != 0) { 608 return BCM_E_INTERNAL; 609 } 610 611 BCM_IF_ERROR_RETURN 612 (_bcm_th2_ecmp_dlb_port_attr_set(unit, port, 613 _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR, 614 _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT, 615 _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT)); 616 } 617 } else { 618 /* Set nexthop with new DLB attributes. 619 * There're 2 cases: 620 * 1, the new port equal to old port 621 * 2, the new port not equal to old port 622 */ 623 if (port == new_port) { 624 /* 1, the new port is equal to old port. */ 625 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) { 626 return BCM_E_INTERNAL; 627 } 628 629 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 1 || 630 ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set) { 631 /* This nexthop is the only nexthop pointing to old port 632 * Set with new DLB attributes. 633 */ 634 BCM_IF_ERROR_RETURN 635 (_bcm_th2_ecmp_dlb_port_attr_set(unit, 636 new_port, 637 egr->dynamic_scaling_factor, 638 egr->dynamic_load_weight, 639 egr->dynamic_queue_size_weight)); 640 } else { 641 /* This nexthop is not the only nexthop pointing to old port 642 * Reject/alert if new DLB attributes are not equal 643 * to old DLB attributes 644 */ 645 if (egr->dynamic_load_weight != old_egr->dynamic_load_weight || 646 egr->dynamic_queue_size_weight != old_egr->dynamic_queue_size_weight || 647 egr->dynamic_scaling_factor != old_egr->dynamic_scaling_factor) { 648 return BCM_E_BUSY; 649 } 650 } 651 652 } else { 653 /* 2, the new port is not equal to old port. 654 * move this nexthop's node or nodes to new port list 655 */ 656 657 /* Check that the move is feasible */ 658 if (!ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set && 659 ECMP_DLB_PORT_INFO(unit, new_port).nh_count >= 1) { 660 int dynamic_scaling_factor; 661 int dynamic_load_weight; 662 int dynamic_qsize_weight; 663 BCM_IF_ERROR_RETURN 664 (_bcm_th2_ecmp_dlb_port_attr_get(unit, 665 new_port, 666 &dynamic_scaling_factor, 667 &dynamic_load_weight, 668 &dynamic_qsize_weight)); 669 if (egr->dynamic_load_weight != dynamic_load_weight || 670 egr->dynamic_queue_size_weight != dynamic_qsize_weight|| 671 egr->dynamic_scaling_factor != dynamic_scaling_factor){ 672 return BCM_E_BUSY; 673 } 674 } 675 676 /* a, first remove this nexthop from old port list */ 677 first_ptr = NULL; 678 last_ptr = NULL; 679 move_dlb_count = 0; 680 prev_ptr = ECMP_DLB_PORT_LIST(unit, port); 681 prev_first_ptr = NULL; 682 while (current_ptr) { 683 if (nh_index == current_ptr->nh_index) { 684 if (first_ptr == NULL) { 685 first_ptr = current_ptr; 686 prev_first_ptr = prev_ptr; 687 } 688 if (current_ptr->dlb_id != -1) { 689 move_dlb_count++; 690 } 691 last_ptr = current_ptr; 692 } else { 693 /* Given the fact nodes with same nh_index are always 694 * bundled together. 695 */ 696 if (first_ptr) { 697 break; 698 } 699 } 700 prev_ptr = current_ptr; 701 current_ptr = current_ptr->next; 702 } 703 /* must do and only do once */ 704 ECMP_DLB_PORT_INFO(unit, port).nh_count--; 705 706 if (last_ptr == NULL || 707 first_ptr == NULL || 708 prev_first_ptr == NULL) { 709 return BCM_E_INTERNAL; 710 } 711 if (prev_first_ptr == ECMP_DLB_PORT_LIST(unit, port)) { 712 ECMP_DLB_PORT_LIST(unit, port) = last_ptr->next; 713 } else { 714 prev_first_ptr->next = last_ptr->next; 715 } 716 717 ECMP_DLB_PORT_INFO(unit, port).dlb_count -= move_dlb_count; 718 719 /* Reset the DLB attributes */ 720 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) { 721 if (ECMP_DLB_PORT_LIST(unit, port) != NULL || 722 ECMP_DLB_PORT_INFO(unit, port).dlb_count != 0) { 723 return BCM_E_INTERNAL; 724 } 725 BCM_IF_ERROR_RETURN 726 (_bcm_th2_ecmp_dlb_port_attr_set(unit, port, 727 _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR, 728 _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT, 729 _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT)); 730 } 731 732 /* Set the DLB attributes */ 733 BCM_IF_ERROR_RETURN( 734 _bcm_th2_ecmp_dlb_port_attr_set(unit, 735 new_port, 736 egr->dynamic_scaling_factor, 737 egr->dynamic_load_weight, 738 egr->dynamic_queue_size_weight)); 739 /* Add into list */ 740 last_ptr->next = ECMP_DLB_PORT_LIST(unit, new_port); 741 ECMP_DLB_PORT_LIST(unit, new_port) = first_ptr; 742 ECMP_DLB_PORT_INFO(unit, new_port).nh_count++; 743 ECMP_DLB_PORT_INFO(unit, new_port).dlb_count += move_dlb_count; 744 745 } 746 } 747 } else { 748 /* Either the Nexthop did not exist or it existed without DLB attributes. */ 749 if (egr->dynamic_scaling_factor == 750 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID) { 751 /* still without DLB porperties */ 752 return BCM_E_NONE; 753 } else { 754 /* With DLB porperties */ 755 756 /* Check that DLB attributes setting is feasible */ 757 if (!ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set && 758 ECMP_DLB_PORT_INFO(unit, new_port).nh_count >= 1) { 759 int dynamic_scaling_factor; 760 int dynamic_load_weight; 761 int dynamic_qsize_weight; 762 BCM_IF_ERROR_RETURN 763 (_bcm_th2_ecmp_dlb_port_attr_get(unit, 764 new_port, 765 &dynamic_scaling_factor, 766 &dynamic_load_weight, 767 &dynamic_qsize_weight)); 768 if (egr->dynamic_load_weight != dynamic_load_weight || 769 egr->dynamic_queue_size_weight != dynamic_qsize_weight || 770 egr->dynamic_scaling_factor != dynamic_scaling_factor){ 771 return BCM_E_BUSY; 772 } 773 } 774 775 BCM_IF_ERROR_RETURN 776 (_bcm_th2_ecmp_dlb_port_attr_set(unit, 777 new_port, 778 egr->dynamic_scaling_factor, 779 egr->dynamic_load_weight, 780 egr->dynamic_queue_size_weight)); 781 782 membership = sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t), 783 "ecmp dlb nh membership"); 784 if (NULL == membership) { 785 return BCM_E_MEMORY; 786 } 787 sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t)); 788 membership->nh_index = nh_index; 789 membership->ref_count = 0; 790 membership->dlb_id = -1; 791 membership->next = ECMP_DLB_PORT_LIST(unit, new_port); 792 ECMP_DLB_PORT_LIST(unit, new_port) = membership; 793 ECMP_DLB_PORT_INFO(unit, new_port).nh_count++; 794 } 795 } 796 797 return BCM_E_NONE; 798 } 799 800 /* 801 * Function: 802 * bcm_th2_l3_egress_dlb_attr_destroy 803 * Purpose: 804 * Destroy ECMP dynamic load balancing attributes for a next hop index. 805 * Parameters: 806 * unit - (IN) SOC unit number. 807 * nh_index - (IN) Next hop index. 808 * Returns: 809 * BCM_E_XXX 810 */ 811 int 812 bcm_th2_l3_egress_dlb_attr_destroy(int unit, int nh_index, bcm_l3_egress_t *egr) 813 { 814 int mod, port; 815 int is_local; 816 _th2_ecmp_dlb_port_membership_t *record_ptr = NULL; 817 _th2_ecmp_dlb_port_membership_t *current_next, *prev_ptr = NULL; 818 _th2_ecmp_dlb_port_membership_t *current_ptr = NULL; 819 820 /* ECMP DLB members shouldn't be LAG */ 821 if (egr->flags & BCM_L3_TGID) { 822 return BCM_E_NONE; 823 } else { 824 BCM_IF_ERROR_RETURN 825 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 826 egr->module, egr->port, 827 &mod, &port)); 828 if (port < 0 || 829 port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) { 830 if (egr->flags & BCM_L3_DST_DISCARD) { 831 return BCM_E_NONE; 832 } 833 return BCM_E_PARAM; 834 } 835 836 (void) _bcm_esw_modid_is_local(unit, mod, &is_local); 837 if (!is_local) { 838 return BCM_E_NONE; 839 } 840 } 841 842 /* Check that the given next hop index is currently not a member of 843 * any ECMP DLB group. 844 */ 845 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 846 while (current_ptr) { 847 if (nh_index == current_ptr->nh_index) { 848 if (record_ptr == NULL) { 849 record_ptr = current_ptr; 850 } 851 if (current_ptr->dlb_id != -1) { 852 return BCM_E_BUSY; 853 } 854 } else { 855 if (record_ptr) { 856 break; 857 } else { 858 prev_ptr = current_ptr; 859 } 860 } 861 current_ptr = current_ptr->next; 862 } 863 864 if (record_ptr == NULL) { 865 return BCM_E_NONE; 866 } 867 868 current_ptr = record_ptr; 869 870 while (current_ptr) { 871 current_next = current_ptr->next; 872 if (nh_index == current_ptr->nh_index) { 873 if (prev_ptr == NULL) { 874 ECMP_DLB_PORT_LIST(unit, port) = current_next; 875 } else { 876 prev_ptr->next = current_next; 877 } 878 sal_free(current_ptr); 879 } else { 880 break; 881 } 882 current_ptr = current_next; 883 } 884 /* must do and only do once */ 885 ECMP_DLB_PORT_INFO(unit, port).nh_count--; 886 887 /* Reset the DLB attributes */ 888 if (ECMP_DLB_PORT_INFO(unit, port).nh_count == 0) { 889 /* Verify nh_count consistent with port_list and dlb_count */ 890 if (ECMP_DLB_PORT_LIST(unit, port) != NULL || 891 ECMP_DLB_PORT_INFO(unit, port).dlb_count != 0) { 892 return BCM_E_INTERNAL; 893 } 894 BCM_IF_ERROR_RETURN 895 (_bcm_th2_ecmp_dlb_port_attr_set(unit, port, 896 _BCM_ECMP_DLB_DEFAULT_SCALING_FACTOR, 897 _BCM_ECMP_DLB_DEFAULT_PORT_LOAD_WEIGHT, 898 _BCM_ECMP_DLB_DEFAULT_QUEUE_SIZE_WEIGHT)); 899 } 900 901 return BCM_E_NONE; 902 } 903 904 /* 905 * Function: 906 * bcm_th2_l3_egress_dlb_attr_get 907 * Purpose: 908 * Get ECMP dynamic load balancing attributes for a next hop index. 909 * Parameters: 910 * unit - (IN) SOC unit number. 911 * nh_index - (IN) Next hop index. 912 * egr - (OUT) L3 egress info. 913 * Returns: 914 * BCM_E_XXX 915 */ 916 int 917 bcm_th2_l3_egress_dlb_attr_get(int unit, int nh_index, bcm_l3_egress_t *egr) 918 { 919 _th2_ecmp_dlb_port_membership_t *current_ptr; 920 int port; 921 922 /* ECMP DLB members shouldn't be LAG */ 923 if (egr->flags & BCM_L3_TGID) { 924 return BCM_E_NONE; 925 } else { 926 BCM_IF_ERROR_RETURN 927 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 928 egr->module, egr->port, 929 NULL, &port)); 930 if (port < 0 || 931 port >= ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size) { 932 if (egr->flags & BCM_L3_DST_DISCARD) { 933 egr->dynamic_scaling_factor = \ 934 BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID; 935 egr->dynamic_load_weight = \ 936 BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID; 937 egr->dynamic_queue_size_weight = \ 938 BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID; 939 return BCM_E_NONE; 940 } 941 return BCM_E_PARAM; 942 } 943 } 944 945 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 946 while (current_ptr) { 947 if (nh_index == current_ptr->nh_index) { 948 break; 949 } 950 current_ptr = current_ptr->next; 951 } 952 953 if (current_ptr) { 954 /* Get the DLB attributes */ 955 BCM_IF_ERROR_RETURN 956 (_bcm_th2_ecmp_dlb_port_attr_get(unit, 957 port, 958 &egr->dynamic_scaling_factor, 959 &egr->dynamic_load_weight, 960 &egr->dynamic_queue_size_weight)); 961 } else { 962 egr->dynamic_scaling_factor = BCM_L3_ECMP_DYNAMIC_SCALING_FACTOR_INVALID; 963 egr->dynamic_load_weight = BCM_L3_ECMP_DYNAMIC_LOAD_WEIGHT_INVALID; 964 egr->dynamic_queue_size_weight = BCM_L3_ECMP_DYNAMIC_QUEUE_SIZE_WEIGHT_INVALID; 965 } 966 967 return BCM_E_NONE; 968 } 969 970 /* 971 * Function: 972 * _bcm_th2_ecmp_dlb_id_alloc 973 * Purpose: 974 * Get a free ECMP DLB ID and mark it used. 975 * Parameters: 976 * unit - (IN) SOC unit number. 977 * dynamic_mode - (IN) Dynamic mode 978 * dlb_id - (OUT) Allocated DLB ID. 979 * Returns: 980 * BCM_E_xxx 981 */ 982 STATIC int 983 _bcm_th2_ecmp_dlb_id_alloc(int unit, bcm_l3_egress_ecmp_t *ecmp, int *dlb_id) 984 { 985 int i; 986 uint32 dynamic_mode = ecmp->dynamic_mode; 987 988 #if defined(BCM_TOMAHAWK3_SUPPORT) 989 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 990 *dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp->ecmp_intf 991 - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)); 992 _BCM_ECMP_DLB_ID_USED_SET(unit, *dlb_id); 993 if (dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 994 _BCM_ECMP_DLB_ID_DGM_SET(unit, *dlb_id); 995 } else { 996 _BCM_ECMP_DLB_ID_DGM_CLR(unit, *dlb_id); 997 } 998 return BCM_E_NONE; 999 } 1000 #endif 1001 for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) { 1002 if (!_BCM_ECMP_DLB_ID_USED_GET(unit, i)) { 1003 _BCM_ECMP_DLB_ID_USED_SET(unit, i); 1004 if (dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 1005 _BCM_ECMP_DLB_ID_DGM_SET(unit, i); 1006 } else { 1007 _BCM_ECMP_DLB_ID_DGM_CLR(unit, i); 1008 } 1009 *dlb_id = i; 1010 return BCM_E_NONE; 1011 } 1012 } 1013 1014 return BCM_E_RESOURCE; 1015 } 1016 1017 /* 1018 * Function: 1019 * _bcm_th2_ecmp_dlb_id_free 1020 * Purpose: 1021 * Free an ECMP DLB ID. 1022 * Parameters: 1023 * unit - (IN) SOC unit number. 1024 * dlb_id - (IN) DLB ID to be freed. 1025 * Returns: 1026 * BCM_E_xxx 1027 */ 1028 STATIC int 1029 _bcm_th2_ecmp_dlb_id_free(int unit, int dlb_id) 1030 { 1031 if (dlb_id < 0 || 1032 dlb_id > soc_mem_index_max(unit, DLB_ECMP_GROUP_CONTROLm)) { 1033 return BCM_E_PARAM; 1034 } 1035 1036 _BCM_ECMP_DLB_ID_USED_CLR(unit, dlb_id); 1037 _BCM_ECMP_DLB_ID_DGM_CLR(unit, dlb_id); 1038 1039 return BCM_E_NONE; 1040 } 1041 1042 /* 1043 * Function: 1044 * _bcm_th2_ecmp_dlb_dynamic_size_encode 1045 * Purpose: 1046 * Encode ECMP dynamic load balancing flow set size. 1047 * Parameters: 1048 * dynamic_size - (IN) Number of flow sets. 1049 * encoded_value - (OUT) Encoded value. 1050 * Returns: 1051 * BCM_E_xxx 1052 */ 1053 STATIC int 1054 _bcm_th2_ecmp_dlb_dynamic_size_encode(int dynamic_size, 1055 int *encoded_value) 1056 { 1057 switch (dynamic_size) { 1058 case 256: 1059 *encoded_value = 1; 1060 break; 1061 case 512: 1062 *encoded_value = 2; 1063 break; 1064 case 1024: 1065 *encoded_value = 3; 1066 break; 1067 case 2048: 1068 *encoded_value = 4; 1069 break; 1070 case 4096: 1071 *encoded_value = 5; 1072 break; 1073 case 8192: 1074 *encoded_value = 6; 1075 break; 1076 case 16384: 1077 *encoded_value = 7; 1078 break; 1079 case 32768: 1080 *encoded_value = 8; 1081 break; 1082 default: 1083 return BCM_E_PARAM; 1084 } 1085 1086 return BCM_E_NONE; 1087 } 1088 1089 /* 1090 * Function: 1091 * _bcm_th2_ecmp_dlb_dynamic_size_decode 1092 * Purpose: 1093 * Decode ECMP dynamic load balancing flow set size. 1094 * Parameters: 1095 * encoded_value - (IN) Encoded value. 1096 * dynamic_size - (OUT) Number of flow sets. 1097 * Returns: 1098 * BCM_E_xxx 1099 */ 1100 STATIC int 1101 _bcm_th2_ecmp_dlb_dynamic_size_decode(int encoded_value, 1102 int *dynamic_size) 1103 { 1104 switch (encoded_value) { 1105 case 1: 1106 *dynamic_size = 256; 1107 break; 1108 case 2: 1109 *dynamic_size = 512; 1110 break; 1111 case 3: 1112 *dynamic_size = 1024; 1113 break; 1114 case 4: 1115 *dynamic_size = 2048; 1116 break; 1117 case 5: 1118 *dynamic_size = 4096; 1119 break; 1120 case 6: 1121 *dynamic_size = 8192; 1122 break; 1123 case 7: 1124 *dynamic_size = 16384; 1125 break; 1126 case 8: 1127 *dynamic_size = 32768; 1128 break; 1129 default: 1130 return BCM_E_INTERNAL; 1131 } 1132 1133 return BCM_E_NONE; 1134 } 1135 1136 /* 1137 * Function: 1138 * _bcm_th2_ecmp_dlb_free_resource 1139 * Purpose: 1140 * Free resources for an ECMP dynamic load balancing group. 1141 * Parameters: 1142 * unit - (IN) SOC unit number. 1143 * ecmp_group_idx - (IN) ECMP group index. 1144 * dlb_id - (IN) DLB id. 1145 * -1: free all DLB resources, 1146 * others: will not disable DLB and free flowset. 1147 * Returns: 1148 * BCM_E_xxx 1149 */ 1150 STATIC int 1151 _bcm_th2_ecmp_dlb_free_resource(int unit, int ecmp_group_idx, int dlb_id, 1152 int cleanup_flowset) 1153 { 1154 int rv = BCM_E_NONE; 1155 ecmp_dlb_control_entry_t ecmp_dlb_control_entry; 1156 int dlb_enable; 1157 dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry; 1158 int entry_base_ptr; 1159 int flow_set_size; 1160 int num_entries; 1161 int block_base_ptr; 1162 int membership_pointer; 1163 int port2member_base = 0; 1164 int num_blocks; 1165 dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry; 1166 int port_map_width; 1167 int alloc_size; 1168 SHR_BITDCL *port_map = NULL, *port_map2 = NULL; 1169 SHR_BITDCL *port_map_remove = NULL; 1170 int port_map_remove_set = 0; 1171 SHR_BITDCL *status_bitmap = NULL; 1172 SHR_BITDCL *override_bitmap = NULL; 1173 int port; 1174 dlb_ecmp_link_control_entry_t link_control_entry; 1175 _th2_ecmp_dlb_port_membership_t *current_ptr, *prev_ptr, *current_next; 1176 int duplicate = 0; 1177 dlb_ecmp_group_port_to_member_entry_t *entry_arr = NULL; 1178 int entry_size; 1179 int entries_per_profile; 1180 int index_max; 1181 #ifdef BCM_TRIDENT3_SUPPORT 1182 ecmp_count_entry_t ecmp_count_entry; 1183 #endif 1184 #if defined(BCM_TOMAHAWK3_SUPPORT) 1185 uint64 dlb_en_bitmap; 1186 #endif 1187 int delete_all_flag = TRUE; 1188 1189 delete_all_flag = (dlb_id == -1) ? TRUE: FALSE; 1190 1191 #if defined(BCM_TOMAHAWK3_SUPPORT) 1192 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 1193 /* Make sure the ECMP group is in DLB range */ 1194 if ( ecmp_group_idx < BCM_TH3_L3_ECMP_DLB_START(unit)) { 1195 return BCM_E_NONE; 1196 } 1197 1198 dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx); 1199 /* Enable bits for the first 64 groups are in 1200 DLB_ID_0_TO_63_ENABLE register and the next 64 are in 1201 DLB_ID_64_TO_127_ENABLE. */ 1202 if (dlb_id < soc_reg_field_length(unit, 1203 DLB_ID_0_TO_63_ENABLEr, BITMAPf)) { 1204 SOC_IF_ERROR_RETURN(READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap)); 1205 if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id))) { 1206 return BCM_E_NONE; 1207 } 1208 } else { 1209 SOC_IF_ERROR_RETURN( \ 1210 READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap)); 1211 if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id - 1212 soc_reg_field_length(unit, DLB_ID_0_TO_63_ENABLEr, BITMAPf)))) { 1213 return BCM_E_NONE; 1214 } 1215 } 1216 delete_all_flag = cleanup_flowset; 1217 } 1218 #endif 1219 1220 if (delete_all_flag) { 1221 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 1222 BCM_IF_ERROR_RETURN( 1223 READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY, 1224 ecmp_group_idx, &ecmp_dlb_control_entry)); 1225 dlb_enable = 1226 soc_ECMP_DLB_CONTROLm_field32_get(unit, &ecmp_dlb_control_entry, 1227 GROUP_ENABLEf); 1228 dlb_id = 1229 soc_ECMP_DLB_CONTROLm_field32_get(unit, 1230 &ecmp_dlb_control_entry, DLB_IDf); 1231 if (!dlb_enable) { 1232 return BCM_E_NONE; 1233 } 1234 /* Clear DLB fields in ECMP group table */ 1235 soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry, 1236 GROUP_ENABLEf, 0); 1237 soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry, 1238 DLB_IDf, 0); 1239 BCM_IF_ERROR_RETURN( 1240 WRITE_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ALL, 1241 ecmp_group_idx, &ecmp_dlb_control_entry)); 1242 } 1243 1244 #ifdef BCM_TRIDENT3_SUPPORT 1245 if (soc_feature(unit, soc_feature_td3_dlb)) { 1246 BCM_IF_ERROR_RETURN(READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry)); 1247 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, LB_MODEf, 0x0); 1248 BCM_IF_ERROR_RETURN(WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry)); 1249 ecmp_grp_enhanced_hashing[unit][ecmp_group_idx] = 0; 1250 } 1251 #endif 1252 } 1253 1254 /* Free flow set table resources */ 1255 BCM_IF_ERROR_RETURN 1256 (READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, dlb_id, 1257 &dlb_ecmp_group_control_entry)); 1258 entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 1259 &dlb_ecmp_group_control_entry, FLOW_SET_BASEf); 1260 flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 1261 &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf); 1262 membership_pointer = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 1263 &dlb_ecmp_group_control_entry, GROUP_MEMBERSHIP_POINTERf); 1264 if (!soc_feature(unit, soc_feature_th3_style_dlb)) { 1265 port2member_base = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 1266 &dlb_ecmp_group_control_entry, GROUP_PORT_TO_MEMBER_BASE_ADDRf); 1267 } 1268 1269 if (delete_all_flag) { 1270 BCM_IF_ERROR_RETURN( 1271 _bcm_th2_ecmp_dlb_dynamic_size_decode(flow_set_size, &num_entries)); 1272 block_base_ptr = 1273 entry_base_ptr >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 1274 num_blocks = 1275 num_entries >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 1276 1277 _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_CLR_RANGE(unit, block_base_ptr, 1278 num_blocks); 1279 } 1280 1281 /* Clear ECMP DLB group control */ 1282 if (cleanup_flowset) { 1283 #if defined(BCM_TOMAHAWK3_SUPPORT) 1284 SOC_IF_ERROR_RETURN(WRITE_DLB_ECMP_GROUP_CONTROLm(unit, \ 1285 MEM_BLOCK_ALL, dlb_id, \ 1286 soc_mem_entry_null(unit, DLB_ECMP_GROUP_CONTROLm))); 1287 if ((soc_feature(unit, soc_feature_th3_style_dlb))) { 1288 if (dlb_id < soc_reg_field_length(unit, 1289 DLB_ID_0_TO_63_ENABLEr, BITMAPf)) { 1290 SOC_IF_ERROR_RETURN( \ 1291 READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap)); 1292 COMPILER_64_BITCLR(dlb_en_bitmap, dlb_id); 1293 SOC_IF_ERROR_RETURN( \ 1294 WRITE_DLB_ID_0_TO_63_ENABLEr(unit, dlb_en_bitmap)); 1295 } else { 1296 SOC_IF_ERROR_RETURN( \ 1297 READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap)); 1298 COMPILER_64_BITCLR(dlb_en_bitmap, (dlb_id - 1299 (soc_reg_field_length(unit, 1300 DLB_ID_0_TO_63_ENABLEr, BITMAPf)))); 1301 SOC_IF_ERROR_RETURN( \ 1302 WRITE_DLB_ID_64_TO_127_ENABLEr(unit, dlb_en_bitmap)); 1303 } 1304 } 1305 #endif 1306 } 1307 1308 /* Allocate port map */ 1309 port_map_width = soc_mem_field_length(unit, 1310 DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf); 1311 alloc_size = SHR_BITALLOCSIZE(port_map_width); 1312 port_map = sal_alloc(alloc_size, "DLB ECMP port map"); 1313 if (NULL == port_map) { 1314 rv = BCM_E_MEMORY; 1315 goto error; 1316 } 1317 sal_memset(port_map, 0, alloc_size); 1318 1319 port_map2 = sal_alloc(alloc_size, "DLB ECMP port map2"); 1320 if (NULL == port_map2) { 1321 rv = BCM_E_MEMORY; 1322 goto error; 1323 } 1324 sal_memset(port_map2, 0, alloc_size); 1325 1326 rv = READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY, membership_pointer, 1327 &dlb_ecmp_group_membership_entry); 1328 if (BCM_FAILURE(rv)) { 1329 goto error; 1330 } 1331 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit, 1332 &dlb_ecmp_group_membership_entry, PORT_MAPf, port_map); 1333 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit, 1334 &dlb_ecmp_group_membership_entry, PORT_MAP_ALTERNATEf, port_map2); 1335 1336 /* Allocate port map remove */ 1337 port_map_remove = sal_alloc(alloc_size, "DLB ECMP port map remove"); 1338 if (NULL == port_map_remove) { 1339 rv = BCM_E_MEMORY; 1340 goto error; 1341 } 1342 sal_memset(port_map_remove, 0, alloc_size); 1343 1344 SHR_BITOR_RANGE(port_map, port_map2, 0, port_map_width, port_map); 1345 for (port = 0; port < port_map_width; port++) { 1346 if (!SHR_BITGET(port_map, port)) { 1347 continue; 1348 } 1349 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 1350 1351 /* 1352 * Traverse the port list and then delete all duplicate nodes, if any, 1353 * in given DLB group. 1354 */ 1355 1356 prev_ptr = NULL; 1357 while (current_ptr) { 1358 current_next = current_ptr->next; 1359 if (current_ptr->dlb_id == dlb_id) { 1360 /* Duplicate nodes are always bundled together. 1361 * Keep the first one if duplicate notes exist. 1362 */ 1363 duplicate = 0; 1364 if (prev_ptr && 1365 prev_ptr->nh_index == current_ptr->nh_index) { 1366 duplicate = 1; 1367 } 1368 1369 if (duplicate) { 1370 prev_ptr->next = current_next; 1371 sal_free(current_ptr); 1372 current_ptr = NULL; 1373 } else { 1374 current_ptr->ref_count = 0; 1375 current_ptr->dlb_id = -1; 1376 } 1377 if (ECMP_DLB_PORT_INFO(unit, port).dlb_count <= 0) { 1378 rv = BCM_E_INTERNAL; 1379 goto error; 1380 } 1381 ECMP_DLB_PORT_INFO(unit, port).dlb_count--; 1382 } 1383 if (current_ptr != NULL) { 1384 prev_ptr = current_ptr; 1385 } 1386 current_ptr = current_next; 1387 } 1388 1389 if (ECMP_DLB_PORT_INFO(unit, port).dlb_count == 0) { 1390 /* This port is now removed from all DLB Groups. 1391 * So it's safe to remove it from link_control. 1392 */ 1393 SHR_BITSET(port_map_remove, port); 1394 port_map_remove_set = 1; 1395 } 1396 } 1397 1398 if (port_map_remove_set) { 1399 rv = READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0, 1400 &link_control_entry); 1401 if (BCM_FAILURE(rv)) { 1402 goto error; 1403 } 1404 /* Clear software status bitmap */ 1405 status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 1406 if (NULL == status_bitmap) { 1407 rv = BCM_E_MEMORY; 1408 goto error; 1409 } 1410 sal_memset(status_bitmap, 0, alloc_size); 1411 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, 1412 &link_control_entry, SW_PORT_STATEf, status_bitmap); 1413 SHR_BITREMOVE_RANGE(status_bitmap, port_map_remove, 0, port_map_width, 1414 status_bitmap); 1415 soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, 1416 &link_control_entry, SW_PORT_STATEf, status_bitmap); 1417 1418 /* Clear software override bitmap */ 1419 override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 1420 if (NULL == override_bitmap) { 1421 rv = BCM_E_MEMORY; 1422 goto error; 1423 } 1424 sal_memset(override_bitmap, 0, alloc_size); 1425 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, 1426 &link_control_entry, SW_OVERRIDE_PORT_MAPf, 1427 override_bitmap); 1428 SHR_BITREMOVE_RANGE(override_bitmap, port_map_remove, 0, port_map_width, 1429 override_bitmap); 1430 soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, 1431 &link_control_entry, SW_OVERRIDE_PORT_MAPf, 1432 override_bitmap); 1433 rv = WRITE_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ALL, 0, 1434 &link_control_entry); 1435 if (BCM_FAILURE(rv)) { 1436 goto error; 1437 } 1438 } 1439 1440 1441 /* Clear group membership */ 1442 rv = WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY, membership_pointer, 1443 soc_mem_entry_null(unit, DLB_ECMP_GROUP_MEMBERSHIPm)); 1444 if (BCM_FAILURE(rv)) { 1445 goto error; 1446 } 1447 1448 /* Clear group port2member */ 1449 entry_size = sizeof(dlb_ecmp_group_port_to_member_entry_t); 1450 entries_per_profile = ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size; 1451 alloc_size = entries_per_profile * entry_size; 1452 entry_arr = soc_cm_salloc(unit, alloc_size, 1453 "ECMP DLB Group Port To Member entries"); 1454 if (entry_arr == NULL) { 1455 rv = BCM_E_MEMORY; 1456 goto error; 1457 } 1458 sal_memset(entry_arr, 0, alloc_size); 1459 1460 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 1461 index_max = port2member_base + entries_per_profile - 1; 1462 rv = soc_mem_write_range(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm, MEM_BLOCK_ALL, 1463 port2member_base, index_max, entry_arr); 1464 } 1465 1466 if (BCM_FAILURE(rv)) { 1467 goto error; 1468 } 1469 1470 if (NULL != status_bitmap) { 1471 sal_free(status_bitmap); 1472 } 1473 if (NULL != override_bitmap) { 1474 sal_free(override_bitmap); 1475 } 1476 sal_free(port_map); 1477 sal_free(port_map2); 1478 sal_free(port_map_remove); 1479 soc_cm_sfree(unit, entry_arr); 1480 1481 /* Free DLB ID */ 1482 if ((soc_feature(unit, soc_feature_th3_style_dlb))) { 1483 if (delete_all_flag) { 1484 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_id_free(unit, dlb_id)); 1485 } 1486 } else { 1487 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_id_free(unit, dlb_id)); 1488 } 1489 1490 return BCM_E_NONE; 1491 1492 error: 1493 if (NULL != port_map) { 1494 sal_free(port_map); 1495 } 1496 if (NULL != port_map2) { 1497 sal_free(port_map2); 1498 } 1499 if (NULL != port_map_remove) { 1500 sal_free(port_map_remove); 1501 } 1502 if (NULL != status_bitmap) { 1503 sal_free(status_bitmap); 1504 } 1505 if (NULL != override_bitmap) { 1506 sal_free(override_bitmap); 1507 } 1508 if (NULL != entry_arr) { 1509 soc_cm_sfree(unit, entry_arr); 1510 } 1511 return rv; 1512 } 1513 1514 /* 1515 * Function: 1516 * _bcm_th2_ecmp_dlb_port_array_get 1517 * Purpose: 1518 * Get ports for each ECMP member. 1519 * Parameters: 1520 * unit - (IN) SOC unit number. 1521 * ecmp - (IN) ECMP group info. 1522 * dlb_id - (IN) DLB group ID. 1523 * primary_count - (IN) ECMP primary count.. 1524 * intf_count - (IN) Number of elements in intf_array. 1525 * intf_array - (IN) Array of Egress forwarding objects. 1526 * port_array - (OUT) Array of ports. 1527 * portmap_first_use - (OUT) Port Bitmap indicates correspoinding port 1528 * in port_array being attached to ECMP Group 1529 * the first time. 1530 * ecmp_member_bitmap - (IN) ECMP DLB members. 1531 * Returns: 1532 * BCM_E_xxx 1533 */ 1534 STATIC int 1535 _bcm_th2_ecmp_dlb_port_array_get(int unit, bcm_l3_egress_ecmp_t *ecmp, 1536 int dlb_id, int primary_count, int intf_count, 1537 bcm_if_t *intf_array, int *port_array, 1538 SHR_BITDCL *portmap_first_use, 1539 SHR_BITDCL *ecmp_member_bitmap) 1540 { 1541 int rv = BCM_E_NONE; 1542 int i; 1543 _th2_ecmp_dlb_port_membership_t *current_ptr, *first_ptr; 1544 _th2_ecmp_dlb_port_membership_t *membership = NULL; 1545 ing_l3_next_hop_entry_t ing_nh_entry; 1546 int mod = 0, port; 1547 int is_local; 1548 int nh_index; 1549 int location_offset = 0; 1550 #ifdef BCM_TRIDENT3_SUPPORT 1551 uint32 dt, dv; 1552 #endif 1553 1554 /* Only alternate members exist , start from 0 instead of max_paths / 2 */ 1555 if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) && 1556 (primary_count == 0)) { 1557 location_offset = ecmp->max_paths / 2; 1558 } 1559 1560 for (i = 0; i < intf_count; i++) { 1561 /* Ignore filler members */ 1562 if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) { 1563 continue; 1564 } 1565 1566 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf_array[i])) { 1567 nh_index = intf_array[i] - BCM_XGS3_EGRESS_IDX_MIN(unit); 1568 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf_array[i])) { 1569 nh_index = intf_array[i] - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 1570 } else { 1571 return BCM_E_PARAM; 1572 } 1573 1574 /* Derive port from nh_index */ 1575 rv = (READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, 1576 nh_index, &ing_nh_entry)); 1577 if (BCM_FAILURE(rv)) { 1578 return rv; 1579 } 1580 #ifdef BCM_TRIDENT3_SUPPORT 1581 if (soc_feature(unit, soc_feature_generic_dest)) { 1582 dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry, 1583 DESTINATIONf, &dt); 1584 if (dt == SOC_MEM_FIF_DEST_LAG) { 1585 /* Next hop correspond to Trunk group */ 1586 return BCM_E_CONFIG; 1587 } else if (dt == SOC_MEM_FIF_DEST_DGPP) { 1588 mod = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >> 1589 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS; 1590 port = dv & SOC_MEM_FIF_DGPP_PORT_MASK; 1591 } else { 1592 return BCM_E_PARAM; 1593 } 1594 } else 1595 #endif 1596 { 1597 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) { 1598 /* Next hop should correspond to a single physical port. */ 1599 return BCM_E_CONFIG; 1600 } 1601 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 1602 mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 1603 MODULE_IDf); 1604 } 1605 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 1606 PORT_NUMf); 1607 } 1608 (void) _bcm_esw_modid_is_local(unit, mod, &is_local); 1609 if (!is_local) { 1610 return BCM_E_PARAM; 1611 } 1612 port_array[i] = port; 1613 1614 /* Check if DLB attributes have been set for next hop index */ 1615 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 1616 while (current_ptr) { 1617 if (current_ptr->nh_index == nh_index) { 1618 break; 1619 } 1620 current_ptr = current_ptr->next; 1621 } 1622 1623 if (current_ptr == NULL) { 1624 /* User did not configure DLB attributes for this next hop index */ 1625 return BCM_E_CONFIG; 1626 } 1627 1628 /* When the port is first referenced by a DLB Group, its link control 1629 * state will be cleard. This is consitent to free_resource where 1630 * the port is removed from all DLB Groups. 1631 */ 1632 if (ECMP_DLB_PORT_INFO(unit, port).dlb_count == 0) { 1633 SHR_BITSET(portmap_first_use, port); 1634 } 1635 1636 /* Continue traverse */ 1637 first_ptr = NULL; 1638 while (current_ptr) { 1639 if (current_ptr->nh_index != nh_index) { 1640 current_ptr = current_ptr->next; 1641 continue; 1642 } 1643 /* There're 3 cases when nh_index equals: 1644 * 1) this nexthop never be used. dlb_id = -1. 1645 * 2) this nexthop is used, and now will be used again in same dlb_id. 1646 * 3) this nexthop is used, but now will be used in different dlb_id. 1647 */ 1648 1649 if (-1 == current_ptr->dlb_id) { 1650 /* first case, set ref_count, dlb_id, and dlb_count. 1651 * And break. 1652 */ 1653 current_ptr->ref_count = 1; 1654 current_ptr->dlb_id = dlb_id; 1655 ECMP_DLB_PORT_INFO(unit, port).dlb_count++; 1656 break; 1657 } else if (dlb_id == current_ptr->dlb_id) { 1658 /* second case, just increase ref_count. And break. */ 1659 current_ptr->ref_count++; 1660 break; 1661 } 1662 if (first_ptr == NULL) { 1663 /* third case, record first same nexthop node, but don't break 1664 * since there's still chance this dlb_id used later. 1665 */ 1666 first_ptr = current_ptr; 1667 } 1668 current_ptr = current_ptr->next; 1669 } 1670 1671 /* deal with third case: same nexthop find but dlb_id is different. 1672 * It's certain that first_ptr is find. We have got this covered above. 1673 */ 1674 if (current_ptr == NULL) { 1675 /* did not find an available node or find an existing node 1676 * however, we record the first node with same nexthop. 1677 * rember the rule is to bundle nodes with same nexthop. 1678 */ 1679 1680 if (first_ptr == NULL) { 1681 /* there must exist a node with same nexthop*/ 1682 return BCM_E_INTERNAL; 1683 } 1684 1685 membership = sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t), 1686 "ecmp dlb nh membership"); 1687 if (NULL == membership) { 1688 return BCM_E_MEMORY; 1689 } 1690 sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t)); 1691 1692 /* this duplicate node will be placed after first one */ 1693 membership->nh_index = nh_index; 1694 membership->ref_count = 1; 1695 membership->dlb_id = dlb_id; 1696 membership->next = first_ptr->next; 1697 first_ptr->next = membership; 1698 ECMP_DLB_PORT_INFO(unit, port).dlb_count++; 1699 } 1700 1701 if (ECMP_DLB_PORT_INFO(unit, port).dlb_count < 1) { 1702 return BCM_E_INTERNAL; 1703 } 1704 } 1705 return BCM_E_NONE; 1706 } 1707 1708 #if defined(BCM_TOMAHAWK3_SUPPORT) 1709 /* 1710 * Function: 1711 * _bcm_th3_cmp_int 1712 * Purpose: 1713 * Compare two integers. 1714 * Parameters: 1715 * b - first compared integer 1716 * a - second compared integer 1717 * Returns: 1718 * a<=>b 1719 */ 1720 static INLINE int 1721 _bcm_th3_cmp_int(void *a, void *b) 1722 { 1723 int first; /* First compared integer. */ 1724 int second; /* Second compared integer. */ 1725 1726 first = *(int *)a; 1727 second = *(int *)b; 1728 1729 if (first < second) { 1730 return (BCM_L3_CMP_LESS); 1731 } else if (first > second) { 1732 return (BCM_L3_CMP_GREATER); 1733 } 1734 return (BCM_L3_CMP_EQUAL); 1735 } 1736 #endif 1737 1738 /* 1739 * Function: 1740 * _bcm_th2_ecmp_dlb_set 1741 * Purpose: 1742 * Configure an ECMP dynamic load balancing group. 1743 * Parameters: 1744 * unit - (IN) bcm device. 1745 * ecmp - (IN) ECMP group info. 1746 * intf_count - (IN) Number of elements in intf_array. 1747 * intf_array - (IN) Array of Egress forwarding objects. 1748 * primary - (IN) ECMP primary count. 1749 * dlb_id - (IN) DLB id. -1: new create, others: replace. 1750 * ecmp_member_bitmap - (IN) ECMP DLB members. 1751 * Returns: 1752 * BCM_E_xxx 1753 */ 1754 STATIC int 1755 _bcm_th2_ecmp_dlb_set(int unit, bcm_l3_egress_ecmp_t *ecmp, int intf_count, 1756 bcm_if_t *intf_array, int primary_count, int dlb_id, 1757 int *old_id, SHR_BITDCL *ecmp_member_bitmap) 1758 { 1759 int rv = BCM_E_NONE; 1760 int *port_array = NULL; 1761 #if defined(BCM_TOMAHAWK3_SUPPORT) 1762 int *ports = NULL; 1763 #endif 1764 soc_mem_t mem; 1765 int flowset_entry_size; 1766 int mflowset_entry_size; 1767 dlb_ecmp_flowset_entry_t *flowset_entry; 1768 dlb_ecmp_flowset_member_entry_t *mflowset_entry; 1769 int num_blocks; 1770 int total_blocks; 1771 int max_block_base_ptr; 1772 int block_base_ptr; 1773 int occupied; 1774 int entry_base_ptr; 1775 int num_entries_per_block; 1776 int port_map_width; 1777 int member_bitmap_width; 1778 int member_bitmap_bitdclsize = 0; 1779 int alloc_size; 1780 uint32 *block_ptr = NULL; 1781 uint32 *mblock_ptr = NULL; 1782 int i = 0, k = 0, j = 0; 1783 int index_min, index_max; 1784 int flow_set_size; 1785 int dlb_mode, primary_size = 0, primary_thd = 0; 1786 int cost = 0, bias = 0; 1787 SHR_BITDCL *port_map = NULL; 1788 SHR_BITDCL *port_map2 = NULL; 1789 SHR_BITDCL *member_bitmap = NULL; 1790 SHR_BITDCL *port_map_first_use = NULL; 1791 SHR_BITDCL *status_bitmap = NULL; 1792 SHR_BITDCL *override_bitmap = NULL; 1793 int ecmp_group_idx; 1794 int entry_size; 1795 int entries_per_profile; 1796 int port; 1797 #if defined(BCM_TOMAHAWK3_SUPPORT) 1798 int unique_intf_count = 0; 1799 #endif 1800 uint32 membership_pointer; 1801 uint32 base_addr = 0; 1802 ecmp_dlb_control_entry_t ecmp_dlb_control_entry; 1803 dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry; 1804 dlb_ecmp_group_membership_entry_t dlb_ecmp_group_membership_entry; 1805 dlb_ecmp_link_control_entry_t link_control_entry; 1806 #ifdef BCM_TRIDENT3_SUPPORT 1807 ecmp_count_entry_t ecmp_count_entry; 1808 #endif 1809 dlb_ecmp_group_port_to_member_entry_t *entry_arr = NULL; 1810 int *member_offset = NULL; 1811 int dlb_member_count = 0; /* Exclude filler member */ 1812 int location_offset = 0; 1813 #ifdef BCM_TOMAHAWK3_SUPPORT 1814 uint64 dlb_en_bitmap; 1815 int unique_primary_intf_count = 0; 1816 #endif 1817 1818 if (ecmp_member_bitmap == NULL) { 1819 return BCM_E_PARAM; 1820 } 1821 1822 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 1823 primary_size = primary_count; 1824 } else { 1825 primary_size = 0; 1826 } 1827 1828 if (dlb_id == -1) { 1829 /* Allocate a DLB ID */ 1830 BCM_IF_ERROR_RETURN( 1831 _bcm_th2_ecmp_dlb_id_alloc(unit, ecmp, &dlb_id)); 1832 } 1833 1834 /* Allocate port array */ 1835 port_array = sal_alloc(sizeof(int) * intf_count, 1836 "ECMP DLB Ports"); 1837 if (NULL == port_array) { 1838 rv = BCM_E_MEMORY; 1839 goto error; 1840 } 1841 sal_memset(port_array, 0, sizeof(int) * intf_count); 1842 1843 /* Allocate portmap first use */ 1844 port_map_width = soc_mem_field_length(unit, 1845 DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf); 1846 alloc_size = SHR_BITALLOCSIZE(port_map_width); 1847 port_map_first_use = sal_alloc(alloc_size, "DLB ECMP port map first use"); 1848 if (NULL == port_map_first_use) { 1849 rv = BCM_E_MEMORY; 1850 goto error; 1851 } 1852 sal_memset(port_map_first_use, 0, alloc_size); 1853 1854 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 1855 1856 rv = _bcm_th2_ecmp_dlb_port_array_get(unit, ecmp, dlb_id, 1857 primary_count, intf_count, 1858 intf_array, port_array, 1859 port_map_first_use, ecmp_member_bitmap); 1860 if (BCM_FAILURE(rv)) { 1861 goto error; 1862 } 1863 1864 if (!SHR_BITNULL_RANGE(port_map_first_use, 0, port_map_width)) { 1865 rv = READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0, 1866 &link_control_entry); 1867 if (BCM_FAILURE(rv)) { 1868 goto error; 1869 } 1870 /* Clear software status bitmap */ 1871 status_bitmap = sal_alloc(alloc_size, "DLB ECMP member status bitmap"); 1872 if (NULL == status_bitmap) { 1873 rv = BCM_E_MEMORY; 1874 goto error; 1875 } 1876 sal_memset(status_bitmap, 0, alloc_size); 1877 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, 1878 &link_control_entry, SW_PORT_STATEf, status_bitmap); 1879 SHR_BITREMOVE_RANGE(status_bitmap, port_map_first_use, 0, port_map_width, 1880 status_bitmap); 1881 soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, 1882 &link_control_entry, SW_PORT_STATEf, status_bitmap); 1883 1884 /* Clear software override bitmap */ 1885 override_bitmap = sal_alloc(alloc_size, "DLB ECMP member override bitmap"); 1886 if (NULL == override_bitmap) { 1887 rv = BCM_E_MEMORY; 1888 goto error; 1889 } 1890 sal_memset(override_bitmap, 0, alloc_size); 1891 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, 1892 &link_control_entry, SW_OVERRIDE_PORT_MAPf, 1893 override_bitmap); 1894 SHR_BITREMOVE_RANGE(override_bitmap, port_map_first_use, 0, port_map_width, 1895 override_bitmap); 1896 soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, 1897 &link_control_entry, SW_OVERRIDE_PORT_MAPf, 1898 override_bitmap); 1899 rv = WRITE_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ALL, 0, 1900 &link_control_entry); 1901 if (BCM_FAILURE(rv)) { 1902 goto error; 1903 } 1904 } 1905 1906 #if defined(BCM_TOMAHAWK3_SUPPORT) 1907 /* Allocate ports */ 1908 ports = sal_alloc(sizeof(int) * intf_count, 1909 "ECMP DLB Ports"); 1910 if (NULL == ports) { 1911 rv = BCM_E_MEMORY; 1912 goto error; 1913 } 1914 1915 sal_memset(ports, 0, sizeof(int) * intf_count); 1916 #endif 1917 1918 /* Allocate port map */ 1919 port_map_width = soc_mem_field_length(unit, 1920 DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf); 1921 alloc_size = SHR_BITALLOCSIZE(port_map_width); 1922 port_map = sal_alloc(alloc_size, "DLB ECMP port map"); 1923 if (NULL == port_map) { 1924 rv = BCM_E_MEMORY; 1925 goto error; 1926 } 1927 sal_memset(port_map, 0, alloc_size); 1928 1929 port_map2 = sal_alloc(alloc_size, "DLB ECMP port map 2"); 1930 if (NULL == port_map2) { 1931 rv = BCM_E_MEMORY; 1932 goto error; 1933 } 1934 sal_memset(port_map2, 0, alloc_size); 1935 1936 member_offset = sal_alloc(intf_count * sizeof(int), 1937 "dlb member offset array"); 1938 if (NULL == member_offset) { 1939 rv = BCM_E_MEMORY; 1940 goto error; 1941 } 1942 1943 sal_memset(member_offset, 0, intf_count * sizeof(int)); 1944 1945 /* Only alternate members exist , start from 0 instead of max_paths / 2 */ 1946 if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) && 1947 (primary_count == 0)) { 1948 location_offset = ecmp->max_paths / 2; 1949 } 1950 1951 /* Allocate member bitmap */ 1952 #if defined(BCM_TOMAHAWK3_SUPPORT) 1953 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 1954 int index = 0; 1955 bcm_if_t *intf_array_copy; 1956 1957 intf_array_copy = sal_alloc(intf_count * sizeof(int), 1958 "dlb member offset array"); 1959 1960 if (NULL == intf_array_copy) { 1961 rv = BCM_E_MEMORY; 1962 goto error; 1963 } 1964 1965 if (dlb_id < soc_reg_field_length(unit, 1966 DLB_ID_0_TO_63_ENABLEr, BITMAPf)) { 1967 rv = READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap); 1968 if (rv < 0) { 1969 goto error; 1970 } 1971 COMPILER_64_BITSET(dlb_en_bitmap, dlb_id); 1972 rv = WRITE_DLB_ID_0_TO_63_ENABLEr(unit, dlb_en_bitmap); 1973 if (rv < 0) { 1974 goto error; 1975 } 1976 } else { 1977 rv = READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap); 1978 if (rv < 0) { 1979 goto error; 1980 } 1981 COMPILER_64_BITSET(dlb_en_bitmap, (dlb_id - 1982 (soc_reg_field_length(unit, 1983 DLB_ID_0_TO_63_ENABLEr, BITMAPf)))); 1984 rv = WRITE_DLB_ID_64_TO_127_ENABLEr(unit, dlb_en_bitmap); 1985 if (rv < 0) { 1986 goto error; 1987 } 1988 } 1989 for (i = 0; i < intf_count; i++) { 1990 intf_array_copy[i] = intf_array[i]; 1991 if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) { 1992 continue; 1993 } 1994 /* Construct port_map */ 1995 port = port_array[i]; 1996 if ((ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) || 1997 (i < primary_size)) { 1998 SHR_BITSET(port_map, port); 1999 /* Construct member bitmap */ 2000 } else { 2001 SHR_BITSET(port_map2, port); 2002 /* Construct member bitmap */ 2003 } 2004 member_offset[j++] = i; 2005 } 2006 2007 _shr_sort(intf_array_copy, intf_count, sizeof(int), 2008 _bcm_th3_cmp_int); 2009 2010 index = 0; 2011 for (i = 1; i < intf_count; i++) { 2012 if (intf_array_copy[i] != intf_array_copy[index]) { 2013 index++; 2014 intf_array_copy[index] = intf_array_copy[i]; 2015 } 2016 } 2017 2018 rv = _bcm_th3_l3_ecmp_dlb_port_get(unit, ecmp, dlb_id, 2019 primary_count, intf_count, 2020 intf_array_copy, ports); 2021 2022 if (rv != BCM_E_NONE) { 2023 goto error; 2024 } 2025 for (i = 0; i < intf_count; i++) { 2026 if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) { 2027 continue; 2028 } 2029 if ((ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) || 2030 (i < primary_size)) { 2031 unique_primary_intf_count++; 2032 } 2033 unique_intf_count++; 2034 } 2035 if ((ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) && 2036 (unique_intf_count > primary_count)) { 2037 unique_intf_count = primary_count; 2038 } 2039 _bcm_th3_l3_ecmp_dlb_port_member_set(unit, ports, unique_primary_intf_count, unique_intf_count, dlb_id); 2040 _bcm_th3_l3_ecmp_dlb_nhi_member_set(unit, intf_array_copy, unique_primary_intf_count, unique_intf_count, dlb_id); 2041 } else 2042 #endif 2043 { 2044 member_bitmap_width = soc_mem_field_length(unit, 2045 DLB_ECMP_GROUP_PORT_TO_MEMBERm, ECMP_MEMBER_BITMAPf); 2046 member_bitmap_bitdclsize = _SHR_BITDCLSIZE(member_bitmap_width); 2047 2048 entries_per_profile = ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size; 2049 alloc_size = SHR_BITALLOCSIZE(member_bitmap_width) * entries_per_profile; 2050 member_bitmap = sal_alloc(alloc_size, "DLB ECMP member bitmap"); 2051 if (NULL == member_bitmap) { 2052 rv = BCM_E_MEMORY; 2053 goto error; 2054 } 2055 2056 sal_memset(member_bitmap, 0, alloc_size); 2057 2058 /* Fulfill member bitmaps */ 2059 for (i = 0; i < intf_count; i++) { 2060 if (!SHR_BITGET(ecmp_member_bitmap, i + location_offset)) { 2061 continue; 2062 } 2063 member_offset[j++] = i; 2064 /* Construct port_map */ 2065 port = port_array[i]; 2066 if (ecmp->dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM || i < primary_size) { 2067 SHR_BITSET(port_map, port); 2068 /* Construct member bitmap */ 2069 SHR_BITSET(&member_bitmap[member_bitmap_bitdclsize * port], i); 2070 } else { 2071 SHR_BITSET(port_map2, port); 2072 /* Construct member bitmap */ 2073 SHR_BITSET(&member_bitmap[member_bitmap_bitdclsize * port], 2074 (i - primary_size)); 2075 } 2076 } 2077 } 2078 2079 SHR_BITAND_RANGE(port_map, port_map2, 0, port_map_width, 2080 port_map_first_use); 2081 if (!SHR_BITNULL_RANGE(port_map_first_use, 0, port_map_width)) { 2082 /* the priamray and alternate port map should not overlap */ 2083 rv = BCM_E_PARAM; 2084 goto error; 2085 } 2086 2087 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 2088 /* Allocate entry array */ 2089 mem = DLB_ECMP_GROUP_PORT_TO_MEMBERm; 2090 entry_size = sizeof(dlb_ecmp_group_port_to_member_entry_t); 2091 entries_per_profile = ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size; 2092 alloc_size = entries_per_profile * entry_size; 2093 entry_arr = soc_cm_salloc(unit, alloc_size, 2094 "ECMP DLB Group Port To Member entries"); 2095 if (entry_arr == NULL) { 2096 rv = BCM_E_MEMORY; 2097 goto error; 2098 } 2099 sal_memset(entry_arr, 0, alloc_size); 2100 2101 /* Construct Port To Member entries */ 2102 SHR_BITOR_RANGE(port_map, port_map2, 0, port_map_width, 2103 port_map_first_use); 2104 2105 for (port = 0; port < entries_per_profile; port++) { 2106 if (SHR_BITGET(port_map_first_use, port)) { 2107 soc_DLB_ECMP_GROUP_PORT_TO_MEMBERm_field_set(unit, 2108 &entry_arr[port], 2109 ECMP_MEMBER_BITMAPf, 2110 &member_bitmap[member_bitmap_bitdclsize * port]); 2111 2112 /* dlb_count only count different DLBs, a ECMP group could have 2113 * 2 identical nexthops (same port, 1 node), 2114 * 1 different nexthop (same port, 1 node) 2115 * however, the 3 nexthops only contributes 2 count. 2116 */ 2117 } else { 2118 sal_memcpy(&entry_arr[port], 2119 soc_mem_entry_null(unit, mem), entry_size); 2120 } 2121 } 2122 2123 base_addr = dlb_id * entries_per_profile; 2124 index_max = base_addr + entries_per_profile - 1; 2125 rv = soc_mem_write_range(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm, MEM_BLOCK_ALL, 2126 base_addr, index_max, entry_arr); 2127 if (BCM_FAILURE(rv)) { 2128 goto error; 2129 } 2130 } 2131 2132 /* Construct membership entry */ 2133 membership_pointer = dlb_id; 2134 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_set(unit, 2135 &dlb_ecmp_group_membership_entry, 2136 PORT_MAPf, 2137 port_map); 2138 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_set(unit, 2139 &dlb_ecmp_group_membership_entry, 2140 PORT_MAP_ALTERNATEf, 2141 port_map2); 2142 rv = WRITE_DLB_ECMP_GROUP_MEMBERSHIPm(unit, 2143 MEM_BLOCK_ALL, 2144 membership_pointer, 2145 &dlb_ecmp_group_membership_entry); 2146 2147 if (BCM_FAILURE(rv)) { 2148 goto error; 2149 } 2150 2151 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 2152 rv = READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY, ecmp_group_idx, 2153 &ecmp_dlb_control_entry); 2154 if (BCM_FAILURE(rv)) { 2155 goto error; 2156 } 2157 } 2158 2159 /* Set ECMP DLB group control table */ 2160 if (old_id == NULL) { /* not replace */ 2161 sal_memset(&dlb_ecmp_group_control_entry, 0, 2162 sizeof(dlb_ecmp_group_control_entry_t)); 2163 } else { 2164 #if defined(BCM_TOMAHAWK3_SUPPORT) 2165 if ((soc_feature(unit, soc_feature_th3_style_dlb))) { 2166 *old_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx); 2167 } else 2168 #endif 2169 { 2170 *old_id = soc_ECMP_DLB_CONTROLm_field32_get 2171 (unit, &ecmp_dlb_control_entry, DLB_IDf); 2172 } 2173 rv = READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, *old_id, 2174 &dlb_ecmp_group_control_entry); 2175 if (BCM_FAILURE(rv)) { 2176 goto error; 2177 } 2178 } 2179 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 2180 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2181 GROUP_PORT_TO_MEMBER_BASE_ADDRf, base_addr); 2182 } 2183 2184 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2185 GROUP_MEMBERSHIP_POINTERf, membership_pointer); 2186 2187 if (old_id == NULL) { /* not replace */ 2188 /* Find a contiguous region in flow set table. 2189 * A better practice would be: make this 2 sub-routies: alloc and free. 2190 * And do the alloc ahead of time, to make sure the resource is available. 2191 */ 2192 2193 #ifdef BCM_TRIDENT3_SUPPORT 2194 if (soc_feature(unit, soc_feature_td3_dlb)){ 2195 if (soc_mem_index_count(unit, DLB_ECMP_FLOWSETm)) { 2196 rv = soc_reg_field32_modify( 2197 unit, ENHANCED_HASHING_CONTROLr, REG_PORT_ANY, 2198 RH_DLB_SELECTIONf, 0); 2199 if (BCM_FAILURE(rv)) { 2200 goto error; 2201 } 2202 } 2203 } 2204 #endif 2205 flowset_entry_size = sizeof(dlb_ecmp_flowset_entry_t); 2206 mflowset_entry_size = sizeof(dlb_ecmp_flowset_member_entry_t); 2207 num_blocks = ecmp->dynamic_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 2208 total_blocks = soc_mem_index_count(unit, DLB_ECMP_FLOWSETm) >> 2209 _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 2210 max_block_base_ptr = total_blocks - num_blocks; 2211 for (block_base_ptr = 0; 2212 block_base_ptr <= max_block_base_ptr; 2213 block_base_ptr++) { 2214 /* Check if the contiguous region of flow set table from 2215 * block_base_ptr to (block_base_ptr + num_blocks - 1) is free. 2216 */ 2217 _BCM_ECMP_DLB_FLOWSET_BLOCK_TEST_RANGE(unit, block_base_ptr, num_blocks, 2218 occupied); 2219 if (!occupied) { 2220 break; 2221 } 2222 } 2223 if (block_base_ptr > max_block_base_ptr) { 2224 /* A contiguous region of the desired size could not be found in 2225 * flow set table. 2226 */ 2227 rv = BCM_E_RESOURCE; 2228 goto error; 2229 } 2230 2231 /* Set DLB flow set table */ 2232 entry_base_ptr = block_base_ptr << _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 2233 num_entries_per_block = 1 << _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 2234 alloc_size = num_entries_per_block * flowset_entry_size; 2235 block_ptr = soc_cm_salloc(unit, alloc_size, 2236 "Block of DLB_ECMP_FLOWSET entries"); 2237 if (NULL == block_ptr) { 2238 rv = BCM_E_MEMORY; 2239 goto error; 2240 } 2241 sal_memset(block_ptr, 0, alloc_size); 2242 2243 alloc_size = num_entries_per_block * mflowset_entry_size; 2244 mblock_ptr = soc_cm_salloc(unit, alloc_size, 2245 "Block of DLB_ECMP_FLOWSET_MEMBER entries"); 2246 if (NULL == mblock_ptr) { 2247 rv = BCM_E_MEMORY; 2248 goto error; 2249 } 2250 sal_memset(mblock_ptr, 0, alloc_size); 2251 2252 /* Reset ECMP count excluding filler members */ 2253 SHR_BITCOUNT_RANGE(ecmp_member_bitmap, dlb_member_count, 2254 0, ecmp->max_paths); 2255 2256 for (i = 0; i < num_blocks; i++) { 2257 for (k = 0; k < num_entries_per_block; k++) { 2258 flowset_entry = soc_mem_table_idx_to_pointer(unit, 2259 DLB_ECMP_FLOWSETm, dlb_ecmp_flowset_entry_t *, 2260 block_ptr, k); 2261 mflowset_entry = soc_mem_table_idx_to_pointer(unit, 2262 DLB_ECMP_FLOWSET_MEMBERm, dlb_ecmp_flowset_member_entry_t *, 2263 mblock_ptr, k); 2264 if (dlb_member_count > 0) { 2265 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry, 2266 VALIDf, 1); 2267 j = (i * num_entries_per_block + k) % dlb_member_count; 2268 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry, 2269 PORT_MEMBER_ASSIGNMENTf, 2270 port_array[member_offset[j]]); 2271 if (member_offset[j] < primary_count) { 2272 soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set( 2273 unit, mflowset_entry, 2274 ECMP_MEMBER_ASSIGNMENTf, member_offset[j]); 2275 soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set( 2276 unit, mflowset_entry, 2277 ECMP_MEMBER_IS_ALTERNATEf, 0); 2278 } else { 2279 soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set( 2280 unit, mflowset_entry, ECMP_MEMBER_ASSIGNMENTf, 2281 member_offset[j] - primary_count); 2282 soc_DLB_ECMP_FLOWSET_MEMBERm_field32_set( 2283 unit, mflowset_entry, 2284 ECMP_MEMBER_IS_ALTERNATEf, 1); 2285 } 2286 } else { 2287 soc_DLB_ECMP_FLOWSETm_field32_set(unit, flowset_entry, 2288 VALIDf, 0); 2289 } 2290 } 2291 index_min = entry_base_ptr + i * num_entries_per_block; 2292 index_max = index_min + num_entries_per_block - 1; 2293 rv = soc_mem_write_range(unit, DLB_ECMP_FLOWSETm, MEM_BLOCK_ALL, 2294 index_min, index_max, block_ptr); 2295 if (BCM_FAILURE(rv)) { 2296 goto error; 2297 } 2298 rv = soc_mem_write_range(unit, DLB_ECMP_FLOWSET_MEMBERm, MEM_BLOCK_ALL, 2299 index_min, index_max, mblock_ptr); 2300 if (BCM_FAILURE(rv)) { 2301 goto error; 2302 } 2303 } 2304 _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, num_blocks); 2305 2306 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2307 ENABLE_OPTIMAL_CANDIDATE_UPDATEf, 1); 2308 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2309 FLOW_SET_BASEf, entry_base_ptr); 2310 rv = _bcm_th2_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size, 2311 &flow_set_size); 2312 if (BCM_FAILURE(rv)) { 2313 goto error; 2314 } 2315 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2316 FLOW_SET_SIZEf, flow_set_size); 2317 #ifdef BCM_TRIDENT3_SUPPORT 2318 if (soc_feature(unit, soc_feature_td3_dlb)) { 2319 ecmp_grp_enhanced_hashing[unit][ecmp_group_idx] = 1; 2320 } 2321 #endif 2322 } 2323 switch (ecmp->dynamic_mode) { 2324 case BCM_L3_ECMP_DYNAMIC_MODE_DGM: 2325 primary_thd = ecmp->dgm.threshold; 2326 cost = ecmp->dgm.cost; 2327 bias = ecmp->dgm.bias; 2328 dlb_mode = 0; 2329 break; 2330 case BCM_L3_ECMP_DYNAMIC_MODE_NORMAL: 2331 dlb_mode = 0; 2332 break; 2333 case BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED: 2334 dlb_mode = 1; 2335 break; 2336 case BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL: 2337 dlb_mode = 2; 2338 break; 2339 default: 2340 rv = BCM_E_PARAM; 2341 goto error; 2342 } 2343 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2344 PORT_ASSIGNMENT_MODEf, dlb_mode); 2345 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2346 PRIMARY_GROUP_SIZEf, primary_size); 2347 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2348 PRIMARY_PATH_THRESHOLDf, primary_thd); 2349 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2350 ALTERNATE_PATH_COSTf, cost); 2351 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2352 ALTERNATE_PATH_BIASf, bias); 2353 soc_DLB_ECMP_GROUP_CONTROLm_field32_set(unit, &dlb_ecmp_group_control_entry, 2354 INACTIVITY_DURATIONf, ecmp->dynamic_age); 2355 rv = WRITE_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ALL, dlb_id, 2356 &dlb_ecmp_group_control_entry); 2357 if (BCM_FAILURE(rv)) { 2358 goto error; 2359 } 2360 2361 /* Update ECMP DLB control table */ 2362 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 2363 soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry, GROUP_ENABLEf, 1); 2364 soc_ECMP_DLB_CONTROLm_field32_set(unit, &ecmp_dlb_control_entry, DLB_IDf, dlb_id); 2365 rv = WRITE_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ALL, ecmp_group_idx, 2366 &ecmp_dlb_control_entry); 2367 if (BCM_FAILURE(rv)) { 2368 goto error; 2369 } 2370 } 2371 #ifdef BCM_TRIDENT3_SUPPORT 2372 if (soc_feature(unit, soc_feature_td3_dlb)) { 2373 rv = READ_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry); 2374 if (BCM_FAILURE(rv)) { 2375 goto error; 2376 } 2377 soc_L3_ECMP_COUNTm_field32_set(unit, &ecmp_count_entry, LB_MODEf, 0x4); 2378 rv = WRITE_L3_ECMP_COUNTm(unit, MEM_BLOCK_ANY, ecmp_group_idx, &ecmp_count_entry); 2379 if (BCM_FAILURE(rv)) { 2380 goto error; 2381 } 2382 } 2383 #endif 2384 if (NULL != status_bitmap) { 2385 sal_free(status_bitmap); 2386 } 2387 if (NULL != override_bitmap) { 2388 sal_free(override_bitmap); 2389 } 2390 sal_free(port_array); 2391 sal_free(port_map); 2392 sal_free(port_map2); 2393 sal_free(member_offset); 2394 if (member_bitmap) { 2395 sal_free(member_bitmap); 2396 } 2397 if (entry_arr) { 2398 soc_cm_sfree(unit, entry_arr); 2399 } 2400 sal_free(port_map_first_use); 2401 if (block_ptr) { 2402 soc_cm_sfree(unit, block_ptr); 2403 } 2404 if (mblock_ptr) { 2405 soc_cm_sfree(unit, mblock_ptr); 2406 } 2407 2408 #if defined(BCM_TOMAHAWK3_SUPPORT) 2409 if (ports) { 2410 sal_free(ports); 2411 } 2412 #endif 2413 return BCM_E_NONE; 2414 2415 error: 2416 if (dlb_id != -1) { 2417 _bcm_th2_ecmp_dlb_id_free(unit, dlb_id); 2418 } 2419 if (NULL != port_array) { 2420 sal_free(port_array); 2421 } 2422 if (NULL != port_map_first_use) { 2423 sal_free(port_map_first_use); 2424 } 2425 if (NULL != block_ptr) { 2426 soc_cm_sfree(unit, block_ptr); 2427 } 2428 if (NULL != mblock_ptr) { 2429 soc_cm_sfree(unit, mblock_ptr); 2430 } 2431 if (NULL != port_map) { 2432 sal_free(port_map); 2433 } 2434 if (NULL != port_map2) { 2435 sal_free(port_map2); 2436 } 2437 if (NULL != member_bitmap) { 2438 sal_free(member_bitmap); 2439 } 2440 if (NULL != member_offset) { 2441 sal_free(member_offset); 2442 } 2443 if (NULL != entry_arr) { 2444 soc_cm_sfree(unit, entry_arr); 2445 } 2446 if (NULL != status_bitmap) { 2447 sal_free(status_bitmap); 2448 } 2449 if (NULL != override_bitmap) { 2450 sal_free(override_bitmap); 2451 } 2452 #if defined(BCM_TOMAHAWK3_SUPPORT) 2453 if (NULL != ports) { 2454 sal_free(ports); 2455 } 2456 #endif 2457 return rv; 2458 } 2459 /* 2460 * Function: 2461 * bcm_th2_l3_egress_ecmp_dlb_create 2462 * Purpose: 2463 * Create ECMP DLB group. 2464 * Parameters: 2465 * unit - (IN) bcm device. 2466 * ecmp - (IN) ECMP group info. 2467 * intf_count - (IN) Number of elements in intf_array. 2468 * intf_array - (IN) Array of Egress forwarding objects. 2469 * ecmp_member_bitmap - (IN) ECMP DLB members. 2470 * Returns: 2471 * BCM_E_XXX 2472 */ 2473 int 2474 bcm_th2_l3_egress_ecmp_dlb_create(int unit, bcm_l3_egress_ecmp_t *ecmp, 2475 int intf_count, bcm_if_t *intf_array, 2476 int primary_count, 2477 SHR_BITDCL *dlb_member_bitmap) 2478 { 2479 int dlb_enable; 2480 int dynamic_size_encode; 2481 int ecmp_group_idx; 2482 uint32 hw_limit; 2483 SHR_BITDCL *group_bitmap_ptr = NULL; 2484 2485 bcm_l3_egress_ecmp_t dlb_ecmp; 2486 int dlb_ecmp_count = 0; 2487 2488 if (BCM_TH2_ECMP_IS_DLB_OR_DGM(unit, ecmp->dynamic_mode)) { 2489 dlb_enable = 1; 2490 } else { 2491 dlb_enable = 0; 2492 } 2493 2494 if (dlb_enable) { 2495 /* Verify dynamic_size */ 2496 BCM_IF_ERROR_RETURN 2497 (_bcm_th2_ecmp_dlb_dynamic_size_encode(ecmp->dynamic_size, 2498 &dynamic_size_encode)); 2499 2500 /* Verify dynamic_age */ 2501 hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GROUP_CONTROLm, 2502 INACTIVITY_DURATIONf)) - 1; 2503 if (ecmp->dynamic_age < 16 || 2504 ecmp->dynamic_age > hw_limit) { 2505 /* Hardware limits */ 2506 return BCM_E_PARAM; 2507 } 2508 2509 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 2510 if (primary_count > intf_count) { 2511 return BCM_E_PARAM; 2512 } 2513 hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GROUP_CONTROLm, 2514 PRIMARY_PATH_THRESHOLDf)) - 1; 2515 2516 if (ecmp->dgm.threshold > hw_limit) { 2517 return BCM_E_PARAM; 2518 } 2519 hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GROUP_CONTROLm, 2520 ALTERNATE_PATH_COSTf)) - 1; 2521 2522 if (ecmp->dgm.cost > hw_limit || 2523 ecmp->dgm.bias > hw_limit) { 2524 return BCM_E_PARAM; 2525 } 2526 } 2527 } 2528 2529 /* Free resources associated with old DLB group, if exists */ 2530 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 2531 2532 if (ecmp->flags & BCM_L3_REPLACE) { 2533 2534 #if defined(BCM_TOMAHAWK3_SUPPORT) 2535 if ((!dlb_enable) && (soc_feature(unit, soc_feature_th3_style_dlb))) { 2536 return BCM_E_NONE; 2537 } 2538 #endif 2539 2540 bcm_l3_egress_ecmp_t_init(&dlb_ecmp); 2541 dlb_ecmp.ecmp_intf = ecmp->ecmp_intf; 2542 BCM_IF_ERROR_RETURN( 2543 _bcm_esw_l3_egress_ecmp_get(unit, &dlb_ecmp, 0, NULL, 2544 &dlb_ecmp_count, TRUE)); 2545 if (dlb_enable /* also indicates it was created before */ 2546 && dlb_ecmp.dynamic_mode == ecmp->dynamic_mode 2547 && dlb_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED 2548 && dlb_ecmp.dynamic_size == ecmp->dynamic_size) { 2549 int old_id = 0, dlb_id; 2550 2551 /* Do new style replace only if free resources left */ 2552 if (BCM_E_NONE == _bcm_th2_ecmp_dlb_id_alloc( 2553 unit, ecmp, &dlb_id)) { 2554 if ((soc_feature(unit, soc_feature_th3_style_dlb))) { 2555 BCM_IF_ERROR_RETURN( 2556 _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx, 2557 old_id, FALSE)); 2558 } 2559 BCM_IF_ERROR_RETURN( 2560 _bcm_th2_ecmp_dlb_set(unit, ecmp, intf_count, intf_array, 2561 primary_count, dlb_id, 2562 &old_id, dlb_member_bitmap)); 2563 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 2564 BCM_IF_ERROR_RETURN( 2565 _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx, 2566 old_id, FALSE)); 2567 } 2568 return BCM_E_NONE; 2569 } 2570 } 2571 } 2572 2573 #ifdef BCM_TOMAHAWK3_SUPPORT 2574 if (soc_feature(unit, soc_feature_th3_style_dlb) && 2575 (ecmp->flags & BCM_L3_REPLACE)) { 2576 int dlb_num, rv = 0; 2577 dlb_num = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp->ecmp_intf 2578 - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit)); 2579 2580 /* If the dynamic size for the new dlb id is greater than the one 2581 being replaced and also greater than the FLOWSET block size (256), 2582 we need to check if we have enough free resources 2583 for the extra size. If we do have free resources, we go ahead 2584 and clean up the old dlb id. Otherwise, we do not clean up and 2585 this way we do not destroy the old dlb id when replace fails 2586 */ 2587 if (ecmp->dynamic_size > dlb_ecmp.dynamic_size && 2588 ecmp->dynamic_size > (1 << _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT)) { 2589 rv = _bcm_th3_l3_egress_ecmp_dlb_resource_validate(unit, ecmp, 2590 dlb_num); 2591 } 2592 2593 if ((rv == BCM_E_NONE)) { 2594 BCM_IF_ERROR_RETURN( 2595 _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx, -1, TRUE)); 2596 } else { 2597 return rv; 2598 } 2599 } else 2600 #endif 2601 { 2602 BCM_IF_ERROR_RETURN( 2603 _bcm_th2_ecmp_dlb_free_resource(unit, ecmp_group_idx, -1, TRUE)); 2604 } 2605 2606 if (dlb_enable) { 2607 /* Set new DLB group */ 2608 BCM_IF_ERROR_RETURN( 2609 _bcm_th2_ecmp_dlb_set(unit, ecmp, intf_count, intf_array, 2610 primary_count, -1, NULL, dlb_member_bitmap)); 2611 } else { 2612 /* Clear DLB bitmap */ 2613 group_bitmap_ptr = 2614 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 2615 SHR_BITCLR_RANGE(group_bitmap_ptr, 0, 2616 BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2); 2617 } 2618 2619 return BCM_E_NONE; 2620 } 2621 2622 /* 2623 * Function: 2624 * bcm_th2_l3_egress_ecmp_dlb_destroy 2625 * Purpose: 2626 * Destroy an ECMP DLB group. 2627 * Parameters: 2628 * unit - (IN) bcm device. 2629 * mpintf - (IN) L3 interface id pointing to Egress multipath object. 2630 * Returns: 2631 * BCM_E_XXX 2632 */ 2633 int 2634 bcm_th2_l3_egress_ecmp_dlb_destroy(int unit, bcm_if_t mpintf) 2635 { 2636 int ecmp_group_idx; 2637 SHR_BITDCL *group_bitmap_ptr = NULL; 2638 2639 /* Free resources associated with old DLB group, if exists */ 2640 ecmp_group_idx = mpintf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 2641 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_free_resource(unit, 2642 ecmp_group_idx, -1, TRUE)); 2643 /* Clear DLB bitmap */ 2644 group_bitmap_ptr = 2645 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 2646 SHR_BITCLR_RANGE(group_bitmap_ptr, 0, 2647 BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2); 2648 return BCM_E_NONE; 2649 } 2650 2651 /* 2652 * Function: 2653 * bcm_th2_l3_egress_ecmp_dlb_get 2654 * Purpose: 2655 * Get info about an ECMP DLB group. 2656 * Parameters: 2657 * unit - (IN) bcm device. 2658 * ecmp - (IN/OUT) ECMP group info. 2659 * Returns: 2660 * BCM_E_XXX 2661 */ 2662 int 2663 bcm_th2_l3_egress_ecmp_dlb_get(int unit, bcm_l3_egress_ecmp_t *ecmp) 2664 { 2665 int ecmp_group_idx; 2666 ecmp_dlb_control_entry_t ecmp_group_entry; 2667 int group_enable, dlb_id; 2668 dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry; 2669 int dlb_mode, primary_size, primary_thd, cost, bias; 2670 int flow_set_size; 2671 2672 /* Get DLB ID */ 2673 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 2674 2675 ecmp->dynamic_mode = 0; 2676 ecmp->dynamic_size = 0; 2677 ecmp->dynamic_age = 0; 2678 ecmp->dgm.threshold = 0; 2679 ecmp->dgm.cost = 0; 2680 ecmp->dgm.bias = 0; 2681 2682 #if defined(BCM_TOMAHAWK3_SUPPORT) 2683 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 2684 if (ecmp_group_idx < BCM_TH3_L3_ECMP_DLB_START(unit)) { 2685 return BCM_E_NONE; 2686 } 2687 dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx); 2688 } else 2689 #endif 2690 { 2691 BCM_IF_ERROR_RETURN(READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY, 2692 ecmp_group_idx, &ecmp_group_entry)); 2693 group_enable = soc_ECMP_DLB_CONTROLm_field32_get(unit, 2694 &ecmp_group_entry, 2695 GROUP_ENABLEf); 2696 if (!group_enable) { 2697 return BCM_E_NONE; 2698 } 2699 dlb_id = soc_ECMP_DLB_CONTROLm_field32_get(unit, 2700 &ecmp_group_entry, DLB_IDf); 2701 } 2702 2703 /* Get dynamic_mode */ 2704 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, 2705 dlb_id, &dlb_ecmp_group_control_entry)); 2706 dlb_mode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 2707 &dlb_ecmp_group_control_entry, PORT_ASSIGNMENT_MODEf); 2708 primary_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 2709 &dlb_ecmp_group_control_entry, PRIMARY_GROUP_SIZEf); 2710 primary_thd = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 2711 &dlb_ecmp_group_control_entry, PRIMARY_PATH_THRESHOLDf); 2712 cost = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 2713 &dlb_ecmp_group_control_entry, ALTERNATE_PATH_COSTf); 2714 bias = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 2715 &dlb_ecmp_group_control_entry, ALTERNATE_PATH_BIASf); 2716 switch (dlb_mode) { 2717 case 0: 2718 if (primary_size == 0 && 2719 !_BCM_ECMP_DLB_ID_DGM_GET(unit, dlb_id)) { 2720 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_NORMAL; 2721 } else { 2722 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_DGM; 2723 ecmp->dgm.threshold = primary_thd; 2724 ecmp->dgm.cost = cost; 2725 ecmp->dgm.bias = bias; 2726 } 2727 /* In L1 warmboot, empty group's dgm mode cannot be recovered */ 2728 #ifdef BCM_WARM_BOOT_SUPPORT 2729 if (SOC_WARM_BOOT(unit)) { 2730 if (!ECMP_DLB_INFO(unit)->recovered_from_scache && 2731 ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 2732 /* If already recovered from scache, do nothing. */ 2733 _BCM_ECMP_DLB_ID_DGM_SET(unit, dlb_id); 2734 } 2735 } 2736 #endif /* BCM_WARM_BOOT_SUPPORT */ 2737 2738 break; 2739 case 1: 2740 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED; 2741 break; 2742 case 2: 2743 ecmp->dynamic_mode = BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL; 2744 break; 2745 default: 2746 return BCM_E_INTERNAL; 2747 } 2748 2749 /* Get dynamic_size */ 2750 flow_set_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 2751 &dlb_ecmp_group_control_entry, FLOW_SET_SIZEf); 2752 BCM_IF_ERROR_RETURN 2753 (_bcm_th2_ecmp_dlb_dynamic_size_decode(flow_set_size, 2754 (int *)&ecmp->dynamic_size)); 2755 2756 /* Get dynamic_age */ 2757 ecmp->dynamic_age = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 2758 &dlb_ecmp_group_control_entry, INACTIVITY_DURATIONf); 2759 2760 return BCM_E_NONE; 2761 } 2762 2763 /* 2764 * Function: 2765 * _bcm_th2_l3_egress_ecmp_port_status_set 2766 * Purpose: 2767 * Set ECMP DLB port status. 2768 * Parameters: 2769 * unit - (IN) SOC unit number. 2770 * port - (IN) Port, not Gport. 2771 * status - (IN) ECMP port status. 2772 * Returns: 2773 * BCM_E_xxx 2774 */ 2775 int 2776 _bcm_th2_l3_egress_ecmp_port_status_set(int unit, bcm_port_t port, int status) 2777 { 2778 dlb_ecmp_link_control_entry_t link_control_entry; 2779 int status_width, alloc_size; 2780 SHR_BITDCL *status_bitmap = NULL; 2781 SHR_BITDCL *override_bitmap = NULL; 2782 int rv = BCM_E_NONE; 2783 2784 soc_mem_lock(unit, DLB_ECMP_LINK_CONTROLm); 2785 /* Get status bitmap */ 2786 rv = READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0, 2787 &link_control_entry); 2788 if (BCM_FAILURE(rv)) { 2789 soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm); 2790 return rv; 2791 } 2792 status_width = soc_mem_field_length(unit, DLB_ECMP_LINK_CONTROLm, 2793 SW_PORT_STATEf); 2794 alloc_size = SHR_BITALLOCSIZE(status_width); 2795 status_bitmap = sal_alloc(alloc_size, "DLB ECMP port status bitmap"); 2796 if (NULL == status_bitmap) { 2797 soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm); 2798 return BCM_E_MEMORY; 2799 } 2800 sal_memset(status_bitmap, 0, alloc_size); 2801 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry, 2802 SW_PORT_STATEf, status_bitmap); 2803 2804 /* Get override bitmap */ 2805 override_bitmap = sal_alloc(alloc_size, "DLB ECMP port override bitmap"); 2806 if (NULL == override_bitmap) { 2807 soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm); 2808 sal_free(status_bitmap); 2809 return BCM_E_MEMORY; 2810 } 2811 sal_memset(override_bitmap, 0, alloc_size); 2812 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry, 2813 SW_OVERRIDE_PORT_MAPf, override_bitmap); 2814 2815 /* Update status and override bitmaps*/ 2816 2817 switch (status) { 2818 case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN: 2819 SHR_BITSET(override_bitmap, port); 2820 SHR_BITCLR(status_bitmap, port); 2821 break; 2822 case BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP: 2823 SHR_BITSET(override_bitmap, port); 2824 SHR_BITSET(status_bitmap, port); 2825 break; 2826 case BCM_L3_ECMP_DYNAMIC_MEMBER_HW: 2827 SHR_BITCLR(override_bitmap, port); 2828 SHR_BITCLR(status_bitmap, port); 2829 break; 2830 default: 2831 sal_free(status_bitmap); 2832 sal_free(override_bitmap); 2833 soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm); 2834 return BCM_E_PARAM; 2835 } 2836 2837 /* Write status and override bitmaps to hardware */ 2838 soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, &link_control_entry, 2839 SW_PORT_STATEf, status_bitmap); 2840 soc_DLB_ECMP_LINK_CONTROLm_field_set(unit, &link_control_entry, 2841 SW_OVERRIDE_PORT_MAPf, override_bitmap); 2842 sal_free(status_bitmap); 2843 sal_free(override_bitmap); 2844 rv = WRITE_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ALL, 0, 2845 &link_control_entry); 2846 2847 soc_mem_unlock(unit, DLB_ECMP_LINK_CONTROLm); 2848 return rv; 2849 } 2850 2851 /* 2852 * Function: 2853 * _bcm_th2_l3_egress_ecmp_port_status_get 2854 * Purpose: 2855 * Get ECMP DLB port status. 2856 * Parameters: 2857 * unit - (IN) SOC unit number. 2858 * port - (IN) Port, not Gport. 2859 * status - (OUT) ECMP port status. 2860 * Returns: 2861 * BCM_E_xxx 2862 */ 2863 int 2864 _bcm_th2_l3_egress_ecmp_port_status_get(int unit, bcm_port_t port, int *status) 2865 { 2866 int rv = BCM_E_NONE; 2867 dlb_ecmp_link_control_entry_t link_control_entry; 2868 int status_width, alloc_size; 2869 SHR_BITDCL *status_bitmap = NULL; 2870 SHR_BITDCL *override_bitmap = NULL; 2871 SHR_BITDCL *hw_status_bitmap = NULL; 2872 dlb_ecmp_port_state_entry_t hw_state; 2873 2874 /* Get status bitmap */ 2875 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_LINK_CONTROLm(unit, MEM_BLOCK_ANY, 0, 2876 &link_control_entry)); 2877 status_width = soc_mem_field_length(unit, DLB_ECMP_LINK_CONTROLm, 2878 SW_PORT_STATEf); 2879 alloc_size = SHR_BITALLOCSIZE(status_width); 2880 status_bitmap = sal_alloc(alloc_size, "DLB ECMP port status bitmap"); 2881 if (NULL == status_bitmap) { 2882 return BCM_E_MEMORY; 2883 } 2884 sal_memset(status_bitmap, 0, alloc_size); 2885 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry, 2886 SW_PORT_STATEf, status_bitmap); 2887 2888 /* Get override bitmap */ 2889 override_bitmap = sal_alloc(alloc_size, "DLB ECMP port override bitmap"); 2890 if (NULL == override_bitmap) { 2891 sal_free(status_bitmap); 2892 return BCM_E_MEMORY; 2893 } 2894 sal_memset(override_bitmap, 0, alloc_size); 2895 soc_DLB_ECMP_LINK_CONTROLm_field_get(unit, &link_control_entry, 2896 SW_OVERRIDE_PORT_MAPf, override_bitmap); 2897 2898 /* Derive status from software override and status bitmaps or 2899 * hardware state bitmap. 2900 */ 2901 if (SHR_BITGET(override_bitmap, port)) { 2902 if (SHR_BITGET(status_bitmap, port)) { 2903 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_UP; 2904 } else { 2905 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_FORCE_DOWN; 2906 } 2907 } else { 2908 /* Get hardware bitmap */ 2909 hw_status_bitmap = sal_alloc(alloc_size, "DLB ECMP member hw status bitmap"); 2910 if (NULL == hw_status_bitmap) { 2911 sal_free(status_bitmap); 2912 sal_free(override_bitmap); 2913 return BCM_E_MEMORY; 2914 } 2915 sal_memset(hw_status_bitmap, 0, alloc_size); 2916 2917 rv = READ_DLB_ECMP_PORT_STATEm(unit, MEM_BLOCK_ANY, 0, &hw_state); 2918 if (BCM_FAILURE(rv)) { 2919 sal_free(status_bitmap); 2920 sal_free(override_bitmap); 2921 sal_free(hw_status_bitmap); 2922 return rv; 2923 } 2924 soc_DLB_ECMP_PORT_STATEm_field_get(unit, &hw_state, 2925 BITMAPf, hw_status_bitmap); 2926 if (SHR_BITGET(hw_status_bitmap, port)) { 2927 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_UP; 2928 } else { 2929 *status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW_DOWN; 2930 } 2931 } 2932 2933 /* Cleanup */ 2934 sal_free(status_bitmap); 2935 sal_free(override_bitmap); 2936 if (NULL != hw_status_bitmap) { 2937 sal_free(hw_status_bitmap); 2938 } 2939 2940 return BCM_E_NONE; 2941 } 2942 2943 2944 /* 2945 * Function: 2946 * bcm_th2_l3_egress_ecmp_member_status_set 2947 * Purpose: 2948 * Set ECMP DLB member status. 2949 * Parameters: 2950 * unit - (IN) SOC unit number. 2951 * intf - (IN) L3 Interface ID pointing to an Egress forwarding object. 2952 * status - (IN) ECMP member status. 2953 * Returns: 2954 * BCM_E_xxx 2955 */ 2956 int 2957 bcm_th2_l3_egress_ecmp_member_status_set(int unit, bcm_if_t intf, int status) 2958 { 2959 int nh_index; 2960 int old_status; 2961 int mod = 0, port; 2962 int is_local; 2963 ing_l3_next_hop_entry_t ing_nh_entry; 2964 _th2_ecmp_dlb_port_membership_t *current_ptr; 2965 #ifdef BCM_TRIDENT3_SUPPORT 2966 uint32 dt, dv; 2967 #endif 2968 2969 /* Derive next hop index */ 2970 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 2971 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 2972 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 2973 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 2974 } else { 2975 return BCM_E_PARAM; 2976 } 2977 2978 /* Derive port from nh_index */ 2979 BCM_IF_ERROR_RETURN(READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, 2980 nh_index, &ing_nh_entry)); 2981 2982 #ifdef BCM_TRIDENT3_SUPPORT 2983 if (soc_feature(unit, soc_feature_generic_dest)) { 2984 dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry, 2985 DESTINATIONf, &dt); 2986 if (dt == SOC_MEM_FIF_DEST_LAG) { 2987 /* Next hop correspond to Trunk group */ 2988 return BCM_E_CONFIG; 2989 } else if (dt == SOC_MEM_FIF_DEST_DGPP) { 2990 mod = (dv & SOC_MEM_FIF_DGPP_MOD_ID_MASK) >> 2991 SOC_MEM_FIF_DGPP_MOD_ID_SHIFT_BITS; 2992 port = dv & SOC_MEM_FIF_DGPP_PORT_MASK; 2993 } else { 2994 return BCM_E_PARAM; 2995 } 2996 } else 2997 #endif 2998 { 2999 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, Tf)) { 3000 /* Next hop should correspond to a single physical port. */ 3001 return BCM_E_CONFIG; 3002 } 3003 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 3004 mod = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 3005 MODULE_IDf); 3006 } 3007 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 3008 PORT_NUMf); 3009 } 3010 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 3011 (void) _bcm_esw_modid_is_local(unit, mod, &is_local); 3012 if (!is_local) { 3013 return BCM_E_PARAM; 3014 } 3015 } 3016 3017 /* Verify that the nh_index is with DLB arrtibutes. */ 3018 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 3019 while (current_ptr) { 3020 if (nh_index == current_ptr->nh_index && 3021 current_ptr->dlb_id != -1) { 3022 break; 3023 } 3024 current_ptr = current_ptr->next; 3025 } 3026 3027 if (current_ptr == NULL) { 3028 return BCM_E_NOT_FOUND; 3029 } 3030 3031 if (!ECMP_DLB_INFO(unit)->ecmp_dlb_property_force_set && 3032 ECMP_DLB_PORT_INFO(unit, port).nh_count > 1) { 3033 BCM_IF_ERROR_RETURN 3034 (_bcm_th2_l3_egress_ecmp_port_status_get(unit, port, &old_status)); 3035 3036 if (old_status == BCM_L3_ECMP_DYNAMIC_MEMBER_HW_UP || 3037 old_status == BCM_L3_ECMP_DYNAMIC_MEMBER_HW_DOWN) { 3038 old_status = BCM_L3_ECMP_DYNAMIC_MEMBER_HW; 3039 } 3040 3041 if (status != old_status) { 3042 return BCM_E_BUSY; 3043 } else { 3044 return BCM_E_NONE; 3045 } 3046 } 3047 3048 return _bcm_th2_l3_egress_ecmp_port_status_set(unit, port, status); 3049 } 3050 3051 /* 3052 * Function: 3053 * bcm_th2_l3_egress_ecmp_member_status_get 3054 * Purpose: 3055 * Get ECMP DLB member status. 3056 * Parameters: 3057 * unit - (IN) SOC unit number. 3058 * intf - (IN) L3 Interface ID pointing to an Egress forwarding object. 3059 * status - (OUT) ECMP member status. 3060 * Returns: 3061 * BCM_E_xxx 3062 */ 3063 int 3064 bcm_th2_l3_egress_ecmp_member_status_get(int unit, bcm_if_t intf, int *status) 3065 { 3066 int nh_index; 3067 int port = 0; 3068 ing_l3_next_hop_entry_t ing_nh_entry; 3069 _th2_ecmp_dlb_port_membership_t *current_ptr; 3070 #ifdef BCM_TRIDENT3_SUPPORT 3071 uint32 dt, dv; 3072 #endif 3073 3074 if (NULL == status) { 3075 return BCM_E_PARAM; 3076 } 3077 3078 /* Derive next hop index */ 3079 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, intf)) { 3080 nh_index = intf - BCM_XGS3_EGRESS_IDX_MIN(unit); 3081 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, intf)) { 3082 nh_index = intf - BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 3083 } else { 3084 return BCM_E_PARAM; 3085 } 3086 3087 /* Derive port from nh_index */ 3088 BCM_IF_ERROR_RETURN(READ_ING_L3_NEXT_HOPm(unit, MEM_BLOCK_ANY, 3089 nh_index, &ing_nh_entry)); 3090 #ifdef BCM_TRIDENT3_SUPPORT 3091 if (soc_feature(unit, soc_feature_generic_dest)) { 3092 dv = soc_mem_field32_dest_get(unit, ING_L3_NEXT_HOPm, &ing_nh_entry, 3093 DESTINATIONf, &dt); 3094 if (dt == SOC_MEM_FIF_DEST_DGPP) { 3095 port = dv & SOC_MEM_FIF_DGPP_PORT_MASK; 3096 } else { 3097 return BCM_E_PARAM; 3098 } 3099 3100 } else 3101 #endif 3102 { 3103 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh_entry, 3104 PORT_NUMf); 3105 } 3106 /* Verify that the nh_index is with DLB arrtibutes. */ 3107 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 3108 while (current_ptr) { 3109 if (nh_index == current_ptr->nh_index && 3110 current_ptr->dlb_id != -1) { 3111 break; 3112 } 3113 current_ptr = current_ptr->next; 3114 } 3115 3116 if (current_ptr == NULL) { 3117 return BCM_E_NOT_FOUND; 3118 } 3119 3120 return _bcm_th2_l3_egress_ecmp_port_status_get(unit, port, status); 3121 } 3122 /* 3123 * Function: 3124 * bcm_th2_l3_egress_ecmp_dlb_ethertype_set 3125 * Purpose: 3126 * Set the Ethertypes that are eligible or ineligible for 3127 * ECMP dynamic load balancing. 3128 * Parameters: 3129 * unit - (IN) Unit number. 3130 * flags - (IN) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags. 3131 * ethertype_count - (IN) Number of elements in ethertype_array. 3132 * ethertype_array - (IN) Array of Ethertypes. 3133 * Returns: 3134 * BCM_E_XXX 3135 */ 3136 int 3137 bcm_th2_l3_egress_ecmp_dlb_ethertype_set( 3138 int unit, 3139 uint32 flags, 3140 int ethertype_count, 3141 int *ethertype_array) 3142 { 3143 int i, j; 3144 dlb_ecmp_eem_configuration_entry_t eem_entry; 3145 dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry; 3146 #ifdef BCM_TRIDENT3_SUPPORT 3147 uint32 reg_val = 0; 3148 #endif 3149 3150 /* Input check */ 3151 if ((ethertype_count > 0) && (NULL == ethertype_array)) { 3152 return BCM_E_PARAM; 3153 } 3154 if (ethertype_count > soc_mem_index_count(unit, 3155 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm)) { 3156 return BCM_E_RESOURCE; 3157 } 3158 #ifdef BCM_TOMAHAWK3_SUPPORT 3159 if ((soc_feature(unit, soc_feature_th3_style_dlb)) && 3160 (flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER)) { 3161 return BCM_E_PARAM; 3162 } 3163 #endif 3164 /* Update quality measure control register */ 3165 #ifdef BCM_TRIDENT3_SUPPORT 3166 if (soc_feature(unit, soc_feature_td3_dlb)) { 3167 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, 3168 ®_val)); 3169 soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 3170 ®_val, CONFIGURATIONf, 3171 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0); 3172 soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 3173 ®_val, INNER_OUTER_ETHERTYPE_SELECTIONf, 3174 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0); 3175 BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, 3176 reg_val)); 3177 } else 3178 #endif 3179 { 3180 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_EEM_CONFIGURATIONm(unit, 3181 MEM_BLOCK_ANY, 0, &eem_entry)); 3182 soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit, 3183 &eem_entry, CONFIGURATIONf, 3184 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE ? 1 : 0); 3185 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 3186 soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit, 3187 &eem_entry, INNER_OUTER_ETHERTYPE_SELECTIONf, 3188 flags & BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER ? 1 : 0); 3189 } 3190 BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_EEM_CONFIGURATIONm(unit, 3191 MEM_BLOCK_ALL, 0, &eem_entry)); 3192 } 3193 /* Update Ethertype eligibility map table */ 3194 for (i = 0; i < ethertype_count; i++) { 3195 sal_memset(ðertype_entry, 0, 3196 sizeof(dlb_ecmp_ethertype_eligibility_map_entry_t)); 3197 soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 3198 ðertype_entry, VALIDf, 1); 3199 soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_set(unit, 3200 ðertype_entry, ETHERTYPEf, ethertype_array[i] & 0xFFFF); 3201 BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 3202 MEM_BLOCK_ALL, i, ðertype_entry)); 3203 } 3204 3205 /* Zero out remaining entries of Ethertype eligibility map table */ 3206 for (j = i; j < soc_mem_index_count(unit, 3207 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); j++) { 3208 BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 3209 MEM_BLOCK_ALL, j, soc_mem_entry_null(unit, 3210 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm))); 3211 } 3212 3213 return BCM_E_NONE; 3214 } 3215 3216 /* 3217 * Function: 3218 * bcm_th2_l3_egress_ecmp_dlb_ethertype_get 3219 * Purpose: 3220 * Get the Ethertypes that are eligible or ineligible for 3221 * ECMP dynamic load balancing. 3222 * Parameters: 3223 * unit - (IN) Unit number. 3224 * flags - (IN/OUT) BCM_L3_ECMP_DYNAMIC_ETHERTYPE_xxx flags. 3225 * ethertype_max - (IN) Number of elements in ethertype_array. 3226 * ethertype_array - (OUT) Array of Ethertypes. 3227 * ethertype_count - (OUT) Number of elements returned in ethertype_array. 3228 * Returns: 3229 * BCM_E_XXX 3230 */ 3231 int 3232 bcm_th2_l3_egress_ecmp_dlb_ethertype_get( 3233 int unit, 3234 uint32 *flags, 3235 int ethertype_max, 3236 int *ethertype_array, 3237 int *ethertype_count) 3238 { 3239 int i; 3240 int ethertype; 3241 dlb_ecmp_ethertype_eligibility_map_entry_t ethertype_entry; 3242 dlb_ecmp_eem_configuration_entry_t eem_entry; 3243 #ifdef BCM_TRIDENT3_SUPPORT 3244 uint32 reg_val = 0; 3245 #endif 3246 3247 /* Input check */ 3248 if (NULL == flags) { 3249 return BCM_E_PARAM; 3250 } 3251 if ((ethertype_max > 0) && (NULL == ethertype_array)) { 3252 return BCM_E_PARAM; 3253 } 3254 if (NULL == ethertype_count) { 3255 return BCM_E_PARAM; 3256 } 3257 3258 *ethertype_count = 0; 3259 3260 /* Get flags */ 3261 #ifdef BCM_TRIDENT3_SUPPORT 3262 if (soc_feature(unit, soc_feature_td3_dlb)) { 3263 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, 3264 ®_val)); 3265 if (soc_reg_field_get(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 3266 reg_val, CONFIGURATIONf)) { 3267 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE; 3268 } 3269 if (soc_reg_field_get(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 3270 reg_val, INNER_OUTER_ETHERTYPE_SELECTIONf)) { 3271 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER; 3272 } 3273 } else 3274 #endif 3275 { 3276 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_EEM_CONFIGURATIONm(unit, 3277 MEM_BLOCK_ANY, 0, &eem_entry)); 3278 if (soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_get(unit, 3279 &eem_entry, CONFIGURATIONf)) { 3280 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_ELIGIBLE; 3281 } 3282 if (!soc_feature(unit, soc_feature_th3_style_dlb)) { 3283 if (soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_get(unit, 3284 &eem_entry, INNER_OUTER_ETHERTYPE_SELECTIONf)) { 3285 *flags |= BCM_L3_ECMP_DYNAMIC_ETHERTYPE_INNER; 3286 } 3287 } 3288 } 3289 /* Get Ethertypes */ 3290 for (i = 0; i < soc_mem_index_count(unit, 3291 DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm); i++) { 3292 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm(unit, 3293 MEM_BLOCK_ANY, i, ðertype_entry)); 3294 if (soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 3295 ðertype_entry, VALIDf)) { 3296 ethertype = soc_DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm_field32_get(unit, 3297 ðertype_entry, ETHERTYPEf); 3298 if (NULL != ethertype_array) { 3299 ethertype_array[*ethertype_count] = ethertype; 3300 } 3301 (*ethertype_count)++; 3302 if ((ethertype_max > 0) && (*ethertype_count == ethertype_max)) { 3303 break; 3304 } 3305 } 3306 } 3307 3308 return BCM_E_NONE; 3309 } 3310 3311 3312 /* 3313 * Function: 3314 * bcm_th2_l3_ecmp_dlb_flowset_reset 3315 * Purpose: 3316 * Invalidate matched flowset entry when deleting ecmp member 3317 * so that they can be given new assignments by DLB 3318 * Parameters: 3319 * unit - (IN) bcm device. 3320 * ecmp - (IN) ECMP group info. 3321 * ecmp_member_bitmap - (IN/OUT) Offset of deleted ecmp member. 3322 * Returns: 3323 * BCM_E_XXX 3324 */ 3325 STATIC int 3326 bcm_th2_l3_ecmp_dlb_flowset_reset(int unit, 3327 bcm_l3_egress_ecmp_t *ecmp, 3328 SHR_BITDCL *ecmp_member_bitmap) 3329 { 3330 int rv = BCM_E_NONE; 3331 int ecmp_group_idx = 0; 3332 int i = 0; 3333 int dlb_id = 0; 3334 int group_enable = 0; 3335 int entry_base_ptr = 0; 3336 int alloc_size = 0; 3337 int index_min = 0; 3338 int index_max = 0; 3339 int assigned_member = 0; 3340 int pipe = 0; 3341 dlb_ecmp_group_control_entry_t dlb_ecmp_group_control_entry; 3342 dlb_ecmp_flowset_entry_t flowset_entry; 3343 ecmp_dlb_control_entry_t ecmp_group_entry; 3344 dlb_ecmp_flowset_member_entry_t *flowset_member_ptr = NULL; 3345 uint32 *flowset_member_buf = NULL; 3346 soc_mem_t ecmp_flowset_member; 3347 soc_mem_t ecmp_flowset; 3348 3349 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED) { 3350 return rv; 3351 } 3352 3353 sal_memcpy(&flowset_entry, soc_mem_entry_null(unit, DLB_ECMP_FLOWSETm), 3354 sizeof(dlb_ecmp_flowset_entry_t)); 3355 3356 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 3357 #if defined(BCM_TOMAHAWK3_SUPPORT) 3358 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 3359 uint64 dlb_en_bitmap; 3360 dlb_id = _bcm_th3_l3_ecmp_dlb_get_id(unit, ecmp_group_idx); 3361 if (dlb_id < soc_reg_field_length(unit, 3362 DLB_ID_0_TO_63_ENABLEr, BITMAPf)) { 3363 SOC_IF_ERROR_RETURN( \ 3364 READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap)); 3365 group_enable = COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id); 3366 } else { 3367 rv = READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap); 3368 if (rv < 0) { 3369 goto error; 3370 } 3371 group_enable = COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id - 3372 (soc_reg_field_length(unit, 3373 DLB_ID_0_TO_63_ENABLEr, BITMAPf))); 3374 } 3375 } else 3376 #endif 3377 { 3378 SOC_IF_ERROR_RETURN( \ 3379 READ_ECMP_DLB_CONTROLm(unit, MEM_BLOCK_ANY, 3380 ecmp_group_idx, &ecmp_group_entry)); 3381 group_enable = 3382 soc_ECMP_DLB_CONTROLm_field32_get(unit, 3383 &ecmp_group_entry, GROUP_ENABLEf); 3384 dlb_id = 3385 soc_ECMP_DLB_CONTROLm_field32_get(unit, &ecmp_group_entry, DLB_IDf); 3386 } 3387 if (!group_enable) { 3388 return rv; 3389 } 3390 3391 BCM_IF_ERROR_RETURN( 3392 READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, 3393 dlb_id, &dlb_ecmp_group_control_entry)); 3394 3395 entry_base_ptr = 3396 soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 3397 &dlb_ecmp_group_control_entry, 3398 FLOW_SET_BASEf); 3399 3400 alloc_size = sizeof(dlb_ecmp_flowset_member_entry_t) * (ecmp->dynamic_size); 3401 flowset_member_buf = soc_cm_salloc(unit, alloc_size, 3402 "ECMP flowset member entries"); 3403 if (NULL == flowset_member_buf) { 3404 rv = BCM_E_MEMORY; 3405 goto error; 3406 } 3407 3408 3409 for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) { 3410 3411 ecmp_flowset_member = 3412 SOC_MEM_UNIQUE_ACC(unit, DLB_ECMP_FLOWSET_MEMBERm)[pipe]; 3413 3414 ecmp_flowset = 3415 SOC_MEM_UNIQUE_ACC(unit, DLB_ECMP_FLOWSETm)[pipe]; 3416 3417 index_min = entry_base_ptr; 3418 index_max = index_min + ecmp->dynamic_size - 1; 3419 rv = soc_mem_read_range(unit, ecmp_flowset_member, MEM_BLOCK_ANY, 3420 index_min, index_max, flowset_member_buf); 3421 if (BCM_FAILURE(rv)) { 3422 goto error; 3423 } 3424 3425 /* Invalidate matched flowset entry */ 3426 for (i = 0; i < ecmp->dynamic_size; i++) { 3427 flowset_member_ptr = 3428 soc_mem_table_idx_to_pointer(unit, ecmp_flowset_member, 3429 dlb_ecmp_flowset_member_entry_t *, 3430 flowset_member_buf, i); 3431 assigned_member = 3432 soc_mem_field32_get(unit, ecmp_flowset_member, 3433 (uint32 *)flowset_member_ptr, 3434 ECMP_MEMBER_ASSIGNMENTf); 3435 if (soc_mem_field32_get(unit, ecmp_flowset_member, 3436 (uint32 *)flowset_member_ptr, 3437 ECMP_MEMBER_IS_ALTERNATEf)) { 3438 assigned_member = assigned_member + ecmp->max_paths / 2; 3439 } 3440 if (SHR_BITGET(ecmp_member_bitmap, assigned_member)) { 3441 3442 rv = soc_mem_write(unit, ecmp_flowset, 3443 MEM_BLOCK_ALL, (i + entry_base_ptr), 3444 &flowset_entry); 3445 if (BCM_FAILURE(rv)) { 3446 goto error; 3447 } 3448 } 3449 } 3450 3451 } 3452 3453 soc_cm_sfree(unit, flowset_member_buf); 3454 3455 return BCM_E_NONE; 3456 3457 error: 3458 3459 if (flowset_member_buf) { 3460 soc_cm_sfree(unit, flowset_member_buf); 3461 } 3462 3463 return rv; 3464 } 3465 3466 /* 3467 * Function: 3468 * bcm_th2_l3_ecmp_dlb_member_delete 3469 * Purpose: 3470 * Delete an Egress forwarding object from an DLB ECMP object 3471 * Parameters: 3472 * unit - (IN) bcm device. 3473 * ecmp - (IN) ECMP group info. 3474 * intf - (IN) Deleted L3 interface id. 3475 * intf_array - (IN/OUT) Array of Egress forwarding objects. 3476 * intf_count - (IN/OUT) Number of entries of intf_count actually filled in. 3477 * Returns: 3478 * BCM_E_XXX 3479 */ 3480 int 3481 bcm_th2_l3_ecmp_dlb_member_delete(int unit, 3482 bcm_l3_egress_ecmp_t *ecmp, bcm_if_t intf, 3483 bcm_if_t *intf_array, int *intf_count) 3484 { 3485 int rv = BCM_E_NONE; 3486 int ecmp_group_idx = 0; 3487 int remove_member_found = FALSE; 3488 bcm_if_t *dlb_intf_array = NULL; 3489 int i = 0, j = 0; 3490 int dlb_member_count = 0; /* Exclude filler */ 3491 int member_bitmap_width = 0; 3492 SHR_BITDCL *member_bitmap = NULL; 3493 SHR_BITDCL *delete_member_bitmap = NULL; 3494 SHR_BITDCL *group_member_ptr = NULL; 3495 3496 3497 /* Check count*/ 3498 if (*intf_count == 0) { 3499 rv = BCM_E_NOT_FOUND; 3500 goto clean_up; 3501 } else if (*intf_count != ecmp->max_paths) { 3502 /* Should always has max_paths members on expanded DLB group */ 3503 rv = BCM_E_INTERNAL; 3504 goto clean_up; 3505 } 3506 3507 /* Allocate DLB member bitmap */ 3508 member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 3509 member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 3510 "DLB ECMP member bitmap"); 3511 if (NULL == member_bitmap) { 3512 rv = BCM_E_MEMORY; 3513 goto clean_up; 3514 } 3515 3516 sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 3517 3518 /* Allocate Deleted DLB member bitmap */ 3519 delete_member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 3520 "Deleted DLB ECMP member bitmap"); 3521 if (NULL == delete_member_bitmap) { 3522 rv = BCM_E_MEMORY; 3523 goto clean_up; 3524 } 3525 3526 sal_memset(delete_member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 3527 3528 /* Allocate DLB member array */ 3529 dlb_intf_array = sal_alloc((*intf_count) * sizeof(bcm_if_t), 3530 "ecmp member array"); 3531 if (NULL == dlb_intf_array) { 3532 rv = BCM_E_MEMORY; 3533 goto clean_up; 3534 } 3535 3536 /* Get currrent group bitmap */ 3537 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 3538 group_member_ptr = 3539 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 3540 sal_memcpy(member_bitmap, group_member_ptr, 3541 SHR_BITALLOCSIZE(member_bitmap_width)); 3542 3543 /* 3544 * Get the DLB members (excluding deleted member and filler members) 3545 * and Clear DLB member bitmap 3546 */ 3547 for (i = 0; i < ecmp->max_paths; i++) { 3548 if (SHR_BITGET(member_bitmap, i)) { 3549 if (!remove_member_found && (intf_array[i] == intf)) { 3550 SHR_BITCLR(member_bitmap, i); 3551 SHR_BITSET(delete_member_bitmap, i); 3552 remove_member_found = TRUE; 3553 } else { 3554 dlb_intf_array[dlb_member_count++] = intf_array[i]; 3555 } 3556 } 3557 } 3558 3559 if (!remove_member_found) { 3560 rv = BCM_E_NOT_FOUND; 3561 goto clean_up; 3562 } 3563 3564 /* Refill the location of deleted members with existing members randomly */ 3565 for (i = 0; i < ecmp->max_paths; i++) { 3566 if (dlb_member_count > 0) { 3567 /* Just reset filler*/ 3568 if (!SHR_BITGET(member_bitmap, i)) { 3569 intf_array[i] = 3570 dlb_intf_array[j % dlb_member_count]; 3571 j++; 3572 } 3573 } else { 3574 /* All the DLB members are deleted */ 3575 intf_array[i] = 0; 3576 (*intf_count)--; 3577 } 3578 } 3579 3580 /* Update ECMP group */ 3581 ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID; 3582 rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *intf_count, intf_array, 3583 BCM_L3_ECMP_MEMBER_OP_DELETE, 3584 1, &intf, *intf_count, member_bitmap); 3585 if (BCM_SUCCESS(rv)) { 3586 sal_memcpy(group_member_ptr, member_bitmap, 3587 SHR_BITALLOCSIZE(member_bitmap_width)); 3588 rv = bcm_th2_l3_ecmp_dlb_flowset_reset(unit, ecmp, 3589 delete_member_bitmap); 3590 } 3591 3592 clean_up: 3593 3594 if (member_bitmap) { 3595 sal_free(member_bitmap); 3596 } 3597 3598 if (delete_member_bitmap) { 3599 sal_free(delete_member_bitmap); 3600 } 3601 3602 if (dlb_intf_array) { 3603 sal_free(dlb_intf_array); 3604 } 3605 3606 return rv; 3607 } 3608 3609 /* 3610 * Function: 3611 * bcm_th2_l3_ecmp_dlb_dgm_member_delete 3612 * Purpose: 3613 * Delete an Egress forwarding object from an DLB/DGM ECMP object 3614 * Parameters: 3615 * unit - (IN) bcm device. 3616 * ecmp - (IN) ECMP group info. 3617 * ecmp_member - (IN) Deleted L3 interface id pointing to Egress forwarding object. 3618 * ecmp_member_array - (IN/OUT) Member array of Egress forwarding objects. 3619 * ecmp_member_count - (IN/OUT) Number of members of ecmp_member_count actually filled in. 3620 * 3621 * Returns: 3622 * BCM_E_XXX 3623 */ 3624 int 3625 bcm_th2_l3_ecmp_dlb_dgm_member_delete(int unit, 3626 bcm_l3_egress_ecmp_t *ecmp, 3627 bcm_l3_ecmp_member_t *ecmp_member, 3628 bcm_l3_ecmp_member_t *ecmp_member_array, 3629 int *ecmp_member_count) 3630 { 3631 int rv = BCM_E_NONE; 3632 int alloc_size = 0; 3633 bcm_if_t *intf_array = 0; 3634 int ecmp_group_idx = 0; 3635 int start = 0, end = 0; 3636 int i = 0, j = 0; 3637 int location_offset = 0; 3638 int copy_offset = 0; 3639 int remove_member_found = FALSE; 3640 int alternate_count = 0; /* Include filler */ 3641 int primary_count = 0; /* Include filler */ 3642 int dlb_member_count = 0; /* Exclude filler */ 3643 int member_bitmap_width = 0; 3644 SHR_BITDCL *member_bitmap = NULL; 3645 SHR_BITDCL *delete_member_bitmap = NULL; 3646 SHR_BITDCL *group_member_ptr = NULL; 3647 bcm_l3_ecmp_member_t *dlb_member_array = NULL; /* Exclude filler */ 3648 3649 3650 /* Allocate DLB member bitmap */ 3651 member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 3652 member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 3653 "DLB ECMP member bitmap"); 3654 if (NULL == member_bitmap) { 3655 rv = BCM_E_MEMORY; 3656 goto clean_up; 3657 } 3658 3659 sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 3660 3661 /* Allocate Deleted DLB member bitmap */ 3662 delete_member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 3663 "Deleted DLB ECMP member bitmap"); 3664 if (NULL == delete_member_bitmap) { 3665 rv = BCM_E_MEMORY; 3666 goto clean_up; 3667 } 3668 3669 sal_memset(delete_member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 3670 3671 /* Allocate DLB member array */ 3672 dlb_member_array = sal_alloc((*ecmp_member_count) * 3673 sizeof(bcm_l3_ecmp_member_t), 3674 "ecmp member array"); 3675 if (NULL == dlb_member_array) { 3676 rv = BCM_E_MEMORY; 3677 goto clean_up; 3678 3679 } 3680 3681 /* Get currrent group bitmap */ 3682 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 3683 group_member_ptr = 3684 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 3685 sal_memcpy(member_bitmap, group_member_ptr, 3686 SHR_BITALLOCSIZE(member_bitmap_width)); 3687 3688 /* Allocate interface array */ 3689 alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit); 3690 intf_array = sal_alloc(alloc_size, "intf array"); 3691 if (NULL == intf_array) { 3692 rv = BCM_E_MEMORY; 3693 goto clean_up; 3694 3695 } 3696 sal_memset(intf_array, 0, alloc_size); 3697 3698 /* 3699 * Index of ecmp_member_array 3700 * - Both primary and alternate members exist: Primary members start 3701 * from 0 and Alternate members start from max_paths / 2 3702 * - Only primary members exist: Primary members start from 0 3703 * - Only alternate members exist: Alternate members start from 0 3704 * Offset of DLB members bitmap 3705 * - Primary members always start from 0 3706 * - Alternate members always start from max_paths / 2 3707 * Member count (including filler) 3708 * - DLB count: 0 or max_paths if any 3709 * - DGM primary count: 0 or max_paths/2 if any 3710 * DGM alternate count: 0 or max_paths/2 if any 3711 */ 3712 if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) && 3713 (ecmp_member->flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) { 3714 /* Delete alternate member */ 3715 start = ecmp->max_paths / 2; 3716 end = start * 2; 3717 3718 /* Get the count of alternate members (without filler) */ 3719 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, 3720 start, end - start); 3721 3722 if (dlb_member_count == 0) { 3723 rv = BCM_E_NOT_FOUND; 3724 goto clean_up; 3725 } else { 3726 alternate_count = ecmp->max_paths / 2; 3727 primary_count = (*ecmp_member_count) - alternate_count; 3728 } 3729 3730 /* 3731 * Only alternate members exist: 3732 * Alternate members start from 0, offset should be max_paths / 2. 3733 */ 3734 if (0 == primary_count) { 3735 location_offset = ecmp->max_paths / 2; 3736 } 3737 3738 /* Internal check */ 3739 if (end - location_offset > (*ecmp_member_count)) { 3740 rv = BCM_E_INTERNAL; 3741 goto clean_up; 3742 } 3743 } else { 3744 /* Delete DGM primary member or DLB member */ 3745 start = 0; 3746 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 3747 end = ecmp->max_paths / 2; 3748 } else { 3749 end = ecmp->max_paths; 3750 } 3751 3752 /* Get the count of DGM primary members or DLB members (without filler) */ 3753 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, start, end); 3754 3755 if (dlb_member_count == 0) { 3756 rv = BCM_E_NOT_FOUND; 3757 goto clean_up; 3758 } 3759 3760 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 3761 primary_count = ecmp->max_paths / 2; 3762 alternate_count = (*ecmp_member_count) - primary_count; 3763 /* 3764 * If delete the lastest primary member, alternate members shoud be 3765 * moved, and start from 0 instead of max_paths / 2. 3766 */ 3767 if (alternate_count > 0) { 3768 copy_offset = ecmp->max_paths / 2; 3769 } 3770 } else { 3771 primary_count = ecmp->max_paths; 3772 } 3773 3774 /* Internal check */ 3775 if (end + copy_offset > (*ecmp_member_count)) { 3776 rv = BCM_E_INTERNAL; 3777 goto clean_up; 3778 } 3779 } 3780 3781 /* 3782 * Get the DLB members (excluding deleted member and filler members) 3783 * and Clear DLB member bitmap 3784 */ 3785 dlb_member_count = 0; 3786 for (i = start - location_offset; i < end - location_offset; i++) { 3787 3788 if (SHR_BITGET(member_bitmap, i + location_offset)) { 3789 if (!remove_member_found && 3790 (ecmp_member_array[i].egress_if == ecmp_member->egress_if)) { 3791 3792 SHR_BITCLR(member_bitmap, i + location_offset); 3793 SHR_BITSET(delete_member_bitmap, i + location_offset); 3794 remove_member_found = TRUE; 3795 } else { 3796 sal_memcpy(&dlb_member_array[dlb_member_count++], 3797 &ecmp_member_array[i], 3798 sizeof(bcm_l3_ecmp_member_t)); 3799 } 3800 } 3801 } 3802 3803 if (!remove_member_found) { 3804 rv = BCM_E_NOT_FOUND; 3805 goto clean_up; 3806 } 3807 3808 /* Refill the location of deleted members with existing members randomly */ 3809 for (i = start - location_offset; i < end - location_offset; i++) { 3810 if (dlb_member_count > 0) { 3811 if (!SHR_BITGET(member_bitmap, i + location_offset)) { 3812 sal_memcpy(&ecmp_member_array[i], 3813 &dlb_member_array[j % dlb_member_count], 3814 sizeof(bcm_l3_ecmp_member_t)); 3815 j++; 3816 } 3817 } else { 3818 /* 3819 * 1. All the DLB members are deleted 3820 * 2. or all the DGM primary members are deleted 3821 * 3. or all the DGM alternate members are deleted 3822 */ 3823 if (copy_offset) { 3824 /* 3825 * DGM - if delete the last primary member, alternate members 3826 * shoud be moved, and start from 0 instead of max_paths / 2 3827 */ 3828 sal_memcpy(&ecmp_member_array[i], 3829 &ecmp_member_array[i + copy_offset], 3830 sizeof(bcm_l3_ecmp_member_t)); 3831 sal_memset(&ecmp_member_array[i + copy_offset], 0, 3832 sizeof(bcm_l3_ecmp_member_t)); 3833 } else { 3834 sal_memset(&ecmp_member_array[i], 0, 3835 sizeof(bcm_l3_ecmp_member_t)); 3836 } 3837 (*ecmp_member_count)--; 3838 if (!(ecmp_member->flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) { 3839 primary_count--; 3840 } 3841 } 3842 } 3843 3844 for (i = 0; i < (*ecmp_member_count); i++) { 3845 intf_array[i] = ecmp_member_array[i].egress_if; 3846 } 3847 3848 /* Update ECMP group */ 3849 ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID; 3850 rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *ecmp_member_count, 3851 intf_array, BCM_L3_ECMP_MEMBER_OP_DELETE, 3852 1, &(ecmp_member->egress_if), 3853 primary_count, member_bitmap); 3854 3855 if (BCM_SUCCESS(rv)) { 3856 sal_memcpy(group_member_ptr, member_bitmap, 3857 SHR_BITALLOCSIZE(member_bitmap_width)); 3858 rv = bcm_th2_l3_ecmp_dlb_flowset_reset(unit, ecmp, 3859 delete_member_bitmap); 3860 } 3861 3862 clean_up: 3863 3864 if (member_bitmap) { 3865 sal_free(member_bitmap); 3866 } 3867 3868 if (delete_member_bitmap) { 3869 sal_free(delete_member_bitmap); 3870 } 3871 3872 if (dlb_member_array) { 3873 sal_free(dlb_member_array); 3874 } 3875 3876 if (intf_array) { 3877 sal_free(intf_array); 3878 } 3879 3880 return rv; 3881 3882 } 3883 3884 /* 3885 * Function: 3886 * bcm_th2_l3_ecmp_dlb_member_create 3887 * Purpose: 3888 * Create or modify an Egress DLB ECMP forwarding object. 3889 * Parameters: 3890 * unit - (IN) bcm device. 3891 * ecmp - (IN) ECMP group info. 3892 * intf_array - (IN/OUT) Array of Egress forwarding objects. 3893 * intf_count - (IN/OUT) Number of entries of intf_count actually filled in. 3894 * Returns: 3895 * BCM_E_XXX 3896 */ 3897 int 3898 bcm_th2_l3_ecmp_dlb_member_create(int unit, 3899 bcm_l3_egress_ecmp_t *ecmp, 3900 bcm_if_t *intf_array, 3901 int intf_count) 3902 { 3903 int rv = BCM_E_NONE; 3904 int i = 0, j = 0; 3905 int alloc_size = 0; 3906 int ecmp_group_idx = 0; 3907 bcm_if_t *dlb_intf_array = NULL; /* Include filler*/ 3908 bcm_if_t *dlb_intf_array_2 = NULL; /* Exclude filler */ 3909 int dlb_intf_count = 0; 3910 int dlb_intf_count_2 = 0; 3911 int member_chg = TRUE; 3912 bcm_l3_egress_ecmp_t dlb_ecmp; 3913 int member_bitmap_width = 0; 3914 SHR_BITDCL *member_bitmap = NULL; 3915 SHR_BITDCL *group_member_ptr = NULL; 3916 3917 /* Check max_paths */ 3918 if ((ecmp->max_paths > BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit)) || 3919 (ecmp->max_paths < 2)) { 3920 return BCM_E_PARAM; 3921 } else if (ecmp->max_paths == 0) { 3922 ecmp->max_paths = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit); 3923 } 3924 3925 if (intf_count > ecmp->max_paths) { 3926 return BCM_E_RESOURCE; 3927 } 3928 3929 /* Allocate interface array */ 3930 alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit); 3931 dlb_intf_array = sal_alloc(alloc_size, "dlb intf array"); 3932 if (NULL == dlb_intf_array) { 3933 return BCM_E_MEMORY; 3934 } 3935 3936 sal_memset(dlb_intf_array, 0, alloc_size); 3937 3938 /* Allocate DLB member bitmap */ 3939 member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 3940 member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 3941 "DLB ECMP member bitmap"); 3942 if (NULL == member_bitmap) { 3943 rv = BCM_E_MEMORY; 3944 goto clean_up; 3945 } 3946 3947 sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 3948 3949 if (ecmp->flags & BCM_L3_REPLACE) { 3950 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) { 3951 rv = BCM_E_PARAM; 3952 goto clean_up; 3953 } 3954 3955 /* Get currrent group bitmap */ 3956 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 3957 group_member_ptr = 3958 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 3959 3960 /* Get DLB group's existing interface array including filler */ 3961 bcm_l3_egress_ecmp_t_init(&dlb_ecmp); 3962 dlb_ecmp.ecmp_intf = ecmp->ecmp_intf; 3963 rv = _bcm_esw_l3_egress_ecmp_get(unit, &dlb_ecmp, 3964 BCM_XGS3_L3_ECMP_MAX(unit), 3965 dlb_intf_array, &dlb_intf_count, TRUE); 3966 if (BCM_FAILURE(rv)) { 3967 goto clean_up; 3968 } 3969 3970 if (dlb_ecmp.dynamic_mode == ecmp->dynamic_mode) { 3971 3972 if (dlb_ecmp.max_paths != ecmp->max_paths) { 3973 rv = BCM_E_PARAM; 3974 goto clean_up; 3975 } 3976 3977 /* Get DLB group's existing interface array excluding filler */ 3978 alloc_size = sizeof(bcm_if_t) * dlb_intf_count; 3979 dlb_intf_array_2 = sal_alloc(alloc_size, "dlb intf array_2"); 3980 if (NULL == dlb_intf_array_2) { 3981 rv = BCM_E_MEMORY; 3982 goto clean_up; 3983 } 3984 sal_memset(dlb_intf_array_2, 0, alloc_size); 3985 /* Exclude filler members of expanded DLB group */ 3986 for (i = 0; i < dlb_intf_count; i++) { 3987 if (SHR_BITGET(group_member_ptr, i)) { 3988 dlb_intf_array_2[dlb_intf_count_2++] = dlb_intf_array[i]; 3989 } 3990 } 3991 3992 /* Compare new members(intf_array) with exisiting members(dlb_intf_array_2) */ 3993 if ((intf_count == dlb_intf_count_2) && 3994 !sal_memcmp((void *)intf_array, (void *)dlb_intf_array_2, 3995 (intf_count * sizeof(bcm_if_t)))) { 3996 member_chg = FALSE; 3997 } 3998 } 3999 } 4000 4001 /* 4002 * To keep the traffic resiliency, the offset of DLB members in L3 ECMP tables should 4003 * not be changed when an DLB ECMP member is deleted or added. 4004 * - An expanded ecmp group will be used for DLB. SDK always allocates member entries 4005 * based on the configuration of max_paths. i.e. DLB(max_paths entries). 4006 * Up to max_paths next hops can be supported in DLB group. The DLB bitmap 4007 * will always reflect the TRUE DLB membership(specified by SDK API), 4008 * and the remaining entries will contain fillers which won't be selected by DLB. 4009 * - When an DLB ECMP member is deleted, the space previously occupied by the deleted 4010 * member will be filled as a duplicate of any existing member. 4011 * - When an DLB ECMP member is added, SDK will choose the space used by a filler 4012 * for the new member. 4013 */ 4014 if (member_chg) { 4015 sal_memset(dlb_intf_array, 0, 4016 sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit)); 4017 if (intf_count) { 4018 for (i = 0; i < ecmp->max_paths; i++) { 4019 j = i % intf_count; 4020 dlb_intf_array[i] = intf_array[j]; 4021 if (i < intf_count) { 4022 SHR_BITSET(member_bitmap, i); 4023 } 4024 } 4025 /* Should be expanded to max_paths with filler */ 4026 dlb_intf_count = ecmp->max_paths; 4027 } else { 4028 dlb_intf_count = 0; 4029 } 4030 } else { 4031 /* No member change */ 4032 sal_memcpy(member_bitmap, group_member_ptr, 4033 SHR_BITALLOCSIZE(member_bitmap_width)); 4034 } 4035 4036 rv = _bcm_esw_l3_ecmp_create(unit, ecmp, dlb_intf_count, 4037 dlb_intf_array, BCM_L3_ECMP_MEMBER_OP_SET, 4038 0, NULL, dlb_intf_count, member_bitmap); 4039 if (member_chg && BCM_SUCCESS(rv)) { 4040 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 4041 group_member_ptr = 4042 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 4043 sal_memcpy(group_member_ptr, member_bitmap, 4044 SHR_BITALLOCSIZE(member_bitmap_width)); 4045 } 4046 4047 clean_up: 4048 4049 if (dlb_intf_array) { 4050 sal_free(dlb_intf_array); 4051 } 4052 4053 if (member_bitmap) { 4054 sal_free(member_bitmap); 4055 } 4056 4057 if (dlb_intf_array_2) { 4058 sal_free(dlb_intf_array_2); 4059 } 4060 4061 return rv; 4062 } 4063 4064 /* 4065 * Function: 4066 * bcm_th2_l3_ecmp_dlb_dgm_member_create 4067 * Purpose: 4068 * Create or modify an Egress DLB/DGM ECMP forwarding object. 4069 * Parameters: 4070 * unit - (IN) bcm device. 4071 * ecmp - (IN) ECMP group info. 4072 * ecmp_member_array - (IN) Member array of Egress forwarding objects. 4073 * ecmp_member_count - (IN) Number of elements in ecmp_member_array. 4074 * 4075 * Returns: 4076 * BCM_E_XXX 4077 */ 4078 int 4079 bcm_th2_l3_ecmp_dlb_dgm_member_create(int unit, 4080 bcm_l3_egress_ecmp_t *ecmp, 4081 bcm_l3_ecmp_member_t *ecmp_member_array, 4082 int ecmp_member_count) 4083 { 4084 int rv = BCM_E_NONE; 4085 int i = 0, j = 0; 4086 int alloc_size = 0; 4087 int ecmp_group_idx = 0; 4088 bcm_if_t *dlb_intf_array = NULL; /* Include filler */ 4089 int dlb_intf_count = 0; 4090 bcm_if_t *dlb_intf_array_2 = NULL; /* Exclude filler */ 4091 int dlb_intf_count_2 = 0; 4092 int grand_max_paths = 0; 4093 int dlb_primary_count = 0; /* Include filler */ 4094 int dlb_primary_count_2 = 0; /* Exclude filler */ 4095 int location_offset = 0; 4096 int member_bitmap_width = 0; 4097 int member_chg = TRUE; 4098 SHR_BITDCL *member_bitmap = NULL; 4099 SHR_BITDCL *group_member_ptr = NULL; 4100 bcm_if_t *intf_array = NULL; 4101 int primary_count = 0; 4102 int intf_count = 0; 4103 int dlb_member_count = 0; 4104 bcm_l3_ecmp_member_t *dlb_member_array = NULL; /* Include filler */ 4105 bcm_l3_egress_ecmp_t dlb_ecmp; 4106 4107 grand_max_paths = 4108 (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) ? 4109 BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2 : 4110 BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit); 4111 /* Check max_paths */ 4112 if ((ecmp->max_paths > grand_max_paths) || (ecmp->max_paths < 2)) { 4113 return BCM_E_PARAM; 4114 } else if (ecmp->max_paths == 0) { 4115 ecmp->max_paths = grand_max_paths; 4116 } 4117 4118 if (ecmp_member_count > ecmp->max_paths) { 4119 return BCM_E_RESOURCE; 4120 } 4121 4122 /* Convert the ecmp_member_array to intf_array */ 4123 intf_count = ecmp_member_count; 4124 alloc_size = BCM_XGS3_L3_ECMP_MAX(unit) * sizeof(bcm_if_t); 4125 intf_array = sal_alloc(alloc_size, "L3 ECMP intf_array"); 4126 if (intf_array == NULL) { 4127 rv = BCM_E_MEMORY; 4128 goto clean_up; 4129 } 4130 sal_memset(intf_array, 0, alloc_size); 4131 4132 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 4133 for (i = 0; i < intf_count; i++) { 4134 if (!(ecmp_member_array[i].flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) { 4135 intf_array[j++] = ecmp_member_array[i].egress_if; 4136 primary_count++; 4137 } 4138 } 4139 for (i = 0; i < intf_count; i++) { 4140 if (ecmp_member_array[i].flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE) { 4141 intf_array[j++] = ecmp_member_array[i].egress_if; 4142 } 4143 } 4144 /* Either primary or alternate cannot exceed half max paths */ 4145 if (primary_count > (ecmp->max_paths >> 1) || 4146 (intf_count - primary_count) > (ecmp->max_paths >> 1)) { 4147 rv = BCM_E_RESOURCE; 4148 goto clean_up; 4149 } 4150 } else { 4151 for (i = 0; i < intf_count; i++) { 4152 intf_array[i] = ecmp_member_array[i].egress_if; 4153 } 4154 primary_count = intf_count; 4155 } 4156 4157 /* Allocate interface array */ 4158 alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit); 4159 dlb_intf_array = sal_alloc(alloc_size, "dlb intf array"); 4160 if (NULL == dlb_intf_array) { 4161 rv = BCM_E_MEMORY; 4162 goto clean_up; 4163 } 4164 sal_memset(dlb_intf_array, 0, alloc_size); 4165 4166 /* Allocate DLB member bitmap */ 4167 member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 4168 member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 4169 "DLB ECMP member bitmap"); 4170 if (NULL == member_bitmap) { 4171 rv = BCM_E_MEMORY; 4172 goto clean_up; 4173 } 4174 4175 sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 4176 4177 if (ecmp->flags & BCM_L3_REPLACE) { 4178 if (!BCM_XGS3_L3_MPATH_EGRESS_IDX_VALID(unit, ecmp->ecmp_intf)) { 4179 rv = BCM_E_PARAM; 4180 goto clean_up; 4181 } 4182 /* Get currrent group bitmap */ 4183 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 4184 group_member_ptr = 4185 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 4186 4187 /* Get DLB group's existing member array including filler */ 4188 bcm_l3_egress_ecmp_t_init(&dlb_ecmp); 4189 dlb_ecmp.ecmp_intf = ecmp->ecmp_intf; 4190 4191 alloc_size = sizeof(bcm_l3_ecmp_member_t) * BCM_XGS3_L3_ECMP_MAX(unit); 4192 dlb_member_array = sal_alloc(alloc_size, "dlb intf array"); 4193 if (NULL == dlb_member_array) { 4194 rv = BCM_E_MEMORY; 4195 goto clean_up; 4196 } 4197 sal_memset(dlb_member_array, 0, alloc_size); 4198 rv = bcm_xgs3_l3_ecmp_get(unit, &dlb_ecmp, BCM_XGS3_L3_ECMP_MAX(unit), 4199 dlb_member_array, &dlb_member_count); 4200 if (BCM_FAILURE(rv)) { 4201 goto clean_up; 4202 } 4203 4204 if (dlb_ecmp.dynamic_mode == ecmp->dynamic_mode) { 4205 /* Max_paths can not be changed for DLB/DGM group*/ 4206 if (dlb_ecmp.max_paths != ecmp->max_paths) { 4207 rv = BCM_E_PARAM; 4208 goto clean_up; 4209 } 4210 4211 /* Get DLB group's existing interface array including filler */ 4212 for (i = 0; i < dlb_member_count; i++) { 4213 dlb_intf_array[i] = dlb_member_array[i].egress_if; 4214 } 4215 4216 dlb_intf_count = dlb_member_count; 4217 4218 /* Get DLB group's existing interface array excluding filler */ 4219 alloc_size = sizeof(bcm_if_t) * dlb_member_count; 4220 4221 dlb_intf_array_2 = sal_alloc(alloc_size, "dlb intf array_2"); 4222 if (NULL == dlb_intf_array_2) { 4223 rv = BCM_E_MEMORY; 4224 goto clean_up; 4225 } 4226 4227 sal_memset(dlb_intf_array_2, 0, alloc_size); 4228 4229 if (dlb_ecmp.dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 4230 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_primary_count_2, 4231 0, dlb_ecmp.max_paths / 2); 4232 if (dlb_primary_count_2) { 4233 /* Should be expanded to max_paths / 2 with filler */ 4234 dlb_primary_count = dlb_ecmp.max_paths / 2; 4235 } else { 4236 /* Only alternate members exist , start from 0 instead of max_paths / 2 */ 4237 location_offset = dlb_ecmp.max_paths / 2; 4238 } 4239 } else { 4240 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_primary_count_2, 4241 0, dlb_ecmp.max_paths); 4242 if (dlb_primary_count_2) { 4243 /* Should be expanded to max_paths with filler */ 4244 dlb_primary_count = dlb_ecmp.max_paths; 4245 } 4246 } 4247 4248 /* Exclude filler members of expanded DLB group */ 4249 for (i = 0; i < dlb_member_count; i++) { 4250 if (SHR_BITGET(group_member_ptr, i + location_offset)) { 4251 dlb_intf_array_2[dlb_intf_count_2++] = 4252 dlb_member_array[i].egress_if; 4253 } 4254 } 4255 4256 /* Compare new members(intf_array) with exisiting members(dlb_intf_array_2) */ 4257 if ((intf_count == dlb_intf_count_2) && 4258 (primary_count == dlb_primary_count_2) && 4259 !sal_memcmp((void *)intf_array, (void *)dlb_intf_array_2, 4260 (intf_count * sizeof(bcm_if_t)))) { 4261 member_chg = FALSE; 4262 } 4263 } 4264 } 4265 4266 /* 4267 * To keep the traffic resiliency, the offset of DLB members in L3 ECMP tables should 4268 * not be changed when an DLB ECMP member is deleted or added. 4269 * - An expanded ecmp group will be used for DLB. SDK always allocates member entries 4270 * based on the configuration of max_paths. i.e. DLB(max_paths entries) or 4271 * DGM (max_paths/2 primary entries , max_paths/2 alternate entries). 4272 * Up to max_paths next hops can be supported in DLB group. 4273 * With DGM, it will support the groups with up to max_paths/2 primary 4274 * next hops and up to max_paths/2 alternate next hops. The DLB bitmap will always 4275 * reflect the TRUE DLB membership(specified by SDK API), 4276 * and the remaining entries will contain fillers which won't be selected by DLB. 4277 * - When an DLB ECMP member is deleted, the space previously occupied by the deleted 4278 * member will be filled as a duplicate of any existing member. 4279 * - When an DLB ECMP member is added, SDK will choose the space used by a filler 4280 * for the new member. 4281 */ 4282 if (member_chg) { 4283 sal_memset(dlb_intf_array, 0, 4284 sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit)); 4285 if (intf_count) { 4286 if ((0 == primary_count) && 4287 (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM)) { 4288 for (i = 0; i < ecmp->max_paths / 2; i++) { 4289 j = i % intf_count; 4290 dlb_intf_array[i] = intf_array[j]; 4291 if (i < intf_count) { 4292 SHR_BITSET(member_bitmap, i + ecmp->max_paths / 2); 4293 } 4294 } 4295 /* If only alternate exist, expand ecmp group to max_paths / 2 with filler */ 4296 dlb_intf_count = ecmp->max_paths / 2; 4297 dlb_primary_count = 0; 4298 } else if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 4299 4300 for (i = 0; i < ecmp->max_paths / 2; i++) { 4301 j = i % primary_count; 4302 dlb_intf_array[i] = intf_array[j]; 4303 if (i < primary_count) { 4304 SHR_BITSET(member_bitmap, i); 4305 } 4306 } 4307 4308 /* If primary exist, expand ecmp group to max_paths / 2 with filler */ 4309 dlb_intf_count = ecmp->max_paths / 2; 4310 dlb_primary_count = ecmp->max_paths / 2; 4311 4312 if (intf_count - primary_count) { 4313 for (i = 0; i < ecmp->max_paths / 2; i++) { 4314 j = primary_count + i % (intf_count - primary_count); 4315 dlb_intf_array[i + ecmp->max_paths / 2] = intf_array[j]; 4316 if (i < (intf_count - primary_count)) { 4317 SHR_BITSET(member_bitmap, i + ecmp->max_paths / 2); 4318 } 4319 } 4320 4321 /* If alternate also exist, expand ecmp group to max_paths with filler */ 4322 dlb_intf_count = dlb_intf_count + ecmp->max_paths / 2; 4323 } 4324 } else { 4325 for (i = 0; i < ecmp->max_paths; i++) { 4326 j = i % intf_count; 4327 dlb_intf_array[i] = intf_array[j]; 4328 if (i < intf_count) { 4329 SHR_BITSET(member_bitmap, i); 4330 } 4331 } 4332 4333 /* expand ecmp group to max_paths with filler */ 4334 dlb_intf_count = ecmp->max_paths; 4335 dlb_primary_count = ecmp->max_paths; 4336 } 4337 } else { 4338 dlb_intf_count = 0; 4339 dlb_primary_count = 0; 4340 } 4341 } else { 4342 sal_memcpy(member_bitmap, group_member_ptr, 4343 SHR_BITALLOCSIZE(member_bitmap_width)); 4344 } 4345 4346 rv = _bcm_esw_l3_ecmp_create(unit, ecmp, dlb_intf_count, 4347 dlb_intf_array, BCM_L3_ECMP_MEMBER_OP_SET, 4348 0, NULL, dlb_primary_count, member_bitmap); 4349 if (member_chg && BCM_SUCCESS(rv)) { 4350 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 4351 group_member_ptr = 4352 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 4353 sal_memcpy(group_member_ptr, member_bitmap, 4354 SHR_BITALLOCSIZE(member_bitmap_width)); 4355 } 4356 4357 clean_up: 4358 4359 if (intf_array) { 4360 sal_free(intf_array); 4361 } 4362 4363 if (dlb_intf_array) { 4364 sal_free(dlb_intf_array); 4365 } 4366 4367 if (member_bitmap) { 4368 sal_free(member_bitmap); 4369 } 4370 4371 if (dlb_member_array) { 4372 sal_free(dlb_member_array); 4373 } 4374 4375 if (dlb_intf_array_2) { 4376 sal_free(dlb_intf_array_2); 4377 } 4378 4379 return rv; 4380 } 4381 4382 /* 4383 * Function: 4384 * bcm_th2_l3_ecmp_dlb_member_add 4385 * Purpose: 4386 * Add an Egress forwarding object to an Egress DLB ECMP forwarding object. 4387 * Parameters: 4388 * unit - (IN) bcm device. 4389 * ecmp - (IN) ECMP group info. 4390 * intf - (IN) Deleted L3 interface id. 4391 * intf_array - (IN/OUT) Array of Egress forwarding objects. 4392 * intf_count - (IN/OUT) Number of entries of intf_count actually filled in. 4393 * Returns: 4394 * BCM_E_XXX 4395 */ 4396 int 4397 bcm_th2_l3_ecmp_dlb_member_add(int unit, 4398 bcm_l3_egress_ecmp_t *ecmp, bcm_if_t intf, 4399 bcm_if_t *intf_array, int *intf_count) 4400 4401 { 4402 int rv = BCM_E_NONE; 4403 int ecmp_group_idx = 0; 4404 int i = 0, j = 0; 4405 int dlb_member_add_flag = FALSE; 4406 int dlb_member_count = 0; /* Exclude filler */ 4407 int member_bitmap_width = 0; 4408 SHR_BITDCL *member_bitmap = NULL; 4409 SHR_BITDCL *group_member_ptr = NULL; 4410 bcm_if_t *dlb_intf_array = NULL; /* Exclude filler */ 4411 4412 /* Allocate DLB member bitmap */ 4413 member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 4414 member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 4415 "DLB ECMP member bitmap"); 4416 if (NULL == member_bitmap) { 4417 rv = BCM_E_MEMORY; 4418 goto clean_up; 4419 } 4420 4421 sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 4422 4423 /* Get currrent group bitmap */ 4424 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 4425 group_member_ptr = 4426 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 4427 4428 if ((*intf_count != ecmp->max_paths) && (*intf_count != 0)) { 4429 /* Should always has max_paths or 0 members on expanded DLB group */ 4430 rv = BCM_E_INTERNAL; 4431 goto clean_up; 4432 } 4433 4434 sal_memcpy(member_bitmap, group_member_ptr, 4435 SHR_BITALLOCSIZE(member_bitmap_width)); 4436 4437 /* Allocate DLB intf array */ 4438 dlb_intf_array = sal_alloc(BCM_XGS3_L3_ECMP_MAX(unit) * 4439 sizeof(bcm_if_t), 4440 "ecmp intf array"); 4441 if (NULL == dlb_intf_array) { 4442 rv = BCM_E_MEMORY; 4443 goto clean_up; 4444 } 4445 4446 /* Get the DLB intf (including added intf) without filler */ 4447 dlb_member_count = 0; 4448 for (i = 0; i < ecmp->max_paths; i++) { 4449 if (SHR_BITGET(member_bitmap, i)) { 4450 dlb_intf_array[dlb_member_count++] = intf_array[i]; 4451 } else { 4452 if(!dlb_member_add_flag) { 4453 dlb_intf_array[dlb_member_count++] = intf; 4454 dlb_member_add_flag = TRUE; 4455 } 4456 } 4457 } 4458 4459 if (!dlb_member_add_flag) { 4460 rv = BCM_E_FULL; 4461 goto clean_up; 4462 } 4463 4464 /* Refill the members of expanded DLB group */ 4465 dlb_member_add_flag = FALSE; 4466 for (i = 0; i < ecmp->max_paths; i++) { 4467 if (dlb_member_count > 1) { 4468 if (!SHR_BITGET(member_bitmap, i)) { 4469 if (dlb_member_add_flag) { 4470 intf_array[i] = dlb_intf_array[j % dlb_member_count]; 4471 j++; 4472 } else { 4473 SHR_BITSET(member_bitmap, i); 4474 intf_array[i] = intf; 4475 dlb_member_add_flag = TRUE; 4476 } 4477 } 4478 } else { 4479 /* Add first primary member into DLB group */ 4480 intf_array[i] = intf; 4481 if (!dlb_member_add_flag) { 4482 SHR_BITSET(member_bitmap, i); 4483 dlb_member_add_flag = TRUE; 4484 } 4485 (*intf_count)++; 4486 } 4487 } 4488 4489 if (!dlb_member_add_flag) { 4490 rv = BCM_E_INTERNAL; 4491 goto clean_up; 4492 } 4493 4494 /* Update ECMP group */ 4495 ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID; 4496 rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *intf_count, 4497 intf_array, BCM_L3_ECMP_MEMBER_OP_ADD, 4498 1, &intf, *intf_count, member_bitmap); 4499 if (BCM_SUCCESS(rv)) { 4500 sal_memcpy(group_member_ptr, member_bitmap, 4501 SHR_BITALLOCSIZE(member_bitmap_width)); 4502 } 4503 4504 clean_up: 4505 4506 if (member_bitmap) { 4507 sal_free(member_bitmap); 4508 } 4509 4510 if (dlb_intf_array) { 4511 sal_free(dlb_intf_array); 4512 } 4513 4514 return rv; 4515 } 4516 4517 /* 4518 * Function: 4519 * bcm_th2_l3_ecmp_dlb_dgm_member_add 4520 * Purpose: 4521 * Add an Egress forwarding object to an Egress DLB/DGM ECMP forwarding object. 4522 * Parameters: 4523 * unit - (IN) bcm device. 4524 * ecmp - (IN) ECMP group info. 4525 * ecmp_member - (IN) Deleted L3 interface id pointing to Egress forwarding object. 4526 * ecmp_member_array - (IN/OUT) Member array of Egress forwarding objects. 4527 * ecmp_member_count - (IN/OUT) Number of members of ecmp_member_count actually filled in. 4528 * 4529 * Returns: 4530 * BCM_E_XXX 4531 */ 4532 int 4533 bcm_th2_l3_ecmp_dlb_dgm_member_add(int unit, 4534 bcm_l3_egress_ecmp_t *ecmp, 4535 bcm_l3_ecmp_member_t *ecmp_member, 4536 bcm_l3_ecmp_member_t *ecmp_member_array, 4537 int *ecmp_member_count) 4538 { 4539 int rv = BCM_E_NONE; 4540 int alloc_size = 0; 4541 bcm_if_t *intf_array = 0; /* Include filler */ 4542 bcm_l3_ecmp_member_t *dlb_member_array = 0; /* Exclude filler */ 4543 int ecmp_group_idx = 0; 4544 int dlb_member_add_flag = FALSE; 4545 int dlb_member_count = 0; /* Exclude filler */ 4546 int alternate_count = 0; /* Include filler */ 4547 int primary_count = 0; /* Include filler */ 4548 int start = 0, end = 0; 4549 int i = 0, j = 0; 4550 int location_offset = 0, copy_offset = 0; 4551 int member_bitmap_width = 0; 4552 SHR_BITDCL *member_bitmap = NULL; 4553 SHR_BITDCL *group_member_ptr = NULL; 4554 4555 /* Allocate DLB member bitmap */ 4556 member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 4557 member_bitmap = sal_alloc(SHR_BITALLOCSIZE(member_bitmap_width), 4558 "DLB ECMP member bitmap"); 4559 if (NULL == member_bitmap) { 4560 rv = BCM_E_MEMORY; 4561 goto clean_up; 4562 } 4563 4564 sal_memset(member_bitmap, 0, SHR_BITALLOCSIZE(member_bitmap_width)); 4565 4566 /* Get currrent group bitmap */ 4567 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 4568 group_member_ptr = 4569 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 4570 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, 0, ecmp->max_paths); 4571 4572 sal_memcpy(member_bitmap, group_member_ptr, 4573 SHR_BITALLOCSIZE(member_bitmap_width)); 4574 4575 /* Allocate interface array */ 4576 alloc_size = sizeof(bcm_if_t) * BCM_XGS3_L3_ECMP_MAX(unit); 4577 intf_array = sal_alloc(alloc_size, "intf array"); 4578 if (NULL == intf_array) { 4579 rv = BCM_E_MEMORY; 4580 goto clean_up; 4581 4582 } 4583 sal_memset(intf_array, 0, alloc_size); 4584 4585 /* 4586 * Index of ecmp_member_array 4587 * - Both primary and alternate members exist: Primary members start 4588 * from 0 and Alternate members start from max_paths / 2 4589 * - Only primary members exist: Primary members start from 0 4590 * - Only alternate members exist: Alternate members start from 0 4591 * Offset of DLB members bitmap 4592 * - Primary members always start from 0 4593 * - Alternate members always start from max_paths / 2 4594 * Member count (including filler) 4595 * - DLB count: 0 or max_paths if exist 4596 * - DGM primary count: 0 or max_paths/2 if exsit 4597 * DGM alternate count: 0 or max_paths/2 if exist 4598 */ 4599 if ((ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) && 4600 (ecmp_member->flags & BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) { 4601 /* Add alternate member */ 4602 start = ecmp->max_paths / 2; 4603 end = start * 2; 4604 4605 /* Get the count of alternate members (without filler) */ 4606 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, 4607 start, end - start); 4608 alternate_count = 4609 dlb_member_count ? ecmp->max_paths / 2 : 0; 4610 primary_count = (*ecmp_member_count) - alternate_count; 4611 4612 /* 4613 * Only alternate members exist: 4614 * Alternate members start from 0, there should a location offset. 4615 */ 4616 if (0 == primary_count) { 4617 location_offset = ecmp->max_paths / 2; 4618 } 4619 4620 } else { 4621 /* Add primary member */ 4622 start = 0; 4623 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 4624 end = ecmp->max_paths / 2; 4625 } else { 4626 end = ecmp->max_paths; 4627 } 4628 4629 /* Get the count of primary members (without filler) */ 4630 SHR_BITCOUNT_RANGE(group_member_ptr, dlb_member_count, start, end); 4631 4632 primary_count = dlb_member_count ? end : 0; 4633 alternate_count = (*ecmp_member_count) - primary_count; 4634 4635 if (ecmp->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 4636 /* 4637 * Add first primary member - Alternate members shoud be moved, 4638 * and start from max_paths / 2 if any. 4639 */ 4640 if (alternate_count > 0) { 4641 copy_offset = ecmp->max_paths / 2; 4642 } 4643 } 4644 } 4645 4646 /* Allocate DLB member array */ 4647 dlb_member_array = sal_alloc(BCM_XGS3_L3_ECMP_MAX(unit) * 4648 sizeof(bcm_l3_ecmp_member_t), 4649 "ecmp member array"); 4650 if (NULL == dlb_member_array) { 4651 rv = BCM_E_MEMORY; 4652 goto clean_up; 4653 } 4654 4655 /* Get the DLB members (including added member) without filler */ 4656 dlb_member_count = 0; 4657 for (i = start - location_offset; i < end - location_offset; i++) { 4658 if (SHR_BITGET(member_bitmap, i + location_offset)) { 4659 sal_memcpy(&dlb_member_array[dlb_member_count++], 4660 &ecmp_member_array[i], 4661 sizeof(bcm_l3_ecmp_member_t)); 4662 } else { 4663 if(!dlb_member_add_flag) { 4664 sal_memcpy(&dlb_member_array[dlb_member_count++], 4665 ecmp_member, 4666 sizeof(bcm_l3_ecmp_member_t)); 4667 dlb_member_add_flag = TRUE; 4668 } 4669 } 4670 } 4671 4672 if (!dlb_member_add_flag) { 4673 rv = BCM_E_FULL; 4674 goto clean_up; 4675 } 4676 4677 /* Refill the members of expanded DLB group */ 4678 dlb_member_add_flag = FALSE; 4679 for (i = start - location_offset; i < end - location_offset; i++) { 4680 if (dlb_member_count > 1) { 4681 if (!SHR_BITGET(member_bitmap, i + location_offset)) { 4682 if (dlb_member_add_flag) { 4683 sal_memcpy(&ecmp_member_array[i], 4684 &dlb_member_array[j % dlb_member_count], 4685 sizeof(bcm_l3_ecmp_member_t)); 4686 j++; 4687 } else { 4688 SHR_BITSET(member_bitmap, i + location_offset); 4689 sal_memcpy(&ecmp_member_array[i], ecmp_member, 4690 sizeof(bcm_l3_ecmp_member_t)); 4691 dlb_member_add_flag = TRUE; 4692 } 4693 } 4694 } else { 4695 /* 4696 * 1. Add first DLB member 4697 * 2. or Add first DGM primary member 4698 * 3. or Add first DGM alternate member 4699 */ 4700 if (copy_offset) { 4701 /* 4702 * DGM - Add the first primary member - 4703 * Alternate members shoud be moved, 4704 * and start from max_paths / 2 instead of 0. 4705 */ 4706 sal_memcpy(&ecmp_member_array[i + copy_offset], 4707 &ecmp_member_array[i], 4708 sizeof(bcm_l3_ecmp_member_t)); 4709 } 4710 sal_memcpy(&ecmp_member_array[i], ecmp_member, 4711 sizeof(bcm_l3_ecmp_member_t)); 4712 4713 if (!dlb_member_add_flag) { 4714 SHR_BITSET(member_bitmap, i + location_offset); 4715 dlb_member_add_flag = TRUE; 4716 } 4717 4718 (*ecmp_member_count)++; 4719 if (!(ecmp_member->flags & 4720 BCM_L3_ECMP_MEMBER_DGM_ALTERNATE)) { 4721 primary_count++; 4722 } 4723 } 4724 } 4725 4726 for (i = 0; i < (*ecmp_member_count); i++) { 4727 intf_array[i] = ecmp_member_array[i].egress_if; 4728 } 4729 4730 /* Update ECMP group */ 4731 ecmp->flags |= BCM_L3_REPLACE | BCM_L3_WITH_ID; 4732 rv = _bcm_esw_l3_ecmp_create(unit, ecmp, *ecmp_member_count, 4733 intf_array, BCM_L3_ECMP_MEMBER_OP_ADD, 4734 1, &(ecmp_member->egress_if), 4735 primary_count, member_bitmap); 4736 if (BCM_SUCCESS(rv)) { 4737 sal_memcpy(group_member_ptr, member_bitmap, 4738 SHR_BITALLOCSIZE(member_bitmap_width)); 4739 } 4740 4741 clean_up: 4742 4743 if (member_bitmap) { 4744 sal_free(member_bitmap); 4745 } 4746 4747 if (intf_array) { 4748 sal_free(intf_array); 4749 } 4750 4751 if (dlb_member_array) { 4752 sal_free(dlb_member_array); 4753 } 4754 4755 return rv; 4756 } 4757 4758 /* 4759 * Function: 4760 * bcm_th2_l3_ecmp_dlb_member_get 4761 * Purpose: 4762 * Get an Egress DLB ECMP forwarding object. 4763 * Parameters: 4764 * unit - (IN) bcm device. 4765 * ecmp - (INOUT) ECMP group info. 4766 * intf_size - (IN) Size of allocated entries in intf_array. 4767 * intf_array - (OUT) Array of Egress forwarding objects. 4768 * intf_count - (OUT) Number of entries of intf_count actually filled in. 4769 * 4770 * Returns: 4771 * BCM_E_XXX 4772 */ 4773 int 4774 bcm_th2_l3_ecmp_dlb_member_get(int unit, 4775 bcm_l3_egress_ecmp_t *ecmp, int intf_size, 4776 bcm_if_t *intf_array, int *intf_count) 4777 { 4778 int rv = BCM_E_NONE; 4779 bcm_if_t *dlb_intf_array = NULL; /* Include filler */ 4780 int dlb_intf_count = 0; /* Include filler */ 4781 int dlb_intf_size = 0; 4782 int ecmp_group_idx = 0; 4783 int i = 0, j = 0; 4784 SHR_BITDCL *group_bitmap_ptr = NULL; 4785 4786 /* input check*/ 4787 if ((NULL == intf_count) || 4788 ((NULL == intf_array) && (0 != intf_size))) { 4789 rv = BCM_E_PARAM; 4790 goto clean_up; 4791 } 4792 4793 if (intf_size) { 4794 dlb_intf_array = sal_alloc(sizeof(bcm_if_t) * 4795 BCM_XGS3_L3_ECMP_MAX(unit), 4796 "ecmp intf array"); 4797 if (NULL == dlb_intf_array) { 4798 rv = BCM_E_MEMORY; 4799 goto clean_up; 4800 } 4801 dlb_intf_size = BCM_XGS3_L3_ECMP_MAX(unit); 4802 } 4803 4804 /* Get the ECMP member's information including filler */ 4805 rv = _bcm_esw_l3_egress_ecmp_get(unit, ecmp, dlb_intf_size, 4806 dlb_intf_array, &dlb_intf_count, TRUE); 4807 if (BCM_FAILURE(rv)) { 4808 goto clean_up; 4809 } 4810 4811 ecmp_group_idx = ecmp->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 4812 group_bitmap_ptr = 4813 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 4814 4815 /* Exclude filler members from expanded DLB group */ 4816 if (intf_size) { 4817 for (i = 0; i < dlb_intf_count; i++) { 4818 if (SHR_BITGET(group_bitmap_ptr, i)) { 4819 intf_array[j++] = dlb_intf_array[i]; 4820 } 4821 if (j == intf_size) { 4822 break; 4823 } 4824 } 4825 *intf_count = j; 4826 } else { 4827 SHR_BITCOUNT_RANGE(group_bitmap_ptr, *intf_count, 0, ecmp->max_paths); 4828 } 4829 4830 clean_up: 4831 4832 if (dlb_intf_array) { 4833 sal_free(dlb_intf_array); 4834 } 4835 4836 return rv; 4837 } 4838 4839 4840 /* 4841 * Function: 4842 * bcm_th2_l3_ecmp_dlb_dgm_member_get 4843 * Purpose: 4844 * Get an Egress DLB/DGM ECMP forwarding object. 4845 * Parameters: 4846 * unit - (IN) bcm device. 4847 * ecmp_info - (INOUT) ECMP group info. 4848 * ecmp_member_size - (IN) Size of allocated entries in ecmp_member_array. 4849 * ecmp_member_array - (OUT) Member array of Egress forwarding objects. 4850 * ecmp_member_count - (OUT) Number of members of ecmp_member_count actually 4851 * filled in. 4852 * Returns: 4853 * BCM_E_XXX 4854 */ 4855 int 4856 bcm_th2_l3_ecmp_dlb_dgm_member_get(int unit, 4857 bcm_l3_egress_ecmp_t *ecmp_info, 4858 int ecmp_member_size, 4859 bcm_l3_ecmp_member_t *ecmp_member_array, 4860 int *ecmp_member_count) 4861 { 4862 int rv = BCM_E_NONE; 4863 int ecmp_group_idx = 0; 4864 int location_offset = 0; 4865 int primary_count = 0; 4866 int i = 0, j = 0; 4867 SHR_BITDCL *group_bitmap_ptr = NULL; 4868 int dlb_member_count = 0; /* Include filler */ 4869 int dlb_member_size = 0; 4870 bcm_l3_ecmp_member_t *dlb_member_array = NULL; /* Include filler */ 4871 4872 /* Input check */ 4873 if ((NULL == ecmp_member_count) || 4874 ((NULL == ecmp_member_array) && (0 != ecmp_member_size))) { 4875 rv = BCM_E_PARAM; 4876 goto clean_up; 4877 } 4878 4879 if (ecmp_member_size) { 4880 dlb_member_array = sal_alloc(sizeof(bcm_l3_ecmp_member_t) * 4881 BCM_XGS3_L3_ECMP_MAX(unit), 4882 "ecmp member array"); 4883 if (NULL == dlb_member_array) { 4884 rv = BCM_E_MEMORY; 4885 goto clean_up; 4886 } 4887 sal_memset(dlb_member_array, 0, sizeof(bcm_l3_ecmp_member_t) * 4888 BCM_XGS3_L3_ECMP_MAX(unit)); 4889 dlb_member_size = BCM_XGS3_L3_ECMP_MAX(unit); 4890 } 4891 4892 /* Get the ECMP member's information including filler */ 4893 rv = _bcm_xgs3_l3_ecmp_member_get( 4894 unit, ecmp_info, dlb_member_size, 4895 dlb_member_array, &dlb_member_count); 4896 4897 if (BCM_FAILURE(rv)) { 4898 goto clean_up; 4899 } 4900 4901 ecmp_group_idx = ecmp_info->ecmp_intf - BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 4902 group_bitmap_ptr = 4903 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, ecmp_group_idx); 4904 4905 if (ecmp_member_size) { 4906 if (ecmp_info->dynamic_mode == BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 4907 4908 SHR_BITCOUNT_RANGE(group_bitmap_ptr, primary_count, 4909 0, ecmp_info->max_paths / 2); 4910 4911 /* Only alternate members exist */ 4912 if (0 == primary_count) { 4913 location_offset = ecmp_info->max_paths / 2; 4914 } 4915 } 4916 4917 /* Exclude filler members from expanded DLB group */ 4918 for (i = 0; i < dlb_member_count; i++) { 4919 if (SHR_BITGET(group_bitmap_ptr, i + location_offset)) { 4920 sal_memcpy(&ecmp_member_array[j++], 4921 &dlb_member_array[i], 4922 sizeof(bcm_l3_ecmp_member_t)); 4923 } 4924 if (j == ecmp_member_size) { 4925 break; 4926 } 4927 } 4928 *ecmp_member_count = j; 4929 } else { 4930 SHR_BITCOUNT_RANGE(group_bitmap_ptr, *ecmp_member_count, 4931 0, ecmp_info->max_paths); 4932 } 4933 4934 clean_up: 4935 4936 if (dlb_member_array) { 4937 sal_free(dlb_member_array); 4938 } 4939 4940 return rv; 4941 } 4942 4943 /* 4944 * Function: 4945 * _bcm_th2_ecmp_dlb_random_seed_set 4946 * Purpose: 4947 * Set ECMP DLB random seed. 4948 * Parameters: 4949 * unit - (IN) SOC unit number. 4950 * seed - (IN) Random seed. 4951 * Returns: 4952 * BCM_E_xxx 4953 */ 4954 STATIC int 4955 _bcm_th2_ecmp_dlb_random_seed_set(int unit, int seed) 4956 { 4957 4958 uint32 rval; 4959 uint32 hw_limit; 4960 4961 hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_RANDOM_SELECTION_CONTROLr, 4962 SEEDf)) - 1; 4963 if (seed < 0 || 4964 seed > hw_limit) { 4965 /* Hardware limits */ 4966 return BCM_E_PARAM; 4967 } 4968 4969 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_RANDOM_SELECTION_CONTROLr(unit, &rval)); 4970 soc_reg_field_set(unit, DLB_ECMP_RANDOM_SELECTION_CONTROLr, &rval, SEEDf, 4971 seed); 4972 4973 BCM_IF_ERROR_RETURN(WRITE_DLB_ECMP_RANDOM_SELECTION_CONTROLr(unit, rval)); 4974 return BCM_E_NONE; 4975 } 4976 4977 4978 4979 4980 /* 4981 * Function: 4982 * _bcm_th2_ecmp_dlb_random_seed_get 4983 * Purpose: 4984 * Set ECMP DLB random seed. 4985 * Parameters: 4986 * unit - (IN) SOC unit number. 4987 * seed - (OUT) Random seed. 4988 * Returns: 4989 * BCM_E_xxx 4990 */ 4991 STATIC int 4992 _bcm_th2_ecmp_dlb_random_seed_get(int unit, int *seed) 4993 { 4994 4995 uint32 rval; 4996 4997 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_RANDOM_SELECTION_CONTROLr(unit, &rval)); 4998 *seed = soc_reg_field_get(unit, DLB_ECMP_RANDOM_SELECTION_CONTROLr, rval, 4999 SEEDf); 5000 return BCM_E_NONE; 5001 } 5002 5003 5004 /* 5005 * Function: 5006 * _bcm_th2_ecmp_dlb_sample_rate_thresholds_set 5007 * Purpose: 5008 * Set ECMP DLB sample period and physical link accounting thresholds. 5009 * Parameters: 5010 * unit - (IN) SOC unit number. 5011 * sample_rate - (IN) Number of samplings per second. 5012 * min_th - (IN) Minimum port load threshold, in mbps. 5013 * max_th - (IN) Maximum port load threshold, in mbps. 5014 * Returns: 5015 * BCM_E_xxx 5016 */ 5017 STATIC int 5018 _bcm_th2_ecmp_dlb_sample_rate_thresholds_set(int unit, int sample_rate, 5019 int min_th, int max_th) 5020 { 5021 int num_time_units; 5022 uint32 measure_control_reg; 5023 int max_th_bytes; 5024 int th_increment; 5025 dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry; 5026 int i; 5027 int th_bytes[7]; 5028 uint32 hw_limit; 5029 5030 if (sample_rate <= 0 || min_th < 0 || max_th < 0) { 5031 return BCM_E_PARAM; 5032 } 5033 5034 if (min_th > max_th) { 5035 max_th = min_th; 5036 } 5037 5038 /* Compute sampling period in units of 1us: 5039 * number of 1us time units = 10^6 / sample_rate 5040 */ 5041 num_time_units = 1000000 / sample_rate; 5042 hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5043 SAMPLING_PERIODf)) - 1; 5044 if (num_time_units < 1 || num_time_units > hw_limit) { 5045 /* Hardware limits */ 5046 return BCM_E_PARAM; 5047 } 5048 5049 /* Compute threshold in bytes per sampling period: 5050 * bytes per 1us = (million bits per sec) * 10^6 / 8 * 10^(-6), 5051 * bytes per sampling period = (bytes per 1us) * (number of 1us 5052 * time units in sampling period) 5053 * = mbps * num_time_units / 8 5054 */ 5055 max_th_bytes = max_th * num_time_units / 8; 5056 hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GLB_QUANTIZE_THRESHOLDm, 5057 PORT_LOADING_THRESHOLDf)) - 1; 5058 if (max_th_bytes > hw_limit) { 5059 /* Hardware limits */ 5060 return BCM_E_PARAM; 5061 } 5062 5063 BCM_IF_ERROR_RETURN 5064 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5065 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5066 &measure_control_reg, SAMPLING_PERIODf, num_time_units); 5067 BCM_IF_ERROR_RETURN 5068 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 5069 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = sample_rate; 5070 5071 /* Use min threshold as threshold 0, and max threshold as threshold 6. 5072 * Thresholds 1 to 5 will be evenly spread out between min and max 5073 * thresholds. 5074 */ 5075 th_increment = (max_th - min_th) / 6; 5076 for (i = 0; i < 7; i++) { 5077 BCM_IF_ERROR_RETURN 5078 (READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i, 5079 &quantize_threshold_entry)); 5080 th_bytes[i] = (min_th + i * th_increment) * num_time_units / 8; 5081 soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_set 5082 (unit, &quantize_threshold_entry, PORT_LOADING_THRESHOLDf, 5083 th_bytes[i]); 5084 BCM_IF_ERROR_RETURN 5085 (WRITE_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i, 5086 &quantize_threshold_entry)); 5087 } 5088 5089 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = min_th; 5090 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = max_th; 5091 5092 return BCM_E_NONE; 5093 } 5094 5095 /* 5096 * Function: 5097 * _bcm_th2_ecmp_dlb_sample_rate_set 5098 * Purpose: 5099 * Set ECMP dynamic load balancing sample rate. 5100 * Parameters: 5101 * unit - (IN) SOC unit number. 5102 * sample_rate - (IN) Number of samplings per second. 5103 * Returns: 5104 * BCM_E_xxx 5105 */ 5106 STATIC int 5107 _bcm_th2_ecmp_dlb_sample_rate_set(int unit, int sample_rate) 5108 { 5109 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit, 5110 sample_rate, ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th, 5111 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th)); 5112 5113 return BCM_E_NONE; 5114 } 5115 5116 5117 /* 5118 * Function: 5119 * _bcm_th2_ecmp_dlb_tx_load_min_th_set 5120 * Purpose: 5121 * Set ECMP DLB port load minimum threshold. 5122 * Parameters: 5123 * unit - (IN) SOC unit number. 5124 * min_th - (IN) Minimum port loading threshold. 5125 * Returns: 5126 * BCM_E_xxx 5127 */ 5128 STATIC int 5129 _bcm_th2_ecmp_dlb_tx_load_min_th_set(int unit, int min_th) 5130 { 5131 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit, 5132 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, min_th, 5133 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th)); 5134 return BCM_E_NONE; 5135 } 5136 5137 /* 5138 * Function: 5139 * _bcm_trident_ecmp_dlb_tx_load_max_th_set 5140 * Purpose: 5141 * Set ECMP DLB port load maximum threshold. 5142 * Parameters: 5143 * unit - (IN) SOC unit number. 5144 * max_th - (IN) Maximum port loading threshold. 5145 * Returns: 5146 * BCM_E_xxx 5147 */ 5148 STATIC int 5149 _bcm_th2_ecmp_dlb_tx_load_max_th_set(int unit, int max_th) 5150 { 5151 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit, 5152 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate, 5153 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th, 5154 max_th)); 5155 return BCM_E_NONE; 5156 } 5157 5158 5159 5160 5161 /* 5162 * Function: 5163 * _bcm_th2_ecmp_dlb_qsize_thresholds_set 5164 * Purpose: 5165 * Set ECMP DLB queue size thresholds. 5166 * Parameters: 5167 * unit - (IN) SOC unit number. 5168 * min_th - (IN) Minimum queue size threshold, in bytes. 5169 * max_th - (IN) Maximum queue size threshold, in bytes. 5170 * Returns: 5171 * BCM_E_xxx 5172 */ 5173 STATIC int 5174 _bcm_th2_ecmp_dlb_qsize_thresholds_set(int unit, int min_th, int max_th) 5175 { 5176 int max_th_cells; 5177 int th_increment; 5178 dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry; 5179 int i; 5180 int th_cells[7]; 5181 uint32 hw_limit; 5182 5183 if (min_th < 0 || max_th < 0) { 5184 return BCM_E_PARAM; 5185 } 5186 5187 if (min_th > max_th) { 5188 max_th = min_th; 5189 } 5190 5191 /* Convert threshold to number of cells */ 5192 max_th_cells = max_th / _BCM_ECMP_DLB_CELL_BYTES; 5193 hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GLB_QUANTIZE_THRESHOLDm, 5194 TOTAL_PORT_QSIZE_THRESHOLDf)) - 1; 5195 if (max_th_cells > hw_limit) { 5196 /* Hardware limits */ 5197 return BCM_E_PARAM; 5198 } 5199 5200 /* Use min threshold as threshold 0, and max threshold as threshold 6. 5201 * Thresholds 1 to 5 will be evenly spread out between min and max 5202 * thresholds. 5203 */ 5204 th_increment = (max_th - min_th) / 6; 5205 for (i = 0; i < 7; i++) { 5206 BCM_IF_ERROR_RETURN 5207 (READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i, 5208 &quantize_threshold_entry)); 5209 th_cells[i] = (min_th + i * th_increment) / _BCM_ECMP_DLB_CELL_BYTES; 5210 soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_set 5211 (unit, &quantize_threshold_entry, TOTAL_PORT_QSIZE_THRESHOLDf, 5212 th_cells[i]); 5213 BCM_IF_ERROR_RETURN 5214 (WRITE_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i, 5215 &quantize_threshold_entry)); 5216 } 5217 5218 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = min_th; 5219 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = max_th; 5220 5221 return BCM_E_NONE; 5222 } 5223 5224 /* 5225 * Function: 5226 * _bcm_th2_ecmp_dlb_qsize_min_th_set 5227 * Purpose: 5228 * Set ECMP DLB queue size minimum threshold. 5229 * Parameters: 5230 * unit - (IN) SOC unit number. 5231 * min_th - (IN) Minimum queue size threshold, in bytes. 5232 * Returns: 5233 * BCM_E_xxx 5234 */ 5235 STATIC int 5236 _bcm_th2_ecmp_dlb_qsize_min_th_set(int unit, int min_th) 5237 { 5238 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_qsize_thresholds_set(unit, 5239 min_th, ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th)); 5240 5241 return BCM_E_NONE; 5242 } 5243 5244 /* 5245 * Function: 5246 * _bcm_th2_ecmp_dlb_qsize_max_th_set 5247 * Purpose: 5248 * Set ECMP DLB queue size maximum threshold. 5249 * Parameters: 5250 * unit - (IN) SOC unit number. 5251 * max_th - (IN) Maximum queue size threshold, in bytes. 5252 * Returns: 5253 * BCM_E_xxx 5254 */ 5255 STATIC int 5256 _bcm_th2_ecmp_dlb_qsize_max_th_set(int unit, int max_th) 5257 { 5258 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_qsize_thresholds_set(unit, 5259 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th, max_th)); 5260 5261 return BCM_E_NONE; 5262 } 5263 5264 5265 /* 5266 * Function: 5267 * _bcm_th2_ecmp_dlb_physical_qsize_thresholds_set 5268 * Purpose: 5269 * Set ECMP DLB physical queue size thresholds. 5270 * Parameters: 5271 * unit - (IN) SOC unit number. 5272 * min_th - (IN) Minimum physical queue size threshold, in bytes. 5273 * max_th - (IN) Maximum physical queue size threshold, in bytes. 5274 * Returns: 5275 * BCM_E_xxx 5276 */ 5277 STATIC int 5278 _bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(int unit, int min_th, int max_th) 5279 { 5280 int max_th_cells; 5281 int th_increment; 5282 dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry; 5283 int i; 5284 int th_cells[7]; 5285 uint32 hw_limit; 5286 soc_field_t qth_field = XPE_PORT_QSIZE_THRESHOLDf; 5287 if (min_th < 0 || max_th < 0) { 5288 return BCM_E_PARAM; 5289 } 5290 5291 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 5292 qth_field = ITM_PORT_QSIZE_THRESHOLDf; 5293 } 5294 5295 if (min_th > max_th) { 5296 max_th = min_th; 5297 } 5298 5299 /* Convert threshold to number of cells */ 5300 max_th_cells = max_th / _BCM_ECMP_DLB_CELL_BYTES; 5301 hw_limit = (1 << soc_mem_field_length(unit, DLB_ECMP_GLB_QUANTIZE_THRESHOLDm, 5302 qth_field)) - 1; 5303 if (max_th_cells > hw_limit) { 5304 /* Hardware limits */ 5305 return BCM_E_PARAM; 5306 } 5307 5308 /* Use min threshold as threshold 0, and max threshold as threshold 6. 5309 * Thresholds 1 to 5 will be evenly spread out between min and max 5310 * thresholds. 5311 */ 5312 th_increment = (max_th - min_th) / 6; 5313 for (i = 0; i < 7; i++) { 5314 BCM_IF_ERROR_RETURN 5315 (READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ANY, i, 5316 &quantize_threshold_entry)); 5317 th_cells[i] = (min_th + i * th_increment) / _BCM_ECMP_DLB_CELL_BYTES; 5318 soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_set 5319 (unit, &quantize_threshold_entry, qth_field, 5320 th_cells[i]); 5321 BCM_IF_ERROR_RETURN 5322 (WRITE_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, MEM_BLOCK_ALL, i, 5323 &quantize_threshold_entry)); 5324 } 5325 5326 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th = min_th; 5327 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th = max_th; 5328 5329 return BCM_E_NONE; 5330 } 5331 5332 5333 5334 /* 5335 * Function: 5336 * _bcm_th2_ecmp_dlb_physical_qsize_min_th_set 5337 * Purpose: 5338 * Set ECMP DLB physical queue size minimum threshold. 5339 * Parameters: 5340 * unit - (IN) SOC unit number. 5341 * min_th - (IN) Minimum physical queue size threshold, in bytes. 5342 * Returns: 5343 * BCM_E_xxx 5344 */ 5345 STATIC int 5346 _bcm_th2_ecmp_dlb_physical_qsize_min_th_set(int unit, int min_th) 5347 { 5348 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(unit, 5349 min_th, ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th)); 5350 5351 return BCM_E_NONE; 5352 } 5353 5354 /* 5355 * Function: 5356 * _bcm_th2_ecmp_dlb_physical_qsize_max_th_set 5357 * Purpose: 5358 * Set ECMP DLB physical queue size maximum threshold. 5359 * Parameters: 5360 * unit - (IN) SOC unit number. 5361 * max_th - (IN) Maximum physical queue size threshold, in bytes. 5362 * Returns: 5363 * BCM_E_xxx 5364 */ 5365 STATIC int 5366 _bcm_th2_ecmp_dlb_physical_qsize_max_th_set(int unit, int max_th) 5367 { 5368 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(unit, 5369 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th, max_th)); 5370 5371 return BCM_E_NONE; 5372 } 5373 5374 5375 /* 5376 * Function: 5377 * _bcm_th2_ecmp_dlb_tx_load_weight_set 5378 * Purpose: 5379 * Set ECMP DLB port load weight. 5380 * Parameters: 5381 * unit - (IN) SOC unit number. 5382 * weight - (IN) Port load weight. 5383 * Returns: 5384 * BCM_E_xxx 5385 */ 5386 STATIC int 5387 _bcm_th2_ecmp_dlb_tx_load_weight_set(int unit, int weight) 5388 { 5389 uint32 measure_control_reg; 5390 uint32 hw_limit; 5391 5392 hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5393 PORT_LOADING_WEIGHTf)) - 1; 5394 if (weight < 0 || 5395 weight > hw_limit) { 5396 /* Hardware limits */ 5397 return BCM_E_PARAM; 5398 } 5399 5400 BCM_IF_ERROR_RETURN 5401 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5402 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5403 &measure_control_reg, PORT_LOADING_WEIGHTf, weight); 5404 BCM_IF_ERROR_RETURN 5405 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 5406 return BCM_E_NONE; 5407 } 5408 5409 /* 5410 * Function: 5411 * _bcm_th2_ecmp_dlb_tx_load_weight_get 5412 * Purpose: 5413 * Get ECMP DLB port load weight. 5414 * Parameters: 5415 * unit - (IN) SOC unit number. 5416 * weight - (OUT) Port load weight. 5417 * Returns: 5418 * BCM_E_xxx 5419 */ 5420 STATIC int 5421 _bcm_th2_ecmp_dlb_tx_load_weight_get(int unit, int *weight) 5422 { 5423 uint32 measure_control_reg; 5424 5425 BCM_IF_ERROR_RETURN 5426 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5427 *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5428 measure_control_reg, PORT_LOADING_WEIGHTf); 5429 5430 return BCM_E_NONE; 5431 } 5432 5433 /* 5434 * Function: 5435 * _bcm_th2_ecmp_dlb_qsize_weight_set 5436 * Purpose: 5437 * Set ECMP DLB qsize weight. 5438 * Parameters: 5439 * unit - (IN) SOC unit number. 5440 * weight - (IN) Qsize weight. 5441 * Returns: 5442 * BCM_E_xxx 5443 */ 5444 STATIC int 5445 _bcm_th2_ecmp_dlb_qsize_weight_set(int unit, int weight) 5446 { 5447 uint32 measure_control_reg; 5448 uint32 hw_limit; 5449 5450 hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5451 TOTAL_QSIZE_WEIGHTf)) - 1; 5452 if (weight < 0 || 5453 weight > hw_limit) { 5454 /* Hardware limits */ 5455 return BCM_E_PARAM; 5456 } 5457 5458 BCM_IF_ERROR_RETURN 5459 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5460 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5461 &measure_control_reg, TOTAL_QSIZE_WEIGHTf, weight); 5462 BCM_IF_ERROR_RETURN 5463 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 5464 return BCM_E_NONE; 5465 } 5466 5467 /* 5468 * Function: 5469 * _bcm_th2_ecmp_dlb_qsize_weight_get 5470 * Purpose: 5471 * Get ECMP DLB qsize weight. 5472 * Parameters: 5473 * unit - (IN) SOC unit number. 5474 * weight - (OUT) Qsize weight. 5475 * Returns: 5476 * BCM_E_xxx 5477 */ 5478 STATIC int 5479 _bcm_th2_ecmp_dlb_qsize_weight_get(int unit, int *weight) 5480 { 5481 uint32 measure_control_reg; 5482 5483 BCM_IF_ERROR_RETURN 5484 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5485 *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5486 measure_control_reg, TOTAL_QSIZE_WEIGHTf); 5487 5488 return BCM_E_NONE; 5489 } 5490 5491 /* 5492 * Function: 5493 * _bcm_th2_ecmp_dlb_physical_qsize_weight_set 5494 * Purpose: 5495 * Set ECMP DLB physical qsize weight. 5496 * Parameters: 5497 * unit - (IN) SOC unit number. 5498 * weight - (IN) Physical Queue size weight. 5499 * Returns: 5500 * BCM_E_xxx 5501 */ 5502 STATIC int 5503 _bcm_th2_ecmp_dlb_physical_qsize_weight_set(int unit, int weight) 5504 { 5505 uint32 measure_control_reg; 5506 soc_field_t qweight_field = XPE_PORT_QSIZE_WEIGHTf; 5507 uint32 hw_limit; 5508 5509 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 5510 qweight_field = ITM_PORT_QSIZE_WEIGHTf; 5511 } 5512 hw_limit = (1 << soc_reg_field_length(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5513 qweight_field)) - 1; 5514 if (weight < 0 || 5515 weight > hw_limit) { 5516 /* Hardware limits */ 5517 return BCM_E_PARAM; 5518 } 5519 5520 BCM_IF_ERROR_RETURN 5521 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5522 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5523 &measure_control_reg, qweight_field, weight); 5524 BCM_IF_ERROR_RETURN 5525 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 5526 return BCM_E_NONE; 5527 } 5528 5529 /* 5530 * Function: 5531 * _bcm_th2_ecmp_dlb_physical_qsize_weight_get 5532 * Purpose: 5533 * Get ECMP DLB physical qsize weight. 5534 * Parameters: 5535 * unit - (IN) SOC unit number. 5536 * weight - (OUT) Physical Queue size weight. 5537 * Returns: 5538 * BCM_E_xxx 5539 */ 5540 STATIC int 5541 _bcm_th2_ecmp_dlb_physical_qsize_weight_get(int unit, int *weight) 5542 { 5543 uint32 measure_control_reg; 5544 5545 BCM_IF_ERROR_RETURN 5546 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5547 #if defined(BCM_TOMAHAWK3_SUPPORT) 5548 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 5549 *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5550 measure_control_reg, ITM_PORT_QSIZE_WEIGHTf); 5551 } else 5552 #endif 5553 { 5554 *weight = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5555 measure_control_reg, XPE_PORT_QSIZE_WEIGHTf); 5556 } 5557 5558 return BCM_E_NONE; 5559 } 5560 5561 /* 5562 * Function: 5563 * _bcm_th2_ecmp_dlb_tx_load_cap_set 5564 * Purpose: 5565 * Set ECMP DLB port load cap control. 5566 * Parameters: 5567 * unit - (IN) SOC unit number. 5568 * cap - (IN) Port load cap control. 5569 * Returns: 5570 * BCM_E_xxx 5571 */ 5572 STATIC int 5573 _bcm_th2_ecmp_dlb_tx_load_cap_set(int unit, int cap) 5574 { 5575 uint32 measure_control_reg; 5576 5577 if (cap < 0 || 5578 cap > 1) { 5579 /* Hardware limits port load cap control to 1 bit */ 5580 return BCM_E_PARAM; 5581 } 5582 5583 BCM_IF_ERROR_RETURN 5584 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5585 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5586 &measure_control_reg, CAP_PORT_LOADING_AVERAGEf, cap); 5587 BCM_IF_ERROR_RETURN 5588 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 5589 return BCM_E_NONE; 5590 } 5591 5592 /* 5593 * Function: 5594 * _bcm_th2_ecmp_dlb_tx_load_cap_get 5595 * Purpose: 5596 * Get ECMP DLB port load cap control. 5597 * Parameters: 5598 * unit - (IN) SOC unit number. 5599 * cap - (OUT) Cap control. 5600 * Returns: 5601 * BCM_E_xxx 5602 */ 5603 STATIC int 5604 _bcm_th2_ecmp_dlb_tx_load_cap_get(int unit, int *cap) 5605 { 5606 uint32 measure_control_reg; 5607 5608 BCM_IF_ERROR_RETURN 5609 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5610 *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5611 measure_control_reg, CAP_PORT_LOADING_AVERAGEf); 5612 5613 return BCM_E_NONE; 5614 } 5615 /* 5616 * Function: 5617 * _bcm_th2_ecmp_dlb_qsize_cap_set 5618 * Purpose: 5619 * Set ECMP DLB queue size cap control. 5620 * Parameters: 5621 * unit - (IN) SOC unit number. 5622 * cap - (IN) Queue size cap control. 5623 * Returns: 5624 * BCM_E_xxx 5625 */ 5626 STATIC int 5627 _bcm_th2_ecmp_dlb_qsize_cap_set(int unit, int cap) 5628 { 5629 uint32 measure_control_reg; 5630 5631 if (cap < 0 || 5632 cap > 1) { 5633 /* Hardware limits port load cap control to 1 bit */ 5634 return BCM_E_PARAM; 5635 } 5636 5637 BCM_IF_ERROR_RETURN 5638 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5639 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5640 &measure_control_reg, CAP_TOTAL_PORT_QSIZE_AVERAGEf, cap); 5641 BCM_IF_ERROR_RETURN 5642 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 5643 return BCM_E_NONE; 5644 } 5645 5646 /* 5647 * Function: 5648 * _bcm_th2_ecmp_dlb_qsize_cap_get 5649 * Purpose: 5650 * Get ECMP DLB queue size cap control. 5651 * Parameters: 5652 * unit - (IN) SOC unit number. 5653 * cap - (OUT) Cap control. 5654 * Returns: 5655 * BCM_E_xxx 5656 */ 5657 STATIC int 5658 _bcm_th2_ecmp_dlb_qsize_cap_get(int unit, int *cap) 5659 { 5660 uint32 measure_control_reg; 5661 5662 BCM_IF_ERROR_RETURN 5663 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5664 *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5665 measure_control_reg, CAP_TOTAL_PORT_QSIZE_AVERAGEf); 5666 5667 return BCM_E_NONE; 5668 } 5669 5670 /* 5671 * Function: 5672 * _bcm_th2_ecmp_dlb_physical_qsize_cap_set 5673 * Purpose: 5674 * Set ECMP DLB physical queue size cap control. 5675 * Parameters: 5676 * unit - (IN) SOC unit number. 5677 * cap - (IN) Physical Queue size cap control. 5678 * Returns: 5679 * BCM_E_xxx 5680 */ 5681 STATIC int 5682 _bcm_th2_ecmp_dlb_physical_qsize_cap_set(int unit, int cap) 5683 { 5684 uint32 measure_control_reg; 5685 soc_field_t qsizeavg_field = CAP_XPE_PORT_QSIZE_AVERAGEf; 5686 5687 if (cap < 0 || 5688 cap > 1) { 5689 /* Hardware limits port load cap control to 1 bit */ 5690 return BCM_E_PARAM; 5691 } 5692 5693 #if defined(BCM_TOMAHAWK3_SUPPORT) 5694 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 5695 qsizeavg_field = CAP_ITM_PORT_QSIZE_AVERAGEf; 5696 } 5697 #endif 5698 5699 BCM_IF_ERROR_RETURN 5700 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5701 soc_reg_field_set(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5702 &measure_control_reg, qsizeavg_field, cap); 5703 BCM_IF_ERROR_RETURN 5704 (WRITE_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, measure_control_reg)); 5705 return BCM_E_NONE; 5706 } 5707 5708 /* 5709 * Function: 5710 * _bcm_th2_ecmp_dlb_physical_qsize_cap_get 5711 * Purpose: 5712 * Get ECMP DLB physical queue size cap control. 5713 * Parameters: 5714 * unit - (IN) SOC unit number. 5715 * cap - (OUT) Physical Queue size cap control. 5716 * Returns: 5717 * BCM_E_xxx 5718 */ 5719 STATIC int 5720 _bcm_th2_ecmp_dlb_physical_qsize_cap_get(int unit, int *cap) 5721 { 5722 uint32 measure_control_reg; 5723 5724 BCM_IF_ERROR_RETURN 5725 (READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, &measure_control_reg)); 5726 #if defined(BCM_TOMAHAWK3_SUPPORT) 5727 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 5728 *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5729 measure_control_reg, CAP_ITM_PORT_QSIZE_AVERAGEf); 5730 } else 5731 #endif 5732 { 5733 *cap = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 5734 measure_control_reg, CAP_XPE_PORT_QSIZE_AVERAGEf); 5735 } 5736 5737 return BCM_E_NONE; 5738 } 5739 5740 5741 /* 5742 * Function: 5743 * _bcm_th2_ecmp_dlb_config_set 5744 * Purpose: 5745 * Set per-chip ECMP dynamic load balancing configuration parameters. 5746 * Parameters: 5747 * unit - (IN) SOC unit number. 5748 * type - (IN) Configuration parameter type. 5749 * arg - (IN) Configuration paramter value. 5750 * Returns: 5751 * BCM_E_xxx 5752 */ 5753 int 5754 _bcm_th2_ecmp_dlb_config_set(int unit, bcm_switch_control_t type, int arg) 5755 { 5756 switch (type) { 5757 case bcmSwitchEcmpDynamicSampleRate: 5758 return _bcm_th2_ecmp_dlb_sample_rate_set(unit, arg); 5759 5760 case bcmSwitchEcmpDynamicEgressBytesExponent: 5761 return _bcm_th2_ecmp_dlb_tx_load_weight_set(unit, arg); 5762 5763 case bcmSwitchEcmpDynamicQueuedBytesExponent: 5764 if (soc_feature(unit, soc_feature_td3_dlb)) { 5765 return BCM_E_UNAVAIL; 5766 } else { 5767 return _bcm_th2_ecmp_dlb_qsize_weight_set(unit, arg); 5768 } 5769 case bcmSwitchEcmpDynamicPhysicalQueuedBytesExponent: 5770 return _bcm_th2_ecmp_dlb_physical_qsize_weight_set(unit, arg); 5771 5772 case bcmSwitchEcmpDynamicEgressBytesDecreaseReset: 5773 return _bcm_th2_ecmp_dlb_tx_load_cap_set(unit, arg); 5774 5775 case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset: 5776 if (soc_feature(unit, soc_feature_td3_dlb)) { 5777 return BCM_E_UNAVAIL; 5778 } else { 5779 return _bcm_th2_ecmp_dlb_qsize_cap_set(unit, arg); 5780 } 5781 case bcmSwitchEcmpDynamicPhysicalQueuedBytesDecreaseReset: 5782 return _bcm_th2_ecmp_dlb_physical_qsize_cap_set(unit, arg); 5783 5784 case bcmSwitchEcmpDynamicEgressBytesMinThreshold: 5785 return _bcm_th2_ecmp_dlb_tx_load_min_th_set(unit, arg); 5786 5787 case bcmSwitchEcmpDynamicEgressBytesMaxThreshold: 5788 return _bcm_th2_ecmp_dlb_tx_load_max_th_set(unit, arg); 5789 5790 case bcmSwitchEcmpDynamicQueuedBytesMinThreshold: 5791 if (soc_feature(unit, soc_feature_td3_dlb)) { 5792 return BCM_E_UNAVAIL; 5793 } else { 5794 return _bcm_th2_ecmp_dlb_qsize_min_th_set(unit, arg); 5795 } 5796 case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold: 5797 if (soc_feature(unit, soc_feature_td3_dlb)) { 5798 return BCM_E_UNAVAIL; 5799 } else { 5800 return _bcm_th2_ecmp_dlb_qsize_max_th_set(unit, arg); 5801 } 5802 case bcmSwitchEcmpDynamicPhysicalQueuedBytesMinThreshold: 5803 return _bcm_th2_ecmp_dlb_physical_qsize_min_th_set(unit, arg); 5804 5805 case bcmSwitchEcmpDynamicPhysicalQueuedBytesMaxThreshold: 5806 return _bcm_th2_ecmp_dlb_physical_qsize_max_th_set(unit, arg); 5807 5808 case bcmSwitchEcmpDynamicRandomSeed: 5809 return _bcm_th2_ecmp_dlb_random_seed_set(unit, arg); 5810 5811 default: 5812 return BCM_E_PARAM; 5813 } 5814 } 5815 5816 /* 5817 * Function: 5818 * _bcm_th2_ecmp_dlb_config_get 5819 * Purpose: 5820 * Get per-chip ECMP dynamic load balancing configuration parameters. 5821 * Parameters: 5822 * unit - (IN) SOC unit number. 5823 * type - (IN) Configuration parameter type. 5824 * arg - (OUT) Configuration paramter value. 5825 * Returns: 5826 * BCM_E_xxx 5827 */ 5828 int 5829 _bcm_th2_ecmp_dlb_config_get(int unit, bcm_switch_control_t type, int *arg) 5830 { 5831 switch (type) { 5832 case bcmSwitchEcmpDynamicSampleRate: 5833 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate; 5834 break; 5835 5836 case bcmSwitchEcmpDynamicEgressBytesExponent: 5837 return _bcm_th2_ecmp_dlb_tx_load_weight_get(unit, arg); 5838 5839 case bcmSwitchEcmpDynamicQueuedBytesExponent: 5840 if (soc_feature(unit, soc_feature_td3_dlb)) { 5841 return BCM_E_UNAVAIL; 5842 } else { 5843 return _bcm_th2_ecmp_dlb_qsize_weight_get(unit, arg); 5844 } 5845 case bcmSwitchEcmpDynamicPhysicalQueuedBytesExponent: 5846 return _bcm_th2_ecmp_dlb_physical_qsize_weight_get(unit, arg); 5847 5848 case bcmSwitchEcmpDynamicEgressBytesDecreaseReset: 5849 return _bcm_th2_ecmp_dlb_tx_load_cap_get(unit, arg); 5850 5851 case bcmSwitchEcmpDynamicQueuedBytesDecreaseReset: 5852 if (soc_feature(unit, soc_feature_td3_dlb)) { 5853 return BCM_E_UNAVAIL; 5854 } else { 5855 return _bcm_th2_ecmp_dlb_qsize_cap_get(unit, arg); 5856 } 5857 case bcmSwitchEcmpDynamicPhysicalQueuedBytesDecreaseReset: 5858 return _bcm_th2_ecmp_dlb_physical_qsize_cap_get(unit, arg); 5859 5860 case bcmSwitchEcmpDynamicEgressBytesMinThreshold: 5861 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th; 5862 break; 5863 5864 case bcmSwitchEcmpDynamicEgressBytesMaxThreshold: 5865 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th; 5866 break; 5867 5868 case bcmSwitchEcmpDynamicQueuedBytesMinThreshold: 5869 if (soc_feature(unit, soc_feature_td3_dlb)) { 5870 return BCM_E_UNAVAIL; 5871 } else { 5872 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th; 5873 break; 5874 } 5875 5876 case bcmSwitchEcmpDynamicQueuedBytesMaxThreshold: 5877 if (soc_feature(unit, soc_feature_td3_dlb)) { 5878 return BCM_E_UNAVAIL; 5879 } else { 5880 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th; 5881 break; 5882 } 5883 5884 case bcmSwitchEcmpDynamicPhysicalQueuedBytesMinThreshold: 5885 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th; 5886 break; 5887 5888 case bcmSwitchEcmpDynamicPhysicalQueuedBytesMaxThreshold: 5889 *arg = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th; 5890 break; 5891 5892 case bcmSwitchEcmpDynamicRandomSeed: 5893 return _bcm_th2_ecmp_dlb_random_seed_get(unit, arg); 5894 5895 default: 5896 return BCM_E_PARAM; 5897 } 5898 5899 return BCM_E_NONE; 5900 } 5901 5902 /* 5903 * Function: 5904 * _bcm_th2_ecmp_dlb_quality_map_profile_init 5905 * Purpose: 5906 * Initialize ECMP DLB quality mapping profile. 5907 * Parameters: 5908 * unit - (IN)SOC unit number. 5909 * Returns: 5910 * BCM_X_XXX 5911 */ 5912 STATIC int 5913 _bcm_th2_ecmp_dlb_quality_map_profile_init(int unit) 5914 { 5915 soc_profile_mem_t *profile; 5916 soc_mem_t mem; 5917 int entry_words; 5918 int entries_per_profile; 5919 int tx_load_percent; 5920 int qsize_percent; 5921 int alloc_size; 5922 uint32 *entry_arr; 5923 int rv = BCM_E_NONE; 5924 void *entries; 5925 uint32 base_index; 5926 int i; 5927 int port; 5928 dlb_ecmp_quantize_control_entry_t quantize_control_entry; 5929 int num_quality_map_profiles; 5930 int field_len; 5931 void *mask_p[1]; 5932 uint32 ent[1] = {0}; 5933 5934 if (NULL == _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) { 5935 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile = 5936 sal_alloc(sizeof(soc_profile_mem_t), 5937 "ECMP DLB Quality Map Profile Mem"); 5938 if (NULL == _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) { 5939 return BCM_E_MEMORY; 5940 } 5941 } else { 5942 soc_profile_mem_destroy(unit, 5943 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile); 5944 } 5945 profile = _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile; 5946 soc_profile_mem_t_init(profile); 5947 5948 mem = DLB_ECMP_PORT_QUALITY_MAPPINGm; 5949 entry_words = sizeof(dlb_ecmp_quality_mapping_entry_t) / sizeof(uint32); 5950 5951 /* Get quality mask */ 5952 field_len = soc_mem_field_length(unit, mem, ASSIGNED_QUALITYf); 5953 soc_mem_field32_set(unit, mem, ent, 5954 ASSIGNED_QUALITYf, (1 << field_len) - 1); 5955 mask_p[0] = ent; 5956 BCM_IF_ERROR_RETURN 5957 (soc_profile_mem_index_create(unit, &mem, &entry_words, 5958 NULL, NULL, mask_p, 1, profile)); 5959 5960 num_quality_map_profiles = 1 << soc_mem_field_length(unit, 5961 DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf); 5962 entries_per_profile = 5963 soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) / 5964 num_quality_map_profiles; 5965 5966 if (!SOC_WARM_BOOT(unit)) { 5967 alloc_size = entries_per_profile * entry_words * sizeof(uint32); 5968 entry_arr = sal_alloc(alloc_size, "ECMP DLB Quality Map entries"); 5969 if (entry_arr == NULL) { 5970 return BCM_E_MEMORY; 5971 } 5972 sal_memset(entry_arr, 0, alloc_size); 5973 5974 /* Assign quality in the entry array, with 100% weight for port load, 5975 * 0% for queue size. 5976 */ 5977 tx_load_percent = 100; 5978 qsize_percent = 0; 5979 rv = _bcm_th2_ecmp_dlb_quality_assign(unit, tx_load_percent, 5980 qsize_percent, entry_arr); 5981 if (BCM_FAILURE(rv)) { 5982 sal_free(entry_arr); 5983 return rv; 5984 } 5985 5986 entries = entry_arr; 5987 rv = soc_profile_mem_add(unit, profile, &entries, entries_per_profile, 5988 &base_index); 5989 sal_free(entry_arr); 5990 if (BCM_FAILURE(rv)) { 5991 return rv; 5992 } 5993 5994 for (port = 0; 5995 port < soc_mem_index_count(unit, DLB_ECMP_QUANTIZE_CONTROLm); 5996 port++) { 5997 BCM_IF_ERROR_RETURN 5998 (READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY, 5999 port, 6000 &quantize_control_entry)); 6001 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, 6002 &quantize_control_entry, PORT_QUALITY_MAPPING_PROFILE_PTRf, 6003 base_index / entries_per_profile); 6004 BCM_IF_ERROR_RETURN 6005 (WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL, 6006 port, 6007 &quantize_control_entry)); 6008 } 6009 6010 for (i = 0; i < entries_per_profile; i++) { 6011 SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i, 6012 port - 1); 6013 } 6014 6015 ECMP_DLB_INFO(unit)-> 6016 ecmp_dlb_load_weight[base_index/entries_per_profile] = 6017 tx_load_percent; 6018 ECMP_DLB_INFO(unit)-> 6019 ecmp_dlb_qsize_weight[base_index/entries_per_profile] = 6020 qsize_percent; 6021 6022 } else { /* Warm boot, recover reference counts and entries_per_set */ 6023 6024 for (port = 0; 6025 port < soc_mem_index_count(unit, DLB_ECMP_QUANTIZE_CONTROLm); 6026 port++) { 6027 BCM_IF_ERROR_RETURN 6028 (READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY, 6029 port, 6030 &quantize_control_entry)); 6031 base_index = soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_get(unit, 6032 &quantize_control_entry, PORT_QUALITY_MAPPING_PROFILE_PTRf); 6033 base_index *= entries_per_profile; 6034 for (i = 0; i < entries_per_profile; i++) { 6035 SOC_PROFILE_MEM_REFERENCE(unit, profile, base_index + i, 1); 6036 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit, profile, 6037 base_index + i, entries_per_profile); 6038 } 6039 } 6040 } 6041 6042 return BCM_E_NONE; 6043 } 6044 6045 6046 /* 6047 * Function: 6048 * _bcm_th2_ecmp_dlb_deinit 6049 * Purpose: 6050 * Deallocate _th2_ecmp_dlb_bk 6051 * Parameters: 6052 * unit - (IN)SOC unit number. 6053 * Returns: 6054 * None 6055 */ 6056 void 6057 _bcm_th2_ecmp_dlb_deinit(int unit) 6058 { 6059 if (_th2_ecmp_dlb_bk[unit]) { 6060 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info) { 6061 sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info); 6062 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info = NULL; 6063 } 6064 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap) { 6065 sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap); 6066 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap = NULL; 6067 } 6068 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap) { 6069 sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap); 6070 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap = NULL; 6071 } 6072 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap) { 6073 sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap); 6074 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap = NULL; 6075 } 6076 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight) { 6077 sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight); 6078 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight = NULL; 6079 } 6080 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight) { 6081 sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight); 6082 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight = NULL; 6083 } 6084 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile) { 6085 soc_profile_mem_destroy(unit, 6086 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile); 6087 sal_free(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile); 6088 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_quality_map_profile = NULL; 6089 } 6090 6091 sal_free(_th2_ecmp_dlb_bk[unit]); 6092 _th2_ecmp_dlb_bk[unit] = NULL; 6093 } 6094 6095 } 6096 6097 /* 6098 * Function: 6099 * _bcm_th2_ecmp_dlb_init 6100 * Purpose: 6101 * Allocate and initialize _th2_ecmp_dlb_bk 6102 * Parameters: 6103 * unit - (IN)SOC unit number. 6104 * Returns: 6105 * BCM_X_XXX 6106 */ 6107 int 6108 _bcm_th2_ecmp_dlb_init(int unit) 6109 { 6110 int rv = BCM_E_NONE; 6111 int num_ecmp_dlb_id; 6112 int flowset_tbl_size; 6113 int total_num_blocks; 6114 int num_quality_map_profiles; 6115 int port; 6116 dlb_ecmp_quantize_control_entry_t quantize_control_entry; 6117 dlb_ecmp_port_quality_update_measure_control_entry_t measure_entry; 6118 dlb_ecmp_eem_configuration_entry_t eem_entry; 6119 int max_ecmp_dlb_ports; 6120 int sample_rate; 6121 int qsize_sel[4] = {1, 0, 0, 1}; 6122 soc_reg_t reg; 6123 int pipe; 6124 uint32 rval; 6125 #ifdef BCM_TRIDENT3_SUPPORT 6126 uint32 reg_val = 0; 6127 #endif 6128 soc_field_t qsf_field = XPE_PORT_QSIZE_THRESHOLD_SCALING_FACTORf; 6129 6130 _bcm_th2_ecmp_dlb_deinit(unit); 6131 6132 if (_th2_ecmp_dlb_bk[unit] == NULL) { 6133 _th2_ecmp_dlb_bk[unit] = sal_alloc( 6134 sizeof(_th2_ecmp_dlb_bookkeeping_t), "_th2_ecmp_dlb_bk"); 6135 if (_th2_ecmp_dlb_bk[unit] == NULL) { 6136 return BCM_E_MEMORY; 6137 } 6138 } 6139 sal_memset(_th2_ecmp_dlb_bk[unit], 0, sizeof(_th2_ecmp_dlb_bookkeeping_t)); 6140 6141 #if defined(BCM_TOMAHAWK3_SUPPORT) 6142 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 6143 qsf_field = ITM_PORT_QSIZE_THRESHOLD_SCALING_FACTORf; 6144 } 6145 #endif 6146 6147 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_property_force_set = 6148 soc_feature(unit, soc_feature_ecmp_dlb_property_force_set); 6149 6150 max_ecmp_dlb_ports = soc_mem_index_count(unit, 6151 DLB_ECMP_QUANTIZE_CONTROLm); 6152 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info == NULL) { 6153 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info = 6154 sal_alloc(sizeof(_th2_ecmp_dlb_port_info_t) * max_ecmp_dlb_ports, 6155 "ecmp_dlb_port_info"); 6156 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info == NULL) { 6157 _bcm_th2_ecmp_dlb_deinit(unit); 6158 return BCM_E_MEMORY; 6159 } 6160 } 6161 sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info, 0, 6162 sizeof(_th2_ecmp_dlb_port_info_t) * max_ecmp_dlb_ports); 6163 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_port_info_size = max_ecmp_dlb_ports; 6164 6165 6166 num_ecmp_dlb_id = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); 6167 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) { 6168 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap = 6169 sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_id), 6170 "ecmp_dlb_id_used_bitmap"); 6171 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap == NULL) { 6172 _bcm_th2_ecmp_dlb_deinit(unit); 6173 return BCM_E_MEMORY; 6174 } 6175 } 6176 sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_used_bitmap, 0, 6177 SHR_BITALLOCSIZE(num_ecmp_dlb_id)); 6178 6179 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap == NULL) { 6180 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap = 6181 sal_alloc(SHR_BITALLOCSIZE(num_ecmp_dlb_id), 6182 "ecmp_dlb_id_dgm_bitmap"); 6183 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap == NULL) { 6184 _bcm_th2_ecmp_dlb_deinit(unit); 6185 return BCM_E_MEMORY; 6186 } 6187 } 6188 sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap, 0, 6189 SHR_BITALLOCSIZE(num_ecmp_dlb_id)); 6190 6191 flowset_tbl_size = soc_mem_index_count(unit, DLB_ECMP_FLOWSETm); 6192 /* Each bit in ecmp_dlb_flowset_block_bitmap corresponds to a block of 256 6193 * flow set table entries. 6194 */ 6195 total_num_blocks = flowset_tbl_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 6196 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) { 6197 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap = 6198 sal_alloc(SHR_BITALLOCSIZE(total_num_blocks), 6199 "ecmp_dlb_flowset_block_bitmap"); 6200 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap == NULL) { 6201 _bcm_th2_ecmp_dlb_deinit(unit); 6202 return BCM_E_MEMORY; 6203 } 6204 } 6205 sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_flowset_block_bitmap, 0, 6206 SHR_BITALLOCSIZE(total_num_blocks)); 6207 6208 num_quality_map_profiles = 1 << soc_mem_field_length(unit, 6209 DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf); 6210 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) { 6211 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight = 6212 sal_alloc(num_quality_map_profiles * sizeof(uint8), 6213 "ecmp_dlb_load_weight"); 6214 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight == NULL) { 6215 _bcm_th2_ecmp_dlb_deinit(unit); 6216 return BCM_E_MEMORY; 6217 } 6218 } 6219 sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_load_weight, 0, 6220 num_quality_map_profiles * sizeof(uint8)); 6221 6222 6223 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight == NULL) { 6224 _th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight = 6225 sal_alloc(num_quality_map_profiles * sizeof(uint8), 6226 "ecmp_dlb_qsize_weight"); 6227 if (_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight == NULL) { 6228 _bcm_th2_ecmp_dlb_deinit(unit); 6229 return BCM_E_MEMORY; 6230 } 6231 } 6232 sal_memset(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_qsize_weight, 0, 6233 num_quality_map_profiles * sizeof(uint8)); 6234 6235 6236 /* Initialize port quality mapping profile */ 6237 rv = _bcm_th2_ecmp_dlb_quality_map_profile_init(unit); 6238 if (BCM_FAILURE(rv)) { 6239 _bcm_th2_ecmp_dlb_deinit(unit); 6240 return rv; 6241 } 6242 6243 if (!SOC_WARM_BOOT(unit)) { 6244 6245 /* Set DLB sampling period and thresholds */ 6246 sample_rate = 62500; 6247 rv = _bcm_th2_ecmp_dlb_sample_rate_thresholds_set(unit, sample_rate, 6248 65536, (65536 * 7)); 6249 if (BCM_FAILURE(rv)) { 6250 _bcm_th2_ecmp_dlb_deinit(unit); 6251 return rv; 6252 } 6253 6254 /* Configure ECMP DLB load EWMA weight */ 6255 rv = _bcm_th2_ecmp_dlb_config_set(unit, 6256 bcmSwitchEcmpDynamicEgressBytesExponent, 0); 6257 if (BCM_FAILURE(rv)) { 6258 _bcm_th2_ecmp_dlb_deinit(unit); 6259 return rv; 6260 } 6261 6262 /* Configure ECMP DLB queue size EWMA weight */ 6263 if (!soc_feature(unit, soc_feature_td3_dlb)) { 6264 rv = _bcm_th2_ecmp_dlb_config_set(unit, 6265 bcmSwitchEcmpDynamicQueuedBytesExponent, 0); 6266 if (BCM_FAILURE(rv)) { 6267 _bcm_th2_ecmp_dlb_deinit(unit); 6268 return rv; 6269 } 6270 } 6271 /* Configure ECMP DLB physical queue size EWMA weight */ 6272 rv = _bcm_th2_ecmp_dlb_config_set(unit, 6273 bcmSwitchEcmpDynamicPhysicalQueuedBytesExponent, 0); 6274 if (BCM_FAILURE(rv)) { 6275 _bcm_th2_ecmp_dlb_deinit(unit); 6276 return rv; 6277 } 6278 6279 /* Configure ECMP DLB load cap control */ 6280 rv = _bcm_th2_ecmp_dlb_config_set(unit, 6281 bcmSwitchEcmpDynamicEgressBytesDecreaseReset, 0); 6282 if (BCM_FAILURE(rv)) { 6283 _bcm_th2_ecmp_dlb_deinit(unit); 6284 return rv; 6285 } 6286 6287 /* Configure ECMP DLB queue size cap control */ 6288 if (!soc_feature(unit, soc_feature_td3_dlb)) { 6289 rv = _bcm_th2_ecmp_dlb_config_set(unit, 6290 bcmSwitchEcmpDynamicQueuedBytesDecreaseReset, 0); 6291 if (BCM_FAILURE(rv)) { 6292 _bcm_th2_ecmp_dlb_deinit(unit); 6293 return rv; 6294 } 6295 } 6296 6297 /* Configure ECMP DLB physical queue size cap control */ 6298 rv = _bcm_th2_ecmp_dlb_config_set(unit, 6299 bcmSwitchEcmpDynamicPhysicalQueuedBytesDecreaseReset, 0); 6300 if (BCM_FAILURE(rv)) { 6301 _bcm_th2_ecmp_dlb_deinit(unit); 6302 return rv; 6303 } 6304 6305 /* Configure ECMP DLB queue size thresholds */ 6306 if (!soc_feature(unit, soc_feature_td3_dlb)) { 6307 rv = _bcm_th2_ecmp_dlb_qsize_thresholds_set(unit, 0, 0); 6308 if (BCM_FAILURE(rv)) { 6309 _bcm_th2_ecmp_dlb_deinit(unit); 6310 return rv; 6311 } 6312 } 6313 /* Configure ECMP DLB physical queue size thresholds */ 6314 rv = _bcm_th2_ecmp_dlb_physical_qsize_thresholds_set(unit, 0, 0); 6315 if (BCM_FAILURE(rv)) { 6316 _bcm_th2_ecmp_dlb_deinit(unit); 6317 return rv; 6318 } 6319 6320 /* Disable link status override by software */ 6321 rv = soc_mem_clear(unit, DLB_ECMP_LINK_CONTROLm, MEM_BLOCK_ALL, 0); 6322 if (BCM_FAILURE(rv)) { 6323 _bcm_th2_ecmp_dlb_deinit(unit); 6324 return rv; 6325 } 6326 6327 /* Clear group membership */ 6328 rv = soc_mem_clear(unit, DLB_ECMP_GROUP_MEMBERSHIPm, MEM_BLOCK_ALL, 0); 6329 if (BCM_FAILURE(rv)) { 6330 _bcm_th2_ecmp_dlb_deinit(unit); 6331 return rv; 6332 } 6333 6334 #ifdef BCM_TOMAHAWK3_SUPPORT 6335 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 6336 uint64 dlb_en_bitmap; 6337 rv = READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap); 6338 if (BCM_SUCCESS(rv)) { 6339 uint64 my_zero; 6340 COMPILER_64_ZERO(my_zero); 6341 soc_reg64_field_set(unit, DLB_ID_0_TO_63_ENABLEr, &dlb_en_bitmap, 6342 BITMAPf, my_zero); 6343 soc_reg64_field_set(unit, DLB_ID_64_TO_127_ENABLEr, 6344 &dlb_en_bitmap, BITMAPf, my_zero); 6345 BCM_IF_ERROR_RETURN(WRITE_DLB_ID_0_TO_63_ENABLEr(unit, 6346 dlb_en_bitmap)); 6347 BCM_IF_ERROR_RETURN(WRITE_DLB_ID_64_TO_127_ENABLEr(unit, 6348 dlb_en_bitmap)); 6349 } 6350 } 6351 #endif 6352 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 6353 /* Clear group port to member tables */ 6354 rv = soc_mem_clear(unit, DLB_ECMP_GROUP_PORT_TO_MEMBERm, 6355 MEM_BLOCK_ALL, 0); 6356 if (BCM_FAILURE(rv)) { 6357 _bcm_th2_ecmp_dlb_deinit(unit); 6358 return rv; 6359 } 6360 } 6361 6362 /* Configure per member quality measure update control. */ 6363 for (port = 0; 6364 port < soc_mem_index_count(unit, 6365 DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm); 6366 port++) { 6367 rv = READ_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm(unit, 6368 MEM_BLOCK_ANY, port, &measure_entry); 6369 if (BCM_FAILURE(rv)) { 6370 _bcm_th2_ecmp_dlb_deinit(unit); 6371 return rv; 6372 } 6373 soc_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm_field32_set(unit, 6374 &measure_entry, ENABLE_MEASURE_AVERAGE_CALCULATIONf, 1); 6375 soc_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm_field32_set(unit, 6376 &measure_entry, ENABLE_PORT_QUALITY_UPDATEf, 1); 6377 soc_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm_field32_set(unit, 6378 &measure_entry, ENABLE_CREDIT_COLLECTIONf, 1); 6379 rv = WRITE_DLB_ECMP_PORT_QUALITY_UPDATE_MEASURE_CONTROLm(unit, 6380 MEM_BLOCK_ALL, port, &measure_entry); 6381 if (BCM_FAILURE(rv)) { 6382 _bcm_th2_ecmp_dlb_deinit(unit); 6383 return rv; 6384 } 6385 } 6386 6387 /* Configure per member threshold scaling factor */ 6388 for (port = 0; 6389 port < soc_mem_index_count(unit, DLB_ECMP_QUANTIZE_CONTROLm); 6390 port++) { 6391 rv = READ_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ANY, 6392 port, &quantize_control_entry); 6393 if (BCM_FAILURE(rv)) { 6394 _bcm_th2_ecmp_dlb_deinit(unit); 6395 return rv; 6396 } 6397 /* default 10G */ 6398 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, 6399 &quantize_control_entry, 6400 PORT_LOADING_THRESHOLD_SCALING_FACTORf, 6401 0); 6402 if (!soc_feature(unit, soc_feature_td3_dlb)) { 6403 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, 6404 &quantize_control_entry, 6405 TOTAL_PORT_QSIZE_THRESHOLD_SCALING_FACTORf, 6406 2); 6407 } 6408 soc_DLB_ECMP_QUANTIZE_CONTROLm_field32_set(unit, 6409 &quantize_control_entry, 6410 qsf_field, 6411 0); 6412 rv = WRITE_DLB_ECMP_QUANTIZE_CONTROLm(unit, MEM_BLOCK_ALL, 6413 port, &quantize_control_entry); 6414 if (BCM_FAILURE(rv)) { 6415 _bcm_th2_ecmp_dlb_deinit(unit); 6416 return rv; 6417 } 6418 } 6419 6420 /* Configure Ethertype eligibility */ 6421 rv = soc_mem_clear(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_MAPm, 6422 MEM_BLOCK_ALL, 0); 6423 if (BCM_FAILURE(rv)) { 6424 _bcm_th2_ecmp_dlb_deinit(unit); 6425 return rv; 6426 } 6427 6428 #ifdef BCM_TRIDENT3_SUPPORT 6429 if (soc_feature(unit, soc_feature_td3_dlb)) { 6430 rv = READ_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, 6431 ®_val); 6432 if (BCM_SUCCESS(rv)) { 6433 soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 6434 ®_val, CONFIGURATIONf, 0); 6435 soc_reg_field_set(unit, DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr, 6436 ®_val, INNER_OUTER_ETHERTYPE_SELECTIONf, 0); 6437 rv = WRITE_DLB_ECMP_ETHERTYPE_ELIGIBILITY_CONTROLr(unit, 6438 reg_val); 6439 } 6440 } else 6441 #endif 6442 { 6443 rv = READ_DLB_ECMP_EEM_CONFIGURATIONm(unit, 6444 MEM_BLOCK_ANY, 0, &eem_entry); 6445 if (BCM_SUCCESS(rv)) { 6446 soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit, 6447 &eem_entry, 6448 CONFIGURATIONf, 0); 6449 if (!(soc_feature(unit, soc_feature_th3_style_dlb))) { 6450 soc_DLB_ECMP_EEM_CONFIGURATIONm_field32_set(unit, 6451 &eem_entry, 6452 INNER_OUTER_ETHERTYPE_SELECTIONf, 0); 6453 } 6454 rv = WRITE_DLB_ECMP_EEM_CONFIGURATIONm(unit, 6455 MEM_BLOCK_ALL, 0, &eem_entry); 6456 } 6457 if (BCM_FAILURE(rv)) { 6458 _bcm_th2_ecmp_dlb_deinit(unit); 6459 return rv; 6460 } 6461 } 6462 6463 #ifdef BCM_TOMAHAWK3_SUPPORT 6464 /* Clear all DLB flow monitoring confuration */ 6465 if (SOC_IS_TOMAHAWK3(unit)) { 6466 int seed = 1; /* Initialize seed to a non-zero value */ 6467 6468 if (soc_property_get(unit, spn_DLB_FLOW_MONITOR_EN, 0)) { 6469 rv = soc_mem_clear(unit, DLB_ECMP_GROUP_MONITOR_CONTROLm, 6470 MEM_BLOCK_ALL, 0); 6471 6472 if (BCM_FAILURE(rv)) { 6473 _bcm_th2_ecmp_dlb_deinit(unit); 6474 return rv; 6475 } 6476 } 6477 6478 /* Program DLB monitor's random selection seed */ 6479 rv = WRITE_DLB_ECMP_MONITOR_CONTROLr(unit, seed); 6480 if (BCM_FAILURE(rv)) { 6481 _bcm_th2_ecmp_dlb_deinit(unit); 6482 return rv; 6483 } 6484 6485 /* Program DLB monitor's random selection seed for IFP */ 6486 rv = WRITE_DLB_ECMP_MONITOR_IFP_CONTROLr(unit, seed); 6487 if (BCM_FAILURE(rv)) { 6488 _bcm_th2_ecmp_dlb_deinit(unit); 6489 return rv; 6490 } 6491 } 6492 #endif 6493 } 6494 if (SOC_REG_IS_VALID(unit, DLB_ECMP_PORT_XPE_A_B_SELECTORr)) { 6495 for (pipe = 0; pipe < NUM_PIPE(unit); pipe ++) { 6496 reg = SOC_REG_UNIQUE_ACC(unit, DLB_ECMP_PORT_XPE_A_B_SELECTORr)[pipe]; 6497 rv = soc_reg_field32_modify(unit, reg, 6498 REG_PORT_ANY, CAP_SINGLE_QSIZE_SELECTORf, qsize_sel[pipe]); 6499 if (BCM_FAILURE(rv)) { 6500 _bcm_th2_ecmp_dlb_deinit(unit); 6501 return rv; 6502 } 6503 } 6504 } 6505 6506 READ_AUX_ARB_CONTROLr(unit, &rval); 6507 if (soc_reg_field_valid(unit, AUX_ARB_CONTROLr, 6508 DLB_HGT_256NS_REFRESH_ENABLEf)) { 6509 soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, 6510 DLB_HGT_256NS_REFRESH_ENABLEf, 1); 6511 } 6512 WRITE_AUX_ARB_CONTROLr(unit, rval); 6513 6514 return rv; 6515 } 6516 6517 6518 #ifdef BCM_WARM_BOOT_SUPPORT 6519 6520 /* 6521 * Function: 6522 * bcm_th2_ecmp_dlb_wb_alloc_size_get 6523 * Purpose: 6524 * Get level 2 warm boot scache size for ECMP DLB. 6525 * Parameters: 6526 * unit - (IN) SOC unit number. 6527 * size - (OUT) Allocation size. 6528 * Returns: 6529 * BCM_E_XXX 6530 */ 6531 int 6532 bcm_th2_ecmp_dlb_wb_alloc_size_get(int unit, int *size) 6533 { 6534 int alloc_size = 0; 6535 int num_elements; 6536 6537 /* Allocate size for the following ECMP DLB parameters: 6538 * int ecmp_dlb_sample_rate; 6539 * int ecmp_dlb_tx_load_min_th; 6540 * int ecmp_dlb_tx_load_max_th; 6541 * int ecmp_dlb_qsize_min_th; 6542 * int ecmp_dlb_qsize_max_th; 6543 * int ecmp_dlb_physical_qsize_min_th; 6544 * int ecmp_dlb_physical_qsize_max_th; 6545 * ecmp_dlb_id_dgm_bitmap 6546 * For TD3, these HW thresholds are absent 6547 * ecmp_dlb_qsize_min_th & ecmp_dlb_qsize_max_th 6548 * For TH3, bitmap for Egr objects are also saved. 6549 */ 6550 if(soc_feature(unit, soc_feature_td3_dlb)) { 6551 alloc_size += sizeof(int) * 5; 6552 } else { 6553 alloc_size += sizeof(int) * 7; 6554 } 6555 /* Allocate size of ecmp_dlb_load_weight & ecmp_dlb_qsize_weight array */ 6556 num_elements = 1 << soc_mem_field_length(unit, 6557 DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf); 6558 alloc_size += sizeof(uint8) * 2 * num_elements; 6559 6560 num_elements = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); 6561 alloc_size += SHR_BITALLOCSIZE(num_elements); 6562 6563 #if defined(BCM_TOMAHAWK3_SUPPORT) 6564 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 6565 /* For TH3, add DLB EGR objects which are not a member of the group. 6566 * Save in a form of bitmap, as this way it always be 4K bytes in size, 6567 * else if IDs are saved directly it might take upto 64K bytes in worst 6568 * case scenario (where all EGR Objects not a part of ECMP groups), as 6569 * there can be max 16K DLB Egr objects. 6570 */ 6571 num_elements = soc_mem_index_count(unit, ING_L3_NEXT_HOPm); 6572 alloc_size += SHR_BITALLOCSIZE(num_elements); 6573 6574 /* For TH3, save the member bitmap for the DLB ECMP group */ 6575 alloc_size += BCM_TH3_L3_ECMP_MAX_DLB_GROUPS * 6576 SHR_BITALLOCSIZE(BCM_TH3_L3_ECMP_DLB_MAX_PATHS * 2); 6577 } else 6578 #endif /* BCM_TOMAHAWK3_SUPPORT */ 6579 { 6580 num_elements = soc_mem_index_count(unit, ING_L3_NEXT_HOPm); 6581 alloc_size += SHR_BITALLOCSIZE(num_elements); 6582 } 6583 *size = alloc_size; 6584 6585 return BCM_E_NONE; 6586 } 6587 6588 /* 6589 * Function: 6590 * bcm_th2_ecmp_dlb_member_sync 6591 * Purpose: 6592 * Sync ECMP DLB member info for those members which do not belong 6593 * to any DLB ECMP group yet. 6594 * Parameters: 6595 * unit - (IN) SOC unit number. 6596 * scache_ptr - (OUT) 6597 * Returns: 6598 * BCM_E_XXX 6599 */ 6600 int 6601 bcm_th2_ecmp_dlb_member_sync(int unit, uint8 **scache_ptr) 6602 { 6603 int port; 6604 6605 SHR_BITDCL *bitmap = (SHR_BITDCL *)(*scache_ptr); 6606 _th2_ecmp_dlb_port_membership_t *current_ptr = NULL; 6607 6608 /* Save the standalone NHOPs from the DLP port based list */ 6609 for (port=0 ;port < ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size ;port++) { 6610 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 6611 while (current_ptr) { 6612 if (-1 == current_ptr->dlb_id) { 6613 if (current_ptr->nh_index < BCM_XGS3_L3_NH_TBL_SIZE(unit)) { 6614 SHR_BITSET(bitmap, current_ptr->nh_index); 6615 } 6616 } 6617 current_ptr = current_ptr->next; 6618 } 6619 } 6620 (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit)); 6621 6622 return BCM_E_NONE; 6623 } 6624 6625 /* 6626 * Function: 6627 * bcm_th2_ecmp_dlb_member_scache_recover 6628 * Purpose: 6629 * Recover ECMP DLB member info for those members which do not belong 6630 * to any DLB ECMP group yet. 6631 * Parameters: 6632 * unit - (IN) SOC unit number. 6633 * scache_ptr - (OUT) 6634 * Returns: 6635 * BCM_E_XXX 6636 */ 6637 int 6638 bcm_th2_ecmp_dlb_member_scache_recover(int unit, uint8 **scache_ptr) 6639 { 6640 int rv = BCM_E_NONE; 6641 6642 int nh_index; 6643 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 6644 uint32 *ing_entry_ptr = NULL; 6645 uint32 port; 6646 uint32 hw_entry[SOC_MAX_MEM_WORDS]; /* Buffer to fill nh entry. */ 6647 SHR_BITDCL *bitmap = (SHR_BITDCL *)(*scache_ptr); 6648 _th2_ecmp_dlb_port_membership_t *membership; 6649 #ifdef BCM_TRIDENT3_SUPPORT 6650 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 6651 #endif 6652 6653 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, nh), 6654 BCM_XGS3_L3_ENT_SZ(unit, nh), 6655 "l3_tbl", &l3_tbl_ptr, NULL); 6656 if (BCM_FAILURE(rv)) { 6657 rv = BCM_E_NONE; 6658 l3_tbl_ptr = NULL; 6659 ing_entry_ptr = &hw_entry[0]; 6660 } 6661 6662 /* Create the DLB port based list */ 6663 SHR_BIT_ITER(bitmap, BCM_XGS3_L3_NH_TBL_SIZE(unit), nh_index) { 6664 /* Read ingress next hop entry. */ 6665 if (l3_tbl_ptr) { 6666 ing_entry_ptr = 6667 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, nh), 6668 uint32 *, l3_tbl_ptr, nh_index); 6669 } else { 6670 BCM_XGS3_L3_MODULE_LOCK(unit); 6671 rv = BCM_XGS3_MEM_READ( 6672 unit, BCM_XGS3_L3_MEM(unit, nh), nh_index, ing_entry_ptr); 6673 BCM_XGS3_L3_MODULE_UNLOCK(unit); 6674 if (BCM_FAILURE(rv)) { 6675 break; 6676 } 6677 } 6678 6679 #ifdef BCM_TRIDENT3_SUPPORT 6680 if (SOC_IS_TRIDENT3X(unit)) { 6681 port = soc_mem_field32_dest_get(unit, BCM_XGS3_L3_MEM(unit, nh), 6682 ing_entry_ptr, DESTINATIONf, &dest_type); 6683 if (dest_type == SOC_MEM_FIF_DEST_DGPP) { 6684 port = (port & SOC_MEM_FIF_DGPP_PORT_MASK); 6685 } else { 6686 continue; 6687 } 6688 } else 6689 #endif 6690 { 6691 if (soc_mem_field32_get( 6692 unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, Tf)) { 6693 /* DLB Egr object cannot be a trunk, Skip the entry */ 6694 continue; 6695 } 6696 port = soc_mem_field32_get( 6697 unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, PORT_NUMf); 6698 } 6699 6700 membership = 6701 sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t), 6702 "ecmp dlb nh membership"); 6703 if (NULL == membership) { 6704 rv = BCM_E_MEMORY; 6705 break; 6706 } 6707 sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t)); 6708 membership->nh_index = nh_index; 6709 membership->dlb_id = -1; 6710 membership->next = ECMP_DLB_PORT_LIST(unit, port); 6711 ECMP_DLB_PORT_LIST(unit, port) = membership; 6712 ECMP_DLB_PORT_INFO(unit, port).nh_count++; 6713 } 6714 6715 if (l3_tbl_ptr) { 6716 soc_cm_sfree(unit, l3_tbl_ptr); 6717 l3_tbl_ptr = NULL; 6718 } 6719 (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit)); 6720 6721 return rv; 6722 } 6723 #if defined(BCM_TOMAHAWK3_SUPPORT) 6724 /* 6725 * Function: 6726 * _bcm_th3_ecmp_dlb_member_sync 6727 * Purpose: 6728 * Sync ECMP DLB member info for those members which do not belong 6729 * to any DLB ECMP group yet. 6730 * Parameters: 6731 * unit - (IN) SOC unit number. 6732 * scache_ptr - (OUT) 6733 * Returns: 6734 * BCM_E_XXX 6735 */ 6736 static int 6737 _bcm_th3_ecmp_dlb_member_sync(int unit, uint8 **scache_ptr) 6738 { 6739 int port; 6740 uint32 bytes; 6741 SHR_BITDCL *bitmap = (SHR_BITDCL *)(*scache_ptr); 6742 _th2_ecmp_dlb_port_membership_t *current_ptr = NULL; 6743 6744 /* Save the standalone NHOPs from the DLP port based list */ 6745 for (port=0 ;port < ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size ;port++) { 6746 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 6747 while (current_ptr) { 6748 if (-1 == current_ptr->dlb_id) { 6749 if (current_ptr->nh_index < BCM_XGS3_L3_NH_TBL_SIZE(unit)) { 6750 SHR_BITSET(bitmap, current_ptr->nh_index); 6751 } 6752 } 6753 current_ptr = current_ptr->next; 6754 } 6755 } 6756 (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit)); 6757 6758 /* Save the member bitmap information for all DLB ECMP groups */ 6759 bitmap = (SHR_BITDCL *) 6760 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR( 6761 unit, BCM_TH3_L3_ECMP_DLB_START(unit)); 6762 bytes = BCM_TH3_L3_ECMP_MAX_DLB_GROUPS * 6763 SHR_BITALLOCSIZE(BCM_TH3_L3_ECMP_DLB_MAX_PATHS * 2); 6764 sal_memcpy((*scache_ptr), bitmap, bytes); 6765 (*scache_ptr) += bytes; 6766 6767 return BCM_E_NONE; 6768 } 6769 6770 /* 6771 * Function: 6772 * _bcm_th3_ecmp_dlb_scache_recover 6773 * Purpose: 6774 * Recover ECMP DLB member info for those members which do not belong 6775 * to any DLB ECMP group yet. 6776 * Parameters: 6777 * unit - (IN) SOC unit number. 6778 * scache_ptr - (OUT) 6779 * Returns: 6780 * BCM_E_XXX 6781 */ 6782 static int 6783 _bcm_th3_ecmp_dlb_scache_recover(int unit, uint8 **scache_ptr) 6784 { 6785 int rv = BCM_E_NONE; 6786 int bytes; 6787 int nh_index; 6788 char *l3_tbl_ptr = NULL; /* Table dma pointer. */ 6789 uint32 *ing_entry_ptr = NULL; 6790 uint32 port; 6791 uint32 hw_entry[SOC_MAX_MEM_WORDS]; /* Buffer to fill nh entry. */ 6792 SHR_BITDCL *bitmap = (SHR_BITDCL *)(*scache_ptr); 6793 _th2_ecmp_dlb_port_membership_t *membership; 6794 6795 rv = bcm_xgs3_l3_tbl_dma(unit, BCM_XGS3_L3_MEM(unit, nh), 6796 BCM_XGS3_L3_ENT_SZ(unit, nh), 6797 "l3_tbl", &l3_tbl_ptr, NULL); 6798 if (BCM_FAILURE(rv)) { 6799 rv = BCM_E_NONE; 6800 l3_tbl_ptr = NULL; 6801 ing_entry_ptr = &hw_entry[0]; 6802 } 6803 6804 /* Create the DLB port based list */ 6805 SHR_BIT_ITER(bitmap, BCM_XGS3_L3_NH_TBL_SIZE(unit), nh_index) { 6806 /* Read ingress next hop entry. */ 6807 if (l3_tbl_ptr) { 6808 ing_entry_ptr = 6809 soc_mem_table_idx_to_pointer(unit, BCM_XGS3_L3_MEM(unit, nh), 6810 uint32 *, l3_tbl_ptr, nh_index); 6811 } else { 6812 BCM_XGS3_L3_MODULE_LOCK(unit); 6813 rv = BCM_XGS3_MEM_READ( 6814 unit, BCM_XGS3_L3_MEM(unit, nh), nh_index, ing_entry_ptr); 6815 BCM_XGS3_L3_MODULE_UNLOCK(unit); 6816 if (BCM_FAILURE(rv)) { 6817 break; 6818 } 6819 } 6820 if (soc_mem_field32_get( 6821 unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, Tf)) { 6822 /* DLB Egr object cannot be a trunk, Skip the entry */ 6823 continue; 6824 } 6825 port = soc_mem_field32_get( 6826 unit, BCM_XGS3_L3_MEM(unit, nh), ing_entry_ptr, PORT_NUMf); 6827 6828 membership = sal_alloc( 6829 sizeof(_th2_ecmp_dlb_port_membership_t), "ecmp dlb nh membership"); 6830 if (NULL == membership) { 6831 rv = BCM_E_MEMORY; 6832 break; 6833 } 6834 sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t)); 6835 membership->nh_index = nh_index; 6836 membership->dlb_id = -1; 6837 membership->next = ECMP_DLB_PORT_LIST(unit, port); 6838 ECMP_DLB_PORT_LIST(unit, port) = membership; 6839 ECMP_DLB_PORT_INFO(unit, port).nh_count++; 6840 } 6841 6842 if (l3_tbl_ptr) { 6843 soc_cm_sfree(unit, l3_tbl_ptr); 6844 l3_tbl_ptr = NULL; 6845 } 6846 (*scache_ptr) += SHR_BITALLOCSIZE(BCM_XGS3_L3_NH_TBL_SIZE(unit)); 6847 if (BCM_FAILURE(rv)) { 6848 return rv; 6849 } 6850 6851 /* Retrieve the member bitmap for DLB ECMP groups */ 6852 bitmap = (SHR_BITDCL *) 6853 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR( 6854 unit, BCM_TH3_L3_ECMP_DLB_START(unit)); 6855 bytes = BCM_TH3_L3_ECMP_MAX_DLB_GROUPS * 6856 SHR_BITALLOCSIZE(BCM_TH3_L3_ECMP_DLB_MAX_PATHS * 2); 6857 sal_memcpy(bitmap, (*scache_ptr), bytes); 6858 (*scache_ptr) += bytes; 6859 return rv; 6860 } 6861 #endif 6862 /* 6863 * Function: 6864 * bcm_th2_ecmp_dlb_sync 6865 * Purpose: 6866 * Store ECMP DLB parameters into scache. 6867 * Parameters: 6868 * unit - (IN) SOC unit number. 6869 * scache_ptr - (IN/OUT) Scache pointer 6870 * Returns: 6871 * BCM_E_XXX 6872 */ 6873 int 6874 bcm_th2_ecmp_dlb_sync(int unit, uint8 **scache_ptr) 6875 { 6876 int value; 6877 int num_elements; 6878 int i; 6879 uint8 load_weight; 6880 uint8 qsize_weight; 6881 6882 /* Store the following ECMP DLB parameters: 6883 * int ecmp_dlb_sample_rate; 6884 * int ecmp_dlb_tx_load_min_th; 6885 * int ecmp_dlb_tx_load_max_th; 6886 * int ecmp_dlb_qsize_min_th; 6887 * int ecmp_dlb_qsize_max_th; 6888 * int ecmp_dlb_physical_qsize_min_th; 6889 * int ecmp_dlb_physical_qsize_max_th; 6890 * ecmp_dlb_id_dgm_bitmap 6891 */ 6892 value = ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate; 6893 sal_memcpy((*scache_ptr), &value, sizeof(int)); 6894 (*scache_ptr) += sizeof(int); 6895 6896 value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th; 6897 sal_memcpy((*scache_ptr), &value, sizeof(int)); 6898 (*scache_ptr) += sizeof(int); 6899 6900 value = ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th; 6901 sal_memcpy((*scache_ptr), &value, sizeof(int)); 6902 (*scache_ptr) += sizeof(int); 6903 6904 if (!soc_feature(unit, soc_feature_td3_dlb)) { 6905 value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th; 6906 sal_memcpy((*scache_ptr), &value, sizeof(int)); 6907 (*scache_ptr) += sizeof(int); 6908 6909 value = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th; 6910 sal_memcpy((*scache_ptr), &value, sizeof(int)); 6911 (*scache_ptr) += sizeof(int); 6912 } 6913 6914 value = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th; 6915 sal_memcpy((*scache_ptr), &value, sizeof(int)); 6916 (*scache_ptr) += sizeof(int); 6917 6918 value = ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th; 6919 sal_memcpy((*scache_ptr), &value, sizeof(int)); 6920 (*scache_ptr) += sizeof(int); 6921 6922 /* Store ecmp_dlb_load_weight & ecmp_dlb_qsize_weight array */ 6923 num_elements = 1 << soc_mem_field_length(unit, 6924 DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf); 6925 for (i = 0; i < num_elements; i++) { 6926 load_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i]; 6927 qsize_weight = ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[i]; 6928 sal_memcpy((*scache_ptr), &load_weight, sizeof(uint8)); 6929 (*scache_ptr) += sizeof(uint8); 6930 sal_memcpy((*scache_ptr), &qsize_weight, sizeof(uint8)); 6931 (*scache_ptr) += sizeof(uint8); 6932 } 6933 6934 num_elements = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); 6935 num_elements = SHR_BITALLOCSIZE(num_elements); 6936 sal_memcpy((*scache_ptr), _th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap, 6937 num_elements); 6938 (*scache_ptr) += num_elements; 6939 6940 #if defined(BCM_TOMAHAWK3_SUPPORT) 6941 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 6942 /* For TH3, add DLB EGR objects which are not a member of the group. 6943 * Save in a form of bitmap, as this way it always be 4K bytes in size, 6944 * else if IDs are saved directly it might take upto 64K bytes in worst 6945 * case scenario (where all EGR Objects not a part of ECMP groups), as 6946 * there can be max 16K DLB Egr objects. 6947 */ 6948 _bcm_th3_ecmp_dlb_member_sync(unit, scache_ptr); 6949 } 6950 #endif /* BCM_TOMAHAWK3_SUPPORT */ 6951 return BCM_E_NONE; 6952 } 6953 6954 /* 6955 * Function: 6956 * bcm_th2_ecmp_dlb_scache_recover 6957 * Purpose: 6958 * Recover ECMP DLB parameters from scache. 6959 * Parameters: 6960 * unit - (IN) SOC unit number. 6961 * scache_ptr - (IN/OUT) Scache pointer 6962 * Returns: 6963 * BCM_E_XXX 6964 */ 6965 int 6966 bcm_th2_ecmp_dlb_scache_recover(int unit, uint8 **scache_ptr) 6967 { 6968 int value; 6969 int num_elements; 6970 int i; 6971 uint8 load_weight; 6972 uint8 qsize_weight; 6973 6974 /* Recover the following ECMP DLB parameters: 6975 * int ecmp_dlb_sample_rate; 6976 * int ecmp_dlb_tx_load_min_th; 6977 * int ecmp_dlb_tx_load_max_th; 6978 * int ecmp_dlb_qsize_min_th; 6979 * int ecmp_dlb_qsize_max_th; 6980 * int ecmp_dlb_physical_qsize_min_th; 6981 * int ecmp_dlb_physical_qsize_max_th; 6982 * ecmp_dlb_id_dgm_bitmap 6983 */ 6984 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 6985 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = value; 6986 (*scache_ptr) += sizeof(int); 6987 6988 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 6989 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = value; 6990 (*scache_ptr) += sizeof(int); 6991 6992 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 6993 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = value; 6994 (*scache_ptr) += sizeof(int); 6995 6996 if (!soc_feature(unit, soc_feature_td3_dlb)) { 6997 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 6998 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = value; 6999 (*scache_ptr) += sizeof(int); 7000 7001 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 7002 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = value; 7003 (*scache_ptr) += sizeof(int); 7004 } 7005 7006 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 7007 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th = value; 7008 (*scache_ptr) += sizeof(int); 7009 7010 sal_memcpy(&value, (*scache_ptr), sizeof(int)); 7011 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th = value; 7012 (*scache_ptr) += sizeof(int); 7013 7014 7015 /* Recover ecmp_dlb_load_weight & ecmp_dlb_qsize_weight array */ 7016 num_elements = 1 << soc_mem_field_length(unit, 7017 DLB_ECMP_QUANTIZE_CONTROLm, PORT_QUALITY_MAPPING_PROFILE_PTRf); 7018 for (i = 0; i < num_elements; i++) { 7019 sal_memcpy(&load_weight, (*scache_ptr), sizeof(uint8)); 7020 ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i] = load_weight; 7021 (*scache_ptr) += sizeof(uint8); 7022 sal_memcpy(&qsize_weight, (*scache_ptr), sizeof(uint8)); 7023 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[i] = qsize_weight; 7024 (*scache_ptr) += sizeof(uint8); 7025 } 7026 7027 num_elements = soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); 7028 num_elements = SHR_BITALLOCSIZE(num_elements); 7029 sal_memcpy(_th2_ecmp_dlb_bk[unit]->ecmp_dlb_id_dgm_bitmap, (*scache_ptr), num_elements); 7030 (*scache_ptr) += num_elements; 7031 7032 #if defined(BCM_TOMAHAWK3_SUPPORT) 7033 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 7034 _bcm_th3_ecmp_dlb_scache_recover(unit, scache_ptr); 7035 } 7036 #endif /* BCM_TOMAHAWK3_SUPPORT */ 7037 7038 ECMP_DLB_INFO(unit)->recovered_from_scache = TRUE; 7039 7040 return BCM_E_NONE; 7041 } 7042 7043 /* 7044 * Function: 7045 * _bcm_th2_ecmp_dlb_member_recover 7046 * Purpose: 7047 * Recover ECMP DLB ports usage and the next hop indices associated 7048 * with the ports. 7049 * Parameters: 7050 * unit - (IN) SOC unit number. 7051 * Returns: 7052 * BCM_E_XXX 7053 */ 7054 STATIC int 7055 _bcm_th2_ecmp_dlb_member_recover(int unit) 7056 { 7057 int rv = BCM_E_NONE; 7058 int port_map_width; 7059 int alloc_size_port_map; 7060 int alloc_size_member_bitmap; 7061 SHR_BITDCL *port_map = NULL; 7062 SHR_BITDCL *port_map2 = NULL; 7063 SHR_BITDCL *member_bitmap = NULL; 7064 int i, j, k; 7065 int port; 7066 int dlb_id; 7067 dlb_ecmp_group_membership_entry_t group_membership_entry; 7068 dlb_ecmp_group_port_to_member_entry_t port2member_entry; 7069 ecmp_dlb_control_entry_t *ecmp_group_entry; 7070 _th2_ecmp_dlb_port_membership_t *membership; 7071 int ecmp_count = 0; /* Next hop count in the group. */ 7072 bcm_if_t *ecmp_member = NULL; /* Ecmp group from hw. */ 7073 dlb_ecmp_group_control_entry_t group_control_entry; 7074 _th2_ecmp_dlb_port_membership_t *current_ptr, *first_ptr; 7075 int membership_pointer; 7076 int base_addr; 7077 int group_enable; 7078 int member_bitmap_width; 7079 int offset; 7080 int count; 7081 int nh_index; 7082 bcm_l3_egress_ecmp_t tmp_ecmp; 7083 int primary_size = 0; 7084 SHR_BITDCL *group_member_ptr = NULL; 7085 int index_min, index_max,buf_size; 7086 uint8 *ecmp_dlb_buf = NULL; 7087 soc_mem_t mem = ECMP_DLB_CONTROLm; 7088 7089 member_bitmap_width = BCM_XGS3_L3_ECMP_DLB_MAX_PATHS(unit) * 2; 7090 7091 /* Allocate port map */ 7092 port_map_width = soc_mem_field_length(unit, 7093 DLB_ECMP_GROUP_MEMBERSHIPm, PORT_MAPf); 7094 alloc_size_port_map = SHR_BITALLOCSIZE(port_map_width); 7095 port_map = sal_alloc(alloc_size_port_map, "DLB ECMP port map"); 7096 if (NULL == port_map) { 7097 rv = BCM_E_MEMORY; 7098 goto cleanup; 7099 } 7100 7101 port_map2 = sal_alloc(alloc_size_port_map, "DLB ECMP port map 2"); 7102 if (NULL == port_map2) { 7103 rv = BCM_E_MEMORY; 7104 goto cleanup; 7105 } 7106 7107 /* Allocate member bitmap */ 7108 alloc_size_member_bitmap = SHR_BITALLOCSIZE(member_bitmap_width); 7109 member_bitmap = sal_alloc(alloc_size_member_bitmap, "DLB ECMP member bitmap"); 7110 if (NULL == member_bitmap) { 7111 rv = BCM_E_MEMORY; 7112 goto cleanup; 7113 } 7114 7115 /* Allocate ECMP group members */ 7116 ecmp_member = sal_alloc(member_bitmap_width * sizeof(bcm_if_t), 7117 "ecmp member array"); 7118 if (NULL == ecmp_member) { 7119 rv = BCM_E_MEMORY; 7120 goto cleanup; 7121 } 7122 7123 index_min = soc_mem_index_min(unit, mem); 7124 index_max = soc_mem_index_max(unit, mem); 7125 buf_size = SOC_MEM_TABLE_BYTES(unit, mem); 7126 ecmp_dlb_buf = soc_cm_salloc(unit, buf_size, "ECMP_DLB_CONTROL buffer"); 7127 if (NULL == ecmp_dlb_buf) { 7128 rv = BCM_E_MEMORY; 7129 goto cleanup; 7130 } 7131 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, index_min, index_max, ecmp_dlb_buf); 7132 if (SOC_FAILURE(rv)) { 7133 goto cleanup; 7134 } 7135 7136 for (i = index_min; i <= index_max; i++) { 7137 ecmp_group_entry = (ecmp_dlb_control_entry_t *) 7138 soc_mem_table_idx_to_pointer 7139 (unit, mem, void *, ecmp_dlb_buf, i); 7140 7141 group_enable = soc_ECMP_DLB_CONTROLm_field32_get(unit, 7142 ecmp_group_entry, 7143 GROUP_ENABLEf); 7144 if (0 == group_enable) { 7145 /* DLB not enabled */ 7146 continue; 7147 } 7148 7149 /* Get DLB group ID */ 7150 dlb_id = soc_ECMP_DLB_CONTROLm_field32_get(unit, ecmp_group_entry, 7151 DLB_IDf); 7152 7153 rv = READ_DLB_ECMP_GROUP_CONTROLm(unit, MEM_BLOCK_ANY, dlb_id, 7154 &group_control_entry); 7155 if (BCM_FAILURE(rv)) { 7156 goto cleanup; 7157 } 7158 membership_pointer = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7159 &group_control_entry, GROUP_MEMBERSHIP_POINTERf); 7160 7161 base_addr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7162 &group_control_entry, GROUP_PORT_TO_MEMBER_BASE_ADDRf); 7163 7164 primary_size = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7165 &group_control_entry, PRIMARY_GROUP_SIZEf); 7166 7167 rv = READ_DLB_ECMP_GROUP_MEMBERSHIPm(unit, MEM_BLOCK_ANY, 7168 membership_pointer, 7169 &group_membership_entry); 7170 if (BCM_FAILURE(rv)) { 7171 goto cleanup; 7172 } 7173 /* We have the DLB_ID here, 7174 * now there are 2 ways to recover these info from hw to sw: 7175 * 1) Use the DLB_ID to get port_map, 7176 * the port map will indicate how many port2member entries are set. 7177 * traverse the valid port2member entries via port map. 7178 * Each port2member entry can be parsed to get the valid bits and then 7179 * the nexthops. Got the nexthop, the DLB_ID, the port. It's enough 7180 * to recover the sw state. 7181 * 2) The first method has a side effect, which is traverse all valid 7182 * port2member entries, and then traverse the valid bits of each. 7183 * That's portnumber * 64 loops in total. 7184 * An alternative way is to get the ecmp members (64 members at most) 7185 * Parse the entries and then get the ports. Same as above, we got 7186 * all the needed info: nexthop, DLB_ID, port. 7187 * 7188 * Actually, the port2member entries are not necessary, if DLB can 7189 * traverse the ecmp member table and get all nexthops pointing 7190 * to the chosen port, it's done. In fact, port2member is just another 7191 * angle of ecmp member table. 7192 */ 7193 7194 /* Get port map */ 7195 sal_memset(port_map, 0, alloc_size_port_map); 7196 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit, 7197 &group_membership_entry, PORT_MAPf, port_map); 7198 7199 sal_memset(port_map2, 0, alloc_size_port_map); 7200 soc_DLB_ECMP_GROUP_MEMBERSHIPm_field_get(unit, 7201 &group_membership_entry, PORT_MAP_ALTERNATEf, port_map2); 7202 7203 /* Get ECMP members */ 7204 /* Check if the ECMP group is DLB enabled. */ 7205 bcm_l3_egress_ecmp_t_init(&tmp_ecmp); 7206 tmp_ecmp.ecmp_intf = i + BCM_XGS3_MPATH_EGRESS_IDX_MIN(unit); 7207 /* 7208 * Increase entry reference count to avoid the failure of calling 7209 * ecmp_get since the reference count of ecmp group is recovered along 7210 * with hash value after the recovery of DLB info. 7211 */ 7212 BCM_XGS3_L3_ENT_REF_CNT_INC( 7213 BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE); 7214 rv = _bcm_esw_l3_egress_ecmp_get(unit, &tmp_ecmp, 0, 7215 NULL, &ecmp_count, TRUE); 7216 BCM_XGS3_L3_ENT_REF_CNT_DEC( 7217 BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE); 7218 if (BCM_FAILURE(rv)) { 7219 goto cleanup; 7220 } 7221 if (tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_NORMAL && 7222 tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_ASSIGNED && 7223 tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_OPTIMAL && 7224 tmp_ecmp.dynamic_mode != BCM_L3_ECMP_DYNAMIC_MODE_DGM) { 7225 rv = BCM_E_INTERNAL; 7226 goto cleanup; 7227 } 7228 7229 if (ecmp_count > member_bitmap_width) { 7230 rv = BCM_E_INTERNAL; 7231 goto cleanup; 7232 } 7233 7234 sal_memset(ecmp_member, 0, member_bitmap_width * sizeof(bcm_if_t)); 7235 /* 7236 * Increase entry reference count to avoid the failure of calling 7237 * ecmp_get since the reference count of ecmp group is recovered along 7238 * with hash value after the recovery of DLB info. 7239 */ 7240 BCM_XGS3_L3_ENT_REF_CNT_INC( 7241 BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE); 7242 rv = _bcm_esw_l3_egress_ecmp_get(unit, &tmp_ecmp, ecmp_count, 7243 ecmp_member, &count, TRUE); 7244 BCM_XGS3_L3_ENT_REF_CNT_DEC( 7245 BCM_XGS3_L3_TBL_PTR(unit, ecmp_grp), i, _BCM_SINGLE_WIDE); 7246 if (BCM_FAILURE(rv)) { 7247 goto cleanup; 7248 } 7249 7250 for (j = 0; j < ecmp_count; j++) { 7251 if (BCM_XGS3_L3_EGRESS_IDX_VALID(unit, ecmp_member[j])) { 7252 offset = BCM_XGS3_EGRESS_IDX_MIN(unit); 7253 } else if (BCM_XGS3_DVP_EGRESS_IDX_VALID(unit, ecmp_member[j])) { 7254 offset = BCM_XGS3_DVP_EGRESS_IDX_MIN(unit); 7255 } else { 7256 rv = BCM_E_PARAM; 7257 goto cleanup; 7258 } 7259 ecmp_member[j] -= offset; 7260 } 7261 7262 SHR_BITOR_RANGE(port_map, port_map2, 0, port_map_width, port_map); 7263 group_member_ptr = 7264 BCM_XGS3_L3_ECMP_DLB_MEMBER_GROUP_PTR(unit, i); 7265 for (port = 0; port < port_map_width; port++) { 7266 if (!SHR_BITGET(port_map, port)){ 7267 continue; 7268 } 7269 7270 rv = (READ_DLB_ECMP_GROUP_PORT_TO_MEMBERm(unit, MEM_BLOCK_ANY, 7271 base_addr + port, 7272 &port2member_entry)); 7273 if (BCM_FAILURE(rv)) { 7274 goto cleanup; 7275 } 7276 7277 /* Get member bitmap */ 7278 sal_memset(member_bitmap, 0, alloc_size_member_bitmap); 7279 soc_DLB_ECMP_GROUP_PORT_TO_MEMBERm_field_get(unit, 7280 &port2member_entry, ECMP_MEMBER_BITMAPf, member_bitmap); 7281 7282 for (k = 0; k < member_bitmap_width; k++) { 7283 if (!SHR_BITGET(member_bitmap, k)) { 7284 continue; 7285 } 7286 if (k >= ecmp_count) { 7287 rv = BCM_E_INTERNAL; 7288 goto cleanup; 7289 } 7290 if (!SHR_BITGET(port_map2, port)) { 7291 nh_index = ecmp_member[k]; 7292 SHR_BITSET(group_member_ptr, k); 7293 } else { /* an alternate port */ 7294 nh_index = ecmp_member[k + primary_size]; 7295 SHR_BITSET(group_member_ptr, k + tmp_ecmp.max_paths / 2); 7296 } 7297 7298 /* now have nh_index (ecmp_member[k]), port (port), dlb_id */ 7299 /* find it nexthop exists in specific port list*/ 7300 current_ptr = ECMP_DLB_PORT_LIST(unit, port); 7301 first_ptr = NULL; 7302 while (current_ptr) { 7303 if (current_ptr->nh_index != nh_index) { 7304 current_ptr = current_ptr->next; 7305 continue; 7306 } 7307 7308 if (dlb_id == current_ptr->dlb_id) { 7309 current_ptr->ref_count++; 7310 break; 7311 } 7312 if (first_ptr == NULL) { 7313 first_ptr = current_ptr; 7314 } 7315 7316 current_ptr = current_ptr->next; 7317 } 7318 7319 if (current_ptr == NULL) { 7320 /* Insert member ID and group to the next hop's linked list of member 7321 * IDs and groups. 7322 */ 7323 membership = sal_alloc(sizeof(_th2_ecmp_dlb_port_membership_t), 7324 "ecmp dlb nh membership"); 7325 if (NULL == membership) { 7326 rv = BCM_E_MEMORY; 7327 goto cleanup; 7328 } 7329 sal_memset(membership, 0, sizeof(_th2_ecmp_dlb_port_membership_t)); 7330 membership->nh_index = nh_index; 7331 membership->ref_count = 1; 7332 membership->dlb_id = dlb_id; 7333 7334 if (first_ptr != NULL) { 7335 /* didnt find exact same node(nh_index, dlb_id) , 7336 * but find same nh_index (A). 7337 * create B after A. 7338 * first_ptr points to A. 7339 */ 7340 membership->next = first_ptr->next; 7341 first_ptr->next = membership; 7342 ECMP_DLB_PORT_INFO(unit, port).dlb_count++; 7343 } else { 7344 /* didnt find same nh_index*/ 7345 /* this is new nh_index, insert it at head */ 7346 membership->next = ECMP_DLB_PORT_LIST(unit, port); 7347 ECMP_DLB_PORT_LIST(unit, port) = membership; 7348 ECMP_DLB_PORT_INFO(unit, port).nh_count++; 7349 ECMP_DLB_PORT_INFO(unit, port).dlb_count++; 7350 } 7351 } 7352 } 7353 } 7354 } 7355 7356 cleanup: 7357 if (ecmp_dlb_buf) { 7358 soc_cm_sfree(unit, ecmp_dlb_buf); 7359 } 7360 if (port_map) { 7361 sal_free(port_map); 7362 } 7363 if (port_map2) { 7364 sal_free(port_map2); 7365 } 7366 if (member_bitmap) { 7367 sal_free(member_bitmap); 7368 } 7369 if (ecmp_member) { 7370 sal_free(ecmp_member); 7371 } 7372 return BCM_E_NONE; 7373 } 7374 7375 /* 7376 * Function: 7377 * _bcm_th2_ecmp_dlb_group_recover 7378 * Purpose: 7379 * Recover ECMP DLB group usage and flowset table usage. 7380 * Parameters: 7381 * unit - (IN) SOC unit number. 7382 * Returns: 7383 * BCM_E_XXX 7384 */ 7385 STATIC int 7386 _bcm_th2_ecmp_dlb_group_recover(int unit) 7387 { 7388 int i; 7389 ecmp_dlb_control_entry_t *ecmp_dlb_control; 7390 int group_enable, dlb_id; 7391 dlb_ecmp_group_control_entry_t group_control_entry; 7392 int entry_base_ptr, dynamic_size_encode, dynamic_size; 7393 int block_base_ptr, num_blocks; 7394 uint32 rval; 7395 int index_min, index_max,buf_size; 7396 uint8 *ecmp_dlb_buf = NULL; 7397 soc_mem_t mem = ECMP_DLB_CONTROLm; 7398 int rv = BCM_E_NONE; 7399 7400 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) { 7401 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval)); 7402 if (1 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval, 7403 RH_DLB_SELECTIONf)) { 7404 /* ECMP DLB hashing is not enabled chip-wide. */ 7405 return BCM_E_NONE; 7406 } 7407 } 7408 7409 index_min = soc_mem_index_min(unit, mem); 7410 index_max = soc_mem_index_max(unit, mem); 7411 buf_size = SOC_MEM_TABLE_BYTES(unit, mem); 7412 ecmp_dlb_buf = soc_cm_salloc(unit, buf_size, "ECMP_DLB_CONTROL buffer for group"); 7413 if (NULL == ecmp_dlb_buf) { 7414 rv = BCM_E_MEMORY; 7415 goto cleanup; 7416 } 7417 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, index_min, index_max, ecmp_dlb_buf); 7418 if (SOC_FAILURE(rv)) { 7419 goto cleanup; 7420 } 7421 7422 for (i = index_min; i <= index_max; i++) { 7423 ecmp_dlb_control = (ecmp_dlb_control_entry_t *) 7424 soc_mem_table_idx_to_pointer 7425 (unit, mem, void *, ecmp_dlb_buf, i); 7426 group_enable = soc_ECMP_DLB_CONTROLm_field32_get(unit, ecmp_dlb_control, 7427 GROUP_ENABLEf); 7428 if (0 == group_enable) { 7429 /* DLB not enabled */ 7430 continue; 7431 } 7432 7433 /* Get DLB group ID and marked it as used */ 7434 dlb_id = soc_ECMP_DLB_CONTROLm_field32_get(unit, ecmp_dlb_control, 7435 DLB_IDf); 7436 _BCM_ECMP_DLB_ID_USED_SET(unit, dlb_id); 7437 7438 /* Get flow set table usage */ 7439 rv = READ_DLB_ECMP_GROUP_CONTROLm(unit, 7440 MEM_BLOCK_ANY, dlb_id, &group_control_entry); 7441 if (SOC_FAILURE(rv)) { 7442 goto cleanup; 7443 } 7444 entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7445 &group_control_entry, FLOW_SET_BASEf); 7446 dynamic_size_encode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7447 &group_control_entry, FLOW_SET_SIZEf); 7448 rv = _bcm_th2_ecmp_dlb_dynamic_size_decode(dynamic_size_encode, 7449 &dynamic_size); 7450 if (SOC_FAILURE(rv)) { 7451 goto cleanup; 7452 } 7453 block_base_ptr = entry_base_ptr >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 7454 num_blocks = dynamic_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 7455 _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, 7456 num_blocks); 7457 #ifdef BCM_TRIDENT3_SUPPORT 7458 if (soc_feature(unit, soc_feature_td3_dlb)) { 7459 ecmp_grp_enhanced_hashing[unit][i] = 1; 7460 } 7461 #endif 7462 } 7463 7464 cleanup: 7465 if (ecmp_dlb_buf) { 7466 soc_cm_sfree(unit, ecmp_dlb_buf); 7467 } 7468 7469 return rv; 7470 } 7471 7472 #if defined(BCM_TOMAHAWK3_SUPPORT) 7473 /* 7474 * Function: 7475 * _bcm_th3_ecmp_dlb_group_recover 7476 * Purpose: 7477 * Recover ECMP DLB group usage and flowset table usage. 7478 * Parameters: 7479 * unit - (IN) SOC unit number. 7480 * Returns: 7481 * BCM_E_XXX 7482 */ 7483 STATIC int 7484 _bcm_th3_ecmp_dlb_group_recover(int unit) 7485 { 7486 int dlb_id; 7487 uint64 dlb_en_bitmap; 7488 dlb_ecmp_group_control_entry_t group_control_entry; 7489 int entry_base_ptr, dynamic_size_encode, dynamic_size; 7490 int block_base_ptr, num_blocks; 7491 uint32 rval; 7492 7493 if (soc_reg_field_valid(unit, ENHANCED_HASHING_CONTROLr, RH_DLB_SELECTIONf)) { 7494 SOC_IF_ERROR_RETURN(READ_ENHANCED_HASHING_CONTROLr(unit, &rval)); 7495 if (1 == soc_reg_field_get(unit, ENHANCED_HASHING_CONTROLr, rval, 7496 RH_DLB_SELECTIONf)) { 7497 /* ECMP DLB hashing is not enabled chip-wide. */ 7498 return BCM_E_NONE; 7499 } 7500 } 7501 7502 for (dlb_id = 0; dlb_id < 128; dlb_id++) { 7503 /* Enable bits for the first 64 groups are in 7504 DLB_ID_0_TO_63_ENABLE register and the next 64 are in 7505 DLB_ID_64_TO_127_ENABLE. */ 7506 if (dlb_id < soc_reg_field_length(unit, 7507 DLB_ID_0_TO_63_ENABLEr, BITMAPf)) { 7508 SOC_IF_ERROR_RETURN( \ 7509 READ_DLB_ID_0_TO_63_ENABLEr(unit, &dlb_en_bitmap)); 7510 if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id))) { 7511 continue; 7512 } 7513 } else { 7514 SOC_IF_ERROR_RETURN( \ 7515 READ_DLB_ID_64_TO_127_ENABLEr(unit, &dlb_en_bitmap)); 7516 if (!(COMPILER_64_BITTEST(dlb_en_bitmap, dlb_id - 7517 soc_reg_field_length(unit, DLB_ID_0_TO_63_ENABLEr, BITMAPf)))) { 7518 continue; 7519 } 7520 } 7521 7522 /* Get DLB group ID and marked it as used */ 7523 _BCM_ECMP_DLB_ID_USED_SET(unit, dlb_id); 7524 7525 /* Get flow set table usage */ 7526 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GROUP_CONTROLm(unit, 7527 MEM_BLOCK_ANY, dlb_id, &group_control_entry)); 7528 entry_base_ptr = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7529 &group_control_entry, FLOW_SET_BASEf); 7530 dynamic_size_encode = soc_DLB_ECMP_GROUP_CONTROLm_field32_get(unit, 7531 &group_control_entry, FLOW_SET_SIZEf); 7532 BCM_IF_ERROR_RETURN 7533 (_bcm_th2_ecmp_dlb_dynamic_size_decode(dynamic_size_encode, 7534 &dynamic_size)); 7535 block_base_ptr = entry_base_ptr >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 7536 num_blocks = dynamic_size >> _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 7537 _BCM_ECMP_DLB_FLOWSET_BLOCK_USED_SET_RANGE(unit, block_base_ptr, 7538 num_blocks); 7539 } 7540 7541 return BCM_E_NONE; 7542 } 7543 #endif 7544 7545 /* 7546 * Function: 7547 * _bcm_th2_ecmp_dlb_quality_parameters_recover 7548 * Purpose: 7549 * Recover ECMP DLB parameters used to derive a member's quality. 7550 * Parameters: 7551 * unit - (IN) SOC unit number. 7552 * Returns: 7553 * BCM_E_XXX 7554 */ 7555 STATIC int 7556 _bcm_th2_ecmp_dlb_quality_parameters_recover(int unit) 7557 { 7558 uint32 measure_control_reg; 7559 int num_time_units; 7560 dlb_ecmp_glb_quantize_threshold_entry_t quantize_threshold_entry; 7561 int min_th_bytes, min_th_cells; 7562 int max_th_bytes, max_th_cells; 7563 int entries_per_profile; 7564 int profile_ptr, base_index; 7565 dlb_ecmp_quality_mapping_entry_t quality_mapping_entry; 7566 int quality; 7567 int num_profile; 7568 7569 if (ECMP_DLB_INFO(unit)->recovered_from_scache) { 7570 /* If already recovered from scache, do nothing. */ 7571 return BCM_E_NONE; 7572 } 7573 7574 /* Recover sampling rate */ 7575 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_QUALITY_MEASURE_CONTROLr(unit, 7576 &measure_control_reg)); 7577 num_time_units = soc_reg_field_get(unit, DLB_ECMP_QUALITY_MEASURE_CONTROLr, 7578 measure_control_reg, SAMPLING_PERIODf); 7579 if (num_time_units > 0) { 7580 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate = 1000000 / num_time_units; 7581 } 7582 7583 /* Recover min and max load, queue size and physical queue size thresholds: 7584 * Load threshold (in mbps) 7585 * = (bytes per sampling period) * 8 bits per byte / 7586 * (sampling period in seconds) / 10^6 7587 * = (bytes per sampling period) * 8 bits per byte / 7588 * (num_time_units * 1 us per time unit * 10^-6) / 10^6 7589 * = (bytes per sampling period) * 8 / num_time_units 7590 */ 7591 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, 7592 MEM_BLOCK_ANY, 0, &quantize_threshold_entry)); 7593 min_th_bytes = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get 7594 (unit, &quantize_threshold_entry, PORT_LOADING_THRESHOLDf); 7595 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th = (min_th_bytes << 3) / 7596 num_time_units; 7597 7598 if (!soc_feature(unit, soc_feature_td3_dlb)) { 7599 min_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get 7600 (unit, &quantize_threshold_entry, TOTAL_PORT_QSIZE_THRESHOLDf); 7601 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th = 7602 min_th_cells * _BCM_ECMP_DLB_CELL_BYTES; 7603 } 7604 7605 min_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get 7606 (unit, &quantize_threshold_entry, XPE_PORT_QSIZE_THRESHOLDf); 7607 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th = 7608 min_th_cells * _BCM_ECMP_DLB_CELL_BYTES; 7609 7610 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm(unit, 7611 MEM_BLOCK_ANY, soc_mem_index_max(unit, 7612 DLB_ECMP_GLB_QUANTIZE_THRESHOLDm), 7613 &quantize_threshold_entry)); 7614 max_th_bytes = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get 7615 (unit, &quantize_threshold_entry, PORT_LOADING_THRESHOLDf); 7616 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th = (max_th_bytes << 3) / 7617 num_time_units; 7618 7619 if (!soc_feature(unit, soc_feature_td3_dlb)) { 7620 max_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get 7621 (unit, &quantize_threshold_entry, TOTAL_PORT_QSIZE_THRESHOLDf); 7622 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th = 7623 max_th_cells * _BCM_ECMP_DLB_CELL_BYTES; 7624 } 7625 7626 max_th_cells = soc_DLB_ECMP_GLB_QUANTIZE_THRESHOLDm_field32_get 7627 (unit, &quantize_threshold_entry, XPE_PORT_QSIZE_THRESHOLDf); 7628 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th = 7629 max_th_cells * _BCM_ECMP_DLB_CELL_BYTES; 7630 7631 /* Recover load weights and qsize weights */ 7632 num_profile = 1 << soc_mem_field_length(unit, DLB_ECMP_QUANTIZE_CONTROLm, 7633 PORT_QUALITY_MAPPING_PROFILE_PTRf); 7634 entries_per_profile = 7635 soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) / num_profile; 7636 for (profile_ptr = 0; profile_ptr < num_profile; profile_ptr++) { 7637 base_index = profile_ptr * entries_per_profile; 7638 /* quality = (quantized_tx_load * tx_load_percent + 7639 * quantized_qsize * qsize_percent + 7640 * quantized_physical_qsize * 7641 * (100 - tx_load_percent - qsize_percent)) / 100; 7642 * The index to DLB_ECMP_PORT_QUALITY_MAPPING table consists of 7643 * base_index + quantized_tx_load * 64 + 7644 * quantized_qsize * 8 + quantized_physical_qsize, 7645 * where quantized_tx_load, quantized_qsize and quantized_physical_qsize 7646 * range from 0 to 7. 7647 * 7648 * With quantized_tx_load = 7, quantized_qsize = quantized_physical_qsize = 0, 7649 * the index to DLB_ECMP_PORT_QUALITY_MAPPING table is 7650 * base_index + 448, and the tx_load_percent expression 7651 * simplifies to quality * 100 / 7; 7652 * 7653 * With quantized_qsize = 7, quantized_tx_load = quantized_physical_qsize = 0, 7654 * the index to DLB_ECMP_PORT_QUALITY_MAPPING table is 7655 * base_index + 56, and the qsize_percent expression 7656 * simplifies to quality * 100 / 7; 7657 */ 7658 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_PORT_QUALITY_MAPPINGm(unit, 7659 MEM_BLOCK_ANY, base_index + 448, 7660 &quality_mapping_entry)); 7661 quality = soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_get(unit, 7662 &quality_mapping_entry, ASSIGNED_QUALITYf); 7663 ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[profile_ptr] = 7664 quality * 100 / 7; 7665 BCM_IF_ERROR_RETURN(READ_DLB_ECMP_PORT_QUALITY_MAPPINGm(unit, 7666 MEM_BLOCK_ANY, base_index + 56, 7667 &quality_mapping_entry)); 7668 quality = soc_DLB_ECMP_PORT_QUALITY_MAPPINGm_field32_get(unit, 7669 &quality_mapping_entry, ASSIGNED_QUALITYf); 7670 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[profile_ptr] = 7671 quality * 100 / 7; 7672 } 7673 7674 return BCM_E_NONE; 7675 } 7676 7677 /* 7678 * Function: 7679 * bcm_th2_ecmp_dlb_hw_recover 7680 * Purpose: 7681 * Recover ECMP DLB internal state from hardware. 7682 * Parameters: 7683 * unit - (IN) SOC unit number. 7684 * scache_ptr - (IN/OUT) Scache pointer 7685 * Returns: 7686 * BCM_E_XXX 7687 */ 7688 int 7689 bcm_th2_ecmp_dlb_hw_recover(int unit) 7690 { 7691 #if defined(BCM_TOMAHAWK3_SUPPORT) 7692 if (soc_feature(unit, soc_feature_th3_style_dlb)) { 7693 7694 BCM_IF_ERROR_RETURN(_bcm_th3_ecmp_dlb_member_recover(unit)); 7695 BCM_IF_ERROR_RETURN(_bcm_th3_ecmp_dlb_group_recover(unit)); 7696 } else 7697 #endif 7698 { 7699 7700 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_member_recover(unit)); 7701 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_group_recover(unit)); 7702 } 7703 BCM_IF_ERROR_RETURN(_bcm_th2_ecmp_dlb_quality_parameters_recover(unit)); 7704 return BCM_E_NONE; 7705 } 7706 7707 #endif /* BCM_WARM_BOOT_SUPPORT */ 7708 7709 7710 #ifndef BCM_SW_STATE_DUMP_DISABLE 7711 /* 7712 * Function: 7713 * bcm_th2_ecmp_dlb_sw_dump 7714 * Purpose: 7715 * Displays ECMP DLB information maintained by software. 7716 * Parameters: 7717 * unit - (IN) Device unit number. 7718 * Returns: 7719 * None 7720 */ 7721 void 7722 bcm_th2_ecmp_dlb_sw_dump(int unit) 7723 { 7724 int i; 7725 _th2_ecmp_dlb_port_membership_t *current_ptr; 7726 int num_entries_per_profile; 7727 int num_profiles; 7728 int rv; 7729 int ref_count; 7730 7731 LOG_CLI((BSL_META_U(unit, 7732 " ECMP DLB Info -\n"))); 7733 7734 /* Print ECMP DLB next hop info */ 7735 LOG_CLI((BSL_META_U(unit, 7736 " ECMP DLB Port Info -\n"))); 7737 for (i = 0; i < ECMP_DLB_INFO(unit)->ecmp_dlb_port_info_size; i++) { 7738 if (ECMP_DLB_PORT_INFO(unit, i).nh_count > 0) { 7739 LOG_CLI((BSL_META_U(unit, 7740 " Port Number %d output by "), 7741 i)); 7742 current_ptr = ECMP_DLB_PORT_LIST(unit, i); 7743 while (NULL != current_ptr) { 7744 LOG_CLI((BSL_META_U(unit, 7745 "nexthop %d in DLB ID %d Ref_count %d"), 7746 current_ptr->nh_index, current_ptr->dlb_id, current_ptr->ref_count)); 7747 current_ptr = current_ptr->next; 7748 if (NULL == current_ptr) { 7749 LOG_CLI((BSL_META_U(unit, 7750 "\n"))); 7751 } else { 7752 LOG_CLI((BSL_META_U(unit, 7753 ", "))); 7754 } 7755 } 7756 } 7757 } 7758 7759 /* Print ECMP DLB group usage */ 7760 LOG_CLI((BSL_META_U(unit, 7761 " ECMP DLB Groups Used:"))); 7762 for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) { 7763 if (_BCM_ECMP_DLB_ID_USED_GET(unit, i)) { 7764 LOG_CLI((BSL_META_U(unit, 7765 " %d"), i)); 7766 } 7767 } 7768 LOG_CLI((BSL_META_U(unit, 7769 "\n"))); 7770 7771 /* Print ECMP DLB flowset table usage */ 7772 LOG_CLI((BSL_META_U(unit, 7773 " ECMP DLB Flowset Table Blocks Used:"))); 7774 for (i = 0; 7775 i < soc_mem_index_count(unit, DLB_ECMP_FLOWSETm) >> 7776 _BCM_ECMP_DLB_FLOWSET_BLOCK_SIZE_SHIFT; 7777 i++) { 7778 if (_BCM_ECMP_DLB_FLOWSET_BLOCK_USED_GET(unit, i)) { 7779 LOG_CLI((BSL_META_U(unit, 7780 " %d"), i)); 7781 } 7782 } 7783 LOG_CLI((BSL_META_U(unit, 7784 "\n"))); 7785 7786 /* Print sample rate and threshold parameters */ 7787 LOG_CLI((BSL_META_U(unit, 7788 " Sample rate: %d per second\n"), 7789 ECMP_DLB_INFO(unit)->ecmp_dlb_sample_rate)); 7790 LOG_CLI((BSL_META_U(unit, 7791 " Tx load min threshold: %d mbps\n"), 7792 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_min_th)); 7793 LOG_CLI((BSL_META_U(unit, 7794 " Tx load max threshold: %d mbps\n"), 7795 ECMP_DLB_INFO(unit)->ecmp_dlb_tx_load_max_th)); 7796 if (!soc_feature(unit, soc_feature_td3_dlb)) { 7797 LOG_CLI((BSL_META_U(unit, 7798 " Total Queue size min threshold: %d cells\n"), 7799 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_min_th)); 7800 LOG_CLI((BSL_META_U(unit, 7801 " Total Queue size max threshold: %d cells\n"), 7802 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_max_th)); 7803 } 7804 LOG_CLI((BSL_META_U(unit, 7805 " Physical Queue size min threshold: %d cells\n"), 7806 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_min_th)); 7807 LOG_CLI((BSL_META_U(unit, 7808 " Physical Queue size max threshold: %d cells\n"), 7809 ECMP_DLB_INFO(unit)->ecmp_dlb_physical_qsize_max_th)); 7810 7811 /* Print quality mapping profiles */ 7812 LOG_CLI((BSL_META_U(unit, 7813 " Quality mapping profiles:\n"))); 7814 num_entries_per_profile = soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm)/ 7815 (1 << soc_mem_field_length(unit, DLB_ECMP_QUANTIZE_CONTROLm, 7816 PORT_QUALITY_MAPPING_PROFILE_PTRf)); 7817 num_profiles = soc_mem_index_count(unit, DLB_ECMP_PORT_QUALITY_MAPPINGm) / 7818 num_entries_per_profile; 7819 for (i = 0; i < num_profiles; i++) { 7820 LOG_CLI((BSL_META_U(unit, 7821 " Profile %d: load weight %d percent, "\ 7822 "qsize weight %d percent, "), 7823 i, ECMP_DLB_INFO(unit)->ecmp_dlb_load_weight[i], 7824 ECMP_DLB_INFO(unit)->ecmp_dlb_qsize_weight[i])); 7825 rv = soc_profile_mem_ref_count_get(unit, 7826 ECMP_DLB_INFO(unit)->ecmp_dlb_quality_map_profile, 7827 i * num_entries_per_profile, &ref_count); 7828 if (BCM_FAILURE(rv)) { 7829 LOG_CLI((BSL_META_U(unit, 7830 "\n"))); 7831 continue; 7832 } 7833 LOG_CLI((BSL_META_U(unit, 7834 "ref count %d\n"), ref_count)); 7835 } 7836 7837 return; 7838 } 7839 7840 #if defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TRIDENT3_SUPPORT) 7841 void 7842 bcm_th2_dgm_sw_dump(int unit) 7843 { 7844 int i; 7845 LOG_CLI((BSL_META_U(unit, 7846 " DGM Info -\n"))); 7847 7848 LOG_CLI((BSL_META_U(unit, 7849 " DGM Alternate Count:(ECMP Group- Alternate Count)"))); 7850 for (i = 0; i < BCM_XGS3_L3_ECMP_MAX_GROUPS(unit); i++) { 7851 if (BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[i] != 0) { 7852 LOG_CLI((BSL_META_U(unit, 7853 " %d-%d"), i, 7854 BCM_XGS3_L3_ALTERNATE_CNT_PTR(unit)[i])); 7855 } 7856 } 7857 LOG_CLI((BSL_META_U(unit, 7858 "\n"))); 7859 7860 /* Print ECMP DGM group usage */ 7861 LOG_CLI((BSL_META_U(unit, 7862 " DGM Groups Used:"))); 7863 for (i = 0; i < soc_mem_index_count(unit, DLB_ECMP_GROUP_CONTROLm); i++) { 7864 if (_BCM_ECMP_DLB_ID_DGM_GET(unit, i)) { 7865 LOG_CLI((BSL_META_U(unit, 7866 " %d"), i)); 7867 } 7868 } 7869 LOG_CLI((BSL_META_U(unit, 7870 "\n"))); 7871 } 7872 #endif 7873 #endif /* ifndef BCM_SW_STATE_DUMP_DISABLE*/ 7874 7875 #endif /* INCLUDE_L3 && BCM_TOMAHAWK2_SUPPORT */ 7876