l2.c (117420B)
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 * L2 - Broadcom StrataSwitch Layer-2 switch API. 8 */ 9 10 #include <sal/core/libc.h> 11 #include <shared/bsl.h> 12 #include <soc/mem.h> 13 #include <soc/profile_mem.h> 14 #include <soc/debug.h> 15 #include <soc/drv.h> 16 #include <soc/l2x.h> 17 #ifdef BCM_WARM_BOOT_SUPPORT 18 #include <soc/scache.h> 19 #endif /* BCM_WARM_BOOT_SUPPORT */ 20 21 #include <bcm/l2.h> 22 #include <bcm/error.h> 23 24 #include <bcm_int/esw/mbcm.h> 25 #include <bcm_int/esw/l2.h> 26 #include <bcm_int/esw/vlan.h> 27 #include <bcm_int/esw/trunk.h> 28 #if defined(BCM_TRX_SUPPORT) 29 #include <bcm_int/esw/trx.h> 30 #endif /* BCM_TRX_SUPPORT */ 31 #include <bcm_int/esw/mpls.h> 32 #include <bcm_int/esw/trident.h> 33 #ifdef BCM_TOMAHAWK3_SUPPORT 34 #include <soc/tomahawk3.h> 35 #include <bcm_int/esw/tomahawk3.h> 36 #endif /* BCM_TOMAHAWK3_SUPPORT */ 37 #ifdef BCM_WARM_BOOT_SUPPORT 38 #include <bcm_int/esw/switch.h> 39 #endif /* BCM_WARM_BOOT_SUPPORT */ 40 41 #include <bcm_int/esw_dispatch.h> 42 43 #ifdef BCM_TOMAHAWK3_SUPPORT 44 /**************************************************************** 45 * 46 * L2 software tables, per unit. 47 */ 48 49 int _th3_l2_init[BCM_MAX_NUM_UNITS]; 50 51 static _bcm_l2_match_ctrl_t *_bcm_th3_l2_match_ctrl[BCM_MAX_NUM_UNITS]; 52 static sal_sem_t _bcm_th3_l2_cb_check[BCM_MAX_NUM_UNITS]; 53 54 /**************************************************************************** 55 * 56 * L2X Message Registration 57 */ 58 59 #define L2_CB_MAX 3 60 61 typedef struct th3_l2x_cb_entry_s { 62 bcm_l2_addr_callback_t fn; 63 void *fn_data; 64 } th3_l2_cb_entry_t; 65 66 #define _BCM_TH3_L2X_THREAD_STOP (1 << 0) 67 typedef struct th3_l2_data_s { 68 th3_l2_cb_entry_t cb[L2_CB_MAX]; 69 int cb_count; 70 int flags; 71 sal_mutex_t l2_mutex; 72 } th3_l2_data_t; 73 74 static th3_l2_data_t th3_l2_data[SOC_MAX_NUM_DEVICES]; 75 76 77 #define L2_LOCK(unit) \ 78 sal_mutex_take(th3_l2_data[unit].l2_mutex, sal_mutex_FOREVER) 79 80 #define L2_UNLOCK(unit) sal_mutex_give(th3_l2_data[unit].l2_mutex) 81 82 #define L2_MUTEX(unit) if (th3_l2_data[unit].l2_mutex == NULL && \ 83 (th3_l2_data[unit].l2_mutex = sal_mutex_create("bcm_l2_lock")) == NULL) \ 84 return BCM_E_MEMORY 85 86 /**************************************************************************** 87 * 88 * L2 Callbacks Registration 89 */ 90 static bcm_l2_addr_callback_t _bcm_th3_l2_cbs[SOC_MAX_NUM_DEVICES]; 91 static void *_bcm_th3_l2_cb_data[SOC_MAX_NUM_DEVICES]; 92 93 /* forward declaration */ 94 #if 0 95 96 static int _bcm_l2_bpdu_init(int unit); 97 #endif 98 STATIC int _bcm_th3_l2_replace(int unit, uint32 flags, uint32 int_flags, 99 bcm_l2_addr_t *match_addr, 100 bcm_module_t new_module, bcm_port_t new_port, 101 bcm_trunk_t new_trunk, 102 bcm_l2_traverse_cb trav_fn, void *user_data); 103 104 /* L2 (vlan, port) tuple structure */ 105 typedef struct _bcm_l2_vlan_port_pair_s { 106 /* Array of PBMP with max VLAN size, the first 0-4095 PBMP entries 107 in the array are for max number of VLANs supported, the 4096th 108 i.e pbm[BCM_VLAN_MAX+1]th entry in the array is to maintain a list 109 of PBMPs for invalid VLANs (used for delete by gport operation). */ 110 bcm_pbmp_t pbm[BCM_VLAN_MAX+2]; 111 } _bcm_l2_vlan_port_pair_t; 112 113 typedef struct _bcm_l2_vlan_trunk_pair_s { 114 SHR_BITDCL *tbm[BCM_VLAN_MAX+2]; 115 } _bcm_l2_vlan_trunk_pair_t; 116 117 typedef struct _bcm_l2_del_vlan_port_pair_s { 118 uint32 flags; /* BCM_L2_AUTH_XXX flags. */ 119 uint32 replace_flags; /* BCM_L2_REPLACE_XXX flags */ 120 bcm_vlan_vector_t del_by_vlan_vec; /* Vlan vector represents 121 delete by vlan */ 122 _bcm_l2_vlan_port_pair_t *mod_pair_arr; /* Reference to Array of 123 (vlan,port) for max modules */ 124 _bcm_l2_vlan_trunk_pair_t *unit_pair_arr; /* Reference to Array of 125 (vlan,tid) for each unit */ 126 } _bcm_l2_del_vlan_port_pair_t; 127 128 typedef enum l2x_memacc_field_e { 129 _BCM_L2_MEMACC_VALID, 130 _BCM_L2_MEMACC_KEY_TYPE, 131 _BCM_L2_MEMACC_NUM 132 } l2x_memacc_field_t; 133 134 static uint32 _l2_dbg_matched_entries[SOC_MAX_NUM_DEVICES], 135 _l2_dbg_unmatched_entries[SOC_MAX_NUM_DEVICES]; 136 137 #ifdef BCM_WARM_BOOT_SUPPORT 138 STATIC int _bcm_th3_l2_wb_alloc(int unit); 139 STATIC int _bcm_th3_l2_wb_recover(int unit); 140 #endif /* BCM_WARM_BOOT_SUPPORT */ 141 142 /* just need to clear SRC or DES hit bit. Customers may call API bcm_esw_l2_replace 143 * with parameter *match_addr which value is NULL */ 144 #define _CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(flag) \ 145 (!(flag & (BCM_L2_REPLACE_MATCH_VLAN |\ 146 BCM_L2_REPLACE_MATCH_MAC |\ 147 BCM_L2_REPLACE_MATCH_DEST)) &&\ 148 (flag & (BCM_L2_REPLACE_DES_HIT_CLEAR |\ 149 BCM_L2_REPLACE_SRC_HIT_CLEAR))) 150 151 /* 152 * Function: 153 * bcm_th3_l2_learn_start 154 * Description: 155 * This function creates learn thread. It is called after L2 learn cache has 156 * and CMICx have been initialized 157 * Parameters: 158 * unit - StrataSwitch device unit number 159 * Returns: 160 * BCM_E_XXX 161 */ 162 int 163 bcm_th3_l2_learn_start(int unit, int interval) 164 { 165 sal_usecs_t cfg_interval = -1; 166 int rv = SOC_E_NONE; 167 168 /* Stop learn thread if it is runnng, and apply new interval provided 169 * by application 170 */ 171 if (soc_th3_l2_learn_thread_running(unit, &cfg_interval)) { 172 LOG_ERROR(BSL_LS_BCM_L2, 173 (BSL_META_U(unit, "Learn thread running, interval=%d\n"), 174 cfg_interval)); 175 176 soc_th3_l2_learn_thread_stop(unit); 177 /* Check if sleep is reqd */ 178 sal_usleep(10000); 179 } 180 181 LOG_INFO(BSL_LS_BCM_L2, (BSL_META_U(unit, "======: Starting learn" 182 " thread\n"))); 183 184 rv = soc_th3_l2_learn_alloc_resources(unit); 185 186 if (rv == SOC_E_NONE) { 187 rv = soc_th3_l2_learn_thread_start(unit, interval); 188 } 189 190 return rv; 191 } 192 193 /* 194 * Function: 195 * bcm_tomahawk3_l2_init 196 * Description: 197 * Perform required initializations to L2 table. 198 * Parameters: 199 * unit - StrataSwitch PCI device unit number (driver internal). 200 * Returns: 201 * BCM_E_XXX 202 */ 203 204 int 205 bcm_tomahawk3_l2_init(int unit) 206 { 207 int rv; 208 sal_usecs_t lrn_interval; 209 sal_usecs_t l2x_interval; 210 uint32 flags = 0; 211 #ifdef BCM_XGS_SWITCH_SUPPORT 212 int frozen; 213 214 BCM_IF_ERROR_RETURN( 215 soc_l2x_is_frozen(unit, SOC_L2X_FROZEN_WITH_LOCK, &frozen)); 216 if (TRUE == frozen) { 217 return BCM_E_BUSY; 218 } 219 #endif /* BCM_XGS_SWITCH_SUPPORT */ 220 _th3_l2_init[unit] = 0; 221 222 if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) { 223 /* Turn off arl aging */ 224 BCM_IF_ERROR_RETURN 225 (SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, 0, 0)); 226 BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_detach(unit)); 227 } 228 229 /* Proposal: during warm boot, customer wants to freeze l2x. 230 * After warm boot, customer will restore l2x. 231 */ 232 if (SOC_WARM_BOOT(unit) && soc_l2x_cml_override_is_enabled(unit)) { 233 /* In this condition, soc_l2x_freeze does not change ING_MISC_CONFIG2r. 234 * It just wants to Increment l2 frozen indicator "f_l2->hw_frozen++". 235 * When we call bcm_tomahawk3_l2_age_timer_set, we won't enable SW aging 236 * by mistake 237 */ 238 BCM_IF_ERROR_RETURN(soc_l2x_selective_freeze(unit, 239 SOC_L2X_FROZEN_WITHOUT_LOCK)); 240 } 241 242 /* 243 * Call chip-dependent initialization 244 */ 245 BCM_IF_ERROR_RETURN 246 (mbcm_driver[unit]->mbcm_l2_init(unit)); 247 248 if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) { 249 /* 250 * Init L2 cache 251 */ 252 rv = bcm_th3_l2_cache_init(unit); 253 if (BCM_FAILURE(rv) && (rv != BCM_E_UNAVAIL)) { 254 return rv; 255 } 256 } 257 258 /* If learn thread is not running, start it */ 259 if (!(soc_th3_l2_learn_thread_running(unit, &lrn_interval))) { 260 int cfg_interval; 261 262 /* Start learn thread. Make sure learn cache and DMA infrastructure 263 * have been initialized at this point 264 */ 265 cfg_interval = soc_property_get(unit, spn_L2XLRN_THREAD_INTERVAL, 266 SAL_BOOT_BCMSIM ? 267 BCMSIM_L2XLRN_INTERVAL : 268 BCM_L2XLRN_INTERVAL_DEFAULT); 269 270 BCM_IF_ERROR_RETURN(bcm_th3_l2_learn_start(unit, cfg_interval)); 271 } 272 273 /* If l2x thread is not running, start it */ 274 if (!soc_l2x_running(unit, &flags, &l2x_interval)) { 275 l2x_interval = soc_property_get(unit, spn_L2XMSG_THREAD_USEC, 276 SOC_L2X_INTERVAL_DEFAULT); 277 rv = soc_l2x_start(unit, 0, l2x_interval); 278 279 if (BCM_FAILURE(rv)) { 280 281 LOG_ERROR(BSL_LS_BCM_L2, 282 (BSL_META_U(unit, "Could not start l2x thread," 283 "rv = %d, interval=%d\n"), rv, l2x_interval)); 284 285 return rv; 286 } 287 } 288 289 #ifdef BCM_WARM_BOOT_SUPPORT 290 if (SOC_WARM_BOOT(unit)) { 291 BCM_IF_ERROR_RETURN(_bcm_th3_l2_wb_recover(unit)); 292 } else { 293 BCM_IF_ERROR_RETURN(_bcm_th3_l2_wb_alloc(unit)); 294 } 295 #endif /* BCM_WARM_BOOT_SUPPORT */ 296 297 if (_bcm_th3_l2_cb_check[unit] == NULL) { 298 _bcm_th3_l2_cb_check[unit] = sal_sem_create("l2 callback check", 299 sal_sem_BINARY, 1); 300 if (_bcm_th3_l2_cb_check[unit] == NULL) { 301 return BCM_E_MEMORY; 302 } 303 } 304 305 _th3_l2_init[unit] = 1; 306 return BCM_E_NONE; 307 } 308 309 /* 310 * Function: 311 * bcm_tomahawk3_l2_detach 312 * Purpose: 313 * Clean up L2 bcm layer when unit is detached 314 * Parameters: 315 * unit - Unit being detached 316 * Returns: 317 * BCM_E_XXX 318 */ 319 int 320 bcm_tomahawk3_l2_detach(int unit) 321 { 322 int frozen; 323 324 /* Verify the table is not frozen */ 325 BCM_IF_ERROR_RETURN(soc_l2x_is_frozen(unit, SOC_L2X_FROZEN_WITH_LOCK, 326 &frozen)); 327 if (TRUE == frozen) { 328 return BCM_E_BUSY; 329 } 330 331 if (_bcm_th3_l2_match_ctrl[unit] && 332 _bcm_th3_l2_match_ctrl[unit]->preserved) { 333 _th3_l2_init[unit] = 0; 334 return BCM_E_NONE; 335 } 336 337 /* 338 * Call chip-dependent finalization 339 */ 340 SOC_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l2_term(unit)); 341 342 if (_bcm_th3_l2_cb_check[unit] != NULL) { 343 sal_sem_destroy(_bcm_th3_l2_cb_check[unit]); 344 _bcm_th3_l2_cb_check[unit] = NULL; 345 } 346 347 _th3_l2_init[unit] = 0; 348 349 return BCM_E_NONE; 350 } 351 352 /* 353 * Function: 354 * _bcm_l2_match_ctrl_init 355 * Purpose: 356 * Allocate resources for match control data (used by callback 357 * registration, traverse and replace APIs) 358 * Parameters: 359 * unit - (IN) BCM device number 360 * Retruns: 361 * BCM_E_NONE on success 362 * Other BCM_E_XXX codes on error 363 */ 364 int 365 _bcm_l2_match_ctrl_init(int unit) 366 { 367 sal_sem_t sem = NULL; 368 369 if (_bcm_th3_l2_match_ctrl[unit] == NULL) { 370 _bcm_th3_l2_match_ctrl[unit] = sal_alloc(sizeof(_bcm_l2_match_ctrl_t), 371 "matched_traverse control"); 372 if (_bcm_th3_l2_match_ctrl[unit] == NULL) { 373 return BCM_E_MEMORY; 374 } 375 sem = sal_sem_create("L2_matched", sal_sem_BINARY, 0); 376 if (sem == NULL) { 377 sal_free(_bcm_th3_l2_match_ctrl[unit]); 378 _bcm_th3_l2_match_ctrl[unit] = NULL; 379 return BCM_E_RESOURCE; 380 } 381 } else { 382 sem = _bcm_th3_l2_match_ctrl[unit]->sem; 383 } 384 385 sal_memset(_bcm_th3_l2_match_ctrl[unit], 0, sizeof(_bcm_l2_match_ctrl_t)); 386 _bcm_th3_l2_match_ctrl[unit]->sem = sem; 387 388 return BCM_E_NONE; 389 } 390 391 /* 392 * Function: 393 * _bcm_l2_match_ctrl_deinit 394 * Purpose: 395 * Free resources allocated for match control data (used by callback 396 * registration, traverse and replace APIs) 397 * Parameters: 398 * unit - (IN) BCM device number 399 * Retruns: 400 * No value 401 */ 402 void 403 _bcm_l2_match_ctrl_deinit(int unit) 404 { 405 406 if (_bcm_th3_l2_match_ctrl[unit] != NULL) { 407 if (_bcm_th3_l2_match_ctrl[unit]->sem != NULL) { 408 sal_sem_destroy(_bcm_th3_l2_match_ctrl[unit]->sem); 409 _bcm_th3_l2_match_ctrl[unit]->sem = NULL; 410 } 411 sal_free(_bcm_th3_l2_match_ctrl[unit]); 412 _bcm_th3_l2_match_ctrl[unit] = NULL; 413 } 414 415 return; 416 } 417 418 int _bcm_tomahawk3_l2_age_timer_set(int unit, int age_seconds, int enabled) 419 { 420 int rv; 421 #ifdef BCM_XGS_SWITCH_SUPPORT 422 int frozen = 0; 423 #endif 424 425 SOC_L2X_MEM_LOCK(unit); 426 #ifdef BCM_XGS_SWITCH_SUPPORT 427 rv = soc_l2x_is_frozen(unit, SOC_L2X_FROZEN, &frozen); 428 429 if (frozen) { 430 soc_age_timer_cache_set(unit, age_seconds, enabled); 431 enabled = 0; /* L2x is frozen, so we can't enable aging function */ 432 } 433 #endif 434 435 rv = SOC_FUNCTIONS(unit)->soc_age_timer_set(unit, age_seconds, enabled); 436 SOC_L2X_MEM_UNLOCK(unit); 437 return rv; 438 } 439 440 /* 441 * Function: 442 * bcm_tomahawk3_l2_age_timer_set 443 * Description: 444 * Set the age timer for all blocks. 445 * Setting the value to 0 disables the age timer. 446 * Parameters: 447 * unit - StrataSwitch PCI device unit number (driver internal). 448 * age_seconds - Age timer value in seconds 449 * Returns: 450 * BCM_E_NONE Success 451 * BCM_E_INTERNAL Chip access failure 452 */ 453 454 int 455 bcm_tomahawk3_l2_age_timer_set(int unit, int age_seconds) 456 { 457 int max_value; 458 int enabled; 459 int rv; 460 461 TH3_L2_INIT(unit); 462 463 BCM_IF_ERROR_RETURN 464 (SOC_FUNCTIONS(unit)->soc_age_timer_max_get(unit, &max_value)); 465 466 if (age_seconds < 0 || age_seconds > max_value) { 467 return BCM_E_PARAM; 468 } 469 470 enabled = age_seconds ? 1 : 0; 471 472 rv = _bcm_tomahawk3_l2_age_timer_set(unit, age_seconds, enabled); 473 474 return rv; 475 } 476 477 int 478 _bcm_tomahawk3_l2_age_timer_get(int unit, int *age_seconds) 479 { 480 int rv = BCM_E_NONE; 481 #ifdef BCM_XGS_SWITCH_SUPPORT 482 int frozen = 0; 483 #endif 484 int enabled; 485 486 SOC_L2X_MEM_LOCK(unit); 487 488 #ifdef BCM_XGS_SWITCH_SUPPORT 489 rv = soc_l2x_is_frozen(unit, SOC_L2X_FROZEN, &frozen); 490 491 if (BCM_FAILURE(rv)) { 492 frozen = 0; 493 } 494 if (frozen) { 495 soc_age_timer_cache_get(unit, age_seconds, &enabled); 496 497 SOC_L2X_MEM_UNLOCK(unit); 498 return rv; 499 } 500 #endif 501 rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, age_seconds, &enabled); 502 503 SOC_L2X_MEM_UNLOCK(unit); 504 return rv; 505 } 506 507 /* 508 * Function: bcm_tomahawk3_l2_age_timer_get 509 * Description: 510 * Returns the current age timer value 511 * The value is 0 if aging is not enabled 512 * Parameters: 513 * unit - StrataSwitch PCI device unit number (driver internal) 514 * age_seconds - Place to store returned age timer value in seconds 515 * Returns: 516 * BCM_E_NONE Success 517 * BCM_E_INTERNAL Chip access failure 518 */ 519 520 int 521 bcm_tomahawk3_l2_age_timer_get(int unit, int *age_seconds) 522 { 523 int seconds, enabled; 524 int rv; 525 526 TH3_L2_INIT(unit); 527 528 if (age_seconds == NULL) { 529 return BCM_E_PARAM; 530 } 531 532 SOC_L2X_MEM_LOCK(unit); 533 rv = SOC_FUNCTIONS(unit)->soc_age_timer_get(unit, &seconds, &enabled); 534 SOC_L2X_MEM_UNLOCK(unit); 535 536 BCM_IF_ERROR_RETURN(rv); 537 538 if (enabled) { 539 *age_seconds = seconds; 540 } else { 541 *age_seconds = 0; 542 } 543 544 return BCM_E_NONE; 545 } 546 547 /* 548 * Function: 549 * _bcm_th3_l2_register_callback 550 * Description: 551 * Call back to handle bcm_l2_addr_register clients 552 * Parameters: 553 * unit - StrataSwitch unit number. 554 * entry_del - Entry to be deleted or updated, NULL if none 555 * entry_add - Entry to be inserted or updated, NULL if none 556 * fn_data - unused 557 * Notes: 558 * Only one callback per unit to the bcm layer is supported here. 559 * Multiple bcm client callbacks per unit are supported in the bcm layer 560 */ 561 void 562 _bcm_th3_l2_register_callback(int unit, 563 int pflags, 564 l2x_entry_t *entry_del, 565 l2x_entry_t *entry_add, 566 void *fn_data) 567 { 568 bcm_l2_addr_t l2addr_del, l2addr_add; 569 _bcm_l2_match_ctrl_t *match_ctrl; 570 l2x_entry_t *l2x_entry_buf; 571 int buf_index, entry_index; 572 573 if (pflags & (SOC_L2X_ENTRY_DUMMY | SOC_L2X_ENTRY_NO_ACTION)) { 574 /* pass l2addr_add info match */ 575 match_ctrl = _bcm_th3_l2_match_ctrl[unit]; 576 buf_index = match_ctrl->entry_wr_idx / _BCM_L2_MATCH_ENTRY_BUF_SIZE; 577 entry_index = match_ctrl->entry_wr_idx % _BCM_L2_MATCH_ENTRY_BUF_SIZE; 578 if (entry_index == 0) { 579 if (buf_index >= _BCM_L2_MATCH_ENTRY_BUF_COUNT) { 580 return; 581 } 582 match_ctrl->l2x_entry_buf[buf_index] = 583 sal_alloc(sizeof(l2x_entry_t) * _BCM_L2_MATCH_ENTRY_BUF_SIZE, 584 "l2_matched_traverse"); 585 if (match_ctrl->l2x_entry_buf[buf_index] == NULL) { 586 return; 587 } 588 } 589 l2x_entry_buf = match_ctrl->l2x_entry_buf[buf_index]; 590 591 if (pflags & SOC_L2X_ENTRY_NO_ACTION) { 592 l2x_entry_buf[entry_index] = *entry_add; 593 } else { 594 sal_memcpy(&l2x_entry_buf[entry_index], 595 soc_mem_entry_null(unit, L2Xm), sizeof(l2x_entry_t)); 596 } 597 match_ctrl->entry_wr_idx++; 598 sal_sem_give(match_ctrl->sem); 599 sal_thread_yield(); 600 } else if (_bcm_th3_l2_cbs[unit] != NULL) { 601 uint32 flags = 0; /* Common flags: Move, From/to native */ 602 603 sal_memset(&l2addr_del, 0, sizeof(bcm_l2_addr_t)); 604 sal_memset(&l2addr_add, 0, sizeof(bcm_l2_addr_t)); 605 606 /* First, set up the entries: decode HW entries and set flags */ 607 if (entry_del != NULL) { 608 (void)_bcm_th3_l2_from_l2x(unit, &l2addr_del, entry_del); 609 } 610 if (entry_add != NULL) { 611 (void)_bcm_th3_l2_from_l2x(unit, &l2addr_add, entry_add); 612 } 613 614 if ((entry_del != NULL) && (entry_add != NULL)) { /* It's a move */ 615 flags |= BCM_L2_MOVE; 616 if (SOC_USE_GPORT(unit)) { 617 if (l2addr_del.port != l2addr_add.port) { 618 flags |= BCM_L2_MOVE_PORT; 619 } 620 } else { 621 if (l2addr_del.modid != l2addr_add.modid || 622 l2addr_del.tgid != l2addr_add.tgid || 623 l2addr_del.port != l2addr_add.port) { 624 flags |= BCM_L2_MOVE_PORT; 625 } 626 } 627 if (!(l2addr_del.flags & BCM_L2_TRUNK_MEMBER)) { 628 if (bcm_tomahawk3_l2_port_native(unit, l2addr_del.modid, 629 l2addr_del.port) > 0) { 630 flags |= BCM_L2_FROM_NATIVE; 631 l2addr_del.flags |= BCM_L2_NATIVE; 632 } 633 } 634 if (!(l2addr_add.flags & BCM_L2_TRUNK_MEMBER)) { 635 if (bcm_tomahawk3_l2_port_native(unit, l2addr_add.modid, 636 l2addr_add.port) > 0) { 637 flags |= BCM_L2_TO_NATIVE; 638 l2addr_add.flags |= BCM_L2_NATIVE; 639 } 640 } 641 l2addr_del.flags |= flags; 642 l2addr_add.flags |= flags; 643 } else if (entry_del != NULL) { /* Age out or simple delete */ 644 if (!(l2addr_del.flags & BCM_L2_TRUNK_MEMBER)) { 645 if (bcm_tomahawk3_l2_port_native(unit, l2addr_del.modid, 646 l2addr_del.port) > 0) { 647 l2addr_del.flags |= BCM_L2_NATIVE; 648 } 649 } 650 } else if (entry_add != NULL) { /* Insert or learn */ 651 if (!(l2addr_add.flags & BCM_L2_TRUNK_MEMBER)) { 652 if (bcm_tomahawk3_l2_port_native(unit, l2addr_add.modid, 653 l2addr_add.port) > 0) { 654 l2addr_add.flags |= BCM_L2_NATIVE; 655 } 656 } 657 } 658 659 if (_bcm_th3_l2_cb_check[unit] != NULL) { 660 sal_sem_take(_bcm_th3_l2_cb_check[unit], sal_sem_FOREVER); 661 } 662 663 /* The entries are now set up. Make the callbacks */ 664 if (entry_del != NULL) { 665 if (_bcm_th3_l2_cbs[unit] != NULL) { 666 _bcm_th3_l2_cbs[unit](unit, &l2addr_del, 0, 667 _bcm_th3_l2_cb_data[unit]); 668 } 669 } 670 671 if (pflags & SOC_L2X_ENTRY_OVERFLOW) { 672 l2addr_add.flags |= BCM_L2_ENTRY_OVERFLOW; 673 } 674 675 if (entry_add != NULL) { 676 if (_bcm_th3_l2_cbs[unit] != NULL) { 677 _bcm_th3_l2_cbs[unit](unit, &l2addr_add, 1, 678 _bcm_th3_l2_cb_data[unit]); 679 } 680 } 681 682 if (_bcm_th3_l2_cb_check[unit] != NULL) { 683 sal_sem_give(_bcm_th3_l2_cb_check[unit]); 684 } 685 } 686 } 687 688 /* 689 * Function: 690 * bcm_tomahawk3_l2_addr_freeze 691 * Description: 692 * Temporarily quiesce ARL from all activity (learning, aging, inserting) 693 * include SW operations 694 * Parameters: 695 * unit - StrataSwitch PCI device unit number (driver internal). 696 * Returns: 697 * BCM_E_NONE Success 698 * BCM_E_INTERNAL Chip access failure 699 */ 700 701 int 702 bcm_tomahawk3_l2_addr_freeze(int unit) 703 { 704 TH3_L2_INIT(unit); 705 706 #ifdef BCM_XGS_SWITCH_SUPPORT 707 if (soc_feature(unit, soc_feature_arl_hashed)) { 708 return soc_l2x_freeze(unit); 709 } 710 #endif 711 712 return BCM_E_UNAVAIL; 713 } 714 715 /* 716 * Function: 717 * bcm_tomahawk3_l2_addr_thaw 718 * Description: 719 * Restore normal ARL activity including S/W and H/W activity. 720 * Parameters: 721 * unit - StrataSwitch PCI device unit number (driver internal). 722 * Returns: 723 * BCM_E_NONE Success 724 * BCM_E_INTERNAL Chip access failure 725 */ 726 727 int 728 bcm_tomahawk3_l2_addr_thaw(int unit) 729 { 730 TH3_L2_INIT(unit); 731 732 #ifdef BCM_XGS_SWITCH_SUPPORT 733 if (soc_feature(unit, soc_feature_arl_hashed)) { 734 return soc_l2x_thaw(unit); 735 } 736 #endif 737 738 return BCM_E_UNAVAIL; 739 } 740 741 /* 742 * Function: 743 * bcm_tomahawk3_l2_clear 744 * Purpose: 745 * Clear the L2 layer 746 * Parameters: 747 * unit - BCM unit number 748 * Returns: 749 * BCM_E_XXX 750 */ 751 752 int 753 bcm_tomahawk3_l2_clear(int unit) 754 { 755 TH3_L2_INIT(unit); 756 757 if (_bcm_th3_l2_match_ctrl[unit]) { 758 _bcm_th3_l2_match_ctrl[unit]->preserved = 1; 759 } 760 761 BCM_IF_ERROR_RETURN(bcm_tomahawk3_l2_detach(unit)); 762 763 if (_bcm_th3_l2_match_ctrl[unit]) { 764 _bcm_th3_l2_match_ctrl[unit]->preserved = 0; 765 } 766 767 /* 768 * Call chip-dependent initialization 769 */ 770 BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_l2_init(unit)); 771 772 #if defined(BCM_XGS_SWITCH_SUPPORT) 773 /* Stop l2x thread if callback registration started it. */ 774 if (th3_l2_data[unit].flags & _BCM_TH3_L2X_THREAD_STOP) { 775 BCM_IF_ERROR_RETURN(soc_l2x_stop(unit)); 776 /* Stop the learn thread */ 777 BCM_IF_ERROR_RETURN(soc_th3_l2_learn_thread_stop(unit)); 778 } 779 #endif /* BCM_XGS_SWITCH_SUPPORT */ 780 781 /* Clear l2_data structure */ 782 th3_l2_data[unit].cb_count = 0; 783 th3_l2_data[unit].flags = 0; 784 sal_memset(&th3_l2_data[unit].cb, 0, sizeof(th3_l2_data[unit].cb)); 785 786 _th3_l2_init[unit] = 1; /* some positive value */ 787 788 return BCM_E_NONE; 789 } 790 791 /* 792 * Function: 793 * bcm_tomahawk3_l2_key_dump 794 * Purpose: 795 * Dump the key (VLAN+MAC) portion of a hardware-independent 796 * L2 address for debugging 797 * Parameters: 798 * unit - Unit number 799 * pfx - String to print before output 800 * entry - Hardware-independent L2 entry to dump 801 * sfx - String to print after output 802 */ 803 804 int 805 bcm_tomahawk3_l2_key_dump(int unit, char *pfx, bcm_l2_addr_t *entry, char *sfx) 806 { 807 LOG_CLI((BSL_META_U(unit, 808 "l2: %sVLAN=0x%03x MAC=0x%02x%02x%02x" 809 "%02x%02x%02x%s"), pfx, entry->vid, 810 entry->mac[0], entry->mac[1], entry->mac[2], 811 entry->mac[3], entry->mac[4], entry->mac[5], sfx)); 812 813 return BCM_E_NONE; 814 } 815 816 /* 817 * Function: 818 * bcm_esw_l2_conflict_get 819 * Purpose: 820 * Given an L2 address, return existing addresses which could conflict. 821 * Parameters: 822 * unit - switch device 823 * addr - l2 address to search for conflicts 824 * cf_array - (OUT) list of l2 addresses conflicting with addr 825 * cf_max - number of entries allocated to cf_array 826 * cf_count - (OUT) actual number of cf_array entries filled 827 * Returns: 828 * BCM_E_XXX 829 * Notes: 830 * Given an L2 or L2 multicast address, return any existing L2 or 831 * L2 multicast addresses which might prevent it from being 832 * inserted because a chip resource (like a hash bucket) is full. 833 * This routine could be used if bcm_l2_addr_add or bcm_l2_mcast_add 834 * returns BCM_E_FULL. 835 */ 836 837 int 838 bcm_tomahawk3_l2_conflict_get(int unit, bcm_l2_addr_t *addr, 839 bcm_l2_addr_t *cf_array, int cf_max, 840 int *cf_count) 841 { 842 TH3_L2_INIT(unit); 843 /* 844 * Call chip-dependent handler. 845 */ 846 SOC_IF_ERROR_RETURN 847 (mbcm_driver[unit]->mbcm_l2_conflict_get(unit, addr, 848 cf_array, cf_max, cf_count)); 849 850 return BCM_E_NONE; 851 } 852 853 /* 854 * Function: 855 * bcm_tomahawk3_l2_learn_limit_set 856 * Description: 857 * Set the L2 MAC learning limit 858 * Parameters: 859 * unit device number 860 * limit learn limit control info 861 * limit->flags - qualifiers bits and action bits 862 * limit->vlan - vlan identifier 863 * limit->port - port number 864 * limit->trunk - trunk identifier 865 * limit->limit - max number of learned entry, -1 for unlimit 866 * Return: 867 * BCM_E_XXX 868 */ 869 int 870 bcm_tomahawk3_l2_learn_limit_set(int unit, bcm_l2_learn_limit_t *limit) 871 { 872 return (BCM_E_UNAVAIL); 873 } 874 875 /* 876 * Function: 877 * bcm_tomahawk3_l2_learn_limit_get 878 * Description: 879 * Get the L2 MAC learning limit 880 * Parameters: 881 * unit device number 882 * limit learn limit control info 883 * limit->flags - qualifiers bits and action bits 884 * limit->vlan - vlan identifier 885 * limit->port - port number 886 * limit->trunk - trunk identifier 887 * limit->limit - max number of learned entry, -1 for unlimit 888 * Return: 889 * BCM_E_XXX 890 */ 891 int 892 bcm_tomahawk3_l2_learn_limit_get(int unit, bcm_l2_learn_limit_t *limit) 893 { 894 return (BCM_E_UNAVAIL); 895 } 896 897 /* 898 * Function: 899 * bcm_tomahawk3_l2_learn_class_set 900 * Description: 901 * To set the attributes of L2 learning class 902 * Parameters: 903 * unit device number 904 * lclass learning class id (0 - 3) 905 * lclass_prio learning class priority (0 - 3, 3 is the highest) 906 * flags flags (BCM_L2_LEARN_CLASS_*) 907 * Return: 908 * BCM_E_XXX 909 * Note: 910 * This feature is disabled by default (see bcmPortControlLearnClassEnable). 911 * By default, each learning class is assigned priority 0 (lowest) 912 * and the attribute, BCM_L2_LEARN_CLASS_MOVE, is not set. By default, 913 * each port is assigned to learning class 0. 914 */ 915 int 916 bcm_tomahawk3_l2_learn_class_set(int unit, int lclass, int lclass_prio, 917 uint32 flags) 918 { 919 return (BCM_E_UNAVAIL); 920 } 921 /* 922 * Function: 923 * bcm_tomahawk3_l2_learn_class_get 924 * Description: 925 * To get the attributes of L2 learning class 926 * Parameters: 927 * unit device number 928 * lclass learning class id (0 - 3) 929 * lclass_prio learning class priority (0 - 3, 3 is the highest) 930 * flags flags (BCM_L2_LEARN_CLASS_*) 931 * Return: 932 * BCM_E_XXX 933 */ 934 int 935 bcm_tomahawk3_l2_learn_class_get(int unit, int lclass, int *lclass_prio, 936 uint32 *flags) 937 { 938 return (BCM_E_UNAVAIL); 939 } 940 941 /* 942 * Function: 943 * bcm_tomahawk3_l2_learn_stat_set 944 * Description: 945 * To set or clear the specified L2 hash counter to the indicated value. 946 * Parameters: 947 * unit - (IN) Unit number. 948 * learn_stat - (IN) Pointer to the L2 learned statistic structure. 949 * Return: 950 * BCM_E_XXX 951 * Note: 952 * The purposes of these counters are used to monitor the L2 hash condition. 953 * When the counter counts to 32'hffff_ffff (maximum value), it will keep this value till 954 * software clear it. Currently these L2 hash counters are system-wise. 955 */ 956 int 957 bcm_tomahawk3_l2_learn_stat_set(int unit, bcm_l2_learn_stat_t *learn_stat) 958 { 959 return (BCM_E_UNAVAIL); 960 } 961 962 /* 963 * Function: 964 * bcm_tomahawk3_l2_learn_stat_get 965 * Description: 966 * To get the statistic of the specified L2 hash counter from chip. 967 * Parameters: 968 * unit - (IN) Unit number. 969 * learn_stat - (INOUT) Pointer to the L2 learned statistic structure. 970 * Return: 971 * BCM_E_XXX 972 * Note: 973 * The purposes of these counters are used to monitor the L2 hash condition. 974 * When the counter counts to 32'hffff_ffff (maximum value), it will keep this value till 975 * software clear it. Currently these L2 hash counters are system-wise. 976 */ 977 int 978 bcm_tomahawk3_l2_learn_stat_get(int unit, bcm_l2_learn_stat_t *learn_stat) 979 { 980 return (BCM_E_UNAVAIL); 981 } 982 983 /* 984 * Function: 985 * _bcm_th3_delete_replace_flags_convert 986 * Description: 987 * A helper function to all delete_by APIs to use bcm_l2_replace 988 * Converts L2 flags to L2 replace flags compatable to use with bcm_l2_replace 989 * Parameters: 990 * unit [IN]- device unit 991 * flags [IN] - BCM_L2_DELETE_XXX 992 * repl_flags [OUT]- Vflags BCM_L2_REPLACE_XXX 993 * Returns: 994 * BCM_E_XXX 995 */ 996 997 STATIC int 998 _bcm_th3_delete_replace_flags_convert(int unit, uint32 flags, 999 uint32 *repl_flags) 1000 { 1001 uint32 tmp_flags = BCM_L2_REPLACE_DELETE; 1002 1003 /* Age feature only supported by bulk Control */ 1004 if (flags & BCM_L2_REPLACE_AGE){ 1005 return BCM_E_UNAVAIL; 1006 } 1007 1008 if (flags & BCM_L2_DELETE_PENDING) { 1009 tmp_flags |= BCM_L2_REPLACE_PENDING; 1010 } 1011 1012 if (flags & BCM_L2_DELETE_STATIC) { 1013 tmp_flags |= BCM_L2_REPLACE_MATCH_STATIC; 1014 } 1015 1016 if (flags & BCM_L2_DELETE_NO_CALLBACKS) { 1017 tmp_flags |= BCM_L2_REPLACE_NO_CALLBACKS; 1018 } 1019 1020 *repl_flags = tmp_flags; 1021 1022 return BCM_E_NONE; 1023 } 1024 1025 /* 1026 * Function: 1027 * bcm_tomahawk3_l2_port_native 1028 * Purpose: 1029 * Determine if the given port is "native" from the point 1030 * of view of L2. 1031 * Parameters: 1032 * unit - The unit 1033 * modid - Module ID of L2 entry being queried 1034 * port - Module port of L2 entry being queried 1035 * Returns: 1036 * TRUE (> 0) if (modid, port) is front panel/CPU port for unit. 1037 * FALSE (0) otherwise. 1038 * < 0 on error. 1039 * 1040 * Native means front panel, but also includes the CPU port. 1041 * HG ports are always excluded as are ports marked as internal or 1042 * external stacking 1043 */ 1044 1045 int 1046 bcm_tomahawk3_l2_port_native(int unit, int modid, int port) 1047 { 1048 bcm_trunk_t tgid; 1049 int id; 1050 1051 TH3_L2_INIT(unit); 1052 1053 if (BCM_GPORT_IS_SET(port)) { 1054 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &modid, 1055 &port, &tgid, &id)); 1056 1057 if (-1 != id || BCM_TRUNK_INVALID != tgid) { 1058 return FALSE; 1059 } 1060 } 1061 1062 return TRUE; 1063 } 1064 1065 /* 1066 * Function: 1067 * bcm_tomahawk3_l2_matched_traverse 1068 * Description: 1069 * This function iterates over L2 table entries, find matching entries based 1070 * on criteria provided by the caller and executes user provided callback 1071 * function for each of the matching entries 1072 * Parameters: 1073 * unit - (IN) Unit number. 1074 * flags - (IN) BCM_L2_TRAVERSE_* flags 1075 * match_addr - (IN) L2 address to match 1076 * trav_fn - (IN) Callback function used for entries matching the 1077 * address and the flags 1078 * user_data - (IN) Pointer to data passed by caller, used with trav_fn 1079 * Return: 1080 * BCM_E_XXX 1081 * Note: 1082 * None 1083 */ 1084 int 1085 bcm_tomahawk3_l2_matched_traverse(int unit, uint32 flags, 1086 bcm_l2_addr_t *match_addr, 1087 bcm_l2_traverse_cb trav_fn, void *user_data) 1088 { 1089 uint32 replace_flags, int_flags; 1090 1091 if (!trav_fn) { 1092 return BCM_E_PARAM; 1093 } 1094 1095 if (!match_addr) { 1096 return BCM_E_PARAM; 1097 } 1098 1099 replace_flags = 0; 1100 int_flags = _BCM_L2_REPLACE_INT_NO_ACTION; 1101 /* 1102 * 1/ If BCM_L2_TRAVERSE_MATCH_DYNAMIC and BCM_L2_TRAVERSE_MATCH_STATIC 1103 * are passed simultaneously to API bcm_l2_matched_traverse, 1104 * this API will match all entries. 1105 * 2/ If both BCM_L2_TRAVERSE_MATCH_DYNAMIC and BCM_L2_TRAVERSE_MATCH_STATIC 1106 * are not passed to API bcm_l2_matched_traverse, 1107 * this API will also match all entries as before. This is the legacy behavior. 1108 * 3/ If only BCM_L2_TRAVERSE_MATCH_DYNAMIC is passed to 1109 * API bcm_l2_matched_traverse, this API will only match dynamic entries. 1110 * 4/ If only BCM_L2_TRAVERSE_MATCH_STATIC is passed to 1111 * API bcm_l2_matched_traverse, this API will only match static entries. 1112 */ 1113 if (((flags & BCM_L2_TRAVERSE_MATCH_STATIC) ? 1 : 0) == 1114 ((flags & BCM_L2_TRAVERSE_MATCH_DYNAMIC) ? 1 : 0)) { 1115 /* Replace static as well as non-static entries */ 1116 replace_flags |= BCM_L2_REPLACE_MATCH_STATIC; 1117 } 1118 if (flags & BCM_L2_TRAVERSE_MATCH_MAC) { 1119 replace_flags |= BCM_L2_REPLACE_MATCH_MAC; 1120 } 1121 if (flags & BCM_L2_TRAVERSE_MATCH_VLAN) { 1122 replace_flags |= BCM_L2_REPLACE_MATCH_VLAN; 1123 } 1124 if (flags & BCM_L2_TRAVERSE_MATCH_DEST) { 1125 replace_flags |= BCM_L2_REPLACE_MATCH_DEST; 1126 } 1127 if (!(flags & BCM_L2_TRAVERSE_IGNORE_DISCARD_SRC)) { 1128 int_flags |= _BCM_L2_REPLACE_INT_MATCH_DISCARD_SRC; 1129 } 1130 if (!(flags & BCM_L2_TRAVERSE_IGNORE_DES_HIT)) { 1131 int_flags |= _BCM_L2_REPLACE_INT_MATCH_DES_HIT; 1132 } 1133 if (!(flags & BCM_L2_TRAVERSE_IGNORE_SRC_HIT)) { 1134 int_flags |= _BCM_L2_REPLACE_INT_MATCH_SRC_HIT; 1135 } 1136 if (flags & BCM_L2_TRAVERSE_MATCH_NATIVE) { 1137 int_flags |= _BCM_L2_REPLACE_INT_MATCH_NATIVE; 1138 } 1139 1140 if ((flags & BCM_L2_TRAVERSE_MATCH_STATIC) && 1141 !(flags & BCM_L2_TRAVERSE_MATCH_DYNAMIC)){ 1142 int_flags |= _BCM_L2_REPLACE_INT_MATCH_ONLY_STATIC; 1143 } 1144 1145 return _bcm_th3_l2_replace(unit, replace_flags, int_flags, match_addr, 0, 1146 0, 0, trav_fn, user_data); 1147 } 1148 1149 /* 1150 * Function: 1151 * _bcm_th3_l2_entry_valid 1152 * Description: 1153 * Check if given L2 entry is valid 1154 * Parameters: 1155 * unit device number 1156 * mem L2 memory to operate on 1157 * l2_entry L2X entry read from HW 1158 * Return: 1159 * BCM_E_NONE 1160 * BCM_E_NOT_FOUND 1161 */ 1162 STATIC int 1163 _bcm_th3_l2_entry_valid(int unit, soc_memacc_t *l2x_memacc, uint32 *l2_entry) 1164 { 1165 int valid; 1166 int key_type; 1167 1168 /* Value below can be read from l2_entry's BASE_VALID field (if reqd) */ 1169 valid = soc_memacc_field32_get(&l2x_memacc[_BCM_L2_MEMACC_VALID], 1170 l2_entry); 1171 1172 if (!valid) { 1173 return BCM_E_NOT_FOUND; 1174 } 1175 1176 key_type = soc_memacc_field32_get(&l2x_memacc[_BCM_L2_MEMACC_KEY_TYPE], 1177 l2_entry); 1178 1179 if (key_type != TH3_L2_HASH_KEY_TYPE_BRIDGE) { 1180 return BCM_E_NOT_FOUND; 1181 } 1182 1183 return BCM_E_NONE; 1184 } 1185 1186 /* 1187 * Function: 1188 * _bcm_th3_l2_traverse_mem 1189 * Description: 1190 * Helper function to _bcm_th3_l2_traverse to iterate over L2X memory 1191 * and parse entries 1192 * Parameters: 1193 * unit device number 1194 * trav_st Traverse structure with initialized data 1195 * Return: 1196 * BCM_E_XXX 1197 */ 1198 STATIC int 1199 _bcm_th3_l2_traverse_mem(int unit, _bcm_l2_traverse_t *trav_st) 1200 { 1201 /* Indexes to iterate over memories, chunks and entries */ 1202 int chnk_idx, ent_idx, chnk_idx_max, mem_idx_max; 1203 int buf_size, chunksize, chnk_end; 1204 /* Buffer to store chunk of L2 table we currently work on */ 1205 uint32 *l2_tbl_chnk; 1206 uint32 *l2_entry; 1207 int rv = BCM_E_NONE; 1208 int i; 1209 soc_memacc_t l2x_memacc_list[_BCM_L2_MEMACC_NUM]; 1210 soc_field_t l2x_fields[_BCM_L2_MEMACC_NUM] = { 1211 BASE_VALIDf, 1212 KEY_TYPEf 1213 }; 1214 _bcm_l2_replace_t *rep_st; 1215 soc_mem_t mem = L2Xm; 1216 1217 if (!soc_mem_index_count(unit, mem)) { 1218 return BCM_E_NONE; 1219 } 1220 1221 for (i = 0; i < _BCM_L2_MEMACC_NUM; i++) { 1222 rv = soc_memacc_init(unit, mem, l2x_fields[i], &l2x_memacc_list[i]); 1223 if (BCM_FAILURE(rv)) { 1224 SOC_MEMACC_INVALID_SET(&l2x_memacc_list[i]); 1225 } 1226 } 1227 1228 chunksize = soc_property_get(unit, spn_L2DELETE_CHUNKS, 1229 L2_MEM_CHUNKS_DEFAULT); 1230 1231 buf_size = 4 * SOC_MAX_MEM_FIELD_WORDS * chunksize; 1232 l2_tbl_chnk = soc_cm_salloc(unit, buf_size, "l2 traverse"); 1233 if (NULL == l2_tbl_chnk) { 1234 return BCM_E_MEMORY; 1235 } 1236 1237 mem_idx_max = soc_mem_index_max(unit, mem); 1238 for (chnk_idx = soc_mem_index_min(unit, mem); 1239 chnk_idx <= mem_idx_max; 1240 chnk_idx += chunksize) { 1241 sal_memset((void *)l2_tbl_chnk, 0, buf_size); 1242 1243 chnk_idx_max = 1244 ((chnk_idx + chunksize) < mem_idx_max) ? 1245 (chnk_idx + chunksize - 1) : mem_idx_max; 1246 1247 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, 1248 chnk_idx, chnk_idx_max, l2_tbl_chnk); 1249 if (SOC_FAILURE(rv)) { 1250 break; 1251 } 1252 1253 chnk_end = (chnk_idx_max - chnk_idx); 1254 for (ent_idx = 0 ; ent_idx <= chnk_end; ent_idx ++) { 1255 l2_entry = 1256 soc_mem_table_idx_to_pointer(unit, mem, uint32 *, 1257 l2_tbl_chnk, ent_idx); 1258 if (BCM_FAILURE(_bcm_th3_l2_entry_valid(unit, l2x_memacc_list, 1259 l2_entry))) { 1260 continue; 1261 } 1262 1263 trav_st->data = l2_entry; 1264 trav_st->mem = mem; 1265 trav_st->mem_idx = chnk_idx + ent_idx; 1266 rv = trav_st->int_cb(unit, (void *)trav_st); 1267 if (BCM_FAILURE(rv)) { 1268 break; 1269 } 1270 } 1271 if (BCM_FAILURE(rv)) { 1272 break; 1273 } 1274 1275 if (!trav_st->user_cb) { 1276 /* Enhancement: use memory write range (per chunk) for replacing 1277 * l2 entry data 1278 */ 1279 rep_st = ((_bcm_l2_traverse_t *)trav_st)->user_data; 1280 if (!(rep_st->flags & BCM_L2_REPLACE_DELETE)) { 1281 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY, 1282 chnk_idx, chnk_idx_max, l2_tbl_chnk); 1283 if (SOC_FAILURE(rv)) { 1284 break; 1285 } 1286 } 1287 } 1288 } 1289 soc_cm_sfree(unit, l2_tbl_chnk); 1290 return rv; 1291 } 1292 1293 /* 1294 * Function: 1295 * _bcm_th3_l2_traverse 1296 * Description: 1297 * Wrapper function for bcm_th3 to iterate over table and read L2X momery 1298 * Parameters: 1299 * unit Device number 1300 * trav_st Traverse structure 1301 * Return: 1302 * BCM_E_XXX 1303 */ 1304 int 1305 _bcm_th3_l2_traverse(int unit, _bcm_l2_traverse_t *trav_st) 1306 { 1307 int rv = BCM_E_UNAVAIL; 1308 1309 rv = _bcm_th3_l2_traverse_mem(unit, trav_st); 1310 1311 return rv; 1312 } 1313 1314 /* 1315 * Function: 1316 * _bcm_th3_l2_traverse_int_cb 1317 * Description: 1318 * Simple internal callback function for bcm_l2_traverse API to call 1319 * a user provided callback on a given entry. 1320 * Parameters: 1321 * unit device number 1322 * trav_st traverse structure 1323 * Return: 1324 * BCM_E_XXX 1325 */ 1326 int 1327 _bcm_th3_l2_traverse_int_cb(int unit, void *trav_st) 1328 { 1329 _bcm_l2_traverse_t *trv; 1330 bcm_l2_addr_t l2_addr; 1331 1332 trv = (_bcm_l2_traverse_t *)trav_st; 1333 1334 BCM_IF_ERROR_RETURN( 1335 _bcm_th3_l2_from_l2x(unit, &l2_addr, (l2x_entry_t *)(trv->data))); 1336 1337 return trv->user_cb(unit, &l2_addr, trv->user_data); 1338 } 1339 1340 /* 1341 * Function: 1342 * bcm_tomahawk3_l2_traverse 1343 * Description: 1344 * Traverse L2 table and call provided callback function with matched entry 1345 * Parameters: 1346 * unit device number 1347 * trav_fn User specified callback function 1348 * user_data User specified cookie 1349 * Return: 1350 * BCM_E_XXX 1351 */ 1352 int 1353 bcm_tomahawk3_l2_traverse(int unit, bcm_l2_traverse_cb trav_fn, void *user_data) 1354 { 1355 _bcm_l2_traverse_t trav_st; 1356 1357 TH3_L2_INIT(unit); 1358 1359 if (!trav_fn) { 1360 return (BCM_E_PARAM); 1361 } 1362 1363 sal_memset(&trav_st, 0, sizeof(_bcm_l2_traverse_t)); 1364 1365 trav_st.user_cb = trav_fn; 1366 trav_st.user_data = user_data; 1367 trav_st.int_cb = _bcm_th3_l2_traverse_int_cb; 1368 1369 return (_bcm_th3_l2_traverse(unit, &trav_st)); 1370 } 1371 1372 /* 1373 * Function: 1374 * _bcm_th3_l2_replace_dest_setup 1375 * Description: 1376 * Helper function to bcm_l2_replace API to setup a destination 1377 * Parameters: 1378 * unit - (IN) Unit number. 1379 * module - (IN) Module number 1380 * port - (IN) Port number for matching L2 entry 1381 * trunk - (IN) Trunkid for matching L2 entry. Valid if is_trunk is TRUE 1382 * is_trunk - (IN) To specify if 'trunk' is valid 1383 * Return: 1384 * BCM_E_XXX 1385 * Note: 1386 * This function is called replace APIs, and indirectly, by delete_by APIs 1387 */ 1388 STATIC int 1389 _bcm_th3_l2_replace_dest_setup(int unit, bcm_module_t module, bcm_port_t port, 1390 bcm_trunk_t trunk, int is_trunk, 1391 _bcm_l2_replace_dest_t *dest) 1392 { 1393 /* If all are -1, means ignore the replacement with new destination */ 1394 if (port == -1 && trunk == -1) { 1395 dest->module = dest->port = dest->trunk = dest->vp = -1; 1396 return BCM_E_NONE; 1397 } 1398 1399 if (BCM_GPORT_IS_SET(port)) { 1400 1401 1402 BCM_IF_ERROR_RETURN(_bcm_esw_gport_resolve(unit, port, &dest->module, 1403 &dest->port, &dest->trunk, 1404 &dest->vp)); 1405 } else if (is_trunk) { 1406 1407 BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, trunk)); 1408 1409 dest->trunk = trunk; 1410 dest->vp = -1; 1411 } else { 1412 /* Check to maintain backward compatibility for 1413 * replace/traverse/delete_by APIs 1414 */ 1415 if (!SOC_MODID_ADDRESSABLE(unit, module)) { 1416 return BCM_E_BADID; 1417 } 1418 dest->module = 0; /* Not used */ 1419 1420 if (!SOC_PORT_ADDRESSABLE(unit, port)) { 1421 return BCM_E_PORT; 1422 } 1423 dest->port = port; 1424 dest->trunk = -1; 1425 dest->vp = -1; 1426 } 1427 1428 return BCM_E_NONE; 1429 } 1430 1431 STATIC int 1432 _bcm_th3_l2_replace_data_mask_setup(int unit, _bcm_l2_replace_t *rep) 1433 { 1434 bcm_mac_t mac_mask; 1435 bcm_mac_t mac_data; 1436 int field_len; 1437 1438 sal_memset(&rep->match_mask, 0, sizeof(l2x_entry_t)); 1439 sal_memset(&rep->match_data, 0, sizeof(l2x_entry_t)); 1440 sal_memset(&rep->new_mask, 0, sizeof(l2x_entry_t)); 1441 sal_memset(&rep->new_data, 0, sizeof(l2x_entry_t)); 1442 1443 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, BASE_VALIDf, 1); 1444 soc_mem_field32_set(unit, L2Xm, &rep->match_data, BASE_VALIDf, 1); 1445 1446 if (rep->key_type != -1) { 1447 field_len = soc_mem_field_length(unit, L2Xm, KEY_TYPEf); 1448 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, KEY_TYPEf, 1449 (1 << field_len) - 1); 1450 soc_mem_field32_set(unit, L2Xm, &rep->match_data, KEY_TYPEf, 1451 rep->key_type); 1452 } 1453 1454 if (rep->flags & BCM_L2_REPLACE_MATCH_VLAN) { 1455 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, VLAN_IDf, 0xfff); 1456 soc_mem_field32_set(unit, L2Xm, &rep->match_data, VLAN_IDf, 1457 rep->key_vlan); 1458 } 1459 1460 if (rep->flags & BCM_L2_REPLACE_MATCH_MAC) { 1461 sal_memset(&mac_mask, 0xFF, sizeof(mac_mask)); 1462 soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf, 1463 mac_mask); 1464 soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf, 1465 rep->key_mac); 1466 } 1467 1468 if ((rep->flags & BCM_L2_REPLACE_MATCH_UC) && 1469 !(rep->flags & BCM_L2_REPLACE_MATCH_MC)) { 1470 /* The 40th bit of Unicast must be 0 */ 1471 sal_memset(&mac_mask, 0x00, sizeof(mac_mask)); 1472 mac_mask[0] = 0x01; 1473 sal_memset(&mac_data, 0x00, sizeof(mac_data)); 1474 soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf, 1475 mac_mask); 1476 soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf, 1477 mac_data); 1478 } else if ((rep->flags & BCM_L2_REPLACE_MATCH_MC) && 1479 !(rep->flags & BCM_L2_REPLACE_MATCH_UC)) { 1480 /* The 40th bit of Multicast must be 1 */ 1481 sal_memset(&mac_mask, 0x00, sizeof(mac_mask)); 1482 mac_mask[0] = 0x01; 1483 sal_memset(&mac_data, 0x00, sizeof(mac_data)); 1484 mac_data[0] = 0x01; 1485 soc_mem_mac_addr_set(unit, L2Xm, &rep->match_mask, MAC_ADDRf, 1486 mac_mask); 1487 soc_mem_mac_addr_set(unit, L2Xm, &rep->match_data, MAC_ADDRf, 1488 mac_data); 1489 } 1490 1491 if (rep->flags & BCM_L2_REPLACE_MATCH_DEST) { 1492 field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf); 1493 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, DEST_TYPEf, 1494 (1 << field_len) - 1); 1495 1496 if (rep->match_dest.trunk != -1) { 1497 soc_mem_field32_set(unit, L2Xm, &rep->match_data, 1498 DEST_TYPEf, 1); 1499 1500 field_len = soc_mem_field_length(unit, L2Xm, TGIDf); 1501 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, TGIDf, 1502 (1 << field_len) - 1); 1503 soc_mem_field32_set(unit, L2Xm, &rep->match_data, TGIDf, 1504 rep->match_dest.trunk); 1505 } else { 1506 /* DEST_TYPE field in data is 0 */ 1507 1508 if (rep->match_dest.port != -1) { 1509 field_len = soc_mem_field_length(unit, L2Xm, PORT_NUMf); 1510 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, 1511 PORT_NUMf, (1 << field_len) - 1); 1512 soc_mem_field32_set(unit, L2Xm, &rep->match_data, 1513 PORT_NUMf, rep->match_dest.port); 1514 } 1515 1516 1517 } 1518 } 1519 1520 /* BCM_L2_REPLACE_MATCH_STATIC means to replace static as well as 1521 * non-static entries 1522 */ 1523 if (!(rep->flags & BCM_L2_REPLACE_MATCH_STATIC)) { 1524 if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_ONLY_STATIC) { 1525 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, STATIC_BITf, 1); 1526 soc_mem_field32_set(unit, L2Xm, &rep->match_data, STATIC_BITf, 1); 1527 } else { 1528 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, STATIC_BITf, 1); 1529 /* STATIC_BIT field in data is 0 */ 1530 } 1531 } 1532 /* STATIC_BIT field in mask is 0 */ 1533 1534 if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_DISCARD_SRC) { 1535 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, SRC_DISCARDf, 1); 1536 if (rep->key_l2_flags & BCM_L2_DISCARD_SRC) { 1537 soc_mem_field32_set(unit, L2Xm, &rep->match_data, SRC_DISCARDf, 1); 1538 } 1539 } 1540 1541 if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_SRC_HIT) { 1542 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITSAf, 1); 1543 if (rep->key_l2_flags & BCM_L2_SRC_HIT) { 1544 soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITSAf, 1); 1545 } 1546 } 1547 if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_DES_HIT) { 1548 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITDAf, 1); 1549 if (rep->key_l2_flags & BCM_L2_DES_HIT) { 1550 soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITDAf, 1); 1551 } 1552 } 1553 1554 if (rep->int_flags & _BCM_L2_REPLACE_INT_MATCH_NATIVE) { 1555 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, LOCAL_SAf, 1); 1556 if (rep->key_l2_flags & BCM_L2_NATIVE) { 1557 soc_mem_field32_set(unit, L2Xm, &rep->match_data, LOCAL_SAf, 1); 1558 } 1559 } 1560 1561 if (_CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(rep->flags)) { 1562 if (rep->flags & BCM_L2_REPLACE_DES_HIT_CLEAR) { 1563 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITDAf, 1); 1564 soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITDAf, 1); 1565 } 1566 if (rep->flags & BCM_L2_REPLACE_SRC_HIT_CLEAR) { 1567 soc_mem_field32_set(unit, L2Xm, &rep->match_mask, HITSAf, 1); 1568 soc_mem_field32_set(unit, L2Xm, &rep->match_data, HITSAf, 1); 1569 } 1570 } 1571 1572 if (!(rep->flags & BCM_L2_REPLACE_DELETE)) { 1573 if (!_CLEAR_ALL_ENTRIES_SRC_OR_DES_HIT_BIT(rep->flags)) { 1574 if (rep->new_dest.trunk != -1) { 1575 field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf); 1576 soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf, 1577 (1 << field_len) - 1); 1578 1579 soc_mem_field32_set(unit, L2Xm, &rep->new_data, DEST_TYPEf, 1); 1580 1581 /* 1582 * Writing to DESTINATION field instead of TGIDf 1583 * to ensure the MSB bits of DESTINATION are cleared. 1584 */ 1585 field_len = soc_mem_field_length(unit, L2Xm, DESTINATIONf); 1586 soc_mem_field32_set(unit, L2Xm, &rep->new_mask, 1587 DESTINATIONf, (1 << field_len) - 1); 1588 soc_mem_field32_set(unit, L2Xm, &rep->new_data, 1589 DESTINATIONf, rep->new_dest.trunk); 1590 } else if (rep->new_dest.port != -1 && rep->new_dest.module != -1) { 1591 /* DEST_TYPE field in data is 0 */ 1592 field_len = soc_mem_field_length(unit, L2Xm, DEST_TYPEf); 1593 soc_mem_field32_set(unit, L2Xm, &rep->new_mask, DEST_TYPEf, 1594 (1 << field_len) - 1); 1595 1596 field_len = soc_mem_field_length(unit, L2Xm, PORT_NUMf); 1597 soc_mem_field32_set(unit, L2Xm, &rep->new_mask, 1598 PORT_NUMf, (1 << field_len) - 1); 1599 soc_mem_field32_set(unit, L2Xm, &rep->new_data, 1600 PORT_NUMf, rep->new_dest.port); 1601 } 1602 } 1603 1604 if (rep->flags & BCM_L2_REPLACE_DES_HIT_CLEAR) { 1605 soc_mem_field32_set(unit, L2Xm, &rep->new_mask, HITDAf, 1); 1606 } 1607 if (rep->flags & BCM_L2_REPLACE_SRC_HIT_CLEAR) { 1608 soc_mem_field32_set(unit, L2Xm, &rep->new_mask, HITSAf, 1); 1609 } 1610 } 1611 1612 return BCM_E_NONE; 1613 } 1614 1615 STATIC int 1616 _bcm_th3_l2_is_soc_l2_mem_cache_enabled(int unit) 1617 { 1618 soc_mem_t mem = L2Xm; 1619 uint32 *cache; 1620 int copyno = SOC_MEM_BLOCK_ANY(unit, mem); 1621 1622 cache = SOC_MEM_STATE(unit, mem).cache[copyno]; 1623 1624 if (cache == NULL) { 1625 return FALSE; 1626 } 1627 1628 return TRUE; 1629 } 1630 1631 /* 1632 * Function: 1633 * _bcm_th3_l2_entry_replace 1634 * Description: 1635 * Helper function to bcm_l2_replace API to be used as a call back for 1636 * bcm_l2_traverse API and replace given entry if MAC matches 1637 * Parameters: 1638 * unit device number 1639 * trav_st structure with information from traverse function 1640 * Return: 1641 * BCM_E_XXX 1642 */ 1643 STATIC int 1644 _bcm_th3_l2_entry_replace(int unit, void *trav_st) 1645 { 1646 _bcm_l2_replace_t *rep_st; 1647 soc_mem_t mem; 1648 uint32 *entry; 1649 uint32 *match_data, *match_mask; 1650 int entry_words, i, idx, rv; 1651 bcm_mac_t l2mac; 1652 int port_val, trunk_val; 1653 soc_control_t *soc = SOC_CONTROL(unit); 1654 bcm_l2_addr_t l2_addr; 1655 1656 if (trav_st == NULL) { 1657 return BCM_E_PARAM; 1658 } 1659 1660 mem = ((_bcm_l2_traverse_t *)trav_st)->mem; 1661 entry = ((_bcm_l2_traverse_t *)trav_st)->data; 1662 idx = ((_bcm_l2_traverse_t *)trav_st)->mem_idx; 1663 rep_st = ((_bcm_l2_traverse_t *)trav_st)->user_data; 1664 1665 if (rep_st == NULL || entry == NULL || mem == INVALIDm) { 1666 return BCM_E_PARAM; 1667 } 1668 1669 match_data = (uint32 *)&rep_st->match_data; 1670 match_mask = (uint32 *)&rep_st->match_mask; 1671 entry_words = soc_mem_entry_words(unit, mem); 1672 1673 for (i = 0; i < entry_words; i++) { 1674 if ((entry[i] ^ match_data[i]) & match_mask[i]) { 1675 return BCM_E_NONE; 1676 } 1677 } 1678 if (rep_st->int_flags & _BCM_L2_REPLACE_INT_NO_ACTION) { 1679 BCM_IF_ERROR_RETURN 1680 (_bcm_th3_l2_from_l2x(unit, &l2_addr, (l2x_entry_t *)entry)); 1681 return rep_st->trav_fn(unit, &l2_addr, rep_st->user_data); 1682 } 1683 if (rep_st->flags & BCM_L2_REPLACE_DELETE) { 1684 MEM_LOCK(unit, mem); 1685 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 1686 MEM_UNLOCK(unit, mem); 1687 return BCM_E_RESOURCE; 1688 } 1689 rv = soc_mem_delete(unit, mem, MEM_BLOCK_ALL, entry); 1690 #ifdef BCM_XGS_SWITCH_SUPPORT 1691 if (BCM_SUCCESS(rv)) { 1692 rv = soc_l2x_sync_delete(unit, entry, idx, 1693 rep_st->flags & BCM_L2_REPLACE_NO_CALLBACKS ? 1694 SOC_L2X_NO_CALLBACKS : 0); 1695 1696 if (rep_st->flags & BCM_L2_REPLACE_NO_CALLBACKS) { 1697 sal_mutex_take(SOC_CONTROL(unit)->l2x_lrn_shadow_mutex, 1698 sal_mutex_FOREVER); 1699 soc_th3_lrn_shadow_delete(unit, (l2x_entry_t *)entry); 1700 sal_mutex_give(SOC_CONTROL(unit)->l2x_lrn_shadow_mutex); 1701 } 1702 } 1703 #endif /* BCM_XGS_SWITCH_SUPPORT */ 1704 SOC_L2_DEL_SYNC_UNLOCK(soc); 1705 MEM_UNLOCK(unit, mem); 1706 1707 return rv; 1708 } 1709 1710 if (rep_st->flags & BCM_L2_REPLACE_MATCH_VLAN) { 1711 if (soc_mem_field32_get(unit, mem, entry, VLAN_IDf) != 1712 rep_st->key_vlan) { 1713 return BCM_E_NONE; 1714 } 1715 } 1716 1717 if (rep_st->flags & BCM_L2_REPLACE_MATCH_MAC) { 1718 soc_mem_mac_addr_get(unit, mem, entry, MAC_ADDRf, l2mac); 1719 if (ENET_CMP_MACADDR(rep_st->key_mac, l2mac)) { 1720 return BCM_E_NONE; 1721 } 1722 } 1723 1724 if (rep_st->flags & BCM_L2_REPLACE_MATCH_DEST) { 1725 trunk_val = -1; 1726 port_val = -1; 1727 1728 if (soc_mem_field32_get(unit, mem, entry, Tf)) { 1729 trunk_val = soc_mem_field32_get(unit, mem, entry, TGIDf); 1730 } else { 1731 port_val = soc_mem_field32_get(unit, mem, entry, PORT_NUMf); 1732 } 1733 1734 if (rep_st->match_dest.trunk != -1) { 1735 if (rep_st->match_dest.trunk != trunk_val) { 1736 return BCM_E_NONE; 1737 } 1738 } else { 1739 if (rep_st->match_dest.port != port_val) { 1740 return BCM_E_NONE; 1741 } 1742 } 1743 } 1744 1745 /* Check if user wants static field matched with the entry's static bit */ 1746 if (!(rep_st->flags & BCM_L2_REPLACE_MATCH_STATIC)) { 1747 /* BCM_L2_REPLACE_MATCH_STATIC means to replace static as well as 1748 * non-static entries */ 1749 if (soc_mem_field32_get(unit, mem, entry, STATIC_BITf)) { 1750 return BCM_E_NONE; 1751 } 1752 } 1753 1754 /* Perform replace action on matching entry */ 1755 /* Note: replace delete flag has been handled at top of this function */ 1756 if (rep_st->new_dest.trunk != -1) { /* New destination is trunk */ 1757 soc_mem_field32_set(unit, mem, entry, DEST_TYPEf, 1); 1758 soc_mem_field32_set(unit, mem, entry, TGIDf, 1759 rep_st->new_dest.trunk); 1760 } else { /* New destination is mod port */ 1761 soc_mem_field32_set(unit, mem, entry, DEST_TYPEf, 0); 1762 soc_mem_field32_set(unit, mem, entry, PORT_NUMf, 1763 rep_st->new_dest.port); 1764 } 1765 1766 return soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx, entry); 1767 } 1768 1769 /* 1770 * Function: 1771 * _bcm_th3_l2_replace 1772 * Description: 1773 * Helper function called by main replace API implementation 1774 * Parameters: 1775 * unit - (IN) Unit number. 1776 * flags - (IN) BCM_L2_REPLACE_* flags 1777 * match_addr - (IN) L2 information used to match one/more L2 addresses 1778 * new_module - (IN) Module number. Not used, see Note below 1779 * new_port - (IN) Port number to replace in the matching entries 1780 * new_trunk - (IN) Port number to replace in the matching entries 1781 * trav_fn - (IN) Callback function (optional) to process matchin 1782 * entries 1783 * user_data - (IN) Arguments to pass to callback function (trav_fn) 1784 * (optional) 1785 * Return: 1786 * BCM_E_XXX 1787 * Note: 1788 * new_module is not used. We accept it here for maintaining compatibility of 1789 * various APIs' behavior. Invalid module id will be rejected inside the call 1790 * sequence below 1791 */ 1792 STATIC int 1793 _bcm_th3_l2_replace(int unit, uint32 flags, uint32 int_flags, 1794 bcm_l2_addr_t *match_addr, bcm_module_t new_module, 1795 bcm_port_t new_port, bcm_trunk_t new_trunk, 1796 bcm_l2_traverse_cb trav_fn, 1797 void *user_data) 1798 { 1799 _bcm_l2_replace_t rep_st; 1800 _bcm_l2_traverse_t trav_st; 1801 int rv = BCM_E_UNAVAIL; 1802 int do_freeze; 1803 1804 sal_memset(&rep_st, 0, sizeof(_bcm_l2_replace_t)); 1805 sal_memset(&trav_st, 0, sizeof(_bcm_l2_traverse_t)); 1806 1807 rep_st.trav_fn = trav_fn; 1808 rep_st.user_data = user_data; 1809 rep_st.flags = flags; 1810 rep_st.int_flags = int_flags; 1811 if ((int_flags & _BCM_L2_REPLACE_IGNORE_PORTID) && 1812 !(flags & BCM_L2_REPLACE_DELETE) && 1813 !(flags & BCM_L2_REPLACE_MATCH_DEST)) { 1814 return BCM_E_PARAM; 1815 } 1816 1817 if (!(flags & BCM_L2_REPLACE_DELETE) && 1818 !(int_flags & _BCM_L2_REPLACE_INT_NO_ACTION)) { 1819 BCM_IF_ERROR_RETURN(_bcm_th3_l2_replace_dest_setup 1820 (unit, new_module, new_port, new_trunk, 1821 flags & BCM_L2_REPLACE_NEW_TRUNK, 1822 &rep_st.new_dest)); 1823 } 1824 1825 /* Note rep_st.key_type is 0 */ 1826 1827 if (match_addr != NULL) { 1828 rep_st.key_l2_flags = match_addr->flags; 1829 1830 if (flags & BCM_L2_REPLACE_MATCH_DEST) { 1831 if (int_flags & _BCM_L2_REPLACE_IGNORE_PORTID) { 1832 if (!SOC_MODID_ADDRESSABLE(unit, match_addr->modid)) { 1833 return BCM_E_BADID; 1834 } 1835 rep_st.match_dest.vp = -1; 1836 rep_st.match_dest.trunk = -1; 1837 rep_st.match_dest.port = -1; 1838 rep_st.match_dest.module = 0; /* match_addr->modid; ignored */ 1839 } else { 1840 BCM_IF_ERROR_RETURN(_bcm_th3_l2_replace_dest_setup 1841 (unit, match_addr->modid, match_addr->port, 1842 match_addr->tgid, 1843 match_addr->flags & BCM_L2_TRUNK_MEMBER, 1844 &rep_st.match_dest)); 1845 } 1846 } 1847 1848 if (flags & BCM_L2_REPLACE_MATCH_VLAN) { 1849 rep_st.key_vfi = -1; 1850 VLAN_CHK_ID(unit, match_addr->vid); 1851 rep_st.key_vlan = match_addr->vid; 1852 rep_st.key_type = 0; /* L2 Bridge */ 1853 } 1854 1855 if (flags & BCM_L2_REPLACE_MATCH_MAC) { 1856 sal_memcpy(&rep_st.key_mac, match_addr->mac, sizeof(bcm_mac_t)); 1857 /* When replace L2 by MAC, key type must be provided. */ 1858 /* Key type is 0 by default for L2 Bridge. */ 1859 } 1860 } 1861 1862 BCM_IF_ERROR_RETURN(_bcm_th3_l2_replace_data_mask_setup(unit, &rep_st)); 1863 1864 /* Delete operation don't require freeze */ 1865 do_freeze = FALSE; 1866 if (!(flags & BCM_L2_REPLACE_DELETE) || 1867 ((flags & BCM_L2_REPLACE_MATCH_STATIC) && 1868 _bcm_th3_l2_is_soc_l2_mem_cache_enabled(unit))) { 1869 do_freeze = TRUE; 1870 } 1871 1872 if (do_freeze) { 1873 BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_freeze(unit)); 1874 } 1875 1876 trav_st.user_data = (void *)&rep_st; 1877 trav_st.int_cb = _bcm_th3_l2_entry_replace; 1878 rv = _bcm_th3_l2_traverse(unit, &trav_st); 1879 1880 /* Check with Michael what this does rv = _soc_l2_sync_mem_cache(unit, &rep_st); */ 1881 1882 if (do_freeze) { 1883 BCM_IF_ERROR_RETURN(bcm_esw_l2_addr_thaw(unit)); 1884 } 1885 1886 return rv; 1887 } 1888 1889 /* 1890 * Function: 1891 * bcm_tomahawk3_l2_addr_delete_by_mac 1892 * Description: 1893 * Delete L2 entries associated with a MAC address 1894 * Parameters: 1895 * unit - device unit 1896 * mac - MAC address 1897 * flags - BCM_L2_DELETE_XXX 1898 * Returns: 1899 * BCM_E_XXX 1900 * Notes: 1901 * Static entries are removed only if BCM_L2_DELETE_STATIC flag is used. 1902 * L2 aging and learning are disabled during this operation 1903 */ 1904 int 1905 bcm_tomahawk3_l2_addr_delete_by_mac(int unit, bcm_mac_t mac, uint32 flags) 1906 { 1907 bcm_l2_addr_t match_addr; 1908 uint32 repl_flags; 1909 1910 TH3_L2_INIT(unit); 1911 1912 sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t)); 1913 sal_memcpy(match_addr.mac, mac, sizeof(bcm_mac_t)); 1914 1915 BCM_IF_ERROR_RETURN 1916 (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags)); 1917 1918 /* Traverse l2 entry contains MAC address field by key type */ 1919 repl_flags |= BCM_L2_REPLACE_MATCH_MAC; 1920 1921 return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0, 1922 NULL, NULL); 1923 } 1924 1925 /* 1926 * Function: 1927 * bcm_tomahawk3_l2_addr_delete_by_vlan 1928 * Description: 1929 * Delete L2 entries associated with a VLAN 1930 * Parameters: 1931 * unit - device unit 1932 * vid - VLAN id 1933 * flags - BCM_L2_DELETE_XXX 1934 * Returns: 1935 * BCM_E_XXX 1936 * Notes: 1937 * Static entries are removed only if BCM_L2_DELETE_STATIC flag is used 1938 * L2 aging and learning are disabled during this operation. 1939 */ 1940 int 1941 bcm_tomahawk3_l2_addr_delete_by_vlan(int unit, bcm_vlan_t vid, uint32 flags) 1942 { 1943 bcm_l2_addr_t match_addr; 1944 uint32 repl_flags; 1945 1946 TH3_L2_INIT(unit); 1947 1948 sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t)); 1949 match_addr.vid = vid; 1950 BCM_IF_ERROR_RETURN 1951 (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags)); 1952 repl_flags |= BCM_L2_REPLACE_MATCH_VLAN; 1953 return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0, 1954 NULL, NULL); 1955 } 1956 1957 /* 1958 * Function: 1959 * bcm_tomahawk3_l2_addr_delete_by_port 1960 * Description: 1961 * Delete L2 addresses associated with a destination module/port. 1962 * Parameters: 1963 * unit - device unit 1964 * mod - module id (or -1 for local unit) 1965 * port - port 1966 * flags - BCM_L2_DELETE_XXX 1967 * Returns: 1968 * BCM_E_XXX 1969 * Notes: 1970 * Static entries are removed only if BCM_L2_DELETE_STATIC flag is used. 1971 * L2 aging and learning are disabled during this operation. 1972 */ 1973 1974 int 1975 bcm_tomahawk3_l2_addr_delete_by_port(int unit, 1976 bcm_module_t mod, bcm_port_t port, 1977 uint32 flags) 1978 { 1979 bcm_l2_addr_t match_addr; 1980 uint32 repl_flags; 1981 uint32 int_flags = 0; 1982 1983 TH3_L2_INIT(unit); 1984 1985 sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t)); 1986 if (port == -1) { 1987 /* non zero mod id is not used, replace will return error */ 1988 match_addr.modid = mod; 1989 match_addr.port = -1; 1990 int_flags = _BCM_L2_REPLACE_IGNORE_PORTID; 1991 } else if (!BCM_GPORT_IS_SET(port) && mod == -1) { 1992 if (!SOC_PORT_VALID(unit, port)) { 1993 return BCM_E_PORT; 1994 } 1995 1996 match_addr.modid = SOC_BASE_MODID(unit); 1997 } else { 1998 match_addr.modid = mod; 1999 } 2000 2001 match_addr.port = port; 2002 2003 BCM_IF_ERROR_RETURN 2004 (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags)); 2005 2006 repl_flags |= BCM_L2_REPLACE_MATCH_DEST; 2007 2008 return _bcm_th3_l2_replace(unit, repl_flags, int_flags, &match_addr, 0, 0, 2009 0, NULL, NULL); 2010 } 2011 2012 /* 2013 * Function: 2014 * bcm_tomahawk3_l2_addr_delete_by_trunk 2015 * Description: 2016 * Delete L2 entries associated with a trunk 2017 * Parameters: 2018 * unit - device unit 2019 * tid - trunk id 2020 * flags - BCM_L2_DELETE_XXX 2021 * Returns: 2022 * BCM_E_XXX 2023 * Notes: 2024 * Static entries are removed only if BCM_L2_DELETE_STATIC flag is used 2025 * L2 aging and learning are disabled during this operation. 2026 */ 2027 int 2028 bcm_tomahawk3_l2_addr_delete_by_trunk(int unit, bcm_trunk_t tid, uint32 flags) 2029 { 2030 bcm_l2_addr_t match_addr; 2031 uint32 repl_flags; 2032 2033 TH3_L2_INIT(unit); 2034 2035 sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t)); 2036 match_addr.tgid = tid; 2037 match_addr.flags = BCM_L2_TRUNK_MEMBER; 2038 2039 BCM_IF_ERROR_RETURN 2040 (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags)); 2041 repl_flags |= BCM_L2_REPLACE_MATCH_DEST; 2042 2043 return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0, 2044 NULL, NULL); 2045 } 2046 2047 /* 2048 * Function: 2049 * bcm_tomahawk3_l2_addr_delete_by_mac_port 2050 * Description: 2051 * Delete L2 entries associated with a MAC address and 2052 * a destination module/port 2053 * Parameters: 2054 * unit - device unit 2055 * mac - MAC address 2056 * mod - module id 2057 * port - port 2058 * flags - BCM_L2_DELETE_XXX 2059 * Returns: 2060 * BCM_E_XXX 2061 * Notes: 2062 * Static entries are removed only if BCM_L2_DELETE_STATIC flag is used. 2063 * L2 aging and learning are disabled during this operation. 2064 */ 2065 int 2066 bcm_tomahawk3_l2_addr_delete_by_mac_port(int unit, bcm_mac_t mac, 2067 bcm_module_t mod, bcm_port_t port, 2068 uint32 flags) 2069 { 2070 bcm_l2_addr_t match_addr; 2071 uint32 repl_flags; 2072 2073 TH3_L2_INIT(unit); 2074 2075 sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t)); 2076 sal_memcpy(match_addr.mac, mac, sizeof(bcm_mac_t)); 2077 2078 if (!BCM_GPORT_IS_SET(port) && mod == -1) { 2079 if (!SOC_PORT_VALID(unit, port)) { 2080 return BCM_E_PORT; 2081 } 2082 match_addr.modid = SOC_BASE_MODID(unit); 2083 } else { 2084 match_addr.modid = mod; 2085 } 2086 match_addr.port = port; 2087 BCM_IF_ERROR_RETURN 2088 (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags)); 2089 repl_flags |= BCM_L2_REPLACE_MATCH_MAC | BCM_L2_REPLACE_MATCH_DEST; 2090 return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0, 2091 NULL, NULL); 2092 } 2093 2094 /* 2095 * Function: 2096 * bcm_tomahawk3_l2_addr_delete_by_vlan_port 2097 * Description: 2098 * Delete L2 entries associated with a VLAN and 2099 * a destination module/port 2100 * Parameters: 2101 * unit - device unit 2102 * vid - VLAN id 2103 * mod - module id 2104 * port - port 2105 * flags - BCM_L2_DELETE_XXX 2106 * Returns: 2107 * BCM_E_XXX 2108 * Notes: 2109 * Static entries are removed only if BCM_L2_DELETE_STATIC flag is used. 2110 * L2 aging and learning are disabled during this operation. 2111 */ 2112 int 2113 bcm_tomahawk3_l2_addr_delete_by_vlan_port(int unit, bcm_vlan_t vid, 2114 bcm_module_t mod, bcm_port_t port, 2115 uint32 flags) 2116 { 2117 bcm_l2_addr_t match_addr; 2118 uint32 repl_flags; 2119 2120 TH3_L2_INIT(unit); 2121 2122 sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t)); 2123 match_addr.vid = vid; 2124 2125 if (!BCM_GPORT_IS_SET(port) && mod == -1) { 2126 if (!SOC_PORT_VALID(unit, port)) { 2127 return BCM_E_PORT; 2128 } 2129 match_addr.modid = SOC_BASE_MODID(unit); 2130 } else { 2131 match_addr.modid = mod; 2132 } 2133 match_addr.port = port; 2134 BCM_IF_ERROR_RETURN 2135 (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags)); 2136 repl_flags |= BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST; 2137 return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0, 2138 NULL, NULL); 2139 } 2140 2141 /* 2142 * Function: 2143 * bcm_tomahawk3_l2_addr_delete_by_vlan_trunk 2144 * Description: 2145 * Delete L2 entries associated with a VLAN and a 2146 * destination trunk. 2147 * Parameters: 2148 * unit - device unit 2149 * vid - VLAN id 2150 * tid - trunk group id 2151 * flags - BCM_L2_DELETE_XXX 2152 * Returns: 2153 * BCM_E_XXX 2154 * Notes: 2155 * Static entries are removed only if BCM_L2_DELETE_STATIC flag is used. 2156 * L2 aging and learning are disabled during this operation. 2157 */ 2158 int 2159 bcm_tomahawk3_l2_addr_delete_by_vlan_trunk(int unit, bcm_vlan_t vid, 2160 bcm_trunk_t tid, uint32 flags) 2161 { 2162 bcm_l2_addr_t match_addr; 2163 uint32 repl_flags; 2164 2165 TH3_L2_INIT(unit); 2166 2167 sal_memset(&match_addr, 0, sizeof(bcm_l2_addr_t)); 2168 match_addr.vid = vid; 2169 match_addr.tgid = tid; 2170 match_addr.flags = BCM_L2_TRUNK_MEMBER; 2171 2172 BCM_IF_ERROR_RETURN 2173 (_bcm_th3_delete_replace_flags_convert(unit, flags, &repl_flags)); 2174 repl_flags |= BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST; 2175 return _bcm_th3_l2_replace(unit, repl_flags, 0, &match_addr, 0, 0, 0, 2176 NULL, NULL); 2177 } 2178 2179 /* 2180 * Function: 2181 * bcm_tomahawk3_l2_replace 2182 * Description: 2183 * This function replaces, or deletes destination for multiple L2 entries 2184 * Parameters: 2185 * unit device number 2186 * flags flags BCM_L2_REPLACE_* 2187 * match_addr L2 parameters to match on delete/replace 2188 * new_module new module ID for a replace (not used) 2189 * new_port new port for a replace 2190 * new_trunk new trunk for a replace 2191 * Return: 2192 * BCM_E_XXX 2193 * Notes: 2194 * The following replace flags are supported on Tomahawk3 since there are no 2195 * requirements in this area (refer PRD), and/or there is no h/w support for 2196 * these flags (Example, flags related to VPN, pending flag and so on) 2197 */ 2198 int 2199 bcm_tomahawk3_l2_replace(int unit, uint32 flags, bcm_l2_addr_t *match_addr, 2200 bcm_module_t new_module, bcm_port_t new_port, 2201 bcm_trunk_t new_trunk) 2202 { 2203 TH3_L2_INIT(unit); 2204 2205 if (!flags) { 2206 return BCM_E_PARAM; 2207 } 2208 2209 if ((flags & (BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_AGE)) && 2210 (flags & BCM_L2_REPLACE_NEW_TRUNK)) { 2211 return BCM_E_PARAM; 2212 } 2213 2214 /* The following flags are not supported */ 2215 if ((flags & BCM_L2_REPLACE_VPN_TYPE) || 2216 (flags & BCM_L2_REPLACE_VLAN_AND_VPN_TYPE) || 2217 (flags & BCM_L2_REPLACE_PENDING) || 2218 (flags & BCM_L2_REPLACE_IGNORE_PENDING) || 2219 (flags & BCM_L2_REPLACE_LEARN_LIMIT) || 2220 (flags & BCM_L2_REPLACE_AGE)) { 2221 return BCM_E_UNAVAIL; 2222 } 2223 2224 if ((flags & BCM_L2_REPLACE_DELETE) && (flags & BCM_L2_REPLACE_MATCH_MAC) && 2225 ((flags & BCM_L2_REPLACE_MATCH_UC) || 2226 (flags & BCM_L2_REPLACE_MATCH_MC))) { 2227 return BCM_E_PARAM; 2228 } 2229 2230 /* matching L2 address allowed to be NULL together with */ 2231 /* BCM_L2_REPLACE_DELETE flag indicating to delete all entries */ 2232 if (NULL == match_addr) { 2233 if (!(flags & BCM_L2_REPLACE_DELETE) && 2234 !(flags & (BCM_L2_REPLACE_SRC_HIT_CLEAR | 2235 BCM_L2_REPLACE_DES_HIT_CLEAR))) { 2236 return BCM_E_PARAM; 2237 } 2238 flags &= ~(BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_MAC | 2239 BCM_L2_REPLACE_MATCH_DEST); 2240 } 2241 /* coverity[var_deref_op : FALSE] */ 2242 /* coverity[var_deref_model : FALSE] */ 2243 return _bcm_th3_l2_replace(unit, flags, 0, match_addr, new_module, 2244 new_port, new_trunk, NULL, NULL); 2245 } 2246 2247 2248 #if 0 2249 #ifdef BCM_XGS_SWITCH_SUPPORT 2250 /* 2251 * Function: 2252 * _bcm_get_op_from_flags 2253 * Description: 2254 * Helper function to _bcm_fb_age_reg_config to 2255 * decide on a PPA command according to flags 2256 * Parameters: 2257 * flags flags BCM_L2_REPLACE_* 2258 * op PPA command to be programmed 2259 * sync_op Search Key for _soc_l2x_sync_delete_by 2260 * Return: 2261 * BCM_E_NONE - Success 2262 * BCM_E_PARAM - Failure 2263 */ 2264 int 2265 _bcm_get_op_from_flags(uint32 flags, uint32 *op, uint32 *sync_op) 2266 { 2267 uint32 cmp_flags = 0, int_op = 0, int_sync_op = 0; 2268 int rv = BCM_E_NONE; 2269 2270 if (NULL == op) { 2271 return BCM_E_PARAM; 2272 } 2273 cmp_flags = flags & (BCM_L2_REPLACE_MATCH_VLAN | 2274 BCM_L2_REPLACE_MATCH_DEST); 2275 switch (cmp_flags) { 2276 case BCM_L2_REPLACE_MATCH_VLAN: 2277 { 2278 int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_VLAN : 2279 XGS_PPAMODE_VLAN_REPLACE); 2280 int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_VLAN_DEL : 2281 SOC_L2X_NO_DEL); 2282 break; 2283 } 2284 case BCM_L2_REPLACE_MATCH_DEST : 2285 { 2286 int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_PORTMOD : 2287 XGS_PPAMODE_PORTMOD_REPLACE); 2288 int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_PORTMOD_DEL : 2289 SOC_L2X_NO_DEL); 2290 break; 2291 } 2292 case BCM_L2_REPLACE_MATCH_VLAN | BCM_L2_REPLACE_MATCH_DEST: 2293 { 2294 int_op = (flags & BCM_L2_REPLACE_DELETE ? XGS_PPAMODE_PORTMOD_VLAN : 2295 XGS_PPAMODE_PORTMOD_VLAN_REPLACE); 2296 int_sync_op = (flags & BCM_L2_REPLACE_DELETE ? SOC_L2X_PORTMOD_VLAN_DEL : 2297 SOC_L2X_NO_DEL); 2298 2299 break; 2300 } 2301 default: 2302 rv = BCM_E_PARAM; 2303 break; 2304 } 2305 2306 *op = int_op; 2307 *sync_op = int_sync_op; 2308 return rv; 2309 } 2310 2311 #endif /* BCM_XGS_SWITCH_SUPPORT */ 2312 2313 STATIC int 2314 _soc_l2_sync_mem_cache(int unit, _bcm_l2_replace_t *rep_st) 2315 { 2316 uint8 *vmap; 2317 soc_mem_t mem = L2Xm; 2318 uint32 *cache, *entry, *match_data, *match_mask; 2319 uint32 *new_data, *new_mask; 2320 int index_max, idx, i; 2321 int entry_dw = soc_mem_entry_words(unit, mem); 2322 int entry_words = soc_mem_entry_words(unit, mem); 2323 int copyno = SOC_MEM_BLOCK_ANY(unit, mem); 2324 soc_field_t vld_fld = VALIDf; 2325 2326 cache = SOC_MEM_STATE(unit, mem).cache[copyno]; 2327 if (cache == NULL) { 2328 return BCM_E_NONE; 2329 } 2330 2331 if (soc_feature(unit, soc_feature_base_valid)) { 2332 vld_fld = BASE_VALIDf; 2333 } 2334 vmap = SOC_MEM_STATE(unit, mem).vmap[copyno]; 2335 index_max = soc_mem_index_max(unit, mem); 2336 for (idx = 0; idx <= index_max; idx++) { 2337 if (!CACHE_VMAP_TST(vmap, idx)) { 2338 continue; 2339 } 2340 entry = cache + (idx * entry_dw); 2341 if (!soc_mem_field32_get(unit, mem, entry, vld_fld)) { 2342 continue; 2343 } 2344 if (!soc_mem_field32_get(unit, mem, entry, STATIC_BITf)) { 2345 continue; 2346 } 2347 match_data = (uint32 *)&rep_st->match_data; 2348 match_mask = (uint32 *)&rep_st->match_mask; 2349 for (i = 0; i < entry_words; i++) { 2350 if ((entry[i] ^ match_data[i]) & match_mask[i]) { 2351 break; 2352 } 2353 } 2354 if (i != entry_words) { 2355 continue; 2356 } 2357 /* Match found, delete or replace entry */ 2358 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2359 (BSL_META_U(unit, 2360 "Match found in L2 bulk cache op: %d\n"), idx)); 2361 if (rep_st->flags & BCM_L2_REPLACE_DELETE) { 2362 /* Delete op - invalidate the entry */ 2363 CACHE_VMAP_CLR(vmap, idx); 2364 } else { 2365 /* Replace op - update entry */ 2366 new_data = (uint32 *)&rep_st->new_data; 2367 new_mask = (uint32 *)&rep_st->new_mask; 2368 for (i = 0; i < entry_words; i++) { 2369 entry[i] ^= (entry[i] ^ new_data[i]) & new_mask[i]; 2370 } 2371 } 2372 } 2373 return BCM_E_NONE; 2374 } 2375 2376 /* 2377 * Function: 2378 * bcm_esw_l2_station_add 2379 * Description: 2380 * Add an entry to L2 Station Table 2381 * Parameters: 2382 * unit - (IN) BCM device number 2383 * station_id - (IN/OUT) Station ID 2384 * station - (IN) Pointer to station address information 2385 * Return: 2386 * BCM_E_XXX 2387 */ 2388 int 2389 bcm_esw_l2_station_add(int unit, int *station_id, bcm_l2_station_t *station) 2390 { 2391 int rv = BCM_E_UNAVAIL; 2392 2393 #if defined(BCM_TRIUMPH_SUPPORT) 2394 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit) 2395 || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) { 2396 rv = bcm_tr_l2_station_add(unit, station_id, station); 2397 } 2398 #endif 2399 2400 return (rv); 2401 } 2402 2403 /* 2404 * Function: 2405 * bcm_esw_l2_station_delete 2406 * Description: 2407 * Delete an entry from L2 Station Table 2408 * Parameters: 2409 * unit - (IN) BCM device number 2410 * station_id - (IN) Station ID 2411 * Return: 2412 * BCM_E_XXX 2413 */ 2414 int 2415 bcm_esw_l2_station_delete(int unit, int station_id) 2416 { 2417 2418 int rv = BCM_E_UNAVAIL; 2419 2420 #if defined(BCM_TRIUMPH_SUPPORT) 2421 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit) 2422 || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) { 2423 rv = bcm_tr_l2_station_delete(unit, station_id); 2424 } 2425 #endif 2426 return (rv); 2427 } 2428 2429 /* 2430 * Function: 2431 * bcm_esw_l2_station_delete_all 2432 * Description: 2433 * Clear all L2 Station Table entries 2434 * Parameters: 2435 * unit - (IN) BCM device number 2436 * Return: 2437 * BCM_E_XXX 2438 */ 2439 int 2440 bcm_esw_l2_station_delete_all(int unit) 2441 { 2442 int rv = BCM_E_UNAVAIL; 2443 2444 #if defined(BCM_TRIUMPH_SUPPORT) 2445 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit) 2446 || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) { 2447 rv = bcm_tr_l2_station_delete_all(unit); 2448 } 2449 #endif 2450 2451 return (rv); 2452 } 2453 2454 /* 2455 * Function: 2456 * bcm_esw_l2_station_get 2457 * Description: 2458 * Get L2 station entry detail from Station Table 2459 * Parameters: 2460 * unit - (IN) BCM device number 2461 * station_id - (IN) Station ID 2462 * station - (OUT) Pointer to station address information. 2463 * Return: 2464 * BCM_E_XXX 2465 */ 2466 int 2467 bcm_esw_l2_station_get(int unit, int station_id, bcm_l2_station_t *station) 2468 { 2469 int rv = BCM_E_UNAVAIL; 2470 2471 #if defined(BCM_TRIUMPH_SUPPORT) 2472 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit) 2473 || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) { 2474 rv = bcm_tr_l2_station_get(unit, station_id, station); 2475 } 2476 #endif 2477 2478 return (rv); 2479 } 2480 2481 /* 2482 * Function: 2483 * bcm_esw_l2_station_size_get 2484 * Description: 2485 * Get size of L2 Station Table 2486 * Parameters: 2487 * unit - (IN) BCM device number 2488 * size - (OUT) L2 Station table size 2489 * Return: 2490 * BCM_E_XXX 2491 */ 2492 int 2493 bcm_esw_l2_station_size_get(int unit, int *size) 2494 { 2495 int rv = BCM_E_UNAVAIL; 2496 2497 #if defined(BCM_TRIUMPH_SUPPORT) 2498 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || SOC_IS_TOMAHAWK(unit) 2499 || SOC_IS_KATANAX(unit) || SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) { 2500 rv = bcm_tr_l2_station_size_get(unit, size); 2501 } 2502 #endif 2503 2504 return (rv); 2505 } 2506 2507 /* 2508 * Function: 2509 * bcm_esw_l2_station_traverse 2510 * Description: 2511 * Traverse L2 station entry from Station Table 2512 * Parameters: 2513 * unit - (IN) BCM device number 2514 * trav_fn - (IN) Customer defines function is used to traverse 2515 * user_data - (IN) Pointer to information of customer. 2516 * Return: 2517 * BCM_E_XXX 2518 */ 2519 int 2520 bcm_esw_l2_station_traverse(int unit, bcm_l2_station_traverse_cb trav_fn, void *user_data) 2521 { 2522 int rv = BCM_E_UNAVAIL; 2523 2524 #if defined(BCM_TRIUMPH_SUPPORT) 2525 if (SOC_IS_TRIDENT(unit) || SOC_IS_TRIDENT2X(unit) || 2526 SOC_IS_TOMAHAWK(unit) || SOC_IS_KATANAX(unit) || 2527 SOC_IS_TRIUMPH3(unit) || SOC_IS_TRIDENT3(unit)) { 2528 rv = bcm_tr_l2_station_traverse(unit, trav_fn, user_data); 2529 } 2530 #endif 2531 2532 return (rv); 2533 } 2534 2535 #endif 2536 2537 int 2538 bcm_tomahawk3_l2_ring_replace( int unit, bcm_l2_ring_t *l2_ring) 2539 { 2540 return BCM_E_UNAVAIL; 2541 } 2542 2543 /* 2544 * Function: 2545 * bcm_tomahawk3_l2_mac_port_create 2546 * Description: 2547 * Create a MAC port. 2548 * Parameters: 2549 * unit - (IN) BCM device number 2550 * mac_port - (IN/OUT) MAC port info 2551 * Return: 2552 * BCM_E_XXX 2553 */ 2554 int 2555 bcm_tomahawk3_l2_mac_port_create(int unit, bcm_l2_mac_port_t *mac_port) 2556 { 2557 return BCM_E_UNAVAIL; 2558 } 2559 2560 /* 2561 * Function: 2562 * bcm_tomahawk3_l2_mac_port_destroy 2563 * Description: 2564 * Destroy a MAC port. 2565 * Parameters: 2566 * unit - (IN) BCM device number 2567 * mac_port_id - (IN) MAC port GPORT ID 2568 * Return: 2569 * BCM_E_XXX 2570 */ 2571 int 2572 bcm_tomahawk3_l2_mac_port_destroy(int unit, bcm_gport_t mac_port_id) 2573 { 2574 return BCM_E_UNAVAIL; 2575 } 2576 2577 /* 2578 * Function: 2579 * bcm_tomahawk3_l2_mac_port_destroy_all 2580 * Description: 2581 * Destroy all MAC ports. 2582 * Parameters: 2583 * unit - (IN) BCM device number 2584 * Return: 2585 * BCM_E_XXX 2586 */ 2587 int 2588 bcm_tomahawk3_l2_mac_port_destroy_all(int unit) 2589 { 2590 return BCM_E_UNAVAIL; 2591 } 2592 2593 /* 2594 * Function: 2595 * bcm_tomahawk3_l2_mac_port_get 2596 * Description: 2597 * Get info about a MAC port. 2598 * Parameters: 2599 * unit - (IN) BCM device number 2600 * mac_port - (IN/OUT) MAC port info 2601 * Return: 2602 * BCM_E_XXX 2603 */ 2604 int 2605 bcm_tomahawk3_l2_mac_port_get(int unit, bcm_l2_mac_port_t *mac_port) 2606 { 2607 return BCM_E_UNAVAIL; 2608 } 2609 2610 /* 2611 * Function: 2612 * bcm_tomahawk3_l2_mac_port_traverse 2613 * Description: 2614 * Traverse MAC ports. 2615 * Parameters: 2616 * unit - (IN) BCM device number 2617 * cb - (IN) Callback 2618 * user_data - (IN) User data 2619 * Return: 2620 * BCM_E_XXX 2621 */ 2622 int 2623 bcm_tomahawk3_l2_mac_port_traverse(int unit, bcm_l2_mac_port_traverse_cb cb, 2624 void *user_data) 2625 { 2626 return BCM_E_UNAVAIL; 2627 } 2628 2629 STATIC void 2630 _bcm_th3_l2_vlan_gport_free(int unit, _bcm_l2_del_vlan_port_pair_t *l2_pair) 2631 { 2632 int i; 2633 2634 if (l2_pair) { 2635 if (l2_pair->mod_pair_arr) { 2636 sal_free(l2_pair->mod_pair_arr); 2637 l2_pair->mod_pair_arr = NULL; 2638 } 2639 2640 if (l2_pair->unit_pair_arr) { 2641 for (i = 0; i < BCM_VLAN_MAX + 2; i++) { 2642 sal_free(l2_pair->unit_pair_arr->tbm[i]); 2643 l2_pair->unit_pair_arr->tbm[i] = NULL; 2644 } 2645 sal_free(l2_pair->unit_pair_arr); 2646 l2_pair->unit_pair_arr = NULL; 2647 } 2648 } 2649 2650 return; 2651 } 2652 2653 #if defined(INCLUDE_L3) 2654 /* 2655 * Function: 2656 * _bcm_th3_is_gport_valid_type 2657 * Purpose: 2658 * Returns TRUE if supplied gport is a valid VP type 2659 * Parameters: 2660 * gport_type - (IN) Gport type to be validated 2661 * Returns: 2662 * TRUE if 'gport' is a valid VP type, FALSE otherwise 2663 */ 2664 2665 STATIC int 2666 _bcm_th3_is_gport_valid_type(int gport_type) 2667 { 2668 switch(gport_type) { 2669 case BCM_GPORT_MPLS_PORT: 2670 case BCM_GPORT_VLAN_PORT: 2671 return 1; 2672 default: 2673 return 0; 2674 } 2675 } 2676 #endif /* INCLUDE_L3 */ 2677 2678 /* 2679 * Function: 2680 * _bcm_th3_l2_vlan_gport_matched_delete 2681 * Purpose: 2682 * L2 Traverse callback function to Purge L2 entry belongs 2683 * to set of (vlan,port) tuple. 2684 * Parameters: 2685 * unit - (IN) Device unit number 2686 * info - (IN) Reference to L2 entry, delete on match 2687 * user_data - (IN) User specified cookie 2688 * Returns: 2689 * BCM_E_XXX 2690 * Note: 2691 * If one of the elements of the (vlan,gport) pair is invalid 2692 * (if vlan value is BCM_VLAN_INVALID or port value is BCM_GPORT_INVALID), 2693 * it is a wildcard. 2694 */ 2695 STATIC int 2696 _bcm_th3_l2_vlan_gport_matched_delete(int unit, bcm_l2_addr_t *info, 2697 void *user_data) 2698 { 2699 int rv = BCM_E_NONE; 2700 int entry_found = FALSE; 2701 _bcm_l2_del_vlan_port_pair_t *l2_pair; 2702 int useGport; 2703 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) 2704 int gport_type; 2705 bcm_port_t local_port; 2706 #endif /* defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) */ 2707 2708 l2_pair = (void *)user_data; 2709 2710 if (l2_pair == NULL) { 2711 return BCM_E_NOT_FOUND; 2712 } 2713 2714 if ((info->flags & BCM_L2_STATIC) && 2715 (!(l2_pair->replace_flags & BCM_L2_REPLACE_MATCH_STATIC))) { 2716 _l2_dbg_unmatched_entries[unit]++; 2717 return BCM_E_NONE; 2718 } 2719 2720 if ((info->flags & BCM_L2_PENDING) && 2721 (!(l2_pair->replace_flags & BCM_L2_REPLACE_PENDING))) { 2722 _l2_dbg_unmatched_entries[unit]++; 2723 return BCM_E_NONE; 2724 } 2725 2726 /* Assumption is that esw's version of switch control will be used on TH3 */ 2727 BCM_IF_ERROR_RETURN 2728 (bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &useGport)); 2729 2730 #if defined(INCLUDE_L3) 2731 /* Extract the gport_type */ 2732 gport_type = (((info->port) >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK); 2733 if (_bcm_th3_is_gport_valid_type(gport_type)) { 2734 /* Assumption is that esw's version of switch control will be used on 2735 * TH3 2736 */ 2737 BCM_IF_ERROR_RETURN( 2738 bcm_esw_port_local_get(unit, info->port, &local_port)); 2739 } 2740 #endif /* defined(INCLUDE_L3) */ 2741 2742 if (BCM_VLAN_VEC_GET(l2_pair->del_by_vlan_vec, info->vid)) { 2743 /* Delete by vlan operation */ 2744 entry_found = TRUE; 2745 } else if ((useGport) && (BCM_GPORT_IS_MODPORT(info->port)) && 2746 BCM_PBMP_MEMBER (l2_pair->mod_pair_arr[info->modid].pbm[BCM_VLAN_MAX+1], 2747 _SHR_GPORT_LOCAL_GET(info->port))) { 2748 /* Delete by (mod, gport) operation */ 2749 entry_found = TRUE; 2750 } else if ((!useGport) && (!BCM_GPORT_IS_SET(info->port)) && 2751 BCM_PBMP_MEMBER (l2_pair->mod_pair_arr[info->modid].pbm[BCM_VLAN_MAX+1], 2752 info->port)) { 2753 /* Delete by (mod, port) operation */ 2754 entry_found = TRUE; 2755 } else if ((useGport) && BCM_GPORT_IS_MODPORT(info->port) && 2756 BCM_PBMP_MEMBER(l2_pair->mod_pair_arr[info->modid].pbm[info->vid], 2757 _SHR_GPORT_LOCAL_GET(info->port))) { 2758 /* Delete by (vlan, (mod, gport)) operation */ 2759 entry_found = TRUE; 2760 } else if (((!useGport) && (!BCM_GPORT_IS_SET(info->port)) && 2761 BCM_PBMP_MEMBER(l2_pair->mod_pair_arr[info->modid].pbm[info->vid], 2762 info->port))) { 2763 /* Delete by (vlan, (mod, port)) operation */ 2764 entry_found = TRUE; 2765 } else if (info->flags & BCM_L2_TRUNK_MEMBER) { 2766 if (SHR_BITGET(l2_pair->unit_pair_arr[0].tbm[BCM_VLAN_MAX+1], info->tgid)) { 2767 /* Delete by (tid) operation */ 2768 entry_found = TRUE; 2769 } else if (SHR_BITGET(l2_pair->unit_pair_arr[0].tbm[info->vid], info->tgid)) { 2770 /* Delete by (vlan, tid) operation */ 2771 entry_found = TRUE; 2772 } 2773 } 2774 2775 if (entry_found == TRUE) { 2776 /* Entry found - Delete the entry */ 2777 2778 rv = mbcm_driver[unit]->mbcm_l2_addr_delete(unit, info->mac, 2779 info->vid); 2780 if (rv == BCM_E_NONE) { 2781 _l2_dbg_matched_entries[unit]++; 2782 } 2783 } else { 2784 _l2_dbg_unmatched_entries[unit]++; 2785 } 2786 2787 return rv; 2788 } 2789 2790 /* 2791 * Function: 2792 * bcm_tomahawk3_l2_addr_delete_by_vlan_gport_multi 2793 * Purpose: 2794 * Purge L2 entries belong to set of (vlan,port) tuple. 2795 * Parameters: 2796 * unit - (IN) Device unit number 2797 * flags - (IN) Only accept BCM_L2_REPLACE_DELETE, BCM_L2_REPLACE_NO_CALLBACKS. 2798 * num_pairs - (IN) Size of (vlan,port) pair array. 2799 * vlan - (IN) Reference to array of VLAN list. 2800 * gport - (IN) Reference to array of gport list. 2801 * Returns: 2802 * BCM_E_XXX 2803 * Note: 2804 * If one of the elements of the (vlan,gport) pair is invalid 2805 * (if vlan value is BCM_VLAN_INVALID or port value is BCM_GPORT_INVALID), 2806 * it is a wildcard. 2807 * Entries are removed only if BCM_L2_REPLACE_DELETE flag is used. With 2808 * flag BCM_L2_REPLACE_NO_CALLBACKS, l2 aging and learning are disabled 2809 * during this operation. 2810 */ 2811 2812 int 2813 bcm_tomahawk3_l2_addr_delete_by_vlan_gport_multi(int unit, uint32 flags, 2814 int num_pairs, 2815 bcm_vlan_t *vlan, 2816 bcm_gport_t *gport) 2817 { 2818 sal_usecs_t interval=0; 2819 bcm_module_t mod_in, modid = 0; 2820 bcm_port_t port_in, port = 0; 2821 bcm_trunk_t trunk_id = 0; 2822 int id = 0, ct, i; 2823 int rv2 = 0, rv = BCM_E_UNAVAIL; 2824 soc_control_t *soc = SOC_CONTROL(unit); 2825 uint32 max_modid; 2826 _bcm_l2_vlan_port_pair_t *mod_l2_pair_arr = NULL; 2827 _bcm_l2_vlan_trunk_pair_t *l2_trunk_pair_arr = NULL; 2828 _bcm_l2_del_vlan_port_pair_t l2_pair; 2829 int alloc_size; 2830 2831 /* Validate the input parameters */ 2832 if (vlan == NULL || gport == NULL || num_pairs == 0) { 2833 return BCM_E_PARAM; 2834 } 2835 2836 /* Validate flag parameter, no action will be proceeded with extra flags */ 2837 if ((flags & ~(BCM_L2_REPLACE_DELETE | BCM_L2_REPLACE_NO_CALLBACKS | 2838 BCM_L2_REPLACE_MATCH_STATIC | 2839 BCM_L2_REPLACE_PENDING )) != 0) { 2840 return BCM_E_NONE; 2841 } 2842 2843 sal_memset(&l2_pair, 0x0, sizeof(l2_pair)); 2844 2845 /* Prepare (vlan, (mod, port)) pair */ 2846 max_modid = SOC_MODID_MAX(unit) + 1; 2847 alloc_size = sizeof(_bcm_l2_vlan_port_pair_t) * max_modid; 2848 mod_l2_pair_arr = sal_alloc(alloc_size, "l2_addr_vlan_gport_multi_delete"); 2849 if (mod_l2_pair_arr == NULL) { 2850 return BCM_E_MEMORY; 2851 } 2852 sal_memset(mod_l2_pair_arr, 0x0, alloc_size); 2853 2854 /* Prepare (vlan, tid) pair */ 2855 l2_pair.mod_pair_arr = mod_l2_pair_arr; 2856 alloc_size = sizeof(_bcm_l2_vlan_trunk_pair_t); 2857 l2_trunk_pair_arr = sal_alloc(alloc_size, "l2_addr_vlan_gport_multi_delete"); 2858 if (l2_trunk_pair_arr == NULL) { 2859 rv = BCM_E_MEMORY; 2860 goto _free_exit; 2861 } 2862 sal_memset(l2_trunk_pair_arr, 0x0, alloc_size); 2863 l2_pair.unit_pair_arr = l2_trunk_pair_arr; 2864 2865 /* Assumption is that the trunk module will have the same function as below 2866 * for getting trunk information 2867 */ 2868 alloc_size = SHR_BITALLOCSIZE(_bcm_esw_trunk_group_num(unit)); 2869 for (i = 0; i < BCM_VLAN_MAX + 2; i++) { 2870 l2_trunk_pair_arr->tbm[i] = sal_alloc(alloc_size, \ 2871 "l2_addr_vlan_gport_multi_delete"); 2872 if (l2_trunk_pair_arr->tbm[i] == NULL) { 2873 rv = BCM_E_MEMORY; 2874 goto _free_exit; 2875 } 2876 sal_memset(l2_trunk_pair_arr->tbm[i], 0x0, alloc_size); 2877 } 2878 2879 /* Validate vlan & gport */ 2880 for (ct = 0; ct < num_pairs; ct++) { 2881 if (vlan[ct] == BCM_VLAN_INVALID && 2882 gport[ct] == BCM_GPORT_INVALID) { 2883 rv = BCM_E_PARAM; 2884 goto _free_exit; 2885 } 2886 2887 if (vlan[ct] != BCM_VLAN_INVALID) { 2888 if (vlan[ct] > BCM_VLAN_MAX) { 2889 rv = BCM_E_PARAM; 2890 goto _free_exit; 2891 } 2892 } 2893 2894 if (gport[ct] != BCM_GPORT_INVALID) { 2895 2896 if (BCM_GPORT_IS_MODPORT(gport[ct])) { 2897 mod_in = BCM_GPORT_MODPORT_MODID_GET(gport[ct]); 2898 port_in = BCM_GPORT_MODPORT_PORT_GET(gport[ct]); 2899 modid = mod_in; 2900 port = port_in; 2901 } else { 2902 rv = _bcm_esw_gport_resolve(unit, gport[ct], 2903 &modid, &port, &trunk_id, &id); 2904 if (BCM_FAILURE(rv)) { 2905 goto _free_exit; 2906 } 2907 2908 if (BCM_GPORT_IS_TRUNK(gport[ct])) { 2909 rv = _bcm_trunk_id_validate(unit, trunk_id); 2910 if (BCM_FAILURE(rv)) { 2911 rv = BCM_E_PARAM; 2912 goto _free_exit; 2913 } 2914 } else { 2915 rv = BCM_E_PARAM; 2916 goto _free_exit; 2917 } 2918 } 2919 } 2920 2921 if (vlan[ct] == BCM_VLAN_INVALID) { 2922 if (BCM_GPORT_IS_TRUNK(gport[ct])) { 2923 SHR_BITSET(l2_pair.unit_pair_arr[0].tbm[BCM_VLAN_MAX+1], \ 2924 trunk_id); 2925 } else if (BCM_GPORT_IS_MODPORT(gport[ct])){ 2926 BCM_PBMP_PORT_ADD( \ 2927 l2_pair.mod_pair_arr[modid].pbm[BCM_VLAN_MAX+1], port); 2928 } 2929 } else if (gport[ct] == BCM_GPORT_INVALID) { 2930 BCM_VLAN_VEC_SET(l2_pair.del_by_vlan_vec, vlan[ct]); 2931 } else { 2932 if (BCM_GPORT_IS_TRUNK(gport[ct])) { 2933 SHR_BITSET(l2_pair.unit_pair_arr[0].tbm[vlan[ct]], \ 2934 trunk_id); 2935 } else /* if (BCM_GPORT_IS_MODPORT(gport[ct])) */{ 2936 BCM_PBMP_PORT_ADD(l2_pair.mod_pair_arr[modid].pbm[vlan[ct]], \ 2937 port); 2938 } 2939 } 2940 } 2941 2942 if (flags & BCM_L2_REPLACE_DELETE) { 2943 _l2_dbg_matched_entries[unit] = 0; 2944 _l2_dbg_unmatched_entries[unit] = 0; 2945 2946 if (flags & BCM_L2_REPLACE_NO_CALLBACKS) { 2947 interval = soc->l2x_interval; 2948 rv = bcm_esw_l2_addr_freeze(unit); 2949 if (BCM_FAILURE(rv)) { 2950 goto _free_exit; 2951 } 2952 2953 rv2 = soc_l2x_stop(unit); 2954 if (rv2 < 0) { 2955 goto _free_exit; 2956 } 2957 2958 LOG_INFO(BSL_LS_BCM_ARL, 2959 (BSL_META_U(unit, "L2 Freeze and stop L2 thread\n"))); 2960 } 2961 2962 l2_pair.replace_flags = flags; 2963 2964 rv = bcm_tomahawk3_l2_traverse(unit, 2965 _bcm_th3_l2_vlan_gport_matched_delete, 2966 &l2_pair); 2967 if (rv == BCM_E_NONE) { 2968 LOG_INFO(BSL_LS_BCM_ARL, 2969 (BSL_META_U(unit, 2970 "Total number of L2 Entries: %d [Deleted:%d Left:%d]\n\r"), 2971 _l2_dbg_matched_entries[unit] + _l2_dbg_unmatched_entries[unit], 2972 _l2_dbg_matched_entries[unit], _l2_dbg_unmatched_entries[unit])); 2973 } 2974 2975 if (flags & BCM_L2_REPLACE_NO_CALLBACKS) { 2976 LOG_INFO(BSL_LS_BCM_ARL, 2977 (BSL_META_U(unit, "L2 Thaw and start L2 thread\n"))); 2978 2979 rv2 = soc_l2x_start(unit, soc->l2x_flags, interval); 2980 if (rv2 < 0) { 2981 goto _free_exit; 2982 } 2983 2984 rv2 = bcm_esw_l2_addr_thaw(unit); 2985 if (rv2 < 0) { 2986 goto _free_exit; 2987 } 2988 } 2989 } 2990 2991 _free_exit: 2992 _bcm_th3_l2_vlan_gport_free(unit, &l2_pair); 2993 2994 if (rv < 0) { 2995 return rv; 2996 } else if (rv2 < 0) { 2997 return rv2; 2998 } else { 2999 return rv; 3000 } 3001 } 3002 3003 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 3004 #if 0 3005 3006 /* 3007 * Function: 3008 * _bcm_l2_sw_dump 3009 * Purpose: 3010 * Displays L2 information maintained by software. 3011 * Parameters: 3012 * unit - Device unit number 3013 * Returns: 3014 * None 3015 * Note: 3016 * The l2_data structure maintains registration of callbacks routines. 3017 * Dump of l2_data is skipped. 3018 */ 3019 void 3020 _bcm_l2_sw_dump(int unit) 3021 { 3022 3023 LOG_CLI((BSL_META_U(unit, 3024 "\nSW Information L2 - Unit %d\n"), unit)); 3025 LOG_CLI((BSL_META_U(unit, 3026 " Initialized : %d\n"), _th3_l2_init[unit])); 3027 3028 _bcm_th3_l2_sw_dump(unit); 3029 3030 return; 3031 } 3032 #endif /* 0 */ 3033 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */ 3034 3035 #ifdef BCM_WARM_BOOT_SUPPORT 3036 /* Warmboot versions below must be as defined in src/bcm/esw/l2.c */ 3037 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 3038 #define BCM_WB_VERSION_1_1 SOC_SCACHE_VERSION(1,1) 3039 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_1 3040 3041 /* 3042 * Function: 3043 * _bcm_th3_l2_wb_alloc 3044 * Purpose: 3045 * Allocated L2 module persistent info for Level 2 Warm Boot 3046 * Parameters: 3047 * unit - StrataSwitch unit number. 3048 * Returns: 3049 * BCM_E_XXX 3050 */ 3051 STATIC int 3052 _bcm_th3_l2_wb_alloc(int unit) 3053 { 3054 int sz = 0; 3055 soc_scache_handle_t scache_handle; 3056 uint8 *scache_ptr; 3057 int rv = BCM_E_NONE; 3058 int stable_size = 0; 3059 _bcm_l2_station_control_t *station_control = NULL; 3060 int sw_aging_support; 3061 int underlay_max_entries = 0; 3062 3063 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 3064 /* Requires extended scache support warmboot */ 3065 if (stable_size == 0) { 3066 return BCM_E_NONE; 3067 } 3068 3069 rv = _bcm_th3_l2_station_control_get(unit, &station_control); 3070 if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) { 3071 return rv; 3072 } 3073 3074 /* TH3 does not support SW aging. Added only for warmboot upgrade purpose. 3075 * See _bcm_esw_l2_wb_alloc 3076 */ 3077 sw_aging_support = 1; 3078 3079 if (sw_aging_support || 3080 ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) { 3081 3082 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0); 3083 3084 if (sw_aging_support) { 3085 /* aging time */ 3086 sz += sizeof(int); 3087 } 3088 3089 if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) { 3090 /* Underlay L2 station entry - sid/prio */ 3091 /* For TH3, l2_station_entry_max_size_get and l2_station_size_get 3092 * would return same value, so we use l2_station_size_get 3093 * (we have not defined bcm_th3_l2_station_max_size_get) 3094 */ 3095 BCM_IF_ERROR_RETURN( 3096 bcm_th3_l2_station_size_get(unit, &underlay_max_entries)); 3097 sz += (underlay_max_entries * (sizeof(int) * 2)); 3098 3099 } 3100 3101 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, TRUE, 3102 sz, &scache_ptr, 3103 BCM_WB_DEFAULT_VERSION, NULL); 3104 3105 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 3106 return rv; 3107 } 3108 } 3109 return BCM_E_NONE; 3110 } 3111 3112 /* 3113 * Function: 3114 * _bcm_th3_l2_wb_sync 3115 * Purpose: 3116 * Record L2 module persistent info for Level 2 Warm Boot 3117 * Parameters: 3118 * unit - StrataSwitch unit number. 3119 * Returns: 3120 * BCM_E_XXX 3121 */ 3122 int 3123 _bcm_th3_l2_wb_sync(int unit) 3124 { 3125 int sz = 0; 3126 soc_scache_handle_t scache_handle; 3127 uint8 *scache_ptr = NULL; 3128 int aging_time = 0; 3129 _bcm_l2_station_entry_t **entry_arr; 3130 _bcm_l2_station_control_t *station_control = NULL; 3131 int stable_size = 0; 3132 int rv = BCM_E_NONE; 3133 int index = 0; 3134 int init_value = 0; 3135 int sw_aging_support; /* SW Learning supported */ 3136 int underlay_max_entries = 0; 3137 3138 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 3139 /* Requires extended scache support warmboot */ 3140 if (stable_size == 0) { 3141 return BCM_E_NONE; 3142 } 3143 3144 rv = _bcm_th3_l2_station_control_get(unit, &station_control); 3145 if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) { 3146 return rv; 3147 } 3148 3149 /* TH3 does not support SW aging. Added only for warmboot upgrade purpose. 3150 * See _bcm_esw_l2_wb_sync 3151 */ 3152 sw_aging_support = 1; 3153 3154 if (sw_aging_support || 3155 ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) { 3156 3157 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0); 3158 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 3159 0, &scache_ptr, 3160 BCM_WB_DEFAULT_VERSION, NULL); 3161 3162 if (BCM_FAILURE(rv) && (rv != BCM_E_INTERNAL)) { 3163 return rv; 3164 } 3165 3166 if (sw_aging_support) { 3167 /* aging time */ 3168 BCM_IF_ERROR_RETURN( 3169 _bcm_tomahawk3_l2_age_timer_get(unit, &aging_time)); 3170 sz = sizeof(int); 3171 sal_memcpy(scache_ptr, &aging_time, sz); 3172 scache_ptr += sz; 3173 } 3174 3175 if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) { 3176 BCM_IF_ERROR_RETURN( 3177 bcm_th3_l2_station_size_get(unit, &underlay_max_entries)); 3178 /* Underlay L2 station entry - sid/prio */ 3179 entry_arr = (station_control->entry_arr); 3180 3181 for (index = 0; index < underlay_max_entries; index++) { 3182 if (entry_arr[index]) { 3183 sal_memcpy(scache_ptr, 3184 &(entry_arr[index]->sid), sizeof(int)); 3185 scache_ptr += sizeof(int); 3186 3187 sal_memcpy(scache_ptr, 3188 &(entry_arr[index]->prio), sizeof(int)); 3189 scache_ptr += sizeof(int); 3190 } else { 3191 sal_memcpy(scache_ptr, &init_value, sizeof(int)); 3192 scache_ptr += sizeof(int); 3193 3194 sal_memcpy(scache_ptr, &init_value, sizeof(int)); 3195 scache_ptr += sizeof(int); 3196 } 3197 } 3198 } 3199 } 3200 3201 return BCM_E_NONE; 3202 } 3203 3204 /* 3205 * Function: 3206 * _bcm_th3_l2_wb_recover 3207 * Purpose: 3208 * Recover L2 module persistent info for Level 2 Warm Boot 3209 * Parameters: 3210 * unit - StrataSwitch unit number. 3211 * Returns: 3212 * BCM_E_XXX 3213 */ 3214 STATIC int 3215 _bcm_th3_l2_wb_recover(int unit) 3216 { 3217 soc_scache_handle_t scache_handle; 3218 uint8 *scache_ptr = NULL; 3219 uint16 recovered_ver = 0; 3220 int aging_time = 0; 3221 int rv = BCM_E_NONE; 3222 int additional_scache_size = 0; 3223 int sw_aging_support; 3224 int underlay_max_entries = 0; 3225 _bcm_l2_station_entry_t **entry_arr; 3226 _bcm_l2_station_control_t *station_control = NULL; 3227 int index = 0; 3228 int sid = 0; 3229 int pri = 0; 3230 int cur_last_sid = 0; 3231 int stable_size = 0; 3232 3233 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 3234 /* Requires extended scache support warmboot */ 3235 if (stable_size == 0) { 3236 return BCM_E_NONE; 3237 } 3238 3239 rv = _bcm_th3_l2_station_control_get(unit, &station_control); 3240 if (BCM_FAILURE(rv) && (rv != BCM_E_INIT)) { 3241 return rv; 3242 } 3243 3244 /* TH3 does not support SW aging. Added only for warmboot upgrade purpose. 3245 * See _bcm_esw_l2_wb_recover 3246 */ 3247 sw_aging_support = 1; 3248 3249 if (sw_aging_support || 3250 ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control)) { 3251 3252 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_L2, 0); 3253 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 3254 0, &scache_ptr, 3255 BCM_WB_DEFAULT_VERSION, &recovered_ver); 3256 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 3257 return rv; 3258 } else if (BCM_E_NOT_FOUND == rv) { 3259 return _bcm_th3_l2_wb_alloc(unit); 3260 } 3261 3262 if (scache_ptr != NULL) { 3263 if (sw_aging_support) { 3264 if (recovered_ver >= BCM_WB_VERSION_1_0) { 3265 /* aging time */ 3266 sal_memcpy(&aging_time, scache_ptr, sizeof(int)); 3267 BCM_IF_ERROR_RETURN( 3268 _bcm_tomahawk3_l2_age_timer_set(unit, aging_time, 3269 aging_time > 0)); 3270 scache_ptr += sizeof(int); 3271 } else { 3272 additional_scache_size += sizeof(int); 3273 } 3274 } 3275 3276 if ((!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) && station_control) { 3277 /* We use bcm_th3_l2_station_size_get since the max_size_get 3278 * version will be the same as size_get 3279 */ 3280 BCM_IF_ERROR_RETURN( 3281 bcm_th3_l2_station_size_get(unit, &underlay_max_entries)); 3282 3283 /* Recover overlay/underlay L2 station entry */ 3284 if (recovered_ver >= BCM_WB_VERSION_1_1) { 3285 entry_arr = (station_control->entry_arr); 3286 3287 for (index = 0; index < underlay_max_entries; index++) { 3288 sal_memcpy(&sid, scache_ptr, sizeof(int)); 3289 scache_ptr += sizeof(int); 3290 3291 sal_memcpy(&pri, scache_ptr, sizeof(int)); 3292 scache_ptr += sizeof(int); 3293 3294 if (sid > cur_last_sid) { 3295 cur_last_sid = sid; 3296 } 3297 3298 if (entry_arr[index]) { 3299 if (0 == sid) { 3300 /* 3301 * Only recover the L2 station entries created 3302 * by bcm_l2_station APIs 3303 */ 3304 if (index < station_control->entries_total) { 3305 if (NULL != entry_arr[index]->tcam_ent) { 3306 sal_free(entry_arr[index]->tcam_ent); 3307 } 3308 3309 sal_free(entry_arr[index]); 3310 3311 entry_arr[index] = NULL; 3312 station_control->entry_count--; 3313 station_control->entries_free++; 3314 } 3315 } else { 3316 entry_arr[index]->sid = sid; 3317 entry_arr[index]->prio = pri; 3318 } 3319 } 3320 } 3321 3322 rv = _bcm_th3_l2_station_entry_last_sid_set(unit, FALSE, 3323 cur_last_sid); 3324 if (BCM_FAILURE(rv)) { 3325 return rv; 3326 } 3327 } else { 3328 /* Underlay L2 station entry - sid/prio */ 3329 additional_scache_size += 3330 (underlay_max_entries *(sizeof(int) * 2)); 3331 } 3332 } 3333 3334 if (additional_scache_size > 0) { 3335 rv = soc_scache_realloc(unit, scache_handle, 3336 additional_scache_size); 3337 if(BCM_FAILURE(rv)) { 3338 return rv; 3339 } 3340 } 3341 } 3342 } 3343 3344 return BCM_E_NONE; 3345 } 3346 #endif /* BCM_WARM_BOOT_SUPPORT */ 3347 3348 /* 3349 * Function: 3350 * bcm_tomahawk3_l2_addr_add 3351 * Description: 3352 * Add a MAC address to the Switch Address Resolution Logic (ARL) 3353 * port with the given VLAN ID and parameters. 3354 * Parameters: 3355 * unit - StrataSwitch PCI device unit number (driver internal). 3356 * l2addr - Pointer to bcm_l2_addr_t containing all valid fields 3357 * Returns: 3358 * BCM_E_NONE Success 3359 * BCM_E_INTERNAL Chip access failure 3360 * Notes: 3361 * Use CMIC_PORT(unit) to associate the entry with the CPU. 3362 * Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU. 3363 * Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be 3364 * passed as well with non-zero trunk group ID) 3365 */ 3366 int 3367 bcm_tomahawk3_l2_addr_add(int unit, bcm_l2_addr_t *l2addr) 3368 { 3369 TH3_L2_INIT(unit); 3370 3371 3372 /* Input parameters check. */ 3373 if (NULL == l2addr) { 3374 return (BCM_E_PARAM); 3375 } 3376 3377 if (l2addr->flags & BCM_L2_DISCARD_DST) { 3378 if (MAC_IS_MCAST(l2addr->mac)) { 3379 return (BCM_E_UNAVAIL); 3380 } 3381 } 3382 3383 if (l2addr->flags & BCM_L2_LOCAL_CPU) { 3384 l2addr->port = CMIC_PORT(unit); 3385 l2addr->modid = 0; 3386 } 3387 3388 if (l2addr->flags & BCM_L2_TRUNK_MEMBER) { 3389 BCM_IF_ERROR_RETURN(_bcm_trunk_id_validate(unit, l2addr->tgid)); 3390 } 3391 3392 if (SOC_L2X_GROUP_ENABLE_GET(unit)) { 3393 /* soc_feature_overlaid_address_class should be enabled */ 3394 if (soc_feature(unit, soc_feature_overlaid_address_class) && 3395 !BCM_L2_PRE_SET(l2addr->flags)) { 3396 if ((l2addr->group > SOC_OVERLAID_ADDR_CLASS_MAX(unit)) || 3397 (l2addr->group < 0)) { 3398 return (BCM_E_PARAM); 3399 } 3400 } else if ((l2addr->group > SOC_ADDR_CLASS_MAX(unit)) || 3401 (l2addr->group < 0)) { 3402 return (BCM_E_PARAM); 3403 } 3404 if (!BCM_PBMP_IS_NULL(l2addr->block_bitmap)) { 3405 return (BCM_E_PARAM); 3406 } 3407 } else { 3408 if (l2addr->group) { 3409 return (BCM_E_PARAM); 3410 } 3411 } 3412 3413 SOC_IF_ERROR_RETURN 3414 (mbcm_driver[unit]->mbcm_l2_addr_add(unit, l2addr)); 3415 3416 return BCM_E_NONE; 3417 } 3418 3419 /* 3420 * Function: 3421 * bcm_tomahawk3_l2_addr_delete 3422 * Description: 3423 * Delete an L2 address (MAC+VLAN) from the device 3424 * Parameters: 3425 * unit - device unit 3426 * mac - MAC address to delete 3427 * vid - VLAN id 3428 * Returns: 3429 * BCM_E_XXX 3430 */ 3431 3432 int 3433 bcm_tomahawk3_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid) 3434 { 3435 TH3_L2_INIT(unit); 3436 3437 /* Calls bcm_th3_l2_addr_delete defined above */ 3438 return mbcm_driver[unit]->mbcm_l2_addr_delete(unit, mac, vid); 3439 } 3440 3441 /* 3442 * Function: 3443 * bcm_tomahawk3_l2_addr_get 3444 * Description: 3445 * Given a MAC address and VLAN ID, check if the entry is present 3446 * in the L2 table, and if so, return all associated information. 3447 * Parameters: 3448 * unit - StrataSwitch PCI device unit number (driver internal). 3449 * mac - input MAC address to search 3450 * vid - input VLAN ID to search 3451 * l2addr - Pointer to bcm_l2_addr_t structure to receive results 3452 * Returns: 3453 * BCM_E_NONE Success (l2addr filled in) 3454 * BCM_E_PARAM Illegal parameter (NULL pointer) 3455 * BCM_E_INTERNAL Chip access failure 3456 * BCM_E_NOT_FOUND Address not found (l2addr not filled in) 3457 */ 3458 3459 int 3460 bcm_tomahawk3_l2_addr_get(int unit, sal_mac_addr_t mac, 3461 bcm_vlan_t vid, bcm_l2_addr_t *l2addr) 3462 { 3463 TH3_L2_INIT(unit); 3464 3465 /* Calls bcm_th3_l2_addr_get defined above */ 3466 SOC_IF_ERROR_RETURN( 3467 mbcm_driver[unit]->mbcm_l2_addr_get(unit, mac, vid, l2addr)); 3468 3469 return BCM_E_NONE; 3470 } 3471 3472 /* 3473 * Function: 3474 * _bcm_th3_l2_addr_callback 3475 * Description: 3476 * Callback used with chip addr registration functions. 3477 * This callback calls all the top level client callbacks. 3478 * Parameters: 3479 * unit - StrataSwitch PCI device unit number (driver internal). 3480 * l2addr 3481 * insert 3482 * userdata 3483 * Returns: 3484 */ 3485 STATIC void 3486 _bcm_th3_l2_addr_callback(int unit, 3487 bcm_l2_addr_t *l2addr, 3488 int insert, 3489 void *userdata) 3490 { 3491 th3_l2_data_t *ad = &th3_l2_data[unit]; 3492 int i; 3493 3494 if (ad->l2_mutex == NULL) { 3495 return; 3496 } 3497 3498 L2_LOCK(unit); 3499 for(i = 0; i < L2_CB_MAX; i++) { 3500 if(ad->cb[i].fn) { 3501 ad->cb[i].fn(unit, l2addr, insert, ad->cb[i].fn_data); 3502 } 3503 } 3504 L2_UNLOCK(unit); 3505 } 3506 3507 /* 3508 * Function: 3509 * bcm_tomahawk3_l2_addr_register 3510 * Description: 3511 * Register a callback routine that will be called whenever 3512 * an entry is inserted into or deleted from the L2 address table 3513 * Parameters: 3514 * unit - StrataSwitch PCI device unit number (driver internal) 3515 * fn - Callback function of type bcm_l2_addr_callback_t 3516 * fn_data - Arbitrary value passed to callback along with messages 3517 * Returns: 3518 * BCM_E_NONE Success, handle valid 3519 * BCM_E_MEMORY Out of memory 3520 * BCM_E_INTERNAL Chip access failure 3521 */ 3522 3523 int 3524 bcm_tomahawk3_l2_addr_register(int unit, 3525 bcm_l2_addr_callback_t fn, 3526 void *fn_data) 3527 { 3528 th3_l2_data_t *ad = &th3_l2_data[unit]; 3529 int i; 3530 int rv = BCM_E_NONE; 3531 int usec; 3532 3533 TH3_L2_INIT(unit); 3534 3535 _bcm_th3_l2_cbs[unit] = _bcm_th3_l2_addr_callback; 3536 _bcm_th3_l2_cb_data[unit] = NULL; 3537 3538 L2_MUTEX(unit); 3539 L2_LOCK(unit); 3540 3541 /* Start L2x thread if it isn't running already. */ 3542 if (!soc_l2x_running(unit, NULL, NULL)) { 3543 /* Use default value. Even for bcmsim we need interval to be 3544 * sufficiently small to track L2X table updates 3545 */ 3546 usec = SOC_L2X_INTERVAL_DEFAULT; 3547 usec = soc_property_get(unit, spn_L2XMSG_THREAD_USEC, usec); 3548 rv = soc_l2x_start(unit, 0, usec); 3549 if ((BCM_FAILURE(rv)) && (rv != BCM_E_UNAVAIL)) { 3550 _bcm_th3_l2_cbs[unit] = NULL; 3551 _bcm_th3_l2_cb_data[unit] = NULL; 3552 L2_UNLOCK(unit); 3553 return(rv); 3554 } 3555 ad->flags |= _BCM_TH3_L2X_THREAD_STOP; 3556 } 3557 3558 /* See if the function is already registered (with same data) */ 3559 for (i = 0; i < L2_CB_MAX; i++) { 3560 if (ad->cb[i].fn == fn && ad->cb[i].fn_data == fn_data) { 3561 L2_UNLOCK(unit); 3562 return BCM_E_NONE; 3563 } 3564 } 3565 3566 /* Not found; add to list. */ 3567 for (i = 0; i < L2_CB_MAX; i++) { 3568 if (ad->cb[i].fn == NULL) { 3569 ad->cb[i].fn = fn; 3570 ad->cb[i].fn_data = fn_data; 3571 ad->cb_count++; 3572 break; 3573 } 3574 } 3575 3576 L2_UNLOCK(unit); 3577 return i >= L2_CB_MAX ? BCM_E_RESOURCE : BCM_E_NONE; 3578 } 3579 3580 /* 3581 * Function: 3582 * bcm_tomahawk3_l2_addr_unregister 3583 * Description: 3584 * Unregister a previously registered callback routine. 3585 * Parameters: 3586 * unit - StrataSwitch PCI device unit number (driver internal). 3587 * fn - Same callback function used to register callback 3588 * fn_data - Same arbitrary value used to register callback 3589 * Returns: 3590 * BCM_E_NONE Success, handle valid 3591 * BCM_E_MEMORY Out of memory 3592 * BCM_E_INTERNAL Chip access failure 3593 * Notes: 3594 * Both callback and userdata must match from original register call. 3595 */ 3596 int 3597 bcm_tomahawk3_l2_addr_unregister(int unit, 3598 bcm_l2_addr_callback_t fn, 3599 void *fn_data) 3600 { 3601 th3_l2_data_t *ad = &th3_l2_data[unit]; 3602 int rv = BCM_E_NOT_FOUND; 3603 int i; 3604 3605 TH3_L2_INIT(unit); 3606 L2_MUTEX(unit); 3607 if (_bcm_th3_l2_cb_check[unit] != NULL) { 3608 sal_sem_take(_bcm_th3_l2_cb_check[unit], sal_sem_FOREVER); 3609 } 3610 L2_LOCK(unit); 3611 3612 for (i = 0; i < L2_CB_MAX; i++) { 3613 if((ad->cb[i].fn == fn) && (ad->cb[i].fn_data == fn_data)) { 3614 rv = BCM_E_NONE; 3615 ad->cb[i].fn = NULL; 3616 ad->cb[i].fn_data = NULL; 3617 ad->cb_count--; 3618 if (ad->cb_count == 0) { 3619 _bcm_th3_l2_cbs[unit] = NULL; 3620 _bcm_th3_l2_cb_data[unit] = NULL; 3621 3622 /* Stop l2x thread if callback registration started it. */ 3623 if (ad->flags & _BCM_TH3_L2X_THREAD_STOP) { 3624 rv = soc_l2x_stop(unit); 3625 ad->flags &= ~_BCM_TH3_L2X_THREAD_STOP; 3626 } 3627 } 3628 } 3629 } 3630 3631 L2_UNLOCK(unit); 3632 if (_bcm_th3_l2_cb_check[unit] != NULL) { 3633 sal_sem_give(_bcm_th3_l2_cb_check[unit]); 3634 } 3635 return (rv); 3636 } 3637 3638 /* 3639 * Function: 3640 * bcm_tomahawk3_l2_station_add 3641 * Description: 3642 * Add an entry to L2 Station Table 3643 * Parameters: 3644 * unit - (IN) BCM device number 3645 * station_id - (IN/OUT) Station ID 3646 * station - (IN) Pointer to station address information 3647 * Return: 3648 * BCM_E_XXX 3649 */ 3650 int 3651 bcm_tomahawk3_l2_station_add(int unit, int *station_id, 3652 bcm_l2_station_t *station) 3653 { 3654 int rv = BCM_E_UNAVAIL; 3655 3656 rv = bcm_th3_l2_station_add(unit, station_id, station); 3657 3658 return rv; 3659 } 3660 3661 /* 3662 * Function: 3663 * bcm_tomahawk3_l2_station_delete 3664 * Description: 3665 * Delete an entry from L2 Station Table 3666 * Parameters: 3667 * unit - (IN) BCM device number 3668 * station_id - (IN) Station ID 3669 * Return: 3670 * BCM_E_XXX 3671 */ 3672 int 3673 bcm_tomahawk3_l2_station_delete(int unit, int station_id) 3674 { 3675 3676 int rv = BCM_E_UNAVAIL; 3677 3678 rv = bcm_th3_l2_station_delete(unit, station_id); 3679 3680 return (rv); 3681 } 3682 3683 /* 3684 * Function: 3685 * bcm_tomahawk3_l2_station_delete_all 3686 * Description: 3687 * Clear all L2 Station Table entries 3688 * Parameters: 3689 * unit - (IN) BCM device number 3690 * Return: 3691 * BCM_E_XXX 3692 */ 3693 int 3694 bcm_tomahawk3_l2_station_delete_all(int unit) 3695 { 3696 int rv = BCM_E_UNAVAIL; 3697 3698 rv = bcm_th3_l2_station_delete_all(unit); 3699 3700 return (rv); 3701 } 3702 3703 /* 3704 * Function: 3705 * bcm_tomahawk3_l2_station_get 3706 * Description: 3707 * Get L2 station entry detail from Station Table 3708 * Parameters: 3709 * unit - (IN) BCM device number 3710 * station_id - (IN) Station ID 3711 * station - (OUT) Pointer to station address information 3712 * Return: 3713 * BCM_E_XXX 3714 */ 3715 int 3716 bcm_tomahawk3_l2_station_get(int unit, int station_id, 3717 bcm_l2_station_t *station) 3718 { 3719 int rv = BCM_E_UNAVAIL; 3720 3721 rv = bcm_th3_l2_station_get(unit, station_id, station); 3722 3723 return (rv); 3724 } 3725 3726 /* 3727 * Function: 3728 * bcm_tomahawk3_l2_station_size_get 3729 * Description: 3730 * Get size of L2 Station Table 3731 * Parameters: 3732 * unit - (IN) BCM device number 3733 * size - (OUT) L2 Station table size 3734 * Return: 3735 * BCM_E_XXX 3736 */ 3737 int 3738 bcm_tomahawk3_l2_station_size_get(int unit, int *size) 3739 { 3740 int rv = BCM_E_UNAVAIL; 3741 3742 rv = bcm_th3_l2_station_size_get(unit, size); 3743 3744 return (rv); 3745 } 3746 3747 /* 3748 * Function: 3749 * bcm_tomahawk3_l2_station_traverse 3750 * Description: 3751 * Traverse L2 station entry from Station Table 3752 * Parameters: 3753 * unit - (IN) BCM device number 3754 * trav_fn - (IN) Customer defines function is used to traverse 3755 * user_data - (IN) Pointer to information of customer. 3756 * Return: 3757 * BCM_E_XXX 3758 */ 3759 int 3760 bcm_tomahawk3_l2_station_traverse(int unit, bcm_l2_station_traverse_cb trav_fn, 3761 void *user_data) 3762 { 3763 int rv = BCM_E_UNAVAIL; 3764 3765 rv = bcm_th3_l2_station_traverse(unit, trav_fn, user_data); 3766 3767 return (rv); 3768 } 3769 3770 /* 3771 * Function: 3772 * bcm_tomahawk3_l2_tunnel_add 3773 * Purpose: 3774 * Add a (MAC, VLAN) for tunnel/MPLS processing, frames 3775 * destined to (MAC, VLAN) is subjected to TUNNEL/MPLS processing. 3776 * Parameters: 3777 * unit - StrataXGS unit number 3778 * mac - MAC address 3779 * vlan - VLAN ID 3780 */ 3781 int 3782 bcm_tomahawk3_l2_tunnel_add(int unit, bcm_mac_t mac, bcm_vlan_t vlan) 3783 { 3784 TH3_L2_INIT(unit); 3785 3786 #if defined(BCM_MPLS_SUPPORT) && defined(INCLUDE_L3) 3787 VLAN_CHK_ID(unit, vlan); 3788 3789 return bcm_td_metro_myStation_add(unit, mac, vlan, -1, 1); 3790 #else 3791 return BCM_E_UNAVAIL; 3792 #endif 3793 } 3794 3795 /* 3796 * Function: 3797 * bcm_tomahawk3_l2_tunnel_delete 3798 * Purpose: 3799 * Remove a tunnel processing indicator for an L2 address 3800 * Parameters: 3801 * unit - StrataXGS unit number 3802 * mac - MAC address 3803 vlan - VLAN ID 3804 */ 3805 3806 int 3807 bcm_tomahawk3_l2_tunnel_delete(int unit, bcm_mac_t mac, bcm_vlan_t vlan) 3808 { 3809 TH3_L2_INIT(unit); 3810 3811 #if defined(BCM_MPLS_SUPPORT) && defined(INCLUDE_L3) 3812 VLAN_CHK_ID(unit, vlan); 3813 return bcm_td_metro_myStation_delete(unit, mac, vlan, -1, 1); 3814 #else 3815 return BCM_E_UNAVAIL; 3816 #endif 3817 } 3818 3819 /* 3820 * Function: 3821 * bcm_tomahawk3_l2_tunnel_delete_all 3822 * Purpose: 3823 * Remove all tunnel processing indicating L2 addresses 3824 * Parameters: 3825 * unit - StrataXGS unit number 3826 */ 3827 3828 int 3829 bcm_tomahawk3_l2_tunnel_delete_all(int unit) 3830 { 3831 TH3_L2_INIT(unit); 3832 3833 #if defined(BCM_MPLS_SUPPORT) && defined(INCLUDE_L3) 3834 return bcm_td_metro_myStation_delete_all(unit); 3835 #else 3836 return BCM_E_UNAVAIL; 3837 #endif 3838 } 3839 #endif /* BCM_TOMAHAWK3_SUPPORT */