l2x.c (88737B)
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 L2 Table Manipulation API routines. 8 * 9 * The L2Xm pseudo-table is an aggregate structure supported by 10 * hardware. When an entry is read from it, it is constructed from the 11 * L2X_BASEm, L2X_VALIDm, L2X_HITm, and L2X_STATICm tables. 12 * NOTE: The L2X pseudo-table is read-only. 13 * 14 * A low-level L2 shadow table is optionally kept in soc->arlShadow by 15 * using a callback to get all inserts/deletes from the l2xmsg task. It 16 * can be disabled by setting the l2xmsg_avl property to 0. 17 */ 18 19 #include <shared/bsl.h> 20 21 #include <sal/core/libc.h> 22 #include <shared/bsl.h> 23 #include <soc/drv.h> 24 #include <soc/l2x.h> 25 #include <soc/ptable.h> 26 #include <soc/debug.h> 27 #include <soc/util.h> 28 #include <soc/mem.h> 29 #include <soc/tucana.h> 30 #ifdef BCM_TRIUMPH3_SUPPORT 31 #include <soc/triumph3.h> 32 #endif 33 #ifdef BCM_KATANA2_SUPPORT 34 #include <bcm_int/esw/katana2.h> 35 #endif 36 #ifdef BCM_TRIUMPH3_SUPPORT 37 #include <soc/tomahawk3.h> 38 #endif 39 40 #define DEFAULT_L2DELETE_CHUNKS (64) /* 16k entries / 64 = 256 */ 41 42 #ifdef BCM_XGS_SWITCH_SUPPORT 43 44 /* 45 * While the L2 table is frozen, the L2Xm lock is held. 46 * 47 * All tasks must obtain the L2Xm lock before modifying the CML bits or 48 * age timer registers. 49 */ 50 51 typedef struct l2_freeze_s { 52 int frozen; 53 int save_age_sec; 54 int save_age_ena; 55 int new_age_set; 56 int hw_frozen; 57 } l2_freeze_t; 58 59 typedef struct cml_freeze_s { 60 int frozen; 61 int *save_cml; 62 int *save_cml_move; 63 int *save_vp_cml; 64 int *save_vp_cml_move; 65 SHR_BITDCL *vp_bitmap; /* Managed in BCM layer */ 66 #ifdef BCM_TRIDENT2_SUPPORT 67 sal_mutex_t cml_freeze_mutex; 68 #endif 69 #ifdef BCM_TRIDENT3_SUPPORT 70 soc_l2x_cml_cb_fn cml_func; /*callback function to set lport_tab in TD3*/ 71 #endif 72 } cml_freeze_t; 73 74 l2_freeze_t l2_freeze_state[SOC_MAX_NUM_DEVICES]; 75 cml_freeze_t cml_freeze_state[SOC_MAX_NUM_DEVICES]; 76 static int l2_freeze_mode[SOC_MAX_NUM_DEVICES]; 77 78 #ifdef BCM_TRIDENT2_SUPPORT 79 #define SOC_CML_FREEZE_LOCK(unit) \ 80 sal_mutex_take(cml_freeze_state[unit].cml_freeze_mutex, sal_mutex_FOREVER) 81 82 #define SOC_CML_FREEZE_UNLOCK(unit) \ 83 sal_mutex_give(cml_freeze_state[unit].cml_freeze_mutex) 84 #endif 85 86 #ifdef PLISIM 87 #ifdef _KATANA_DEBUG /* BCM_KATANA_SUPPORT */ 88 STATIC uint32 port_age_enable=FALSE; 89 STATIC uint32 port_age_flags=0; 90 STATIC _bcm_l2_replace_t *port_age_rep_st=NULL; 91 #define SOC_L2X_TGID_TRUNK_INDICATOR(unit) \ 92 SOC_IS_RAVEN(unit) ? 0x40 : 0x20 93 #define SOC_L2X_TGID_PORT_TRUNK_MASK 0x1f 94 #define SOC_L2X_TGID_PORT_TRUNK_MASK_HI 0x60 95 #endif 96 #endif 97 98 /* 99 * Function: 100 * soc_l2x_entry_compare_key 101 * Purpose: 102 * Comparison function for AVL shadow table operations. Compares 103 * key portion of entry only. 104 * Parameters: 105 * user_data - used to pass StrataSwitch unit # 106 * datum1 - first L2X entry to compare 107 * datum2 - second L2X entry to compare 108 * Returns: 109 * datum1 <=> datum2 110 */ 111 112 int 113 soc_l2x_entry_compare_key(void *user_data, 114 shr_avl_datum_t *datum1, 115 shr_avl_datum_t *datum2) 116 { 117 int unit = PTR_TO_INT(user_data); 118 119 return soc_mem_compare_key(unit, L2Xm, datum1, datum2); 120 } 121 122 /* 123 * Function: 124 * soc_l2x_entry_compare_all 125 * Purpose: 126 * Comparison function for AVL shadow table operations. Compares 127 * entire key+data of entry, but key is still most significant. 128 * Parameters: 129 * user_data - used to pass StrataSwitch unit # 130 * datum1 - first L2X entry to compare 131 * datum2 - second L2X entry to compare 132 * Returns: 133 * datum1 <=> datum2 134 */ 135 136 int 137 soc_l2x_entry_compare_all(void *user_data, 138 shr_avl_datum_t *datum1, 139 shr_avl_datum_t *datum2) 140 { 141 int unit = PTR_TO_INT(user_data); 142 int i; 143 144 i = soc_mem_compare_key(unit, L2Xm, datum1, datum2); 145 146 if (i == 0) { 147 i = sal_memcmp(datum1, datum2, sizeof (l2x_entry_t)); 148 } 149 150 return i; 151 } 152 153 /* 154 * Function: 155 * soc_l2x_entry_dump 156 * Purpose: 157 * Debug dump function for AVL shadow table operations. 158 * Parameters: 159 * user_data - used to pass StrataSwitch unit # 160 * datum - L2X entry to dump 161 * extra_data - unused 162 * Returns: 163 * SOC_E_XXX 164 */ 165 166 int 167 soc_l2x_entry_dump(void *user_data, shr_avl_datum_t *datum, void *extra_data) 168 { 169 int unit = PTR_TO_INT(user_data); 170 171 COMPILER_REFERENCE(extra_data); 172 173 soc_mem_entry_dump(unit, L2Xm, (l2x_entry_t *) datum, BSL_LSS_CLI); 174 LOG_CLI((BSL_META_U(unit, 175 "\n"))); 176 177 return SOC_E_NONE; 178 } 179 180 /* 181 * Function: 182 * soc_l2x_shadow_callback 183 * Purpose: 184 * Internal callback routine for updating an AVL tree shadow table 185 * Parameters: 186 * unit - StrataSwitch unit number. 187 * entry_del - Entry to be deleted or updated, NULL if none. 188 * entry_add - Entry to be inserted or updated, NULL if none. 189 * fn_data - unused. 190 * Notes: 191 * Used only if L2X shadow table is enabled. 192 */ 193 194 STATIC void 195 soc_l2x_shadow_callback(int unit, 196 int flags, 197 l2x_entry_t *entry_del, 198 l2x_entry_t *entry_add, 199 void *fn_data) 200 { 201 soc_control_t *soc = SOC_CONTROL(unit); 202 203 if (flags & (SOC_L2X_ENTRY_DUMMY | SOC_L2X_ENTRY_NO_ACTION | 204 SOC_L2X_ENTRY_OVERFLOW)) { 205 return; 206 } 207 208 sal_mutex_take(soc->arlShadowMutex, sal_mutex_FOREVER); 209 210 if (entry_del != NULL) { 211 shr_avl_delete(soc->arlShadow, soc_l2x_entry_compare_key, 212 (shr_avl_datum_t *)entry_del); 213 } 214 215 if (entry_add != NULL) { 216 shr_avl_insert(soc->arlShadow, soc_l2x_entry_compare_key, 217 (shr_avl_datum_t *)entry_add); 218 } 219 220 sal_mutex_give(soc->arlShadowMutex); 221 } 222 223 /* 224 * Function: 225 * _soc_l2x_cml_struct_free 226 * Purpose: 227 * Frees cml_freeze_state structure for a given unit 228 * Parameters: 229 * unit - StrataSwitch unit number. 230 * Returns: 231 * NONE 232 */ 233 234 void 235 _soc_l2x_cml_struct_free(int unit) 236 { 237 if (NULL != cml_freeze_state[unit].save_cml) { 238 sal_free(cml_freeze_state[unit].save_cml); 239 cml_freeze_state[unit].save_cml = NULL; 240 } 241 if (NULL != cml_freeze_state[unit].save_cml_move) { 242 sal_free(cml_freeze_state[unit].save_cml_move); 243 cml_freeze_state[unit].save_cml_move = NULL; 244 } 245 if (NULL != cml_freeze_state[unit].save_vp_cml) { 246 sal_free(cml_freeze_state[unit].save_vp_cml); 247 cml_freeze_state[unit].save_vp_cml = NULL; 248 } 249 if (NULL != cml_freeze_state[unit].save_vp_cml_move) { 250 sal_free(cml_freeze_state[unit].save_vp_cml_move); 251 cml_freeze_state[unit].save_vp_cml_move = NULL; 252 } 253 254 /* We DO NOT free the vp_bitmap here because it is a copy 255 * of a BCM-layer pointer for SOC reference. 256 * We do mark it NULL for safety. 257 */ 258 cml_freeze_state[unit].vp_bitmap = NULL; 259 #ifdef BCM_TRIDENT3_SUPPORT 260 if (SOC_IS_TRIDENT3X(unit)) { 261 cml_freeze_state[unit].cml_func = NULL; 262 } 263 #endif 264 265 #ifdef BCM_TRIDENT2_SUPPORT 266 if (SOC_IS_TD2_TT2(unit)) { 267 if (cml_freeze_state[unit].cml_freeze_mutex != NULL) { 268 sal_mutex_destroy(cml_freeze_state[unit].cml_freeze_mutex); 269 cml_freeze_state[unit].cml_freeze_mutex = NULL; 270 } 271 } 272 #endif 273 return; 274 } 275 276 /* 277 * Function: 278 * _soc_l2x_cml_struct_alloc 279 * Purpose: 280 * Allocates cml_freeze_state structure for a given unit 281 * Parameters: 282 * unit - StrataSwitch unit number. 283 * Returns: 284 * SOC_E_NONE - Allocated succesfully 285 * SOC_E_MEMORY - Allocation failed 286 */ 287 288 int 289 _soc_l2x_cml_struct_alloc(int unit) 290 { 291 int cml_alloc_size, num_ports = 0; 292 if (soc_feature(unit, soc_feature_linkphy_coe) || 293 soc_feature(unit, soc_feature_subtag_coe)) { 294 num_ports = (SOC_MAX_NUM_PP_PORTS > SOC_MAX_NUM_PORTS) ? 295 SOC_MAX_NUM_PP_PORTS : SOC_MAX_NUM_PORTS; 296 } else { 297 num_ports = SOC_MAX_NUM_PORTS; 298 } 299 300 cml_alloc_size = sizeof(int) * num_ports; 301 302 cml_freeze_state[unit].save_cml = (int *)sal_alloc(cml_alloc_size, "CML"); 303 if (NULL == cml_freeze_state[unit].save_cml) { 304 goto e_memory; 305 } 306 sal_memset(cml_freeze_state[unit].save_cml, 0, cml_alloc_size); 307 308 cml_freeze_state[unit].save_cml_move = 309 (int *)sal_alloc(cml_alloc_size, "CML MOVE"); 310 if (NULL == cml_freeze_state[unit].save_cml_move) { 311 goto e_memory; 312 } 313 sal_memset(cml_freeze_state[unit].save_cml_move, 0, cml_alloc_size); 314 315 if (SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 316 cml_alloc_size = sizeof(int) * soc_mem_index_count(unit,SOURCE_VPm); 317 cml_freeze_state[unit].save_vp_cml = 318 (int *)sal_alloc(cml_alloc_size, "VP CML"); 319 if (NULL == cml_freeze_state[unit].save_vp_cml) { 320 goto e_memory; 321 } 322 sal_memset(cml_freeze_state[unit].save_vp_cml, 0, cml_alloc_size); 323 324 cml_freeze_state[unit].save_vp_cml_move = 325 (int *)sal_alloc(cml_alloc_size, "VP CML MOVE"); 326 if (NULL == cml_freeze_state[unit].save_vp_cml_move) { 327 goto e_memory; 328 } 329 sal_memset(cml_freeze_state[unit].save_vp_cml_move, 0, cml_alloc_size); 330 } 331 /* We DO NOT initialize the vp_bitmap here because it is a copy 332 * of a BCM-layer pointer for SOC reference. 333 * We do mark it NULL for safety until the BCM layer passes 334 * a valid pointer. 335 */ 336 cml_freeze_state[unit].vp_bitmap = NULL; 337 #ifdef BCM_TRIDENT3_SUPPORT 338 if (SOC_IS_TRIDENT3X(unit)) { 339 cml_freeze_state[unit].cml_func = NULL; 340 } 341 #endif/*BCM_TRIDENT3_SUPPORT*/ 342 343 #ifdef BCM_TRIDENT2_SUPPORT 344 if (SOC_IS_TD2_TT2(unit)) { 345 if ((cml_freeze_state[unit].cml_freeze_mutex = 346 sal_mutex_create("soc_cml_freeze_lock")) == NULL) { 347 return (SOC_E_MEMORY); 348 } 349 } 350 #endif 351 return SOC_E_NONE; 352 353 e_memory: 354 _soc_l2x_cml_struct_free(unit); 355 356 return SOC_E_MEMORY; 357 358 } 359 360 /* 361 * Function: 362 * soc_l2x_cml_vp_bitmap_set 363 * Purpose: 364 * Record pointer to the in-use virtual port bitmap managed by 365 * the BCM layer. 366 * Parameters: 367 * unit - StrataSwitch unit number. 368 * vp_bitmap - pointer to BCM-layer VP use bitmap. 369 * Returns: 370 * Nothing 371 */ 372 373 void 374 soc_l2x_cml_vp_bitmap_set(int unit, SHR_BITDCL *vp_bitmap) 375 { 376 #if defined(BCM_TOMAHAWK3_SUPPORT) 377 /* On Tomahawk3, do not store the bitmap since VP memory is not supported */ 378 if (SOC_IS_TOMAHAWK3(unit)) { 379 return; 380 } else 381 #endif /* BCM_TOMAHAWK3_SUPPORT */ 382 { 383 cml_freeze_state[unit].vp_bitmap = vp_bitmap; 384 } 385 } 386 387 /* 388 * Function: 389 * soc_l2x_attach 390 * Purpose: 391 * Allocate L2X subsystem resources 392 * Parameters: 393 * unit - StrataSwitch unit number. 394 * Returns: 395 * SOC_E_XXX 396 * Notes: 397 * The L2X tree shadow table is optional and its allocation 398 * is controlled using a property. 399 */ 400 401 int 402 soc_l2x_attach(int unit) 403 { 404 soc_control_t *soc = SOC_CONTROL(unit); 405 406 soc->l2x_age_timeout = soc_property_get(unit, spn_ARL_CLEAN_TIMEOUT_USEC, 407 15000000); 408 soc->l2x_mode = soc_l2x_mode_cfg_get(unit); 409 410 #ifdef BCM_TRIUMPH3_SUPPORT 411 if (SOC_IS_TRIUMPH3(unit)) { 412 return soc_tr3_l2_attach(unit); 413 } 414 #endif 415 416 #ifdef BCM_TOMAHAWK3_SUPPORT 417 if (SOC_IS_TOMAHAWK3(unit)) { 418 /* FIFO mode is not supported, since h/w to support it does not exist 419 * on TH3. So this property setting is ignored 420 */ 421 soc->l2x_mode = L2MODE_POLL; 422 return soc_th3_l2x_attach(unit); 423 } 424 #endif 425 426 (void)soc_l2x_detach(unit); 427 428 if (soc_property_get(unit, spn_L2XMSG_AVL, TRUE)) { 429 int datum_bytes, datum_max; 430 431 datum_bytes = sizeof (l2x_entry_t); 432 datum_max = soc_mem_index_count(unit, L2Xm); 433 434 if (shr_avl_create(&soc->arlShadow, 435 INT_TO_PTR(unit), 436 datum_bytes, 437 datum_max) < 0) { 438 return SOC_E_MEMORY; 439 } 440 441 if ((soc->arlShadowMutex = sal_mutex_create("asMutex")) == NULL) { 442 (void)soc_l2x_detach(unit); 443 return SOC_E_MEMORY; 444 } 445 446 soc_l2x_register(unit, soc_l2x_shadow_callback, NULL); 447 } 448 449 /* Reset l2 freeze structure. */ 450 sal_memset(l2_freeze_state + unit, 0, sizeof(l2_freeze_t)); 451 452 /* Allocate cml freeze structure */ 453 return _soc_l2x_cml_struct_alloc(unit); 454 } 455 456 /* 457 * Function: 458 * soc_l2x_detach 459 * Purpose: 460 * Deallocate L2X subsystem resources 461 * Parameters: 462 * unit - StrataSwitch unit number. 463 * Returns: 464 * SOC_E_XXX 465 */ 466 467 int 468 soc_l2x_detach(int unit) 469 { 470 soc_control_t *soc = SOC_CONTROL(unit); 471 472 #ifdef BCM_TRIUMPH3_SUPPORT 473 if (SOC_IS_TRIUMPH3(unit)) { 474 return soc_tr3_l2_detach(unit); 475 } 476 #endif 477 478 #ifdef BCM_TOMAHAWK3_SUPPORT 479 if (SOC_IS_TOMAHAWK3(unit)) { 480 return soc_th3_l2x_detach(unit); 481 } 482 #endif 483 484 soc_l2x_unregister(unit, soc_l2x_shadow_callback, NULL); 485 486 /* Free cml_freeze structure */ 487 _soc_l2x_cml_struct_free(unit); 488 489 if (soc->arlShadow != NULL) { 490 shr_avl_destroy(soc->arlShadow); 491 soc->arlShadow = NULL; 492 } 493 494 if (soc->arlShadowMutex != NULL) { 495 sal_mutex_destroy(soc->arlShadowMutex); 496 soc->arlShadowMutex = NULL; 497 } 498 499 return SOC_E_NONE; 500 } 501 502 /* 503 * Function: 504 * soc_l2x_init 505 * Purpose: 506 * Initialize L2 table subsystem. 507 * Parameters: 508 * unit - StrataSwitch unit number. 509 * Returns: 510 * SOC_E_xxx 511 * Notes: 512 * This routine must not do anything time consuming since it is 513 * called by soc_init(). 514 */ 515 516 int 517 soc_l2x_init(int unit) 518 { 519 /* The L2 table is cleared in soc_misc_init(). */ 520 return SOC_E_NONE; 521 } 522 523 #if defined(BCM_XGS12_SWITCH_SUPPORT) 524 /* 525 * Function: 526 * soc_l2x_lookup 527 * Purpose: 528 * Send an L2 lookup message over the S-Channel and receive the 529 * response. 530 * Parameters: 531 * unit - StrataSwitch unit # 532 * key - L2X entry to look up; only MAC+VLAN fields are relevant 533 * result - L2X entry to receive entire found entry 534 * index_ptr (OUT) - If found, receives table index where found 535 * Returns: 536 * SOC_E_INTERNAL if retries exceeded or other internal error 537 * SOC_E_NOT_FOUND if the entry is not found. 538 * SOC_E_NONE (0) on success (entry found): 539 * Notes: 540 * The S-Channel response contains either a matching L2 entry, 541 * or an entry with a key of all f's if not found. It is okay 542 * if the result pointer is the same as the key pointer. 543 * Retries the lookup in cases where the particular chip requires it. 544 */ 545 546 int 547 soc_l2x_lookup(int unit, 548 l2x_entry_t *key, l2x_entry_t *result, 549 int *index_ptr) 550 { 551 schan_msg_t schan_msg; 552 int src_blk; 553 int opcode; 554 555 schan_msg_clear(&schan_msg); 556 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 557 soc_schan_header_cmd_set(unit, &schan_msg.header, ARL_LOOKUP_CMD_MSG, 558 0, src_blk, 0, 8, 0, 0); 559 schan_msg.arllkup.address = soc_mem_addr(unit, L2Xm, 0, ARL_BLOCK(unit), 0); 560 561 /* Fill in packet data */ 562 563 sal_memcpy(schan_msg.arllkup.data, key, sizeof (schan_msg.arllkup.data)); 564 565 /* 566 * Write onto S-Channel "ARL lookup" command packet consisting of 567 * header word + address + two words of ARL key, and read back header 568 * word + 2 words of a special lookup result format. 569 */ 570 571 SOC_IF_ERROR_RETURN(soc_schan_op(unit, &schan_msg, 4, 3, 1)); 572 573 /* Check result */ 574 soc_schan_header_status_get(unit, &schan_msg.header, &opcode, NULL, NULL, 575 NULL, NULL, NULL); 576 if (opcode != READ_MEMORY_ACK_MSG) { 577 LOG_ERROR(BSL_LS_SOC_L2, 578 (BSL_META_U(unit, 579 "soc_l2x_lookup: " 580 "invalid S-Channel reply, expected READ_MEMORY_ACK:\n"))); 581 soc_schan_dump(unit, &schan_msg, 3); 582 return SOC_E_INTERNAL; 583 } 584 585 /* 586 * Fill in result entry from read data. 587 * Note that the lookup does not return the key, so it must be copied. 588 * 589 * Format of S-Channel response: 590 * readresp.header : Memory Read Ack S-channel header 591 * readresp.data[0]: { 4'h0, hit, static, l2_table_data } 592 * readresp.data[1]: { 18'h0, index_into_L2_table[13:0] } 593 */ 594 595 if (schan_msg.readresp.data[0] == 0xffffffff && 596 schan_msg.readresp.data[1] == 0xffffffff) { 597 *index_ptr = -1; 598 return SOC_E_NOT_FOUND; 599 } 600 601 /* MACADDR<31:0> */ 602 result->entry_data[0] = key->entry_data[0]; 603 604 /* CPU, COS<2:0>, VLAN<12:0>, MACADDR<47:32> */ 605 result->entry_data[1] = ((schan_msg.readresp.data[0] << 28) | 606 (key->entry_data[1] & 0x0fffffff)); 607 608 /* ZERO<6:0>, VALID=1, HIT, STATIC .. DST_DISCARD */ 609 result->entry_data[2] = schan_msg.readresp.data[0] >> 4; 610 result->entry_data[2] |= 1 << (88-64); 611 612 *index_ptr = schan_msg.readresp.data[1]; 613 614 if (bsl_check(bslLayerSoc, bslSourceSocmem, bslSeverityNormal, unit)) { 615 LOG_INFO(BSL_LS_SOC_SOCMEM, 616 (BSL_META_U(unit, 617 "L2 entry lookup: "))); 618 soc_mem_entry_dump(unit, L2Xm, result, BSL_INFO|BSL_LS_SOC_SOCMEM); 619 LOG_INFO(BSL_LS_SOC_SOCMEM, 620 (BSL_META_U(unit, 621 " (index=%d)\n"), *index_ptr)); 622 } 623 624 return SOC_E_NONE; 625 } 626 627 /* 628 * Function: 629 * _soc_l2x_hit_clear 630 * Purpose: 631 * Clear the hit bit on a specified L2 entry. 632 * Parameters: 633 * unit - StrataSwitch PCI device unit number 634 * entry - Entry to operate on 635 * Returns: 636 * SOC_E_NONE - success 637 * SOC_E_NOT_FOUND - no such address 638 * SOC_E_XXX - other 639 * Notes: 640 * The proper way to clear hit bits is to use soc_l2x_insert() 641 * with the hit bit clear. This is just a helper routine for 642 * a 5690 problem. 643 * 644 * 5690 cannot clear hit bits atomically, hence there is a race 645 * condition where if other hit bit(s) got set in the same bucket 646 * between our read and write operations, they could also be 647 * cleared. 648 */ 649 650 int 651 _soc_l2x_hit_clear(int unit, l2x_entry_t *entry) 652 { 653 l2x_entry_t result; 654 l2x_hit_entry_t hit_bits; 655 int index, bucket, bit, r; 656 657 if ((r = soc_l2x_lookup(unit, entry, &result, &index)) < 0) { 658 return r; 659 } 660 661 bucket = index / SOC_L2X_BUCKET_SIZE; 662 bit = index % SOC_L2X_BUCKET_SIZE; 663 664 /* Read/modify/write bucket hit bits */ 665 666 soc_mem_lock(unit, L2X_HITm); 667 668 if ((r = soc_mem_read(unit, L2X_HITm, MEM_BLOCK_ANY, 669 bucket, &hit_bits)) < 0) { 670 soc_mem_unlock(unit, L2X_HITm); 671 return r; 672 } 673 674 hit_bits.entry_data[0] &= ~(1 << bit); 675 676 if ((r = soc_mem_write(unit, L2X_HITm, MEM_BLOCK_ANY, 677 bucket, &hit_bits)) < 0) { 678 soc_mem_unlock(unit, L2X_HITm); 679 return r; 680 } 681 682 soc_mem_unlock(unit, L2X_HITm); 683 684 return SOC_E_NONE; 685 } 686 687 /* 688 * Function: 689 * soc_l2x_insert 690 * Purpose: 691 * Insert an entry into the L2X hash table. 692 * Parameters: 693 * unit - StrataSwitch unit # 694 * entry - L2X entry to insert 695 * Returns: 696 * SOC_E_NONE - success 697 * SOC_E_FULL - hash bucket full 698 * Notes: 699 * Uses hardware insertion; sends an L2 INSERT message over the 700 * S-Channel. The hardware needs the L2Xm entry type. 701 * This affects the L2_ENTRYm table, L2_VALIDm table, L2_STATICm 702 * table, and the L2_HITm table. 703 */ 704 705 int 706 soc_l2x_insert(int unit, l2x_entry_t *entry) 707 { 708 l2x_entry_t valid_entry; 709 schan_msg_t schan_msg; 710 int rv; 711 int src_blk; 712 713 if (bsl_check(bslLayerSoc, bslSourceSocmem, bslSeverityNormal, unit)) { 714 LOG_INFO(BSL_LS_SOC_SOCMEM, 715 (BSL_META_U(unit, 716 "Insert table[L2X]: "))); 717 soc_mem_entry_dump(unit, L2Xm, entry, BSL_INFO|BSL_LS_SOC_SOCMEM); 718 LOG_INFO(BSL_LS_SOC_SOCMEM, 719 (BSL_META_U(unit, 720 "\n"))); 721 } 722 723 memcpy(&valid_entry, entry, sizeof(l2x_entry_t)); 724 soc_L2Xm_field32_set(unit, &valid_entry, VALID_BITf, 1); 725 726 #define SOC_L2X_MEM_BYTES 11 727 schan_msg_clear(&schan_msg); 728 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 729 soc_schan_header_cmd_set(unit, &schan_msg.header, ARL_INSERT_CMD_MSG, 730 0, src_blk, 0, SOC_L2X_MEM_BYETS, 0, 0); 731 #undef SOC_L2X_MEM_BYTES 732 733 /* Fill in ARL packet data */ 734 735 sal_memcpy(schan_msg.arlins.data, &valid_entry, 736 sizeof (schan_msg.arlins.data)); 737 738 /* Lock ARL memory to avoid modifying L2 table while frozen */ 739 740 soc_mem_lock(unit, L2Xm); 741 742 /* Execute S-Channel operation (header word + 3 DWORDs) */ 743 744 rv = soc_schan_op(unit, &schan_msg, 4, 0, 1); 745 746 if (rv == SOC_E_FAIL) { 747 LOG_INFO(BSL_LS_SOC_SOCMEM, 748 (BSL_META_U(unit, 749 "Insert table[L2X]: hash bucket full\n"))); 750 rv = SOC_E_FULL; 751 } 752 753 soc_mem_unlock(unit, L2Xm); 754 755 /* 5690 workaround; see _soc_l2x_hit_clear() for details */ 756 757 if (rv >= 0 && 758 soc_feature(unit, soc_feature_l2x_ins_sets_hit) && 759 !soc_L2Xm_field32_get(unit, entry, HIT_BITf)) { 760 rv = _soc_l2x_hit_clear(unit, entry); 761 } 762 763 return rv; 764 } 765 766 /* 767 * Function: 768 * soc_l2x_delete 769 * Purpose: 770 * Delete an entry from the L2X hash table. 771 * Parameters: 772 * unit - StrataSwitch unit # 773 * entry - L2X entry to delete 774 * Returns: 775 * SOC_E_NONE - success 776 * SOC_E_FULL - hash bucket full 777 * Notes: 778 * Uses hardware deletion; sends an L2 DELETE message over the 779 * S-Channel. The hardware needs the L2Xm entry type. 780 * Only the L2_VALIDm table is affected. 781 */ 782 783 int 784 soc_l2x_delete(int unit, l2x_entry_t *entry) 785 { 786 schan_msg_t schan_msg; 787 int rv; 788 int src_blk; 789 790 if (bsl_check(bslLayerSoc, bslSourceSocmem, bslSeverityNormal, unit)) { 791 LOG_INFO(BSL_LS_SOC_SOCMEM, 792 (BSL_META_U(unit, 793 "Delete table[L2X]: "))); 794 soc_mem_entry_dump(unit, L2Xm, entry, BSL_INFO|BSL_LS_SOC_SOCMEM); 795 LOG_INFO(BSL_LS_SOC_SOCMEM, 796 (BSL_META_U(unit, 797 "\n"))); 798 } 799 800 #define SOC_L2X_MEM_KEY_BYTES 8 801 schan_msg_clear(&schan_msg); 802 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 803 soc_schan_header_cmd_set(unit, &schan_msg.header, ARL_DELETE_CMD_MSG, 804 0, src_blk, 0, SOC_L2X_MEM_KEY_BYTES, 0, 0); 805 #undef SOC_L2X_MEM_KEY_BYTES 806 807 /* Fill in packet data */ 808 809 sal_memcpy(schan_msg.arldel.data, entry, sizeof (schan_msg.arldel.data)); 810 811 /* Lock ARL memory to avoid modifying L2 table while frozen */ 812 813 soc_mem_lock(unit, L2Xm); 814 815 /* Execute S-Channel operation (header word + 2 DWORDs) */ 816 rv = soc_schan_op(unit, &schan_msg, 3, 0, 1); 817 818 soc_mem_unlock(unit, L2Xm); 819 820 return rv; 821 } 822 823 /* 824 * Function: 825 * soc_l2x_delete_all 826 * Purpose: 827 * Clear the L2 table by invalidating entries. 828 * Parameters: 829 * unit - StrataSwitch unit # 830 * static_too - if TRUE, delete static and non-static entries; 831 * if FALSE, delete only non-static entries 832 * Returns: 833 * SOC_E_XXX 834 */ 835 836 int 837 soc_l2x_delete_all(int unit, int static_too) 838 { 839 soc_control_t *soc = SOC_CONTROL(unit); 840 int index_min, index_max, index; 841 l2x_valid_entry_t valid_bits; 842 l2x_static_entry_t static_bits; 843 int rv = SOC_E_NONE; 844 845 soc_mem_lock(unit, L2Xm); 846 847 sal_memset(&valid_bits, 0, sizeof (valid_bits)); 848 849 index_min = soc_mem_index_min(unit, L2X_VALIDm); 850 index_max = soc_mem_index_max(unit, L2X_VALIDm); 851 852 for (index = index_min; index <= index_max; index++) { 853 if (!static_too) { 854 if ((rv = soc_mem_read(unit, L2X_VALIDm, MEM_BLOCK_ANY, 855 index, &valid_bits)) < 0) { 856 goto done; 857 } 858 859 if ((rv = soc_mem_read(unit, L2X_STATICm, MEM_BLOCK_ANY, 860 index, &static_bits)) < 0) { 861 goto done; 862 } 863 864 valid_bits.entry_data[0] &= static_bits.entry_data[0]; 865 } /* else the valid bits will always be 0 */ 866 867 if ((rv = soc_mem_write(unit, L2X_VALIDm, MEM_BLOCK_ALL, 868 index, &valid_bits)) < 0) { 869 goto done; 870 } 871 } 872 873 if (soc->arlShadow != NULL) { 874 sal_mutex_take(soc->arlShadowMutex, sal_mutex_FOREVER); 875 (void) shr_avl_delete_all(soc->arlShadow); 876 sal_mutex_give(soc->arlShadowMutex); 877 } 878 879 done: 880 881 soc_mem_unlock(unit, L2Xm); 882 883 return rv; 884 } 885 #endif /* BCM_XGS12_SWITCH_SUPPORT */ 886 #ifdef PLISIM 887 #ifdef _KATANA_DEBUG /* BCM_KATANA_SUPPORT */ 888 void _bcm_kt_enable_port_age_simulation(uint32 flags, _bcm_l2_replace_t *rep_st) 889 { 890 port_age_enable=TRUE; 891 port_age_flags=flags; 892 port_age_rep_st=rep_st; 893 return ; 894 } 895 STATIC int perform_port_age_simulation(int unit) 896 { 897 uint32 sync_op; 898 soc_field_t valid_bit = VALID_BITf; 899 int static_bit_val; 900 int pending_bit_val; 901 int port_val, mod_val; 902 vlan_id_t vlan_val; 903 int vfi_val; 904 int tgid_hi=0,tgid_lo=0; 905 int tgid_val=0, tid_val=0; 906 int trunk128; 907 uint32 tid; 908 909 910 /* Indexes to iterate over memories, chunks and entries */ 911 int chnk_idx, ent_idx, chnk_idx_max, mem_idx_max; 912 int buf_size, chunksize, chnk_end; 913 /* Buffer to store chunk of L2 table we currently work on */ 914 uint32 *l2_tbl_chnk; 915 uint32 *l2_entry; 916 int rv = SOC_E_NONE; 917 918 if ( port_age_enable==FALSE) { 919 LOG_CLI((BSL_META_U(unit, 920 "INFO:PortAging simulation not enabled yet \n"))); 921 return SOC_E_NONE; 922 } 923 port_age_enable=FALSE; 924 LOG_CLI((BSL_META_U(unit, 925 "Performing PortAging simulation... STATIC %d \n"), 926 port_age_flags & BCM_L2_REPLACE_MATCH_STATIC)); 927 928 if (SOC_IS_FBX(unit)) { 929 valid_bit = VALIDf; 930 } 931 tid = port_age_rep_st->match_trunk; 932 if (!(port_age_flags & BCM_L2_REPLACE_DELETE) || (port_age_flags & _BCM_L2_REPLACE_DELETE_ALL)) { 933 return SOC_E_NONE; 934 } 935 switch (port_age_flags & (BCM_L2_REPLACE_MATCH_DEST | BCM_L2_REPLACE_MATCH_VLAN)) { 936 case BCM_L2_REPLACE_MATCH_DEST: 937 if (port_age_rep_st->isTrunk) { 938 sync_op = SOC_L2X_TRUNK_DEL; 939 } else { 940 sync_op = SOC_L2X_PORTMOD_DEL; 941 } 942 break; 943 case BCM_L2_REPLACE_MATCH_VLAN: 944 sync_op = SOC_L2X_VLAN_DEL; 945 break; 946 case BCM_L2_REPLACE_MATCH_DEST | BCM_L2_REPLACE_MATCH_VLAN: 947 if (port_age_rep_st->isTrunk) { 948 sync_op = SOC_L2X_TRUNK_VLAN_DEL; 949 } else { 950 sync_op = SOC_L2X_PORTMOD_VLAN_DEL; 951 } 952 break; 953 default: 954 LOG_CLI((BSL_META_U(unit, 955 "Unknown PortAging operation !!! \n"))); 956 return SOC_E_PARAM; 957 } 958 if (!soc_mem_index_count(unit, L2Xm)) { 959 return SOC_E_NONE; 960 } 961 chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS, L2_MEM_CHUNKS_DEFAULT); 962 buf_size = 4 * SOC_MAX_MEM_FIELD_WORDS * chunksize; 963 l2_tbl_chnk = soc_cm_salloc(unit, buf_size, "l2 traverse"); 964 if (NULL == l2_tbl_chnk) { 965 return SOC_E_MEMORY; 966 } 967 mem_idx_max = soc_mem_index_max(unit, L2Xm); 968 for (chnk_idx = soc_mem_index_min(unit, L2Xm); chnk_idx <= mem_idx_max; chnk_idx += chunksize) { 969 sal_memset((void *)l2_tbl_chnk, 0, buf_size); 970 chnk_idx_max = ((chnk_idx + chunksize) < mem_idx_max) ? (chnk_idx + chunksize - 1) : mem_idx_max; 971 rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY, chnk_idx, chnk_idx_max, l2_tbl_chnk); 972 if (SOC_FAILURE(rv)) { 973 break; 974 } 975 chnk_end = (chnk_idx_max - chnk_idx); 976 for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx ++) { 977 l2_entry = soc_mem_table_idx_to_pointer(unit, L2Xm, uint32 *, l2_tbl_chnk, ent_idx); 978 if (!soc_mem_field32_get(unit,L2Xm, l2_entry,valid_bit)) { 979 continue; 980 } 981 trunk128 = soc_feature(unit, soc_feature_trunk_extended); 982 if (!trunk128) 983 { 984 tid &= SOC_L2X_TGID_PORT_TRUNK_MASK; 985 tid |= SOC_L2X_TGID_TRUNK_INDICATOR(unit); 986 } 987 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 988 port_val = soc_mem_field32_get(unit, L2Xm, l2_entry, PORT_NUMf); 989 if (trunk128) 990 { 991 tid_val = soc_mem_field32_get(unit, L2Xm, l2_entry, TGIDf); 992 } 993 } else { 994 port_val = soc_mem_field32_get(unit, L2Xm, l2_entry, TGID_PORTf); 995 if (trunk128) 996 { 997 tgid_val = soc_mem_field32_get(unit, L2Xm, l2_entry, MODULE_IDf); 998 tgid_hi = (tid & SOC_L2X_TGID_PORT_TRUNK_MASK_HI) >> SOC_TRUNK_BIT_POS(unit); 999 tgid_lo = tid & SOC_L2X_TGID_PORT_TRUNK_MASK; 1000 tgid_lo |= SOC_L2X_TGID_TRUNK_INDICATOR(unit); 1001 } 1002 } 1003 mod_val = soc_mem_field32_get(unit,L2Xm,l2_entry,MODULE_IDf); 1004 static_bit_val = soc_mem_field32_get(unit,L2Xm,l2_entry,STATIC_BITf); 1005 pending_bit_val = soc_mem_field32_get(unit,L2Xm,l2_entry,PENDINGf); 1006 vlan_val = soc_mem_field32_get(unit,L2Xm,l2_entry,VLAN_IDf); 1007 vfi_val = soc_mem_field32_get(unit, L2Xm,l2_entry, VFIf); 1008 switch(sync_op) 1009 { 1010 case SOC_L2X_PORTMOD_DEL: 1011 if (soc_mem_field32_get(unit, L2Xm, l2_entry, Tf)) { 1012 continue; 1013 } 1014 if ((port_val != port_age_rep_st->match_port) || (mod_val != port_age_rep_st->match_module)) { 1015 continue; 1016 } 1017 break; 1018 case SOC_L2X_VLAN_DEL: 1019 if (soc_mem_field32_get(unit, L2Xm, l2_entry, Tf)) { 1020 continue; 1021 } 1022 if (vlan_val != port_age_rep_st->match_vid) { 1023 continue; 1024 } 1025 break; 1026 case SOC_L2X_VFI_DEL: 1027 LOG_CLI((BSL_META_U(unit, 1028 "NOT IMPLEMENTED!\n"))); 1029 continue; 1030 case SOC_L2X_PORTMOD_VLAN_DEL: 1031 if (soc_mem_field32_get(unit, L2Xm, l2_entry, Tf)) { 1032 continue; 1033 } 1034 if ((vlan_val != port_age_rep_st->match_vid) || (port_val != port_age_rep_st->match_port) || (mod_val != port_age_rep_st->match_module)) { 1035 continue; 1036 } 1037 break; 1038 case SOC_L2X_TRUNK_DEL: 1039 case SOC_L2X_TRUNK_VLAN_DEL: 1040 if(trunk128) { 1041 LOG_CLI((BSL_META_U(unit, 1042 "Trunk128...\n"))); 1043 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 1044 if (!soc_mem_field32_get(unit, L2Xm, l2_entry, Tf)) { 1045 continue; 1046 } 1047 if (tid_val != port_age_rep_st->match_trunk) { 1048 continue; 1049 } 1050 }else { 1051 if ((tgid_lo != port_val) ||(tgid_hi != tgid_val)) { 1052 continue; 1053 } 1054 } 1055 if (sync_op == SOC_L2X_TRUNK_VLAN_DEL) { 1056 if(vlan_val != port_age_rep_st->match_vid) { 1057 continue; 1058 } 1059 } 1060 } else { 1061 if (port_val != port_age_rep_st->match_trunk) { 1062 continue; 1063 } 1064 if (sync_op == SOC_L2X_TRUNK_VLAN_DEL) { 1065 if(vlan_val != port_age_rep_st->match_vid) { 1066 continue; 1067 } 1068 } 1069 } 1070 break; 1071 default: 1072 continue; 1073 } 1074 /* Check for static entry deletion */ 1075 if ( (port_age_flags & BCM_L2_REPLACE_MATCH_STATIC) != BCM_L2_REPLACE_MATCH_STATIC) { 1076 if (static_bit_val == 1) { 1077 LOG_CLI((BSL_META_U(unit, 1078 "Skipped STATIC L2 Entry Deletion:" 1079 "port_val:%d mod_id : %d static_bit_val : %d " 1080 "pending_bit_val %d vlan_id : %d vfi_id : %d " 1081 "\n"), 1082 port_val, mod_val, static_bit_val, 1083 pending_bit_val, vlan_val, vfi_val)); 1084 continue; 1085 } 1086 } 1087 if( (port_age_flags & BCM_L2_REPLACE_PENDING) == BCM_L2_REPLACE_PENDING) { 1088 if (pending_bit_val != 1) { 1089 LOG_CLI((BSL_META_U(unit, 1090 "Skipped Non Pending L2 Entry Deletion:" 1091 "port_val:%d mod_id : %d static_bit_val : %d " 1092 "pending_bit_val %d vlan_id : %d vfi_id : %d " 1093 "\n"), 1094 port_val, mod_val, static_bit_val, 1095 pending_bit_val, vlan_val, vfi_val)); 1096 continue; 1097 } 1098 } 1099 /* soc_mem_field32_set(unit,L2Xm, l2_entry,valid_bit,0); */ 1100 rv = soc_mem_delete(unit, L2Xm, MEM_BLOCK_ALL, l2_entry); 1101 if (SOC_FAILURE(rv)) { 1102 break; 1103 } 1104 LOG_CLI((BSL_META_U(unit, 1105 "Deleted L2 Entry:port_val:%d mod_id : %d " 1106 "static_bit_val : %d pending_bit_val : %d " 1107 "vlan_id : %d vfi_id : %d \n"), 1108 port_val, mod_val, static_bit_val, 1109 pending_bit_val, vlan_val, vfi_val)); 1110 } 1111 } 1112 soc_cm_sfree(unit, l2_tbl_chnk); 1113 return SOC_E_NONE; 1114 } 1115 #endif 1116 #endif 1117 1118 #ifdef BCM_TRIDENT2_SUPPORT 1119 STATIC int 1120 _soc_l2x_td2_convert_delete_to_replace(int unit) 1121 { 1122 uint32 rval; 1123 SOC_IF_ERROR_RETURN(READ_L2_BULK_CONTROLr(unit, &rval)); 1124 if (soc_reg_field_get(unit, L2_BULK_CONTROLr, rval, 1125 ACTIONf) == 1) { 1126 l2_bulk_replace_mask_entry_t repl_mask; 1127 l2_bulk_replace_data_entry_t repl_data; 1128 sal_memset(&repl_mask, 0xFF, sizeof(repl_mask)); 1129 sal_memset(&repl_data, 0, sizeof(repl_data)); 1130 SOC_IF_ERROR_RETURN 1131 (WRITE_L2_BULK_REPLACE_MASKm(unit, MEM_BLOCK_ALL, 0, &repl_mask)); 1132 SOC_IF_ERROR_RETURN 1133 (WRITE_L2_BULK_REPLACE_DATAm(unit, MEM_BLOCK_ALL, 0, &repl_data)); 1134 SOC_IF_ERROR_RETURN 1135 (soc_reg_field32_modify(unit, L2_BULK_CONTROLr, REG_PORT_ANY, 1136 ACTIONf, 2)); 1137 } 1138 return SOC_E_NONE; 1139 } 1140 1141 STATIC int 1142 _soc_l2x_td2_frozen_cml_restore(int unit) 1143 { 1144 uint32 rval; 1145 cml_freeze_t *f_cml = &cml_freeze_state[unit]; /* Cml freeze state.*/ 1146 1147 1148 SOC_CML_FREEZE_LOCK(unit); 1149 /* If going out of freeze restore values to HW. */ 1150 if (f_cml->frozen == 1) { 1151 SOC_IF_ERROR_RETURN( 1152 READ_ING_MISC_CONFIG2r(unit, &rval)); 1153 soc_reg_field_set(unit, ING_MISC_CONFIG2r, &rval, 1154 CML_OVERRIDE_ENABLE_NEWf, 0); 1155 soc_reg_field_set(unit, ING_MISC_CONFIG2r, &rval, 1156 CML_OVERRIDE_ENABLE_MOVEf, 0); 1157 SOC_IF_ERROR_RETURN( 1158 WRITE_ING_MISC_CONFIG2r(unit, rval)); 1159 } 1160 1161 /* Regardless of status, decrement frozen count. */ 1162 f_cml->frozen--; 1163 SOC_CML_FREEZE_UNLOCK(unit); 1164 return SOC_E_NONE; 1165 } 1166 1167 STATIC int 1168 _soc_l2x_td2_frozen_cml_save(int unit) 1169 { 1170 uint32 rval; 1171 cml_freeze_t *f_cml = &cml_freeze_state[unit]; /* Cml freeze state.*/ 1172 1173 SOC_CML_FREEZE_LOCK(unit); 1174 /* Freezing l2 - disable learning. */ 1175 if (f_cml->frozen == 0) { 1176 SOC_IF_ERROR_RETURN( 1177 READ_ING_MISC_CONFIG2r(unit, &rval)); 1178 soc_reg_field_set(unit, ING_MISC_CONFIG2r, &rval, 1179 CML_OVERRIDE_ENABLE_NEWf, 1); 1180 soc_reg_field_set(unit, ING_MISC_CONFIG2r, &rval, 1181 CML_OVERRIDE_ENABLE_MOVEf, 1); 1182 SOC_IF_ERROR_RETURN( 1183 WRITE_ING_MISC_CONFIG2r(unit, rval)); 1184 } 1185 1186 /* Icrement CML frozen indicator. */ 1187 f_cml->frozen++; 1188 SOC_CML_FREEZE_UNLOCK(unit); 1189 return SOC_E_NONE; 1190 } 1191 1192 int 1193 soc_l2x_cml_override_is_enabled(int unit) 1194 { 1195 uint32 rval = 0; 1196 uint32 enable_newf = 0, enable_movef = 0; 1197 int rv = SOC_E_NONE; 1198 1199 rv = READ_ING_MISC_CONFIG2r(unit, &rval); 1200 if (rv != SOC_E_NONE) { 1201 return 0; 1202 } 1203 enable_newf = soc_reg_field_get(unit, ING_MISC_CONFIG2r, 1204 rval, CML_OVERRIDE_ENABLE_NEWf); 1205 1206 enable_movef = soc_reg_field_get(unit, ING_MISC_CONFIG2r, 1207 rval, CML_OVERRIDE_ENABLE_MOVEf); 1208 1209 rval = (enable_newf == 0 && enable_movef == 0)? 0:1; 1210 return rval; 1211 } 1212 1213 #endif /* BCM_TRIDENT2_SUPPORT */ 1214 1215 #ifdef BCM_WARM_BOOT_SUPPORT 1216 /* 1217 * Function: 1218 * soc_l2x_wb_scache_size_get 1219 * Purpose: 1220 * Returns required scache size for L2 part 1221 * Parameters: 1222 * unit - (IN) Unit number. 1223 * req_scache_size - (OUT) Request scache size 1224 * Returns: 1225 * SOC_E_XXX 1226 * Notes: 1227 */ 1228 int 1229 soc_l2x_wb_scache_size_get(int unit, int *req_scache_size) 1230 { 1231 int alloc_size = 0; 1232 1233 alloc_size += sizeof(l2_freeze_mode); 1234 *req_scache_size += alloc_size; 1235 return SOC_E_NONE; 1236 } 1237 1238 /* 1239 * Function: 1240 * soc_l2x_scache_sync 1241 * Purpose: 1242 * Syncs L2 part warmboot state to scache 1243 * Parameters: 1244 * unit - (IN) Unit number. 1245 * scache_ptr - (IN) Scache pointer. 1246 * Returns: 1247 * SOC_E_XXX 1248 * Notes: 1249 */ 1250 int 1251 soc_l2x_scache_sync(int unit, uint8 **scache_ptr) 1252 { 1253 int *iptr = NULL; 1254 1255 iptr = (int *)(*scache_ptr); 1256 *iptr = l2_freeze_mode[unit]; 1257 iptr++; 1258 *scache_ptr = (uint8 *)iptr; 1259 1260 return SOC_E_NONE; 1261 } 1262 1263 /* 1264 * Function: 1265 * soc_l2x_reinit 1266 * Purpose: 1267 * Recovers L2 part warmboot state from scache 1268 * Parameters: 1269 * unit - (IN) Unit number. 1270 * scache_ptr - (IN) Scache pointer. 1271 * Returns: 1272 * SOC_E_XXX 1273 * Notes: 1274 */ 1275 int 1276 soc_l2x_reinit(int unit, uint8 **scache_ptr) 1277 { 1278 int *iptr = NULL; 1279 1280 iptr = (int *)(*scache_ptr); 1281 l2_freeze_mode[unit] = *iptr; 1282 iptr++; 1283 *scache_ptr = (uint8 *)iptr; 1284 1285 return SOC_E_NONE; 1286 } 1287 #endif /* BCM_WARM_BOOT_SUPPORT */ 1288 1289 /* 1290 * Function: 1291 * soc_l2x_freeze_mode_is_global_override 1292 * Description: 1293 * Check if SDK is using global override to freeze L2X. 1294 * Parameters: 1295 * unit - (IN) Device number 1296 * Return Value: 1297 * TRUE / FALSE 1298 */ 1299 int 1300 soc_l2x_freeze_mode_is_global_override(int unit) 1301 { 1302 return (l2_freeze_mode[unit] == SOC_L2X_FREEZE_MODE_GLOBAL_OVERRIDE)? \ 1303 TRUE:FALSE; 1304 } 1305 1306 /* 1307 * Function: 1308 * soc_l2x_freeze_mode_set 1309 * Description: 1310 * Record configured freeze mode. 1311 * Mode cannot be changed during frozen. Because freeze/thaw should 1312 * be executed with the same mode. 1313 * Parameters: 1314 * unit - (IN) Device number 1315 * mode - (IN) Mode to use 1316 * Return Value: 1317 * SOC_E_XXX 1318 */ 1319 int 1320 soc_l2x_freeze_mode_set(int unit, int mode) 1321 { 1322 int frozen = 0; 1323 int cur_mode = 0; 1324 1325 SOC_IF_ERROR_RETURN(soc_l2x_freeze_mode_get(unit, &cur_mode)); 1326 if (mode == cur_mode) { 1327 return SOC_E_NONE; 1328 } 1329 SOC_IF_ERROR_RETURN(soc_l2x_is_frozen(unit, SOC_L2X_FROZEN, &frozen)); 1330 if (frozen) { 1331 return SOC_E_BUSY; 1332 } else { 1333 l2_freeze_mode[unit] = mode; 1334 } 1335 1336 return SOC_E_NONE; 1337 } 1338 1339 /* 1340 * Function: 1341 * soc_l2x_freeze_mode_get 1342 * Description: 1343 * Retrieve configured freeze mode.. 1344 * Parameters: 1345 * unit - (IN) Device number 1346 * mode - (OUT) Mode in use 1347 * Return Value: 1348 * SOC_E_XXX 1349 */ 1350 int 1351 soc_l2x_freeze_mode_get(int unit, int *mode) 1352 { 1353 if (mode == NULL) { 1354 return SOC_E_PARAM; 1355 } 1356 *mode = l2_freeze_mode[unit]; 1357 1358 return SOC_E_NONE; 1359 } 1360 1361 /* 1362 * Function: 1363 * _soc_l2x_port_age 1364 * Purpose: 1365 * Use HW port/VLAN "aging" to delete selected L2 entries. 1366 * Parameters: 1367 * unit - StrataSwitch unit # 1368 * age_reg0 - port aging register. 1369 * age_reg1 - optioanl 2nd port aging register. 1370 * Returns: 1371 * SOC_E_XXX 1372 * Notes: 1373 * Hardware deletion is used. 1374 * The chip requires that ARL aging be disabled during this 1375 * operation. An unavoidable side effect is that the hardware 1376 * aging timer gets restarted whenever this routine is called. 1377 */ 1378 int 1379 soc_l2x_port_age(int unit, soc_reg_t reg0, soc_reg_t reg1) 1380 { 1381 static soc_field_t fields[2] = { STARTf, COMPLETEf }; 1382 static uint32 values[2] = { 1, 0 }; 1383 soc_timeout_t to; 1384 int rv; 1385 int timeout_usec; 1386 int reg0_complete, reg1_complete; 1387 uint32 rval; 1388 int mode; 1389 #ifdef BCM_TRIDENT2_SUPPORT 1390 soc_control_t *soc = SOC_CONTROL(unit); 1391 #endif 1392 #ifdef BCM_HURRICANE3_SUPPORT 1393 uint64 rval64; 1394 #endif 1395 1396 if (reg0 == INVALIDr && reg1 == INVALIDr) { 1397 return SOC_E_NONE; 1398 } 1399 1400 timeout_usec = SOC_CONTROL(unit)->l2x_age_timeout; 1401 mode = SOC_CONTROL(unit)->l2x_mode; 1402 1403 if (mode != L2MODE_FIFO) { 1404 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 1405 SOC_IF_ERROR_RETURN(_soc_l2x_frozen_cml_save(unit)); 1406 } else { 1407 SOC_IF_ERROR_RETURN(soc_l2x_freeze(unit)); 1408 } 1409 } 1410 1411 #ifdef BCM_TRIDENT2_SUPPORT 1412 if (SOC_IS_TRIDENT2(unit) || SOC_IS_TITAN2(unit)) { 1413 /* if action == 1, convert action to 2 and replace data to be 0 */ 1414 /* TD3TBD, does TD3 need this? */ 1415 rv = _soc_l2x_td2_convert_delete_to_replace(unit); 1416 if (SOC_FAILURE(rv)) { 1417 goto exit; 1418 } 1419 } 1420 #endif 1421 1422 #ifdef BCM_TRIDENT2_SUPPORT 1423 if (soc_feature(unit, soc_feature_l2_hw_aging_bug) && 1424 sal_thread_self() == soc->l2x_age_pid) { 1425 TABLE_DMA_LOCK(unit); 1426 SOC_SBUSDMA_DM_LOCK(unit); 1427 SCHAN_LOCK(unit); 1428 } 1429 #endif 1430 1431 reg0_complete = TRUE; 1432 if (reg0 != INVALIDr) { 1433 rv = soc_reg_fields32_modify(unit, reg0, REG_PORT_ANY, 2, fields, 1434 values); 1435 if (SOC_FAILURE(rv)) { 1436 goto done; 1437 } 1438 reg0_complete = FALSE; 1439 } 1440 1441 reg1_complete = TRUE; 1442 if (reg1 != INVALIDr) { 1443 rv = soc_reg_fields32_modify(unit, reg1, REG_PORT_ANY, 2, fields, 1444 values); 1445 if (SOC_FAILURE(rv)) { 1446 goto done; 1447 } 1448 reg1_complete = FALSE; 1449 } 1450 1451 SOC_CONTROL(unit)->l2x_ppa_in_progress = TRUE; 1452 soc_timeout_init(&to, timeout_usec, 0); 1453 for (;;) { 1454 if (!reg0_complete) { 1455 #ifdef BCM_HURRICANE3_SUPPORT 1456 if ((SOC_IS_HURRICANE3(unit) || SOC_IS_GREYHOUND2(unit)) && 1457 reg0 == PER_PORT_AGE_CONTROL_64r) { 1458 rv = soc_reg64_get(unit, reg0, REG_PORT_ANY, 0, &rval64); 1459 if (SOC_SUCCESS(rv)) { 1460 reg0_complete = soc_reg64_field32_get(unit, reg0, rval64, COMPLETEf); 1461 } 1462 } else 1463 #endif 1464 { 1465 rv = soc_reg32_get(unit, reg0, REG_PORT_ANY, 0, &rval); 1466 if (SOC_SUCCESS(rv)) { 1467 reg0_complete = soc_reg_field_get(unit, reg0, rval, COMPLETEf); 1468 } 1469 } 1470 } 1471 if (!reg1_complete) { 1472 rv = soc_reg32_get(unit, reg1, REG_PORT_ANY, 0, &rval); 1473 if (SOC_SUCCESS(rv)) { 1474 reg1_complete = soc_reg_field_get(unit, reg1, rval, COMPLETEf); 1475 } 1476 } 1477 1478 if (reg0_complete && reg1_complete) { 1479 rv = SOC_E_NONE; 1480 break; 1481 } 1482 1483 if (soc_timeout_check(&to)) { 1484 rv = SOC_E_TIMEOUT; 1485 break; 1486 } 1487 } 1488 1489 done: 1490 #ifdef BCM_TRIDENT2_SUPPORT 1491 if (soc_feature(unit, soc_feature_l2_hw_aging_bug) && 1492 sal_thread_self() == soc->l2x_age_pid) { 1493 SCHAN_UNLOCK(unit); 1494 SOC_SBUSDMA_DM_UNLOCK(unit); 1495 TABLE_DMA_UNLOCK(unit); 1496 } 1497 1498 exit: 1499 #endif 1500 SOC_CONTROL(unit)->l2x_ppa_in_progress = FALSE; 1501 if (mode != L2MODE_FIFO) { 1502 if (SOC_IS_TOMAHAWKX(unit) || SOC_IS_TRIDENT3X(unit)) { 1503 SOC_IF_ERROR_RETURN(_soc_l2x_frozen_cml_restore(unit)); 1504 } else { 1505 SOC_IF_ERROR_RETURN(soc_l2x_thaw(unit)); 1506 } 1507 } 1508 #ifdef PLISIM 1509 #ifdef _KATANA_DEBUG /* BCM_KATANA_SUPPORT */ 1510 if (SAL_BOOT_PLISIM) { 1511 if ((rv == SOC_E_NONE) && (SOC_IS_KATANA(unit))) { 1512 perform_port_age_simulation(unit); 1513 } 1514 } 1515 #endif 1516 #endif 1517 return rv; 1518 } 1519 1520 #ifdef BCM_TRIDENT3_SUPPORT 1521 int 1522 soc_l2x_cml_register(int unit, soc_l2x_cml_cb_fn fn) 1523 { 1524 cml_freeze_t *f_cml = &cml_freeze_state[unit]; 1525 f_cml->cml_func = fn; 1526 return SOC_E_NONE; 1527 } 1528 #endif/*BCM_TRIDENT3_SUPPORT*/ 1529 /* 1530 * Function: 1531 * _soc_l2x_frozen_cml_restore 1532 * Purpose: 1533 * Helper function to restore port learning mode. 1534 * Parameters: 1535 * unit - (IN) BCM device number. 1536 * Returns: 1537 * SOC_E_XXX 1538 */ 1539 int 1540 _soc_l2x_frozen_cml_restore(int unit) 1541 { 1542 cml_freeze_t *f_cml = &cml_freeze_state[unit]; /* Cml freeze state.*/ 1543 soc_port_t port; /* Device port iterator. */ 1544 port_tab_entry_t pent; /* Port table hw entry buffer. */ 1545 int cml; /* Learn mode for specific port. */ 1546 int rv = SOC_E_NONE; /* Operation return status. */ 1547 soc_pbmp_t pbmp; 1548 1549 #ifdef BCM_TRIDENT2_SUPPORT 1550 if (SOC_IS_TD2_TT2(unit) && 1551 soc_l2x_freeze_mode_is_global_override(unit)) { 1552 return _soc_l2x_td2_frozen_cml_restore(unit); 1553 } 1554 #endif 1555 1556 SOC_PBMP_CLEAR(pbmp); 1557 /* Take protection mutex. */ 1558 if (SOC_MEM_IS_VALID(unit, PORT_TABm)) { 1559 soc_mem_lock(unit, PORT_TABm); 1560 } 1561 if (SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 1562 soc_mem_lock(unit, SOURCE_VPm); 1563 } 1564 1565 /* If going out of freeze restore sw preserved values to HW. */ 1566 if (f_cml->frozen == 1) { 1567 SOC_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 1568 #ifdef BCM_KATANA2_SUPPORT 1569 if (soc_feature(unit, soc_feature_linkphy_coe) || 1570 soc_feature(unit, soc_feature_subtag_coe)) { 1571 _bcm_kt2_subport_pbmp_update(unit, &pbmp); 1572 } 1573 #endif 1574 PBMP_ITER(pbmp, port) { 1575 /* Read port table entry. */ 1576 if (!SOC_IS_TRIDENT3X(unit)) { 1577 rv = READ_PORT_TAB_MOD_CHK(unit, MEM_BLOCK_ANY, port, &pent); 1578 if (SOC_FAILURE(rv)) { 1579 break; 1580 } 1581 } 1582 /* Get port current learning mode. */ 1583 #ifdef BCM_TRIDENT3_SUPPORT 1584 if (SOC_IS_TRIDENT3X(unit)) { 1585 /*mem write is not allowed during WB*/ 1586 if (SOC_WARM_BOOT(unit)) { 1587 break; 1588 } 1589 if (f_cml->cml_func == NULL) { 1590 rv = SOC_E_FAIL; 1591 break; 1592 } 1593 rv = f_cml->cml_func(unit, port, FALSE, 1594 &f_cml->save_cml[port], 1595 &f_cml->save_cml_move[port]); 1596 if (SOC_FAILURE(rv)) { 1597 break; 1598 } 1599 } else 1600 #endif /*BCM_TRIDENT3_SUPPORT*/ 1601 #ifdef BCM_TRX_SUPPORT 1602 if (SOC_IS_TRX(unit)) { 1603 int cml_change = FALSE; 1604 cml = soc_PORT_TABm_field32_get(unit, &pent, CML_FLAGS_NEWf); 1605 if (cml != f_cml->save_cml[port]) { 1606 soc_PORT_TABm_field32_set(unit, &pent, CML_FLAGS_NEWf, 1607 f_cml->save_cml[port]); 1608 cml_change = TRUE; 1609 } 1610 cml = soc_PORT_TABm_field32_get(unit, &pent, CML_FLAGS_MOVEf); 1611 if (cml != f_cml->save_cml_move[port]) { 1612 soc_PORT_TABm_field32_set(unit, &pent, CML_FLAGS_MOVEf, 1613 f_cml->save_cml_move[port]); 1614 cml_change = TRUE; 1615 } 1616 if (cml_change) { 1617 rv = WRITE_PORT_TAB_MOD_CHK(unit, MEM_BLOCK_ALL, port, 1618 &pent); 1619 if (SOC_FAILURE(rv)) { 1620 break; 1621 } 1622 } 1623 } else 1624 #endif /* BCM_TRX_SUPPORT */ 1625 { 1626 cml = soc_PORT_TABm_field32_get(unit, &pent, CMLf); 1627 /* Update mode if necessary. */ 1628 if (cml != f_cml->save_cml[port]) { 1629 soc_PORT_TABm_field32_set(unit, &pent, CMLf, 1630 f_cml->save_cml[port]); 1631 rv = WRITE_PORT_TAB_MOD_CHK(unit, MEM_BLOCK_ALL, port, 1632 &pent); 1633 if (SOC_FAILURE(rv)) { 1634 break; 1635 } 1636 } 1637 } 1638 } 1639 /* Restore CML value and on Virtual ports */ 1640 if (SOC_SUCCESS(rv) && SOC_MEM_IS_VALID(unit, SOURCE_VPm) && 1641 (NULL != f_cml->vp_bitmap)) { 1642 int index, index_min, index_max, buf_index, count; 1643 void *svp, *buf; 1644 1645 index_min = soc_mem_index_min(unit, SOURCE_VPm); 1646 index_max = soc_mem_index_max(unit, SOURCE_VPm); 1647 index_min += 1; /* Always skip entry 0 of SVP table */ 1648 1649 if (!shr_bitop_range_null(f_cml->vp_bitmap, index_min, 1650 (index_max - index_min + 1))) { 1651 buf = soc_cm_salloc(unit, 1652 SOC_MEM_TABLE_BYTES(unit, SOURCE_VPm), 1653 "source_vp for cml restore"); 1654 if (buf == NULL) { 1655 rv = SOC_E_MEMORY; 1656 } 1657 1658 if (SOC_SUCCESS(rv)) { 1659 rv = soc_mem_read_range(unit, SOURCE_VPm, MEM_BLOCK_ANY, 1660 index_min, index_max, buf); 1661 } 1662 if (SOC_SUCCESS(rv)) { 1663 count = 0; 1664 for (index = index_min; index < index_max; index++) { 1665 if (!SHR_BITGET(f_cml->vp_bitmap, index)) { 1666 /* VP not in use */ 1667 continue; 1668 } 1669 buf_index = index - index_min; 1670 svp = soc_mem_table_idx_to_pointer 1671 (unit, SOURCE_VPm, void *, buf, buf_index); 1672 if (soc_mem_field32_get(unit, SOURCE_VPm, svp, 1673 ENTRY_TYPEf) == 0) { 1674 continue; 1675 } 1676 soc_mem_field32_set 1677 (unit, SOURCE_VPm, svp, CML_FLAGS_MOVEf, 1678 f_cml->save_vp_cml_move[buf_index]); 1679 soc_mem_field32_set 1680 (unit, SOURCE_VPm, svp, CML_FLAGS_NEWf, 1681 f_cml->save_vp_cml[buf_index]); 1682 count++; 1683 } 1684 if (count > 0) { 1685 rv = soc_mem_write_range(unit, SOURCE_VPm, 1686 MEM_BLOCK_ANY, index_min, 1687 index_max, buf); 1688 } 1689 } 1690 if (buf != NULL) { 1691 soc_cm_sfree(unit, buf); 1692 } /* Else not using any VPs, don't process the SVP table. */ 1693 } 1694 } 1695 } 1696 1697 /* Regardless of status, decrement frozen count. */ 1698 f_cml->frozen--; 1699 1700 /* Release protection mutex. */ 1701 if (SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 1702 soc_mem_unlock(unit, SOURCE_VPm); 1703 } 1704 if (SOC_MEM_IS_VALID(unit, PORT_TABm)) { 1705 soc_mem_unlock(unit, PORT_TABm); 1706 } 1707 return (rv); 1708 } 1709 1710 1711 /* 1712 * Function: 1713 * _soc_l2x_frozen_cml_save 1714 * Purpose: 1715 * Helper function to preserve port learning mode in sw structure. 1716 * Parameters: 1717 * unit - (IN) BCM device number. 1718 * Returns: 1719 * SOC_E_XXX 1720 */ 1721 int 1722 _soc_l2x_frozen_cml_save(int unit) 1723 { 1724 cml_freeze_t *f_cml = &cml_freeze_state[unit]; /* Cml freeze state.*/ 1725 soc_port_t port; /* Device port iterator. */ 1726 port_tab_entry_t pent; /* Port table hw entry buffer. */ 1727 int rv = SOC_E_NONE; /* Operation return status. */ 1728 soc_pbmp_t pbmp; 1729 1730 #ifdef BCM_TRIDENT2_SUPPORT 1731 if (SOC_IS_TD2_TT2(unit) && 1732 soc_l2x_freeze_mode_is_global_override(unit)) { 1733 return _soc_l2x_td2_frozen_cml_save(unit); 1734 } 1735 #endif 1736 1737 SOC_PBMP_CLEAR(pbmp); 1738 1739 /* Take protection mutex. */ 1740 if (SOC_MEM_IS_VALID(unit, PORT_TABm)) { 1741 soc_mem_lock(unit, PORT_TABm); 1742 } 1743 if (SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 1744 soc_mem_lock(unit, SOURCE_VPm); 1745 } 1746 1747 /* Freezing l2 save l2 learn mode and disable learning. */ 1748 if (f_cml->frozen == 0) { 1749 SOC_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit)); 1750 #ifdef BCM_KATANA2_SUPPORT 1751 if (soc_feature(unit, soc_feature_linkphy_coe) || 1752 soc_feature(unit, soc_feature_subtag_coe)) { 1753 _bcm_kt2_subport_pbmp_update(unit, &pbmp); 1754 } 1755 #endif 1756 PBMP_ITER(pbmp, port) { 1757 /* Read port table entry. */ 1758 if (!SOC_IS_TRIDENT3X(unit)) { 1759 rv = READ_PORT_TAB_MOD_CHK(unit, MEM_BLOCK_ANY, port, &pent); 1760 if (SOC_FAILURE(rv)) { 1761 break; 1762 } 1763 } 1764 #ifdef BCM_TRIDENT3_SUPPORT 1765 if (SOC_IS_TRIDENT3X(unit)) { 1766 /*mem write is not allowed during WB*/ 1767 if (SOC_WARM_BOOT(unit)) { 1768 break; 1769 } 1770 if (f_cml->cml_func == NULL) { 1771 rv = SOC_E_FAIL; 1772 break; 1773 } 1774 rv = f_cml->cml_func(unit, port, TRUE, 1775 &f_cml->save_cml[port], 1776 &f_cml->save_cml_move[port]); 1777 if (SOC_FAILURE(rv)) { 1778 break; 1779 } 1780 } else 1781 #endif /*BCM_TRIDENT3_SUPPORT*/ 1782 #ifdef BCM_TRX_SUPPORT 1783 if (SOC_IS_TRX(unit)) { 1784 f_cml->save_cml[port] = 1785 soc_PORT_TABm_field32_get(unit, &pent, CML_FLAGS_NEWf); 1786 f_cml->save_cml_move[port] = 1787 soc_PORT_TABm_field32_get(unit, &pent, CML_FLAGS_MOVEf); 1788 1789 /* Set bits to the equivilant of DROP and COPY TO CPU */ 1790 soc_PORT_TABm_field32_set(unit, &pent, CML_FLAGS_NEWf, 1791 f_cml->save_cml[port] & 0x03); 1792 soc_PORT_TABm_field32_set(unit, &pent, CML_FLAGS_MOVEf, 1793 f_cml->save_cml_move[port] & 0x03); 1794 rv = WRITE_PORT_TAB_MOD_CHK(unit, MEM_BLOCK_ALL, port, &pent); 1795 if (SOC_FAILURE(rv)) { 1796 break; 1797 } 1798 } else 1799 #endif /* BCM_TRX_SUPPORT */ 1800 { 1801 /* Save current learning mode in sw structure. */ 1802 f_cml->save_cml[port] = soc_PORT_TABm_field32_get(unit, &pent, CMLf); 1803 1804 /* Disable L2 learning on the port. */ 1805 if ((f_cml->save_cml[port] == PVP_CML_SWITCH) || 1806 (f_cml->save_cml[port] == PVP_CML_CPU_SWITCH)) { 1807 soc_PORT_TABm_field32_set(unit, &pent, CMLf, PVP_CML_FORWARD); 1808 rv = WRITE_PORT_TAB_MOD_CHK(unit, MEM_BLOCK_ALL, port, &pent); 1809 if (SOC_FAILURE(rv)) { 1810 break; 1811 } 1812 } 1813 } 1814 } 1815 1816 /* Saving CML value and disable learning on Virtual ports */ 1817 if (SOC_SUCCESS(rv) && SOC_MEM_IS_VALID(unit, SOURCE_VPm) && 1818 (NULL != f_cml->vp_bitmap)) { 1819 int index, index_min, index_max, buf_index, count; 1820 void *svp, *buf; 1821 1822 index_min = soc_mem_index_min(unit, SOURCE_VPm); 1823 index_max = soc_mem_index_max(unit, SOURCE_VPm); 1824 index_min += 1; /* Always skip entry 0 of SVP table */ 1825 1826 if (!shr_bitop_range_null(f_cml->vp_bitmap, index_min, 1827 (index_max - index_min + 1))) { 1828 buf = soc_cm_salloc(unit, 1829 SOC_MEM_TABLE_BYTES(unit, SOURCE_VPm), 1830 "source_vp for cml restore"); 1831 if (buf == NULL) { 1832 rv = SOC_E_MEMORY; 1833 } 1834 1835 if (SOC_SUCCESS(rv)) { 1836 rv = soc_mem_read_range(unit, SOURCE_VPm, MEM_BLOCK_ANY, 1837 index_min, index_max, buf); 1838 } 1839 if (SOC_SUCCESS(rv)) { 1840 count = 0; 1841 for (index = index_min; index < index_max; index++) { 1842 if (!SHR_BITGET(f_cml->vp_bitmap, index)) { 1843 /* VP not in use */ 1844 continue; 1845 } 1846 buf_index = index - index_min; 1847 svp = soc_mem_table_idx_to_pointer 1848 (unit, SOURCE_VPm, void *, buf, buf_index); 1849 if (soc_mem_field32_get(unit, SOURCE_VPm, svp, 1850 ENTRY_TYPEf) == 0) { 1851 continue; 1852 } 1853 f_cml->save_vp_cml_move[buf_index] = 1854 soc_mem_field32_get(unit, SOURCE_VPm, svp, 1855 CML_FLAGS_MOVEf); 1856 f_cml->save_vp_cml[buf_index] = 1857 soc_mem_field32_get(unit, SOURCE_VPm, svp, 1858 CML_FLAGS_NEWf); 1859 /* Set bits to the equivilant of DROP and COPY TO CPU */ 1860 soc_mem_field32_set(unit, SOURCE_VPm, svp, 1861 CML_FLAGS_MOVEf, 1862 f_cml->save_vp_cml_move[buf_index] & 1863 0x03); 1864 soc_mem_field32_set(unit, SOURCE_VPm, svp, 1865 CML_FLAGS_NEWf, 1866 f_cml->save_vp_cml[buf_index] & 1867 0x03); 1868 count++; 1869 } 1870 if (count > 0) { 1871 rv = soc_mem_write_range(unit, SOURCE_VPm, 1872 MEM_BLOCK_ANY, index_min, 1873 index_max, buf); 1874 } 1875 } 1876 if (buf != NULL) { 1877 soc_cm_sfree(unit, buf); 1878 } 1879 } /* Else not using any VPs, don't process the SVP table. */ 1880 } 1881 } 1882 1883 /* Increase CML frozen indicator. */ 1884 if (SOC_SUCCESS(rv)) { 1885 f_cml->frozen++; 1886 } 1887 if (SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 1888 soc_mem_unlock(unit, SOURCE_VPm); /* UNLOCK Virtual port */ 1889 } 1890 if (SOC_MEM_IS_VALID(unit, PORT_TABm)) { 1891 soc_mem_unlock(unit, PORT_TABm); /* PORT_UNLOCK */ 1892 } 1893 return(rv); 1894 } 1895 1896 /* 1897 * Function: 1898 * soc_l2x_is_frozen 1899 * Purpose: 1900 * Provides indication if L3 table is in frozen state 1901 * Parameters: 1902 * unit - (IN) BCM device number. 1903 * frozen - (OUT) TRUE if L2x is frozen, FLASE otherwise 1904 * Returns: 1905 * SOC_E_NONE 1906 * Notes: 1907 * Does not change the frozen status of L2x table only reads it. 1908 */ 1909 1910 int 1911 soc_l2x_is_frozen(int unit, int frozen_type, int *frozen) 1912 { 1913 l2_freeze_t *f_l2 = &l2_freeze_state[unit]; 1914 1915 #ifdef BCM_TRIUMPH3_SUPPORT 1916 if (SOC_IS_TRIUMPH3(unit)) { 1917 return soc_tr3_l2_is_frozen(unit, frozen); 1918 } 1919 #endif 1920 if (frozen_type == SOC_L2X_FROZEN_WITH_LOCK) { 1921 *frozen = (f_l2->frozen > 0) ? TRUE : FALSE ; 1922 } else if (frozen_type == SOC_L2X_FROZEN_WITHOUT_LOCK) { 1923 *frozen = (f_l2->hw_frozen > 0) ? TRUE : FALSE ; 1924 } else { 1925 *frozen = (f_l2->frozen > 0 || f_l2->hw_frozen > 0) ? TRUE : FALSE ; 1926 } 1927 return (SOC_E_NONE); 1928 } 1929 1930 /* 1931 * Function: 1932 * soc_age_timer_cache_set 1933 * Purpose: 1934 * set value of l2_freeze_state[unit].save_age_ena 1935 * and l2_freeze_state[unit].save_age_sec 1936 * Parameters: 1937 * unit - (IN) BCM device number. 1938 * Returns: 1939 * NONE 1940 */ 1941 void 1942 soc_age_timer_cache_set(int unit, int age_seconds, int enabled) 1943 { 1944 l2_freeze_t *f_l2 = &l2_freeze_state[unit]; 1945 1946 f_l2->save_age_sec = age_seconds; 1947 f_l2->save_age_ena = enabled; 1948 f_l2->new_age_set = 1; 1949 return; 1950 } 1951 1952 /* 1953 * Function: 1954 * soc_age_timer_cache_get 1955 * Purpose: 1956 * get value of l2_freeze_state[unit].save_age_ena 1957 * and l2_freeze_state[unit].save_age_sec 1958 * Parameters: 1959 * unit - (IN) BCM device number. 1960 * Returns: 1961 * NONE 1962 */ 1963 void 1964 soc_age_timer_cache_get(int unit, int *age_seconds, int *enabled) 1965 { 1966 l2_freeze_t *f_l2 = &l2_freeze_state[unit]; 1967 1968 *age_seconds = f_l2->save_age_sec; 1969 *enabled = f_l2->save_age_ena; 1970 return; 1971 } 1972 1973 /* 1974 * Function: 1975 * soc_l2x_selective_freeze 1976 * Purpose: 1977 * Temporarily quiesce L2 table from H/W activity (learning, aging) 1978 * Does not quiesce S/W activity 1979 * Parameters: 1980 * unit - (IN) BCM device number. 1981 * freeze_mode -(IN) 1: Only H/W is frozen 1982 * Returns: 1983 * SOC_E_XXX 1984 */ 1985 1986 /*soc_l2x_selective_freeze matches with soc_l2x_selective_thaw */ 1987 int 1988 soc_l2x_selective_freeze(int unit, int freeze_mode) 1989 { 1990 l2_freeze_t *f_l2 = &l2_freeze_state[unit]; 1991 int rv = SOC_E_NONE; 1992 int age_sec = 0; 1993 int age_ena = 0; 1994 1995 /* Check if already frozen. */ 1996 SOC_L2X_MEM_LOCK(unit); 1997 if (f_l2->frozen > 0 || f_l2->hw_frozen > 0) { 1998 /* Keep count - do nothing. */ 1999 if (freeze_mode == SOC_L2X_FROZEN_WITH_LOCK) { 2000 f_l2->frozen++; 2001 } else { 2002 f_l2->hw_frozen++; 2003 } 2004 SOC_L2X_MEM_UNLOCK(unit); 2005 return (SOC_E_NONE); 2006 } 2007 2008 /* 2009 * Increase l2 frozen indicator in the beginning to 2010 * avoid _soc_l2x_frozen_cml_save() being called twice 2011 * in reentrance unexpectedly. 2012 */ 2013 if (freeze_mode == SOC_L2X_FROZEN_WITH_LOCK) { 2014 f_l2->frozen++; 2015 } else { 2016 f_l2->hw_frozen++; 2017 } 2018 SOC_L2X_MEM_UNLOCK(unit); 2019 2020 /* Preserve ports learning mode & disable learning. */ 2021 rv = _soc_l2x_frozen_cml_save(unit); 2022 if (SOC_FAILURE(rv)) { 2023 /* Decrease l2 frozen indicator. */ 2024 if (freeze_mode == SOC_L2X_FROZEN_WITH_LOCK) { 2025 f_l2->frozen--; 2026 } else { 2027 f_l2->hw_frozen--; 2028 } 2029 return rv; 2030 } 2031 2032 /* 2033 * Lock l2x, disable learning and aging. 2034 */ 2035 SOC_L2X_MEM_LOCK(unit); 2036 2037 /* Read l2 aging interval. */ 2038 rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, 2039 &age_sec, 2040 &age_ena); 2041 if (SOC_FAILURE(rv)) { 2042 /* Decrease l2 frozen indicator. */ 2043 if (freeze_mode == SOC_L2X_FROZEN_WITH_LOCK) { 2044 f_l2->frozen--; 2045 } else { 2046 f_l2->hw_frozen--; 2047 } 2048 SOC_L2X_MEM_UNLOCK(unit); 2049 _soc_l2x_frozen_cml_restore(unit); 2050 return rv; 2051 } 2052 /* If use bcm_esw_l2_age_timer_set to set new age seconde, we use new age_sec. */ 2053 if (!f_l2->new_age_set) { 2054 f_l2->save_age_sec = age_sec; 2055 f_l2->save_age_ena = age_ena; 2056 } 2057 /* If l2 aging is on - disable it. */ 2058 /* If use bcm_esw_l2_age_timer_set to set new age seconde as 0 - save it. */ 2059 if (f_l2->save_age_ena || f_l2->new_age_set) { 2060 rv = SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, 2061 f_l2->save_age_sec, 0); 2062 if (SOC_FAILURE(rv)) { 2063 /* Decrease l2 frozen indicator. */ 2064 if (freeze_mode == SOC_L2X_FROZEN_WITH_LOCK) { 2065 f_l2->frozen--; 2066 } else { 2067 f_l2->hw_frozen--; 2068 } 2069 SOC_L2X_MEM_UNLOCK(unit); 2070 _soc_l2x_frozen_cml_restore(unit); 2071 return rv; 2072 } 2073 f_l2->new_age_set = 0; 2074 } 2075 2076 SOC_L2X_MEM_UNLOCK(unit); 2077 return (SOC_E_NONE); 2078 } 2079 /* 2080 * Function: 2081 * soc_l2x_freeze 2082 * Purpose: 2083 * Temporarily quiesce L2 table from all activity (learning, aging) 2084 * Include H/W and S/W activity 2085 * Parameters: 2086 * unit - (IN) BCM device number. 2087 * Returns: 2088 * SOC_E_XXX 2089 */ 2090 int 2091 soc_l2x_freeze(int unit) 2092 { 2093 #ifdef BCM_TRIUMPH3_SUPPORT 2094 if (SOC_IS_TRIUMPH3(unit)) { 2095 return soc_tr3_l2_freeze(unit); 2096 } 2097 #endif 2098 2099 SOC_IF_ERROR_RETURN(soc_l2x_selective_freeze(unit, SOC_L2X_FROZEN_WITH_LOCK)); 2100 2101 SOC_L2X_MEM_LOCK(unit); 2102 2103 return (SOC_E_NONE); 2104 } 2105 2106 /* 2107 * Function: 2108 * soc_l2x_selective_thaw 2109 * Purpose: 2110 * Restore normal L2 H/W activity. 2111 * Parameters: 2112 * unit - (IN) BCM device number. 2113 * thaw_mode - Only H/W is thawed 2114 * Returns: 2115 * SOC_E_XXX 2116 */ 2117 /*soc_l2x_selective_freeze matches with soc_l2x_selective_thaw */ 2118 int 2119 soc_l2x_selective_thaw(int unit, int thaw_mode) 2120 { 2121 l2_freeze_t *f_l2 = &l2_freeze_state[unit]; 2122 int l2rv, cmlrv; 2123 2124 /* Sanity check to protect from thaw without freeze. */ 2125 SOC_L2X_MEM_LOCK(unit); 2126 if (thaw_mode == SOC_L2X_FROZEN_WITH_LOCK) { 2127 if (f_l2->frozen == 0) { 2128 SOC_L2X_MEM_UNLOCK(unit); 2129 assert(0); 2130 return (SOC_E_UNAVAIL); 2131 } 2132 /* In case of nested freeze/thaw just decrement reference counter. */ 2133 if (f_l2->frozen > 1 || 2134 (f_l2->frozen == 1 && f_l2->hw_frozen > 0)) { 2135 f_l2->frozen--; 2136 SOC_L2X_MEM_UNLOCK(unit); 2137 return (SOC_E_NONE); 2138 } 2139 } else { 2140 if (f_l2->hw_frozen == 0) { 2141 SOC_L2X_MEM_UNLOCK(unit); 2142 return (SOC_E_NONE); 2143 } 2144 /* In case of nested freeze/thaw just decrement reference counter. */ 2145 if (f_l2->hw_frozen > 1 || 2146 (f_l2->hw_frozen == 1 && f_l2->frozen > 0)) { 2147 f_l2->hw_frozen--; 2148 SOC_L2X_MEM_UNLOCK(unit); 2149 return (SOC_E_NONE); 2150 } 2151 } 2152 /* 2153 * Last thaw restore L2 learning and aging. 2154 */ 2155 l2rv = SOC_E_NONE; 2156 /* If use bcm_esw_l2_age_timer_set to set new age seconde as 0 - save it. */ 2157 if (f_l2->save_age_ena || f_l2->new_age_set) { 2158 l2rv = SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, 2159 f_l2->save_age_sec, 2160 f_l2->save_age_ena); 2161 f_l2->new_age_set = 0; 2162 } 2163 2164 /* L2 freeze reference counter decrement. */ 2165 if (thaw_mode == SOC_L2X_FROZEN_WITH_LOCK) { 2166 f_l2->frozen--; 2167 } else { 2168 f_l2->hw_frozen--; 2169 } 2170 2171 SOC_L2X_MEM_UNLOCK(unit); 2172 2173 /* Restore port learning mode. */ 2174 cmlrv = _soc_l2x_frozen_cml_restore(unit); 2175 2176 if (SOC_FAILURE(l2rv)) { 2177 return l2rv; 2178 } 2179 return cmlrv; 2180 } 2181 2182 /* 2183 * Function: 2184 * soc_l2x_thaw 2185 * Purpose: 2186 * Restore normal L2 activity. 2187 * Parameters: 2188 * unit - (IN) BCM device number. 2189 * Returns: 2190 * SOC_E_XXX 2191 */ 2192 2193 int 2194 soc_l2x_thaw(int unit) 2195 { 2196 2197 #ifdef BCM_TRIUMPH3_SUPPORT 2198 if (SOC_IS_TRIUMPH3(unit)) { 2199 return soc_tr3_l2_thaw(unit); 2200 } 2201 #endif 2202 2203 SOC_L2X_MEM_UNLOCK(unit); 2204 2205 return soc_l2x_selective_thaw(unit, SOC_L2X_FROZEN_WITH_LOCK); 2206 } 2207 2208 /* 2209 * Function: 2210 * soc_l2x_frozen_cml_set 2211 * Purpose: 2212 * Update the saved Cpu Managed Learning mode for a port 2213 * if the device is frozen. 2214 * Parameters: 2215 * unit device number 2216 * port port number 2217 * cml Cpu-Managed-Learning mode to update 2218 * cml_move Station move Cpu-Managed-Learning mode to update 2219 * repl_cml CML mode to use in port table update 2220 * repl_cml_move Station move CML mode to use in port table update 2221 * Returns: 2222 * SOC_E_NONE frozen cml is updated 2223 * SOC_E_FAIL unit is not frozen 2224 * 2225 * NOTE: 2226 * PORT_TAB must be locked when calling this routine. 2227 */ 2228 int 2229 soc_l2x_frozen_cml_set(int unit, soc_port_t port, int cml, int cml_move, int *repl_cml, int *repl_cml_move) 2230 { 2231 cml_freeze_t *f_cml = &cml_freeze_state[unit]; 2232 int frozen = 0; 2233 2234 if (SOC_IS_TD2_TT2(unit) && 2235 soc_l2x_freeze_mode_is_global_override(unit)) { 2236 return SOC_E_UNAVAIL; 2237 } 2238 2239 #if defined(BCM_TRIUMPH3_SUPPORT) 2240 if (SOC_IS_TRIUMPH3(unit)) { 2241 soc_tr3_l2_is_frozen(unit, &frozen); 2242 } else 2243 #endif 2244 { 2245 frozen = f_cml->frozen; 2246 } 2247 2248 if (frozen) { 2249 f_cml->save_cml[port] = cml; 2250 f_cml->save_cml_move[port] = cml_move; 2251 if (repl_cml != NULL) { 2252 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_TRX_SUPPORT) 2253 if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRX(unit)) { 2254 /* Since L2 is frozen, bits 4, 3 should be clear, they would 2255 reflect the actual value after thaw */ 2256 *repl_cml = (cml & 0x3); 2257 } else 2258 #endif 2259 { 2260 *repl_cml = PVP_CML_FORWARD; 2261 } 2262 } 2263 if (repl_cml_move != NULL) { 2264 #if defined(BCM_TRIUMPH3_SUPPORT) || defined(BCM_TRX_SUPPORT) 2265 if (SOC_IS_TRIUMPH3(unit) || SOC_IS_TRX(unit)) { 2266 /* Since L2 is frozen, bits 4, 3 should be clear, they would 2267 reflect the actual value after thaw */ 2268 *repl_cml_move = (cml_move & 0x3); 2269 } else 2270 #endif 2271 { 2272 *repl_cml_move = PVP_CML_FORWARD; 2273 } 2274 } 2275 2276 return SOC_E_NONE; 2277 } 2278 return SOC_E_FAIL; 2279 } 2280 2281 /* 2282 * Function: 2283 * soc_l2x_frozen_cml_get 2284 * Purpose: 2285 * Get the saved Cpu Managed Learning mode for a port 2286 * if the device is frozen. 2287 * Parameters: 2288 * unit device number 2289 * port port number 2290 * cml (OUT) saved Cpu-Managed-Learning mode 2291 * cml_move (OUT) saved Station move Cpu-Managed-Learning mode 2292 * Returns: 2293 * SOC_E_NONE frozen cml is returned 2294 * SOC_E_FAIL unit is not frozen 2295 * 2296 * NOTE: 2297 * PORT_TAB must be locked when calling this routine. 2298 */ 2299 int 2300 soc_l2x_frozen_cml_get(int unit, soc_port_t port, int *cml, int *cml_move) 2301 { 2302 cml_freeze_t *f_cml = &cml_freeze_state[unit]; 2303 int frozen = 0; 2304 2305 if (SOC_IS_TD2_TT2(unit) && 2306 soc_l2x_freeze_mode_is_global_override(unit)) { 2307 return SOC_E_UNAVAIL; 2308 } 2309 2310 #if defined(BCM_TRIUMPH3_SUPPORT) 2311 if (SOC_IS_TRIUMPH3(unit)) { 2312 soc_tr3_l2_is_frozen(unit, &frozen); 2313 } else 2314 #endif 2315 { 2316 frozen = f_cml->frozen; 2317 } 2318 2319 if (frozen) { 2320 if (cml) { 2321 *cml = f_cml->save_cml[port]; 2322 } 2323 if (cml_move) { 2324 *cml_move = f_cml->save_cml_move[port]; 2325 } 2326 2327 return SOC_E_NONE; 2328 } 2329 return SOC_E_FAIL; 2330 } 2331 2332 2333 #ifdef BCM_FIREBOLT_SUPPORT 2334 static int 2335 soc_fb_l2x_entries(int unit) 2336 { 2337 int index_min, index_max, index, total, rv; 2338 uint32 *ent; 2339 uint32 *buf = NULL; 2340 int validf = -1; 2341 2342 2343 index_min = soc_mem_index_min(unit, L2Xm); 2344 index_max = soc_mem_index_max(unit, L2Xm); 2345 buf = soc_cm_salloc(unit, 2346 SOC_MEM_TABLE_BYTES(unit, L2Xm), 2347 "l2x_entries"); 2348 if (buf == NULL) { 2349 return SOC_E_MEMORY; 2350 } 2351 2352 rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY, 2353 index_min, index_max, buf); 2354 2355 if (rv < 0) { 2356 soc_cm_sfree(unit, buf); 2357 return rv; 2358 } 2359 2360 total = 0; 2361 ent = buf; 2362 2363 if (soc_feature(unit, soc_feature_base_valid)) { 2364 validf = BASE_VALIDf; 2365 } else { 2366 validf = VALIDf; 2367 } 2368 2369 for (index = 0; index < (index_max - index_min); index++) { 2370 if (soc_L2Xm_field32_get(unit, ent, validf)) { 2371 total++; 2372 } 2373 ent += soc_mem_entry_words(unit, L2Xm); 2374 } 2375 2376 soc_cm_sfree(unit, buf); 2377 2378 return total; 2379 } 2380 #endif /* BCM_FIREBOLT_SUPPORT */ 2381 2382 /* 2383 * Function: 2384 * soc_l2x_entries 2385 * Purpose: 2386 * Return number of valid entries in L2 table. 2387 * Parameters: 2388 * unit - StrataSwitch unit # 2389 * Returns: 2390 * If >= 0, number of entries in L2 table 2391 * If < 0, SOC_E_XXX 2392 * Notes: 2393 * Somewhat slow; has to read whole table. 2394 * New improved: Now with DMA power. 2395 */ 2396 2397 int 2398 soc_l2x_entries(int unit) 2399 { 2400 #ifdef BCM_FIREBOLT_SUPPORT 2401 if (SOC_IS_FBX(unit)) { 2402 return soc_fb_l2x_entries(unit); 2403 } 2404 #endif /* BCM_FIREBOLT_SUPPORT */ 2405 return 0; 2406 } 2407 2408 #ifdef BCM_FIREBOLT_SUPPORT 2409 /* 2410 * Function: 2411 * soc_fb_l2x_bank_lookup 2412 * Purpose: 2413 * Send an L2 lookup message over the S-Channel and receive the 2414 * response. 2415 * Parameters: 2416 * unit - StrataSwitch unit # 2417 * banks - For dual hashing, which halves are selected (inverted) 2418 * key - L2X entry to look up; only MAC+VLAN fields are relevant 2419 * result - L2X entry to receive entire found entry 2420 * index_ptr (OUT) - If found, receives table index where found 2421 * Returns: 2422 * SOC_E_INTERNAL if retries exceeded or other internal error 2423 * SOC_E_NOT_FOUND if the entry is not found. 2424 * SOC_E_NONE (0) on success (entry found): 2425 * Notes: 2426 * The S-Channel response contains either a matching L2 entry, 2427 * or an entry with a key of all f's if not found. It is okay 2428 * if the result pointer is the same as the key pointer. 2429 * Retries the lookup in cases where the particular chip requires it. 2430 */ 2431 2432 int 2433 soc_fb_l2x_bank_lookup(int unit, uint8 banks, 2434 l2x_entry_t *key, l2x_entry_t *result, 2435 int *index_ptr) 2436 { 2437 schan_msg_t schan_msg; 2438 int entry_dw = soc_mem_entry_words(unit, L2Xm); 2439 int nbits; 2440 int rv; 2441 int dst_blk, src_blk, data_byte_len; 2442 uint32 bank_ignore_mask; 2443 int opcode, nack; 2444 2445 schan_msg_clear(&schan_msg); 2446 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 2447 dst_blk = SOC_BLOCK2SCH(unit, IPIPE_BLOCK(unit)); 2448 bank_ignore_mask = banks & 0x3; 2449 data_byte_len = entry_dw * 4; 2450 soc_schan_header_cmd_set(unit, &schan_msg.header, L2_LOOKUP_CMD_MSG, 2451 dst_blk, src_blk, 0, data_byte_len, 0, 2452 bank_ignore_mask); 2453 2454 /* Fill in entry data */ 2455 2456 sal_memcpy(schan_msg.l2x2.data, key, sizeof (schan_msg.l2x2.data)); 2457 2458 /* 2459 * Write onto S-Channel "L2 lookup" command packet consisting of 2460 * header word + three words of L2 key, and read back header 2461 * word + 4 words of lookup result. (index of the extry + contents of 2462 * the entry) 2463 */ 2464 2465 rv = soc_schan_op(unit, &schan_msg, entry_dw + 1, entry_dw + 2, 1); 2466 2467 /* Check result */ 2468 soc_schan_header_status_get(unit, &schan_msg.header, &opcode, NULL, NULL, 2469 NULL, NULL, &nack); 2470 if (opcode != L2_LOOKUP_ACK_MSG) { 2471 LOG_ERROR(BSL_LS_SOC_L2, 2472 (BSL_META_U(unit, 2473 "soc_fb_l2x_bank_lookup: " 2474 "invalid S-Channel reply, expected L2_LOOKUP_ACK_MSG:\n"))); 2475 soc_schan_dump(unit, &schan_msg, entry_dw + 2); 2476 return SOC_E_INTERNAL; 2477 } 2478 2479 /* 2480 * Fill in result entry from read data. 2481 * 2482 * Format of S-Channel response: 2483 * readresp.header : L2 lookup Ack S-channel header 2484 * readresp.data[0]: index of the entry in the L2Xm Table 2485 * readresp.data[1-3]: entry contents 2486 * ============================================================= 2487 * | PERR_PBM | MFIFO_FULL | OP_FAIL | Index | L2x entry data | 2488 * ============================================================= 2489 */ 2490 nbits = soc_mem_entry_bits(unit, L2Xm) % 32; /* Data Bits in last word */ 2491 2492 if ((nack != 0) || (rv == SOC_E_FAIL)) { 2493 *index_ptr = -1; 2494 if (soc_feature(unit, soc_feature_l2x_parity)) { 2495 int op_fail_pos; 2496 op_fail_pos = SOC_L2X_OP_FAIL_POS(unit); 2497 if ((schan_msg.readresp.data[3] >> (op_fail_pos + 2)) & 0xff) { 2498 uint32 index = (schan_msg.readresp.data[2] >> nbits) & 2499 ((1 << (32 - nbits)) - 1); 2500 index |= (schan_msg.readresp.data[3] << (32 - nbits)) & 2501 soc_mem_index_max(unit, L2Xm); /* Assume size of table 2^N */ 2502 LOG_ERROR(BSL_LS_SOC_L2, 2503 (BSL_META_U(unit, 2504 "Lookup table[L2Xm]: Parity Error Index %d Bucket Bitmap 0x%08x\n"), 2505 index, 2506 (schan_msg.readresp.data[3] >> (op_fail_pos + 2)) & 0xff )); 2507 return SOC_E_INTERNAL; 2508 } 2509 } 2510 return SOC_E_NOT_FOUND; 2511 } 2512 2513 /* MACADDR<31:0> */ 2514 result->entry_data[0] = schan_msg.readresp.data[0]; 2515 2516 /* CPU, PRI<2:0>, VLAN<12:0>, MACADDR<47:32> */ 2517 result->entry_data[1] = schan_msg.readresp.data[1]; 2518 2519 /* HIT SA, HIT DA, VALID, MIRROR, RPE, STATIC_BIT, RESERVED, 2520 * MAC_BLOCK_INDEX, L3 MODULE_ID, PORT_TGID, SCP, SRC_DISCARD, 2521 * DST_DISCARD 2522 */ 2523 result->entry_data[2] = schan_msg.readresp.data[2] & ((1 << nbits) - 1); 2524 2525 *index_ptr = (schan_msg.readresp.data[2] >> nbits) & 2526 ((1 << (32 - nbits)) - 1); 2527 *index_ptr |= (schan_msg.readresp.data[3] << (32 - nbits)); 2528 *index_ptr &= soc_mem_index_max(unit, L2Xm); /* Assume size of table 2^N */ 2529 if (bsl_check(bslLayerSoc, bslSourceSocmem, bslSeverityNormal, unit)) { 2530 LOG_INFO(BSL_LS_SOC_SOCMEM, 2531 (BSL_META_U(unit, 2532 "L2 entry lookup: "))); 2533 soc_mem_entry_dump(unit, L2Xm, result, BSL_INFO|BSL_LS_SOC_SOCMEM); 2534 LOG_INFO(BSL_LS_SOC_SOCMEM, 2535 (BSL_META_U(unit, 2536 " (index=%d)\n"), *index_ptr)); 2537 } 2538 2539 return SOC_E_NONE; 2540 } 2541 2542 /* 2543 * Function: 2544 * soc_fb_l2x_bank_insert 2545 * Purpose: 2546 * Insert an entry into the L2X hash table. 2547 * Parameters: 2548 * unit - StrataSwitch unit # 2549 * banks - For dual hashing, which halves are selected (inverted) 2550 * entry - L2X entry to insert 2551 * Returns: 2552 * SOC_E_NONE - success 2553 * SOC_E_FULL - hash bucket full 2554 * SOC_E_BUSY - modfifo full 2555 * Notes: 2556 * Uses hardware insertion; sends an L2 INSERT message over the 2557 * S-Channel. The hardware needs the L2Xm entry type. 2558 */ 2559 2560 int 2561 soc_fb_l2x_bank_insert(int unit, uint8 banks, l2x_entry_t *entry) 2562 { 2563 schan_msg_t schan_msg; 2564 int rv; 2565 int op_fail_pos; 2566 int entry_dw = soc_mem_entry_words(unit, L2Xm); 2567 int nbits; 2568 int dst_blk, src_blk, data_byte_len; 2569 uint32 bank_ignore_mask; 2570 int opcode, nack; 2571 2572 if (bsl_check(bslLayerSoc, bslSourceSocmem, bslSeverityNormal, unit)) { 2573 LOG_INFO(BSL_LS_SOC_SOCMEM, 2574 (BSL_META_U(unit, 2575 "Insert table[L2_ENTRY]: "))); 2576 soc_mem_entry_dump(unit, L2Xm, entry, BSL_INFO|BSL_LS_SOC_SOCMEM); 2577 LOG_INFO(BSL_LS_SOC_SOCMEM, 2578 (BSL_META_U(unit, 2579 "\n"))); 2580 } 2581 2582 schan_msg_clear(&schan_msg); 2583 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 2584 dst_blk = SOC_BLOCK2SCH(unit, IPIPE_BLOCK(unit)); 2585 bank_ignore_mask = banks & 0x3; 2586 data_byte_len = entry_dw * 4; 2587 soc_schan_header_cmd_set(unit, &schan_msg.header, ARL_INSERT_CMD_MSG, 2588 dst_blk, src_blk, 0, data_byte_len, 0, 2589 bank_ignore_mask); 2590 2591 /* Fill in ARL packet data */ 2592 2593 sal_memcpy(schan_msg.l2x2.data, entry, sizeof (schan_msg.l2x2.data)); 2594 2595 /* Execute S-Channel operation (header word + 3 DWORDs) */ 2596 2597 rv = soc_schan_op(unit, &schan_msg, entry_dw + 1, entry_dw + 2, 1); 2598 2599 soc_schan_header_status_get(unit, &schan_msg.header, &opcode, NULL, NULL, 2600 NULL, NULL, &nack); 2601 if (opcode != ARL_INSERT_DONE_MSG) { 2602 LOG_ERROR(BSL_LS_SOC_L2, 2603 (BSL_META_U(unit, 2604 "soc_fb_l2x_bank_insert: " 2605 "invalid S-Channel reply, expected L2_INSERT_ACK_MSG:\n"))); 2606 soc_schan_dump(unit, &schan_msg, 1); 2607 return SOC_E_INTERNAL; 2608 } 2609 2610 /* 2611 * ============================================================= 2612 * | PERR_PBM | MFIFO_FULL | OP_FAIL | Index | L2x entry data | 2613 * ============================================================= 2614 */ 2615 nbits = soc_mem_entry_bits(unit, L2Xm) % 32; /* Data Bits in last word */ 2616 op_fail_pos = SOC_L2X_OP_FAIL_POS(unit); 2617 2618 /* bit-106 OP_FAIL; bit-107 ModFifo Full */ 2619 if ((nack != 0) || (rv == SOC_E_FAIL)) { 2620 if (schan_msg.readresp.data[3] & (1 << op_fail_pos)) { 2621 LOG_INFO(BSL_LS_SOC_SOCMEM, 2622 (BSL_META_U(unit, 2623 "Insert table[L2Xm]: hash bucket full\n"))); 2624 rv = SOC_E_FULL; 2625 } else if (schan_msg.readresp.data[3] & (1 << (op_fail_pos + 1))) { 2626 LOG_INFO(BSL_LS_SOC_SOCMEM, 2627 (BSL_META_U(unit, 2628 "Insert table[L2Xm]: Modfifo full\n"))); 2629 rv = SOC_E_BUSY; 2630 } else if (soc_feature(unit, soc_feature_l2x_parity) && 2631 ((schan_msg.readresp.data[3] >> (op_fail_pos + 2)) & 0xff)) { 2632 uint32 index = (schan_msg.readresp.data[2] >> nbits) & 2633 ((1 << (32 - nbits)) - 1); 2634 index |= (schan_msg.readresp.data[3] << (32 - nbits)) & 2635 soc_mem_index_max(unit, L2Xm); /* Assume size of table 2^N */ 2636 LOG_ERROR(BSL_LS_SOC_L2, 2637 (BSL_META_U(unit, 2638 "Insert table[L2Xm]: Parity Error Index %d Bucket Bitmap 0x%08x\n"), 2639 index, 2640 (schan_msg.readresp.data[3] >> (op_fail_pos + 2)) & 0xff )); 2641 rv = SOC_E_INTERNAL; 2642 } else { 2643 rv = SOC_E_FAIL; 2644 } 2645 } 2646 2647 return rv; 2648 } 2649 2650 /* 2651 * Function: 2652 * soc_fb_l2x_bank_delete 2653 * Purpose: 2654 * Delete an entry from the L2X hash table. 2655 * Parameters: 2656 * unit - StrataSwitch unit # 2657 * banks - For dual hashing, which halves are selected (inverted) 2658 * entry - L2X entry to delete 2659 * Returns: 2660 * SOC_E_NONE - success 2661 * SOC_E_NOT_FOUND - hash bucket full 2662 * SOC_E_BUSY - modfifo full 2663 * Notes: 2664 * Uses hardware deletion; sends an L2 DELETE message over the 2665 * S-Channel. The hardware needs the L2Xm entry type. 2666 */ 2667 2668 int 2669 soc_fb_l2x_bank_delete(int unit, uint8 banks, l2x_entry_t *entry) 2670 { 2671 schan_msg_t schan_msg; 2672 int rv; 2673 int op_fail_pos; 2674 int nbits; 2675 int entry_dw = soc_mem_entry_words(unit, L2Xm); 2676 int dst_blk, src_blk, data_byte_len; 2677 uint32 bank_ignore_mask; 2678 int opcode, nack; 2679 2680 if (bsl_check(bslLayerSoc, bslSourceSocmem, bslSeverityNormal, unit)) { 2681 LOG_INFO(BSL_LS_SOC_SOCMEM, 2682 (BSL_META_U(unit, 2683 "Delete table[L2Xm]: "))); 2684 soc_mem_entry_dump(unit, L2Xm, entry, BSL_INFO|BSL_LS_SOC_SOCMEM); 2685 LOG_INFO(BSL_LS_SOC_SOCMEM, 2686 (BSL_META_U(unit, 2687 "\n"))); 2688 } 2689 2690 schan_msg_clear(&schan_msg); 2691 src_blk = SOC_BLOCK2SCH(unit, CMIC_BLOCK(unit)); 2692 dst_blk = SOC_BLOCK2SCH(unit, IPIPE_BLOCK(unit)); 2693 bank_ignore_mask = banks & 0x3; 2694 data_byte_len = entry_dw * 4; 2695 soc_schan_header_cmd_set(unit, &schan_msg.header, ARL_DELETE_CMD_MSG, 2696 dst_blk, src_blk, 0, data_byte_len, 0, 2697 bank_ignore_mask); 2698 2699 /* Fill in packet data */ 2700 2701 sal_memcpy(schan_msg.l2x2.data, entry, sizeof (schan_msg.l2x2.data)); 2702 2703 /* Execute S-Channel operation (header word + 2 DWORDs) */ 2704 rv = soc_schan_op(unit, &schan_msg, entry_dw + 1, entry_dw + 2, 1); 2705 2706 soc_schan_header_status_get(unit, &schan_msg.header, &opcode, NULL, NULL, 2707 NULL, NULL, &nack); 2708 if (opcode != ARL_DELETE_DONE_MSG) { 2709 LOG_ERROR(BSL_LS_SOC_L2, 2710 (BSL_META_U(unit, 2711 "soc_fb_l2x_bank_delete: " 2712 "invalid S-Channel reply, expected L2_DELETE_ACK_MSG:\n"))); 2713 soc_schan_dump(unit, &schan_msg, 1); 2714 return SOC_E_INTERNAL; 2715 } 2716 2717 /* 2718 * ============================================================= 2719 * | PERR_PBM | MFIFO_FULL | OP_FAIL | Index | L2x entry data | 2720 * ============================================================= 2721 */ 2722 nbits = soc_mem_entry_bits(unit, L2Xm) % 32; /* Data Bits in last word */ 2723 op_fail_pos = SOC_L2X_OP_FAIL_POS(unit); 2724 2725 /* bit-106 OP_FAIL; bit-107 ModFifo Full */ 2726 if ((nack != 0) || (rv == SOC_E_FAIL)) { 2727 if (schan_msg.readresp.data[3] & (1 << op_fail_pos)) { 2728 LOG_INFO(BSL_LS_SOC_SOCMEM, 2729 (BSL_META_U(unit, 2730 "Delete table[L2Xm]: Not found\n"))); 2731 rv = SOC_E_NOT_FOUND; 2732 } else if (schan_msg.readresp.data[3] & (1 << (op_fail_pos + 1))) { 2733 LOG_INFO(BSL_LS_SOC_SOCMEM, 2734 (BSL_META_U(unit, 2735 "Delete table[L2Xm]: Modfifo full\n"))); 2736 rv = SOC_E_BUSY; 2737 } else if (soc_feature(unit, soc_feature_l2x_parity) && 2738 ((schan_msg.readresp.data[3] >> (op_fail_pos + 2)) & 0xff)) { 2739 uint32 index = (schan_msg.readresp.data[2] >> nbits) & 2740 ((1 << (32 - nbits)) - 1); 2741 index |= (schan_msg.readresp.data[3] << (32 - nbits)) & 2742 soc_mem_index_max(unit, L2Xm); /* Assume size of table 2^N */ 2743 LOG_ERROR(BSL_LS_SOC_L2, 2744 (BSL_META_U(unit, 2745 "Delete table[L2Xm]: Parity Error Index %d Bucket Bitmap 0x%08x\n"), 2746 index, 2747 (schan_msg.readresp.data[3] >> (op_fail_pos + 2)) & 0xff )); 2748 rv = SOC_E_INTERNAL; 2749 } else { 2750 rv = SOC_E_FAIL; 2751 } 2752 } 2753 2754 return rv; 2755 } 2756 2757 /* 2758 * Original non-bank versions of the FB L2X table op functions 2759 */ 2760 2761 int 2762 soc_fb_l2x_insert(int unit, l2x_entry_t *entry) 2763 { 2764 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) || \ 2765 defined(BCM_TRX_SUPPORT) 2766 if (soc_feature(unit, soc_feature_dual_hash)) { 2767 return 2768 _soc_mem_dual_hash_insert(unit, L2Xm, COPYNO_ALL, (void *)entry, 2769 NULL, SOC_DUAL_HASH_MOVE_MAX_L2X(unit)); 2770 } else 2771 #endif 2772 { 2773 return soc_fb_l2x_bank_insert(unit, 0, entry); 2774 } 2775 } 2776 2777 int 2778 soc_fb_l2x_delete(int unit, l2x_entry_t *entry) 2779 { 2780 return soc_fb_l2x_bank_delete(unit, 0, entry); 2781 } 2782 2783 int 2784 soc_fb_l2x_lookup(int unit, l2x_entry_t *key, 2785 l2x_entry_t *result, int *index_ptr) 2786 { 2787 return soc_fb_l2x_bank_lookup(unit, 0, key, result, index_ptr); 2788 } 2789 2790 /* 2791 * Function: 2792 * soc_fb_l2x_delete_all 2793 * Purpose: 2794 * Clear the L2 table by invalidating entries. 2795 * Parameters: 2796 * unit - StrataSwitch unit # 2797 * static_too - if TRUE, delete static and non-static entries; 2798 * if FALSE, delete only non-static entries 2799 * Returns: 2800 * SOC_E_XXX 2801 */ 2802 2803 int 2804 soc_fb_l2x_delete_all(int unit) 2805 { 2806 soc_control_t *soc = SOC_CONTROL(unit); 2807 int index_min, index_max, index, mem_max; 2808 l2x_entry_t *l2x_entry; 2809 int rv = SOC_E_NONE; 2810 int *buffer = NULL; 2811 int mem_size, idx; 2812 2813 index_min = soc_mem_index_min(unit, L2_ENTRY_ONLYm); 2814 mem_max = soc_mem_index_max(unit, L2_ENTRY_ONLYm); 2815 mem_size = DEFAULT_L2DELETE_CHUNKS * sizeof(l2x_entry_t); 2816 2817 buffer = soc_cm_salloc(unit, mem_size, "L2X_delete"); 2818 if (NULL == buffer) { 2819 return SOC_E_MEMORY; 2820 } 2821 2822 soc_mem_lock(unit, L2Xm); 2823 for (idx = index_min; idx < mem_max; idx += DEFAULT_L2DELETE_CHUNKS) { 2824 index_max = idx + DEFAULT_L2DELETE_CHUNKS - 1; 2825 if ( index_max > mem_max) { 2826 index_max = mem_max; 2827 } 2828 if ((rv = soc_mem_read_range(unit, L2_ENTRY_ONLYm, MEM_BLOCK_ANY, 2829 idx, index_max, buffer)) < 0 ) { 2830 break; 2831 } 2832 for (index = 0; index < index_max - idx + 1; index++) { 2833 l2x_entry = 2834 soc_mem_table_idx_to_pointer(unit, L2_ENTRY_ONLYm, 2835 l2x_entry_t *, buffer, index); 2836 sal_memcpy(l2x_entry, soc_mem_entry_null(unit, L2_ENTRY_ONLYm), 2837 sizeof(l2x_entry_t)); 2838 } 2839 if ((rv = soc_mem_write_range(unit, L2_ENTRY_ONLYm, MEM_BLOCK_ALL, 2840 idx, index_max, buffer)) < 0) { 2841 break; 2842 } 2843 } 2844 soc_mem_unlock(unit, L2Xm); 2845 2846 if (soc->arlShadow != NULL) { 2847 sal_mutex_take(soc->arlShadowMutex, sal_mutex_FOREVER); 2848 (void) shr_avl_delete_all(soc->arlShadow); 2849 sal_mutex_give(soc->arlShadowMutex); 2850 } 2851 soc_cm_sfree(unit, buffer); 2852 2853 2854 return rv; 2855 } 2856 2857 #endif /* BCM_FIREBOLT_SUPPORT */ 2858 2859 #if defined(BCM_TOMAHAWK3_SUPPORT) 2860 /* 2861 * Function: 2862 * soc_th3_l2x_reset_freeze_state 2863 * Purpose: 2864 * This function clears aging related information during attach sequence 2865 * Parameters: 2866 * unit - StrataSwitch unit number 2867 * Returns: 2868 * No value 2869 */ 2870 void soc_th3_l2x_reset_freeze_state(int unit) 2871 { 2872 sal_memset(l2_freeze_state + unit, 0, sizeof(l2_freeze_t)); 2873 } 2874 #endif /* BCM_TOMAHAWK3_SUPPORT */ 2875 2876 #endif /* BCM_XGS_SWITCH_SUPPORT */