l2_helpers.c (84901B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: l2.c 8 * Purpose: Triumph L2 function implementations 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <soc/defs.h> 14 #include <assert.h> 15 16 #include <sal/core/libc.h> 17 18 #include <soc/mem.h> 19 #include <soc/cm.h> 20 #include <soc/drv.h> 21 #include <soc/register.h> 22 #include <soc/memory.h> 23 #include <soc/hash.h> 24 #include <soc/l2x.h> 25 #include <soc/tomahawk3.h> 26 #include <soc/triumph.h> 27 #ifdef BCM_TRIDENT2_SUPPORT 28 #include <soc/trident2.h> 29 #endif /* BCM_TRIDENT2_SUPPORT */ 30 #ifdef BCM_TOMAHAWK_SUPPORT 31 #include <soc/tomahawk.h> 32 #endif /* BCM_TOMAHAWK_SUPPORT */ 33 34 #include <bcm/l2.h> 35 #include <bcm/error.h> 36 37 #include <bcm_int/esw/mbcm.h> 38 #include <bcm_int/esw/l2.h> 39 #include <bcm_int/esw/firebolt.h> 40 #include <bcm_int/esw/trx.h> 41 #include <bcm_int/esw/triumph.h> 42 #include <bcm_int/esw/mpls.h> 43 #include <bcm_int/common/multicast.h> 44 #include <bcm_int/esw/multicast.h> 45 #include <bcm_int/esw_dispatch.h> 46 #include <bcm_int/esw/trident.h> 47 #include <bcm_int/esw/switch.h> 48 #if defined(BCM_TRIUMPH3_SUPPORT) 49 #include <bcm_int/esw/triumph3.h> 50 #endif /* BCM_TRIUMPH3_SUPPORT */ 51 #if defined(BCM_TRIDENT2_SUPPORT) 52 #include <bcm_int/esw/trident2.h> 53 #endif /* BCM_TRIDENT2_SUPPORT */ 54 55 #ifdef BCM_TOMAHAWK3_SUPPORT 56 #include <bcm_int/esw/tomahawk3.h> 57 58 #if defined(BCM_TRIUMPH_SUPPORT) /* BCM_TRIUMPH_SUPPORT */ 59 60 #define GPORT_TYPE(_gport) (((_gport) >> _SHR_GPORT_TYPE_SHIFT) & _SHR_GPORT_TYPE_MASK) 61 62 #endif /* !BCM_TRIUMPH_SUPPORT */ 63 #define DEFAULT_L2DELETE_CHUNKS 64 /* 8k entries / 64 = 512 */ 64 65 typedef struct _bcm_mac_block_info_s { 66 bcm_pbmp_t mb_pbmp; 67 int ref_count; 68 } _bcm_mac_block_info_t; 69 70 static _bcm_mac_block_info_t *_mbi_entries[BCM_MAX_NUM_UNITS]; 71 static int _mbi_num[BCM_MAX_NUM_UNITS]; 72 73 #if defined(INCLUDE_L3) 74 extern int16 * _sc_subport_group_index[BCM_MAX_NUM_UNITS]; 75 #define _SC_SUBPORT_NUM_PORT (4096) 76 #define _SC_SUBPORT_NUM_GROUP (4096/8) 77 #define _SC_SUBPORT_VPG_FIND(unit, vp, grp) \ 78 do { \ 79 int ix; \ 80 grp = -1; \ 81 for (ix = 0; ix < _SC_SUBPORT_NUM_GROUP; ix++) { \ 82 if (_sc_subport_group_index[unit][ix] == vp) { \ 83 grp = ix * 8; \ 84 break; \ 85 } \ 86 } \ 87 } while ((0)) 88 #endif /* INCLUDE_L3 */ 89 90 typedef enum _bcm_th3_l2x_memacc_field_e { 91 _BCM_TH3_L2X_MEMACC_BASE_VALID_f, 92 _BCM_TH3_L2X_MEMACC_KEY_TYPE_f, 93 _BCM_TH3_L2X_MEMACC_MAC_ADDR_f, 94 _BCM_TH3_L2X_MEMACC_VLAN_ID_f, 95 _BCM_TH3_L2X_MEMACC_L2MC_PTR_f, 96 _BCM_TH3_L2X_MEMACC_DEST_TYPE_f, 97 _BCM_TH3_L2X_MEMACC_TGID_f, 98 _BCM_TH3_L2X_MEMACC_PORT_NUM_f, 99 _BCM_TH3_L2X_MEMACC_CLASS_ID_f, 100 _BCM_TH3_L2X_MEMACC_MAC_BLOCK_INDEX_f, 101 _BCM_TH3_L2X_MEMACC_PRI_f, 102 _BCM_TH3_L2X_MEMACC_CPU_f, 103 _BCM_TH3_L2X_MEMACC_DST_DISCARD_f, 104 _BCM_TH3_L2X_MEMACC_SRC_DISCARD_f, 105 _BCM_TH3_L2X_MEMACC_SCP_f, 106 _BCM_TH3_L2X_MEMACC_STATIC_BIT_f, 107 _BCM_TH3_L2X_MEMACC_HITDA_f, 108 _BCM_TH3_L2X_MEMACC_HITSA_f, 109 _BCM_TH3_L2X_MEMACC_LOCAL_SA_f, 110 _BCM_TH3_L2X_MEMACC_DESTINATION_f, 111 _BCM_TH3_L2X_MEMACC_T_f, 112 _BCM_TH3_L2X_MEMACC_RPE_f, 113 _BCM_TH3_L2X_MEMACC_RESERVED_KEY_PADDING_f, 114 _BCM_TH3_L2X_MEMACC_NUM 115 } _bcm_th3_l2x_memacc_field_t; 116 117 static soc_memacc_t *_bcm_th3_l2x_memacc[BCM_UNITS_MAX]; 118 static soc_field_t _bcm_th3_l2x_fields[] = { 119 BASE_VALIDf, 120 KEY_TYPEf, 121 MAC_ADDRf, 122 VLAN_IDf, 123 L2MC_PTRf, 124 DEST_TYPEf, 125 TGIDf, 126 PORT_NUMf, 127 CLASS_IDf, 128 MAC_BLOCK_INDEXf, 129 PRIf, 130 CPUf, 131 DST_DISCARDf, 132 SRC_DISCARDf, 133 SCPf, 134 STATIC_BITf, 135 HITDAf, 136 HITSAf, 137 LOCAL_SAf, 138 DESTINATIONf, 139 Tf, 140 RPEf, 141 RESERVED_KEY_PADDINGf 142 }; 143 144 #define _BCM_L2X_MEMACC_FIELD(_u_, _f_) \ 145 (&_bcm_th3_l2x_memacc[_u_][_BCM_TH3_L2X_MEMACC_##_f_]) 146 147 #define _BCM_L2X_MEMACC_FIELD_VALID(_u_, _f_) \ 148 SOC_MEMACC_VALID(_BCM_L2X_MEMACC_FIELD(_u_, _f_)) 149 150 #define _BCM_L2X_MEMACC_FIELD32_GET(_u_, _entBuf_, _f_) \ 151 soc_memacc_field32_get(_BCM_L2X_MEMACC_FIELD(_u_, _f_), _entBuf_) 152 153 #define _BCM_L2X_MEMACC_FIELD32_SET(_u_, _entBuf_, _f_, _v_) \ 154 soc_memacc_field32_set(_BCM_L2X_MEMACC_FIELD(_u_, _f_), _entBuf_, \ 155 _v_) 156 157 typedef enum _bcm_th3_l2hit_mem_e { 158 _BCM_TH3_L2HITDA, 159 _BCM_TH3_L2HITSA, 160 _BCM_TH3_L2HIT_MEM_NUM 161 } _bcm_th3_l2hit_mem_t; 162 163 typedef enum _bcm_th3_l2hit_field_e { 164 _BCM_TH3_L2HITDA_HITDA_f_0, 165 _BCM_TH3_L2HITDA_HITDA_f_1, 166 _BCM_TH3_L2HITDA_HITDA_f_2, 167 _BCM_TH3_L2HITDA_HITDA_f_3, 168 _BCM_TH3_L2HITSA_HITSA_f_0, 169 _BCM_TH3_L2HITSA_HITSA_f_1, 170 _BCM_TH3_L2HITSA_HITSA_f_2, 171 _BCM_TH3_L2HITSA_HITSA_f_3, 172 _BCM_TH3_L2HITSA_LOCAL_SA_f_0, 173 _BCM_TH3_L2HITSA_LOCAL_SA_f_1, 174 _BCM_TH3_L2HITSA_LOCAL_SA_f_2, 175 _BCM_TH3_L2HITSA_LOCAL_SA_f_3, 176 _BCM_TH3_L2HIT_FIELD_NUM 177 } _bcm_th3_l2hit_field_t; 178 179 180 static soc_memacc_t *_th3_l2hit_memacc[BCM_UNITS_MAX][_BCM_TH3_L2HIT_MEM_NUM]; 181 182 #define _TH3_L2HIT_MEM(_u_, _m_, _p_) \ 183 (_BCM_TH3_##_m_ + (_p_)) 184 185 #define _TH3_L2HIT_FIELD(_u_, _m_,_f_, _i_) \ 186 (_BCM_TH3_##_m_##_##_f_##_0 + (_i_)) 187 188 #define _TH3_L2HIT_MEMACC_FIELD(_u_, _mem_, _fld_) \ 189 (&_th3_l2hit_memacc[_u_][_mem_][_fld_]) 190 191 #define _TH3_L2HIT_MEMACC_FIELD32_GET(_u_, _mem_, _entBuf_, _fld_) \ 192 soc_memacc_field32_get(_TH3_L2HIT_MEMACC_FIELD(_u_, _mem_, _fld_), \ 193 _entBuf_) 194 195 STATIC int 196 _bcm_th3_l2_memacc_init(int unit) 197 { 198 int rv, i; 199 int alloc_size; 200 int m, f; 201 static soc_mem_t _bcm_th3_l2hit_mems[] = { 202 L2_HITDA_ONLYm, 203 L2_HITSA_ONLYm, 204 }; 205 static soc_field_t _bcm_th3_l2hit_fields[] = { 206 HITDA_0f, HITDA_1f, HITDA_2f, HITDA_3f, 207 HITSA_0f, HITSA_1f, HITSA_2f, HITSA_3f, 208 LOCAL_SA_0f, LOCAL_SA_1f, LOCAL_SA_2f, LOCAL_SA_3f, 209 }; 210 211 if (_bcm_th3_l2x_memacc[unit] != NULL) { 212 sal_free(_bcm_th3_l2x_memacc[unit]); 213 } 214 alloc_size = sizeof(soc_memacc_t) * _BCM_TH3_L2X_MEMACC_NUM; 215 _bcm_th3_l2x_memacc[unit] = sal_alloc(alloc_size, "L2 memacc"); 216 if (_bcm_th3_l2x_memacc[unit] == NULL) { 217 return BCM_E_MEMORY; 218 } 219 sal_memset(_bcm_th3_l2x_memacc[unit], 0, alloc_size); 220 221 for (i = 0; i < _BCM_TH3_L2X_MEMACC_NUM; i++) { 222 rv = soc_memacc_init(unit, L2Xm, _bcm_th3_l2x_fields[i], 223 &_bcm_th3_l2x_memacc[unit][i]); 224 if (BCM_FAILURE(rv)) { 225 SOC_MEMACC_INVALID_SET(&_bcm_th3_l2x_memacc[unit][i]); 226 } 227 } 228 229 for (m = 0; m < _BCM_TH3_L2HIT_MEM_NUM; m++) { 230 if (_th3_l2hit_memacc[unit][m] != NULL) { 231 sal_free(_th3_l2hit_memacc[unit][m]); 232 } 233 alloc_size = sizeof(soc_memacc_t) * _BCM_TH3_L2HIT_FIELD_NUM; 234 _th3_l2hit_memacc[unit][m] = sal_alloc(alloc_size, "L2hit memacc"); 235 if (_th3_l2hit_memacc[unit][m] == NULL) { 236 sal_free(_bcm_th3_l2x_memacc[unit]); 237 _bcm_th3_l2x_memacc[unit] = NULL; 238 return BCM_E_MEMORY; 239 } 240 241 for (f = 0; f < _BCM_TH3_L2HIT_FIELD_NUM; f++) { 242 rv = soc_memacc_init(unit, _bcm_th3_l2hit_mems[m], 243 _bcm_th3_l2hit_fields[f], 244 &_th3_l2hit_memacc[unit][m][f]); 245 if (BCM_FAILURE(rv)) { 246 SOC_MEMACC_INVALID_SET(&_th3_l2hit_memacc[unit][m][f]); 247 } 248 } 249 } 250 251 return BCM_E_NONE; 252 } 253 254 STATIC int 255 _bcm_th3_l2_memacc_deinit(int unit) 256 { 257 int m; 258 259 if (_bcm_th3_l2x_memacc[unit] != NULL) { 260 sal_free(_bcm_th3_l2x_memacc[unit]); 261 _bcm_th3_l2x_memacc[unit] = NULL; 262 } 263 264 for (m = 0; m < _BCM_TH3_L2HIT_MEM_NUM; m++) { 265 if (_th3_l2hit_memacc[unit][m] != NULL) { 266 sal_free(_th3_l2hit_memacc[unit][m]); 267 _th3_l2hit_memacc[unit][m] = NULL; 268 } 269 } 270 271 return BCM_E_NONE; 272 } 273 274 /* 275 * Function: 276 * _bcm_th3_mac_block_delete 277 * Purpose: 278 * Remove reference to MAC_BLOCK table entry matching the given bitmap 279 * Parameters: 280 * unit - Unit number 281 * mb_index - Index of MAC_BLOCK table with bitmap 282 */ 283 STATIC void 284 _bcm_th3_mac_block_delete(int unit, int mb_index) 285 { 286 if (_mbi_entries[unit][mb_index].ref_count > 0) { 287 _mbi_entries[unit][mb_index].ref_count--; 288 } else if (mb_index) { 289 /* Someone reran init without flushing L2 table */ 290 } /* else mb_index = 0, as expected for learning */ 291 } 292 293 /* 294 * Function: 295 * _bcm_th3_mac_block_insert 296 * Purpose: 297 * Find or create a MAC_BLOCK table entry matching the given bitmap 298 * Parameters: 299 * unit - Unit number 300 * mb_pbmp - egress port bitmap for source MAC blocking 301 * mb_index - (OUT) Index of MAC_BLOCK table with bitmap 302 * Returns: 303 * BCM_E_NONE Success 304 * BCM_E_INTERNAL Chip access failure 305 * BCM_E_RESOURCE No more MAC_BLOCK entries available 306 * BCM_E_PARAM Bad bitmap supplied 307 */ 308 STATIC int 309 _bcm_th3_mac_block_insert(int unit, bcm_pbmp_t mb_pbmp, int *mb_index) 310 { 311 int cur_index = 0; 312 _bcm_mac_block_info_t *mbi = _mbi_entries[unit]; 313 mac_block_entry_t mbe; 314 bcm_pbmp_t temp_pbmp; 315 316 /* Check for reasonable pbmp */ 317 BCM_PBMP_ASSIGN(temp_pbmp, mb_pbmp); 318 BCM_PBMP_AND(temp_pbmp, PBMP_ALL(unit)); 319 if (BCM_PBMP_NEQ(mb_pbmp, temp_pbmp)) { 320 return BCM_E_PARAM; 321 } 322 323 for (cur_index = 0; cur_index < _mbi_num[unit]; cur_index++) { 324 if (BCM_PBMP_EQ(mbi[cur_index].mb_pbmp, mb_pbmp)) { 325 mbi[cur_index].ref_count++; 326 *mb_index = cur_index; 327 return BCM_E_NONE; 328 } 329 } 330 331 /* Not in table already, see if any space free */ 332 for (cur_index = 1; cur_index < _mbi_num[unit]; cur_index++) { 333 if (mbi[cur_index].ref_count == 0) { 334 /* Attempt insert */ 335 sal_memset(&mbe, 0, sizeof(mac_block_entry_t)); 336 337 soc_mem_pbmp_field_set(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf, 338 &mb_pbmp); 339 340 SOC_IF_ERROR_RETURN(WRITE_MAC_BLOCKm(unit, MEM_BLOCK_ALL, 341 cur_index, &mbe)); 342 mbi[cur_index].ref_count++; 343 BCM_PBMP_ASSIGN(mbi[cur_index].mb_pbmp, mb_pbmp); 344 *mb_index = cur_index; 345 return BCM_E_NONE; 346 } 347 } 348 349 /* Didn't find a free slot, out of table space */ 350 return BCM_E_RESOURCE; 351 } 352 353 354 #if 0 355 /* 356 * function: 357 * _bcm_tr_l2_traverse_mem 358 * Description: 359 * Helper function to _bcm_esw_l2_traverse to itterate over given memory 360 * and actually read the table and parse entries for Triumph external 361 * memory 362 * Parameters: 363 * unit device number 364 * mem External L2 memory to read 365 * trav_st Traverse structure with all the data. 366 * Return: 367 * BCM_E_XXX 368 */ 369 #ifdef BCM_TRIUMPH_SUPPORT 370 int 371 _bcm_tr_l2_traverse_mem(int unit, soc_mem_t mem, _bcm_l2_traverse_t *trav_st) 372 { 373 _soc_tr_l2e_ppa_info_t *ppa_info; 374 ext_l2_entry_entry_t ext_l2_entry; 375 ext_l2_entry_tcam_entry_t tcam_entry; 376 ext_l2_entry_data_entry_t data_entry; 377 ext_src_hit_bits_l2_entry_t src_hit_entry; 378 ext_dst_hit_bits_l2_entry_t dst_hit_entry; 379 int src_hit, dst_hit; 380 int idx, idx_max; 381 382 if (mem != EXT_L2_ENTRYm) { 383 return BCM_E_UNAVAIL; 384 } 385 386 if (!soc_mem_index_count(unit, mem)) { 387 return BCM_E_NONE; 388 } 389 390 ppa_info = SOC_CONTROL(unit)->ext_l2_ppa_info; 391 if (ppa_info == NULL) { 392 return BCM_E_NONE; 393 } 394 395 idx_max = soc_mem_index_max(unit, mem); 396 for (idx = soc_mem_index_min(unit, mem); idx <= idx_max; idx++ ) { 397 if (!(ppa_info[idx].data & _SOC_TR_L2E_VALID)) { 398 continue; 399 } 400 SOC_IF_ERROR_RETURN 401 (soc_mem_read(unit, EXT_L2_ENTRY_TCAMm, MEM_BLOCK_ANY, idx, 402 &tcam_entry)); 403 SOC_IF_ERROR_RETURN 404 (soc_mem_read(unit, EXT_L2_ENTRY_DATAm, MEM_BLOCK_ANY, idx, 405 &data_entry)); 406 SOC_IF_ERROR_RETURN 407 (soc_mem_read(unit, EXT_SRC_HIT_BITS_L2m, MEM_BLOCK_ANY, idx >> 5, 408 &src_hit_entry)); 409 SOC_IF_ERROR_RETURN 410 (soc_mem_read(unit, EXT_DST_HIT_BITS_L2m, MEM_BLOCK_ANY, idx >> 5, 411 &dst_hit_entry)); 412 src_hit = (soc_mem_field32_get 413 (unit, EXT_SRC_HIT_BITS_L2m, &src_hit_entry, SRC_HITf) >> 414 (idx & 0x1f)) & 1; 415 dst_hit = (soc_mem_field32_get 416 (unit, EXT_DST_HIT_BITS_L2m, &dst_hit_entry, DST_HITf) >> 417 (idx & 0x1f)) & 1; 418 BCM_IF_ERROR_RETURN 419 (_bcm_tr_compose_ext_l2_entry(unit, &tcam_entry, &data_entry, 420 src_hit, dst_hit, &ext_l2_entry)); 421 trav_st->data = (uint32 *)&ext_l2_entry; 422 trav_st->mem = mem; 423 424 BCM_IF_ERROR_RETURN(trav_st->int_cb(unit, trav_st)); 425 } 426 427 return BCM_E_NONE; 428 } 429 #endif /* BCM_TRIUMPH_SUPPORT */ 430 431 /* 432 * Function: 433 * _bcm_mac_block_insert 434 * Purpose: 435 * Find or create a MAC_BLOCK table entry matching the given bitmap. 436 * Parameters: 437 * unit - Unit number 438 * mb_pbmp - egress port bitmap for source MAC blocking 439 * mb_index - (OUT) Index of MAC_BLOCK table with bitmap. 440 * Returns: 441 * BCM_E_NONE Success 442 * BCM_E_INTERNAL Chip access failure 443 * BCM_E_RESOURCE No more MAC_BLOCK entries available 444 * BCM_E_PARAM Bad bitmap supplied 445 */ 446 static int 447 _bcm_mac_block_insert(int unit, bcm_pbmp_t mb_pbmp, int *mb_index) 448 { 449 int cur_index = 0; 450 _bcm_mac_block_info_t *mbi = _mbi_entries[unit]; 451 mac_block_entry_t mbe; 452 bcm_pbmp_t temp_pbmp; 453 #if defined(BCM_KATANA2_SUPPORT) 454 uint32 fldbuf[SOC_PBMP_WORD_MAX]; 455 bcm_pbmp_t mb_pbmp0, mb_pbmp1; 456 int mask_w0_width = 0; 457 int mask_w1_width = 0; 458 int i = 0; 459 460 SOC_PBMP_CLEAR(mb_pbmp0); 461 SOC_PBMP_CLEAR(mb_pbmp1); 462 #endif 463 464 /* Check for reasonable pbmp */ 465 BCM_PBMP_ASSIGN(temp_pbmp, mb_pbmp); 466 BCM_PBMP_AND(temp_pbmp, PBMP_ALL(unit)); 467 if (BCM_PBMP_NEQ(mb_pbmp, temp_pbmp)) { 468 return BCM_E_PARAM; 469 } 470 471 for (cur_index = 0; cur_index < _mbi_num[unit]; cur_index++) { 472 if (BCM_PBMP_EQ(mbi[cur_index].mb_pbmp, mb_pbmp)) { 473 mbi[cur_index].ref_count++; 474 *mb_index = cur_index; 475 return BCM_E_NONE; 476 } 477 } 478 479 /* Not in table already, see if any space free */ 480 for (cur_index = 1; cur_index < _mbi_num[unit]; cur_index++) { 481 if (mbi[cur_index].ref_count == 0) { 482 /* Attempt insert */ 483 sal_memset(&mbe, 0, sizeof(mac_block_entry_t)); 484 485 if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_LOf)) { 486 soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_LOf, 487 SOC_PBMP_WORD_GET(mb_pbmp, 0)); 488 } else if (soc_mem_field_valid(unit, MAC_BLOCKm, 489 MAC_BLOCK_MASK_W0f)) { 490 #if defined(BCM_KATANA2_SUPPORT) 491 if (SOC_IS_KATANA2(unit)) { 492 mask_w0_width = soc_mem_field_length(unit, MAC_BLOCKm, 493 MAC_BLOCK_MASK_W0f); 494 for (i = 0; i < mask_w0_width; i++) { 495 if (SOC_PBMP_MEMBER(mb_pbmp, i)) { 496 SOC_PBMP_PORT_ADD(mb_pbmp0, i); 497 } 498 } 499 500 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 501 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 502 fldbuf[i] = SOC_PBMP_WORD_GET(mb_pbmp0, i); 503 } 504 soc_MAC_BLOCKm_field_set(unit, &mbe, 505 MAC_BLOCK_MASK_W0f, fldbuf); 506 } else 507 #endif /* BCM_KATANA2_SUPPORT */ 508 { 509 soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_W0f, 510 SOC_PBMP_WORD_GET(mb_pbmp, 0)); 511 } 512 } else if (soc_mem_field_valid(unit, MAC_BLOCKm, 513 MAC_BLOCK_MASKf)) { 514 soc_mem_pbmp_field_set(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf, 515 &mb_pbmp); 516 } else { 517 return BCM_E_INTERNAL; 518 } 519 if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_HIf)) { 520 soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_HIf, 521 SOC_PBMP_WORD_GET(mb_pbmp, 1)); 522 } else if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_W1f)) { 523 #if defined(BCM_KATANA2_SUPPORT) 524 if (SOC_IS_KATANA2(unit)) { 525 mask_w1_width = soc_mem_field_length(unit, MAC_BLOCKm, 526 MAC_BLOCK_MASK_W1f); 527 528 for (i = mask_w0_width; 529 i < (mask_w0_width + mask_w1_width); i++) { 530 if (SOC_PBMP_MEMBER(mb_pbmp, i)) { 531 SOC_PBMP_PORT_ADD(mb_pbmp1, (i - mask_w0_width)); 532 } 533 } 534 535 sal_memset(fldbuf, 0, SOC_PBMP_WORD_MAX * sizeof(uint32)); 536 for (i = 0; i < SOC_PBMP_WORD_MAX; i++) { 537 fldbuf[i] = SOC_PBMP_WORD_GET(mb_pbmp1, i); 538 } 539 soc_MAC_BLOCKm_field_set(unit, &mbe, 540 MAC_BLOCK_MASK_W1f, fldbuf); 541 } else 542 #endif /* BCM_KATANA2_SUPPORT */ 543 { 544 soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_W1f, 545 SOC_PBMP_WORD_GET(mb_pbmp, 1)); 546 } 547 } 548 if (soc_mem_field_valid(unit, MAC_BLOCKm, MAC_BLOCK_MASK_W2f)) { 549 #if defined(BCM_TRIDENT_SUPPORT) 550 if (SOC_IS_TRIDENT(unit)) { 551 soc_MAC_BLOCKm_field32_set(unit, &mbe, MAC_BLOCK_MASK_W2f, 552 SOC_PBMP_WORD_GET(mb_pbmp, 2)); 553 } 554 #endif 555 } 556 557 SOC_IF_ERROR_RETURN(WRITE_MAC_BLOCKm(unit, MEM_BLOCK_ALL, 558 cur_index, &mbe)); 559 mbi[cur_index].ref_count++; 560 BCM_PBMP_ASSIGN(mbi[cur_index].mb_pbmp, mb_pbmp); 561 *mb_index = cur_index; 562 return BCM_E_NONE; 563 } 564 } 565 566 /* Didn't find a free slot, out of table space */ 567 return BCM_E_RESOURCE; 568 } 569 570 /* 571 * Function: 572 * _bcm_mac_block_delete 573 * Purpose: 574 * Remove reference to MAC_BLOCK table entry matching the given bitmap. 575 * Parameters: 576 * unit - Unit number 577 * mb_index - Index of MAC_BLOCK table with bitmap. 578 */ 579 static void 580 _bcm_mac_block_delete(int unit, int mb_index) 581 { 582 if (_mbi_entries[unit][mb_index].ref_count > 0) { 583 _mbi_entries[unit][mb_index].ref_count--; 584 } else if (mb_index) { 585 586 /* Someone reran init without flushing the L2 table */ 587 } /* else mb_index = 0, as expected for learning */ 588 } 589 590 #endif /* 0 */ 591 592 593 #if 0 594 #ifdef BCM_TRIUMPH_SUPPORT 595 STATIC int 596 _bcm_t_l2e_ppa_match(int unit, _bcm_l2_replace_t *rep_st) 597 { 598 _soc_tr_l2e_ppa_info_t *ppa_info; 599 _soc_tr_l2e_ppa_vlan_t *ppa_vlan; 600 int i, imin, imax, rv, nmatches; 601 soc_mem_t mem; 602 uint32 entdata, entmask, entvalue, newdata, newmask; 603 ext_l2_entry_entry_t l2entry, old_l2entry; 604 int same_dest; 605 606 ppa_info = SOC_CONTROL(unit)->ext_l2_ppa_info; 607 ppa_vlan = SOC_CONTROL(unit)->ext_l2_ppa_vlan; 608 if (ppa_info == NULL) { 609 return BCM_E_NONE; 610 } 611 612 mem = EXT_L2_ENTRYm; 613 imin = soc_mem_index_min(unit, mem); 614 imax = soc_mem_index_max(unit, mem); 615 616 /* convert match data */ 617 entdata = _SOC_TR_L2E_VALID; 618 entmask = _SOC_TR_L2E_VALID; 619 if (!(rep_st->flags & BCM_L2_REPLACE_MATCH_STATIC)) { 620 entdata |= 0x00000000; 621 entmask |= _SOC_TR_L2E_STATIC; 622 } 623 if (rep_st->flags & BCM_L2_REPLACE_MATCH_VLAN) { 624 entdata |= (rep_st->key_vlan & _SOC_TR_L2E_VLAN_MASK) << 625 _SOC_TR_L2E_VLAN_SHIFT; 626 entmask |= _SOC_TR_L2E_VLAN_MASK << _SOC_TR_L2E_VLAN_SHIFT; 627 imin = ppa_vlan->vlan_min[rep_st->key_vlan]; 628 imax = ppa_vlan->vlan_max[rep_st->key_vlan]; 629 } 630 if (rep_st->flags & BCM_L2_REPLACE_MATCH_DEST) { 631 if (rep_st->match_dest.trunk != -1) { 632 entdata |= _SOC_TR_L2E_T | 633 ((rep_st->match_dest.trunk & _SOC_TR_L2E_TRUNK_MASK) 634 << _SOC_TR_L2E_TRUNK_SHIFT); 635 entmask |= _SOC_TR_L2E_T | 636 (_SOC_TR_L2E_TRUNK_MASK << _SOC_TR_L2E_TRUNK_SHIFT); 637 } else { 638 entdata |= 639 ((rep_st->match_dest.module & _SOC_TR_L2E_MOD_MASK) << 640 _SOC_TR_L2E_MOD_SHIFT) | 641 ((rep_st->match_dest.port & _SOC_TR_L2E_PORT_MASK) << 642 _SOC_TR_L2E_PORT_SHIFT); 643 entmask |= _SOC_TR_L2E_T | 644 (_SOC_TR_L2E_MOD_MASK << _SOC_TR_L2E_MOD_SHIFT) | 645 (_SOC_TR_L2E_PORT_MASK << _SOC_TR_L2E_PORT_SHIFT); 646 } 647 } 648 649 nmatches = 0; 650 651 if (imin >= 0) { 652 soc_mem_lock(unit, mem); 653 for (i = imin; i <= imax; i++) { 654 entvalue = ppa_info[i].data; 655 if ((entvalue & entmask) != entdata) { 656 continue; 657 } 658 if (rep_st->flags & BCM_L2_REPLACE_MATCH_MAC) { 659 if (ENET_CMP_MACADDR(rep_st->key_mac, ppa_info[i].mac)) { 660 continue; 661 } 662 } 663 nmatches += 1; 664 665 /* lookup the matched entry */ 666 sal_memset(&l2entry, 0, sizeof(l2entry)); 667 soc_mem_field32_set(unit, mem, &l2entry, VLAN_IDf, 668 (entvalue >> 16) & 0xfff); 669 soc_mem_mac_addr_set(unit, mem, &l2entry, MAC_ADDRf, 670 ppa_info[i].mac); 671 672 /* operate on matched entry */ 673 if (rep_st->flags & BCM_L2_REPLACE_DELETE) { 674 int mb_index; 675 676 /* coverity[value_overwrite] */ 677 rv = soc_mem_generic_delete(unit, mem, MEM_BLOCK_ANY, 0, 678 &l2entry, &l2entry, NULL); 679 if (rv < 0) { 680 soc_mem_unlock(unit, mem); 681 return rv; 682 } 683 if (!SOC_CONTROL(unit)->l2x_group_enable) { 684 mb_index = soc_mem_field32_get(unit, mem, &l2entry, 685 MAC_BLOCK_INDEXf); 686 _bcm_mac_block_delete(unit, mb_index); 687 } 688 if (entvalue & _SOC_TR_L2E_LIMIT_COUNTED) { 689 /* coverity[returned_value] */ 690 rv = soc_triumph_learn_count_update(unit, &l2entry, 691 TRUE, -1); 692 } 693 } else { 694 /* replace destination fields */ 695 /* coverity[value_overwrite] */ 696 rv = soc_mem_generic_lookup(unit, mem, MEM_BLOCK_ANY, 0, 697 &l2entry, &l2entry, NULL); 698 if (rep_st->flags & BCM_L2_REPLACE_NEW_TRUNK) { 699 newdata = _SOC_TR_L2E_T | 700 ((rep_st->new_dest.trunk & _SOC_TR_L2E_TRUNK_MASK) << 701 _SOC_TR_L2E_TRUNK_SHIFT); 702 newmask = _SOC_TR_L2E_T | 703 (_SOC_TR_L2E_TRUNK_MASK << _SOC_TR_L2E_TRUNK_SHIFT); 704 soc_mem_field32_set(unit, mem, &l2entry, Tf, 1); 705 soc_mem_field32_set(unit, mem, &l2entry, TGIDf, 706 rep_st->new_dest.trunk); 707 } else { 708 newdata = 709 (rep_st->new_dest.module << _SOC_TR_L2E_MOD_SHIFT) | 710 (rep_st->new_dest.port << _SOC_TR_L2E_PORT_SHIFT); 711 newmask = _SOC_TR_L2E_T | 712 (_SOC_TR_L2E_MOD_MASK << _SOC_TR_L2E_MOD_SHIFT) | 713 (_SOC_TR_L2E_PORT_MASK << _SOC_TR_L2E_PORT_SHIFT); 714 soc_mem_field32_set(unit, mem, &l2entry, MODULE_IDf, 715 rep_st->new_dest.module); 716 soc_mem_field32_set(unit, mem, &l2entry, PORT_NUMf, 717 rep_st->new_dest.port); 718 } 719 same_dest = !((entvalue ^ newdata) & newmask); 720 721 if ((entvalue & _SOC_TR_L2E_LIMIT_COUNTED) && !same_dest) { 722 rv = soc_triumph_learn_count_update(unit, &l2entry, FALSE, 723 1); 724 if (SOC_FAILURE(rv)) { 725 soc_mem_unlock(unit, mem); 726 return rv; 727 } 728 } 729 730 /* re-insert entry */ 731 rv = soc_mem_generic_insert(unit, mem, MEM_BLOCK_ANY, 0, 732 &l2entry, &old_l2entry, NULL); 733 if (rv == BCM_E_EXISTS) { 734 rv = BCM_E_NONE; 735 } 736 if (rv < 0) { 737 soc_mem_unlock(unit, mem); 738 return rv; 739 } 740 if ((entvalue & _SOC_TR_L2E_LIMIT_COUNTED) && !same_dest) { 741 rv = soc_triumph_learn_count_update(unit, &old_l2entry, 742 FALSE, -1); 743 if (SOC_FAILURE(rv)) { 744 soc_mem_unlock(unit, mem); 745 return rv; 746 } 747 } 748 } 749 } 750 soc_mem_unlock(unit, EXT_L2_ENTRYm); 751 } 752 LOG_VERBOSE(BSL_LS_SOC_COMMON, 753 (BSL_META_U(unit, 754 "tr_l2e_ppa_match: imin=%d imax=%d nmatches=%d flags=0x%x\n"), 755 imin, imax, nmatches, rep_st->flags)); 756 return BCM_E_NONE; 757 } 758 #endif /* BCM_TRIUMPH_SUPPORT */ 759 760 /* 761 * Function: 762 * _bcm_l2_hash_dynamic_replace 763 * Purpose: 764 * Replace dynamic L2 entries in a dual hash. 765 * Parameters: 766 * unit - Unit number 767 * l2x_entry - Entry to insert instead of dynamic entry. 768 * Returns: 769 * BCM_E_NONE Success 770 * BCM_E_XXX Error 771 */ 772 773 int _bcm_l2_hash_dynamic_replace(int unit, l2x_entry_t *l2x_entry) 774 { 775 l2x_entry_t l2ent; 776 int rv; 777 uint32 fval; 778 bcm_mac_t mac; 779 int cf_hit, cf_unhit; 780 int bank, bucket, slot, index; 781 int num_banks; 782 int entries_per_bank, entries_per_row, entries_per_bucket; 783 int bank_base, bucket_offset; 784 785 786 787 BCM_IF_ERROR_RETURN(soc_trident2_hash_bank_count_get(unit, L2Xm, &num_banks)); 788 789 BCM_IF_ERROR_RETURN(soc_l2x_freeze(unit)); 790 791 cf_hit = cf_unhit = -1; 792 for (bank = 0; bank < num_banks; bank++) { 793 { 794 795 rv = soc_trident2_hash_bank_info_get(unit, L2Xm, bank, 796 &entries_per_bank, 797 &entries_per_row, 798 &entries_per_bucket, 799 &bank_base, &bucket_offset); 800 if (SOC_FAILURE(rv)) { 801 (void)soc_l2x_thaw(unit); 802 return rv; 803 } 804 bucket = soc_td2_l2x_bank_entry_hash(unit, bank, 805 (uint32 *)l2x_entry); 806 } 807 808 809 for (slot = 0; slot < entries_per_bucket; slot++) { 810 uint32 valid = 0; 811 index = bank_base + bucket * entries_per_row + bucket_offset + 812 slot; 813 rv = soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, index, &l2ent); 814 if (SOC_FAILURE(rv)) { 815 (void)soc_l2x_thaw(unit); 816 return rv; 817 } 818 819 if (soc_feature(unit, soc_feature_base_valid)) { 820 valid = soc_L2Xm_field32_get(unit, &l2ent, BASE_VALIDf); 821 } else { 822 valid = soc_L2Xm_field32_get(unit, &l2ent, VALIDf); 823 } 824 if (!valid) { 825 /* Found invalid entry - stop the search victim found */ 826 cf_unhit = index; 827 break; 828 } 829 830 fval = soc_mem_field32_get(unit, L2Xm, &l2ent, KEY_TYPEf); 831 #ifdef BCM_TRIDENT2_SUPPORT 832 if (SOC_IS_TD2_TT2(unit)) { 833 if (fval != TD2_L2_HASH_KEY_TYPE_BRIDGE && 834 fval != TD2_L2_HASH_KEY_TYPE_VFI) { 835 continue; 836 } 837 } else 838 #endif /* BCM_TRIDENT2_SUPPORT */ 839 if (fval != TR_L2_HASH_KEY_TYPE_BRIDGE && 840 fval != TR_L2_HASH_KEY_TYPE_VFI) { 841 continue; 842 } 843 844 soc_L2Xm_mac_addr_get(unit, &l2ent, MAC_ADDRf, mac); 845 /* Skip static entries */ 846 if ((soc_L2Xm_field32_get(unit, &l2ent, STATIC_BITf)) || 847 (BCM_MAC_IS_MCAST(mac)) || 848 (soc_mem_field_valid(unit, L2Xm, L3f) && 849 soc_L2Xm_field32_get(unit, &l2ent, L3f))) { 850 continue; 851 } 852 853 if (soc_L2Xm_field32_get(unit, &l2ent, HITDAf) || 854 soc_L2Xm_field32_get(unit, &l2ent, HITSAf) ) { 855 cf_hit = index; 856 } else { 857 /* Found unhit entry - stop search victim found */ 858 cf_unhit = index; 859 break; 860 } 861 } 862 if (cf_unhit != -1) { 863 break; 864 } 865 } 866 867 COMPILER_REFERENCE(entries_per_bank); 868 869 if (cf_unhit >= 0) { 870 index = cf_unhit; /* take last unhit dynamic */ 871 } else if (cf_hit >= 0) { 872 index = cf_hit; /* or last hit dynamic */ 873 } else { 874 rv = BCM_E_FULL; /* no dynamics to delete */ 875 (void) soc_l2x_thaw(unit); 876 return rv; 877 } 878 879 rv = soc_mem_delete_index(unit, L2Xm, MEM_BLOCK_ALL, index); 880 if (SOC_SUCCESS(rv)) { 881 rv = soc_mem_generic_insert(unit, L2Xm, MEM_BLOCK_ANY, 0, 882 l2x_entry, NULL, NULL); 883 } 884 if (SOC_FAILURE(rv)) { 885 (void) soc_l2x_thaw(unit); 886 return rv; 887 } 888 889 return soc_l2x_thaw(unit); 890 } 891 892 /* 893 * Function: 894 * bcm_bfd_l2_hash_dynamic_replace 895 * Purpose: 896 * Replace dynamic L2 entries in a dual hash. 897 * Parameters: 898 * unit - Unit number 899 * l2x_entry - Entry to insert instead of dynamic entry. 900 * Returns: 901 * BCM_E_NONE Success 902 * BCM_E_XXX Error 903 */ 904 905 int bcm_bfd_l2_hash_dynamic_replace(int unit, l2x_entry_t *l2x_entry) 906 { 907 int rv; 908 909 #if defined(BCM_TRIUMPH3_SUPPORT) 910 if (SOC_IS_TRIUMPH3(unit)) { 911 rv = bcm_tr3_bfd_l2_hash_dynamic_replace(unit, (void *)l2x_entry); 912 } else 913 #endif /* BCM_TRIUMPH3_SUPPORT */ 914 { 915 rv = _bcm_l2_hash_dynamic_replace(unit, l2x_entry); 916 } 917 918 return rv; 919 } 920 921 #endif 922 923 #if defined(BCM_TRIDENT2_SUPPORT) 924 /* 925 * Function: 926 * _bcm_th3_l2_hit_retrieve 927 * Purpose: 928 * Retrieve the hit bit from both x and y pipe, then "or" the hitbit values and assign it to 929 * L2_ENTRY data structure. 930 * Parameters: 931 * unit Unit number 932 * l2addr (OUT) L2 API data structure 933 * l2x_entry L2X entry 934 * l2_hw_index L2X entry hardware index 935 */ 936 int 937 _bcm_th3_l2_hit_retrieve(int unit, l2x_entry_t *l2x_entry, 938 int l2_hw_index) 939 { 940 uint32 hit_sa, hit_da, hit_local_sa; /* composite hit = hit_x|hit_y */ 941 int idx_offset, hit_idx_shift; 942 l2_hitsa_only_x_entry_t hit_sa_x; 943 l2_hitsa_only_y_entry_t hit_sa_y; 944 l2_hitda_only_x_entry_t hit_da_x; 945 l2_hitda_only_y_entry_t hit_da_y; 946 soc_field_t hit_saf[] = { HITSA_0f, HITSA_1f, HITSA_2f, HITSA_3f}; 947 soc_field_t hit_daf[] = { HITDA_0f, HITDA_1f, HITDA_2f, HITDA_3f}; 948 soc_field_t hit_local_saf[] = { LOCAL_SA_0f, LOCAL_SA_1f, 949 LOCAL_SA_2f, LOCAL_SA_3f}; 950 951 idx_offset = (l2_hw_index & 0x3); 952 hit_idx_shift = 2; 953 954 /* Retrieve DA HIT */ 955 BCM_IF_ERROR_RETURN( 956 BCM_XGS3_MEM_READ(unit, L2_HITDA_ONLY_Xm, 957 (l2_hw_index >> hit_idx_shift), &hit_da_x)); 958 959 BCM_IF_ERROR_RETURN( 960 BCM_XGS3_MEM_READ(unit, L2_HITDA_ONLY_Ym, 961 (l2_hw_index >> hit_idx_shift), &hit_da_y)); 962 963 hit_da = 0; 964 hit_da |= soc_mem_field32_get(unit, L2_HITDA_ONLY_Xm, 965 &hit_da_x, hit_daf[idx_offset]); 966 967 hit_da |= soc_mem_field32_get(unit, L2_HITDA_ONLY_Ym, 968 &hit_da_y, hit_daf[idx_offset]); 969 970 _BCM_L2X_MEMACC_FIELD32_SET(unit, l2x_entry, HITDA_f, hit_da); 971 972 /* Retrieve SA HIT */ 973 BCM_IF_ERROR_RETURN( 974 BCM_XGS3_MEM_READ(unit, L2_HITSA_ONLY_Xm, 975 (l2_hw_index >> hit_idx_shift), &hit_sa_x)); 976 977 BCM_IF_ERROR_RETURN( 978 BCM_XGS3_MEM_READ(unit, L2_HITSA_ONLY_Ym, 979 (l2_hw_index >> hit_idx_shift), &hit_sa_y)); 980 981 hit_sa = 0; 982 hit_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Xm, 983 &hit_sa_x, hit_saf[idx_offset]); 984 985 hit_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Ym, 986 &hit_sa_y, hit_saf[idx_offset]); 987 988 _BCM_L2X_MEMACC_FIELD32_SET(unit, l2x_entry, HITSA_f, hit_sa); 989 990 /* Retrieve LOCAL_SA HIT */ 991 hit_local_sa = 0; 992 hit_local_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Xm, 993 &hit_sa_x, hit_local_saf[idx_offset]); 994 995 hit_local_sa |= soc_mem_field32_get(unit, L2_HITSA_ONLY_Ym, 996 &hit_sa_y, hit_local_saf[idx_offset]); 997 998 _BCM_L2X_MEMACC_FIELD32_SET(unit, l2x_entry, LOCAL_SA_f, hit_local_sa); 999 1000 return BCM_E_NONE; 1001 } 1002 1003 #endif /* BCM_TRIDENT2_SUPPORT */ 1004 1005 1006 #if 0 1007 /* 1008 * Function: 1009 * bcm_tr_l2_addr_add 1010 * Description: 1011 * Add a MAC address to the Switch Address Resolution Logic (ARL) 1012 * port with the given VLAN ID and parameters. 1013 * Parameters: 1014 * unit - StrataSwitch PCI device unit number (driver internal). 1015 * l2addr - Pointer to bcm_l2_addr_t containing all valid fields 1016 * Returns: 1017 * BCM_E_NONE Success 1018 * BCM_E_INTERNAL Chip access failure 1019 * BCM_E_RESOURCE No MAC_BLOCK entries available 1020 * Notes: 1021 * Use CMIC_PORT(unit) to associate the entry with the CPU. 1022 * Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU. 1023 * Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be 1024 * passed as well with non-zero trunk group ID) 1025 * In case the L2X table is full (e.g. bucket full), an attempt 1026 * will be made to store the entry in the L2_USER_ENTRY table. 1027 */ 1028 int 1029 bcm_tr_l2_addr_add(int unit, bcm_l2_addr_t *l2addr) 1030 { 1031 l2x_entry_t l2x_entry, l2x_lookup; 1032 #ifdef BCM_TRIUMPH_SUPPORT 1033 _soc_tr_l2e_ppa_info_t *ppa_info = NULL; 1034 ext_l2_entry_entry_t ext_l2_entry, ext_l2_lookup; 1035 int exist_in_ext_l2 =0, limit_counted; 1036 int rv1, ext_l2_index; 1037 #endif /* BCM_TRIUMPH_SUPPORT */ 1038 int enable_ppa_war; 1039 int rv, l2_index, mb_index = 0; 1040 1041 #ifdef BCM_TRIDENT_SUPPORT 1042 if (SOC_IS_TRIDENT(unit) || SOC_IS_KATANAX(unit) || 1043 SOC_IS_TD2_TT2(unit)) { 1044 if (soc_mem_is_valid(unit, MY_STATION_TCAMm) && 1045 (l2addr->flags & BCM_L2_L3LOOKUP)) { 1046 BCM_IF_ERROR_RETURN(bcm_td_l2_myStation_add(unit, l2addr)); 1047 } 1048 else if (soc_mem_is_valid(unit, MY_STATION_TCAMm) && 1049 !(l2addr->flags & BCM_L2_L3LOOKUP)) { 1050 /* If VPN specified do not perform myStation delete */ 1051 if (!_BCM_VPN_VFI_IS_SET(l2addr->vid)) { 1052 rv = bcm_td_l2_myStation_delete(unit, 1053 l2addr->mac, l2addr->vid, &l2_index); 1054 if (rv != BCM_E_NONE && rv != BCM_E_NOT_FOUND) { 1055 return rv; 1056 } 1057 } 1058 } 1059 } 1060 #endif /* BCM_TRIDENT_SUPPORT */ 1061 1062 BCM_IF_ERROR_RETURN(_bcm_tr_l2_to_l2x(unit, &l2x_entry, l2addr, FALSE)); 1063 1064 rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry, 1065 &l2x_lookup, &l2_index); 1066 if (BCM_FAILURE(rv) && rv != BCM_E_NOT_FOUND) { 1067 return rv; 1068 } 1069 1070 if (!SOC_CONTROL(unit)->l2x_group_enable) { 1071 /* Mac blocking, attempt to associate with bitmap entry */ 1072 BCM_IF_ERROR_RETURN 1073 (_bcm_mac_block_insert(unit, l2addr->block_bitmap, &mb_index)); 1074 soc_mem_field32_set(unit, L2Xm, &l2x_entry, MAC_BLOCK_INDEXf, 1075 mb_index); 1076 } 1077 1078 enable_ppa_war = FALSE; 1079 if (SOC_CONTROL(unit)->l2x_ppa_bypass == FALSE && 1080 soc_feature(unit, soc_feature_ppa_bypass) && 1081 soc_mem_field32_get(unit, L2Xm, &l2x_entry, KEY_TYPEf) != 1082 TR_L2_HASH_KEY_TYPE_BRIDGE) { 1083 enable_ppa_war = TRUE; 1084 } 1085 1086 rv = soc_mem_insert_return_old(unit, L2Xm, MEM_BLOCK_ANY, 1087 (void *)&l2x_entry, NULL); 1088 if ((rv == BCM_E_FULL) && (l2addr->flags & BCM_L2_REPLACE_DYNAMIC)) { 1089 rv = _bcm_l2_hash_dynamic_replace( unit, &l2x_entry); 1090 if (rv < 0 ) { 1091 goto done; 1092 } 1093 } else if (rv == BCM_E_EXISTS) { 1094 if (!SOC_CONTROL(unit)->l2x_group_enable) { 1095 mb_index = soc_mem_field32_get(unit, L2Xm, &l2x_lookup, 1096 MAC_BLOCK_INDEXf); 1097 _bcm_mac_block_delete(unit, mb_index); 1098 } 1099 rv = BCM_E_NONE; 1100 } 1101 1102 if (BCM_SUCCESS(rv) && enable_ppa_war) { 1103 SOC_CONTROL(unit)->l2x_ppa_bypass = TRUE; 1104 } 1105 1106 #ifdef BCM_TRIUMPH_SUPPORT 1107 if (SOC_SUCCESS(rv)) { 1108 if (exist_in_ext_l2) { 1109 soc_mem_lock(unit, EXT_L2_ENTRYm); 1110 limit_counted = 1111 ppa_info[ext_l2_index].data & _SOC_TR_L2E_LIMIT_COUNTED; 1112 rv1 = soc_mem_generic_delete(unit, EXT_L2_ENTRYm, MEM_BLOCK_ANY, 1113 0, &ext_l2_entry, &ext_l2_lookup, 1114 &ext_l2_index); 1115 if (SOC_SUCCESS(rv1)) { 1116 if (!SOC_CONTROL(unit)->l2x_group_enable) { 1117 mb_index = 1118 soc_mem_field32_get(unit, EXT_L2_ENTRYm, 1119 &ext_l2_lookup, MAC_BLOCK_INDEXf); 1120 _bcm_mac_block_delete(unit, mb_index); 1121 } 1122 if (limit_counted) { 1123 (void)soc_triumph_learn_count_update(unit, &ext_l2_lookup, 1124 TRUE, -1); 1125 } 1126 } 1127 soc_mem_unlock(unit, EXT_L2_ENTRYm); 1128 } 1129 } 1130 #endif 1131 1132 done: 1133 if (rv < 0) { 1134 _bcm_mac_block_delete(unit, mb_index); 1135 } 1136 1137 return rv; 1138 } 1139 1140 /* 1141 * Function: 1142 * bcm_tr_l2_addr_delete 1143 * Description: 1144 * Delete an L2 address (MAC+VLAN) from the device 1145 * Parameters: 1146 * unit - device unit 1147 * mac - MAC address to delete 1148 * vid - VLAN id 1149 * Returns: 1150 * BCM_E_XXX 1151 */ 1152 int 1153 bcm_tr_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid) 1154 { 1155 bcm_l2_addr_t l2addr; 1156 l2x_entry_t l2x_entry, l2x_lookup; 1157 int l2_index, mb_index; 1158 int rv; 1159 soc_control_t *soc = SOC_CONTROL(unit); 1160 1161 bcm_l2_addr_t_init(&l2addr, mac, vid); 1162 1163 #ifdef BCM_TRIDENT_SUPPORT 1164 if (SOC_IS_TRIDENT(unit) || (SOC_IS_KATANAX(unit)) || 1165 SOC_IS_TD2_TT2(unit)) { 1166 if (soc_mem_is_valid(unit, MY_STATION_TCAMm) && BCM_VLAN_VALID(vid)) { 1167 rv = bcm_td_l2_myStation_delete (unit, mac, vid, &l2_index); 1168 if ((rv != BCM_E_NOT_FOUND) && (rv != BCM_E_FULL)) { 1169 if (rv != BCM_E_NONE) { 1170 return rv; 1171 } 1172 } 1173 } 1174 } 1175 #endif /* BCM_TRIDENT_SUPPORT */ 1176 1177 BCM_IF_ERROR_RETURN(_bcm_tr_l2_to_l2x(unit, &l2x_entry, &l2addr, TRUE)); 1178 1179 soc_mem_lock(unit, L2Xm); 1180 1181 rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ANY, &l2_index, 1182 (void *)&l2x_entry, (void *)&l2x_lookup, 0); 1183 if (BCM_E_NONE != rv) { 1184 soc_mem_unlock(unit, L2Xm); 1185 return rv; 1186 } 1187 1188 if (!SOC_CONTROL(unit)->l2x_group_enable) { 1189 mb_index = soc_L2Xm_field32_get(unit, &l2x_lookup, MAC_BLOCK_INDEXf); 1190 _bcm_mac_block_delete(unit, mb_index); 1191 } 1192 1193 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 1194 soc_mem_unlock(unit, L2Xm); 1195 return BCM_E_RESOURCE; 1196 } 1197 rv = soc_mem_delete_return_old(unit, L2Xm, MEM_BLOCK_ANY, 1198 (void *)&l2x_entry, (void *)&l2x_entry); 1199 if (rv >= 0) { 1200 rv = soc_l2x_sync_delete(unit, (uint32 *) &l2x_lookup, l2_index, 0); 1201 } 1202 SOC_L2_DEL_SYNC_UNLOCK(soc); 1203 soc_mem_unlock(unit, L2Xm); 1204 1205 return rv; 1206 } 1207 1208 /* 1209 * Function: 1210 * bcm_tr_l2_addr_get 1211 * Description: 1212 * Given a MAC address and VLAN ID, check if the entry is present 1213 * in the L2 table, and if so, return all associated information. 1214 * Parameters: 1215 * unit - Device unit number 1216 * mac - input MAC address to search 1217 * vid - input VLAN ID to search 1218 * check_l2_only - only check if the target exist in L2 table. 1219 * l2addr - Pointer to bcm_l2_addr_t structure to receive results 1220 * Returns: 1221 * BCM_E_NONE Success (l2addr filled in) 1222 * BCM_E_PARAM Illegal parameter (NULL pointer) 1223 * BCM_E_INTERNAL Chip access failure 1224 * BCM_E_NOT_FOUND Address not found (l2addr not filled in) 1225 */ 1226 1227 int 1228 _bcm_tr_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid, 1229 int check_l2_only, bcm_l2_addr_t *l2addr) 1230 { 1231 bcm_l2_addr_t l2addr_key; 1232 l2x_entry_t l2x_entry, l2x_lookup; 1233 int l2_hw_index; 1234 int rv; 1235 1236 bcm_l2_addr_t_init(&l2addr_key, mac, vid); 1237 1238 #ifdef BCM_TRIDENT_SUPPORT 1239 if (SOC_IS_TRIDENT(unit) || SOC_IS_KATANAX(unit) || 1240 SOC_IS_TD2_TT2(unit)) { 1241 if (soc_mem_is_valid(unit, MY_STATION_TCAMm) && (!check_l2_only)) { 1242 rv = bcm_td_l2_myStation_get (unit, mac, vid, l2addr); 1243 if (BCM_SUCCESS(rv)) { 1244 return rv; 1245 } 1246 } 1247 } 1248 #endif /* BCM_TRIDENT_SUPPORT */ 1249 1250 BCM_IF_ERROR_RETURN( 1251 _bcm_tr_l2_to_l2x(unit, &l2x_entry, &l2addr_key, TRUE)); 1252 1253 soc_mem_lock(unit, L2Xm); 1254 1255 rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry, 1256 &l2x_lookup, &l2_hw_index); 1257 1258 soc_mem_unlock(unit, L2Xm); 1259 1260 if (check_l2_only) { 1261 return rv; 1262 } 1263 1264 if (SOC_SUCCESS(rv)) { 1265 /* Retrieve the hit bit for TD2/TT2 */ 1266 #ifdef BCM_TRIDENT2_SUPPORT 1267 if (!SOC_IS_TOMAHAWK(unit) && !SOC_IS_APACHE(unit) && 1268 !SOC_IS_TRIDENT3(unit) && 1269 SOC_IS_TD2_TT2(unit)) { 1270 BCM_IF_ERROR_RETURN( 1271 _bcm_th3_l2_hit_retrieve(unit, &l2x_lookup, l2_hw_index)); 1272 } 1273 #endif /* BCM_TRIDENT2_SUPPORT */ 1274 rv = _bcm_tr_l2_from_l2x(unit, l2addr, &l2x_lookup); 1275 } 1276 1277 return rv; 1278 } 1279 1280 int 1281 bcm_tr_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid, 1282 bcm_l2_addr_t *l2addr) 1283 { 1284 return _bcm_tr_l2_addr_get(unit, mac, vid, FALSE, l2addr); 1285 } 1286 1287 #endif 1288 1289 #ifdef BCM_WARM_BOOT_SUPPORT 1290 /* 1291 * Function: 1292 * _bcm_th3_l2_reload_mbi 1293 * Description: 1294 * Load MAC block info from hardware into software data structures 1295 * Parameters: 1296 * unit - StrataSwitch unit number 1297 */ 1298 int 1299 _bcm_th3_l2_reload_mbi(int unit) 1300 { 1301 _bcm_mac_block_info_t *mbi = _mbi_entries[unit]; 1302 l2x_entry_t *l2x_entry, *l2x_table; 1303 mac_block_entry_t mbe; 1304 int index, mb_index, l2x_size; 1305 pbmp_t mb_pbmp; 1306 1307 /* 1308 * Refresh MAC Block information from the hardware tables 1309 */ 1310 1311 for (mb_index = 0; mb_index < _mbi_num[unit]; mb_index++) { 1312 SOC_IF_ERROR_RETURN 1313 (READ_MAC_BLOCKm(unit, MEM_BLOCK_ANY, mb_index, &mbe)); 1314 1315 SOC_PBMP_CLEAR(mb_pbmp); 1316 1317 soc_mem_pbmp_field_set(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf, 1318 &mb_pbmp); 1319 1320 BCM_PBMP_ASSIGN(mbi[mb_index].mb_pbmp, mb_pbmp); 1321 } 1322 1323 if (!SOC_CONTROL(unit)->l2x_group_enable) { 1324 l2x_size = sizeof(l2x_entry_t) * soc_mem_index_count(unit, L2Xm); 1325 l2x_table = soc_cm_salloc(unit, l2x_size, "l2 reload"); 1326 if (l2x_table == NULL) { 1327 return BCM_E_MEMORY; 1328 } 1329 1330 memset((void *)l2x_table, 0, l2x_size); 1331 if (soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY, 1332 soc_mem_index_min(unit, L2Xm), 1333 soc_mem_index_max(unit, L2Xm), 1334 l2x_table) < 0) { 1335 soc_cm_sfree(unit, l2x_table); 1336 return SOC_E_INTERNAL; 1337 } 1338 1339 for (index = soc_mem_index_min(unit, L2Xm); 1340 index <= soc_mem_index_max(unit, L2Xm); index++) { 1341 1342 l2x_entry = soc_mem_table_idx_to_pointer(unit, L2Xm, 1343 l2x_entry_t *, 1344 l2x_table, index); 1345 1346 if (!soc_L2Xm_field32_get(unit, l2x_entry, BASE_VALIDf)) { 1347 continue; 1348 } 1349 1350 mb_index = soc_L2Xm_field32_get(unit, l2x_entry, MAC_BLOCK_INDEXf); 1351 mbi[mb_index].ref_count++; 1352 } 1353 soc_cm_sfree(unit, l2x_table); 1354 } 1355 1356 return BCM_E_NONE; 1357 } 1358 #endif /* BCM_WARM_BOOT_SUPPORT */ 1359 1360 /* 1361 * Function: 1362 * _bcm_th3_l2x_delete_all 1363 * Purpose: 1364 * Clear L2 table by invalidating entries 1365 * Parameters: 1366 * unit - StrataSwitch unit # 1367 * Returns: 1368 * SOC_E_XXX 1369 */ 1370 1371 STATIC int 1372 _bcm_th3_l2x_delete_all(int unit) 1373 { 1374 soc_control_t *soc = SOC_CONTROL(unit); 1375 int copyno; 1376 int index_min, index_max, index, mem_max; 1377 l2_entry_only_single_entry_t *l2x_entry; 1378 int rv = SOC_E_NONE; 1379 int *buffer = NULL; 1380 int mem_size, idx; 1381 int modified; 1382 uint32 key_type; 1383 1384 index_min = soc_mem_index_min(unit, L2Xm); 1385 mem_max = soc_mem_index_max(unit, L2Xm); 1386 mem_size = DEFAULT_L2DELETE_CHUNKS * sizeof(l2_entry_only_single_entry_t); 1387 1388 buffer = soc_cm_salloc(unit, mem_size, "L2_ENTRY_ONLY_SINGLE_delete"); 1389 if (buffer == NULL) { 1390 return SOC_E_MEMORY; 1391 } 1392 1393 /* Lock on aggregate entry */ 1394 soc_mem_lock(unit, L2Xm); 1395 for (idx = index_min; idx < mem_max; idx += DEFAULT_L2DELETE_CHUNKS) { 1396 index_max = idx + DEFAULT_L2DELETE_CHUNKS - 1; 1397 if (index_max > mem_max) { 1398 index_max = mem_max; 1399 } 1400 1401 if ((rv = soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ALL, 1402 idx, index_max, buffer)) < 0 ) { 1403 soc_cm_sfree(unit, buffer); 1404 soc_mem_unlock(unit, L2Xm); 1405 return rv; 1406 } 1407 1408 modified = FALSE; 1409 for (index = 0; index < DEFAULT_L2DELETE_CHUNKS; index++) { 1410 l2x_entry = 1411 soc_mem_table_idx_to_pointer(unit, L2Xm, 1412 l2_entry_only_single_entry_t *, 1413 buffer, index); 1414 if (!soc_L2Xm_field32_get(unit, l2x_entry, BASE_VALIDf)) { 1415 continue; 1416 } 1417 1418 key_type = soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf); 1419 if (key_type == TH3_L2_HASH_KEY_TYPE_BRIDGE) { 1420 sal_memcpy(l2x_entry, soc_mem_entry_null(unit, L2Xm), 1421 sizeof(l2_entry_only_single_entry_t)); 1422 modified = TRUE; 1423 } 1424 } 1425 1426 if (!modified) { 1427 continue; 1428 } 1429 1430 if ((rv = soc_mem_write_range(unit, L2Xm, 1431 MEM_BLOCK_ALL, idx, index_max, buffer)) 1432 < 0) { 1433 soc_cm_sfree(unit, buffer); 1434 soc_mem_unlock(unit, L2Xm); 1435 return rv; 1436 } 1437 } 1438 1439 soc_cm_sfree(unit, buffer); 1440 1441 /* Clear all shadow table entries */ 1442 if (soc->arlShadow != NULL) { 1443 sal_mutex_take(soc->arlShadowMutex, sal_mutex_FOREVER); 1444 (void) shr_avl_delete_all(soc->arlShadow); 1445 sal_mutex_give(soc->arlShadowMutex); 1446 } 1447 1448 /* Free AVL table used for L2 learning */ 1449 if (soc->l2x_lrn_shadow != NULL) { 1450 sal_mutex_take(soc->l2x_lrn_shadow_mutex, sal_mutex_FOREVER); 1451 shr_avl_delete_all(soc->l2x_lrn_shadow); 1452 sal_mutex_give(soc->l2x_lrn_shadow_mutex); 1453 } 1454 1455 copyno = SOC_MEM_BLOCK_ANY(unit, L2Xm); 1456 if (SOC_MEM_BLOCK_VALID(unit, L2Xm, copyno)) { 1457 SOP_MEM_STATE(unit, L2Xm).count[copyno] = 0; 1458 } 1459 1460 soc_mem_unlock(unit, L2Xm); 1461 1462 return rv; 1463 } 1464 1465 1466 1467 /* 1468 * Function: 1469 * bcm_th3_l2_init 1470 * Description: 1471 * Initialize chip-dependent parts of L2 module 1472 * Parameters: 1473 * unit - StrataSwitch unit number 1474 */ 1475 1476 int 1477 bcm_th3_l2_init(int unit) 1478 { 1479 int rv, was_running = FALSE; 1480 uint32 flags; 1481 sal_usecs_t interval = 0; 1482 sal_usecs_t lrn_interval; 1483 int lrn_thread_running = FALSE; 1484 1485 if (soc_l2x_running(unit, &flags, &interval)) { 1486 was_running = TRUE; 1487 BCM_IF_ERROR_RETURN(soc_l2x_stop(unit)); 1488 } 1489 1490 if (soc_th3_l2_learn_thread_running(unit, &lrn_interval)) { 1491 lrn_thread_running = TRUE; 1492 BCM_IF_ERROR_RETURN(soc_th3_l2_learn_thread_stop(unit)); 1493 } 1494 1495 if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) { 1496 1497 if (!(SAL_BOOT_QUICKTURN || 1498 ((SAL_BOOT_SIMULATION || SAL_BOOT_BCMSIM || SAL_BOOT_XGSSIM) && 1499 !SOC_IS_TOMAHAWKX(unit)))) { 1500 _bcm_th3_l2x_delete_all(unit); 1501 } 1502 } 1503 1504 if (_mbi_entries[unit] != NULL) { 1505 sal_free(_mbi_entries[unit]); 1506 _mbi_entries[unit] = NULL; 1507 } 1508 1509 _mbi_num[unit] = (SOC_MEM_INFO(unit, MAC_BLOCKm).index_max - 1510 SOC_MEM_INFO(unit, MAC_BLOCKm).index_min + 1); 1511 _mbi_entries[unit] = sal_alloc(_mbi_num[unit] * 1512 sizeof(_bcm_mac_block_info_t), 1513 "BCM L2X MAC blocking info"); 1514 if (!_mbi_entries[unit]) { 1515 return BCM_E_MEMORY; 1516 } 1517 sal_memset(_mbi_entries[unit], 0, _mbi_num[unit] * sizeof(_bcm_mac_block_info_t)); 1518 1519 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_init(unit)); 1520 1521 #ifdef BCM_WARM_BOOT_SUPPORT 1522 if (SOC_WARM_BOOT(unit)) { 1523 BCM_IF_ERROR_RETURN(_bcm_th3_l2_reload_mbi(unit)); 1524 1525 #if defined(BCM_TRIUMPH_SUPPORT) 1526 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_reload(unit)); 1527 #endif 1528 } 1529 #endif 1530 1531 BCM_IF_ERROR_RETURN(_bcm_l2_match_ctrl_init(unit)); 1532 1533 rv = _bcm_th3_l2_memacc_init(unit); 1534 if (BCM_FAILURE(rv)) { 1535 _bcm_l2_match_ctrl_deinit(unit); 1536 return rv; 1537 } 1538 1539 /* bcm_l2_register clients */ 1540 soc_l2x_register(unit, _bcm_th3_l2_register_callback, NULL); 1541 1542 if (was_running) { 1543 /* Use value saved in soc_control[]. Original code running on 1544 * bcmsim sets it back to default value 1545 * 'interval' should be non-0 if the task was running originally 1546 */ 1547 soc_l2x_start(unit, flags, interval); 1548 } 1549 1550 if (lrn_thread_running) { 1551 /* Use value saved in soc_control[], no point setting it back to 1552 * default value 1553 * 'lrn_interval' should be non-0 if the task was running originally 1554 */ 1555 soc_th3_l2_learn_thread_start(unit, lrn_interval); 1556 } 1557 1558 return BCM_E_NONE; 1559 } 1560 1561 /* 1562 * Function: 1563 * bcm_th3_l2_term 1564 * Description: 1565 * Finalize chip-dependent parts of L2 module 1566 * Parameters: 1567 * unit - StrataSwitch unit number. 1568 */ 1569 1570 int 1571 bcm_th3_l2_term(int unit) 1572 { 1573 if (_mbi_entries[unit] != NULL) { 1574 sal_free(_mbi_entries[unit]); 1575 _mbi_entries[unit] = NULL; 1576 } 1577 1578 BCM_IF_ERROR_RETURN(_bcm_th3_l2_station_control_deinit(unit)); 1579 1580 /* Free resources allocated for match control data */ 1581 _bcm_l2_match_ctrl_deinit(unit); 1582 1583 BCM_IF_ERROR_RETURN(_bcm_th3_l2_memacc_deinit(unit)); 1584 1585 return BCM_E_NONE; 1586 } 1587 1588 STATIC int 1589 _bcm_th3_dual_l2_conflict_get(int unit, bcm_l2_addr_t *addr, 1590 bcm_l2_addr_t *cf_array, int cf_max, 1591 int *cf_count) 1592 { 1593 l2x_entry_t match_entry, entry; 1594 uint32 fval; 1595 int bank, bucket, slot, index; 1596 int num_banks; 1597 int entries_per_bank, entries_per_row, entries_per_bucket; 1598 int bank_base, bucket_offset; 1599 1600 1601 BCM_IF_ERROR_RETURN(soc_tomahawk3_hash_bank_count_get(unit, L2Xm, 1602 &num_banks)); 1603 1604 *cf_count = 0; 1605 1606 BCM_IF_ERROR_RETURN(_bcm_th3_l2_to_l2x(unit, &match_entry, addr, TRUE)); 1607 for (bank = 0; bank < num_banks; bank++) { 1608 1609 BCM_IF_ERROR_RETURN(soc_tomahawk3_hash_bank_info_get(unit, 1610 L2Xm, 1611 bank, 1612 &entries_per_bank, 1613 &entries_per_row, 1614 &entries_per_bucket, 1615 &bank_base, &bucket_offset)); 1616 1617 bucket = soc_tomahawk3_l2x_bank_entry_hash(unit, bank, 1618 (uint32 *)&match_entry); 1619 1620 for (slot = 0; slot < entries_per_bucket; slot++) { 1621 index = bank_base + bucket * entries_per_row + bucket_offset + 1622 slot; 1623 1624 LOG_DEBUG(BSL_LS_BCM_L2, 1625 (BSL_META_U(unit, 1626 "bucket=%d, index=%d) \n"), bucket, index)); 1627 1628 SOC_IF_ERROR_RETURN(soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, index, 1629 &entry)); 1630 1631 if (!soc_L2Xm_field32_get(unit, &entry, BASE_VALIDf)) { 1632 continue; 1633 } 1634 1635 fval = soc_mem_field32_get(unit, L2Xm, &entry, KEY_TYPEf); 1636 1637 if (fval != TH3_L2_HASH_KEY_TYPE_BRIDGE) { 1638 continue; 1639 } 1640 1641 BCM_IF_ERROR_RETURN(_bcm_th3_l2_from_l2x(unit, 1642 &cf_array[*cf_count], 1643 &entry)); 1644 1645 *cf_count += 1; 1646 if (*cf_count >= cf_max) { 1647 return BCM_E_NONE; 1648 } 1649 } 1650 } 1651 1652 COMPILER_REFERENCE(entries_per_bank); 1653 1654 return BCM_E_NONE; 1655 } 1656 1657 int 1658 bcm_th3_l2_conflict_get(int unit, bcm_l2_addr_t *addr, bcm_l2_addr_t *cf_array, 1659 int cf_max, int *cf_count) 1660 { 1661 1662 if (soc_feature(unit, soc_feature_dual_hash)) { 1663 return _bcm_th3_dual_l2_conflict_get(unit, addr, cf_array, 1664 cf_max, cf_count); 1665 } 1666 1667 return BCM_E_UNAVAIL; 1668 } 1669 1670 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 1671 /* 1672 * Function: 1673 * _bcm_th3_l2_sw_dump 1674 * Purpose: 1675 * Displays L2 information maintained by software. 1676 * Parameters: 1677 * unit - Device unit number 1678 * Returns: 1679 * None 1680 */ 1681 void 1682 _bcm_th3_l2_sw_dump(int unit) 1683 { 1684 _bcm_mac_block_info_t *mbi; 1685 char pfmt[SOC_PBMP_FMT_LEN]; 1686 int i; 1687 1688 LOG_CLI((BSL_META_U(unit, 1689 "\n"))); 1690 LOG_CLI((BSL_META_U(unit, 1691 " TR L2 MAC Blocking Info -\n"))); 1692 LOG_CLI((BSL_META_U(unit, 1693 " Number : %d\n"), _mbi_num[unit])); 1694 1695 mbi = _mbi_entries[unit]; 1696 LOG_CLI((BSL_META_U(unit, 1697 " Entries (index: pbmp-count) :\n"))); 1698 if (mbi != NULL) { 1699 for (i = 0; i < _mbi_num[unit]; i++) { 1700 SOC_PBMP_FMT(mbi[i].mb_pbmp, pfmt); 1701 LOG_CLI((BSL_META_U(unit, 1702 " %5d: %s-%d\n"), i, pfmt, mbi[i].ref_count)); 1703 } 1704 } 1705 LOG_CLI((BSL_META_U(unit, 1706 "\n"))); 1707 1708 LOG_CLI((BSL_META_U(unit, 1709 "\n TR L2 PPA bypass - %s\n"), 1710 SOC_CONTROL(unit)->l2x_ppa_bypass ? "TRUE" : "FALSE")); 1711 return; 1712 } 1713 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */ 1714 1715 /* 1716 * Function: 1717 * _bcm_th3_l2_gport_parse 1718 * Description: 1719 * Parse gport in the l2 table 1720 * Parameters: 1721 * unit - [IN] StrataSwitch PCI device unit number (driver internal). 1722 * l2addr - [IN/OUT] l2 addr structure to parse and fill 1723 * sub_port - [OUT] Virtual port group (-1 if not supported) 1724 * mpls_port - [OUT] MPLS port (-1 if not supported) 1725 * Returns: 1726 * BCM_E_XXX 1727 */ 1728 int 1729 _bcm_th3_l2_gport_parse(int unit, bcm_l2_addr_t *l2addr, 1730 _bcm_l2_gport_params_t *params) 1731 { 1732 int id; 1733 bcm_port_t _port; 1734 bcm_trunk_t _trunk; 1735 bcm_module_t _modid, _mymodid; 1736 1737 if ((NULL == l2addr) || (NULL == params)){ 1738 return BCM_E_PARAM; 1739 } 1740 1741 params->param0 = -1; 1742 params->param1 = -1; 1743 params->type = 0; 1744 1745 1746 BCM_IF_ERROR_RETURN( 1747 _bcm_esw_gport_resolve(unit, l2addr->port, &_modid, &_port, 1748 &_trunk, &id)); 1749 1750 _mymodid = 0; 1751 1752 if ((BCM_TRUNK_INVALID != _trunk) && (-1 == id)) { 1753 params->param0 = _trunk; 1754 params->type = _SHR_GPORT_TYPE_TRUNK; 1755 return BCM_E_NONE; 1756 } 1757 1758 if ((-1 != _port) && (-1 == id)) { 1759 params->param0 = _port; 1760 if ((_port == CMIC_PORT(unit)) && (_modid == _mymodid)) { 1761 params->type = _SHR_GPORT_TYPE_LOCAL_CPU; 1762 return BCM_E_NONE; 1763 } 1764 params->param1 = _modid; 1765 params->type = _SHR_GPORT_TYPE_MODPORT; 1766 return BCM_E_NONE; 1767 } 1768 1769 if (-1 != id) { 1770 params->param0 = id; 1771 /* Check if the settings below apply to TH3 L2 */ 1772 if (BCM_GPORT_IS_MPLS_PORT(l2addr->port)){ 1773 params->type = _SHR_GPORT_TYPE_MPLS_PORT; 1774 } else if (BCM_GPORT_IS_VLAN_PORT(l2addr->port)){ 1775 params->type = _SHR_GPORT_TYPE_VLAN_PORT; 1776 } 1777 return BCM_E_NONE; 1778 } else if (BCM_GPORT_IS_BLACK_HOLE(l2addr->port)) { 1779 params->type = _SHR_GPORT_TYPE_BLACK_HOLE; 1780 params->param0 = 0; 1781 params->param1 = id; 1782 1783 return BCM_E_NONE; 1784 } 1785 1786 return BCM_E_PORT; 1787 } 1788 1789 /* 1790 * Function: 1791 * _bcm_th3_l2_to_l2x 1792 * Purpose: 1793 * Convert an L2 API data structure to a Triumph L2X entry 1794 * Parameters: 1795 * unit Unit number 1796 * l2x_entry (OUT) Triumph L2X entry 1797 * l2addr L2 API data structure 1798 * key_only Only construct key portion 1799 */ 1800 int 1801 _bcm_th3_l2_to_l2x(int unit, l2x_entry_t *l2x_entry, bcm_l2_addr_t *l2addr, 1802 int key_only) 1803 { 1804 bcm_cos_t cos_dst = l2addr->cos_dst; 1805 int group = l2addr->group; 1806 1807 if (l2addr->cos_dst < 0 || l2addr->cos_dst > 15) { 1808 return BCM_E_PARAM; 1809 } 1810 1811 /* BCM_L2_MIRROR is not supported starting from Triumph */ 1812 if (l2addr->flags & BCM_L2_MIRROR) { 1813 return BCM_E_PARAM; 1814 } 1815 1816 /* Setting both flags is not a valid configuration. */ 1817 if (l2addr->flags & BCM_L2_LEARN_LIMIT_EXEMPT && 1818 l2addr->flags & BCM_L2_LEARN_LIMIT_EXEMPT_LOCAL) { 1819 return BCM_E_PARAM; 1820 } 1821 1822 sal_memset(l2x_entry, 0, sizeof (*l2x_entry)); 1823 1824 VLAN_CHK_ID(unit, l2addr->vid); 1825 soc_L2Xm_field32_set(unit, l2x_entry, VLAN_IDf, l2addr->vid); 1826 soc_L2Xm_field32_set(unit, l2x_entry, KEY_TYPEf, 1827 TH3_L2_HASH_KEY_TYPE_BRIDGE); 1828 1829 soc_L2Xm_mac_addr_set(unit, l2x_entry, MAC_ADDRf, l2addr->mac); 1830 1831 if (key_only) { 1832 return BCM_E_NONE; 1833 } 1834 1835 if (BCM_MAC_IS_MCAST(l2addr->mac)) { 1836 if (l2addr->l2mc_group < 0) { 1837 return BCM_E_PARAM; 1838 } 1839 1840 if (_BCM_MULTICAST_IS_SET(l2addr->l2mc_group)) { 1841 soc_L2Xm_field32_set(unit, l2x_entry, DESTINATIONf, 1842 _BCM_MULTICAST_ID_GET(l2addr->l2mc_group)); 1843 } else { 1844 soc_L2Xm_field32_set(unit, l2x_entry, L2MC_PTRf, 1845 l2addr->l2mc_group); 1846 } 1847 } else { 1848 bcm_port_t port = -1; 1849 bcm_trunk_t tgid = BCM_TRUNK_INVALID; 1850 bcm_module_t modid = -1; 1851 int gport_id = -1; 1852 1853 if (BCM_GPORT_IS_SET(l2addr->port)) { 1854 _bcm_l2_gport_params_t g_params; 1855 1856 if (BCM_GPORT_IS_BLACK_HOLE(l2addr->port)) { 1857 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 1); 1858 } else { 1859 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 0); 1860 BCM_IF_ERROR_RETURN( 1861 _bcm_th3_l2_gport_parse(unit, l2addr, &g_params)); 1862 1863 switch (g_params.type) { 1864 case _SHR_GPORT_TYPE_TRUNK: 1865 tgid = g_params.param0; 1866 break; 1867 case _SHR_GPORT_TYPE_MODPORT: 1868 port = g_params.param0; 1869 modid = g_params.param1; 1870 break; 1871 case _SHR_GPORT_TYPE_LOCAL_CPU: 1872 port = g_params.param0; 1873 BCM_IF_ERROR_RETURN( 1874 bcm_esw_stk_my_modid_get(unit, &modid)); 1875 break; 1876 case _SHR_GPORT_TYPE_MPLS_PORT: 1877 gport_id = g_params.param0; 1878 break; 1879 case _SHR_GPORT_TYPE_VLAN_PORT: 1880 gport_id = g_params.param0; 1881 break; 1882 default: 1883 return BCM_E_PORT; 1884 } 1885 } 1886 } else if (l2addr->flags & BCM_L2_TRUNK_MEMBER) { 1887 tgid = l2addr->tgid; 1888 } else { 1889 /* Check parameters */ 1890 if (!SOC_MODID_ADDRESSABLE(unit, l2addr->modid)) { 1891 return BCM_E_BADID; 1892 } 1893 modid = l2addr->modid; /* Should be zero */ 1894 if (!SOC_PORT_ADDRESSABLE(unit, l2addr->port)) { 1895 return BCM_E_PORT; 1896 } 1897 port = l2addr->port; 1898 } 1899 1900 /* Setting l2x_entry fields according to parameters */ 1901 if (BCM_TRUNK_INVALID != tgid) { 1902 soc_L2Xm_field32_set(unit, l2x_entry, Tf, 1); 1903 soc_L2Xm_field32_set(unit, l2x_entry, TGIDf, tgid); 1904 soc_L2Xm_field32_set(unit, l2x_entry, DEST_TYPEf, 0x1); 1905 1906 if (l2addr->flags & BCM_L2_REMOTE_TRUNK) { 1907 /* Note REMOTE_TRUNK is not supported. 1908 * Remove this if after top-level check 1909 */ 1910 } 1911 } else if (-1 != port) { 1912 soc_L2Xm_field32_set(unit, l2x_entry, PORT_NUMf, port); 1913 soc_L2Xm_field32_set(unit, l2x_entry, DEST_TYPEf, 0x0); 1914 } else if (-1 != gport_id) { 1915 1916 soc_L2Xm_field32_set(unit, l2x_entry, DESTINATIONf, gport_id); 1917 } 1918 } 1919 1920 if (SOC_L2X_GROUP_ENABLE_GET(unit)) { 1921 if (soc_feature(unit, soc_feature_overlaid_address_class) && 1922 !BCM_L2_PRE_SET(l2addr->flags)) { 1923 if ((l2addr->group > SOC_OVERLAID_ADDR_CLASS_MAX(unit)) || 1924 (l2addr->group < 0)) { 1925 return BCM_E_PARAM; 1926 } 1927 cos_dst = (l2addr->group & 0x3C0) >> 6; 1928 group = l2addr->group & 0x3F; 1929 } 1930 } 1931 1932 if (SOC_CONTROL(unit)->l2x_group_enable) { 1933 soc_L2Xm_field32_set(unit, l2x_entry, CLASS_IDf, group); 1934 } /* else MAC_BLOCK_INDEXf is handled in the add/remove functions below */ 1935 1936 if (l2addr->flags & BCM_L2_SETPRI) { 1937 soc_L2Xm_field32_set(unit, l2x_entry, RPEf, 1); 1938 } 1939 1940 if (!SOC_IS_TRIUMPH3(unit)) { 1941 soc_L2Xm_field32_set(unit, l2x_entry, PRIf, cos_dst); 1942 } 1943 1944 if (l2addr->flags & BCM_L2_COPY_TO_CPU) { 1945 soc_L2Xm_field32_set(unit, l2x_entry, CPUf, 1); 1946 } 1947 1948 if (l2addr->flags & BCM_L2_DISCARD_DST) { 1949 soc_L2Xm_field32_set(unit, l2x_entry, DST_DISCARDf, 1); 1950 } 1951 1952 if (l2addr->flags & BCM_L2_DISCARD_SRC) { 1953 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 1); 1954 } 1955 1956 if (l2addr->flags & BCM_L2_COS_SRC_PRI) { 1957 soc_L2Xm_field32_set(unit, l2x_entry, SCPf, 1); 1958 } 1959 1960 if (l2addr->flags & BCM_L2_PENDING) { 1961 /* Not supported - relevant h/w learn support is absent in TH3 */ 1962 } 1963 1964 if (l2addr->flags & BCM_L2_STATIC) { 1965 soc_L2Xm_field32_set(unit, l2x_entry, STATIC_BITf, 1); 1966 } 1967 1968 soc_L2Xm_field32_set(unit, l2x_entry, BASE_VALIDf, 1); 1969 1970 if ((l2addr->flags & BCM_L2_DES_HIT) || 1971 (l2addr->flags & BCM_L2_HIT)) { 1972 soc_L2Xm_field32_set(unit, l2x_entry, HITDAf, 1); 1973 } 1974 1975 if ((l2addr->flags & BCM_L2_SRC_HIT) || 1976 (l2addr->flags & BCM_L2_HIT)) { 1977 soc_L2Xm_field32_set(unit, l2x_entry, HITSAf, 1); 1978 } 1979 1980 if (SOC_MEM_FIELD_VALID(unit, L2Xm, LOCAL_SAf)) { 1981 if (l2addr->flags & BCM_L2_NATIVE) { 1982 soc_L2Xm_field32_set(unit, l2x_entry, LOCAL_SAf, 1); 1983 } 1984 } 1985 1986 if (l2addr->flags & BCM_L2_LEARN_LIMIT_EXEMPT_LOCAL) { 1987 return BCM_E_PARAM; 1988 } 1989 1990 return BCM_E_NONE; 1991 } 1992 1993 /* 1994 * Function: 1995 * _bcm_th3_l2_from_l2x 1996 * Purpose: 1997 * Convert a L2X entry to an L2 API data structure 1998 * Parameters: 1999 * unit Unit number 2000 * l2addr (OUT) L2 API data structure 2001 * l2x_entry Triumph L2X entry 2002 */ 2003 int 2004 _bcm_th3_l2_from_l2x(int unit, bcm_l2_addr_t *l2addr, l2x_entry_t *l2x_entry) 2005 { 2006 int l2mc_index, mb_index, rval; 2007 soc_memacc_t *memacc; 2008 2009 sal_memset(l2addr, 0, sizeof(*l2addr)); 2010 2011 /* _BCM_L2X_MEMACC_FIELD and related macros defined for TH3(l2_helpers.c) */ 2012 memacc = _BCM_L2X_MEMACC_FIELD(unit, MAC_ADDR_f); 2013 soc_memacc_mac_addr_get(memacc, l2x_entry, l2addr->mac); 2014 2015 l2addr->vid = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, VLAN_ID_f); 2016 2017 if (BCM_MAC_IS_MCAST(l2addr->mac)) { 2018 l2addr->flags |= BCM_L2_MCAST; 2019 l2mc_index = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, L2MC_PTR_f); 2020 2021 l2addr->l2mc_group = l2mc_index; 2022 /* Translate l2mc index */ 2023 BCM_IF_ERROR_RETURN( 2024 bcm_esw_switch_control_get(unit, bcmSwitchL2McIdxRetType, &rval)); 2025 if (rval) { 2026 _BCM_MULTICAST_GROUP_SET(l2addr->l2mc_group, _BCM_MULTICAST_TYPE_L2, 2027 l2addr->l2mc_group); 2028 } 2029 } else { 2030 _bcm_gport_dest_t dest; 2031 int dest_type_is_trunk = 0; 2032 int isGport = 0; 2033 2034 _bcm_gport_dest_t_init(&dest); 2035 #if defined(INCLUDE_L3) 2036 dest_type_is_trunk = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, T_f); 2037 #endif /* INCLUDE_L3 */ 2038 if (dest_type_is_trunk) { 2039 /* Trunk group */ 2040 l2addr->flags |= BCM_L2_TRUNK_MEMBER; 2041 l2addr->tgid = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, TGID_f); 2042 2043 dest.tgid = l2addr->tgid; 2044 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 2045 BCM_IF_ERROR_RETURN( 2046 bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport)); 2047 } else { 2048 bcm_module_t mod_in; 2049 bcm_port_t port_in; 2050 2051 port_in = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, PORT_NUM_f); 2052 mod_in = 0; 2053 2054 l2addr->modid = mod_in; 2055 l2addr->port = port_in; 2056 dest.port = l2addr->port; 2057 dest.modid = l2addr->modid; 2058 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 2059 BCM_IF_ERROR_RETURN( 2060 bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport)); 2061 } 2062 2063 if (isGport) { 2064 2065 BCM_IF_ERROR_RETURN( 2066 _bcm_esw_gport_construct(unit, &dest, &(l2addr->port))); 2067 } 2068 } 2069 2070 if (SOC_CONTROL(unit)->l2x_group_enable) { 2071 l2addr->group = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, 2072 CLASS_ID_f); 2073 } else { 2074 mb_index = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, 2075 MAC_BLOCK_INDEX_f); 2076 if (mb_index) { 2077 BCM_PBMP_ASSIGN(l2addr->block_bitmap, 2078 _mbi_entries[unit][mb_index].mb_pbmp); 2079 } 2080 } 2081 2082 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, RPE_f)) { 2083 l2addr->flags |= BCM_L2_SETPRI; 2084 } 2085 2086 l2addr->cos_dst = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, PRI_f); 2087 l2addr->cos_src = _BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, PRI_f); 2088 2089 if (SOC_CONTROL(unit)->l2x_group_enable) { 2090 if (!BCM_L2_PRE_SET(l2addr->flags)) { 2091 l2addr->group |= (l2addr->cos_dst & 0xF) << 6; 2092 } 2093 } 2094 2095 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, CPU_f)) { 2096 l2addr->flags |= BCM_L2_COPY_TO_CPU; 2097 } 2098 2099 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, DST_DISCARD_f)) { 2100 l2addr->flags |= BCM_L2_DISCARD_DST; 2101 } 2102 2103 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, SRC_DISCARD_f)) { 2104 l2addr->flags |= BCM_L2_DISCARD_SRC; 2105 } 2106 2107 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, SCP_f)) { 2108 l2addr->flags |= BCM_L2_COS_SRC_PRI; 2109 } 2110 2111 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, STATIC_BIT_f)) { 2112 l2addr->flags |= BCM_L2_STATIC; 2113 } 2114 2115 /* No 'pending' support in h/w, so do not set BCM_L2_PENDING */ 2116 2117 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, HITDA_f)) { 2118 l2addr->flags |= BCM_L2_DES_HIT; 2119 l2addr->flags |= BCM_L2_HIT; 2120 } 2121 2122 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, HITSA_f)) { 2123 l2addr->flags |= BCM_L2_SRC_HIT; 2124 l2addr->flags |= BCM_L2_HIT; 2125 } 2126 2127 if (_BCM_L2X_MEMACC_FIELD_VALID(unit, LOCAL_SA_f)) { 2128 if (_BCM_L2X_MEMACC_FIELD32_GET(unit, l2x_entry, LOCAL_SA_f)) { 2129 l2addr->flags |= BCM_L2_NATIVE; 2130 } 2131 } 2132 2133 return BCM_E_NONE; 2134 } 2135 2136 /* 2137 * Function: 2138 * _bcm_th3_l2_addr_get 2139 * Description: 2140 * Given a MAC address and VLAN ID, check if the entry is present 2141 * in the L2 table, and if so, return all associated information 2142 * Parameters: 2143 * unit - Device unit number 2144 * mac - input MAC address to search 2145 * vid - input VLAN ID to search 2146 * check_l2_only - only check if the target exist in L2 table 2147 * l2addr - Pointer to bcm_l2_addr_t structure to receive results 2148 * Returns: 2149 * BCM_E_NONE Success (l2addr filled in) 2150 * BCM_E_PARAM Illegal parameter (NULL pointer) 2151 * BCM_E_INTERNAL Chip access failure 2152 * BCM_E_NOT_FOUND Address not found (l2addr not filled in) 2153 */ 2154 2155 int 2156 _bcm_th3_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid, 2157 int check_l2_only, bcm_l2_addr_t *l2addr) 2158 { 2159 bcm_l2_addr_t l2addr_key; 2160 l2x_entry_t l2x_entry, l2x_lookup; 2161 int l2_hw_index; 2162 int rv; 2163 2164 bcm_l2_addr_t_init(&l2addr_key, mac, vid); 2165 2166 if (!check_l2_only) { 2167 /* Check if function below has all l2 my stn mem fields */ 2168 rv = bcm_td_l2_myStation_get (unit, mac, vid, l2addr); 2169 if (BCM_SUCCESS(rv)) { 2170 return rv; 2171 } 2172 } 2173 2174 BCM_IF_ERROR_RETURN( 2175 _bcm_th3_l2_to_l2x(unit, &l2x_entry, &l2addr_key, TRUE)); 2176 2177 soc_mem_lock(unit, L2Xm); 2178 2179 rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry, 2180 &l2x_lookup, &l2_hw_index); 2181 2182 soc_mem_unlock(unit, L2Xm); 2183 2184 if (check_l2_only) { 2185 return rv; 2186 } 2187 2188 if (SOC_SUCCESS(rv)) { 2189 rv = _bcm_th3_l2_from_l2x(unit, l2addr, &l2x_lookup); 2190 } 2191 2192 return rv; 2193 } 2194 2195 int 2196 bcm_th3_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid, 2197 bcm_l2_addr_t *l2addr) 2198 { 2199 return _bcm_th3_l2_addr_get(unit, mac, vid, FALSE, l2addr); 2200 } 2201 2202 /* 2203 * Function: 2204 * bcm_th3_l2_addr_delete 2205 * Description: 2206 * Delete an L2 address (MAC+VLAN) from the device 2207 * Parameters: 2208 * unit - device unit 2209 * mac - MAC address to delete 2210 * vid - VLAN id 2211 * Returns: 2212 * BCM_E_XXX 2213 */ 2214 int 2215 bcm_th3_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid) 2216 { 2217 bcm_l2_addr_t l2addr; 2218 l2x_entry_t l2x_entry, l2x_lookup; 2219 int l2_index, mb_index; 2220 int rv; 2221 soc_control_t *soc = SOC_CONTROL(unit); 2222 2223 bcm_l2_addr_t_init(&l2addr, mac, vid); 2224 2225 if (BCM_VLAN_VALID(vid)) { 2226 rv = bcm_td_l2_myStation_delete (unit, mac, vid, &l2_index); 2227 if ((rv != BCM_E_NOT_FOUND) && (rv != BCM_E_FULL)) { 2228 if (rv != BCM_E_NONE) { 2229 return rv; 2230 } 2231 } 2232 } 2233 2234 BCM_IF_ERROR_RETURN(_bcm_th3_l2_to_l2x(unit, &l2x_entry, &l2addr, TRUE)); 2235 2236 soc_mem_lock(unit, L2Xm); 2237 2238 rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ANY, &l2_index, 2239 (void *)&l2x_entry, (void *)&l2x_lookup, 0); 2240 if (BCM_E_NONE != rv) { 2241 soc_mem_unlock(unit, L2Xm); 2242 return rv; 2243 } 2244 2245 if (!SOC_CONTROL(unit)->l2x_group_enable) { 2246 mb_index = soc_L2Xm_field32_get(unit, &l2x_lookup, MAC_BLOCK_INDEXf); 2247 _bcm_th3_mac_block_delete(unit, mb_index); 2248 } 2249 2250 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 2251 soc_mem_unlock(unit, L2Xm); 2252 return BCM_E_RESOURCE; 2253 } 2254 rv = soc_mem_delete_return_old(unit, L2Xm, MEM_BLOCK_ANY, 2255 (void *)&l2x_entry, (void *)&l2x_entry); 2256 if (rv >= 0) { 2257 rv = soc_l2x_sync_delete(unit, (uint32 *) &l2x_lookup, l2_index, 0); 2258 } 2259 SOC_L2_DEL_SYNC_UNLOCK(soc); 2260 soc_mem_unlock(unit, L2Xm); 2261 2262 return rv; 2263 } 2264 2265 /* 2266 * Function: 2267 * _bcm_th3_l2_hash_dynamic_replace 2268 * Purpose: 2269 * Replace dynamic L2 entries in a dual hash. 2270 * Parameters: 2271 * unit - Unit number 2272 * l2x_entry - Entry to insert instead of dynamic entry. 2273 * Returns: 2274 * BCM_E_NONE Success 2275 * BCM_E_XXX Error 2276 */ 2277 2278 int _bcm_th3_l2_hash_dynamic_replace(int unit, l2x_entry_t *l2x_entry) 2279 { 2280 l2x_entry_t l2ent; 2281 int rv; 2282 uint32 fval; 2283 bcm_mac_t mac; 2284 int cf_hit, cf_unhit; 2285 int bank, bucket, slot, index; 2286 int num_banks; 2287 int entries_per_bank, entries_per_row, entries_per_bucket; 2288 int bank_base, bucket_offset; 2289 2290 BCM_IF_ERROR_RETURN 2291 (soc_tomahawk3_hash_bank_count_get(unit, L2Xm, &num_banks)); 2292 2293 BCM_IF_ERROR_RETURN(soc_l2x_freeze(unit)); 2294 2295 cf_hit = cf_unhit = -1; 2296 for (bank = 0; bank < num_banks; bank++) { 2297 2298 rv = soc_tomahawk3_hash_bank_info_get(unit, L2Xm, bank, 2299 &entries_per_bank, 2300 &entries_per_row, 2301 &entries_per_bucket, 2302 &bank_base, &bucket_offset); 2303 if (SOC_FAILURE(rv)) { 2304 (void)soc_l2x_thaw(unit); 2305 return rv; 2306 } 2307 2308 bucket = soc_tomahawk3_l2x_bank_entry_hash(unit, bank, (uint32 *)l2x_entry); 2309 2310 for (slot = 0; slot < entries_per_bucket; slot++) { 2311 uint32 valid = 0; 2312 index = bank_base + bucket * entries_per_row + bucket_offset + 2313 slot; 2314 rv = soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, index, &l2ent); 2315 if (SOC_FAILURE(rv)) { 2316 (void)soc_l2x_thaw(unit); 2317 return rv; 2318 } 2319 2320 valid = soc_L2Xm_field32_get(unit, &l2ent, BASE_VALIDf); 2321 2322 if (!valid) { 2323 /* Found invalid entry - stop the search victim found */ 2324 cf_unhit = index; 2325 break; 2326 } 2327 2328 fval = soc_mem_field32_get(unit, L2Xm, &l2ent, KEY_TYPEf); 2329 2330 if (fval != TH3_L2_HASH_KEY_TYPE_BRIDGE) { 2331 continue; 2332 } 2333 2334 soc_L2Xm_mac_addr_get(unit, &l2ent, MAC_ADDRf, mac); 2335 2336 /* Skip static entries */ 2337 if ((soc_L2Xm_field32_get(unit, &l2ent, STATIC_BITf)) || 2338 (BCM_MAC_IS_MCAST(mac))) { 2339 continue; 2340 } 2341 2342 if (soc_L2Xm_field32_get(unit, &l2ent, HITDAf) || 2343 soc_L2Xm_field32_get(unit, &l2ent, HITSAf) ) { 2344 cf_hit = index; 2345 } else { 2346 /* Found unhit entry - stop search victim found */ 2347 cf_unhit = index; 2348 break; 2349 } 2350 } 2351 if (cf_unhit != -1) { 2352 break; 2353 } 2354 } 2355 2356 COMPILER_REFERENCE(entries_per_bank); 2357 2358 if (cf_unhit >= 0) { 2359 index = cf_unhit; /* take last unhit dynamic */ 2360 } else if (cf_hit >= 0) { 2361 index = cf_hit; /* or last hit dynamic */ 2362 } else { 2363 rv = BCM_E_FULL; /* no dynamics to delete */ 2364 (void) soc_l2x_thaw(unit); 2365 return rv; 2366 } 2367 2368 rv = soc_mem_delete_index(unit, L2Xm, MEM_BLOCK_ALL, index); 2369 if (SOC_SUCCESS(rv)) { 2370 rv = soc_mem_generic_insert(unit, L2Xm, MEM_BLOCK_ANY, 0, 2371 l2x_entry, NULL, NULL); 2372 } 2373 if (SOC_FAILURE(rv)) { 2374 (void) soc_l2x_thaw(unit); 2375 return rv; 2376 } 2377 2378 return soc_l2x_thaw(unit); 2379 } 2380 2381 /* 2382 * Function: 2383 * bcm_th3_l2_addr_add 2384 * Description: 2385 * Add a MAC address to the Switch Address Resolution Logic (ARL) 2386 * port with the given VLAN ID and parameters. 2387 * Parameters: 2388 * unit - StrataSwitch PCI device unit number (driver internal). 2389 * l2addr - Pointer to bcm_l2_addr_t containing all valid fields 2390 * Returns: 2391 * BCM_E_NONE Success 2392 * BCM_E_INTERNAL Chip access failure 2393 * BCM_E_RESOURCE No MAC_BLOCK entries available 2394 * Notes: 2395 * Use CMIC_PORT(unit) to associate the entry with the CPU. 2396 * Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU. 2397 * Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be 2398 * passed as well with non-zero trunk group ID) 2399 * In case the L2X table is full (e.g. bucket full), an attempt 2400 * will be made to store the entry in the L2_USER_ENTRY table. 2401 */ 2402 int 2403 bcm_th3_l2_addr_add(int unit, bcm_l2_addr_t *l2addr) 2404 { 2405 l2x_entry_t l2x_entry, l2x_lookup; 2406 int rv, l2_index, mb_index = 0; 2407 2408 if (l2addr->flags & BCM_L2_L3LOOKUP) { 2409 BCM_IF_ERROR_RETURN(bcm_td_l2_myStation_add(unit, l2addr)); 2410 } else { 2411 rv = bcm_td_l2_myStation_delete(unit, l2addr->mac, l2addr->vid, 2412 &l2_index); 2413 if (rv != BCM_E_NONE && rv != BCM_E_NOT_FOUND) { 2414 return rv; 2415 } 2416 } 2417 2418 BCM_IF_ERROR_RETURN(_bcm_th3_l2_to_l2x(unit, &l2x_entry, l2addr, FALSE)); 2419 2420 rv = soc_mem_generic_lookup(unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry, 2421 &l2x_lookup, &l2_index); 2422 if (BCM_FAILURE(rv) && rv != BCM_E_NOT_FOUND) { 2423 return rv; 2424 } 2425 2426 if (!SOC_CONTROL(unit)->l2x_group_enable) { 2427 /* Mac blocking, attempt to associate with bitmap entry */ 2428 BCM_IF_ERROR_RETURN 2429 (_bcm_th3_mac_block_insert(unit, l2addr->block_bitmap, &mb_index)); 2430 soc_mem_field32_set(unit, L2Xm, &l2x_entry, MAC_BLOCK_INDEXf, 2431 mb_index); 2432 } 2433 2434 rv = soc_mem_insert_return_old(unit, L2Xm, MEM_BLOCK_ANY, 2435 (void *)&l2x_entry, NULL); 2436 if ((rv == BCM_E_FULL) && (l2addr->flags & BCM_L2_REPLACE_DYNAMIC)) { 2437 rv = _bcm_th3_l2_hash_dynamic_replace( unit, &l2x_entry); 2438 if (rv < 0 ) { 2439 goto done; 2440 } 2441 } else if (rv == BCM_E_EXISTS) { 2442 if (!SOC_CONTROL(unit)->l2x_group_enable) { 2443 mb_index = soc_mem_field32_get(unit, L2Xm, &l2x_lookup, 2444 MAC_BLOCK_INDEXf); 2445 _bcm_th3_mac_block_delete(unit, mb_index); 2446 } 2447 rv = BCM_E_NONE; 2448 } 2449 2450 done: 2451 if (rv < 0) { 2452 _bcm_th3_mac_block_delete(unit, mb_index); 2453 } 2454 2455 return rv; 2456 } 2457 2458 /* 2459 * Function: 2460 * _bcm_th3_l2_cross_connect_add 2461 * Description: 2462 * Add a VLAN cross connect entry 2463 * Parameters: 2464 * unit - Device unit number 2465 * outer_vlan - Outer vlan ID 2466 * destt - array of 2, specifies the corresponding dst is TGID or Port 2467 * destv - array of 2, TGID or Port corresponding to two gports 2468 * Returns: 2469 * BCM_E_NONE - Success. 2470 * BCM_E_XXX 2471 * Notes: 2472 * All incoming paramaters are assumed to be valid 2473 * and hence no further checks are performed on them 2474 */ 2475 int 2476 _bcm_th3_l2_cross_connect_add( 2477 int unit, bcm_vlan_t outer_vlan, uint8 *destt, int *destv) 2478 { 2479 int rv; 2480 int l2_index; 2481 l2x_entry_t l2x_entry; 2482 l2x_entry_t l2x_lookup; 2483 2484 sal_memset(&l2x_entry, 0, sizeof (l2x_entry)); 2485 2486 soc_L2Xm_field32_set(unit, &l2x_entry, BASE_VALIDf, 1); 2487 soc_L2Xm_field32_set(unit, &l2x_entry, STATIC_BITf, 1); 2488 soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__OVIDf, outer_vlan); 2489 soc_L2Xm_field32_set(unit, &l2x_entry, KEY_TYPEf, 2490 TH3_L2_HASH_KEY_TYPE_SINGLE_CROSS_CONNECT); 2491 2492 /* See if the entry already exists */ 2493 rv = soc_mem_generic_lookup( 2494 unit, L2Xm, MEM_BLOCK_ANY, 0, &l2x_entry, &l2x_lookup, &l2_index); 2495 2496 if ((rv < 0) && (rv != BCM_E_NOT_FOUND)) { 2497 return rv; 2498 } 2499 2500 /* Fill in first port */ 2501 soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DEST_TYPEf, !!destt[0]); 2502 soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DESTINATIONf, destv[0]); 2503 /* Fill in second port */ 2504 soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DEST_TYPE_1f, !!destt[1]); 2505 soc_L2Xm_field32_set(unit, &l2x_entry, VLAN__DESTINATION_1f, destv[1]); 2506 2507 rv = soc_mem_insert_return_old(unit, L2Xm, MEM_BLOCK_ANY, 2508 (void *)&l2x_entry, (void *)&l2x_entry); 2509 if (rv == BCM_E_FULL) { 2510 rv = _bcm_th3_l2_hash_dynamic_replace(unit, &l2x_entry); 2511 } 2512 2513 return rv; 2514 } 2515 2516 #if defined(BCM_WARM_BOOT_SUPPORT) 2517 /* 2518 * Function: 2519 * _bcm_th3_l2_cross_connect_entry_add_all 2520 * Description: 2521 * Walks through the valid cross connect entries 2522 * in L2X and adds the entry in VLAN CC Database. 2523 * Parameters: 2524 * unit - (IN) bcm device. 2525 * Returns: 2526 * BCM_E_NONE - Success. 2527 * BCM_E_XXX 2528 */ 2529 int 2530 _bcm_th3_l2_cross_connect_entry_add_all(int unit) 2531 { 2532 int idx, index; 2533 int index_min, index_max, mem_max; 2534 int rv = SOC_E_NONE; 2535 int *buffer = NULL; 2536 l2x_entry_t *l2x_entry; 2537 bcm_vlan_t outer_vlan; 2538 soc_mem_t mem = L2Xm; 2539 uint8 destt[2]; 2540 int destv[2]; 2541 int l2delete_chunks = DEFAULT_L2DELETE_CHUNKS; 2542 2543 index_min = soc_mem_index_min(unit, mem); 2544 mem_max = soc_mem_index_max(unit, mem); 2545 2546 buffer = soc_cm_salloc( unit, 2547 (l2delete_chunks * sizeof(l2x_entry_t)), 2548 "cross connect traverse"); 2549 if (NULL == buffer) { 2550 return SOC_E_MEMORY; 2551 } 2552 2553 soc_mem_lock(unit, L2Xm); 2554 for (idx = index_min; idx < mem_max; idx += l2delete_chunks) { 2555 index_max = idx + l2delete_chunks - 1; 2556 if ( index_max > mem_max) { 2557 index_max = mem_max; 2558 } 2559 if ((rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ALL, 2560 idx, index_max, buffer)) < 0 ) { 2561 break; 2562 } 2563 for (index = 0; index < l2delete_chunks; index++) { 2564 l2x_entry = 2565 soc_mem_table_idx_to_pointer(unit, mem, 2566 l2x_entry_t *, buffer, index); 2567 if (soc_L2Xm_field32_get(unit, l2x_entry, BASE_VALIDf)) { 2568 if (TH3_L2_HASH_KEY_TYPE_SINGLE_CROSS_CONNECT != 2569 soc_L2Xm_field32_get(unit, l2x_entry, KEY_TYPEf)) { 2570 continue; 2571 } 2572 2573 /* Extract the outer vlan */ 2574 outer_vlan = soc_L2Xm_field32_get(unit, l2x_entry, VLAN__OVIDf); 2575 2576 /* Deduce the first destination */ 2577 destv[0] = 2578 soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DESTINATIONf); 2579 destt[0] = (uint8) 2580 soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DEST_TYPEf); 2581 2582 /* Deduce the second destination */ 2583 destv[1] = 2584 soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DESTINATION_1f); 2585 destt[1] = (uint8) 2586 soc_L2Xm_field32_get(unit, l2x_entry, VLAN__DEST_TYPE_1f); 2587 2588 rv = _bcm_th3_vlan_xconnect_db_entry_add( 2589 unit, outer_vlan, destt, destv); 2590 if (BCM_FAILURE(rv)) { 2591 soc_mem_unlock(unit, L2Xm); 2592 soc_cm_sfree(unit, buffer); 2593 return rv; 2594 } 2595 } 2596 } 2597 } 2598 soc_mem_unlock(unit, L2Xm); 2599 soc_cm_sfree(unit, buffer); 2600 2601 return rv; 2602 } 2603 #endif /* BCM_WARM_BOOT_SUPPORT */ 2604 #endif /* BCM_TOMAHAWK3_SUPPORT */