l2.c (36889B)
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: Firebolt L2 function implementations 9 */ 10 11 #include <soc/defs.h> 12 13 #ifdef BCM_FIREBOLT_SUPPORT 14 15 #include <assert.h> 16 17 #include <sal/core/libc.h> 18 #include <shared/bsl.h> 19 #include <soc/mem.h> 20 #include <soc/debug.h> 21 #include <soc/cm.h> 22 #include <soc/drv.h> 23 #include <soc/register.h> 24 #include <soc/memory.h> 25 #include <soc/hash.h> 26 #include <soc/l2x.h> 27 28 #include <bcm/l2.h> 29 #include <bcm/error.h> 30 31 #include <bcm_int/esw/mbcm.h> 32 #include <bcm_int/esw/firebolt.h> 33 #include <bcm_int/esw/stack.h> 34 #include <bcm_int/common/multicast.h> 35 36 #include <bcm_int/esw_dispatch.h> 37 38 typedef struct _bcm_mac_block_info_s { 39 bcm_pbmp_t mb_pbmp; 40 int ref_count; 41 } _bcm_mac_block_info_t; 42 43 static _bcm_mac_block_info_t *_mbi_entries[BCM_MAX_NUM_UNITS]; 44 static int _mbi_num[BCM_MAX_NUM_UNITS]; 45 46 /* 47 * Function: 48 * _bcm_fb_l2_from_l2x 49 * Purpose: 50 * Convert a Firebolt L2X entry to a hardware-independent L2 entry 51 * Parameters: 52 * unit - Unit number 53 * l2addr - (OUT) Hardware-independent L2 entry 54 * l2x_entry - Firebolt L2X entry 55 */ 56 57 int 58 _bcm_fb_l2_from_l2x(int unit, bcm_l2_addr_t *l2addr, 59 l2x_entry_t *l2x_entry) 60 { 61 int mb_index, rval; 62 63 sal_memset(l2addr, 0, sizeof (*l2addr)); 64 65 /* Valid bit is ignored here; entry is assumed valid */ 66 67 soc_L2_ENTRY_ONLYm_mac_addr_get(unit, l2x_entry, MAC_ADDRf, l2addr->mac); 68 69 l2addr->vid = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, VLAN_IDf); 70 l2addr->cos_dst = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, PRIf); 71 l2addr->cos_src = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, PRIf); 72 73 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, CPUf)) { 74 l2addr->flags |= BCM_L2_COPY_TO_CPU; 75 } 76 77 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, DST_DISCARDf)) { 78 l2addr->flags |= BCM_L2_DISCARD_DST; 79 } 80 81 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, SRC_DISCARDf)) { 82 l2addr->flags |= BCM_L2_DISCARD_SRC; 83 } 84 85 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, SCPf)) { 86 l2addr->flags |= BCM_L2_COS_SRC_PRI; 87 } 88 89 if (BCM_MAC_IS_MCAST(l2addr->mac)) { 90 l2addr->flags |= BCM_L2_MCAST; 91 l2addr->l2mc_group = 92 soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, L2MC_PTRf); 93 94 /* Translate l2mc index */ 95 BCM_IF_ERROR_RETURN( 96 bcm_esw_switch_control_get(unit, bcmSwitchL2McIdxRetType, &rval)); 97 if (rval) { 98 _BCM_MULTICAST_GROUP_SET(l2addr->l2mc_group, _BCM_MULTICAST_TYPE_L2, 99 l2addr->l2mc_group); 100 } 101 } else { 102 _bcm_gport_dest_t dest; 103 int isGport, rv; 104 105 _bcm_gport_dest_t_init(&dest); 106 /* Trunk group */ 107 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, Tf)) { 108 int psc = 0; /* Dummy not used */ 109 l2addr->flags |= BCM_L2_TRUNK_MEMBER; 110 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 111 l2addr->tgid = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, 112 TGIDf); 113 } else if (soc_mem_field_valid(unit, L2_ENTRY_ONLYm, TGID_LOf)) { 114 l2addr->tgid = (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, TGID_LOf)) | 115 (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, TGID_HIf) 116 << BCM_TGID_TRUNK_LO_BITS(unit)); 117 } 118 else { 119 l2addr->tgid = (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, TGIDf)); 120 } 121 bcm_esw_trunk_psc_get(unit, l2addr->tgid, &psc); 122 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, REMOTE_TRUNKf)) { 123 l2addr->flags |= BCM_L2_REMOTE_TRUNK; 124 } 125 dest.tgid = l2addr->tgid; 126 dest.gport_type = _SHR_GPORT_TYPE_TRUNK; 127 } else { 128 bcm_module_t mod_in, mod_out; 129 bcm_port_t port_in, port_out; 130 131 if (soc_feature(unit,soc_feature_trunk_group_overlay)) { 132 port_in = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, 133 PORT_NUMf); 134 } else { 135 port_in = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, 136 PORT_TGIDf); 137 } 138 mod_in = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, MODULE_IDf); 139 BCM_IF_ERROR_RETURN 140 (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 141 mod_in, port_in, &mod_out, &port_out)); 142 l2addr->modid = mod_out; 143 l2addr->port = port_out; 144 145 dest.port = l2addr->port; 146 dest.modid = l2addr->modid; 147 dest.gport_type = _SHR_GPORT_TYPE_MODPORT; 148 } 149 rv = bcm_esw_switch_control_get(unit, bcmSwitchUseGport, &isGport); 150 151 if (BCM_SUCCESS(rv) && isGport) { 152 BCM_IF_ERROR_RETURN( 153 _bcm_esw_gport_construct(unit, &dest, &(l2addr->port))); 154 } 155 } 156 157 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, L3f)) { 158 l2addr->flags |= BCM_L2_L3LOOKUP; 159 } 160 161 if (SOC_CONTROL(unit)->l2x_group_enable) { 162 l2addr->group = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, 163 MAC_BLOCK_INDEXf); 164 } else { 165 mb_index = soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, 166 MAC_BLOCK_INDEXf); 167 if (mb_index) { 168 BCM_PBMP_ASSIGN(l2addr->block_bitmap, 169 _mbi_entries[unit][mb_index].mb_pbmp); 170 } 171 l2addr->group = 0; 172 } 173 174 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, RPEf)) { 175 l2addr->flags |= BCM_L2_SETPRI; 176 } 177 178 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, STATIC_BITf)) { 179 l2addr->flags |= BCM_L2_STATIC; 180 } 181 182 if (soc_L2_ENTRY_ONLYm_field32_get(unit, l2x_entry, MIRRORf)) { 183 l2addr->flags |= BCM_L2_MIRROR; 184 } 185 186 if (soc_L2Xm_field32_get(unit, l2x_entry, HITSAf)) { 187 l2addr->flags |= BCM_L2_SRC_HIT; 188 l2addr->flags |= BCM_L2_HIT; 189 } 190 191 if (soc_L2Xm_field32_get(unit, l2x_entry, HITDAf)) { 192 l2addr->flags |= BCM_L2_DES_HIT; 193 l2addr->flags |= BCM_L2_HIT; 194 } 195 196 return BCM_E_NONE; 197 } 198 199 /* 200 * Function: 201 * _bcm_fb_l2_to_l2x 202 * Purpose: 203 * Convert a hardware-independent L2 entry to a Firebolt L2X entry 204 * Parameters: 205 * unit - Unit number 206 * l2x_entry - (OUT) Firebolt L2X entry 207 * l2addr - Hardware-independent L2 entry 208 */ 209 210 int 211 _bcm_fb_l2_to_l2x(int unit, l2x_entry_t *l2x_entry, bcm_l2_addr_t *l2addr) 212 { 213 VLAN_CHK_ID(unit, l2addr->vid); 214 VLAN_CHK_PRIO(unit, l2addr->cos_dst); 215 if (l2addr->flags & BCM_L2_PENDING) { 216 return BCM_E_PARAM; 217 } 218 219 220 sal_memset(l2x_entry, 0, sizeof (*l2x_entry)); 221 222 soc_L2Xm_field32_set(unit, l2x_entry, VALIDf, 1); 223 soc_L2Xm_mac_addr_set(unit, l2x_entry, MAC_ADDRf, l2addr->mac); 224 soc_L2Xm_field32_set(unit, l2x_entry, VLAN_IDf, l2addr->vid); 225 soc_L2Xm_field32_set(unit, l2x_entry, PRIf, l2addr->cos_dst); 226 227 if (l2addr->flags & BCM_L2_COPY_TO_CPU) { 228 soc_L2Xm_field32_set(unit, l2x_entry, CPUf, 1); 229 } 230 231 if (l2addr->flags & BCM_L2_DISCARD_DST) { 232 soc_L2Xm_field32_set(unit, l2x_entry, DST_DISCARDf, 1); 233 } 234 235 if (l2addr->flags & BCM_L2_DISCARD_SRC) { 236 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 1); 237 } 238 239 if (l2addr->flags & BCM_L2_COS_SRC_PRI) { 240 soc_L2Xm_field32_set(unit, l2x_entry, SCPf, 1); 241 } 242 243 if (l2addr->flags & BCM_L2_REMOTE_TRUNK) { 244 soc_L2Xm_field32_set(unit, l2x_entry, REMOTE_TRUNKf, 1); 245 } 246 247 if (l2addr->flags & BCM_L2_MCAST) { /* if (BCM_MAC_IS_MCAST(l2addr->mac)) { */ 248 if (_BCM_MULTICAST_IS_SET(l2addr->l2mc_group)) { 249 if (_BCM_MULTICAST_IS_L2(l2addr->l2mc_group)) { 250 soc_L2Xm_field32_set(unit, l2x_entry, L2MC_PTRf, 251 _BCM_MULTICAST_ID_GET(l2addr->l2mc_group)); 252 } else { 253 /* No other multicast types in L2 on these devices */ 254 return BCM_E_PARAM; 255 } 256 } else { 257 soc_L2Xm_field32_set(unit, l2x_entry, L2MC_PTRf, 258 l2addr->l2mc_group); 259 } 260 } else { 261 bcm_port_t port = -1; 262 bcm_trunk_t tgid = BCM_TRUNK_INVALID; 263 bcm_module_t modid = -1; 264 265 if (BCM_GPORT_IS_SET(l2addr->port)) { 266 _bcm_l2_gport_params_t g_params; 267 268 if (BCM_GPORT_IS_BLACK_HOLE(l2addr->port)) { 269 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 1); 270 } else { 271 if (!(l2addr->flags & BCM_L2_DISCARD_SRC)) { 272 soc_L2Xm_field32_set(unit, l2x_entry, SRC_DISCARDf, 0); 273 } 274 BCM_IF_ERROR_RETURN( 275 _bcm_esw_l2_gport_parse(unit, l2addr, &g_params)); 276 277 switch (g_params.type) { 278 case _SHR_GPORT_TYPE_TRUNK: 279 tgid = g_params.param0; 280 break; 281 case _SHR_GPORT_TYPE_MODPORT: 282 port = g_params.param0; 283 modid = g_params.param1; 284 break; 285 case _SHR_GPORT_TYPE_LOCAL_CPU: 286 port = g_params.param0; 287 BCM_IF_ERROR_RETURN( 288 bcm_esw_stk_my_modid_get(unit, &modid)); 289 break; 290 default: 291 return BCM_E_PORT; 292 } 293 } 294 } else if (l2addr->flags & BCM_L2_TRUNK_MEMBER) { 295 tgid = l2addr->tgid; 296 297 } else { 298 BCM_IF_ERROR_RETURN( 299 _bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_SET, 300 l2addr->modid, l2addr->port, 301 &modid, &port)); 302 /* Check parameters */ 303 if (!SOC_MODID_ADDRESSABLE(unit, modid)) { 304 return BCM_E_BADID; 305 } 306 if (!SOC_PORT_ADDRESSABLE(unit, port)) { 307 return BCM_E_PORT; 308 } 309 } 310 311 /* Setting l2x_entry fields according to parameters */ 312 if ( BCM_TRUNK_INVALID != tgid) { 313 soc_L2Xm_field32_set(unit, l2x_entry, Tf, 1); 314 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 315 soc_L2Xm_field32_set(unit, l2x_entry, TGIDf, tgid); 316 } else if (soc_mem_field_valid(unit, L2Xm, TGID_LOf)) { 317 soc_L2Xm_field32_set(unit, l2x_entry, TGID_LOf, 318 tgid & BCM_TGID_PORT_TRUNK_MASK(unit)); 319 soc_L2Xm_field32_set(unit, l2x_entry, TGID_HIf, 320 tgid >> BCM_TGID_TRUNK_LO_BITS(unit)); 321 } 322 else { 323 soc_L2Xm_field32_set(unit, l2x_entry, TGIDf, 324 (tgid & BCM_TGID_PORT_TRUNK_MASK(unit))); 325 } 326 /* 327 * Note: RTAG is ignored here. Use bcm_trunk_psc_set to 328 * to set for a given trunk. 329 */ 330 } else if (-1 != port) { 331 soc_L2Xm_field32_set(unit, l2x_entry, MODULE_IDf, modid); 332 if (soc_feature(unit, soc_feature_trunk_group_overlay)) { 333 soc_L2Xm_field32_set(unit, l2x_entry, PORT_NUMf, port); 334 } else { 335 soc_L2Xm_field32_set(unit, l2x_entry, PORT_TGIDf, port); 336 } 337 } 338 } 339 if (l2addr->flags & BCM_L2_L3LOOKUP) { 340 soc_L2Xm_field32_set(unit, l2x_entry, L3f, 1); 341 } 342 343 if (l2addr->flags & BCM_L2_MIRROR) { 344 soc_L2Xm_field32_set(unit, l2x_entry, MIRRORf, 1); 345 } 346 347 if (SOC_CONTROL(unit)->l2x_group_enable) { 348 soc_L2Xm_field32_set(unit, l2x_entry, MAC_BLOCK_INDEXf, l2addr->group); 349 } /* else MAC_BLOCK_INDEXf is handled in the add/remove functions below */ 350 351 if (l2addr->flags & BCM_L2_SETPRI) { 352 soc_L2Xm_field32_set(unit, l2x_entry, RPEf, 1); 353 } 354 355 if (l2addr->flags & BCM_L2_STATIC) { 356 soc_L2Xm_field32_set(unit, l2x_entry, STATIC_BITf, 1); 357 } 358 359 if ((l2addr->flags & BCM_L2_SRC_HIT) || 360 (l2addr->flags & BCM_L2_HIT)) { 361 soc_L2Xm_field32_set(unit, l2x_entry, HITSAf, 1); 362 } 363 364 if ((l2addr->flags & BCM_L2_DES_HIT) || 365 (l2addr->flags & BCM_L2_HIT)){ 366 soc_L2Xm_field32_set(unit, l2x_entry, HITDAf, 1); 367 } 368 369 return BCM_E_NONE; 370 } 371 372 /* 373 * Function: 374 * _bcm_mac_block_insert 375 * Purpose: 376 * Find or create a MAC_BLOCK table entry matching the given bitmap. 377 * Parameters: 378 * unit - Unit number 379 * mb_pbmp - egress port bitmap for source MAC blocking 380 * mb_index - (OUT) Index of MAC_BLOCK table with bitmap. 381 * Returns: 382 * BCM_E_NONE Success 383 * BCM_E_INTERNAL Chip access failure 384 * BCM_E_RESOURCE No more MAC_BLOCK entries available 385 * BCM_E_PARAM Bad bitmap supplied 386 */ 387 static int 388 _bcm_mac_block_insert(int unit, bcm_pbmp_t mb_pbmp, int *mb_index) 389 { 390 int cur_index = 0; 391 _bcm_mac_block_info_t *mbi = _mbi_entries[unit]; 392 mac_block_entry_t mbe; 393 bcm_pbmp_t temp_pbmp; 394 395 /* Check for reasonable pbmp */ 396 BCM_PBMP_ASSIGN(temp_pbmp, mb_pbmp); 397 BCM_PBMP_AND(temp_pbmp, PBMP_ALL(unit)); 398 if (BCM_PBMP_NEQ(mb_pbmp, temp_pbmp)) { 399 return BCM_E_PARAM; 400 } 401 402 for (cur_index = 0; cur_index < _mbi_num[unit]; cur_index++) { 403 if (BCM_PBMP_EQ(mbi[cur_index].mb_pbmp, mb_pbmp)) { 404 mbi[cur_index].ref_count++; 405 *mb_index = cur_index; 406 return BCM_E_NONE; 407 } 408 } 409 410 /* Not in table already, see if any space free */ 411 for (cur_index = 1; cur_index < _mbi_num[unit]; cur_index++) { 412 if (mbi[cur_index].ref_count == 0) { 413 /* Attempt insert */ 414 sal_memset(&mbe, 0, sizeof(mac_block_entry_t)); 415 soc_mem_pbmp_field_set(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf, 416 &mb_pbmp); 417 SOC_IF_ERROR_RETURN(WRITE_MAC_BLOCKm(unit, MEM_BLOCK_ALL, 418 cur_index, &mbe)); 419 mbi[cur_index].ref_count++; 420 BCM_PBMP_ASSIGN(mbi[cur_index].mb_pbmp, mb_pbmp); 421 *mb_index = cur_index; 422 return BCM_E_NONE; 423 } 424 } 425 426 /* Didn't find a free slot, out of table space */ 427 return BCM_E_RESOURCE; 428 } 429 430 /* 431 * Function: 432 * _bcm_mac_block_delete 433 * Purpose: 434 * Remove reference to MAC_BLOCK table entry matching the given bitmap. 435 * Parameters: 436 * unit - Unit number 437 * mb_index - Index of MAC_BLOCK table with bitmap. 438 */ 439 static void 440 _bcm_mac_block_delete(int unit, int mb_index) 441 { 442 if (_mbi_entries[unit][mb_index].ref_count > 0) { 443 _mbi_entries[unit][mb_index].ref_count--; 444 } else if (mb_index) { 445 446 /* Someone reran init without flushing the L2 table */ 447 } /* else mb_index = 0, as expected for learning */ 448 } 449 450 /* 451 * Function: 452 * bcm_fb_l2_addr_add 453 * Description: 454 * Add a MAC address to the Switch Address Resolution Logic (ARL) 455 * port with the given VLAN ID and parameters. 456 * Parameters: 457 * unit - StrataSwitch PCI device unit number (driver internal). 458 * l2addr - Pointer to bcm_l2_addr_t containing all valid fields 459 * Returns: 460 * BCM_E_NONE Success 461 * BCM_E_INTERNAL Chip access failure 462 * BCM_E_RESOURCE No MAC_BLOCK entries available 463 * Notes: 464 * Use CMIC_PORT(unit) to associate the entry with the CPU. 465 * Use flag of BCM_L2_COPY_TO_CPU to send a copy to the CPU. 466 * Use flag of BCM_L2_TRUNK_MEMBER to set trunking (TGID must be 467 * passed as well with non-zero trunk group ID) 468 * In case the L2X table is full (e.g. bucket full), an attempt 469 * will be made to store the entry in the L2_USER_ENTRY table. 470 */ 471 472 int 473 bcm_fb_l2_addr_add(int unit, bcm_l2_addr_t *l2addr) 474 { 475 l2x_entry_t l2x_entry, l2ent; 476 int rv, hash_select, bucket, slot; 477 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) 478 int hash_select2, bucket2 = -1; 479 #endif 480 l2x_entry_t l2x_lookup; 481 int l2_index, mb_index = 0; 482 uint8 key[XGS_HASH_KEY_SIZE]; 483 uint32 hash_control; 484 int cf_hit, cf_unhit; 485 bcm_mac_t mac; 486 487 488 if (l2addr->flags & BCM_L2_TRUNK_MEMBER) 489 { 490 BCM_IF_ERROR_RETURN( 491 _bcm_trunk_id_validate(unit, l2addr->tgid)); 492 } 493 494 BCM_IF_ERROR_RETURN( 495 _bcm_fb_l2_to_l2x(unit, &l2x_entry, l2addr)); 496 497 rv = soc_fb_l2x_lookup(unit, &l2x_entry, &l2x_lookup, &l2_index); 498 if (rv < 0) { 499 if (rv != BCM_E_NOT_FOUND) { 500 return rv; 501 } 502 } 503 504 if (SOC_CONTROL(unit)->l2x_group_enable) { 505 /* Using MAC_BLOCK_INDEX field for storing the L2 group */ 506 soc_L2Xm_field32_set(unit, &l2x_entry, MAC_BLOCK_INDEXf, 507 l2addr->group); 508 } else { 509 if (rv == BCM_E_NONE) { 510 /* Only here if L2 entry was found */ 511 mb_index = soc_L2Xm_field32_get(unit, &l2x_lookup, MAC_BLOCK_INDEXf); 512 _bcm_mac_block_delete(unit, mb_index); 513 } 514 /* Mac blocking, attempt to associate with bitmap entry */ 515 BCM_IF_ERROR_RETURN( 516 _bcm_mac_block_insert(unit, l2addr->block_bitmap, &mb_index)); 517 518 soc_L2Xm_field32_set(unit, &l2x_entry, MAC_BLOCK_INDEXf, mb_index); 519 } 520 521 rv = soc_fb_l2x_insert(unit, &l2x_entry); 522 if ((rv == BCM_E_FULL) && (l2addr->flags & BCM_L2_REPLACE_DYNAMIC)) { 523 rv = READ_HASH_CONTROLr(unit, &hash_control); 524 if (rv < 0 ) { 525 goto done; 526 } 527 hash_select = soc_reg_field_get(unit, HASH_CONTROLr, hash_control, 528 L2_AND_VLAN_MAC_HASH_SELECTf); 529 530 soc_draco_l2x_param_to_key(l2addr->mac, l2addr->vid, key); 531 bucket = soc_fb_l2_hash(unit, hash_select, key); 532 533 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) 534 if (soc_feature(unit, soc_feature_dual_hash)) { 535 rv = READ_L2_AUX_HASH_CONTROLr(unit, &hash_control); 536 if (rv < 0 ) { 537 goto done; 538 } 539 if (soc_reg_field_get(unit, L2_AUX_HASH_CONTROLr, 540 hash_control, ENABLEf)) { 541 hash_select2 = soc_reg_field_get(unit, L2_AUX_HASH_CONTROLr, 542 hash_control, HASH_SELECTf); 543 } else { 544 hash_select2 = hash_select; 545 } 546 bucket2 = soc_fb_l2_hash(unit, hash_select2, key); 547 } 548 #endif 549 550 rv = soc_l2x_freeze(unit); 551 if (rv < 0) { 552 goto done; 553 } 554 555 cf_hit = cf_unhit = -1; 556 for (slot = 0; slot < SOC_L2X_BUCKET_SIZE; slot++) { 557 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) 558 if ((bucket2 >=0) && (slot == (SOC_L2X_BUCKET_SIZE/2))) { 559 bucket = bucket2; 560 } 561 #endif 562 l2_index = bucket * SOC_L2X_BUCKET_SIZE + slot; 563 rv = soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, l2_index, &l2ent); 564 if ((rv < 0)) { 565 (void) soc_l2x_thaw(unit); 566 goto done; 567 } 568 569 if (!soc_L2Xm_field32_get(unit, &l2ent, VALIDf)) { 570 /* Found invalid entry - stop the search victim found */ 571 cf_unhit = l2_index; 572 break; 573 } else { 574 575 soc_L2Xm_mac_addr_get(unit, &l2ent, MAC_ADDRf, mac); 576 /* Skip static entries */ 577 if ((soc_L2Xm_field32_get(unit, &l2ent, STATIC_BITf)) || 578 (BCM_MAC_IS_MCAST(mac)) || 579 (soc_L2Xm_field32_get(unit, &l2ent, L3f))) { 580 continue; 581 } 582 if (soc_L2Xm_field32_get(unit, &l2ent, HITDAf) || 583 soc_L2Xm_field32_get(unit, &l2ent, HITSAf) ) { 584 cf_hit = l2_index; 585 } else { 586 /* Found unhit entry - stop search victim found */ 587 cf_unhit = l2_index; 588 break; 589 } 590 } 591 } 592 593 if (cf_unhit >= 0) { 594 l2_index = cf_unhit; /* take last unhit dynamic */ 595 } else if (cf_hit >= 0) { 596 l2_index = cf_hit; /* or last hit dynamic */ 597 } else { 598 rv = BCM_E_FULL; /* no dynamics to delete */ 599 (void) soc_l2x_thaw(unit); 600 goto done; 601 } 602 603 soc_mem_write(unit, L2Xm, MEM_BLOCK_ALL, l2_index, &l2x_entry); 604 rv = soc_l2x_thaw(unit); 605 } 606 607 done: 608 if (rv < 0) { 609 _bcm_mac_block_delete(unit, mb_index); 610 } 611 612 return rv; 613 } 614 615 /* 616 * Function: 617 * bcm_fb_l2_addr_delete 618 * Description: 619 * Delete an L2 address (MAC+VLAN) from the device 620 * Parameters: 621 * unit - device unit 622 * mac - MAC address to delete 623 * vid - VLAN id 624 * Returns: 625 * BCM_E_XXX 626 */ 627 int 628 bcm_fb_l2_addr_delete(int unit, bcm_mac_t mac, bcm_vlan_t vid) 629 { 630 bcm_l2_addr_t l2addr; 631 l2x_entry_t l2x_entry, l2x_lookup; 632 int l2_index, mb_index; 633 int rv; 634 soc_control_t *soc = SOC_CONTROL(unit); 635 636 bcm_l2_addr_t_init(&l2addr, mac, vid); 637 638 BCM_IF_ERROR_RETURN( 639 _bcm_fb_l2_to_l2x(unit, &l2x_entry, &l2addr)); 640 641 soc_mem_lock(unit, L2Xm); 642 rv = soc_fb_l2x_lookup(unit, &l2x_entry, &l2x_lookup, &l2_index); 643 if (BCM_E_NONE != rv) { 644 soc_mem_unlock(unit, L2Xm); 645 return rv; 646 } 647 648 if (!SOC_CONTROL(unit)->l2x_group_enable) { 649 mb_index = soc_L2Xm_field32_get(unit, &l2x_lookup, MAC_BLOCK_INDEXf); 650 _bcm_mac_block_delete(unit, mb_index); 651 } 652 653 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 654 soc_mem_unlock(unit, L2Xm); 655 return BCM_E_RESOURCE; 656 } 657 if ((rv = soc_fb_l2x_delete(unit, &l2x_entry)) >= 0) { 658 rv = soc_l2x_sync_delete(unit, (uint32 *) &l2x_lookup, l2_index, 0); 659 } 660 SOC_L2_DEL_SYNC_UNLOCK(soc); 661 soc_mem_unlock(unit, L2Xm); 662 663 return rv; 664 } 665 666 /* 667 * Function: 668 * bcm_fb_l2_addr_get 669 * Description: 670 * Given a MAC address and VLAN ID, check if the entry is present 671 * in the L2 table, and if so, return all associated information. 672 * Parameters: 673 * unit - Device unit number 674 * mac - input MAC address to search 675 * vid - input VLAN ID to search 676 * l2addr - Pointer to bcm_l2_addr_t structure to receive results 677 * Returns: 678 * BCM_E_NONE Success (l2addr filled in) 679 * BCM_E_PARAM Illegal parameter (NULL pointer) 680 * BCM_E_INTERNAL Chip access failure 681 * BCM_E_NOT_FOUND Address not found (l2addr not filled in) 682 */ 683 684 int 685 bcm_fb_l2_addr_get(int unit, sal_mac_addr_t mac, bcm_vlan_t vid, 686 bcm_l2_addr_t *l2addr) 687 { 688 l2x_entry_t l2fb_search, l2fb_entry; 689 int index, rv; 690 691 VLAN_CHK_ID(unit, vid); 692 693 /* Set up entry for query */ 694 sal_memset(&l2fb_search, 0, sizeof(l2fb_search)); 695 sal_memset(&l2fb_entry, 0, sizeof(l2fb_entry)); 696 soc_L2Xm_mac_addr_set(unit, &l2fb_search, MAC_ADDRf, mac); 697 soc_L2Xm_field32_set(unit, &l2fb_search, VLAN_IDf, vid); 698 699 rv = soc_mem_search(unit, L2Xm, MEM_BLOCK_ANY, &index, 700 &l2fb_search, &l2fb_entry, 0); 701 702 if (rv == SOC_E_NONE) { 703 BCM_IF_ERROR_RETURN(_bcm_fb_l2_from_l2x(unit, l2addr, &l2fb_entry)); 704 return BCM_E_NONE; 705 } 706 707 return rv; 708 } 709 710 /* 711 * Function: 712 * _bcm_fb_l2_reload_mbi 713 * Description: 714 * Load MAC block info from hardware into software data structures. 715 * Parameters: 716 * unit - StrataSwitch unit number. 717 */ 718 719 STATIC int 720 _bcm_fb_l2_reload_mbi(int unit) 721 { 722 #ifdef BCM_WARM_BOOT_SUPPORT 723 _bcm_mac_block_info_t *mbi = _mbi_entries[unit]; 724 l2x_entry_t *l2x_entry, *l2x_table; 725 mac_block_entry_t mbe; 726 int index, mb_index, l2x_size; 727 728 /* 729 * Refresh MAC Block information from the hardware tables. 730 */ 731 732 for (mb_index = 0; mb_index < _mbi_num[unit]; mb_index++) { 733 SOC_IF_ERROR_RETURN 734 (READ_MAC_BLOCKm(unit, MEM_BLOCK_ANY, mb_index, &mbe)); 735 soc_mem_pbmp_field_get(unit, MAC_BLOCKm, &mbe, MAC_BLOCK_MASKf, 736 &mbi[mb_index].mb_pbmp); 737 } 738 739 if (!SOC_CONTROL(unit)->l2x_group_enable) { 740 l2x_size = sizeof(l2x_entry_t) * soc_mem_index_count(unit, L2Xm); 741 l2x_table = soc_cm_salloc(unit, l2x_size, "l2 reload"); 742 if (l2x_table == NULL) { 743 return BCM_E_MEMORY; 744 } 745 746 memset((void *)l2x_table, 0, l2x_size); 747 if (soc_mem_read_range(unit, L2Xm, MEM_BLOCK_ANY, 748 soc_mem_index_min(unit, L2Xm), 749 soc_mem_index_max(unit, L2Xm), 750 l2x_table) < 0) { 751 soc_cm_sfree(unit, l2x_table); 752 return SOC_E_INTERNAL; 753 } 754 755 for (index = soc_mem_index_min(unit, L2Xm); 756 index <= soc_mem_index_max(unit, L2Xm); index++) { 757 758 l2x_entry = soc_mem_table_idx_to_pointer(unit, L2Xm, 759 l2x_entry_t *, 760 l2x_table, index); 761 if (!soc_L2Xm_field32_get(unit, l2x_entry, VALIDf)) { 762 continue; 763 } 764 765 mb_index = soc_L2Xm_field32_get(unit, l2x_entry, MAC_BLOCK_INDEXf); 766 mbi[mb_index].ref_count++; 767 } 768 soc_cm_sfree(unit, l2x_table); 769 } /* Else, MAC Block table is used for L2 group instead, so no reload */ 770 771 return BCM_E_NONE; 772 #else 773 return BCM_E_UNAVAIL; 774 #endif /* BCM_WARM_BOOT_SUPPORT */ 775 } 776 777 /* 778 * Function: 779 * bcm_fb_l2_init 780 * Description: 781 * Initialize chip-dependent parts of L2 module 782 * Parameters: 783 * unit - StrataSwitch unit number. 784 */ 785 786 int 787 bcm_fb_l2_init(int unit) 788 { 789 int was_running = FALSE; 790 uint32 flags; 791 sal_usecs_t interval; 792 793 if (soc_l2x_running(unit, &flags, &interval)) { 794 was_running = TRUE; 795 BCM_IF_ERROR_RETURN(soc_l2x_stop(unit)); 796 } 797 798 if (!SOC_WARM_BOOT(unit) && !SOC_IS_RCPU_ONLY(unit)) { 799 if (!SAL_BOOT_SIMULATION || SAL_BOOT_BCMSIM) { 800 soc_fb_l2x_delete_all(unit); 801 } 802 } 803 804 if (_mbi_entries[unit] != NULL) { 805 sal_free(_mbi_entries[unit]); 806 _mbi_entries[unit] = NULL; 807 } 808 809 _mbi_num[unit] = (SOC_MEM_INFO(unit, MAC_BLOCKm).index_max - 810 SOC_MEM_INFO(unit, MAC_BLOCKm).index_min + 1); 811 _mbi_entries[unit] = sal_alloc(_mbi_num[unit] * 812 sizeof(_bcm_mac_block_info_t), 813 "BCM L2X MAC blocking info"); 814 if (!_mbi_entries[unit]) { 815 return BCM_E_MEMORY; 816 } 817 818 sal_memset(_mbi_entries[unit], 0, 819 _mbi_num[unit] * sizeof(_bcm_mac_block_info_t)); 820 821 if (SOC_WARM_BOOT(unit)) { 822 BCM_IF_ERROR_RETURN(_bcm_fb_l2_reload_mbi(unit)); 823 } 824 825 /* bcm_l2_register clients */ 826 827 soc_l2x_register(unit, 828 _bcm_l2_register_callback, 829 NULL); 830 831 if (was_running || SAL_BOOT_BCMSIM) { 832 interval = (SAL_BOOT_BCMSIM)? BCMSIM_L2XMSG_INTERVAL : interval; 833 soc_l2x_start(unit, flags, interval); 834 } 835 836 return BCM_E_NONE; 837 } 838 839 /* 840 * Function: 841 * bcm_fb_l2_term 842 * Description: 843 * Finalize chip-dependent parts of L2 module 844 * Parameters: 845 * unit - StrataSwitch unit number. 846 */ 847 848 int 849 bcm_fb_l2_term(int unit) 850 { 851 if (_mbi_entries[unit] != NULL) { 852 sal_free(_mbi_entries[unit]); 853 _mbi_entries[unit] = NULL; 854 } 855 856 return BCM_E_NONE; 857 } 858 859 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) 860 int 861 _bcm_dual_l2_conflict_get(int unit, bcm_l2_addr_t *addr, 862 bcm_l2_addr_t *cf_array, int cf_max, 863 int *cf_count) 864 { 865 l2x_entry_t l2ent; 866 uint8 key[XGS_HASH_KEY_SIZE]; 867 int hash_select, bucket, bucket_chunk, slot, bank; 868 869 *cf_count = 0; 870 871 for (bank = 0; bank < 2; bank++) { 872 /* Get L2 hash select */ 873 SOC_IF_ERROR_RETURN 874 (soc_fb_l2x_entry_bank_hash_sel_get(unit, bank, &hash_select)); 875 soc_draco_l2x_param_to_key(addr->mac, addr->vid, key); 876 bucket = soc_fb_l2_hash(unit, hash_select, key); 877 878 bucket_chunk = SOC_L2X_BUCKET_SIZE / 2; 879 880 for (slot = bucket_chunk * bank; 881 (slot < (bucket_chunk * (bank + 1))) && (*cf_count < cf_max); 882 slot++) { 883 SOC_IF_ERROR_RETURN 884 (soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, 885 bucket * SOC_L2X_BUCKET_SIZE + slot, 886 &l2ent)); 887 if (soc_L2Xm_field32_get(unit, &l2ent, VALIDf)) { 888 BCM_IF_ERROR_RETURN 889 (_bcm_fb_l2_from_l2x(unit, &cf_array[*cf_count], &l2ent)); 890 *cf_count += 1; 891 } 892 } 893 } 894 895 return BCM_E_NONE; 896 } 897 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT */ 898 899 int 900 bcm_fb_l2_conflict_get(int unit, bcm_l2_addr_t *addr, 901 bcm_l2_addr_t *cf_array, int cf_max, 902 int *cf_count) 903 { 904 l2x_entry_t l2ent; 905 uint8 key[XGS_HASH_KEY_SIZE]; 906 int hash_select, bucket, slot; 907 uint32 hash_control; 908 909 #if defined(BCM_FIREBOLT2_SUPPORT) || defined(BCM_RAVEN_SUPPORT) 910 if (soc_feature(unit, soc_feature_dual_hash)) { 911 return _bcm_dual_l2_conflict_get(unit, addr, cf_array, 912 cf_max, cf_count); 913 } 914 #endif /* BCM_FIREBOLT2_SUPPORT || BCM_RAVEN_SUPPORT */ 915 916 *cf_count = 0; 917 918 /* Get L2 hash select */ 919 SOC_IF_ERROR_RETURN(READ_HASH_CONTROLr(unit, &hash_control)); 920 hash_select = soc_reg_field_get(unit, HASH_CONTROLr, hash_control, 921 L2_AND_VLAN_MAC_HASH_SELECTf); 922 soc_draco_l2x_param_to_key(addr->mac, addr->vid, key); 923 bucket = soc_fb_l2_hash(unit, hash_select, key); 924 925 for (slot = 0; 926 slot < SOC_L2X_BUCKET_SIZE && *cf_count < cf_max; 927 slot++) { 928 SOC_IF_ERROR_RETURN 929 (soc_mem_read(unit, L2Xm, MEM_BLOCK_ANY, 930 bucket * SOC_L2X_BUCKET_SIZE + slot, 931 &l2ent)); 932 if (soc_L2Xm_field32_get(unit, &l2ent, VALIDf)) { 933 BCM_IF_ERROR_RETURN 934 (_bcm_fb_l2_from_l2x(unit, &cf_array[*cf_count], &l2ent)); 935 *cf_count += 1; 936 } 937 } 938 939 return BCM_E_NONE; 940 } 941 942 /* 943 * Function: 944 * _bcm_fb_age_reg_config 945 * Description: 946 * Helper function to _bcm_fb_l2_addr_replace_by_XXX functions to 947 * configure PER_PORT_AGE_CONTROL register for Firebolt 948 * Parameters: 949 * unit device number 950 * flags flags BCM_L2_REPLACE_* 951 * rep_st structure with information of what to replace 952 * Return: 953 * BCM_E_XXX 954 */ 955 STATIC int 956 _bcm_fb_age_reg_config(int unit, uint32 flags, _bcm_l2_replace_t *rep_st) 957 { 958 uint32 age_val = 0, op, match_mod, match_port; 959 uint32 sync_op, soc_flags; 960 soc_control_t *soc = SOC_CONTROL(unit); 961 int rv; 962 963 BCM_IF_ERROR_RETURN( 964 _bcm_get_op_from_flags(flags, &op, &sync_op)); 965 966 if (rep_st->match_dest.trunk != -1) { 967 match_mod = BCM_TRUNK_TO_MODIDf(unit, rep_st->match_dest.trunk); 968 match_port = BCM_TRUNK_TO_TGIDf(unit, rep_st->match_dest.trunk); 969 if (sync_op == SOC_L2X_PORTMOD_DEL) { 970 sync_op = SOC_L2X_TRUNK_DEL; 971 } 972 } else { 973 match_mod = rep_st->match_dest.module; 974 match_port = rep_st->match_dest.port; 975 } 976 977 soc_reg_field_set(unit, PER_PORT_AGE_CONTROLr, &age_val, 978 EXCL_STATICf, 979 (flags & BCM_L2_REPLACE_MATCH_STATIC) ? 0 : 1); 980 soc_reg_field_set(unit, PER_PORT_AGE_CONTROLr, &age_val, 981 PPA_MODEf, op); 982 soc_reg_field_set(unit, PER_PORT_AGE_CONTROLr, &age_val, 983 VLAN_IDf, rep_st->key_vlan); 984 soc_reg_field_set(unit, PER_PORT_AGE_CONTROLr, &age_val, 985 MODULE_IDf, match_mod); 986 soc_reg_field_set(unit, PER_PORT_AGE_CONTROLr, &age_val, 987 TGID_PORTf, match_port); 988 BCM_IF_ERROR_RETURN(WRITE_PER_PORT_AGE_CONTROLr(unit, age_val)); 989 990 /* OK not to lock L2Xm before since it is locked by upper layer */ 991 if (SOC_L2_DEL_SYNC_LOCK(soc) < 0) { 992 return BCM_E_RESOURCE; 993 } 994 rv = soc_l2x_port_age(unit, PER_PORT_AGE_CONTROLr, INVALIDr); 995 if (BCM_FAILURE(rv)) { 996 SOC_L2_DEL_SYNC_UNLOCK(soc); 997 return rv; 998 } 999 if ((flags & BCM_L2_REPLACE_DELETE)) { 1000 soc_flags = (flags & BCM_L2_REPLACE_MATCH_STATIC) ? SOC_L2X_INC_STATIC : 0; 1001 if (flags & BCM_L2_REPLACE_NO_CALLBACKS) { 1002 soc_flags |= SOC_L2X_NO_CALLBACKS; 1003 } 1004 rv = _soc_l2x_sync_delete_by(unit, rep_st->match_dest.module, 1005 rep_st->match_dest.port, 1006 rep_st->key_vlan, 1007 rep_st->match_dest.trunk, 0, 1008 soc_flags, sync_op); 1009 } 1010 SOC_L2_DEL_SYNC_UNLOCK(soc); 1011 return rv; 1012 } 1013 1014 /* 1015 * Function: 1016 * _bcm_fb_repl_reg_config 1017 * Description: 1018 * Helper function to _bcm_fb_l2_addr_replace_by_XXX functions to 1019 * configure PER_PORT_REPL_CONTROL register for Firebolt 1020 * Parameters: 1021 * unit device number 1022 * flags flags BCM_L2_REPLACE_* 1023 * rep_st structure with information of what to replace 1024 * Return: 1025 * BCM_E_XXX 1026 */ 1027 STATIC int 1028 _bcm_fb_repl_reg_config(int unit, _bcm_l2_replace_t *rep_st) 1029 { 1030 uint32 repl_val = 0, mod_val, port_val; 1031 1032 if (rep_st->new_dest.trunk != -1) { 1033 mod_val = BCM_TRUNK_TO_MODIDf(unit, rep_st->new_dest.trunk); 1034 port_val = BCM_TRUNK_TO_TGIDf(unit, rep_st->new_dest.trunk); 1035 } else { 1036 mod_val = rep_st->new_dest.module; 1037 port_val = rep_st->new_dest.port; 1038 } 1039 soc_reg_field_set(unit, PER_PORT_REPL_CONTROLr, &repl_val, 1040 MODULE_IDf, mod_val); 1041 soc_reg_field_set(unit, PER_PORT_REPL_CONTROLr, &repl_val, 1042 PORT_TGIDf, port_val); 1043 SOC_IF_ERROR_RETURN(WRITE_PER_PORT_REPL_CONTROLr(unit, repl_val)); 1044 1045 return BCM_E_NONE; 1046 } 1047 1048 /* 1049 * Function: 1050 * _bcm_fb_l2_addr_replace_by_vlan 1051 * Description: 1052 * Helper function to _bcm_l2_addr_replace_by_vlan API to replace l2 entries 1053 * by vlan for Firebolt family 1054 * Parameters: 1055 * unit device number 1056 * flags flags BCM_L2_REPLACE_* 1057 * rep_st structure with information of what to replace 1058 * Return: 1059 * BCM_E_XXX 1060 */ 1061 int 1062 _bcm_fb_l2_addr_replace_by_vlan_dest(int unit, uint32 flags, _bcm_l2_replace_t *rep_st) 1063 { 1064 1065 if (NULL == rep_st) { 1066 return BCM_E_PARAM; 1067 } 1068 if (flags & BCM_L2_REPLACE_MATCH_VLAN) { 1069 VLAN_CHK_ID(unit, rep_st->key_vlan); 1070 } 1071 1072 if (0 == (flags & BCM_L2_REPLACE_DELETE)) { 1073 BCM_IF_ERROR_RETURN( 1074 _bcm_fb_repl_reg_config(unit, rep_st)); 1075 } 1076 BCM_IF_ERROR_RETURN( 1077 _bcm_fb_age_reg_config(unit, flags, rep_st)); 1078 1079 return BCM_E_NONE; 1080 } 1081 1082 #ifndef BCM_SW_STATE_DUMP_DISABLE 1083 /* 1084 * Function: 1085 * _bcm_fb_l2_sw_dump 1086 * Purpose: 1087 * Displays L2 information maintained by software. 1088 * Parameters: 1089 * unit - Device unit number 1090 * Returns: 1091 * None 1092 */ 1093 void 1094 _bcm_fb_l2_sw_dump(int unit) 1095 { 1096 _bcm_mac_block_info_t *mbi; 1097 char pfmt[SOC_PBMP_FMT_LEN]; 1098 int i; 1099 1100 LOG_CLI((BSL_META_U(unit, 1101 "\n"))); 1102 LOG_CLI((BSL_META_U(unit, 1103 " FB L2 MAC Blocking Info -\n"))); 1104 LOG_CLI((BSL_META_U(unit, 1105 " Number : %d\n"), _mbi_num[unit])); 1106 1107 mbi = _mbi_entries[unit]; 1108 LOG_CLI((BSL_META_U(unit, 1109 " Entries (index: pbmp-count) :\n"))); 1110 if (mbi != NULL) { 1111 for (i = 0; i < _mbi_num[unit]; i++) { 1112 SOC_PBMP_FMT(mbi[i].mb_pbmp, pfmt); 1113 LOG_CLI((BSL_META_U(unit, 1114 " %5d: %s-%d\n"), i, pfmt, mbi[i].ref_count)); 1115 } 1116 } 1117 1118 LOG_CLI((BSL_META_U(unit, 1119 "\n"))); 1120 1121 return; 1122 } 1123 #endif /* BCM_SW_STATE_DUMP_DISABLE */ 1124 1125 #endif /* BCM_FIREBOLT_SUPPORT */ 1126