ecmp.c (58980B)
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: ecmp.c 8 * Purpose: Ecmp SOC functions. 9 */ 10 11 12 #include <soc/defs.h> 13 14 #ifdef SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT 15 16 #include <shared/bsl.h> 17 #include <soc/error.h> 18 #include <soc/esw/ecmp.h> 19 20 #ifdef BCM_WARM_BOOT_SUPPORT 21 #include <soc/scache.h> 22 23 #define SOC_ESW_ECMP_WB_VERSION_1_1 SOC_SCACHE_VERSION(1,1) 24 25 /* Default warmboot version */ 26 #define SOC_ESW_ECMP_WB_DEFAULT_VERSION SOC_ESW_ECMP_WB_VERSION_1_1 27 28 29 #define SOC_ESW_ECMP_WB_SIZE(_data_) sizeof(*(_data_)) 30 31 32 #define SOC_ESW_ECMP_WB_SYNC(_scache_, _data_) \ 33 do { \ 34 sal_memcpy((_scache_), (_data_), sizeof(*(_data_))); \ 35 (_scache_) += sizeof(*(_data_)); \ 36 } while (0) 37 38 #define SOC_ESW_ECMP_WB_RECOVER(_scache_, _data_) \ 39 do { \ 40 sal_memcpy((_data_), (_scache_), sizeof(*(_data_))); \ 41 (_scache_) += sizeof(*(_data_)); \ 42 } while (0) 43 44 #endif /* BCM_WARM_BOOT_SUPPORT */ 45 46 47 /* SOC ESW ECMP State */ 48 soc_esw_ecmp_state_t *soc_esw_ecmp_state[SOC_MAX_NUM_DEVICES]; 49 50 static const soc_mem_t ecmp_member_mems[] = { 51 INITIAL_L3_ECMPm, 52 L3_ECMPm 53 }; 54 55 static const soc_mem_t ecmp_group_mems[] = { 56 INITIAL_L3_ECMP_GROUPm, 57 L3_ECMP_COUNTm 58 }; 59 60 61 62 STATIC void 63 soc_esw_nh_if_ecmp_grp_decode(int unit, uint32 *nh_idx, int *ecmpf) 64 { 65 int ecmp_if_offset; 66 67 ecmp_if_offset = SOC_ESW_ECMP_STATE(unit)->ecmp_grp_if_offset; 68 69 if (*nh_idx >= ecmp_if_offset) { 70 *ecmpf = 1; 71 *nh_idx -= ecmp_if_offset; 72 } 73 74 return; 75 } 76 77 STATIC void 78 soc_esw_nh_if_ecmp_grp_encode(int unit, uint32 *nh_idx, int ecmpf) 79 { 80 int ecmp_if_offset; 81 82 ecmp_if_offset = SOC_ESW_ECMP_STATE(unit)->ecmp_grp_if_offset; 83 84 if (ecmpf) { 85 *nh_idx += ecmp_if_offset; 86 } 87 88 return; 89 } 90 91 92 93 /* 94 * Function: 95 * soc_esw_mem_dma_read 96 * Purpose: 97 * 98 * Parameters: 99 * unit -(IN)SOC unit number. 100 * tbl_mem -(IN)Table memory. 101 * tbl_entry_sz -(IN)Table entry size. 102 * descr -(IN)Table descriptor. 103 * start -(IN) Start index 104 * count -(IN) Number of entries 105 * res_ptr -(OUT) Allocated pointer filled with table info 106 * Returns: 107 * SOC_E_XXX 108 */ 109 int 110 soc_esw_mem_dma_read(int unit, soc_mem_t tbl_mem, uint16 tbl_entry_sz, 111 const char *descr, int start, int end, uint8 **res_ptr) 112 { 113 int alloc_size; /* Allocation size. */ 114 uint8 *buffer; /* Buffer to read the table. */ 115 int tbl_size; /* HW table size. */ 116 117 /* Input parameters sanity check. */ 118 if ((NULL == res_ptr) || (NULL == descr)) { 119 return (SOC_E_PARAM); 120 } 121 122 /* If entry size is not deterministic. reject. */ 123 if (tbl_entry_sz <= 0) { 124 return (SOC_E_PARAM); 125 } 126 127 if (INVALIDm == tbl_mem) { 128 return (SOC_E_NOT_FOUND); 129 } 130 131 if (start < soc_mem_index_min(unit, tbl_mem) || 132 end > soc_mem_index_max(unit, tbl_mem)) { 133 return SOC_E_PARAM; 134 } 135 136 /* Calculate table size. */ 137 tbl_size = (end - start) + 1; 138 alloc_size = tbl_entry_sz * tbl_size; 139 140 /* Allocate memory buffer. */ 141 buffer = soc_cm_salloc(unit, alloc_size, descr); 142 if (buffer == NULL) { 143 return (SOC_E_MEMORY); 144 } 145 146 /* Reset allocated buffer. */ 147 memset(buffer, 0, alloc_size); 148 149 /* Read table to the buffer. */ 150 if (soc_mem_read_range(unit, tbl_mem, MEM_BLOCK_ANY, 151 start, 152 end, buffer) < 0) { 153 soc_cm_sfree(unit, buffer); 154 return (SOC_E_INTERNAL); 155 } 156 157 *res_ptr = buffer; 158 return (SOC_E_NONE); 159 } 160 161 162 STATIC int 163 soc_esw_ecmp_protected_idx_alloc(int unit, int bix, int ecmp_idx, int count) 164 { 165 int offset; 166 int start; 167 soc_esw_ecmp_bank_state_t *bank_info; 168 169 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix); 170 offset = bank_info->tbl_offset; 171 172 start = (ecmp_idx - offset); 173 SHR_BITSET_RANGE(bank_info->idx_used, start, count); 174 175 return SOC_E_NONE; 176 } 177 178 STATIC int 179 soc_esw_ecmp_protected_idx_free(int unit, int bix, int ecmp_idx, int count) 180 { 181 int start; 182 int offset; 183 soc_esw_ecmp_bank_state_t *bank_info; 184 185 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix); 186 offset = bank_info->tbl_offset; 187 188 start = (ecmp_idx - offset); 189 SHR_BITCLR_RANGE(bank_info->idx_used, start, count); 190 191 return SOC_E_NONE; 192 } 193 194 STATIC int 195 soc_esw_ecmp_protected_idx_move(int unit, 196 int src_bix, int to_bix, 197 int ecmp_idx, int count) 198 { 199 int rv; 200 int start; 201 202 start = (SOC_ESW_ECMP_BANK_INFO(unit, src_bix))->tbl_offset + ecmp_idx; 203 rv = soc_esw_ecmp_protected_idx_free(unit, src_bix, start, count); 204 SOC_IF_ERROR_RETURN(rv); 205 206 start = (SOC_ESW_ECMP_BANK_INFO(unit, to_bix))->tbl_offset + ecmp_idx; 207 rv = soc_esw_ecmp_protected_idx_alloc(unit, to_bix, start, count); 208 SOC_IF_ERROR_RETURN(rv); 209 210 return SOC_E_NONE; 211 } 212 213 214 215 216 STATIC int 217 soc_esw_ecmp_idx_bank_get(int unit, int idx, int *bank_idx) 218 { 219 int bix; 220 soc_esw_ecmp_bank_state_t *bank_info; 221 222 for (bix = 0; bix < SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks; bix++) { 223 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix); 224 if ((idx >= bank_info->tbl_offset) && 225 (idx < (bank_info->tbl_offset + bank_info->bank_size))) { 226 *bank_idx = bix; 227 return SOC_E_NONE; 228 } 229 } 230 231 return SOC_E_NOT_FOUND; 232 } 233 234 235 STATIC int 236 soc_esw_ecmp_idx_bank_offset_get(int unit, int *if_id) 237 { 238 int rv; 239 int bank_idx; 240 241 rv = soc_esw_ecmp_idx_bank_get(unit, *if_id, &bank_idx); 242 SOC_IF_ERROR_RETURN(rv); 243 244 *if_id -= (SOC_ESW_ECMP_BANK_INFO(unit, bank_idx))->tbl_offset; 245 246 return SOC_E_NONE; 247 } 248 249 250 251 STATIC int 252 soc_esw_ecmp_protected_state_set(int unit, int grp_idx, 253 int bank_idx, int base, int count) 254 { 255 soc_esw_ecmp_group_state_t *grp_state; 256 257 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx); 258 259 grp_state->bank = bank_idx; 260 grp_state->base = base; 261 grp_state->count = count; 262 263 return SOC_E_NONE; 264 } 265 266 STATIC int 267 soc_esw_ecmp_protected_state_get(int unit, int grp_idx, 268 int *bank_idx, int *base, int *count) 269 { 270 soc_esw_ecmp_group_state_t *grp_state; 271 272 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx); 273 274 if (bank_idx) { 275 *bank_idx = grp_state->bank; 276 } 277 if (base) { 278 *base = grp_state->base; 279 } 280 if (count) { 281 *count = grp_state->count; 282 } 283 284 return SOC_E_NONE; 285 } 286 287 STATIC int 288 soc_esw_ecmp_bank_used_count_get(int unit, int bank_idx, int *count) 289 { 290 int ix; 291 int use_count = 0; 292 soc_esw_ecmp_bank_state_t *bank_info; 293 294 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx); 295 296 for (ix = 0; ix < _SHR_BITDCLSIZE(bank_info->bank_size); ix++) { 297 use_count += _shr_popcount(bank_info->idx_used[ix]); 298 } 299 300 *count = use_count; 301 302 return SOC_E_NONE; 303 } 304 305 STATIC int 306 soc_esw_ecmp_bank_active_set(int unit, int bank_idx) 307 { 308 int rv; 309 int rsvd_bank; 310 uint32 regval = 0; 311 uint32 banksel[1] = {0}; 312 313 rsvd_bank = SOC_ESW_ECMP_BANK_RSVD_GET(unit); 314 315 /* Update BANK_SEL config. */ 316 rv = soc_reg32_get(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, ®val); 317 SOC_IF_ERROR_RETURN(rv); 318 319 banksel[0] = soc_reg_field_get(unit, ING_L3_ECMP_BANK_SELr, regval, BANK_SELf); 320 if (SHR_BITGET(banksel, bank_idx)) { 321 SHR_BITSET(banksel, rsvd_bank); 322 } else { 323 SHR_BITCLR(banksel, rsvd_bank); 324 } 325 soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr, ®val, BANK_SELf, banksel[0]); 326 327 rv = soc_reg32_set(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval); 328 SOC_IF_ERROR_RETURN(rv); 329 rv = soc_reg32_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval); 330 SOC_IF_ERROR_RETURN(rv); 331 332 return SOC_E_NONE; 333 } 334 335 STATIC int 336 soc_esw_ecmp_bank_reserved_set(int unit, int bank_idx) 337 { 338 int rv; 339 int rsvd_bank; 340 int tmp_level; 341 int tmp_prot_disabled; 342 uint32 regval = 0; 343 uint32 banksel[1] = {0}; 344 soc_esw_ecmp_bank_state_t *src_bank_info, *dst_bank_info; 345 346 rsvd_bank = SOC_ESW_ECMP_BANK_RSVD_GET(unit); 347 348 src_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx); 349 dst_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, rsvd_bank); 350 351 tmp_level = dst_bank_info->level; 352 tmp_prot_disabled = dst_bank_info->protected_write_disabled; 353 354 dst_bank_info->level = src_bank_info->level; 355 dst_bank_info->protected_write_disabled = src_bank_info->protected_write_disabled; 356 357 src_bank_info->level = tmp_level; 358 src_bank_info->protected_write_disabled = tmp_prot_disabled; 359 360 /* Update BANK_SEL config. */ 361 rv = soc_reg32_get(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, ®val); 362 SOC_IF_ERROR_RETURN(rv); 363 364 banksel[0] = soc_reg_field_get(unit, ING_L3_ECMP_BANK_SELr, regval, BANK_SELf); 365 SHR_BITCLR(banksel, bank_idx); 366 soc_reg_field_set(unit, ING_L3_ECMP_BANK_SELr, ®val, BANK_SELf, banksel[0]); 367 368 rv = soc_reg32_set(unit, ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval); 369 SOC_IF_ERROR_RETURN(rv); 370 rv = soc_reg32_set(unit, INITIAL_ING_L3_ECMP_BANK_SELr, REG_PORT_ANY, 0, regval); 371 SOC_IF_ERROR_RETURN(rv); 372 373 /* Mark bank_idx as reserved */ 374 SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx = bank_idx; 375 376 return SOC_E_NONE; 377 } 378 379 STATIC int 380 soc_esw_ecmp_protected_idx_range_get(int unit, int bank_idx, int rsvd_bank, 381 int ecmp_idx, int max_grp_size, 382 int *rd_start, int *rd_end, 383 int *wr_start, int *wr_end) 384 { 385 int use_count; 386 soc_esw_ecmp_bank_state_t *bank_info; 387 388 SOC_IF_ERROR_RETURN(soc_esw_ecmp_bank_used_count_get(unit, bank_idx, &use_count)); 389 390 if ((!SOC_ESW_ECMP_BANK_PROTECTED_ACCESS(unit, bank_idx)) || (use_count == 0)) { 391 *rd_start = *wr_start = (ecmp_idx); 392 *rd_end = *wr_end = (ecmp_idx + max_grp_size); 393 394 return SOC_E_NONE; 395 } 396 397 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx); 398 *rd_start = (bank_info->tbl_offset); 399 *rd_end = (*rd_start + bank_info->bank_size - 1); 400 401 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, rsvd_bank); 402 *wr_start = (bank_info->tbl_offset); 403 *wr_end = (*wr_start + bank_info->bank_size - 1); 404 405 return SOC_E_NONE; 406 } 407 408 409 STATIC int 410 soc_esw_ecmp_protected_bank_update(int unit, int src_bank, int dst_bank) 411 { 412 int rv; 413 int grp_idx; 414 int ecmp_base_offset; 415 int idx_min, idx_max; 416 soc_mem_t ecmp_grp_mem1, ecmp_grp_mem2; 417 soc_esw_ecmp_group_state_t *grp_state; 418 419 uint8 *ecmp1_tbl_p = NULL; /* L3_ECMP_GROUP table pointer. */ 420 uint8 *ecmp2_tbl_p = NULL; /* INITIAL_L3_ECMP_GROUP table pointer. */ 421 422 uint32 *ecmp_grp_ptr = NULL; /* ECMP group pointer.*/ 423 uint32 *ecmp2_grp_ptr = NULL; /* INITIAL_ECMP group pointer.*/ 424 425 ecmp_grp_mem1 = L3_ECMP_COUNTm; 426 ecmp_grp_mem2 = INITIAL_L3_ECMP_GROUPm; 427 idx_min = soc_mem_index_min(unit, ecmp_grp_mem1); 428 idx_max = soc_mem_index_max(unit, ecmp_grp_mem1); 429 430 /* Read ecmp group tables */ 431 rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem1, 432 sizeof(ecmp_count_entry_t), 433 "ecmp_grp_tbl", 434 idx_min, idx_max, 435 &ecmp1_tbl_p); 436 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 437 438 rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem2, 439 sizeof(initial_l3_ecmp_group_entry_t), 440 "ecmp2_grp_tbl", 441 idx_min, idx_max, 442 &ecmp2_tbl_p); 443 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 444 445 446 for (grp_idx = 0; grp_idx < SOC_ESW_ECMP_MAX_GROUPS; grp_idx++) { 447 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx); 448 449 /* Group is not installed yet */ 450 if (grp_state->count == 0) { 451 continue; 452 } 453 /* Group does not have members in the src_bank */ 454 if (grp_state->bank != src_bank) { 455 continue; 456 } 457 458 ecmp_base_offset = grp_state->base; 459 rv = soc_esw_ecmp_idx_bank_offset_get(unit, &ecmp_base_offset); 460 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 461 462 /* Update ecmp base and bank_idx for the group */ 463 grp_state->base = ((SOC_ESW_ECMP_BANK_INFO(unit, dst_bank))->tbl_offset + ecmp_base_offset); 464 grp_state->bank = dst_bank; 465 466 467 /* Move ecmp idx range from src_bank to dst_bank. */ 468 rv = soc_esw_ecmp_protected_idx_move(unit, src_bank, dst_bank, 469 ecmp_base_offset, grp_state->count); 470 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 471 472 ecmp_grp_ptr = 473 soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem1, uint32 *, 474 ecmp1_tbl_p, grp_idx); 475 ecmp2_grp_ptr = 476 soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem2, uint32 *, 477 ecmp2_tbl_p, grp_idx); 478 479 soc_mem_field32_set(unit, ecmp_grp_mem1, ecmp_grp_ptr, 480 BASE_PTRf, grp_state->base); 481 soc_mem_field32_set(unit, ecmp_grp_mem2, ecmp2_grp_ptr, 482 BASE_PTRf, grp_state->base); 483 } 484 485 rv = soc_esw_ecmp_bank_active_set(unit, src_bank); 486 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 487 488 /* Write updated member tables */ 489 rv = soc_mem_write_range(unit, ecmp_grp_mem1, MEM_BLOCK_ALL, 490 idx_min, idx_max, ecmp1_tbl_p); 491 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 492 493 rv = soc_mem_write_range(unit, ecmp_grp_mem2, MEM_BLOCK_ALL, 494 idx_min, idx_max, ecmp2_tbl_p); 495 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 496 497 rv = soc_esw_ecmp_bank_reserved_set(unit, src_bank); 498 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 499 500 err_exit: 501 if (ecmp2_tbl_p) { 502 soc_cm_sfree(unit, ecmp2_tbl_p); 503 } 504 if (ecmp1_tbl_p) { 505 soc_cm_sfree(unit, ecmp1_tbl_p); 506 } 507 508 return rv; 509 } 510 511 512 STATIC int 513 soc_esw_ecmp_protected_base_ptr_update(int unit) 514 { 515 int rv; 516 int grp_idx; 517 int idx_min, idx_max; 518 soc_mem_t ecmp_grp_mem1, ecmp_grp_mem2; 519 520 soc_esw_ecmp_group_state_t *grp_state; 521 522 uint8 *ecmp1_tbl_p = NULL; /* L3_ECMP_GROUP table pointer. */ 523 uint8 *ecmp2_tbl_p = NULL; /* INITIAL_L3_ECMP_GROUP table pointer. */ 524 525 uint32 *ecmp_grp_ptr = NULL; /* ECMP group pointer.*/ 526 uint32 *ecmp2_grp_ptr = NULL; /* INITIAL_ECMP group pointer.*/ 527 528 ecmp_grp_mem1 = L3_ECMP_COUNTm; 529 ecmp_grp_mem2 = INITIAL_L3_ECMP_GROUPm; 530 idx_min = soc_mem_index_min(unit, ecmp_grp_mem1); 531 idx_max = soc_mem_index_max(unit, ecmp_grp_mem1); 532 533 /* Read ecmp group tables */ 534 rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem1, 535 sizeof(ecmp_count_entry_t), 536 "ecmp_grp_tbl", 537 idx_min, idx_max, 538 &ecmp1_tbl_p); 539 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 540 541 rv = soc_esw_mem_dma_read(unit, ecmp_grp_mem2, 542 sizeof(initial_l3_ecmp_group_entry_t), 543 "ecmp2_grp_tbl", 544 idx_min, idx_max, 545 &ecmp2_tbl_p); 546 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 547 548 549 for (grp_idx = 0; grp_idx < SOC_ESW_ECMP_MAX_GROUPS; grp_idx++) { 550 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx); 551 552 /* Group not in use. */ 553 if (!grp_state->count && !grp_state->base) { 554 continue; 555 } 556 557 ecmp_grp_ptr = 558 soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem1, uint32 *, 559 ecmp1_tbl_p, grp_idx); 560 ecmp2_grp_ptr = 561 soc_mem_table_idx_to_pointer(unit, ecmp_grp_mem2, uint32 *, 562 ecmp2_tbl_p, grp_idx); 563 564 soc_mem_field32_set(unit, ecmp_grp_mem1, ecmp_grp_ptr, 565 BASE_PTRf, grp_state->base); 566 soc_mem_field32_set(unit, ecmp_grp_mem2, ecmp2_grp_ptr, 567 BASE_PTRf, grp_state->base); 568 } 569 570 /* Write updated member tables */ 571 rv = soc_mem_write_range(unit, ecmp_grp_mem1, MEM_BLOCK_ALL, 572 idx_min, idx_max, ecmp1_tbl_p); 573 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 574 575 rv = soc_mem_write_range(unit, ecmp_grp_mem2, MEM_BLOCK_ALL, 576 idx_min, idx_max, ecmp2_tbl_p); 577 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 578 579 err_exit: 580 if (ecmp2_tbl_p) { 581 soc_cm_sfree(unit, ecmp2_tbl_p); 582 } 583 if (ecmp1_tbl_p) { 584 soc_cm_sfree(unit, ecmp1_tbl_p); 585 } 586 587 return rv; 588 } 589 590 591 STATIC int 592 soc_esw_ecmp_protected_member_move(int unit, 593 int grp_idx, 594 int src_bank_idx, 595 int dst_bank_idx, 596 uint8 *src_ecmp_tbl1_p, 597 uint8 *src_ecmp_tbl2_p, 598 uint8 *dst_ecmp_tbl1_p, 599 uint8 *dst_ecmp_tbl2_p, 600 int new_base_idx 601 ) 602 { 603 int rv; 604 int idx; 605 int ecmp_base_offset; 606 soc_esw_ecmp_bank_state_t *src_bank_info, *dst_bank_info; 607 soc_esw_ecmp_group_state_t *grp_state; 608 609 uint32 *src_ecmp1_p = NULL; 610 uint32 *src_ecmp2_p = NULL; 611 uint32 *dst_ecmp1_p = NULL; 612 uint32 *dst_ecmp2_p = NULL; 613 614 src_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, src_bank_idx); 615 dst_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, dst_bank_idx); 616 617 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx); 618 ecmp_base_offset = (grp_state->base - src_bank_info->tbl_offset); 619 620 for (idx = ecmp_base_offset; 621 idx < (ecmp_base_offset + grp_state->count); 622 idx++) { 623 src_ecmp1_p = 624 soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *, 625 src_ecmp_tbl1_p, idx); 626 src_ecmp2_p = 627 soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *, 628 src_ecmp_tbl2_p, idx); 629 630 dst_ecmp1_p = 631 soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *, 632 dst_ecmp_tbl1_p, new_base_idx); 633 dst_ecmp2_p = 634 soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *, 635 dst_ecmp_tbl2_p, new_base_idx); 636 637 sal_memcpy(dst_ecmp1_p, src_ecmp1_p, sizeof(ecmp_entry_t)); 638 sal_memcpy(dst_ecmp2_p, src_ecmp2_p, 639 sizeof(initial_l3_ecmp_entry_t)); 640 641 new_base_idx++; 642 } 643 644 /* Free idx from src_bank. */ 645 rv = soc_esw_ecmp_protected_idx_free(unit, 646 src_bank_idx, 647 grp_state->base, 648 grp_state->count); 649 SOC_IF_ERROR_RETURN(rv); 650 651 grp_state->base = (dst_bank_info->tbl_offset + new_base_idx - grp_state->count); 652 653 /* Alloc idx in dst_bank. */ 654 rv = soc_esw_ecmp_protected_idx_alloc(unit, 655 dst_bank_idx, 656 grp_state->base, 657 grp_state->count); 658 SOC_IF_ERROR_RETURN(rv); 659 660 /* Update ECMP group bank */ 661 grp_state->bank = dst_bank_idx; 662 663 return SOC_E_NONE; 664 } 665 666 /* 667 * Function: 668 * soc_esw_ecmp_protected_grp_size_update 669 * Purpose: 670 * Update the max group size of an ECMP group. 671 * Parameters: 672 * unit - (IN)SOC unit number. 673 * grp_info - (IN)ecmp group id to write. 674 * base_ptr - (IN)ecmp member base pointer. 675 * Returns: 676 * SOC_E_XXX 677 */ 678 STATIC int 679 soc_esw_ecmp_protected_grp_size_update(int unit, 680 soc_esw_ecmp_group_info_t *grp_info, 681 int *base_ptr) 682 { 683 int rv = SOC_E_NONE; 684 int bix; 685 int bank; 686 int grp_idx; 687 int old_max_grp_sz; 688 int new_max_grp_size; 689 int free_count = 0; 690 int free_idx; 691 int level; 692 uint32 bank_bmp = 0; 693 soc_esw_ecmp_group_state_t *grp_state; 694 soc_esw_ecmp_bank_state_t *bank_info; 695 696 grp_idx = grp_info->ecmp_grp; 697 new_max_grp_size = grp_info->max_paths; 698 699 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx); 700 bank = grp_state->bank; 701 old_max_grp_sz = grp_state->count; 702 703 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank); 704 level = bank_info->level; 705 706 /* Get the number of free entries in this bank. */ 707 rv = soc_esw_ecmp_bank_free_count_get(unit, 708 bank, 709 &free_count); 710 SOC_IF_ERROR_RETURN(rv); 711 712 if (new_max_grp_size <= (free_count + old_max_grp_sz)) { 713 rv = soc_esw_ecmp_protected_bank_defragment(unit, 714 bank, 715 grp_idx, 716 &free_count); 717 SOC_IF_ERROR_RETURN(rv); 718 719 /* Check if the current bank can accommodate the new max path */ 720 *base_ptr = grp_state->base; 721 } else { 722 rv = soc_esw_ecmp_protected_banks_get(unit, 723 level, 724 &bank_bmp); 725 SOC_IF_ERROR_RETURN(rv); 726 727 free_count = 0; 728 /* Compress other banks of the same level to make room for new group */ 729 for (bix = 0; bix < SOC_ESW_ECMP_MAX_BANKS; bix++) { 730 if (SHR_BITGET(&bank_bmp, bix) && bix != grp_state->bank) { 731 rv = soc_esw_ecmp_bank_free_count_get(unit, 732 bix, 733 &free_count); 734 SOC_IF_ERROR_RETURN(rv); 735 736 /* Not enough space in this bank, continue. */ 737 if (free_count < new_max_grp_size) { 738 continue; 739 } 740 741 rv = soc_esw_ecmp_protected_bank_defragment(unit, 742 bix, 743 -1, 744 &free_count); 745 SOC_IF_ERROR_RETURN(rv); 746 747 /* If the defragmented bank can fit the new group, break */ 748 if (free_count >= new_max_grp_size) { 749 break; 750 } 751 } 752 } 753 754 if (free_count < new_max_grp_size) { 755 return SOC_E_FULL; 756 } 757 758 /* Check if a free idx can be found now */ 759 free_idx = -1; 760 bank_bmp = 0; 761 rv = soc_esw_ecmp_protected_banks_get(unit, 762 level, 763 &bank_bmp); 764 SOC_IF_ERROR_RETURN(rv); 765 766 767 for (bix = 0; bix < SOC_ESW_ECMP_MAX_BANKS; bix++) { 768 if (SHR_BITGET(&bank_bmp, bix) && bix != grp_state->bank) { 769 rv = soc_esw_ecmp_protected_idx_free_get(unit, 770 bix, 771 new_max_grp_size, 772 &free_idx); 773 if (rv == SOC_E_NONE) { 774 *base_ptr = free_idx; 775 break; 776 } 777 } 778 } 779 } 780 781 return rv; 782 } 783 784 /* | *************************************************** | 785 * | *************************************************** | 786 * | * Start - Public Functions * | 787 * | *************************************************** | 788 * | *************************************************** | 789 */ 790 791 /* Function to initialize ecmp_init_info struct */ 792 void 793 soc_esw_ecmp_init_info_t_init(soc_esw_ecmp_init_info_t *info) 794 { 795 sal_memset(info, 0, sizeof(soc_esw_ecmp_init_info_t)); 796 797 return; 798 } 799 800 /* Function to initialize ecmp_group_info struct */ 801 void 802 soc_esw_ecmp_group_info_t_init(soc_esw_ecmp_group_info_t *info) 803 { 804 sal_memset(info, 0, sizeof(soc_esw_ecmp_group_info_t)); 805 806 return; 807 } 808 809 /* 810 * Function: 811 * soc_esw_ecmp_state_lock 812 * Purpose: 813 * Mutext Take (lock) ecmp state 814 * Parameters: 815 * unit - (IN)SOC unit number. 816 * Returns: 817 * SOC_E_XXX 818 */ 819 int 820 soc_esw_ecmp_state_lock(int unit) 821 { 822 if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) { 823 return SOC_E_INIT; 824 } 825 826 sal_mutex_take(SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock, 827 sal_mutex_FOREVER); 828 829 return SOC_E_NONE; 830 } 831 832 /* 833 * Function: 834 * soc_esw_ecmp_state_unlock 835 * Purpose: 836 * Mutext Give (unlock) ecmp state 837 * Parameters: 838 * unit - (IN)SOC unit number. 839 * Returns: 840 * SOC_E_XXX 841 */ 842 int 843 soc_esw_ecmp_state_unlock(int unit) 844 { 845 if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) { 846 return SOC_E_INIT; 847 } 848 849 if (sal_mutex_give(SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock) != 0) { 850 return SOC_E_INTERNAL; 851 } 852 853 return SOC_E_NONE; 854 } 855 856 #ifdef BCM_WARM_BOOT_SUPPORT 857 858 STATIC void 859 soc_esw_ecmp_protected_state_wb_alloc_size(int unit, uint32 *size) 860 { 861 int ix; 862 int alloc_size; 863 soc_esw_ecmp_group_state_t *group_info; 864 soc_esw_ecmp_bank_state_t *bank_info; 865 866 alloc_size = 0; 867 868 /* spare bank idx */ 869 alloc_size += SOC_ESW_ECMP_WB_SIZE(&(SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx)); 870 871 /* Sync group_info structs. */ 872 for (ix = 0; ix < SOC_ESW_ECMP_MAX_GROUPS; ix++) { 873 group_info = SOC_ESW_ECMP_GROUP_INFO(unit, ix); 874 875 alloc_size += SOC_ESW_ECMP_WB_SIZE(group_info); 876 } 877 878 /* Sync bank_info structs. */ 879 for (ix = 0; ix < SOC_ESW_ECMP_MAX_BANKS; ix++) { 880 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, ix); 881 882 alloc_size += SOC_ESW_ECMP_WB_SIZE(bank_info); 883 } 884 885 /* Return the calculated size. */ 886 *size = alloc_size; 887 888 return; 889 } 890 891 /* 892 * Function: 893 * soc_esw_ecmp_protected_state_wb_alloc_size 894 * Purpose: 895 * Allocate persistent info memory for soc esw ecmp module 896 * Parameters: 897 * unit - (IN) SOC device id 898 * Returns: 899 * SOC_E_XXX 900 */ 901 int 902 soc_esw_ecmp_protected_state_warmboot_alloc(int unit) 903 { 904 905 uint8 *ecmp_scache_ptr; 906 uint32 size = 0; 907 int rv = SOC_E_NONE; 908 soc_scache_handle_t scache_handle; 909 910 scache_handle = SOC_ESW_ECMP_STATE(unit)->scache_handle; 911 912 913 soc_esw_ecmp_protected_state_wb_alloc_size(unit, &size); 914 915 rv = soc_versioned_scache_ptr_get(unit, scache_handle, TRUE, 916 &size, &ecmp_scache_ptr, 917 SOC_ESW_ECMP_WB_DEFAULT_VERSION, NULL); 918 919 if (SOC_E_NOT_FOUND == rv) { 920 /* Proceed with Level 1 Warm Boot */ 921 rv = SOC_E_NONE; 922 } 923 924 return rv; 925 } 926 927 /* 928 * Function: 929 * soc_esw_ecmp_protected_state_warmboot_sync 930 * Purpose: 931 * Sync soc esw ecmp state. 932 * Parameters: 933 * unit - (IN) SOC device id 934 * 935 * Returns: 936 * SOC_E_XXX 937 */ 938 int 939 soc_esw_ecmp_protected_state_warmboot_sync(int unit) 940 { 941 int ix; 942 uint32 size; 943 soc_esw_ecmp_group_state_t *group_info; 944 soc_esw_ecmp_bank_state_t *bank_info; 945 uint8 *ecmp_scache_ptr; 946 soc_scache_handle_t scache_handle; 947 948 scache_handle = SOC_ESW_ECMP_STATE(unit)->scache_handle; 949 950 951 /* Get the size to save ecmp protected warmboot state. */ 952 soc_esw_ecmp_protected_state_wb_alloc_size(unit, &size); 953 954 SOC_IF_ERROR_RETURN 955 (soc_versioned_scache_ptr_get(unit, scache_handle, FALSE, 956 &size, &ecmp_scache_ptr, 957 SOC_ESW_ECMP_WB_DEFAULT_VERSION, NULL)); 958 959 960 /* spare bank idx */ 961 SOC_ESW_ECMP_WB_SYNC(ecmp_scache_ptr, &(SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx)); 962 963 /* Sync group_info structs. */ 964 for (ix = 0; ix < SOC_ESW_ECMP_MAX_GROUPS; ix++) { 965 group_info = SOC_ESW_ECMP_GROUP_INFO(unit, ix); 966 967 SOC_ESW_ECMP_WB_SYNC(ecmp_scache_ptr, group_info); 968 } 969 970 /* Sync bank_info structs. */ 971 for (ix = 0; ix < SOC_ESW_ECMP_MAX_BANKS; ix++) { 972 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, ix); 973 974 SOC_ESW_ECMP_WB_SYNC(ecmp_scache_ptr, bank_info); 975 } 976 977 return SOC_E_NONE; 978 } 979 980 /* 981 * Function: 982 * soc_esw_ecmp_protected_state_warmboot_recover 983 * Purpose: 984 * Recover soc esw ecmp state. 985 * Parameters: 986 * unit - (IN) SOC device id 987 * 988 * Returns: 989 * SOC_E_XXX 990 */ 991 992 int 993 soc_esw_ecmp_protected_state_warmboot_recover(int unit) 994 { 995 int ix; 996 uint32 size; 997 soc_esw_ecmp_group_state_t *group_info; 998 soc_esw_ecmp_bank_state_t *bank_info; 999 uint8 *ecmp_scache_ptr; 1000 soc_scache_handle_t scache_handle; 1001 1002 scache_handle = SOC_ESW_ECMP_STATE(unit)->scache_handle; 1003 1004 /* Get the size to save ecmp protected warmboot state. */ 1005 soc_esw_ecmp_protected_state_wb_alloc_size(unit, &size); 1006 1007 1008 SOC_IF_ERROR_RETURN 1009 (soc_versioned_scache_ptr_get(unit, scache_handle, FALSE, 1010 &size, &ecmp_scache_ptr, 1011 SOC_ESW_ECMP_WB_DEFAULT_VERSION, NULL)); 1012 1013 /* spare bank idx */ 1014 SOC_ESW_ECMP_WB_RECOVER(ecmp_scache_ptr, &(SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx)); 1015 1016 /* Sync group_info structs. */ 1017 for (ix = 0; ix < SOC_ESW_ECMP_MAX_GROUPS; ix++) { 1018 group_info = SOC_ESW_ECMP_GROUP_INFO(unit, ix); 1019 1020 SOC_ESW_ECMP_WB_RECOVER(ecmp_scache_ptr, group_info); 1021 } 1022 1023 /* Sync bank_info structs. */ 1024 for (ix = 0; ix < SOC_ESW_ECMP_MAX_BANKS; ix++) { 1025 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, ix); 1026 1027 SOC_ESW_ECMP_WB_RECOVER(ecmp_scache_ptr, bank_info); 1028 } 1029 1030 return SOC_E_NONE; 1031 } 1032 1033 #endif /* BCM_WARM_BOOT_SUPPORT */ 1034 1035 /* 1036 * Function: 1037 * soc_esw_ecmp_protected_init 1038 * Purpose: 1039 * Initialize state for ecmp protected accesses 1040 * Parameters: 1041 * unit - (IN)SOC unit number. 1042 * first_lkup_sz - (IN)ECMP table first lookup size. 1043 * ecmp_table_sz - (IN)ECMP table total size. 1044 * ecmp_nh_offset - (IN)ECMP next hop offset. 1045 * Returns: 1046 * SOC_E_XXX 1047 */ 1048 int 1049 soc_esw_ecmp_protected_init(int unit, 1050 soc_esw_ecmp_init_info_t *init_info) 1051 { 1052 int ix; 1053 int bix, bix_r; 1054 int tbl_offset; 1055 int bank_size; 1056 int lkup1_banks, lkup2_banks; 1057 soc_mem_t mem; 1058 soc_esw_ecmp_bank_state_t *bank_info; 1059 1060 if ((init_info == NULL) || 1061 (init_info->bank_size > SOC_ESW_ECMP_BANK_SIZE)) { 1062 return SOC_E_INIT; 1063 } 1064 1065 /* Make sure the ECMP member and group tables are always enabled for memcache */ 1066 for (ix = 0; ix < COUNTOF(ecmp_member_mems); ix++) { 1067 mem = ecmp_member_mems[0]; 1068 if (SOC_MEM_STATE(unit, mem).cache[SOC_MEM_BLOCK_ANY(unit, mem)] == NULL) { 1069 return SOC_E_INIT; 1070 } 1071 } 1072 for (ix = 0; ix < COUNTOF(ecmp_group_mems); ix++) { 1073 mem = ecmp_group_mems[0]; 1074 if (SOC_MEM_STATE(unit, mem).cache[SOC_MEM_BLOCK_ANY(unit, mem)] == NULL) { 1075 return SOC_E_INIT; 1076 } 1077 } 1078 1079 1080 /* Allocate export software state. */ 1081 if (SOC_ESW_ECMP_STATE(unit) == NULL) { 1082 SOC_ESW_ECMP_STATE(unit) = 1083 sal_alloc(sizeof(soc_esw_ecmp_state_t), 1084 "SOC esw ecmp sw state"); 1085 } 1086 1087 if (SOC_ESW_ECMP_STATE(unit) == NULL) { 1088 return SOC_E_MEMORY; 1089 } 1090 sal_memset(SOC_ESW_ECMP_STATE(unit), 0, sizeof(soc_esw_ecmp_state_t)); 1091 1092 /* Create ECMP State lock */ 1093 if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) { 1094 SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock = 1095 sal_mutex_create("soc.esw.ecmp.state.mutex"); 1096 1097 if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock == NULL) { 1098 sal_free(SOC_ESW_ECMP_STATE(unit)); 1099 SOC_ESW_ECMP_STATE(unit) = NULL; 1100 return SOC_E_MEMORY; 1101 } 1102 } 1103 1104 SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks = init_info->num_banks; 1105 SOC_ESW_ECMP_STATE(unit)->ecmp_members_per_banks = init_info->bank_size; 1106 SOC_ESW_ECMP_STATE(unit)->ecmp_grp_if_offset = init_info->ecmp_if_offset; 1107 #ifdef BCM_WARM_BOOT_SUPPORT 1108 SOC_ESW_ECMP_STATE(unit)->scache_handle = init_info->scache_handle; 1109 #endif /* BCM_WARM_BOOT_SUPPORT */ 1110 1111 tbl_offset = 0; 1112 bank_size = init_info->bank_size; 1113 lkup1_banks = ((init_info->lkup1_size + (bank_size - 1)) / bank_size); 1114 lkup2_banks = ((init_info->lkup2_size + (bank_size - 1)) / bank_size); 1115 1116 bix_r = -1; 1117 for (bix = 0; bix < SOC_ESW_ECMP_MAX_BANKS; bix++) { 1118 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix); 1119 1120 if (init_info->num_levels < 2) { 1121 bank_info->protected_write_disabled = 1; 1122 bank_info->level = socEswEcmpBankLkupLevelInvalid; 1123 continue; 1124 } 1125 1126 1127 if (bix < lkup1_banks) { 1128 bank_info->level = socEswEcmpBankLkupLevelOverlay; 1129 bank_info->protected_write_disabled = 0; 1130 } else if (bix < (lkup1_banks + lkup2_banks)) { 1131 bank_info->level = socEswEcmpBankLkupLevelUnderlay; 1132 bank_info->protected_write_disabled = 0; 1133 } else { 1134 if (bix_r == -1) { 1135 bix_r = bix; 1136 bank_info->level = socEswEcmpBankLkupLevelReserved; 1137 1138 SOC_ESW_ECMP_STATE(unit)->ecmp_spare_bank_idx = bix; 1139 } else { 1140 bank_info->level = socEswEcmpBankLkupLevelInvalid; 1141 } 1142 bank_info->protected_write_disabled = 1; 1143 } 1144 1145 1146 bank_info->idx_min = 0; 1147 bank_info->idx_max = bank_size; 1148 bank_info->bank_size = bank_size; 1149 1150 bank_info->tbl_offset = tbl_offset; 1151 tbl_offset += bank_size; 1152 } 1153 1154 1155 #ifdef BCM_WARM_BOOT_SUPPORT 1156 if (!SOC_WARM_BOOT(unit)) { 1157 SOC_IF_ERROR_RETURN(soc_esw_ecmp_protected_state_warmboot_alloc(unit)); 1158 } else { 1159 SOC_IF_ERROR_RETURN(soc_esw_ecmp_protected_state_warmboot_recover(unit)); 1160 } 1161 #endif /* BCM_WARM_BOOT_SUPPORT */ 1162 1163 return SOC_E_NONE; 1164 } 1165 1166 /* 1167 * Function: 1168 * soc_esw_ecmp_protected_detach 1169 * Purpose: 1170 * De-Initialize state for ecmp protected accesses 1171 * Parameters: 1172 * unit - (IN)SOC unit number. 1173 * Returns: 1174 * SOC_E_XXX 1175 */ 1176 int 1177 soc_esw_ecmp_protected_detach(int unit) 1178 { 1179 1180 /* Destroy ECMP State lock */ 1181 if (SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock != NULL) { 1182 sal_mutex_destroy(SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock); 1183 SOC_ESW_ECMP_STATE(unit)->soc_esw_ecmp_lock = NULL; 1184 } 1185 1186 /* Free export software state. */ 1187 if (SOC_ESW_ECMP_STATE(unit)) { 1188 sal_free(SOC_ESW_ECMP_STATE(unit)); 1189 SOC_ESW_ECMP_STATE(unit) = NULL; 1190 } 1191 1192 return SOC_E_NONE; 1193 } 1194 1195 1196 /* 1197 * Function: 1198 * soc_esw_ecmp_protected_enabled 1199 * Purpose: 1200 * Checks whether protected ecmp is required or not. 1201 * Parameters: 1202 * unit - (IN)SOC unit number. 1203 * Returns: 1204 * TRUE: Protected ECMP access routines should be used 1205 * FALSE: Protected ECMP access routines are not required 1206 */ 1207 int 1208 soc_esw_ecmp_protected_enabled(int unit) 1209 { 1210 int bix; 1211 1212 /* SOC featue is not set. Return FALSE. */ 1213 if (!soc_feature(unit, soc_feature_l3_ecmp_protected_access)) { 1214 return FALSE; 1215 } 1216 1217 /* Ecmp state is not initialized yet. Return FALSE. */ 1218 if (SOC_ESW_ECMP_STATE(unit) == NULL) { 1219 return FALSE; 1220 } 1221 1222 /* TRUE if at least one bank requires protected writing. */ 1223 for (bix = 0; bix < SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks; bix++) { 1224 if (SOC_ESW_ECMP_BANK_PROTECTED_ACCESS(unit, bix)) { 1225 return TRUE; 1226 } 1227 } 1228 1229 return FALSE; 1230 } 1231 1232 int 1233 soc_esw_ecmp_protected_idx_free_get(int unit, 1234 int bix, 1235 int count, 1236 int *free_idx) 1237 { 1238 int idx, lkup_idx; 1239 soc_esw_ecmp_bank_state_t *bank_info; 1240 1241 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix); 1242 1243 *free_idx = -1; 1244 for (lkup_idx = 0; 1245 lkup_idx <= bank_info->bank_size; lkup_idx++) { 1246 1247 if (!SHR_BITGET(bank_info->idx_used, lkup_idx)) { 1248 idx = count; 1249 /* Check if the group crosses the bank boundary. */ 1250 if ((lkup_idx + idx) > bank_info->bank_size) { 1251 break; 1252 } 1253 while (--idx) { 1254 /* Check if free slots can accomodate wide entry. */ 1255 if (SHR_BITGET(bank_info->idx_used, lkup_idx + idx)) { 1256 break; 1257 } 1258 } 1259 if (idx) { 1260 /* There is no room to accomodate wide entry. */ 1261 continue; 1262 } 1263 *free_idx = (lkup_idx + bank_info->tbl_offset); 1264 return (SOC_E_NONE); 1265 } 1266 } 1267 1268 return SOC_E_FULL; 1269 } 1270 1271 1272 int 1273 soc_esw_ecmp_protected_banks_get(int unit, 1274 soc_esw_ecmp_bank_lkup_level_t lvl, 1275 uint32 *bank_bitmap) 1276 { 1277 int bix; 1278 soc_esw_ecmp_bank_state_t *bank_info; 1279 1280 for (bix = 0; bix < SOC_ESW_ECMP_STATE(unit)->ecmp_member_banks; bix++) { 1281 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bix); 1282 if (bank_info->level == lvl) { 1283 SHR_BITSET(bank_bitmap, bix); 1284 } 1285 } 1286 1287 return SOC_E_NONE; 1288 } 1289 1290 /* 1291 * Function: 1292 * soc_esw_ecmp_protected_bank_defragment 1293 * Purpose: 1294 * Defragment an ecmp bank to fill up holes in 1295 * the middle of the ecmp member table and compress. 1296 * Parameters: 1297 * unit - (IN) SOC unit number. 1298 * bank_idx - (IN) bank idx to compress. 1299 * grp_idx_move - (IN) ecmp group id to write. 1300 * free_count - (OUT) Free count in bank after compression. 1301 * Returns: 1302 * SOC_E_XXX 1303 */ 1304 int 1305 soc_esw_ecmp_protected_bank_defragment(int unit, 1306 int bank_idx, 1307 int grp_idx_move, 1308 int *free_count) 1309 { 1310 int rv; 1311 int grp_idx; 1312 int new_base_idx; 1313 int rd_start, rd_end, wr_start, wr_end; 1314 1315 soc_esw_ecmp_group_state_t *grp_state; 1316 soc_esw_ecmp_bank_state_t *src_bank_info, *dst_bank_info; 1317 1318 uint8 *ecmp1_tbl_p = NULL; /* L3_ECMP table pointer. */ 1319 uint8 *ecmp2_tbl_p = NULL; /* INITIAL_L3_ECMP table pointer. */ 1320 uint8 *dst_ecmp1_tbl_p = NULL; /* L3_ECMP table pointer. */ 1321 uint8 *dst_ecmp2_tbl_p = NULL; /* INITIAL_L3_ECMP table pointer. */ 1322 1323 src_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx); 1324 dst_bank_info = SOC_ESW_ECMP_BANK_INFO(unit, SOC_ESW_ECMP_BANK_RSVD_GET(unit)); 1325 1326 1327 rd_start = src_bank_info->tbl_offset; 1328 rd_end = (src_bank_info->tbl_offset + src_bank_info->bank_size - 1); 1329 1330 wr_start = dst_bank_info->tbl_offset; 1331 wr_end = (dst_bank_info->tbl_offset + dst_bank_info->bank_size - 1); 1332 1333 /* Copy all member table entries into buffer */ 1334 rv = soc_esw_mem_dma_read(unit, L3_ECMPm, 1335 sizeof(ecmp_entry_t), 1336 "ecmp_tbl", 1337 rd_start, rd_end, 1338 &ecmp1_tbl_p); 1339 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1340 1341 rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm, 1342 sizeof(initial_l3_ecmp_entry_t), 1343 "ecmp2_tbl", 1344 rd_start, rd_end, 1345 &ecmp2_tbl_p); 1346 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1347 1348 /* Read ecmp member tables */ 1349 rv = soc_esw_mem_dma_read(unit, L3_ECMPm, 1350 sizeof(ecmp_entry_t), 1351 "ecmp_tbl", 1352 wr_start, wr_end, 1353 &dst_ecmp1_tbl_p); 1354 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1355 1356 rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm, 1357 sizeof(initial_l3_ecmp_entry_t), 1358 "ecmp2_tbl", 1359 wr_start, wr_end, 1360 &dst_ecmp2_tbl_p); 1361 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1362 1363 1364 new_base_idx = 0; 1365 1366 for (grp_idx = 0; grp_idx < SOC_ESW_ECMP_MAX_GROUPS; grp_idx++) { 1367 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx); 1368 1369 if (grp_state->bank != bank_idx) { 1370 continue; 1371 } 1372 1373 /* Group not in use. */ 1374 if (!grp_state->bank && !grp_state->base && !grp_state->count) { 1375 continue; 1376 } 1377 1378 /* Do it at the end */ 1379 if (grp_idx == grp_idx_move) { 1380 continue; 1381 } 1382 1383 rv = soc_esw_ecmp_protected_member_move(unit, 1384 grp_idx, 1385 bank_idx, 1386 SOC_ESW_ECMP_BANK_RSVD_GET(unit), 1387 ecmp1_tbl_p, 1388 ecmp2_tbl_p, 1389 dst_ecmp1_tbl_p, 1390 dst_ecmp2_tbl_p, 1391 new_base_idx); 1392 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1393 1394 new_base_idx += grp_state->count; 1395 } 1396 1397 if (grp_idx_move != -1) { 1398 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_idx_move); 1399 1400 rv = soc_esw_ecmp_protected_member_move(unit, 1401 grp_idx_move, 1402 bank_idx, 1403 SOC_ESW_ECMP_BANK_RSVD_GET(unit), 1404 ecmp1_tbl_p, 1405 ecmp2_tbl_p, 1406 dst_ecmp1_tbl_p, 1407 dst_ecmp2_tbl_p, 1408 new_base_idx); 1409 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1410 1411 new_base_idx += grp_state->count; 1412 } 1413 1414 /* Write updated member tables */ 1415 rv = soc_mem_write_range(unit, L3_ECMPm, MEM_BLOCK_ALL, 1416 wr_start, wr_end, dst_ecmp1_tbl_p); 1417 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1418 1419 rv = soc_mem_write_range(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 1420 wr_start, wr_end, dst_ecmp2_tbl_p); 1421 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1422 1423 rv = soc_esw_ecmp_bank_active_set(unit, bank_idx); 1424 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1425 1426 /* traverse group tables and update base pointers. */ 1427 rv = soc_esw_ecmp_protected_base_ptr_update(unit); 1428 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1429 1430 rv = soc_esw_ecmp_bank_reserved_set(unit, bank_idx); 1431 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1432 1433 if (free_count) { 1434 *free_count = (dst_bank_info->bank_size - new_base_idx); 1435 } 1436 1437 err_exit: 1438 if (ecmp2_tbl_p) { 1439 soc_cm_sfree(unit, ecmp2_tbl_p); 1440 } 1441 if (ecmp1_tbl_p) { 1442 soc_cm_sfree(unit, ecmp1_tbl_p); 1443 } 1444 1445 if (dst_ecmp1_tbl_p) { 1446 soc_cm_sfree(unit, dst_ecmp1_tbl_p); 1447 } 1448 1449 if (dst_ecmp2_tbl_p) { 1450 soc_cm_sfree(unit, dst_ecmp2_tbl_p); 1451 } 1452 return rv; 1453 } 1454 1455 /* 1456 * Function: 1457 * soc_esw_ecmp_protected_ser_update 1458 * Purpose: 1459 * Free the bank corresponding to index of errored ECMP memory. 1460 * Parameters: 1461 * unit - (IN) SOC unit number. 1462 * mem - (IN) SOC memory. 1463 * ecmp_idx - (IN) ECMP memory index. 1464 * Returns: 1465 * SOC_E_XXX 1466 */ 1467 int 1468 soc_esw_ecmp_protected_ser_update(int unit, 1469 soc_mem_t mem, 1470 int ecmp_idx) 1471 { 1472 int rv; 1473 int bank_idx; 1474 1475 /* Bank update required only for INITIAL_L3_ECMP memory. */ 1476 if (mem != INITIAL_L3_ECMPm) { 1477 return SOC_E_NONE; 1478 } 1479 1480 /* get ECMP member bank idx */ 1481 rv = soc_esw_ecmp_idx_bank_get(unit, ecmp_idx, &bank_idx); 1482 SOC_IF_ERROR_RETURN(rv); 1483 1484 if (!SOC_ESW_ECMP_BANK_PROTECTED_ACCESS(unit, bank_idx)) { 1485 return SOC_E_NONE; 1486 } 1487 1488 /* Call defragment function for the bank_idx. This does necessary shuffling. */ 1489 rv = soc_esw_ecmp_protected_bank_defragment(unit, bank_idx, -1, NULL); 1490 1491 return rv; 1492 } 1493 1494 /* 1495 * Function: 1496 * soc_esw_ecmp_bank_free_count_get 1497 * Purpose: 1498 * Get the number of free entries in this bank. 1499 * Parameters: 1500 * unit - (IN) SOC unit number. 1501 * bank_idx - (IN) Bank index. 1502 * count - (OUT) Free entry count. 1503 * Returns: 1504 * SOC_E_XXX 1505 */ 1506 int 1507 soc_esw_ecmp_bank_free_count_get(int unit, int bank_idx, int *count) 1508 { 1509 int use_count = 0; 1510 soc_esw_ecmp_bank_state_t *bank_info; 1511 1512 bank_info = SOC_ESW_ECMP_BANK_INFO(unit, bank_idx); 1513 1514 SOC_IF_ERROR_RETURN( 1515 soc_esw_ecmp_bank_used_count_get(unit, bank_idx, &use_count)); 1516 1517 *count = (bank_info->bank_size - use_count); 1518 1519 return SOC_E_NONE; 1520 } 1521 1522 /* 1523 * Function: 1524 * soc_esw_ecmp_protected_grp_add 1525 * Purpose: 1526 * Add ecmp group next hop members, or reset ecmp group entry. 1527 * NOTE: Function only updates the INITIAL_L3_ECMP and L3_ECMP tables only. 1528 * Group tables and other associated tables are updated by the callee. 1529 * Function may update group tables of other groups as part of this API though. 1530 * Parameters: 1531 * unit - (IN)SOC unit number. 1532 * grp_info - (IN)ecmp group id to write. 1533 * member_list - (IN)Next hop indexes or NULL for entry reset. 1534 * Returns: 1535 * SOC_E_XXX 1536 */ 1537 int 1538 soc_esw_ecmp_protected_grp_add(int unit, 1539 soc_esw_ecmp_group_info_t *grp_info, 1540 void *member_list) 1541 { 1542 int idx; /* Iteration index. */ 1543 int rv; /* Operation return value. */ 1544 int ecmpf; /* Ecmp group vs NextHop Id indicator. */ 1545 int nh_idx; /* NextHop Idx or Ecmp Group. */ 1546 int bank_idx; /* Ecmp Member Table Bank. */ 1547 int bank_idx_r; /* Reserved ecmp member bank. */ 1548 int ecmp_idx; /* Ecmp table entry index. */ 1549 int ecmp_base_offset; /* Ecmp table entry index. */ 1550 int max_grp_size; /* Maximum ecmp group size. */ 1551 int rd_start, rd_end; /* Read idx range. */ 1552 int wr_start, wr_end; /* Write idx range. */ 1553 int bank_swap_reqd; /* Bank Swap needed */ 1554 1555 uint8 *ecmp1_tbl_p = NULL; /* L3_ECMP table pointer. */ 1556 uint8 *ecmp2_tbl_p = NULL; /* INITIAL_L3_ECMP table pointer. */ 1557 uint32 *ecmp1_entry_ptr = NULL; /* ECMP entry pointer.*/ 1558 uint32 *ecmp2_entry_ptr = NULL; /* INITIAL ECMP entry pointer.*/ 1559 soc_esw_ecmp_member_info_t *ecmp_members; /* Ecmp group member info. */ 1560 soc_esw_ecmp_group_state_t *grp_state; /* ECMP group info. */ 1561 void *ecmp1_null_entry = NULL, *ecmp2_null_entry = NULL; 1562 1563 /* Cast input buffer. */ 1564 ecmp_members = member_list; 1565 1566 bank_idx_r = SOC_ESW_ECMP_BANK_RSVD_GET(unit); 1567 1568 max_grp_size = grp_info->max_paths; 1569 ecmp_idx = grp_info->ecmp_member_base; 1570 ecmp_base_offset = ecmp_idx; 1571 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_info->ecmp_grp); 1572 1573 if (grp_state->count != 0) { 1574 if (max_grp_size > grp_state->count) { 1575 rv = soc_esw_ecmp_protected_grp_size_update(unit, 1576 grp_info, 1577 &ecmp_idx); 1578 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1579 ecmp_base_offset = ecmp_idx; 1580 } 1581 } 1582 1583 /* get ECMP member bank idx */ 1584 rv = soc_esw_ecmp_idx_bank_get(unit, ecmp_idx, &bank_idx); 1585 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1586 1587 rv = soc_esw_ecmp_protected_idx_range_get(unit, bank_idx, bank_idx_r, 1588 ecmp_idx, max_grp_size, 1589 &rd_start, &rd_end, 1590 &wr_start, &wr_end); 1591 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1592 1593 /* Bank swap required if read and write ranges different */ 1594 bank_swap_reqd = ((wr_start != rd_start) ? 1 : 0); 1595 1596 rv = soc_esw_ecmp_idx_bank_offset_get(unit, &ecmp_base_offset); 1597 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1598 1599 /* Read ecmp member tables */ 1600 rv = soc_esw_mem_dma_read(unit, L3_ECMPm, 1601 sizeof(ecmp_entry_t), 1602 "ecmp_tbl", 1603 rd_start, rd_end, 1604 &ecmp1_tbl_p); 1605 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1606 1607 rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm, 1608 sizeof(initial_l3_ecmp_entry_t), 1609 "ecmp2_tbl", 1610 rd_start, rd_end, 1611 &ecmp2_tbl_p); 1612 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1613 1614 ecmp1_null_entry = soc_mem_entry_null(unit, L3_ECMPm); 1615 ecmp2_null_entry = soc_mem_entry_null(unit, INITIAL_L3_ECMPm); 1616 1617 /* Populate new nexthop indices in the member tables. */ 1618 for (idx = ecmp_base_offset, nh_idx = 0; 1619 idx < (ecmp_base_offset + max_grp_size); 1620 idx++, nh_idx++) { 1621 1622 /* Set next hop index. */ 1623 ecmp1_entry_ptr = 1624 soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *, 1625 ecmp1_tbl_p, idx); 1626 ecmp2_entry_ptr = 1627 soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *, 1628 ecmp2_tbl_p, idx); 1629 1630 sal_memcpy(ecmp1_entry_ptr, ecmp1_null_entry, 1631 sizeof(ecmp_entry_t)); 1632 sal_memcpy(ecmp2_entry_ptr, ecmp2_null_entry, 1633 sizeof(initial_l3_ecmp_entry_t)); 1634 1635 ecmpf = 0; 1636 soc_esw_nh_if_ecmp_grp_decode(unit, &(ecmp_members[nh_idx].nh), &ecmpf); 1637 1638 /* Set ecmp flag if member is an ecmp group */ 1639 if (ecmpf == 1) { 1640 soc_mem_field32_set(unit, L3_ECMPm, 1641 ecmp1_entry_ptr, ECMP_FLAGf, 1); 1642 soc_mem_field32_set(unit, INITIAL_L3_ECMPm, 1643 ecmp2_entry_ptr, ECMPf, 1); 1644 1645 soc_mem_field32_dest_set(unit, L3_ECMPm, 1646 ecmp1_entry_ptr, 1647 DESTINATIONf, SOC_MEM_FIF_DEST_ECMP, 1648 ecmp_members[nh_idx].nh); 1649 soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm, 1650 ecmp2_entry_ptr, 1651 DESTINATIONf, SOC_MEM_FIF_DEST_ECMP, 1652 ecmp_members[nh_idx].nh); 1653 } else { 1654 soc_mem_field32_dest_set(unit, L3_ECMPm, 1655 ecmp1_entry_ptr, 1656 DESTINATIONf, SOC_MEM_FIF_DEST_NEXTHOP, 1657 ecmp_members[nh_idx].nh); 1658 soc_mem_field32_dest_set(unit, INITIAL_L3_ECMPm, 1659 ecmp2_entry_ptr, 1660 DESTINATIONf, SOC_MEM_FIF_DEST_NEXTHOP, 1661 ecmp_members[nh_idx].nh); 1662 } 1663 1664 if (grp_info->vp_lag == 1) { 1665 soc_mem_field32_set(unit, L3_ECMPm, 1666 ecmp1_entry_ptr, DVPf, 1667 ecmp_members[nh_idx].dvp); 1668 } 1669 1670 soc_mem_field32_set(unit, INITIAL_L3_ECMPm, 1671 ecmp2_entry_ptr, 1672 PROT_NEXT_HOP_INDEXf, 1673 ecmp_members[nh_idx].prot_nh); 1674 1675 soc_mem_field32_set(unit, INITIAL_L3_ECMPm, 1676 ecmp2_entry_ptr, 1677 PROT_GROUPf, 1678 ecmp_members[nh_idx].prot_grp); 1679 } 1680 1681 /* Write updated member tables */ 1682 rv = soc_mem_write_range(unit, L3_ECMPm, MEM_BLOCK_ALL, 1683 wr_start, wr_end, ecmp1_tbl_p); 1684 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1685 1686 rv = soc_mem_write_range(unit, INITIAL_L3_ECMPm, MEM_BLOCK_ALL, 1687 wr_start, wr_end, ecmp2_tbl_p); 1688 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1689 1690 /* If the group is being updated and index has moved, free old index. */ 1691 rv = soc_esw_ecmp_protected_idx_free(unit, 1692 grp_state->bank, 1693 grp_state->base, 1694 grp_state->count); 1695 SOC_IF_ERROR_RETURN(rv); 1696 1697 /* Update ECMP group's base ptr */ 1698 grp_info->ecmp_member_base = (ecmp_idx + (wr_start - rd_start)); 1699 1700 /* Update ECMP member state */ 1701 rv = soc_esw_ecmp_protected_idx_alloc(unit, 1702 (bank_swap_reqd ? bank_idx_r : bank_idx), 1703 grp_info->ecmp_member_base, 1704 grp_info->max_paths); 1705 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1706 1707 /* Update ECMP group state */ 1708 rv = soc_esw_ecmp_protected_state_set(unit, 1709 grp_info->ecmp_grp, 1710 (bank_swap_reqd ? bank_idx_r : bank_idx), 1711 grp_info->ecmp_member_base, 1712 grp_info->max_paths); 1713 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1714 1715 if (bank_swap_reqd) { 1716 /* Update other groups with members in this bank */ 1717 rv = soc_esw_ecmp_protected_bank_update(unit, bank_idx, bank_idx_r); 1718 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1719 } 1720 1721 err_exit: 1722 if (ecmp2_tbl_p) { 1723 soc_cm_sfree(unit, ecmp2_tbl_p); 1724 } 1725 if (ecmp1_tbl_p) { 1726 soc_cm_sfree(unit, ecmp1_tbl_p); 1727 } 1728 1729 1730 return rv; 1731 } 1732 1733 /* 1734 * Function: 1735 * soc_esw_ecmp_protected_grp_delete 1736 * Purpose: 1737 * Delete ECMP members 1738 * NOTE: Function does not update the INITIAL_L3_ECMP and L3_ECMP tables. 1739 * Group tables need to be updated to reflect group delete. 1740 * Parameters: 1741 * unit - (IN)SOC unit number. 1742 * grp_info - (IN)ecmp group id to write. 1743 * Returns: 1744 * SOC_E_XXX 1745 */ 1746 int 1747 soc_esw_ecmp_protected_grp_delete(int unit, 1748 soc_esw_ecmp_group_info_t *grp_info) 1749 { 1750 int rv; 1751 soc_esw_ecmp_group_state_t *grp_state; 1752 1753 grp_state = SOC_ESW_ECMP_GROUP_INFO(unit, grp_info->ecmp_grp); 1754 1755 /* Update ECMP member state */ 1756 rv = soc_esw_ecmp_protected_idx_free(unit, 1757 grp_state->bank, 1758 grp_state->base, 1759 grp_state->count); 1760 SOC_IF_ERROR_RETURN(rv); 1761 1762 /* Update ECMP group state */ 1763 rv = soc_esw_ecmp_protected_state_set(unit, 1764 grp_info->ecmp_grp, 1765 0, 1766 0, 1767 0); 1768 SOC_IF_ERROR_RETURN(rv); 1769 1770 return SOC_E_NONE; 1771 } 1772 1773 /* 1774 * Function: 1775 * soc_esw_ecmp_protected_grp_get 1776 * Purpose: 1777 * Fetch ecmp members info for a given group 1778 * Parameters: 1779 * unit - (IN)SOC unit number. 1780 * grp_info - (IN)ecmp group id to write. 1781 * mem_list - (OUT)Next hop indexes or NULL for entry reset. 1782 * Returns: 1783 * SOC_E_XXX 1784 */ 1785 int 1786 soc_esw_ecmp_protected_grp_get(int unit, 1787 soc_esw_ecmp_group_info_t *grp_info, 1788 void *mem_list) 1789 { 1790 int max_grp_size; /* Maximum ecmp group size.*/ 1791 int ecmp_idx; /* Ecmp table entry index. */ 1792 int nh_idx; /* NextHop Idx or Ecmp Group */ 1793 int bank_idx; /* Ecmp Member Table Bank */ 1794 int idx; /* Iteration index. */ 1795 int rv; /* Operation return value. */ 1796 1797 uint8 *ecmp1_tbl_p = NULL; /* Dma L3 ECMP table pointer. */ 1798 uint8 *ecmp2_tbl_p = NULL; /* Dma L3 ECMP table pointer. */ 1799 uint32 *ecmp1_entry_ptr = NULL; /* ECMP entry pointer.*/ 1800 uint32 *ecmp2_entry_ptr = NULL; /* ECMP entry pointer.*/ 1801 uint32 dest_val; 1802 uint32 dest_type = SOC_MEM_FIF_DEST_INVALID; 1803 soc_esw_ecmp_member_info_t *ecmp_members;/* Ecmp group nh indexes. */ 1804 1805 /* Get ECMP group state */ 1806 rv = soc_esw_ecmp_protected_state_get(unit, 1807 grp_info->ecmp_grp, 1808 &bank_idx, 1809 &ecmp_idx, 1810 &max_grp_size); 1811 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1812 1813 /* Cast input buffer. */ 1814 ecmp_members = mem_list; 1815 1816 /* Read ecmp member tables */ 1817 rv = soc_esw_mem_dma_read(unit, L3_ECMPm, 1818 sizeof(ecmp_entry_t), 1819 "ecmp_tbl", 1820 ecmp_idx, 1821 (ecmp_idx + max_grp_size - 1), 1822 &ecmp1_tbl_p); 1823 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1824 1825 /* Read ecmp member tables */ 1826 rv = soc_esw_mem_dma_read(unit, INITIAL_L3_ECMPm, 1827 sizeof(ecmp_entry_t), 1828 "initial_ecmp_tbl", 1829 ecmp_idx, 1830 (ecmp_idx + max_grp_size - 1), 1831 &ecmp2_tbl_p); 1832 SOC_ESW_ECMP_IF_ERR_EXIT(rv); 1833 1834 /* Populate new nexthop indices from the member tables. */ 1835 for (idx = 0, nh_idx = 0; idx < max_grp_size; idx++, nh_idx++) { 1836 /* Set next hop index. */ 1837 ecmp1_entry_ptr = 1838 soc_mem_table_idx_to_pointer(unit, L3_ECMPm, uint32 *, 1839 ecmp1_tbl_p, idx); 1840 ecmp2_entry_ptr = 1841 soc_mem_table_idx_to_pointer(unit, INITIAL_L3_ECMPm, uint32 *, 1842 ecmp2_tbl_p, idx); 1843 1844 dest_val = soc_mem_field32_dest_get(unit, L3_ECMPm, ecmp1_entry_ptr, 1845 DESTINATIONf, &dest_type); 1846 soc_esw_nh_if_ecmp_grp_encode(unit, &(dest_val), 1847 (dest_type == SOC_MEM_FIF_DEST_ECMP)); 1848 ecmp_members[nh_idx].nh = dest_val; 1849 1850 if (grp_info->vp_lag == 1) { 1851 ecmp_members[nh_idx].dvp = soc_mem_field32_get(unit, L3_ECMPm, 1852 ecmp1_entry_ptr, DVPf); 1853 } 1854 1855 ecmp_members[nh_idx].prot_nh = soc_mem_field32_get(unit, INITIAL_L3_ECMPm, 1856 ecmp2_entry_ptr, 1857 PROT_NEXT_HOP_INDEXf); 1858 ecmp_members[nh_idx].prot_grp = soc_mem_field32_get(unit, INITIAL_L3_ECMPm, 1859 ecmp2_entry_ptr, 1860 PROT_GROUPf); 1861 } 1862 1863 err_exit: 1864 if (ecmp1_tbl_p) { 1865 soc_cm_sfree(unit, ecmp1_tbl_p); 1866 } 1867 1868 if (ecmp2_tbl_p) { 1869 soc_cm_sfree(unit, ecmp2_tbl_p); 1870 } 1871 return rv; 1872 } 1873 1874 #else 1875 int _include_soc_ecmp_not_empty; 1876 #endif /* SOC_L3_ECMP_PROTECTED_ACCESS_SUPPORT */ 1877