l2x.c (78760B)
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 * XGS TR3 L2 Table Manipulation API routines. 8 * 9 * A low-level L2 shadow table is optionally kept in soc->arlShadow by 10 * using a callback to get all inserts/deletes from the l2xmsg task. It 11 * can be disabled by setting the l2xmsg_avl property to 0. 12 */ 13 14 #include <sal/core/libc.h> 15 #include <shared/bsl.h> 16 #include <soc/drv.h> 17 #include <soc/l2x.h> 18 #include <soc/ptable.h> 19 #include <soc/debug.h> 20 #include <soc/util.h> 21 #include <soc/mem.h> 22 #include <soc/ism_hash.h> 23 #include <soc/triumph3.h> 24 #include <soc/tcam/tcamtype1.h> 25 #include <soc/er_tcam.h> 26 27 #ifdef BCM_XGS_SWITCH_SUPPORT 28 29 #define _SOC_ALL_L2X_MEM_LOCK(unit) \ 30 SOC_L2X_MEM_LOCK(unit); \ 31 if (soc_feature(unit, soc_feature_esm_support)) { \ 32 SOC_EXT_L2X_MEM_LOCK(unit); \ 33 } 34 35 #define _SOC_ALL_L2X_MEM_UNLOCK(unit) \ 36 SOC_L2X_MEM_UNLOCK(unit); \ 37 if (soc_feature(unit, soc_feature_esm_support)) { \ 38 SOC_EXT_L2X_MEM_UNLOCK(unit); \ 39 } 40 41 #define _SOC_IF_ERROR_ALL_L2X_UNLOCK_RETURN(rv) \ 42 if (!SOC_SUCCESS(rv)) { \ 43 SOC_L2X_MEM_UNLOCK(unit); \ 44 if (soc_feature(unit, soc_feature_esm_support)) { \ 45 SOC_EXT_L2X_MEM_UNLOCK(unit); \ 46 } \ 47 LOG_ERROR(BSL_LS_SOC_L2, \ 48 (BSL_META_U(unit, \ 49 "rv: %d\n"), rv)); \ 50 return rv; \ 51 } 52 53 #define _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, label) \ 54 if (!SOC_SUCCESS(rv)) { \ 55 SOC_L2X_MEM_UNLOCK(unit); \ 56 if (soc_feature(unit, soc_feature_esm_support)) { \ 57 SOC_EXT_L2X_MEM_UNLOCK(unit); \ 58 } \ 59 LOG_ERROR(BSL_LS_SOC_L2, \ 60 (BSL_META_U(unit, \ 61 "rv: %d\n"), rv)); \ 62 goto label; \ 63 } 64 65 /* 66 * While the L2 table is frozen, the L2Xm lock is held. 67 * 68 * All tasks must obtain the L2Xm lock before modifying the CML bits or 69 * age timer registers. 70 */ 71 72 typedef struct l2_freeze_s { 73 int frozen; 74 int save_age_sec; 75 int save_age_ena; 76 } l2_freeze_t; 77 78 typedef enum { 79 _SOC_AGE_DEFAULT, 80 _SOC_AGE_ON_HITSA_ONLY 81 } _soc_age_criteria_t; 82 83 typedef enum { 84 RETRY_DEFAULT, 85 RETRY_DELETE, 86 RETRY_AGE 87 } retry_action; 88 89 90 l2_freeze_t tr3_l2_freeze_state[SOC_MAX_NUM_DEVICES]; 91 92 #define _SOC_TR3_L2_TABLE_DMA_CHUNK_SIZE 1024 93 #define _SOC_TR3_VALID_MAX_AGE_INTERVAL (2147) 94 #define _SOC_TR3_L2AGE_USEC_IN_ONESEC (1000000) 95 96 /* 97 * Function: 98 * soc_tr3_l2_entry_compare_key 99 * Purpose: 100 * Comparison function for AVL shadow table operations. Compares 101 * key portion of entry only. 102 * Parameters: 103 * user_data - used to pass StrataSwitch unit # 104 * datum1 - first L2X entry to compare 105 * datum2 - second L2X entry to compare 106 * Returns: 107 * datum1 <=> datum2 108 */ 109 110 int 111 soc_tr3_l2_entry_compare_key(void *user_data, 112 shr_avl_datum_t *datum1, 113 shr_avl_datum_t *datum2) 114 { 115 int unit = PTR_TO_INT(user_data); 116 117 return _soc_mem_cmp_tr3_l2x(unit, (void *)datum1, (void *)datum2); 118 } 119 120 int 121 soc_tr3_ext_l2_entry_compare_key(void *user_data, 122 shr_avl_datum_t *datum1, 123 shr_avl_datum_t *datum2) 124 { 125 int unit = PTR_TO_INT(user_data); 126 127 return _soc_mem_cmp_tr3_ext_l2x(unit, (void *)datum1, (void *)datum2); 128 } 129 130 /* 131 * Function: 132 * soc_tr3_l2_entry_dump 133 * Purpose: 134 * Debug dump function for AVL shadow table operations. 135 * Parameters: 136 * user_data - used to pass StrataSwitch unit # 137 * datum - L2X entry to dump 138 * extra_data - unused 139 * Returns: 140 * SOC_E_XXX 141 */ 142 143 int 144 soc_tr3_l2_entry_dump(void *user_data, shr_avl_datum_t *datum, void *extra_data) 145 { 146 uint32 val; 147 int unit = PTR_TO_INT(user_data); 148 soc_mem_t mem_type = L2_ENTRY_1m; 149 150 COMPILER_REFERENCE(extra_data); 151 152 val = soc_mem_field32_get(unit, L2_ENTRY_1m, (l2_entry_1_entry_t *)datum, KEY_TYPEf); 153 if ((val == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) || 154 (val == SOC_MEM_KEY_L2_ENTRY_2_L2_VFI) || 155 (val == SOC_MEM_KEY_L2_ENTRY_2_L2_TRILL_NONUC_ACCESS)) { 156 mem_type = L2_ENTRY_2m; 157 } 158 159 if (mem_type == L2_ENTRY_1m) { 160 soc_mem_entry_dump(unit, L2_ENTRY_1m, (l2x_entry_t *)datum, BSL_LSS_CLI); 161 } else { 162 soc_mem_entry_dump(unit, L2_ENTRY_2m, (l2x_entry_t *)datum, BSL_LSS_CLI); 163 } 164 LOG_CLI((BSL_META_U(unit, 165 "\n"))); 166 167 return SOC_E_NONE; 168 } 169 170 int 171 soc_tr3_ext_l2_1_entry_dump(void *user_data, shr_avl_datum_t *datum, void *extra_data) 172 { 173 int unit = PTR_TO_INT(user_data); 174 175 COMPILER_REFERENCE(extra_data); 176 177 soc_mem_entry_dump(unit, EXT_L2_ENTRY_1m, (l2x_entry_t *)datum, BSL_LSS_CLI); 178 LOG_CLI((BSL_META_U(unit, 179 "\n"))); 180 181 return SOC_E_NONE; 182 } 183 184 int 185 soc_tr3_ext_l2_2_entry_dump(void *user_data, shr_avl_datum_t *datum, void *extra_data) 186 { 187 int unit = PTR_TO_INT(user_data); 188 189 COMPILER_REFERENCE(extra_data); 190 191 soc_mem_entry_dump(unit, EXT_L2_ENTRY_2m, (l2x_entry_t *)datum, BSL_LSS_CLI); 192 LOG_CLI((BSL_META_U(unit, 193 "\n"))); 194 195 return SOC_E_NONE; 196 } 197 198 /* 199 * Function: 200 * soc_tr3_l2_shadow_callback 201 * Purpose: 202 * Internal callback routine for updating an AVL tree shadow table 203 * Parameters: 204 * unit - StrataSwitch unit number. 205 * entry_del - Entry to be deleted or updated, NULL if none. 206 * entry_add - Entry to be inserted or updated, NULL if none. 207 * fn_data - unused. 208 * Notes: 209 * Used only if L2X shadow table is enabled. 210 */ 211 212 STATIC void 213 soc_tr3_l2_shadow_callback(int unit, uint32 flags, soc_mem_t mem, 214 l2_combo_entry_t *entry_del, 215 l2_combo_entry_t *entry_add, 216 void *fn_data) 217 { 218 soc_control_t *soc = SOC_CONTROL(unit); 219 220 sal_mutex_take(soc->arlShadowMutex, sal_mutex_FOREVER); 221 if ((mem == L2_ENTRY_1m) || (mem == L2_ENTRY_2m)) { 222 if (entry_del != NULL) { 223 shr_avl_delete(soc->arlShadow, soc_tr3_l2_entry_compare_key, 224 (shr_avl_datum_t *)entry_del); 225 } 226 if (entry_add != NULL) { 227 shr_avl_insert(soc->arlShadow, soc_tr3_l2_entry_compare_key, 228 (shr_avl_datum_t *)entry_add); 229 } 230 } else if (soc_feature(unit, soc_feature_esm_support)) { 231 if (mem == EXT_L2_ENTRY_1m) { 232 if (entry_del != NULL) { 233 shr_avl_delete(soc->arlShadow_ext1, soc_tr3_ext_l2_entry_compare_key, 234 (shr_avl_datum_t *)entry_del); 235 } 236 if (entry_add != NULL) { 237 shr_avl_insert(soc->arlShadow_ext1, soc_tr3_ext_l2_entry_compare_key, 238 (shr_avl_datum_t *)entry_add); 239 } 240 } else if (mem == EXT_L2_ENTRY_2m) { 241 if (entry_del != NULL) { 242 shr_avl_delete(soc->arlShadow_ext2, soc_tr3_ext_l2_entry_compare_key, 243 (shr_avl_datum_t *)entry_del); 244 } 245 if (entry_add != NULL) { 246 shr_avl_insert(soc->arlShadow_ext2, soc_tr3_ext_l2_entry_compare_key, 247 (shr_avl_datum_t *)entry_add); 248 } 249 } 250 } 251 sal_mutex_give(soc->arlShadowMutex); 252 } 253 254 /* 255 * Function: 256 * soc_tr3_l2_detach 257 * Purpose: 258 * Deallocate L2X subsystem resources 259 * Parameters: 260 * unit - StrataSwitch unit number. 261 * Returns: 262 * SOC_E_XXX 263 */ 264 265 int 266 soc_tr3_l2_detach(int unit) 267 { 268 soc_control_t *soc = SOC_CONTROL(unit); 269 270 soc_l2_entry_unregister(unit, soc_tr3_l2_shadow_callback, NULL); 271 272 /* Free cml_freeze structure */ 273 _soc_l2x_cml_struct_free(unit); 274 275 if (soc->arlShadow != NULL) { 276 shr_avl_destroy(soc->arlShadow); 277 soc->arlShadow = NULL; 278 } 279 if (soc_feature(unit, soc_feature_esm_support)) { 280 if (soc->arlShadow_ext1 != NULL) { 281 shr_avl_destroy(soc->arlShadow_ext1); 282 soc->arlShadow_ext1 = NULL; 283 } 284 if (soc->arlShadow_ext2 != NULL) { 285 shr_avl_destroy(soc->arlShadow_ext2); 286 soc->arlShadow_ext2 = NULL; 287 } 288 } 289 290 if (soc->arlShadowMutex != NULL) { 291 sal_mutex_destroy(soc->arlShadowMutex); 292 soc->arlShadowMutex = NULL; 293 } 294 295 return SOC_E_NONE; 296 } 297 298 /* 299 * Function: 300 * soc_tr3_l2_attach 301 * Purpose: 302 * Allocate L2X subsystem resources 303 * Parameters: 304 * unit - StrataSwitch unit number. 305 * Returns: 306 * SOC_E_XXX 307 * Notes: 308 * The L2X tree shadow table is optional and its allocation 309 * is controlled using a property. 310 */ 311 312 int 313 soc_tr3_l2_attach(int unit) 314 { 315 soc_control_t *soc = SOC_CONTROL(unit); 316 soc_tcam_info_t *tcam_info; 317 soc_tcam_partition_t *partitions = NULL; 318 319 (void)soc_tr3_l2_detach(unit); 320 321 tcam_info = soc->tcam_info; 322 if (tcam_info) { 323 partitions = tcam_info->partitions; 324 } 325 if (soc_property_get(unit, spn_L2XMSG_AVL, TRUE)) { 326 int datum_bytes, datum_max; 327 328 datum_bytes = sizeof(l2_entry_1_entry_t); 329 datum_max = tcam_info ? partitions[TCAM_PARTITION_FWD_L2].num_entries : 330 soc_mem_index_count(unit, L2_ENTRY_1m); 331 if (shr_avl_create(&soc->arlShadow, 332 INT_TO_PTR(unit), 333 datum_bytes, 334 datum_max) < 0) { 335 return SOC_E_MEMORY; 336 } 337 if (soc_feature(unit, soc_feature_esm_support)) { 338 datum_bytes = sizeof(ext_l2_entry_1_entry_t); 339 datum_max = tcam_info ? 340 partitions[TCAM_PARTITION_FWD_L2].num_entries : 341 soc_mem_index_count(unit, EXT_L2_ENTRY_1m); 342 if (shr_avl_create(&soc->arlShadow_ext1, 343 INT_TO_PTR(unit), 344 datum_bytes, 345 datum_max) < 0) { 346 (void)soc_tr3_l2_detach(unit); 347 return SOC_E_MEMORY; 348 } 349 datum_bytes = sizeof(ext_l2_entry_2_entry_t); 350 datum_max = tcam_info ? 351 partitions[TCAM_PARTITION_FWD_L2_WIDE].num_entries : 352 soc_mem_index_count(unit, EXT_L2_ENTRY_2m); 353 if (shr_avl_create(&soc->arlShadow_ext2, 354 INT_TO_PTR(unit), 355 datum_bytes, 356 datum_max) < 0) { 357 (void)soc_tr3_l2_detach(unit); 358 return SOC_E_MEMORY; 359 } 360 } 361 if ((soc->arlShadowMutex = sal_mutex_create("asMutex")) == NULL) { 362 (void)soc_tr3_l2_detach(unit); 363 return SOC_E_MEMORY; 364 } 365 366 soc_l2_entry_register(unit, soc_tr3_l2_shadow_callback, NULL); 367 } 368 369 /* Reset l2 freeze structure. */ 370 sal_memset(&tr3_l2_freeze_state[unit], 0, sizeof(l2_freeze_t)); 371 372 /* Init cml state */ 373 SOC_IF_ERROR_RETURN(_soc_l2x_cml_struct_alloc(unit)); 374 375 return SOC_E_NONE; 376 } 377 378 /* 379 * Function: 380 * _soc_tr3_l2_port_age 381 * Purpose: 382 * Use HW port/VLAN "aging" to delete selected L2 entries. 383 * Parameters: 384 * unit - StrataSwitch unit # 385 * age_reg0 - port aging register. 386 * age_reg1 - optioanl 2nd port aging register. 387 * Returns: 388 * SOC_E_XXX 389 * Notes: 390 * Hardware deletion is used. 391 * The chip requires that ARL aging be disabled during this 392 * operation. An unavoidable side effect is that the hardware 393 * aging timer gets restarted whenever this routine is called. 394 */ 395 int 396 soc_tr3_l2_port_age(int unit, soc_reg_t reg0, soc_reg_t reg1) 397 { 398 static soc_field_t fields[2] = { STARTf, COMPLETEf }; 399 static uint32 values[2] = { 1, 0 }; 400 soc_timeout_t to; 401 int rv; 402 int timeout_usec; 403 int reg0_complete, reg1_complete; 404 uint32 rval; 405 int mode; 406 407 if (reg0 == INVALIDr && reg1 == INVALIDr) { 408 return SOC_E_NONE; 409 } 410 411 timeout_usec = SOC_CONTROL(unit)->l2x_age_timeout; 412 mode = SOC_CONTROL(unit)->l2x_mode; 413 414 if (mode != L2MODE_FIFO) { 415 /* Disable learning etc. */ 416 SOC_IF_ERROR_RETURN(_soc_l2x_frozen_cml_save(unit)); 417 } 418 419 reg0_complete = TRUE; 420 if (reg0 != INVALIDr) { 421 rv = soc_reg_fields32_modify(unit, reg0, REG_PORT_ANY, 2, fields, 422 values); 423 if (SOC_FAILURE(rv)) { 424 goto done; 425 } 426 reg0_complete = FALSE; 427 } 428 429 reg1_complete = TRUE; 430 if (reg1 != INVALIDr) { 431 rv = soc_reg_fields32_modify(unit, reg1, REG_PORT_ANY, 2, fields, 432 values); 433 if (SOC_FAILURE(rv)) { 434 goto done; 435 } 436 reg1_complete = FALSE; 437 } 438 439 SOC_CONTROL(unit)->l2x_ppa_in_progress = TRUE; 440 soc_timeout_init(&to, timeout_usec, 0); 441 for (;;) { 442 if (!reg0_complete) { 443 rv = soc_reg32_get(unit, reg0, REG_PORT_ANY, 0, &rval); 444 if (SOC_SUCCESS(rv)) { 445 reg0_complete = soc_reg_field_get(unit, reg0, rval, COMPLETEf); 446 } 447 } 448 if (!reg1_complete) { 449 rv = soc_reg32_get(unit, reg1, REG_PORT_ANY, 0, &rval); 450 if (SOC_SUCCESS(rv)) { 451 reg1_complete = soc_reg_field_get(unit, reg1, rval, COMPLETEf); 452 } 453 } 454 455 if (reg0_complete && reg1_complete) { 456 rv = SOC_E_NONE; 457 break; 458 } 459 460 if (soc_timeout_check(&to)) { 461 rv = SOC_E_TIMEOUT; 462 break; 463 } 464 sal_usleep(SAL_BOOT_QUICKTURN ? 10000 : 1000); 465 } 466 467 done: 468 SOC_CONTROL(unit)->l2x_ppa_in_progress = FALSE; 469 if (mode != L2MODE_FIFO) { 470 SOC_IF_ERROR_RETURN(_soc_l2x_frozen_cml_restore(unit)); 471 } 472 return rv; 473 } 474 475 /* 476 * Function: 477 * soc_tr3_l2_is_frozen 478 * Purpose: 479 * Provides indication if L3 table is in frozen state 480 * Parameters: 481 * unit - (IN) BCM device number. 482 * frozen - (OUT) TRUE if L2x is frozen, FLASE otherwise 483 * Returns: 484 * SOC_E_NONE 485 * Notes: 486 * Does not change the frozen status of L2x table only reads it. 487 */ 488 489 int 490 soc_tr3_l2_is_frozen(int unit, int *frozen) 491 { 492 l2_freeze_t *f_l2 = &tr3_l2_freeze_state[unit]; 493 494 *frozen = (f_l2->frozen > 0) ? TRUE : FALSE ; 495 496 return (SOC_E_NONE); 497 } 498 499 /* 500 * Function: 501 * soc_tr3_l2_freeze 502 * Purpose: 503 * Temporarily quiesce L2 table from all activity (learning, aging) 504 * Parameters: 505 * unit - (IN) BCM device number. 506 * Returns: 507 * SOC_E_XXX 508 * Notes: 509 * Leaves L2Xm locked until corresponding thaw. 510 * PORT_TABm is locked in order to lockout bcm_port calls 511 * bcm_port calls will callout to soc_arl_frozen_cml_set/get 512 */ 513 514 int 515 soc_tr3_l2_freeze(int unit) 516 { 517 l2_freeze_t *f_l2 = &tr3_l2_freeze_state[unit]; 518 int rv = SOC_E_NONE; 519 520 /* Check if already frozen. */ 521 SOC_L2X_MEM_LOCK(unit); 522 if (f_l2->frozen > 0) { 523 /* Keep count - do nothing. */ 524 f_l2->frozen++; 525 SOC_L2X_MEM_UNLOCK(unit); 526 return (SOC_E_NONE); 527 } 528 SOC_L2X_MEM_UNLOCK(unit); 529 /* Disable learning etc. */ 530 SOC_IF_ERROR_RETURN(_soc_l2x_frozen_cml_save(unit)); 531 532 /* 533 * Disable learning and aging. 534 */ 535 /* Read l2 aging interval. */ 536 rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, &f_l2->save_age_sec, 537 &f_l2->save_age_ena); 538 if (SOC_FAILURE(rv)) { 539 _soc_l2x_frozen_cml_restore(unit); 540 return rv; 541 } 542 /* If l2 aging is on - disable it. */ 543 if (f_l2->save_age_ena) { 544 rv = SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, 545 f_l2->save_age_sec, 0); 546 if (SOC_FAILURE(rv)) { 547 _soc_l2x_frozen_cml_restore(unit); 548 return rv; 549 } 550 } 551 SOC_L2X_MEM_LOCK(unit); 552 /* Increment l2 frozen indicator. */ 553 f_l2->frozen++; 554 return (SOC_E_NONE); 555 } 556 557 558 /* 559 * Function: 560 * soc_tr3_l2_thaw 561 * Purpose: 562 * Restore normal L2 activity. 563 * Parameters: 564 * unit - (IN) BCM device number. 565 * Returns: 566 * SOC_E_XXX 567 */ 568 569 int 570 soc_tr3_l2_thaw(int unit) 571 { 572 l2_freeze_t *f_l2 = &tr3_l2_freeze_state[unit]; 573 int l2rv, cmlrv; 574 575 /* Sanity check to protect from thaw without freeze. */ 576 if (f_l2->frozen == 0 ) { 577 assert(0); 578 } 579 580 /* In case of nested freeze/thaw just decrement reference counter. */ 581 SOC_L2X_MEM_LOCK(unit); 582 if (f_l2->frozen > 1) { 583 f_l2->frozen--; 584 SOC_L2X_MEM_UNLOCK(unit); 585 return (SOC_E_NONE); 586 } 587 SOC_L2X_MEM_UNLOCK(unit); 588 /* 589 * Last thaw restore L2 learning and aging. 590 */ 591 l2rv = SOC_E_NONE; 592 if (f_l2->save_age_ena) { 593 l2rv = SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, f_l2->save_age_sec, 594 1); 595 } 596 /* L2 freeze reference counter decrement. */ 597 f_l2->frozen--; 598 SOC_L2X_MEM_UNLOCK(unit); 599 600 /* Restore port learning mode. */ 601 cmlrv = _soc_l2x_frozen_cml_restore(unit); 602 if (SOC_FAILURE(l2rv)) { 603 return l2rv; 604 } 605 return cmlrv; 606 } 607 608 static int _soc_tr3_l2_bulk_age_iter[SOC_MAX_NUM_DEVICES] = {0}; 609 610 /* 611 * Function: 612 * _soc_tr3_l2_do_age 613 * Purpose: 614 * set up match criteria and execute bulk 615 * operations on l2 table 616 * Parameters: 617 * unit - unit number. 618 * flags- to specify match criteria 619 * retry_loc-to store the memory if it returns a time_out 620 * Returns: 621 * none 622 */ 623 624 STATIC void 625 _soc_tr3_l2_do_age(int unit, uint32 flags, int8 *retry_loc) { 626 uint32 rval; 627 int field_len, rv; 628 soc_control_t *soc = SOC_CONTROL(unit); 629 sal_usecs_t stime, etime; 630 l2_bulk_entry_t l2_bulk; 631 l2_entry_1_entry_t l2_entry_1; 632 l2_entry_2_entry_t l2_entry_2; 633 ext_l2_entry_1_entry_t ext_l2_entry_1; 634 ext_l2_entry_2_entry_t ext_l2_entry_2; 635 int age_on_hitsa_only = flags & _SOC_AGE_ON_HITSA_ONLY; 636 637 stime = sal_time_usecs(); 638 639 _SOC_ALL_L2X_MEM_LOCK(unit); 640 if (soc_mem_index_count(unit, L2_ENTRY_1m) == 0) { 641 goto skip_age_int_l2; 642 } 643 if (*retry_loc > 0) { 644 goto skip_age_int_l2_1; 645 } 646 *retry_loc = 0; 647 sal_memset(&l2_bulk, 0, sizeof(l2_bulk)); 648 sal_memset(&l2_entry_1, 0, sizeof(l2_entry_1)); 649 650 /* First work on L2_ENTRY_1 */ 651 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, VALIDf, 1); 652 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, WIDEf, 1); 653 654 field_len = soc_mem_field_length(unit, L2_ENTRY_1m, KEY_TYPEf); 655 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, KEY_TYPEf, 656 (1 << field_len) - 1); 657 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, STATIC_BITf, 1); 658 if (age_on_hitsa_only) { 659 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, HITSAf, 1); 660 } 661 sal_memcpy(&l2_bulk, &l2_entry_1, sizeof(l2_entry_1)); 662 /* Set match mask */ 663 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 1, &l2_bulk); 664 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 665 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, WIDEf, 0); 666 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, KEY_TYPEf, 667 SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE); 668 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, STATIC_BITf, 0); 669 if (age_on_hitsa_only) { 670 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, HITSAf, 0); 671 } 672 sal_memcpy(&l2_bulk, &l2_entry_1, sizeof(l2_entry_1)); 673 /* Set match data */ 674 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0, &l2_bulk); 675 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 676 rv = READ_L2_BULK_CONTROLr(unit, &rval); 677 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 678 if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) { 679 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 1); 680 } else { 681 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 0); 682 } 683 if (age_on_hitsa_only) { 684 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 1); 685 } else { 686 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 3); 687 } 688 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, BURST_ENTRIESf, 689 _SOC_TR3_L2_BULK_BURST_MIN); 690 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ENTRY_WIDTHf, 0); 691 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 692 soc_mem_index_count(unit, L2_ENTRY_1m)); 693 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, EXTERNAL_L2_ENTRYf, 0); 694 rv = WRITE_L2_BULK_CONTROLr(unit, rval); 695 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 696 /* Age entries for SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE */ 697 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 698 if (rv == SOC_E_TIMEOUT) { 699 goto skip_age_ext_l2_2; 700 } 701 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 702 soc_mem_field32_set(unit, L2_ENTRY_1m, &l2_entry_1, KEY_TYPEf, 703 SOC_MEM_KEY_L2_ENTRY_1_L2_VFI); 704 sal_memcpy(&l2_bulk, &l2_entry_1, sizeof(l2_entry_1)); 705 /* Set match data */ 706 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0, &l2_bulk); 707 /* Age entries for SOC_MEM_KEY_L2_ENTRY_1_L2_VFI */ 708 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 709 if (rv == SOC_E_TIMEOUT) { 710 goto skip_age_ext_l2_2; 711 } 712 713 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 714 *retry_loc = -1; 715 716 skip_age_int_l2_1: 717 if (*retry_loc > 1) { 718 goto skip_age_int_l2; 719 } 720 *retry_loc = 1; 721 sal_memset(&l2_bulk, 0, sizeof(l2_bulk)); 722 sal_memset(&l2_entry_2, 0, sizeof(l2_entry_2)); 723 /* Then work on L2_ENTRY_2 */ 724 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, VALID_0f, 1); 725 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, VALID_1f, 1); 726 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, WIDE_0f, 1); 727 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, WIDE_1f, 1); 728 field_len = soc_mem_field_length(unit, L2_ENTRY_2m, KEY_TYPE_0f); 729 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, KEY_TYPE_0f, 730 (1 << field_len) - 1); 731 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, KEY_TYPE_1f, 732 (1 << field_len) - 1); 733 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, STATIC_BIT_0f, 1); 734 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, STATIC_BIT_1f, 1); 735 if (age_on_hitsa_only) { 736 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, HITSAf, 1); 737 } 738 sal_memcpy(&l2_bulk, &l2_entry_2, sizeof(l2_entry_2)); 739 /* Set match mask */ 740 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 1, &l2_bulk); 741 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 742 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, KEY_TYPE_0f, 743 SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE); 744 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, KEY_TYPE_1f, 745 SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE); 746 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, STATIC_BIT_0f, 0); 747 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, STATIC_BIT_1f, 0); 748 if (age_on_hitsa_only) { 749 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, HITSAf, 0); 750 } 751 sal_memcpy(&l2_bulk, &l2_entry_2, sizeof(l2_entry_2)); 752 /* Set match data */ 753 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0, &l2_bulk); 754 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 755 rv = READ_L2_BULK_CONTROLr(unit, &rval); 756 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 757 if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) { 758 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 1); 759 } else { 760 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 0); 761 } 762 if (age_on_hitsa_only) { 763 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 1); 764 } else { 765 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 3); 766 } 767 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, BURST_ENTRIESf, 768 _SOC_TR3_L2_BULK_BURST_MIN); 769 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ENTRY_WIDTHf, 1); 770 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 771 soc_mem_index_count(unit, L2_ENTRY_2m)); 772 rv = WRITE_L2_BULK_CONTROLr(unit, rval); 773 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 774 /* Age entries for SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE */ 775 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 776 if (rv == SOC_E_TIMEOUT) { 777 goto skip_age_ext_l2_2; 778 } 779 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 780 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, KEY_TYPE_0f, 781 SOC_MEM_KEY_L2_ENTRY_2_L2_VFI); 782 soc_mem_field32_set(unit, L2_ENTRY_2m, &l2_entry_2, KEY_TYPE_1f, 783 SOC_MEM_KEY_L2_ENTRY_2_L2_VFI); 784 sal_memcpy(&l2_bulk, &l2_entry_2, sizeof(l2_entry_2)); 785 /* Set match data */ 786 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0, &l2_bulk); 787 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 788 /* Age entries for SOC_MEM_KEY_L2_ENTRY_2_L2_VFI */ 789 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 790 if (rv == SOC_E_TIMEOUT) { 791 goto skip_age_ext_l2_2; 792 } 793 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 794 795 *retry_loc = -1; 796 797 skip_age_int_l2: 798 if (!soc_feature(unit, soc_feature_esm_support)) { 799 goto skip_age_ext_l2_2; 800 } 801 if (soc_mem_index_count(unit, EXT_L2_ENTRY_1m) == 0) { 802 goto skip_age_ext_l2_1; 803 } 804 if (*retry_loc > 2) { 805 goto skip_age_ext_l2_1; 806 } 807 *retry_loc = 2; 808 sal_memset(&l2_bulk, 0, sizeof(l2_bulk)); 809 sal_memset(&ext_l2_entry_1, 0, sizeof(ext_l2_entry_1)); 810 /* First work on EXT_L2_ENTRY_1 */ 811 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, &ext_l2_entry_1, FREEf, 1); 812 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, &ext_l2_entry_1, STATIC_BITf, 1); 813 if (age_on_hitsa_only) { 814 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, &ext_l2_entry_1, HITSAf, 1); 815 } 816 sal_memcpy(&l2_bulk, &ext_l2_entry_1, sizeof(ext_l2_entry_1)); 817 818 /* Set match mask */ 819 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 1, &l2_bulk); 820 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 821 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, &ext_l2_entry_1, FREEf, 0); 822 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, &ext_l2_entry_1, STATIC_BITf, 0); 823 if (age_on_hitsa_only) { 824 soc_mem_field32_set(unit, EXT_L2_ENTRY_1m, &ext_l2_entry_1, HITSAf, 0); 825 } 826 sal_memcpy(&l2_bulk, &ext_l2_entry_1, sizeof(ext_l2_entry_1)); 827 /* Set match data */ 828 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0, &l2_bulk); 829 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 830 rv = READ_L2_BULK_CONTROLr(unit, &rval); 831 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 832 if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) { 833 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 1); 834 } else { 835 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 0); 836 } 837 if (age_on_hitsa_only) { 838 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 1); 839 } else { 840 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 3); 841 } 842 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, BURST_ENTRIESf, 843 _SOC_TR3_L2_BULK_BURST_MIN); 844 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ENTRY_WIDTHf, 0); 845 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 846 SOC_MEM_TR3_EXT_L2_MAX_ENTRIES); 847 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, EXTERNAL_L2_ENTRYf, 1); 848 rv = WRITE_L2_BULK_CONTROLr(unit, rval); 849 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 850 /* Age entries */ 851 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 852 if (rv == SOC_E_TIMEOUT) { 853 goto skip_age_ext_l2_2; 854 } 855 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 856 rv = WRITE_ETU_EXT_L2_BULK_INFOr(unit, 0); 857 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 858 /* Issue dummy op */ 859 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 0); 860 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ENTRY_WIDTHf, 0); 861 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 1); 862 rv = WRITE_L2_BULK_CONTROLr(unit, rval); 863 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 864 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 865 if (rv == SOC_E_TIMEOUT) { 866 goto skip_age_ext_l2_2; 867 } 868 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 869 rv = WRITE_ETU_EXT_L2_BULK_INFOr(unit, 0); 870 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 871 872 *retry_loc = -1; 873 874 skip_age_ext_l2_1: 875 if (soc_mem_index_count(unit, EXT_L2_ENTRY_2m) == 0) { 876 goto skip_age_ext_l2_2; 877 } 878 if (*retry_loc >= 0 && *retry_loc < 3) { 879 goto skip_age_ext_l2_2; 880 } 881 *retry_loc = 3; 882 sal_memset(&l2_bulk, 0, sizeof(l2_bulk)); 883 sal_memset(&ext_l2_entry_2, 0, sizeof(ext_l2_entry_2)); 884 885 /* Then work on EXT_L2_ENTRY_2 */ 886 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, &ext_l2_entry_2, FREEf, 1); 887 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, &ext_l2_entry_2, STATIC_BITf, 1); 888 if (age_on_hitsa_only) { 889 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, &ext_l2_entry_2, HITSAf, 1); 890 } 891 sal_memcpy(&l2_bulk, &ext_l2_entry_2, sizeof(ext_l2_entry_2)); 892 /* Set match mask */ 893 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 1, &l2_bulk); 894 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 895 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, &ext_l2_entry_2, FREEf, 0); 896 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, &ext_l2_entry_2, STATIC_BITf, 0); 897 if (age_on_hitsa_only) { 898 soc_mem_field32_set(unit, EXT_L2_ENTRY_2m, &ext_l2_entry_2, HITSAf, 0); 899 } 900 sal_memcpy(&l2_bulk, &ext_l2_entry_2, sizeof(ext_l2_entry_2)); 901 /* Set match data */ 902 rv = WRITE_L2_BULKm(unit, MEM_BLOCK_ALL, 0, &l2_bulk); 903 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 904 rv = READ_L2_BULK_CONTROLr(unit, &rval); 905 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 906 if (SOC_CONTROL(unit)->l2x_mode == L2MODE_FIFO) { 907 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 1); 908 } else { 909 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, L2_MOD_FIFO_RECORDf, 0); 910 } 911 if (age_on_hitsa_only) { 912 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 1); 913 } else { 914 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 3); 915 } 916 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, BURST_ENTRIESf, 917 _SOC_TR3_L2_BULK_BURST_MIN); 918 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ENTRY_WIDTHf, 1); 919 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 920 SOC_MEM_TR3_EXT_L2_MAX_ENTRIES); 921 rv = WRITE_L2_BULK_CONTROLr(unit, rval); 922 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 923 /* Age entries */ 924 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 925 if (rv == SOC_E_TIMEOUT) { 926 goto skip_age_ext_l2_2; 927 } 928 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 929 rv = WRITE_ETU_EXT_L2_BULK_INFOr(unit, 0); 930 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 931 /* Issue dummy op */ 932 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ACTIONf, 0); 933 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, ENTRY_WIDTHf, 0); 934 soc_reg_field_set(unit, L2_BULK_CONTROLr, &rval, NUM_ENTRIESf, 1); 935 rv = WRITE_L2_BULK_CONTROLr(unit, rval); 936 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 937 rv = soc_tr3_l2_port_age(unit, L2_BULK_CONTROLr, INVALIDr); 938 if (rv == SOC_E_TIMEOUT) { 939 goto skip_age_ext_l2_2; 940 } 941 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 942 rv = WRITE_ETU_EXT_L2_BULK_INFOr(unit, 0); 943 _SOC_IF_ERROR_ALL_L2X_UNLOCK_JUMP(rv, cleanup_exit); 944 945 *retry_loc = -1; 946 947 skip_age_ext_l2_2: 948 _SOC_ALL_L2X_MEM_UNLOCK(unit); 949 etime = sal_time_usecs(); 950 LOG_VERBOSE(BSL_LS_SOC_ARL, 951 (BSL_META_U(unit, 952 "l2_bulk_age_thread: unit=%d: done in %d usec\n"), 953 unit, SAL_USECS_SUB(etime, stime))); 954 955 return; 956 957 cleanup_exit: 958 LOG_VERBOSE(BSL_LS_SOC_COMMON, 959 (BSL_META_U(unit, 960 "l2_bulk_age_thread: exiting\n"))); 961 (void)sal_sem_take(soc->l2x_age_notify, 1); 962 soc->l2x_age_pid = SAL_THREAD_ERROR; 963 sal_thread_exit(0); 964 } 965 966 /* 967 * Function: 968 * _soc_tr3_l2age_sem_wait 969 * Purpose: 970 * Wait in soc->l2x_age_notify semaphore for specified interval 971 * Parameters: 972 * wait_time - amount of time to be waited on semaphore 973 * Returns: 974 * usec - time spent in semaphore 975 */ 976 977 978 STATIC 979 sal_usecs_t _soc_tr3_l2age_sem_wait(void * unit_vp, sal_usecs_t wait_time) 980 { 981 int unit = PTR_TO_INT(unit_vp); 982 soc_control_t *soc = SOC_CONTROL(unit); 983 sal_usecs_t timebefore_agewait = 0, timeafter_agewait = 0, retval = 0; 984 985 timebefore_agewait = sal_time_usecs(); 986 (void)sal_sem_take(soc->l2x_age_notify, wait_time); 987 timeafter_agewait = sal_time_usecs(); 988 if (timeafter_agewait > timebefore_agewait) { 989 retval = timeafter_agewait - timebefore_agewait; 990 } 991 else { 992 retval = ((0xFFFFFFFF - timebefore_agewait) + timeafter_agewait); 993 } 994 995 return (retval); 996 } 997 998 999 /* 1000 * Function: 1001 * _soc_tr3_l2_bulk_age 1002 * Purpose: 1003 * l2 bulk age thread 1004 * Parameters: 1005 * unit - unit number. 1006 * Returns: 1007 * none 1008 */ 1009 STATIC void 1010 _soc_tr3_l2_bulk_age(void *unit_vp) 1011 { 1012 int unit = PTR_TO_INT(unit_vp); 1013 int c, m, r, iter = 0; 1014 uint32 flags = 0; 1015 soc_control_t *soc = SOC_CONTROL(unit); 1016 sal_usecs_t interval; 1017 sal_usecs_t timebefore_agewait = 0, timeafter_agewait = 0; 1018 sal_usecs_t actual_wait_time= 0, wait_interval = 0; 1019 int skip_tr3_l2age_semops = 0; 1020 int8 retry_loc = -1; /* To store the memory if bulk action times out */ 1021 1022 /* In case a bulk operation times out, we need to store which action timed 1023 out in order to retry. This variable stores the failed action - 1024 age or delete. If action succeds this variable is again set back to 1025 RETRY_DEFAULT */ 1026 int retry_action = RETRY_DEFAULT; 1027 1028 timebefore_agewait = sal_time_usecs(); 1029 while((interval = soc->l2x_age_interval) != 0) { 1030 if (!iter) { 1031 goto age_delay; 1032 } 1033 1034 run_tr3_l2bulkage_ops: 1035 LOG_VERBOSE(BSL_LS_SOC_ARL, 1036 (BSL_META_U(unit, 1037 "l2_bulk_age_thread: " 1038 "Process iters(total:%d, this run:%d\n"), 1039 ++_soc_tr3_l2_bulk_age_iter[unit], iter)); 1040 1041 timebefore_agewait = sal_time_usecs(); 1042 soc->l2x_agetime_adjust_usec = 0; 1043 soc->l2x_agetime_curr_timeblk = 0; 1044 soc->l2x_agetime_curr_timeblk_usec = 0; 1045 1046 1047 /* If aging should be based on HITSA only, we need to delete all entries 1048 HITSA = 0 and HITDA = 1 first, and then perform an age action. Age action 1049 deletes entries with HITSA = 0 and HITDA = 0, and clears all hit bits */ 1050 if (soc->l2x_age_hitsa_only) { 1051 flags |= _SOC_AGE_ON_HITSA_ONLY; 1052 if (retry_action == RETRY_DEFAULT || retry_action == RETRY_DELETE) { 1053 _soc_tr3_l2_do_age(unit, flags, &retry_loc); 1054 1055 if (retry_loc != -1) { 1056 /* Bulk delete failed. Need to retry this action */ 1057 retry_action = RETRY_DELETE; 1058 goto age_delay; 1059 } else { 1060 /* Bulk delete succeeded */ 1061 retry_action = RETRY_DEFAULT; 1062 } 1063 } 1064 } 1065 1066 if (retry_action == RETRY_DEFAULT || retry_action == RETRY_AGE) { 1067 _soc_tr3_l2_do_age(unit, 0, &retry_loc); 1068 1069 if (retry_loc != -1) { 1070 /* Bulk age failed. Need to retry this action */ 1071 retry_action = RETRY_AGE; 1072 goto age_delay; 1073 } else { 1074 /* Bulk age succeeded */ 1075 retry_action = RETRY_DEFAULT; 1076 } 1077 } 1078 1079 /* age delay processing normally wait in l2x_age_notify semaphore for the 1080 * specified interval before running bulk operation, now l2 bulk operation 1081 * API like delete_by_vlan/port will stop and start the age thread. 1082 * Here during exit, aging thread keeps track of amount of time spent on 1083 * semaphore in current cycle. Now when aging thread restarted, it waits 1084 * (aging interval - time spent on previuos cycle). Lets say, aging interval 1085 * is 50 sec, aging thread run for 20 sec. At that time, delete by vlan API 1086 * gets called, it stops and restarts the aging thread. This time aging 1087 * thread will wait for (50 sec - 20 sec) = 30 sec before running bulk ops 1088 * 1089 * _SOC_TR3_VALID_MAX_AGE_INTERVAL is 2147 sec. Now sem_take takes usec 1090 * integer vlaue. Max integer vlaue that can be adjusted in 31 bit is 1091 * 0x7FFFFFFF which approximates to (2147 * 1000000) usec. If age interval 1092 * is greater then 2147 sec, it is splitted to number of 2147 time blocks 1093 * and reminder part. For example, if age time is 2150 sec, there will be 1094 * (2150/2147 = 1) , one 2147 time block and (2150%2147= 3) , three sec 1095 * reminder part. Thread will wait first 2147 sec and then 3 sec before 1096 * running bulk operation. 1097 * 1098 * if age time is less that 2147 sec, soc->l2x_agetime_adjust_usec keeps 1099 * track of amount of time spent on semaphore in current cycle. It is 1100 * accumulative in nature , resetted before running bulk ops. 1101 * 1102 * if age time is greater then 2147 sec, soc->l2x_agetime_curr_timeblk 1103 * keeps track of current time block index and 1104 * soc->l2x_agetime_curr_timeblk_usec keeps track of amount of time 1105 * spent of sem. during current cycle. soc->l2x_agetime_adjust_usec keeps 1106 * track of reminder part of age time. All the variable are accumulative 1107 * in nature and resetted before running bulk ops. 1108 */ 1109 age_delay: 1110 /* If this flow is due to a force-bulk-op, goto exit, no ageing 1111 necessary */ 1112 if (skip_tr3_l2age_semops) { 1113 goto post_skip_l2bulkage_semops; 1114 } 1115 if (interval > _SOC_TR3_VALID_MAX_AGE_INTERVAL) { 1116 int aging_off = 0; 1117 1118 /* age interval greater than 2147 processing. */ 1119 1120 /* Cumpute the number of '_SOC_TR3_VALID_MAX_AGE_INTERVAL' blocks 1121 in the current interval */ 1122 m = interval / _SOC_TR3_VALID_MAX_AGE_INTERVAL; 1123 1124 /* Gather the reminder of the interval that is < than a block 1125 boundary */ 1126 r = interval % _SOC_TR3_VALID_MAX_AGE_INTERVAL; 1127 1128 /* Loop thru the # of blocks waiting. If we have already waited on 1129 the sem earlier, the 'l2x_agetime_curr_timeblk' will keep track of 1130 how long, so start there */ 1131 for (c = soc->l2x_agetime_curr_timeblk; c < m; c++) { 1132 /* Compute the mac usec's per '_SOC_TR3_VALID_MAX_AGE_INTERVAL' 1133 block */ 1134 wait_interval = _SOC_TR3_VALID_MAX_AGE_INTERVAL 1135 * _SOC_TR3_L2AGE_USEC_IN_ONESEC; 1136 /* Make sure 'wait_interval' is > than the accumulated time */ 1137 if (soc->l2x_agetime_curr_timeblk_usec < wait_interval) { 1138 /* Wait for the duration - any accumulated time */ 1139 actual_wait_time = _soc_tr3_l2age_sem_wait(unit_vp, 1140 wait_interval - soc->l2x_agetime_curr_timeblk_usec); 1141 /* Take into account how long we waited */ 1142 soc->l2x_agetime_curr_timeblk_usec += actual_wait_time; 1143 /* If the user is doing a bulk-op, 'soc->l2x_age_interval' 1144 would have gone to 0, if so, turn off aging and break */ 1145 if (!soc->l2x_age_interval) { 1146 aging_off =1; 1147 break; 1148 } else if (interval != soc->l2x_age_interval) { 1149 interval = soc->l2x_age_interval; 1150 soc->l2x_agetime_curr_timeblk_usec = 0; 1151 goto age_delay; 1152 } 1153 } 1154 /* In case of the user changes the age_interval while we are 1155 waiting on sem, the sem_wait exits sooner hence need to turn 1156 off aging, which will run bulk-op, init all vars and go back 1157 to sem-wait */ 1158 if (wait_interval > soc->l2x_agetime_curr_timeblk_usec) { 1159 aging_off = 1; 1160 break; 1161 } 1162 /* Increment how many blocks we have traversed thus far */ 1163 soc->l2x_agetime_curr_timeblk++; 1164 soc->l2x_agetime_curr_timeblk_usec = 0; 1165 } 1166 /* Wait on the sem for the reminder of the interval that is < than a 1167 block */ 1168 if (!aging_off) { 1169 if ( (r * _SOC_TR3_L2AGE_USEC_IN_ONESEC) > 1170 soc->l2x_agetime_adjust_usec ) { 1171 wait_interval = (r*_SOC_TR3_L2AGE_USEC_IN_ONESEC) - 1172 soc->l2x_agetime_adjust_usec; 1173 soc->l2x_agetime_adjust_usec += 1174 _soc_tr3_l2age_sem_wait(unit_vp, wait_interval); 1175 if (soc->l2x_age_interval && (interval != soc->l2x_age_interval)) { 1176 interval = soc->l2x_age_interval; 1177 goto age_delay; 1178 } 1179 } 1180 } 1181 } else { 1182 /* age time interval less then 2147 sec processing */ 1183 if ((interval * _SOC_TR3_L2AGE_USEC_IN_ONESEC) > 1184 soc->l2x_agetime_adjust_usec) { 1185 (void)sal_sem_take(soc->l2x_age_notify, 1186 (interval * _SOC_TR3_L2AGE_USEC_IN_ONESEC) 1187 - soc->l2x_agetime_adjust_usec); 1188 } 1189 if (soc->l2x_age_interval && (interval != soc->l2x_age_interval)) { 1190 interval = soc->l2x_age_interval; 1191 goto age_delay; 1192 } 1193 /* After the current pass, note the time after age_wait */ 1194 timeafter_agewait = sal_time_usecs(); 1195 } 1196 iter++; 1197 } 1198 1199 /* age thread exit processing */ 1200 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1201 (BSL_META_U(unit, 1202 "l2_bulk_age_thread: exiting\n"))); 1203 /* Check if the previous accumulated time exceeds the max interval? */ 1204 if (soc->l2x_prev_age_timeout <= _SOC_TR3_VALID_MAX_AGE_INTERVAL) { 1205 if (!timeafter_agewait) { 1206 /* If time_after is not set yet, do it now. This happends when 1207 thread is not schedduled but is exiting */ 1208 timeafter_agewait = sal_time_usecs(); 1209 } 1210 /* Normal case, where after is less than before*/ 1211 if (timeafter_agewait >= timebefore_agewait) { 1212 soc->l2x_agetime_adjust_usec += 1213 (timeafter_agewait - timebefore_agewait); 1214 } 1215 else { 1216 /* This is a wrap around case, where after is less than before */ 1217 soc->l2x_agetime_adjust_usec += 1218 ((0xFFFFFFFF - timebefore_agewait) + timeafter_agewait); 1219 } 1220 1221 /* Check for a special case where accumulated time exceeds the wait 1222 interval In such a case we need to force a bulk-op, before exiting */ 1223 if ((soc->l2x_prev_age_timeout) && (soc->l2x_agetime_adjust_usec >= 1224 (soc->l2x_prev_age_timeout * _SOC_TR3_L2AGE_USEC_IN_ONESEC))) { 1225 skip_tr3_l2age_semops = 1; 1226 /* Goto the force bulk op section */ 1227 goto run_tr3_l2bulkage_ops; 1228 } 1229 } 1230 post_skip_l2bulkage_semops: 1231 (void)sal_sem_take(soc->l2x_age_notify, 1); 1232 soc->l2x_age_pid = SAL_THREAD_ERROR; 1233 sal_thread_exit(0); 1234 1235 } 1236 1237 /* 1238 * Function: 1239 * soc_tr3_l2_bulk_age_start 1240 * Purpose: 1241 * Start l2 bulk age thread 1242 * Parameters: 1243 * unit - unit number. 1244 * Returns: 1245 * SOC_E_XXX 1246 */ 1247 int 1248 soc_tr3_l2_bulk_age_start(int unit, int interval) 1249 { 1250 int cfg_interval; 1251 soc_control_t *soc = SOC_CONTROL(unit); 1252 1253 cfg_interval = soc_property_get(unit, spn_L2_SW_AGING_INTERVAL, 1254 SAL_BOOT_QUICKTURN ? 30 : 10); 1255 SOC_CONTROL_LOCK(unit); 1256 soc->l2x_age_interval = interval ? interval : cfg_interval; 1257 sal_snprintf(soc->l2x_age_name, sizeof (soc->l2x_age_name), 1258 "bcmL2age.%d", unit); 1259 soc->l2x_age_pid = sal_thread_create(soc->l2x_age_name, SAL_THREAD_STKSZ, 1260 soc_property_get(unit, spn_L2AGE_THREAD_PRI, 50), 1261 _soc_tr3_l2_bulk_age, INT_TO_PTR(unit)); 1262 if (soc->l2x_age_pid == SAL_THREAD_ERROR) { 1263 LOG_ERROR(BSL_LS_SOC_L2, 1264 (BSL_META_U(unit, 1265 "bcm_esw_l2_init: Could not start L2 bulk age thread\n"))); 1266 SOC_CONTROL_UNLOCK(unit); 1267 return SOC_E_MEMORY; 1268 } 1269 SOC_CONTROL_UNLOCK(unit); 1270 return SOC_E_NONE; 1271 } 1272 1273 /* 1274 * Function: 1275 * soc_tr3_l2_bulk_age_stop 1276 * Purpose: 1277 * Stop l2 bulk age thread 1278 * Parameters: 1279 * unit - unit number. 1280 * Returns: 1281 * SOC_E_XXX 1282 */ 1283 int 1284 soc_tr3_l2_bulk_age_stop(int unit) 1285 { 1286 soc_control_t *soc = SOC_CONTROL(unit); 1287 int rv = SOC_E_NONE; 1288 soc_timeout_t to; 1289 1290 SOC_CONTROL_LOCK(unit); 1291 soc->l2x_age_interval = 0; /* Request exit */ 1292 SOC_CONTROL_UNLOCK(unit); 1293 1294 if (soc->l2x_age_pid && (soc->l2x_age_pid != SAL_THREAD_ERROR)) { 1295 /* Wake up thread so it will check the exit flag */ 1296 sal_sem_give(soc->l2x_age_notify); 1297 1298 /* Give thread a few seconds to wake up and exit */ 1299 if (SAL_BOOT_SIMULATION) { 1300 soc_timeout_init(&to, 300 * 1000000, 0); 1301 } else { 1302 soc_timeout_init(&to, 60 * 1000000, 0); 1303 } 1304 1305 while (soc->l2x_age_pid != SAL_THREAD_ERROR) { 1306 if (soc_timeout_check(&to)) { 1307 LOG_ERROR(BSL_LS_SOC_L2, 1308 (BSL_META_U(unit, 1309 "thread will not exit\n"))); 1310 rv = SOC_E_INTERNAL; 1311 break; 1312 } 1313 } 1314 } 1315 return rv; 1316 } 1317 1318 /************************************************** 1319 * @function soc_tr3_l2_entry_limit_count_update 1320 * 1321 * 1322 * @purpose Read L2 table from hardware, calculate 1323 * and restore port/trunk and vlan/vfi 1324 * mac counts. 1325 * 1326 * @param unit @b{(input)} unit number 1327 * 1328 * @returns BCM_E_NONE 1329 * @returns BCM_E_FAIL 1330 * 1331 * @comments This rountine gets called for an 1332 * L2 table SER event, if any of the 1333 * mac limits(system, port, vlan) are 1334 * enabled on the device. 1335 * 1336 * @end 1337 */ 1338 1339 int 1340 soc_tr3_l2_entry_limit_count_update(int unit) 1341 { 1342 uint32 entry[SOC_MAX_MEM_WORDS], rval; 1343 uint32 *v_entry; /* vlan or vfi count entry */ 1344 uint32 *p_entry; /* port or trunk count entry */ 1345 uint32 *l2; /* l2 entry */ 1346 int32 v_index = -1; /* vlan index */ 1347 int32 p_index = -1; /* port index */ 1348 uint32 s_count = 0; /* system mac count */ 1349 uint32 p_count = 0; /* port or trunk mac count */ 1350 uint32 v_count = 0; /* vlan or vfi mac count */ 1351 1352 /* l2 table */ 1353 int index_min, index_max; 1354 int entry_dw, entry_sz; 1355 int chnk_idx, chnk_idx_max, table_chnk_sz, idx; 1356 int chunk_size = _SOC_TR3_L2_TABLE_DMA_CHUNK_SIZE; 1357 1358 /* port or trunk mac count table */ 1359 int ptm_index_min, ptm_index_max; 1360 int ptm_table_sz, ptm_entry_dw, ptm_entry_sz; 1361 1362 /* vlan or vfi mac count table */ 1363 int vvm_index_min, vvm_index_max; 1364 int vvm_table_sz, vvm_entry_dw, vvm_entry_sz; 1365 1366 uint32 *buf = NULL; 1367 uint32 *ptm_buf = NULL; 1368 uint32 *vvm_buf = NULL; 1369 1370 uint32 dest_type, key_type; 1371 uint32 is_valid, is_limit_counted = 0; 1372 uint32 is_free; 1373 soc_mem_t mem; 1374 int rv; 1375 1376 p_index = -1; 1377 v_index = -1; 1378 1379 1380 /* If MAC learn limit not enabled do nothing */ 1381 SOC_IF_ERROR_RETURN(READ_SYS_MAC_LIMIT_CONTROLr(unit, &rval)); 1382 if (!soc_reg_field_get(unit, SYS_MAC_LIMIT_CONTROLr, 1383 rval, ENABLE_INTERNAL_L2_ENTRYf)) { 1384 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1385 (BSL_META_U(unit, 1386 "\nMAC limits not enabled.\n"))); 1387 return SOC_E_NONE; 1388 } 1389 1390 1391 /* 1392 * Mac limits are enabled. 1393 * 1. Read (DMA) L2 table to recalculate mac count 1394 * 2. Iterate through all the entries. 1395 * 3. if the entry is limit_counted 1396 * Check if KEY_TYPE is BRIDGE, VLAN or VFI 1397 * based on DEST_TYPE determine if Trunk or ModPort 1398 * Get port index into port_or_trunk_mac_count table 1399 * Get vlan/vfi index into vlan_or_vfi_mac_count table 1400 * update the port, vlan/vfi, system mac count. 1401 * Write(slam) port_or_trunk_mac count and 1402 * vlan_or_vfi_mac_count tables. 1403 */ 1404 1405 mem = L2_ENTRY_1m; 1406 _SOC_ALL_L2X_MEM_LOCK(unit); 1407 1408 /* 1409 * Allocate memory for port/trunk mac count table to store 1410 * the updated count. 1411 */ 1412 ptm_entry_dw = soc_mem_entry_words(unit, PORT_OR_TRUNK_MAC_COUNTm); 1413 ptm_entry_sz = ptm_entry_dw * sizeof(uint32); 1414 ptm_index_min = soc_mem_index_min(unit, PORT_OR_TRUNK_MAC_COUNTm); 1415 ptm_index_max = soc_mem_index_max(unit,PORT_OR_TRUNK_MAC_COUNTm); 1416 ptm_table_sz = (ptm_index_max - ptm_index_min + 1) * ptm_entry_sz; 1417 1418 ptm_buf = soc_cm_salloc(unit, ptm_table_sz, "ptm_tmp"); 1419 1420 if (ptm_buf == NULL) { 1421 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1422 LOG_ERROR(BSL_LS_SOC_L2, 1423 (BSL_META_U(unit, 1424 "soc_tr3_l2_entry_limit_count_update: " 1425 "Memory allocation failed for port mac count\n"))); 1426 return SOC_E_MEMORY; 1427 } 1428 1429 sal_memset(ptm_buf, 0, ptm_table_sz); 1430 1431 /* 1432 * Allocate memory for vlan/vfi mac count table to store 1433 * the updated count. 1434 */ 1435 vvm_entry_dw = soc_mem_entry_words(unit, VLAN_OR_VFI_MAC_COUNTm); 1436 vvm_entry_sz = vvm_entry_dw * sizeof(uint32); 1437 vvm_index_min = soc_mem_index_min(unit, VLAN_OR_VFI_MAC_COUNTm); 1438 vvm_index_max = soc_mem_index_max(unit,VLAN_OR_VFI_MAC_COUNTm); 1439 vvm_table_sz = (vvm_index_max - vvm_index_min + 1) * vvm_entry_sz; 1440 1441 vvm_buf = soc_cm_salloc(unit, vvm_table_sz, "vvm_tmp"); 1442 1443 if (vvm_buf == NULL) { 1444 soc_cm_sfree(unit, ptm_buf); 1445 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1446 LOG_ERROR(BSL_LS_SOC_L2, 1447 (BSL_META_U(unit, 1448 "soc_tr3_l2_entry_limit_count_update: " 1449 "Memory allocation failed for vlan mac count\n"))); 1450 return SOC_E_MEMORY; 1451 } 1452 1453 sal_memset(vvm_buf, 0, vvm_table_sz); 1454 1455 /* Create a copy L2_ENTRY_1m table for calculating mac count */ 1456 entry_dw = soc_mem_entry_words(unit, mem); 1457 entry_sz = entry_dw * sizeof(uint32); 1458 index_min = soc_mem_index_min(unit, mem); 1459 index_max = soc_mem_index_max(unit, mem); 1460 table_chnk_sz = chunk_size * entry_sz; 1461 1462 buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_tmp"); 1463 1464 if (buf == NULL) { 1465 soc_cm_sfree(unit, ptm_buf); 1466 soc_cm_sfree(unit, vvm_buf); 1467 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1468 LOG_ERROR(BSL_LS_SOC_L2, 1469 (BSL_META_U(unit, 1470 "soc_tr3_l2_entry_limit_count_update: " 1471 "Memory allocation failed for %s\n"), 1472 SOC_MEM_NAME(unit, mem))); 1473 return SOC_E_MEMORY; 1474 } 1475 1476 for (chnk_idx = index_min; chnk_idx <= index_max; chnk_idx += chunk_size) { 1477 1478 sal_memset(buf, 0, table_chnk_sz); 1479 1480 chnk_idx_max = ((chnk_idx + chunk_size) <= index_max) ? 1481 (chnk_idx + chunk_size - 1) : index_max; 1482 1483 /* DMA L2 Table */ 1484 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, chnk_idx, 1485 chnk_idx_max, buf); 1486 if (rv < 0) { 1487 soc_cm_sfree(unit, buf); 1488 soc_cm_sfree(unit, ptm_buf); 1489 soc_cm_sfree(unit, vvm_buf); 1490 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1491 LOG_ERROR(BSL_LS_SOC_L2, 1492 (BSL_META_U(unit, 1493 "DMA failed: %s, mac limts not synced!\n"), 1494 soc_errmsg(rv))); 1495 return SOC_E_FAIL; 1496 } 1497 1498 /* Iter through all l2 entries in the chunk */ 1499 for (idx = 0; idx <= (chnk_idx_max - chnk_idx); idx++) { 1500 l2 = (buf + (idx * entry_dw)); 1501 1502 /* check if entry is valid */ 1503 is_valid = soc_mem_field32_get(unit, mem, l2, VALIDf); 1504 if (!is_valid) { 1505 /* not valid entry skip it */ 1506 continue; 1507 } 1508 1509 /* check if entry is limit counted */ 1510 if (soc_mem_field_valid(unit, mem, LIMIT_COUNTEDf)) { 1511 is_limit_counted = soc_mem_field32_get(unit,mem, l2, 1512 LIMIT_COUNTEDf); 1513 if (!is_limit_counted) { 1514 /* entry not limit counted skip it */ 1515 continue; 1516 } 1517 } 1518 1519 /* 1520 * Get the key type of the entries 1521 * Process entries with only key_types 1522 * 1. SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE 1523 * 2. SOC_MEM_KEY_L2_ENTRY_1_L2_VFI 1524 */ 1525 key_type = soc_mem_field32_get(unit, mem, l2, KEY_TYPEf); 1526 1527 if ((key_type != SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE) && 1528 (key_type != SOC_MEM_KEY_L2_ENTRY_1_L2_VFI)) { 1529 continue; 1530 } 1531 1532 dest_type = soc_mem_field32_get(unit, mem, l2, L2__DEST_TYPEf); 1533 1534 switch (dest_type) { 1535 case 0: /* mod port */ 1536 rv = soc_mem_read(unit, PORT_TABm, 1537 MEM_BLOCK_ANY, 0, 1538 &entry); 1539 if (SOC_FAILURE(rv)) { 1540 soc_cm_sfree(unit, buf); 1541 soc_cm_sfree(unit, ptm_buf); 1542 soc_cm_sfree(unit, vvm_buf); 1543 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1544 return rv; 1545 } 1546 1547 if (soc_mem_field32_get(unit, PORT_TABm, 1548 &entry, MY_MODIDf) == 1549 soc_mem_field32_get(unit, mem, l2, L2__MODULE_IDf)) { 1550 p_index = soc_mem_field32_get(unit, mem, 1551 l2, PORT_NUMf) + 1552 soc_mem_index_count(unit, TRUNK_GROUPm) ; 1553 } 1554 break; 1555 case 1: /* trunk */ 1556 p_index = soc_mem_field32_get(unit, mem, l2, L2__TGIDf); 1557 break; 1558 default: 1559 /* if VFI based key then break else continue? */ 1560 break; 1561 } 1562 1563 /* 1564 * based on key_type get vlan or vfi 1565 * to index into VLAN_OR_VFI_MAC_COUNTm 1566 */ 1567 if (key_type == SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE) { 1568 v_index = soc_mem_field32_get(unit, mem, l2, L2__VLAN_IDf); 1569 } else { 1570 v_index = soc_mem_field32_get(unit, mem, l2, L2__VFIf) + 1571 soc_mem_index_count(unit, VLAN_TABm); 1572 } 1573 1574 1575 /* 1576 * read and update vlan or vfi mac count 1577 * in buffer also update the sys mac count. 1578 */ 1579 v_count = 0; 1580 if (v_index >= 0) { 1581 v_entry = (vvm_buf + (v_index * vvm_entry_dw)); 1582 v_count = soc_mem_field32_get(unit, VLAN_OR_VFI_MAC_COUNTm, 1583 v_entry, COUNTf); 1584 s_count++; 1585 v_count++; 1586 soc_mem_field32_set(unit, VLAN_OR_VFI_MAC_COUNTm, 1587 v_entry, COUNTf, v_count); 1588 } 1589 1590 /* 1591 * read and update port or trunk mac count 1592 * in buffer. 1593 */ 1594 p_count = 0; 1595 if (p_index >= 0) { 1596 p_entry = ptm_buf + (p_index * ptm_entry_dw); 1597 p_count = soc_mem_field32_get(unit, PORT_OR_TRUNK_MAC_COUNTm, 1598 p_entry, COUNTf); 1599 p_count++; 1600 soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm, 1601 p_entry, COUNTf, p_count); 1602 } 1603 1604 } /* End for index */ 1605 } /* End for chnk_idx */ 1606 1607 /* Free memory */ 1608 soc_cm_sfree(unit, buf); 1609 1610 /* Now create a copy L2_ENTRY_2m table for calculating mac count */ 1611 mem = L2_ENTRY_2m; 1612 entry_dw = soc_mem_entry_words(unit, mem); 1613 entry_sz = entry_dw * sizeof(uint32); 1614 index_min = soc_mem_index_min(unit, mem); 1615 index_max = soc_mem_index_max(unit, mem); 1616 table_chnk_sz = chunk_size * entry_sz; 1617 1618 buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_tmp"); 1619 1620 if (buf == NULL) { 1621 soc_cm_sfree(unit, ptm_buf); 1622 soc_cm_sfree(unit, vvm_buf); 1623 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1624 LOG_ERROR(BSL_LS_SOC_L2, 1625 (BSL_META_U(unit, 1626 "soc_tr3_l2_entry_limit_count_update: " 1627 "Memory allocation failed for %s\n"), 1628 SOC_MEM_NAME(unit, mem))); 1629 return SOC_E_MEMORY; 1630 } 1631 1632 for (chnk_idx = index_min; chnk_idx <= index_max; chnk_idx += chunk_size) { 1633 1634 sal_memset(buf, 0, table_chnk_sz); 1635 1636 chnk_idx_max = ((chnk_idx + chunk_size) <= index_max) ? 1637 (chnk_idx + chunk_size - 1) : index_max; 1638 1639 /* DMA L2 Table */ 1640 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, chnk_idx, 1641 chnk_idx_max, buf); 1642 if (rv < 0) { 1643 soc_cm_sfree(unit, buf); 1644 soc_cm_sfree(unit, ptm_buf); 1645 soc_cm_sfree(unit, vvm_buf); 1646 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1647 LOG_ERROR(BSL_LS_SOC_L2, 1648 (BSL_META_U(unit, 1649 "DMA failed: %s, mac limts not synced!\n"), 1650 soc_errmsg(rv))); 1651 return SOC_E_FAIL; 1652 } 1653 1654 /* Iter through all l2 entries in the chunk */ 1655 for (idx = 0; idx <= (chnk_idx_max - chnk_idx); idx++) { 1656 l2 = (buf + (idx * entry_dw)); 1657 1658 /* check if entry is valid */ 1659 if (!soc_mem_field32_get(unit, mem, l2, VALID_0f)) { 1660 /* not valid entry skip it */ 1661 continue; 1662 } 1663 1664 /* check if entry is limit counted */ 1665 if (soc_mem_field_valid(unit, mem, LIMIT_COUNTEDf)) { 1666 is_limit_counted = soc_mem_field32_get(unit,mem, l2, 1667 LIMIT_COUNTEDf); 1668 if (!is_limit_counted) { 1669 /* entry not limit counted skip it */ 1670 continue; 1671 } 1672 } 1673 1674 /* 1675 * Get the key type of the entries 1676 * Process entries with only key_types 1677 * 1. SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE 1678 * 2. SOC_MEM_KEY_L2_ENTRY_2_L2_VFI 1679 */ 1680 key_type = soc_mem_field32_get(unit, L2_ENTRY_1m, l2, KEY_TYPEf); 1681 1682 if ((key_type != SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) && 1683 (key_type != SOC_MEM_KEY_L2_ENTRY_2_L2_VFI)) { 1684 continue; 1685 } 1686 1687 dest_type = soc_mem_field32_get(unit, mem, l2, L2__DEST_TYPEf); 1688 1689 switch (dest_type) { 1690 case 0: /* mod port */ 1691 rv = soc_mem_read(unit, PORT_TABm, 1692 MEM_BLOCK_ANY, 0, 1693 &entry); 1694 if (SOC_FAILURE(rv)) { 1695 soc_cm_sfree(unit, buf); 1696 soc_cm_sfree(unit, ptm_buf); 1697 soc_cm_sfree(unit, vvm_buf); 1698 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1699 return rv; 1700 } 1701 if (soc_mem_field32_get(unit, PORT_TABm, 1702 &entry, MY_MODIDf) == 1703 soc_mem_field32_get(unit, mem, l2, L2__MODULE_IDf)) { 1704 p_index = soc_mem_field32_get(unit, mem, 1705 l2, L2__PORT_NUMf) + 1706 soc_mem_index_count(unit, TRUNK_GROUPm) ; 1707 } 1708 break; 1709 case 1: /* trunk */ 1710 p_index = soc_mem_field32_get(unit, mem, l2, L2__TGIDf); 1711 break; 1712 default: 1713 /* if VFI based key then break else continue? */ 1714 break; 1715 } 1716 1717 /* 1718 * based on key_type get vlan or vfi 1719 * to index into VLAN_OR_VFI_MAC_COUNTm 1720 */ 1721 if (key_type == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) { 1722 v_index = soc_mem_field32_get(unit, mem, l2, L2__VLAN_IDf); 1723 } else { 1724 v_index = soc_mem_field32_get(unit, mem, l2, L2__VFIf) + 1725 soc_mem_index_count(unit, VLAN_TABm); 1726 } 1727 1728 1729 /* 1730 * read and update vlan or vfi mac count 1731 * in buffer also update the sys mac count. 1732 */ 1733 v_count = 0; 1734 if (v_index >= 0) { 1735 v_entry = (vvm_buf + (v_index * vvm_entry_dw)); 1736 v_count = soc_mem_field32_get(unit, VLAN_OR_VFI_MAC_COUNTm, 1737 v_entry, COUNTf); 1738 s_count++; 1739 v_count++; 1740 soc_mem_field32_set(unit, VLAN_OR_VFI_MAC_COUNTm, 1741 v_entry, COUNTf, v_count); 1742 } 1743 1744 /* 1745 * read and update port or trunk mac count 1746 * in buffer. 1747 */ 1748 p_count = 0; 1749 if (p_index >= 0) { 1750 p_entry = ptm_buf + (p_index * ptm_entry_dw); 1751 p_count = soc_mem_field32_get(unit, PORT_OR_TRUNK_MAC_COUNTm, 1752 p_entry, COUNTf); 1753 p_count++; 1754 soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm, 1755 p_entry, COUNTf, p_count); 1756 } 1757 1758 } /* End for index */ 1759 } /* End for chnk_idx */ 1760 1761 soc_cm_sfree(unit, buf); 1762 1763 /* Work on EXT_L2_TABLE */ 1764 if (soc_feature(unit, soc_feature_esm_support)) { 1765 /* Create a copy EXT_L2_ENTRY_1m table for calculating mac count */ 1766 mem = EXT_L2_ENTRY_1m; 1767 entry_dw = soc_mem_entry_words(unit, mem); 1768 entry_sz = entry_dw * sizeof(uint32); 1769 index_min = soc_mem_index_min(unit, mem); 1770 index_max = soc_mem_index_max(unit, mem); 1771 table_chnk_sz = chunk_size * entry_sz; 1772 1773 buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_tmp"); 1774 1775 if (buf == NULL) { 1776 soc_cm_sfree(unit, ptm_buf); 1777 soc_cm_sfree(unit, vvm_buf); 1778 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1779 LOG_ERROR(BSL_LS_SOC_L2, 1780 (BSL_META_U(unit, 1781 "soc_tr3_l2_entry_limit_count_update: " 1782 "Memory allocation failed for %s\n"), 1783 SOC_MEM_NAME(unit, mem))); 1784 return SOC_E_MEMORY; 1785 } 1786 1787 for (chnk_idx = index_min; chnk_idx <= index_max; 1788 chnk_idx += chunk_size) { 1789 1790 sal_memset(buf, 0, table_chnk_sz); 1791 1792 chnk_idx_max = ((chnk_idx + chunk_size) <= index_max) ? 1793 (chnk_idx + chunk_size - 1) : index_max; 1794 1795 /* DMA L2 Table */ 1796 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, chnk_idx, 1797 chnk_idx_max, buf); 1798 if (rv < 0) { 1799 soc_cm_sfree(unit, buf); 1800 soc_cm_sfree(unit, ptm_buf); 1801 soc_cm_sfree(unit, vvm_buf); 1802 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1803 LOG_ERROR(BSL_LS_SOC_L2, 1804 (BSL_META_U(unit, 1805 "DMA failed: %s, mac limts not synced!\n"), 1806 soc_errmsg(rv))); 1807 return SOC_E_FAIL; 1808 } 1809 1810 /* Iter through all l2 entries in the chunk */ 1811 for (idx = 0; idx <= (chnk_idx_max - chnk_idx); idx++) { 1812 l2 = (buf + (idx * entry_dw)); 1813 1814 /* check if entry is valid */ 1815 is_free = soc_mem_field32_get(unit, mem, l2, FREEf); 1816 if (is_free) { 1817 /* not valid entry skip it */ 1818 continue; 1819 } 1820 1821 /* check if entry is limit counted */ 1822 if (soc_mem_field_valid(unit, mem, LIMIT_COUNTEDf)) { 1823 is_limit_counted = soc_mem_field32_get(unit,mem, l2, 1824 LIMIT_COUNTEDf); 1825 if (!is_limit_counted) { 1826 /* entry not limit counted skip it */ 1827 continue; 1828 } 1829 } 1830 1831 /* 1832 * Get the key type of the entries 1833 * Process entries with only key_types 1834 * 1. SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE 1835 * 2. SOC_MEM_KEY_L2_ENTRY_1_L2_VFI 1836 */ 1837 key_type = soc_mem_field32_get(unit, mem, l2, KEY_TYPEf); 1838 1839 if ((key_type != SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE) && 1840 (key_type != SOC_MEM_KEY_L2_ENTRY_1_L2_VFI)) { 1841 continue; 1842 } 1843 1844 dest_type = soc_mem_field32_get(unit, mem, l2, DEST_TYPEf); 1845 1846 switch (dest_type) { 1847 case 0: /* mod port */ 1848 rv = soc_mem_read(unit, PORT_TABm, 1849 MEM_BLOCK_ANY, 0, 1850 &entry); 1851 if (SOC_FAILURE(rv)) { 1852 soc_cm_sfree(unit, buf); 1853 soc_cm_sfree(unit, ptm_buf); 1854 soc_cm_sfree(unit, vvm_buf); 1855 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1856 return rv; 1857 } 1858 if (soc_mem_field32_get(unit, PORT_TABm, 1859 &entry, MY_MODIDf) == 1860 soc_mem_field32_get(unit, mem, l2, MODULE_IDf)) { 1861 p_index = soc_mem_field32_get(unit, mem, 1862 l2, PORT_NUMf) + 1863 soc_mem_index_count(unit, TRUNK_GROUPm) ; 1864 } 1865 break; 1866 case 1: /* trunk */ 1867 p_index = soc_mem_field32_get(unit, mem, 1868 l2, TGIDf); 1869 break; 1870 default: 1871 /* if VFI based key then break else continue? */ 1872 break; 1873 } 1874 1875 /* 1876 * based on key_type get vlan or vfi 1877 * to index into VLAN_OR_VFI_MAC_COUNTm 1878 */ 1879 if (key_type == SOC_MEM_KEY_L2_ENTRY_1_L2_BRIDGE) { 1880 v_index = soc_mem_field32_get(unit, mem, l2, VLAN_IDf); 1881 } else { 1882 v_index = soc_mem_field32_get(unit, mem, l2, VFIf) + 1883 soc_mem_index_count(unit, VLAN_TABm); 1884 } 1885 1886 1887 /* 1888 * read and update vlan or vfi mac count 1889 * in buffer also update the sys mac count. 1890 */ 1891 v_count = 0; 1892 if (v_index >= 0) { 1893 v_entry = (vvm_buf + (v_index * vvm_entry_dw)); 1894 v_count = soc_mem_field32_get(unit, VLAN_OR_VFI_MAC_COUNTm, 1895 v_entry, COUNTf); 1896 s_count++; 1897 v_count++; 1898 soc_mem_field32_set(unit, VLAN_OR_VFI_MAC_COUNTm, 1899 v_entry, COUNTf, v_count); 1900 } 1901 1902 /* 1903 * read and update port or trunk mac count 1904 * in buffer. 1905 */ 1906 p_count = 0; 1907 if (p_index >= 0) { 1908 p_entry = ptm_buf + (p_index * ptm_entry_dw); 1909 p_count = soc_mem_field32_get(unit, 1910 PORT_OR_TRUNK_MAC_COUNTm, 1911 p_entry, COUNTf); 1912 p_count++; 1913 soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm, 1914 p_entry, COUNTf, p_count); 1915 } 1916 1917 } /* End for index */ 1918 } /* End for chnk_idx */ 1919 1920 /* Free memory */ 1921 soc_cm_sfree(unit, buf); 1922 1923 /* Create a copy EXT_L2_ENTRY_2m table for calculating mac count */ 1924 mem = EXT_L2_ENTRY_2m; 1925 entry_dw = soc_mem_entry_words(unit, mem); 1926 entry_sz = entry_dw * sizeof(uint32); 1927 index_min = soc_mem_index_min(unit, mem); 1928 index_max = soc_mem_index_max(unit, mem); 1929 table_chnk_sz = chunk_size * entry_sz; 1930 1931 buf = soc_cm_salloc(unit, table_chnk_sz, "l2x_tmp"); 1932 1933 if (buf == NULL) { 1934 soc_cm_sfree(unit, ptm_buf); 1935 soc_cm_sfree(unit, vvm_buf); 1936 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1937 LOG_ERROR(BSL_LS_SOC_L2, 1938 (BSL_META_U(unit, 1939 "soc_tr3_l2_entry_limit_count_update: " 1940 "Memory allocation failed for %s\n"), 1941 SOC_MEM_NAME(unit, mem))); 1942 return SOC_E_MEMORY; 1943 } 1944 1945 for (chnk_idx = index_min; chnk_idx <= index_max; chnk_idx += chunk_size) { 1946 1947 sal_memset(buf, 0, table_chnk_sz); 1948 1949 chnk_idx_max = ((chnk_idx + chunk_size) <= index_max) ? 1950 (chnk_idx + chunk_size - 1) : index_max; 1951 1952 /* DMA L2 Table */ 1953 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, chnk_idx, 1954 chnk_idx_max, buf); 1955 if (rv < 0) { 1956 soc_cm_sfree(unit, buf); 1957 soc_cm_sfree(unit, ptm_buf); 1958 soc_cm_sfree(unit, vvm_buf); 1959 _SOC_ALL_L2X_MEM_UNLOCK(unit); 1960 LOG_ERROR(BSL_LS_SOC_L2, 1961 (BSL_META_U(unit, 1962 "DMA failed: %s, mac limts not synced!\n"), 1963 soc_errmsg(rv))); 1964 return SOC_E_FAIL; 1965 } 1966 1967 /* Iter through all l2 entries in the chunk */ 1968 for (idx = 0; idx <= (chnk_idx_max - chnk_idx); idx++) { 1969 l2 = (buf + (idx * entry_dw)); 1970 1971 /* check if entry is valid */ 1972 is_free = soc_mem_field32_get(unit, mem, l2, FREEf); 1973 if (is_free) { 1974 /* not valid entry skip it */ 1975 continue; 1976 } 1977 1978 /* check if entry is limit counted */ 1979 if (soc_mem_field_valid(unit, mem, LIMIT_COUNTEDf)) { 1980 is_limit_counted = soc_mem_field32_get(unit,mem, l2, 1981 LIMIT_COUNTEDf); 1982 if (!is_limit_counted) { 1983 /* entry not limit counted skip it */ 1984 continue; 1985 } 1986 } 1987 1988 /* 1989 * Get the key type of the entries 1990 * Process entries with only key_types 1991 * 1. SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE 1992 * 2. SOC_MEM_KEY_L2_ENTRY_2_L2_VFI 1993 */ 1994 key_type = soc_mem_field32_get(unit, mem, l2, KEY_TYPEf); 1995 1996 if ((key_type != SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) && 1997 (key_type != SOC_MEM_KEY_L2_ENTRY_2_L2_VFI)) { 1998 continue; 1999 } 2000 2001 dest_type = soc_mem_field32_get(unit, mem, l2, DEST_TYPEf); 2002 2003 switch (dest_type) { 2004 case 0: /* mod port */ 2005 rv = soc_mem_read(unit, PORT_TABm, 2006 MEM_BLOCK_ANY, 0, 2007 &entry); 2008 if (SOC_FAILURE(rv)) { 2009 soc_cm_sfree(unit, buf); 2010 soc_cm_sfree(unit, ptm_buf); 2011 soc_cm_sfree(unit, vvm_buf); 2012 _SOC_ALL_L2X_MEM_UNLOCK(unit); 2013 return rv; 2014 } 2015 if (soc_mem_field32_get(unit, PORT_TABm, 2016 &entry, MY_MODIDf) == 2017 soc_mem_field32_get(unit, mem, l2, MODULE_IDf)) { 2018 p_index = soc_mem_field32_get(unit, mem, 2019 l2, PORT_NUMf) + 2020 soc_mem_index_count(unit, TRUNK_GROUPm) ; 2021 } 2022 break; 2023 case 1: /* trunk */ 2024 p_index = soc_mem_field32_get(unit, mem, 2025 l2, TGIDf); 2026 break; 2027 default: 2028 /* if VFI based key then break else continue? */ 2029 break; 2030 } 2031 2032 /* 2033 * based on key_type get vlan or vfi 2034 * to index into VLAN_OR_VFI_MAC_COUNTm 2035 */ 2036 if (key_type == SOC_MEM_KEY_L2_ENTRY_2_L2_BRIDGE) { 2037 v_index = soc_mem_field32_get(unit, mem, l2, VLAN_IDf); 2038 } else { 2039 v_index = soc_mem_field32_get(unit, mem, l2, VFIf) + 2040 soc_mem_index_count(unit, VLAN_TABm); 2041 } 2042 2043 2044 /* 2045 * read and update vlan or vfi mac count 2046 * in buffer also update the sys mac count. 2047 */ 2048 v_count = 0; 2049 if (v_index >= 0) { 2050 v_entry = (vvm_buf + (v_index * vvm_entry_dw)); 2051 v_count = soc_mem_field32_get(unit, VLAN_OR_VFI_MAC_COUNTm, 2052 v_entry, COUNTf); 2053 s_count++; 2054 v_count++; 2055 soc_mem_field32_set(unit, VLAN_OR_VFI_MAC_COUNTm, 2056 v_entry, COUNTf, v_count); 2057 } 2058 2059 /* 2060 * read and update port or trunk mac count 2061 * in buffer. 2062 */ 2063 p_count = 0; 2064 if (p_index >= 0) { 2065 p_entry = ptm_buf + (p_index * ptm_entry_dw); 2066 p_count = soc_mem_field32_get(unit, 2067 PORT_OR_TRUNK_MAC_COUNTm, 2068 p_entry, COUNTf); 2069 p_count++; 2070 soc_mem_field32_set(unit, PORT_OR_TRUNK_MAC_COUNTm, 2071 p_entry, COUNTf, p_count); 2072 } 2073 2074 } /* End for index */ 2075 } /* End for chnk_idx */ 2076 } /* End if soc_feature_esm_support */ 2077 2078 /* Write the tables to hardware */ 2079 /* coverity[stack_use_overflow] */ 2080 rv = soc_mem_write_range(unit, PORT_OR_TRUNK_MAC_COUNTm, MEM_BLOCK_ANY, 2081 ptm_index_min, ptm_index_max, (void *)ptm_buf); 2082 2083 if (rv < 0) { 2084 soc_cm_sfree(unit, buf); 2085 soc_cm_sfree(unit, ptm_buf); 2086 soc_cm_sfree(unit, vvm_buf); 2087 _SOC_ALL_L2X_MEM_UNLOCK(unit); 2088 LOG_ERROR(BSL_LS_SOC_L2, 2089 (BSL_META_U(unit, 2090 "PORT_OR_TRUNK_MAC_COUNT write failed: " 2091 "%s, mac limts not synced!\n"), 2092 soc_errmsg(rv))); 2093 return SOC_E_FAIL; 2094 } 2095 2096 rv = soc_mem_write_range(unit, VLAN_OR_VFI_MAC_COUNTm, MEM_BLOCK_ANY, 2097 vvm_index_min, vvm_index_max, (void *)vvm_buf); 2098 2099 if (rv < 0) { 2100 soc_cm_sfree(unit, buf); 2101 soc_cm_sfree(unit, ptm_buf); 2102 soc_cm_sfree(unit, vvm_buf); 2103 _SOC_ALL_L2X_MEM_UNLOCK(unit); 2104 LOG_ERROR(BSL_LS_SOC_L2, 2105 (BSL_META_U(unit, 2106 "VLAN_OR_VFI_MAC_COUNT write failed: " 2107 "%s, mac limts not synced!\n"), 2108 soc_errmsg(rv))); 2109 return SOC_E_FAIL; 2110 } 2111 2112 /* Update system count */ 2113 soc_reg_field_set(unit, SYS_MAC_COUNTr, &rval, COUNTf, s_count); 2114 rv = WRITE_SYS_MAC_COUNTr(unit, rval); 2115 2116 /* Free memory */ 2117 soc_cm_sfree(unit, buf); 2118 soc_cm_sfree(unit, ptm_buf); 2119 soc_cm_sfree(unit, vvm_buf); 2120 2121 _SOC_ALL_L2X_MEM_UNLOCK(unit); 2122 return rv; 2123 } 2124 2125 #endif /* BCM_XGS_SWITCH_SUPPORT */