subport.c (67848B)
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: subport.c 8 * Purpose: Triumph SUBPORT functions 9 */ 10 11 #include <soc/defs.h> 12 #include <sal/core/libc.h> 13 #include <shared/bsl.h> 14 #if defined(BCM_TRX_SUPPORT) && defined(INCLUDE_L3) 15 16 #include <soc/drv.h> 17 #include <soc/scache.h> 18 #include <soc/hash.h> 19 #include <soc/util.h> 20 #include <soc/debug.h> 21 22 #include <bcm/error.h> 23 #include <bcm/subport.h> 24 25 #include <bcm_int/esw/mbcm.h> 26 #include <bcm_int/esw/firebolt.h> 27 #include <bcm_int/esw/trx.h> 28 #include <bcm_int/esw/triumph.h> 29 #include <bcm_int/esw/l3.h> 30 #include <bcm_int/esw/virtual.h> 31 #include <bcm_int/esw/stack.h> 32 #include <bcm_int/esw/subport.h> 33 #ifdef BCM_TRIUMPH2_SUPPORT 34 #include <bcm_int/esw/triumph2.h> 35 #endif 36 37 #include <bcm_int/esw_dispatch.h> 38 39 /* Usage bitmap of subport groups (1 group = 8 VPs) */ 40 STATIC SHR_BITDCL *_tr_group_bitmap[BCM_MAX_NUM_UNITS] = { 0 }; 41 42 /* Array of L3_INTF IDs per VP (0xffff means unused) */ 43 STATIC uint16 *_tr_subport_id[BCM_MAX_NUM_UNITS] = { 0 }; 44 45 /* Per-port count of all subports added */ 46 STATIC int _tr_subport_group_count[BCM_MAX_NUM_UNITS][SOC_MAX_NUM_PORTS] = {{ 0 }}; 47 48 /* 49 * Limited to 4K VPs (instead of actual table size of 8K) 50 * since the IVID field (12-bits) in EGR_VLAN_XLATE table is 51 * used as the DVP value. 52 */ 53 #define SUBPORT_NUM_VP (4096) 54 #define VP_PER_SUBPORT_GROUP (8) 55 #define SUBPORT_NUM_GROUP (SUBPORT_NUM_VP / VP_PER_SUBPORT_GROUP) 56 57 #define SUBPORT_VP_MEM_LOCK(unit) \ 58 do { \ 59 if (SOC_IS_TR_VL(unit) || SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { \ 60 MEM_LOCK(unit, SOURCE_VPm); \ 61 } else { \ 62 sal_mutex_take(_subport_vp_mutex[unit], sal_mutex_FOREVER); \ 63 } \ 64 } while ((0)) 65 66 #define SUBPORT_VP_MEM_UNLOCK(unit) \ 67 do { \ 68 if (SOC_IS_TR_VL(unit) || SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { \ 69 MEM_UNLOCK(unit, SOURCE_VPm); \ 70 } else { \ 71 sal_mutex_give(_subport_vp_mutex[unit]); \ 72 } \ 73 } while ((0)) 74 75 /* Index to ING_L3_NEXT_HOP for VPG */ 76 int16 * _sc_subport_group_index[BCM_MAX_NUM_UNITS] = {NULL}; 77 /* L3 index */ 78 int16 * _sc_subport_port_l3idx_map[BCM_MAX_NUM_UNITS] = {NULL}; 79 /* Vp base */ 80 int16 * _sc_subport_group_vp_base[BCM_MAX_NUM_UNITS] = {NULL}; 81 /* OVID for subport groups */ 82 STATIC int16 * _sc_subport_group_ovid[BCM_MAX_NUM_UNITS] = {NULL}; 83 STATIC sal_mutex_t _subport_vp_mutex[BCM_MAX_NUM_UNITS] = {NULL}; 84 85 #define _TR_SUBPORT_CHECK_INIT(_unit_) \ 86 if (!_tr_group_bitmap[_unit_]) \ 87 return BCM_E_INIT 88 89 STATIC int _bcm_tr_subport_port_delete(int unit, int l3_idx, int vp); 90 STATIC int _bcm_tr_subport_group_destroy(int unit, int vp_base); 91 92 /* 93 * Subport group usage bitmap operations 94 */ 95 #define _BCM_GROUP_USED_GET(_u_, _group_) \ 96 SHR_BITGET(_tr_group_bitmap[_u_], (_group_)) 97 #define _BCM_GROUP_USED_SET(_u_, _group_) \ 98 SHR_BITSET(_tr_group_bitmap[_u_], (_group_)) 99 #define _BCM_GROUP_USED_CLR(_u_, _group_) \ 100 SHR_BITCLR(_tr_group_bitmap[_u_], (_group_)) 101 102 /* 103 * Subport port usage bitmap operations 104 */ 105 #define _BCM_SUBPORT_ID_GET(_u_, _subport_) \ 106 (_tr_subport_id[_u_][_subport_]) 107 #define _BCM_SUBPORT_ID_SET(_u_, _subport_, _id_) \ 108 (_tr_subport_id[_u_][_subport_] = _id_) 109 #define _BCM_SUBPORT_ID_CLR(_u_, _subport_) \ 110 (_tr_subport_id[_u_][_subport_] = 0xffff) 111 112 /* 113 * Function Vector 114 */ 115 static bcm_esw_subport_drv_t bcmi_tr_subport_drv = { 116 117 /* subport_init */ bcm_tr_subport_init, 118 /* subport_group_create */ bcm_tr_subport_group_create, 119 /* subport_group_get */ bcm_tr_subport_group_get, 120 /* subport_group_traverse */ NULL, 121 /* subport_group_destroy */ bcm_tr_subport_group_destroy, 122 /* subport_linkphy_config_set */ NULL, 123 /* subport_linkphy_config_get */ NULL, 124 /* subport_port_add */ bcm_tr_subport_port_add, 125 /* subport_port_get */ bcm_tr_subport_port_get, 126 /* subport_port_traverse */ bcm_tr_subport_port_traverse, 127 /* subport_port_stat_set */ NULL, 128 /* subport_port_stat_get */ NULL, 129 /* subport_port_delete */ bcm_tr_subport_port_delete, 130 /* subport_cleanup */ bcm_tr_subport_cleanup, 131 132 /* coe_init */ NULL, 133 /* coe_group_create */ NULL, 134 /* coe_group_get */ NULL, 135 /* coe_group_traverse */ NULL, 136 /* coe_group_destroy */ NULL, 137 /* coe_linkphy_config_set */ NULL, 138 /* coe_linkphy_config_get */ NULL, 139 /* coe_port_add */ NULL, 140 /* coe_port_get */ NULL, 141 /* coe_port_traverse */ NULL, 142 /* coe_port_stat_set */ NULL, 143 /* coe_port_stat_get */ NULL, 144 /* coe_port_delete */ NULL, 145 /* coe_cleanup */ NULL 146 }; 147 148 /* 149 * Function: 150 * _bcm_tr_subport_gport_used 151 * Purpose: 152 * Internal function for testing if a gport is a configured subport type 153 * Parameters: 154 * unit - (IN) Device number. 155 * port - (IN) Gport 156 * Returns: 157 * BCM_X_XXX 158 */ 159 int 160 _bcm_tr_subport_gport_used(int unit, bcm_gport_t port) 161 { 162 int vp; 163 164 if (BCM_GPORT_IS_SUBPORT_GROUP(port)) { 165 vp = BCM_GPORT_SUBPORT_GROUP_GET(port); 166 if (!_BCM_GROUP_USED_GET(unit, (vp / 8))) { 167 return BCM_E_NOT_FOUND; 168 } 169 } else if (BCM_GPORT_IS_SUBPORT_PORT(port)) { 170 vp = BCM_GPORT_SUBPORT_PORT_GET(port); 171 if (_BCM_SUBPORT_ID_GET(unit, vp) == 0xffff) { 172 return BCM_E_NOT_FOUND; 173 } 174 } 175 return BCM_E_NONE; 176 } 177 178 /* 179 * Function: 180 * _bcm_tr_subport_group_find 181 * Purpose: 182 * Internal function to determine the subport group 183 * Parameters: 184 * unit - (IN) Device number. 185 * port - (IN) Gport 186 * Returns: 187 * BCM_X_XXX 188 */ 189 190 int 191 _bcm_tr_subport_group_find(int unit, int vp, int *grp) 192 { 193 #ifdef BCM_SCORPION_SUPPORT 194 int ix; 195 196 if (NULL == _sc_subport_group_index[unit]) { 197 /* Not initialized, not applicable on this unit. */ 198 return BCM_E_UNAVAIL; 199 } 200 201 *grp = -1; 202 for (ix = 0; ix < SUBPORT_NUM_GROUP; ix++) { 203 if (_sc_subport_group_index[unit][ix] == vp) { 204 *grp = ix * 8; 205 return BCM_E_NONE; 206 } 207 } 208 return BCM_E_UNAVAIL; 209 #else 210 *grp = -1; 211 return BCM_E_NONE; 212 #endif 213 } 214 /* 215 * Function: 216 * _bcm_tr_subport_vp_alloc 217 * Purpose: 218 * Internal function for allocating a group of VPs 219 * Parameters: 220 * unit - (IN) Device number. 221 * base_vp - (OUT) Base VP index 222 * Returns: 223 * BCM_X_XXX 224 */ 225 STATIC int 226 _bcm_tr_subport_vp_alloc(int unit, int *base_vp) 227 { 228 int i; 229 /* 230 * VP allocation is normally done by the MPLS module. However, 231 * for builds without MPLS support, the VP allocation is done here. 232 */ 233 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \ 234 defined(INCLUDE_L3) 235 if (SOC_IS_TR_VL(unit)) { 236 int rv; 237 _bcm_vp_info_t vp_info; 238 /* 239 * Allocate a group of 8 consecutive VPs since 3-bit prio 240 * is added to DVP-group to get the final DVP in the L2 lookup. 241 * Only allocate from the 0 - 4k range since only 12-bits 242 * are used in the EGR_VLAN_XLATE table key. 243 * (the IVID field is used as the DVP in EGR_VLAN_XLATE) 244 */ 245 _bcm_vp_info_init(&vp_info); 246 vp_info.vp_type = _bcmVpTypeSubport; 247 rv = _bcm_vp_alloc(unit, 0, 4095, 8, SOURCE_VPm, vp_info, base_vp); 248 if (rv < 0) { 249 return rv; 250 } 251 _BCM_GROUP_USED_SET(unit, *base_vp / 8); 252 return BCM_E_NONE; 253 } 254 #endif 255 256 SUBPORT_VP_MEM_LOCK(unit); 257 for (i = 0; i < SUBPORT_NUM_GROUP; i++) { 258 if (!_BCM_GROUP_USED_GET(unit, i)) { 259 break; 260 } 261 } 262 if (i == SUBPORT_NUM_GROUP) { 263 SUBPORT_VP_MEM_UNLOCK(unit); 264 return BCM_E_RESOURCE; 265 } 266 *base_vp = i * 8; 267 268 _BCM_GROUP_USED_SET(unit, i); 269 SUBPORT_VP_MEM_UNLOCK(unit); 270 return BCM_E_NONE; 271 } 272 273 /* 274 * Function: 275 * _bcm_tr_subport_vp_free 276 * Purpose: 277 * Internal function for freeing a group of VPs 278 * Parameters: 279 * unit - (IN) Device number. 280 * base_vp - (IN) Base VP index 281 * Returns: 282 * BCM_X_XXX 283 */ 284 STATIC int 285 _bcm_tr_subport_vp_free(int unit, int base_vp) 286 { 287 /* 288 * VP freeing is normally done by the MPLS module. However, 289 * for builds without MPLS support, the VP free is done here. 290 */ 291 #if defined(BCM_TRIUMPH_SUPPORT) && defined(BCM_MPLS_SUPPORT) && \ 292 defined(INCLUDE_L3) 293 if (SOC_IS_TR_VL(unit)) { 294 int rv; 295 296 rv = _bcm_vp_free(unit, _bcmVpTypeSubport, 8, base_vp); 297 BCM_IF_ERROR_RETURN (rv); 298 } 299 #endif 300 301 _BCM_GROUP_USED_CLR(unit, base_vp / 8); 302 303 #ifdef BCM_SCORPION_SUPPORT 304 if (SOC_IS_SC_CQ(unit)) { 305 _sc_subport_group_index[unit][base_vp/8] = ~0; 306 _sc_subport_group_ovid[unit][base_vp/8] = ~0; 307 } 308 #endif 309 310 return BCM_E_NONE; 311 } 312 313 STATIC int 314 _bcm_tr_subport_hw_clear(int unit) 315 { 316 int i; /* Subport groups iterator. */ 317 int l3_idx; /* Port id. */ 318 int vp; /* VP iterator. */ 319 int rv = BCM_E_NONE; /* Operation return status. */ 320 321 322 /* _bcm_tr_subport_port_delete() is taking VLAN_XLATEm lock. */ 323 SUBPORT_VP_MEM_LOCK(unit); 324 /* Delete all existing subports */ 325 for (vp = 0; vp < SUBPORT_NUM_VP; vp++) { 326 l3_idx = _BCM_SUBPORT_ID_GET(unit, vp); 327 if (l3_idx != 0xffff) { 328 rv = _bcm_tr_subport_port_delete(unit, l3_idx, vp); 329 if (rv < 0) { 330 SUBPORT_VP_MEM_UNLOCK(unit); 331 return rv; 332 } 333 } 334 } 335 336 /* Delete all existing groups (Group 0 reserved.)*/ 337 for (i = 1; i < SUBPORT_NUM_GROUP; i++) { 338 if (_BCM_GROUP_USED_GET(unit, i)) { 339 rv = _bcm_tr_subport_group_destroy(unit, (i * 8)); 340 if (rv < 0) { 341 SUBPORT_VP_MEM_UNLOCK(unit); 342 return rv; 343 } 344 } 345 } 346 SUBPORT_VP_MEM_UNLOCK(unit); 347 return (rv); 348 } 349 350 STATIC void 351 _bcm_tr_subport_free_resource(int unit) 352 { 353 if (_tr_group_bitmap[unit]) { 354 sal_free(_tr_group_bitmap[unit]); 355 _tr_group_bitmap[unit] = NULL; 356 } 357 if (_tr_subport_id[unit]) { 358 sal_free(_tr_subport_id[unit]); 359 _tr_subport_id[unit] = NULL; 360 } 361 362 if (_subport_vp_mutex[unit] != NULL) { 363 sal_mutex_destroy(_subport_vp_mutex[unit]); 364 _subport_vp_mutex[unit] = NULL; 365 } 366 #ifdef BCM_SCORPION_SUPPORT 367 if (SOC_IS_SC_CQ(unit)){ 368 if (_sc_subport_group_index[unit] != NULL) { 369 sal_free(_sc_subport_group_index[unit]); 370 _sc_subport_group_index[unit] = NULL; 371 } 372 if (_sc_subport_group_ovid[unit] != NULL) { 373 sal_free(_sc_subport_group_ovid[unit]); 374 _sc_subport_group_ovid[unit] = NULL; 375 } 376 if (_sc_subport_port_l3idx_map[unit] != NULL) { 377 sal_free(_sc_subport_port_l3idx_map[unit]); 378 _sc_subport_port_l3idx_map[unit] = NULL; 379 } 380 if (_sc_subport_group_vp_base[unit] != NULL) { 381 sal_free(_sc_subport_group_vp_base[unit]); 382 _sc_subport_group_vp_base[unit] = NULL; 383 } 384 } 385 #endif 386 } 387 388 #ifdef BCM_WARM_BOOT_SUPPORT 389 /* 390 * Function: 391 * _bcm_tr_subport_reinit 392 * Purpose: 393 * Reinit for warm boot. 394 * Parameters: 395 * unit : (IN) Device Unit Number 396 * Returns: 397 * BCM_E_XXX 398 */ 399 STATIC int 400 _bcm_tr_subport_reinit(int unit) 401 { 402 int stable_size; 403 int idx, vp = 0; 404 int num_vp; 405 int index_min, index_max, tpid_enable, index; 406 source_vp_entry_t svp_entry; 407 egr_l3_intf_entry_t egr_l3_entry; 408 _bcm_vp_info_t vp_info; 409 410 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 411 412 /* Reconstruct s/w state: Subport IDs */ 413 index_min = soc_mem_index_min(unit, EGR_L3_INTFm); 414 index_max = soc_mem_index_max(unit, EGR_L3_INTFm); 415 416 for (idx = index_min; idx <= index_max; idx++) { 417 SOC_IF_ERROR_RETURN(soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ANY, 418 idx, &egr_l3_entry)); 419 if (0 == soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry, 420 IVID_VALIDf)) { 421 continue; 422 } 423 if ((vp = soc_EGR_L3_INTFm_field32_get(unit, &egr_l3_entry, 424 IVIDf)) == 0){ 425 continue; 426 } 427 428 if (soc_feature(unit, soc_feature_virtual_switching)) { 429 if ((stable_size == 0) || SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)) { 430 _bcm_vp_info_init(&vp_info); 431 vp_info.vp_type = _bcmVpTypeSubport; 432 BCM_IF_ERROR_RETURN( 433 _bcm_vp_used_set(unit, vp, vp_info)); 434 _BCM_SUBPORT_ID_SET(unit, vp, idx); 435 } else { 436 /* Extended scache based (Level 2) recovery */ 437 if (_bcm_vp_used_get(unit, vp, _bcmVpTypeSubport)) { 438 _BCM_SUBPORT_ID_SET(unit, vp, idx); 439 } 440 } 441 } else { /* SC and CQ devices */ 442 _BCM_SUBPORT_ID_SET(unit, vp, idx); 443 } 444 445 BCM_L3_INTF_USED_SET(unit, idx); 446 } 447 448 if (soc_feature(unit, soc_feature_virtual_switching)) { 449 num_vp = soc_mem_index_count(unit, SOURCE_VPm); 450 /* Reconstruct s/w state: Subport Groups */ 451 index_min = soc_mem_index_min(unit, SOURCE_VPm); 452 index_max = soc_mem_index_max(unit, SOURCE_VPm); 453 for (idx = 0; idx < num_vp ; idx++) { 454 SOC_IF_ERROR_RETURN(soc_mem_read(unit, SOURCE_VPm, MEM_BLOCK_ANY, 455 idx, &svp_entry)); 456 457 if (0x3 != soc_SOURCE_VPm_field32_get(unit, &svp_entry, 458 ENTRY_TYPEf)) { 459 continue; 460 } 461 462 _BCM_GROUP_USED_SET(unit, (idx/VP_PER_SUBPORT_GROUP)); 463 464 /* Recover TPID ref count */ 465 if (soc_SOURCE_VPm_field32_get(unit, &svp_entry, 466 SD_TAG_MODEf) == 1) { 467 tpid_enable = soc_SOURCE_VPm_field32_get(unit, &svp_entry, 468 TPID_ENABLEf); 469 for (index = 0; index < 4; index++) { 470 if (tpid_enable & (1 << index)) { 471 BCM_IF_ERROR_RETURN( 472 _bcm_fb2_outer_tpid_tab_ref_count_add( unit, index, 1)); 473 break; 474 } 475 } 476 } 477 } 478 } 479 480 return BCM_E_NONE; 481 } 482 #endif /* BCM_WARM_BOOT_SUPPORT */ 483 484 /* 485 * Function: 486 * bcm_subport_init 487 * Purpose: 488 * Initialize the SUBPORT software module 489 * Parameters: 490 * unit - Device Number 491 * Returns: 492 * BCM_E_XXX 493 */ 494 int 495 bcm_tr_subport_init(int unit) 496 { 497 int i; 498 int rv = BCM_E_NONE; 499 500 /* Make sure module was initialized. */ 501 if (!BCM_XGS3_L3_INITIALIZED(unit)) { 502 return (BCM_E_INIT); 503 } 504 505 /* 506 * Include hook to flex stats 507 */ 508 509 if (_tr_subport_id[unit] == NULL) { 510 _tr_subport_id[unit] = 511 sal_alloc(SUBPORT_NUM_VP * sizeof(uint16), "subport_bitmap"); 512 if (_tr_subport_id[unit] == NULL) { 513 return BCM_E_MEMORY; 514 } 515 } 516 for (i = 0; i < SUBPORT_NUM_VP; i++) { 517 _BCM_SUBPORT_ID_CLR(unit, i); 518 } 519 520 if (_tr_group_bitmap[unit] == NULL) { 521 _tr_group_bitmap[unit] = 522 sal_alloc(SHR_BITALLOCSIZE(SUBPORT_NUM_GROUP), "subport_group_bitmap"); 523 if (_tr_group_bitmap[unit] == NULL) { 524 _bcm_tr_subport_free_resource(unit); 525 return BCM_E_MEMORY; 526 } 527 } 528 sal_memset(_tr_group_bitmap[unit], 0, SHR_BITALLOCSIZE(SUBPORT_NUM_GROUP)); 529 /* Don't use VP 0 (HW restriction) : mark group 0 as used */ 530 _BCM_GROUP_USED_SET(unit, 0); 531 532 for (i = 0; i < SOC_MAX_NUM_PORTS; i++) { 533 _tr_subport_group_count[unit][i] = 0; 534 } 535 536 if (!SOC_MEM_IS_VALID(unit, SOURCE_VPm)) { 537 if (NULL == _subport_vp_mutex[unit]) { 538 _subport_vp_mutex[unit] = sal_mutex_create("subport vp mutex"); 539 if (_subport_vp_mutex[unit] == NULL) { 540 _bcm_tr_subport_free_resource(unit); 541 return BCM_E_MEMORY; 542 } 543 } 544 } 545 #ifdef BCM_SCORPION_SUPPORT 546 if (SOC_IS_SC_CQ(unit)) { 547 if (NULL == _sc_subport_group_index[unit]) { 548 _sc_subport_group_index[unit] = 549 sal_alloc(SUBPORT_NUM_GROUP * sizeof(int16), "sc subport grp idx"); 550 if (_sc_subport_group_index[unit] == NULL) { 551 _bcm_tr_subport_free_resource(unit); 552 return BCM_E_MEMORY; 553 } 554 } 555 for (i = 0; i < SUBPORT_NUM_GROUP; i++) { 556 /* Mark invalid index */ 557 _sc_subport_group_index[unit][i] = ~0; 558 } 559 if (NULL == _sc_subport_group_ovid[unit]) { 560 _sc_subport_group_ovid[unit] = 561 sal_alloc(SUBPORT_NUM_GROUP * sizeof(int16), "sc subport grp ovid"); 562 if (_sc_subport_group_ovid[unit] == NULL) { 563 _bcm_tr_subport_free_resource(unit); 564 return BCM_E_MEMORY; 565 } 566 } 567 for (i = 0; i < SUBPORT_NUM_GROUP; i++) { 568 /* Mark invalid ovid */ 569 _sc_subport_group_ovid[unit][i] = ~0; 570 } 571 if (NULL == _sc_subport_port_l3idx_map[unit]) { 572 _sc_subport_port_l3idx_map[unit] = 573 sal_alloc(SUBPORT_NUM_VP * sizeof(int16), "sc subport l3 idx"); 574 if (_sc_subport_port_l3idx_map[unit] == NULL) { 575 _bcm_tr_subport_free_resource(unit); 576 return BCM_E_MEMORY; 577 } 578 } 579 for (i = 0; i < SUBPORT_NUM_VP; i++) { 580 /* Mark invalid l3_idx */ 581 _sc_subport_port_l3idx_map[unit][i] = ~0; 582 } 583 if (NULL == _sc_subport_group_vp_base[unit]) { 584 _sc_subport_group_vp_base[unit] = 585 sal_alloc(SUBPORT_NUM_VP * sizeof(int16), "sc subport vp base"); 586 if (_sc_subport_group_vp_base[unit] == NULL) { 587 _bcm_tr_subport_free_resource(unit); 588 return BCM_E_MEMORY; 589 } 590 } 591 for (i = 0; i < SUBPORT_NUM_VP ; i++) { 592 /* Mark invalid vp base*/ 593 _sc_subport_group_vp_base[unit][i] = ~0; 594 } 595 } 596 #endif /* BCM_SCORPION_SUPPORT */ 597 598 #ifdef BCM_WARM_BOOT_SUPPORT 599 if(SOC_WARM_BOOT(unit)) { 600 rv = _bcm_tr_subport_reinit(unit); 601 if (rv != BCM_E_NONE) { 602 _bcm_tr_subport_free_resource(unit); 603 } 604 } 605 #endif /* BCM_WARM_BOOT_SUPPORT */ 606 607 608 /* Initialize common SUBPORT module */ 609 BCM_IF_ERROR_RETURN 610 (bcmi_subport_common_init(unit, &bcmi_tr_subport_drv)); 611 612 return rv; 613 } 614 615 /* 616 * Function: 617 * bcm_subport_cleanup 618 * Purpose: 619 * Cleanup the SUBPORT software module 620 * Parameters: 621 * unit - Device Number 622 * Returns: 623 * BCM_E_XXX 624 */ 625 int 626 bcm_tr_subport_cleanup(int unit) 627 { 628 int rv; /* Operation return status. */ 629 630 if (NULL == _tr_group_bitmap[unit]) { 631 return (BCM_E_NONE); 632 } 633 634 if (0 == SOC_HW_ACCESS_DISABLE(unit)) { 635 rv = _bcm_tr_subport_hw_clear(unit); 636 BCM_IF_ERROR_RETURN(rv); 637 } 638 639 _bcm_tr_subport_free_resource(unit); 640 return BCM_E_NONE; 641 } 642 643 /* 644 * Function: 645 * bcm_subport_group_create 646 * Purpose: 647 * Create a subport group 648 * Parameters: 649 * unit - (IN) Device Number 650 * config - (IN) Subport group config information 651 * group - (OUT) GPORT (generic port) identifier 652 * Returns: 653 * BCM_E_XXX 654 */ 655 int 656 bcm_tr_subport_group_create(int unit, bcm_subport_group_config_t *config, 657 bcm_gport_t *group) 658 { 659 int gport_id, rv, vp_base = -1, nh_index = -1, is_local_modid, priority; 660 int i = 0, early_exit_flag = 0; 661 initial_ing_l3_next_hop_entry_t initial_ing_nh; 662 ing_l3_next_hop_entry_t ing_nh; 663 egr_l3_next_hop_entry_t egr_nh; 664 source_vp_entry_t svp; 665 ing_dvp_table_entry_t dvp; 666 bcm_l3_egress_t nh_info; 667 uint32 nh_flags; 668 bcm_module_t mod_out; 669 bcm_port_t port_out; 670 bcm_trunk_t trunk_id; 671 672 _TR_SUBPORT_CHECK_INIT(unit); 673 674 if ((config == NULL) || (group == NULL) || (config->vlan > BCM_VLAN_MAX)) { 675 return BCM_E_PARAM; 676 } 677 rv = _bcm_esw_gport_resolve(unit, config->port, &mod_out, &port_out, &trunk_id, 678 &gport_id); 679 BCM_IF_ERROR_RETURN(rv); 680 681 if (config->flags & BCM_SUBPORT_GROUP_WITH_ID) { 682 vp_base = BCM_GPORT_SUBPORT_GROUP_GET(*group); 683 SUBPORT_VP_MEM_LOCK(unit); 684 if ((vp_base < 0) || (vp_base > (4096 - 8))) { 685 rv = BCM_E_PARAM; 686 } else if (_BCM_GROUP_USED_GET(unit, (vp_base / 8))) { 687 rv = BCM_E_EXISTS; 688 } else { 689 _BCM_GROUP_USED_SET(unit, vp_base / 8); 690 } 691 SUBPORT_VP_MEM_UNLOCK(unit); 692 } else { 693 /* 694 * Allocate a group of 8 consecutive VPs since 3-bit prio 695 * is added to DVP-group to get the final DVP in the L2 lookup. 696 * Only allocate from the 0 - 4k range since only 12-bits 697 * are used in the EGR_VLAN_XLATE table key. 698 * (the IVID field is used as the DVP in EGR_VLAN_XLATE) 699 */ 700 rv = _bcm_tr_subport_vp_alloc(unit, &vp_base); 701 } 702 BCM_IF_ERROR_RETURN (rv); 703 704 /* 705 * Allocate a next-hop entry. By calling bcm_xgs3_nh_add() 706 * with _BCM_L3_SHR_WRITE_DISABLE flag, a next-hop index is 707 * allocated but nothing is written to hardware. The "nh_info" 708 * in this case is not used, so just set to all zeros. 709 */ 710 for (priority = 0; priority < 8; priority ++) { 711 sal_memset(&nh_info, 0, sizeof(nh_info)); 712 nh_flags = _BCM_L3_SHR_MATCH_DISABLE | _BCM_L3_SHR_WRITE_DISABLE; 713 #ifdef BCM_SCORPION_SUPPORT 714 715 if (SOC_IS_SC_CQ(unit)) { 716 nh_flags |= _BCM_L3_SHR_SKIP_INDEX_ZERO; 717 } 718 #endif 719 rv = bcm_xgs3_nh_add(unit, nh_flags, &nh_info, &nh_index); 720 if (rv < 0) { 721 early_exit_flag = 1; 722 goto cleanup; 723 } 724 725 #ifdef BCM_SCORPION_SUPPORT 726 /* Only (0 - 4k) can be used */ 727 if (SOC_IS_SC_CQ(unit)) { 728 if (priority == 0) { 729 _sc_subport_group_index[unit][vp_base/8] = nh_index; 730 } 731 if (nh_index >= 4096) { 732 rv = BCM_E_RESOURCE; 733 goto cleanup; 734 } 735 } 736 #endif 737 738 /* 739 * The EGR_L3_NEXT_HOP is not actually used in the datapath. 740 * Instead, the DVP value is passed through the MMU in the 741 * IVID field. At the egress, the IVID (DVP) is used in the 742 * egress vlan translate table key. Here we use the 743 * EGR_L3_NEXT_HOP just to store the subport group's vlan 744 * for warm reboot purposes for Triumph. 745 */ 746 if (SOC_IS_TR_VL(unit)) { 747 /* Write EGR_L3_NEXT_HOP entry */ 748 sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t)); 749 soc_mem_field32_set(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf, 750 config->vlan); 751 rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, 752 MEM_BLOCK_ALL, nh_index, &egr_nh); 753 if (rv < 0) { 754 goto cleanup; 755 } 756 } else if (SOC_IS_SC_CQ(unit)) { 757 _sc_subport_group_ovid[unit][vp_base/8] = config->vlan; 758 } 759 760 /* Write ING_L3_NEXT_HOP entry */ 761 sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t)); 762 if (BCM_GPORT_IS_TRUNK(config->port)) { 763 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf, 1); 764 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, 765 &ing_nh, TGIDf, trunk_id); 766 } else { 767 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, 768 &ing_nh, PORT_NUMf, port_out); 769 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, 770 &ing_nh, MODULE_IDf, mod_out); 771 } 772 /* Use all 8 DVPs in the group. */ 773 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, 774 &ing_nh, DVP_RES_INFOf, 0x7f); 775 776 if (SOC_IS_TR_VL(unit)) { 777 soc_mem_field32_set(unit, ING_L3_NEXT_HOPm, 778 &ing_nh, ENTRY_TYPEf, 0x3); /* GPON DVP */ 779 } 780 781 rv = soc_mem_write (unit, ING_L3_NEXT_HOPm, 782 MEM_BLOCK_ALL, nh_index, &ing_nh); 783 if (rv < 0) { 784 goto cleanup; 785 } 786 787 /* Write INITIAL_ING_L3_NEXT_HOP entry */ 788 sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t)); 789 if (BCM_GPORT_IS_TRUNK(config->port)) { 790 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, 791 &initial_ing_nh, Tf, 1); 792 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, 793 &initial_ing_nh, TGIDf, trunk_id); 794 } else { 795 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, 796 &initial_ing_nh, PORT_NUMf, port_out); 797 soc_mem_field32_set(unit, INITIAL_ING_L3_NEXT_HOPm, 798 &initial_ing_nh, MODULE_IDf, mod_out); 799 } 800 rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm, 801 MEM_BLOCK_ALL, nh_index, &initial_ing_nh); 802 if (rv < 0) { 803 goto cleanup; 804 } 805 806 if (SOC_IS_TR_VL(unit)) { 807 /* Write ING_DVP_TABLE entry */ 808 sal_memset(&dvp, 0, sizeof(ing_dvp_table_entry_t)); 809 soc_ING_DVP_TABLEm_field32_set(unit, &dvp, NEXT_HOP_INDEXf, nh_index); 810 rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + priority), &dvp); 811 if (rv < 0) { 812 goto cleanup; 813 } 814 815 /* Write SOURCE_VP table entry */ 816 sal_memset(&svp, 0, sizeof(svp)); 817 soc_SOURCE_VPm_field32_set(unit, &svp, ENTRY_TYPEf, 0x3); /* GPON */ 818 soc_SOURCE_VPm_field32_set(unit, &svp, CLASS_IDf, config->if_class); 819 820 /* Set the CML to PVP_CML_SWITCH by default (hw learn and forward) */ 821 822 soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, 0x8); 823 soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, 0x8); 824 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, (vp_base + priority), &svp); 825 if (rv < 0) { 826 goto cleanup; 827 } 828 } 829 BCM_IF_ERROR_RETURN( 830 _bcm_esw_modid_is_local(unit, mod_out, &is_local_modid)); 831 832 if (TRUE == is_local_modid) { 833 if (_tr_subport_group_count[unit][port_out]++ == 0) { 834 SOC_IF_ERROR_RETURN 835 (soc_reg_field32_modify(unit, EGR_IPMC_CFG2r, port_out, 836 DISABLE_TTL_CHECKf, 1)); 837 } 838 } 839 } 840 BCM_GPORT_SUBPORT_GROUP_SET(*group, vp_base); 841 842 #ifdef BCM_WARM_BOOT_SUPPORT 843 SOC_CONTROL_LOCK(unit); 844 SOC_CONTROL(unit)->scache_dirty = 1; 845 SOC_CONTROL_UNLOCK(unit); 846 #endif 847 848 return BCM_E_NONE; 849 850 cleanup: 851 /* For Scorpion, if cleanup happened before nh_index can be stored then 852 * reduce priority by 1 to clean right number of next hop indexes. 853 */ 854 if (SOC_IS_SC_CQ(unit)) { 855 if(early_exit_flag) { 856 priority -= 1; 857 } 858 } 859 for (;priority >= 0; priority --) { 860 if (SOC_IS_TR_VL(unit)) { 861 (void) READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + priority), &dvp); 862 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 863 } else if (SOC_IS_SC_CQ(unit)) { 864 nh_index = _sc_subport_group_index[unit][vp_base/8]; 865 nh_index = nh_index - i; 866 } 867 if (nh_index != -1) { 868 nh_flags = _BCM_L3_SHR_WRITE_DISABLE; 869 (void) bcm_xgs3_nh_del(unit, nh_flags, nh_index); 870 } 871 i++; 872 } 873 if (vp_base != -1) { 874 (void) _bcm_tr_subport_vp_free(unit, vp_base); 875 } 876 return rv; 877 } 878 879 STATIC int 880 _bcm_tr_subport_group_destroy(int unit, int vp_base) 881 { 882 int i, l3_idx, nh_index=-1, rv, is_local_modid; 883 initial_ing_l3_next_hop_entry_t initial_ing_nh; 884 ing_l3_next_hop_entry_t ing_nh; 885 egr_l3_next_hop_entry_t egr_nh; 886 ing_dvp_table_entry_t dvp; 887 source_vp_entry_t svp; 888 bcm_port_t port; 889 bcm_module_t modid; 890 891 if (SOC_IS_TR_VL(unit)) { 892 /* Get the next-hop index from the base VP */ 893 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp); 894 BCM_IF_ERROR_RETURN(rv); 895 896 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 897 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 898 nh_index, &ing_nh)); 899 900 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) { 901 /* Entry type is not GPON DVP */ 902 return BCM_E_NOT_FOUND; 903 } 904 } else if (SOC_IS_SC_CQ(unit)) { 905 nh_index = _sc_subport_group_index[unit][vp_base/8]; 906 if (nh_index == ~0) { 907 return BCM_E_NOT_FOUND; 908 } 909 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 910 nh_index, &ing_nh)); 911 } 912 913 /* Delete any ports that were added to the group */ 914 for (i = 0; i < 8; i++) { 915 l3_idx = _BCM_SUBPORT_ID_GET(unit, (vp_base + i)); 916 if (l3_idx != 0xffff) { 917 rv = _bcm_tr_subport_port_delete(unit, l3_idx, (vp_base + i)); 918 BCM_IF_ERROR_RETURN(rv); 919 } 920 921 if (SOC_IS_TR_VL(unit)) { 922 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, (vp_base + i), &dvp); 923 BCM_IF_ERROR_RETURN(rv); 924 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 925 926 /* Clear SOURCE_VP table entry */ 927 sal_memset(&svp, 0, sizeof(svp)); 928 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base + i, &svp); 929 BCM_IF_ERROR_RETURN(rv); 930 931 /* Clear ING_DVP_TABLE entry */ 932 sal_memset(&dvp, 0, sizeof(dvp)); 933 rv = WRITE_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base + i, &dvp); 934 BCM_IF_ERROR_RETURN(rv); 935 936 937 /* Clear EGR_L3_NEXT_HOP entry */ 938 sal_memset(&egr_nh, 0, sizeof(egr_l3_next_hop_entry_t)); 939 rv = soc_mem_write(unit, EGR_L3_NEXT_HOPm, 940 MEM_BLOCK_ALL, nh_index, &egr_nh); 941 BCM_IF_ERROR_RETURN(rv); 942 } else if (SOC_IS_SC_CQ(unit)) { 943 nh_index = _sc_subport_group_index[unit][vp_base/8]; 944 nh_index = nh_index + i; 945 } 946 947 /* Get the modid/port number from ING_L3_NEXT_HOP entry */ 948 /* coverity[negative_returns : FALSE] */ 949 rv = soc_mem_read(unit, ING_L3_NEXT_HOPm, 950 MEM_BLOCK_ALL, nh_index, &ing_nh); 951 BCM_IF_ERROR_RETURN(rv); 952 modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 953 &ing_nh, MODULE_IDf); 954 port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 955 &ing_nh, PORT_NUMf); 956 957 /* Clear ING_L3_NEXT_HOP entry */ 958 sal_memset(&ing_nh, 0, sizeof(ing_l3_next_hop_entry_t)); 959 rv = soc_mem_write (unit, ING_L3_NEXT_HOPm, 960 MEM_BLOCK_ALL, nh_index, &ing_nh); 961 BCM_IF_ERROR_RETURN(rv); 962 963 /* Clear INITIAL_ING_L3_NEXT_HOP entry */ 964 sal_memset(&initial_ing_nh, 0, sizeof(initial_ing_l3_next_hop_entry_t)); 965 rv = soc_mem_write(unit, INITIAL_ING_L3_NEXT_HOPm, 966 MEM_BLOCK_ALL, nh_index, &initial_ing_nh); 967 BCM_IF_ERROR_RETURN(rv); 968 969 /* Free the next-hop index */ 970 rv = bcm_xgs3_nh_del(unit, _BCM_L3_SHR_WRITE_DISABLE, nh_index); 971 BCM_IF_ERROR_RETURN(rv); 972 } 973 #ifdef BCM_TRIUMPH2_SUPPORT 974 if (soc_feature(unit, soc_feature_gport_service_counters)) { 975 bcm_gport_t gport; 976 977 /* Release Service counter, if any */ 978 BCM_GPORT_SUBPORT_GROUP_SET(gport, vp_base); 979 _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport); 980 } 981 #endif 982 983 /* Free the VP */ 984 rv = _bcm_tr_subport_vp_free(unit, vp_base); 985 BCM_IF_ERROR_RETURN(rv); 986 987 BCM_IF_ERROR_RETURN( 988 _bcm_esw_modid_is_local(unit, modid, &is_local_modid)); 989 990 if (TRUE == is_local_modid) { 991 if (--_tr_subport_group_count[unit][port] == 0) { 992 SOC_IF_ERROR_RETURN 993 (soc_reg_field32_modify(unit, EGR_IPMC_CFG2r, port, 994 DISABLE_TTL_CHECKf, 0)); 995 } 996 } 997 998 #ifdef BCM_WARM_BOOT_SUPPORT 999 SOC_CONTROL_LOCK(unit); 1000 SOC_CONTROL(unit)->scache_dirty = 1; 1001 SOC_CONTROL_UNLOCK(unit); 1002 #endif 1003 1004 return rv; 1005 } 1006 1007 /* 1008 * Function: 1009 * bcm_subport_group_destroy 1010 * Purpose: 1011 * Destroy a subport group 1012 * Parameters: 1013 * unit - (IN) Device Number 1014 * group - (IN) GPORT (generic port) identifier 1015 * Returns: 1016 * BCM_E_XXX 1017 */ 1018 int 1019 bcm_tr_subport_group_destroy(int unit, bcm_gport_t group) 1020 { 1021 int vp_base; 1022 1023 _TR_SUBPORT_CHECK_INIT(unit); 1024 1025 vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 1026 if (vp_base == -1) { 1027 return BCM_E_PARAM; 1028 } 1029 1030 return _bcm_tr_subport_group_destroy(unit, vp_base); 1031 } 1032 1033 /* 1034 * Function: 1035 * bcm_subport_group_get 1036 * Purpose: 1037 * Get a subport group 1038 * Parameters: 1039 * unit - (IN) Device Number 1040 * group - (IN) GPORT (generic port) identifier 1041 * config - (OUT) Subport group config information 1042 * Returns: 1043 * BCM_E_XXX 1044 */ 1045 int 1046 bcm_tr_subport_group_get(int unit, bcm_gport_t group, 1047 bcm_subport_group_config_t *config) 1048 { 1049 int rv = BCM_E_NONE; 1050 egr_l3_next_hop_entry_t egr_nh; 1051 ing_l3_next_hop_entry_t ing_nh; 1052 ing_dvp_table_entry_t dvp; 1053 source_vp_entry_t svp; 1054 int nh_index = -1, vp_base; 1055 bcm_port_t port_in, port_out; 1056 bcm_module_t mod_in, mod_out; 1057 bcm_trunk_t trunk_id; 1058 1059 _TR_SUBPORT_CHECK_INIT(unit); 1060 1061 if (config == NULL) { 1062 return BCM_E_PARAM; 1063 } 1064 1065 vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 1066 if (vp_base == -1) { 1067 return BCM_E_PARAM; 1068 } 1069 1070 if (SOC_IS_TR_VL(unit)) { 1071 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp); 1072 BCM_IF_ERROR_RETURN(rv); 1073 1074 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 1075 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1076 nh_index, &ing_nh)); 1077 1078 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) { 1079 /* Entry type is not GPON DVP */ 1080 return BCM_E_NOT_FOUND; 1081 } 1082 } else if (SOC_IS_SC_CQ(unit)) { 1083 nh_index = _sc_subport_group_index[unit][vp_base/8]; 1084 if (nh_index == ~0) { 1085 return BCM_E_NOT_FOUND; 1086 } 1087 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1088 nh_index, &ing_nh)); 1089 } 1090 1091 /* Get the physical gport information from the ingress next-hop entry */ 1092 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) { 1093 trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf); 1094 BCM_GPORT_TRUNK_SET(config->port, trunk_id); 1095 } else { 1096 mod_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf); 1097 port_in = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf); 1098 BCM_IF_ERROR_RETURN(_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET, 1099 mod_in, port_in, 1100 &mod_out, &port_out)); 1101 BCM_GPORT_MODPORT_SET(config->port, mod_out, port_out); 1102 } 1103 1104 if (SOC_IS_TR_VL(unit)) { 1105 /* Get the group's OVID from the group's egress next-hop entry */ 1106 rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, 1107 MEM_BLOCK_ALL, nh_index, &egr_nh); 1108 BCM_IF_ERROR_RETURN(rv); 1109 config->vlan = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf); 1110 } else if (SOC_IS_SC_CQ(unit)) { 1111 config->vlan = _sc_subport_group_ovid[unit][vp_base/8]; 1112 } 1113 1114 if (SOC_IS_TR_VL(unit)) { 1115 /* Get the class-ID from the SOURCE_VP table entry */ 1116 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp); 1117 BCM_IF_ERROR_RETURN(rv); 1118 config->if_class = soc_SOURCE_VPm_field32_get(unit, &svp, CLASS_IDf); 1119 } 1120 return BCM_E_NONE; 1121 } 1122 1123 /* 1124 * Function: 1125 * bcm_subport_port_add 1126 * Purpose: 1127 * Add a subport to a subport group 1128 * Parameters: 1129 * unit - (IN) Device Number 1130 * config - (IN) Subport config information 1131 * port - (OUT) GPORT (generic port) identifier 1132 * Returns: 1133 * BCM_E_XXX 1134 */ 1135 int 1136 bcm_tr_subport_port_add(int unit, bcm_subport_config_t *config, 1137 bcm_gport_t *port) 1138 { 1139 int rv, l3_idx = -1, nh_index=-1, vp_base, vp, is_modid_local; 1140 ing_dvp_table_entry_t dvp; 1141 egr_l3_next_hop_entry_t egr_nh; 1142 ing_l3_next_hop_entry_t ing_nh; 1143 egr_l3_intf_entry_t l3_intf; 1144 egr_vlan_xlate_entry_t egr_vent; 1145 vlan_xlate_entry_t ing_vent; 1146 bcm_vlan_t ovid = 0; 1147 bcm_port_t local_port = 0; 1148 bcm_module_t modid = 0; 1149 bcm_vlan_action_set_t action; 1150 uint32 egr_profile_idx = 0xffffffff; 1151 uint32 ing_profile_idx = 0xffffffff, port_class = 0; 1152 1153 _TR_SUBPORT_CHECK_INIT(unit); 1154 1155 if ((config->int_pri < 0) || (config->int_pri > 7)) { 1156 return BCM_E_PARAM; 1157 } 1158 1159 /* Check Vlan range */ 1160 if ((config->pkt_vlan >= BCM_VLAN_INVALID) || ( config->pkt_vlan == BCM_VLAN_DEFAULT)) { 1161 return BCM_E_PARAM; 1162 } 1163 1164 /* Make sure the group exists */ 1165 vp_base = BCM_GPORT_SUBPORT_GROUP_GET(config->group); 1166 if (vp_base == -1) { 1167 return BCM_E_PARAM; 1168 } 1169 1170 if (!_BCM_GROUP_USED_GET(unit, vp_base / 8)) { 1171 return BCM_E_NOT_FOUND; 1172 } 1173 1174 /* See if this entry already exists */ 1175 if (SOC_IS_SC_CQ(unit)) { 1176 nh_index = _sc_subport_group_index[unit][vp_base/8]; 1177 vp = nh_index + config->int_pri; 1178 if(_BCM_SUBPORT_ID_GET(unit, vp) != 0xffff){ 1179 return BCM_E_EXISTS; 1180 } 1181 _sc_subport_group_vp_base[unit][vp] = vp_base; 1182 } else { 1183 vp = vp_base + config->int_pri; 1184 if (_BCM_SUBPORT_ID_GET(unit, vp) != 0xffff) { 1185 return BCM_E_EXISTS; 1186 } 1187 } 1188 1189 /* Get the group's next-hop index */ 1190 if (SOC_IS_TR_VL(unit)) { 1191 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp, &dvp); 1192 BCM_IF_ERROR_RETURN(rv); 1193 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 1194 } else if (SOC_IS_SC_CQ(unit)) { 1195 nh_index = _sc_subport_group_index[unit][vp_base/8]; 1196 if (nh_index == ~0) { 1197 return BCM_E_NOT_FOUND; 1198 } 1199 } 1200 1201 if (nh_index == -1) { 1202 return BCM_E_INTERNAL; 1203 } 1204 1205 /* Get the modid and port_class for the destination port */ 1206 rv = soc_mem_read(unit, ING_L3_NEXT_HOPm, 1207 MEM_BLOCK_ALL, nh_index, &ing_nh); 1208 if (rv < 0) { 1209 goto cleanup; 1210 } 1211 if (!soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, Tf)) { 1212 modid = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, &ing_nh, MODULE_IDf); 1213 1214 BCM_IF_ERROR_RETURN( 1215 _bcm_esw_modid_is_local(unit, modid, &is_modid_local)); 1216 1217 if (TRUE != is_modid_local ) { 1218 /* No local state is required for groups on remoted devices */ 1219 return BCM_E_NONE; 1220 } 1221 local_port = soc_mem_field32_get(unit, ING_L3_NEXT_HOPm, 1222 &ing_nh, PORT_NUMf); 1223 rv = bcm_esw_port_class_get(unit, local_port, bcmPortClassVlanTranslateEgress, 1224 &port_class); 1225 if (rv < 0) { 1226 goto cleanup; 1227 } 1228 } 1229 1230 if (SOC_IS_TR_VL(unit)) { 1231 /* Get the group's OVID from the group's egress next-hop entry */ 1232 rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, 1233 MEM_BLOCK_ALL, nh_index, &egr_nh); 1234 BCM_IF_ERROR_RETURN(rv); 1235 ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf); 1236 } else if (SOC_IS_SC_CQ(unit)) { 1237 ovid = _sc_subport_group_ovid[unit][vp_base/8]; 1238 } 1239 1240 /* 1241 * For each subport, we need to allocate an L3_INTF entry. 1242 * This is needed for multicast replication. MMU replicates 1243 * multicast packets to each subport by sending a copy to 1244 * the subport's L3_INTF index. 1245 */ 1246 1247 /* Search for unused index. */ 1248 MEM_LOCK(unit, EGR_L3_INTFm); 1249 for (l3_idx = 0; l3_idx < BCM_XGS3_L3_IF_TBL_SIZE(unit); l3_idx++) { 1250 /* Check if interface index is used. */ 1251 if (!BCM_L3_INTF_USED_GET(unit, l3_idx)) { 1252 /* Free index found. */ 1253 BCM_L3_INTF_USED_SET(unit, l3_idx); 1254 break; 1255 } 1256 } 1257 if (l3_idx == BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 1258 MEM_UNLOCK(unit, EGR_L3_INTFm); 1259 return BCM_E_FULL; 1260 } 1261 1262 /* Write EGR_L3_INTF entry */ 1263 sal_memset(&l3_intf, 0, sizeof(egr_l3_intf_entry_t)); 1264 soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, OVIDf, ovid); 1265 1266 /* IVID field is used as the DVP */ 1267 if (SOC_IS_TR_VL(unit)) { 1268 soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVIDf, vp); 1269 } else if (SOC_IS_SC_CQ(unit)) { 1270 soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVIDf, 1271 (nh_index + config->int_pri)); 1272 } 1273 soc_mem_field32_set(unit, EGR_L3_INTFm, &l3_intf, IVID_VALIDf, 1); 1274 rv = soc_mem_write(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf); 1275 if (rv < 0) { 1276 MEM_UNLOCK(unit, EGR_L3_INTFm); 1277 goto cleanup; 1278 } 1279 MEM_UNLOCK(unit, EGR_L3_INTFm); 1280 1281 /* Write EGR_VLAN_XLATE table */ 1282 bcm_vlan_action_set_t_init(&action); 1283 /* Create a profile entry that replaces the outer vid 1284 * with the new 16-bit vlan tag. 1285 */ 1286 action.ot_outer = bcmVlanActionReplace; 1287 action.dt_outer = bcmVlanActionReplace; 1288 action.dt_inner = bcmVlanActionDelete; 1289 rv = _bcm_trx_egr_vlan_action_profile_entry_add(unit, &action, &egr_profile_idx); 1290 if (rv < 0) { 1291 goto cleanup; 1292 } 1293 sal_memset(&egr_vent, 0, sizeof(egr_vent)); 1294 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, VALIDf, 1); 1295 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, OVIDf, ovid); 1296 if (SOC_IS_TR_VL(unit)) { 1297 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp); 1298 } else if (SOC_IS_SC_CQ(unit)) { 1299 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, 1300 (nh_index + config->int_pri)); 1301 } 1302 1303 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, PORT_GROUP_IDf, port_class); 1304 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, TAG_ACTION_PROFILE_PTRf, 1305 egr_profile_idx); 1306 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, NEW_OTAG_VPTAGf, config->pkt_vlan); 1307 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, NEW_OTAG_VPTAG_SELf, 1); 1308 rv = soc_mem_insert_return_old(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, 1309 &egr_vent, &egr_vent); 1310 if (rv == SOC_E_EXISTS) { 1311 /* Delete the old vlan translate profile entry */ 1312 egr_profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent, 1313 TAG_ACTION_PROFILE_PTRf); 1314 rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, egr_profile_idx); 1315 } 1316 if (rv < 0) { 1317 goto cleanup; 1318 } 1319 1320 /* Write ingress VLAN_XLATE table */ 1321 bcm_vlan_action_set_t_init(&action); 1322 action.ot_outer = bcmVlanActionReplace; 1323 action.ot_outer_prio = bcmVlanActionReplace; 1324 action.dt_outer = bcmVlanActionReplace; 1325 action.dt_outer_prio = bcmVlanActionReplace; 1326 rv = _bcm_trx_vlan_action_profile_entry_add(unit, &action, &ing_profile_idx); 1327 if (rv < 0) { 1328 goto cleanup; 1329 } 1330 sal_memset(&ing_vent, 0, sizeof(ing_vent)); 1331 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, VALIDf, 1); 1332 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, KEY_TYPEf, 1333 TR_VLXLT_HASH_KEY_TYPE_OTAG); 1334 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, OTAGf, config->pkt_vlan); 1335 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, MODULE_IDf, modid); 1336 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, PORT_NUMf, local_port); 1337 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, RPEf, 1); 1338 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, PRIf, config->int_pri); 1339 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, TAG_ACTION_PROFILE_PTRf, 1340 ing_profile_idx); 1341 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, NEW_OVIDf, ovid); 1342 1343 if (SOC_IS_TR_VL(unit)) { 1344 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, SOURCE_VPf, vp_base); /* group VP */ 1345 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, MPLS_ACTIONf, 1); /* L2 SVP */ 1346 } else if (SOC_IS_SC_CQ(unit)) { 1347 /* next hop index gets to L3 next hop directly */ 1348 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, NEW_IVID_SVPGf, nh_index); 1349 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, NEW_IVID_SVPG_SELf, 1); 1350 } 1351 1352 rv = soc_mem_insert_return_old(unit, VLAN_XLATEm, MEM_BLOCK_ALL, 1353 &ing_vent, &ing_vent); 1354 if (rv == SOC_E_EXISTS) { 1355 /* Delete the old vlan translate profile entry */ 1356 ing_profile_idx = soc_VLAN_XLATEm_field32_get(unit, &ing_vent, 1357 TAG_ACTION_PROFILE_PTRf); 1358 rv = _bcm_trx_vlan_action_profile_entry_delete(unit, ing_profile_idx); 1359 } 1360 if (rv < 0) { 1361 goto cleanup; 1362 } 1363 1364 if (SOC_IS_TR_VL(unit)) { 1365 _BCM_SUBPORT_ID_SET(unit, vp, l3_idx); 1366 } else if (SOC_IS_SC_CQ(unit)) { 1367 _BCM_SUBPORT_ID_SET(unit, (nh_index + config->int_pri), l3_idx); 1368 /*store the l3_idx for vp */ 1369 _sc_subport_port_l3idx_map[unit][nh_index + config->int_pri] = l3_idx; 1370 } 1371 1372 BCM_GPORT_SUBPORT_PORT_SET(*port, ((modid << 12) | l3_idx)); 1373 1374 #ifdef BCM_WARM_BOOT_SUPPORT 1375 SOC_CONTROL_LOCK(unit); 1376 SOC_CONTROL(unit)->scache_dirty = 1; 1377 SOC_CONTROL_UNLOCK(unit); 1378 #endif 1379 1380 return BCM_E_NONE; 1381 cleanup: 1382 if (l3_idx != -1) { 1383 BCM_L3_INTF_USED_CLR(unit, l3_idx); 1384 } 1385 return rv; 1386 } 1387 1388 STATIC int 1389 _bcm_tr_subport_port_delete(int unit, int l3_idx, int vp) 1390 { 1391 int rv, vp_base, vt_index, nh_index=-1; 1392 egr_l3_intf_entry_t l3_intf; 1393 ing_l3_next_hop_entry_t ing_nh; 1394 egr_l3_next_hop_entry_t egr_nh; 1395 egr_vlan_xlate_entry_t egr_vent; 1396 vlan_xlate_entry_t ing_vent; 1397 ing_dvp_table_entry_t dvp; 1398 bcm_port_t port = 0; 1399 bcm_module_t modid = 0; 1400 bcm_vlan_t pkt_vlan, ovid = 0; 1401 uint32 egr_profile_idx, ing_profile_idx, port_class = 0; 1402 1403 _TR_SUBPORT_CHECK_INIT(unit); 1404 1405 rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf); 1406 BCM_IF_ERROR_RETURN(rv); 1407 1408 /* Get the base group VP */ 1409 if (SOC_IS_SC_CQ(unit)) { 1410 vp_base = _sc_subport_group_vp_base[unit][vp]; 1411 } else { 1412 vp_base = vp & ~(0x7); 1413 } 1414 1415 if (SOC_IS_TR_VL(unit)) { 1416 /* Get the group's next-hop index */ 1417 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp); 1418 BCM_IF_ERROR_RETURN(rv); 1419 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 1420 /* Get the group's OVID from the group's egress next-hop entry */ 1421 rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, 1422 MEM_BLOCK_ALL, nh_index, &egr_nh); 1423 BCM_IF_ERROR_RETURN(rv); 1424 ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf); 1425 } else if (SOC_IS_SC_CQ(unit)) { 1426 int idx = vp_base / 8; 1427 nh_index = _sc_subport_group_index[unit][idx]; 1428 ovid = _sc_subport_group_ovid[unit][idx]; 1429 } 1430 1431 if (nh_index == -1) { 1432 return BCM_E_INTERNAL; 1433 } 1434 1435 /* Get the egress port class */ 1436 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1437 nh_index, &ing_nh)); 1438 if (!soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) { 1439 modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf); 1440 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf); 1441 rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress, 1442 &port_class); 1443 BCM_IF_ERROR_RETURN(rv); 1444 } 1445 1446 /* Find the egress vlan translate entry */ 1447 sal_memset(&egr_vent, 0, sizeof(egr_vent)); 1448 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, VALIDf, 1); 1449 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, OVIDf, ovid); 1450 if (SOC_IS_TR_VL(unit)) { 1451 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp); 1452 } else if (SOC_IS_SC_CQ(unit)) { 1453 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp); 1454 } 1455 1456 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, PORT_GROUP_IDf, port_class); 1457 1458 MEM_LOCK(unit, EGR_VLAN_XLATEm); 1459 rv = soc_mem_search(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &vt_index, 1460 &egr_vent, &egr_vent, 0); 1461 if (rv < 0) { 1462 MEM_UNLOCK(unit, EGR_VLAN_XLATEm); 1463 return rv; 1464 } 1465 1466 /* Get the old vlan translate profile entry */ 1467 egr_profile_idx = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent, 1468 TAG_ACTION_PROFILE_PTRf); 1469 1470 /* Delete the egress vlan translate entry */ 1471 rv = soc_mem_delete(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &egr_vent); 1472 MEM_UNLOCK(unit, EGR_VLAN_XLATEm); 1473 BCM_IF_ERROR_RETURN(rv); 1474 1475 /* Delete the old vlan translate profile entry */ 1476 rv = _bcm_trx_egr_vlan_action_profile_entry_delete(unit, egr_profile_idx); 1477 BCM_IF_ERROR_RETURN(rv); 1478 1479 /* Find vlan translate entry */ 1480 pkt_vlan = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent, NEW_OTAG_VPTAGf); 1481 sal_memset(&ing_vent, 0, sizeof(ing_vent)); 1482 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, VALIDf, 1); 1483 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, KEY_TYPEf, 1484 TR_VLXLT_HASH_KEY_TYPE_OTAG); 1485 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, OTAGf, pkt_vlan); 1486 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, MODULE_IDf, modid); 1487 soc_VLAN_XLATEm_field32_set(unit, &ing_vent, PORT_NUMf, port); 1488 1489 MEM_LOCK(unit, VLAN_XLATEm); 1490 rv = soc_mem_search(unit, VLAN_XLATEm, MEM_BLOCK_ALL, &vt_index, 1491 &ing_vent, &ing_vent, 0); 1492 if (rv < 0) { 1493 MEM_UNLOCK(unit, VLAN_XLATEm); 1494 return rv; 1495 } 1496 1497 /* Get the old vlan translate profile entry */ 1498 ing_profile_idx = soc_VLAN_XLATEm_field32_get(unit, &ing_vent, 1499 TAG_ACTION_PROFILE_PTRf); 1500 1501 /* Delete the ingress vlan translate entry */ 1502 rv = soc_mem_delete(unit, VLAN_XLATEm, MEM_BLOCK_ALL, &ing_vent); 1503 MEM_UNLOCK(unit, VLAN_XLATEm); 1504 BCM_IF_ERROR_RETURN(rv); 1505 1506 /* Delete the old vlan translate profile entry */ 1507 rv = _bcm_trx_vlan_action_profile_entry_delete(unit, ing_profile_idx); 1508 BCM_IF_ERROR_RETURN(rv); 1509 1510 /* Clear the EGR_L3_INTF entry */ 1511 sal_memset(&l3_intf, 0, sizeof(egr_l3_intf_entry_t)); 1512 rv = soc_mem_write(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf); 1513 1514 /* Free the L3_INTF index */ 1515 BCM_L3_INTF_USED_CLR(unit, l3_idx); 1516 1517 #ifdef BCM_TRIUMPH2_SUPPORT 1518 if (soc_feature(unit, soc_feature_gport_service_counters)) { 1519 bcm_gport_t gport; 1520 1521 /* Release Service counter, if any */ 1522 BCM_GPORT_SUBPORT_PORT_SET(gport, vp); 1523 _bcm_esw_flex_stat_handle_free(unit, _bcmFlexStatTypeGport, gport); 1524 } 1525 #endif 1526 1527 /* Clear the subport usage SW state */ 1528 _BCM_SUBPORT_ID_CLR(unit, vp); 1529 1530 #ifdef BCM_WARM_BOOT_SUPPORT 1531 SOC_CONTROL_LOCK(unit); 1532 SOC_CONTROL(unit)->scache_dirty = 1; 1533 SOC_CONTROL_UNLOCK(unit); 1534 #endif 1535 1536 return BCM_E_NONE; 1537 } 1538 1539 /* 1540 * Function: 1541 * bcm_subport_port_delete 1542 * Purpose: 1543 * Delete a subport 1544 * Parameters: 1545 * unit - (IN) Device Number 1546 * port - (IN) GPORT (generic port) identifier 1547 * Returns: 1548 * BCM_E_XXX 1549 */ 1550 int 1551 bcm_tr_subport_port_delete(int unit, bcm_gport_t port) 1552 { 1553 egr_l3_intf_entry_t l3_intf; 1554 int l3_idx, vp=-1, rv, is_modid_local; 1555 bcm_module_t modid; 1556 1557 _TR_SUBPORT_CHECK_INIT(unit); 1558 1559 modid = (BCM_GPORT_SUBPORT_PORT_GET(port) >> 12) & SOC_MODID_MAX(unit); 1560 BCM_IF_ERROR_RETURN( 1561 _bcm_esw_modid_is_local(unit, modid, &is_modid_local)); 1562 1563 if (TRUE != is_modid_local) { 1564 return BCM_E_PORT; 1565 } 1566 1567 l3_idx = BCM_GPORT_SUBPORT_PORT_GET(port) & 0xfff; 1568 if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 1569 return (BCM_E_PARAM); 1570 } 1571 1572 rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf); 1573 BCM_IF_ERROR_RETURN(rv); 1574 1575 1576 if (SOC_IS_TR_VL(unit)) { 1577 vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf); 1578 if (_BCM_SUBPORT_ID_GET(unit, vp) != l3_idx) { 1579 return BCM_E_NOT_FOUND; 1580 } 1581 } else if (SOC_IS_SC_CQ(unit)) { 1582 /* IVIDf in Scorpion can not be used for vp */ 1583 1584 for (vp = 0; vp < SUBPORT_NUM_VP; vp++) { 1585 if (l3_idx == _BCM_SUBPORT_ID_GET(unit, vp)) { 1586 break; 1587 } 1588 } 1589 if (vp == SUBPORT_NUM_VP) { 1590 return BCM_E_NOT_FOUND; 1591 } 1592 } 1593 1594 if (vp == -1) { 1595 return BCM_E_INTERNAL; 1596 } 1597 1598 return _bcm_tr_subport_port_delete(unit, l3_idx, vp); 1599 } 1600 1601 STATIC int 1602 _bcm_tr_subport_port_get(int unit, int l3_idx, 1603 bcm_subport_config_t *config) 1604 { 1605 int index, vp=-1, rv, vp_base, nh_index=-1; 1606 egr_l3_intf_entry_t l3_intf; 1607 ing_l3_next_hop_entry_t ing_nh; 1608 egr_l3_next_hop_entry_t egr_nh; 1609 egr_vlan_xlate_entry_t egr_vent; 1610 ing_dvp_table_entry_t dvp; 1611 bcm_port_t port = 0; 1612 bcm_vlan_t ovid = 0; 1613 uint32 port_class = 0; 1614 1615 rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf); 1616 BCM_IF_ERROR_RETURN(rv); 1617 1618 if (SOC_IS_TR_VL(unit)) { 1619 vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf); 1620 if (_BCM_SUBPORT_ID_GET(unit, vp) != l3_idx) { 1621 return BCM_E_NOT_FOUND; 1622 } 1623 } else if (SOC_IS_SC_CQ(unit)) { 1624 /* IVIDf in Scorpion can not be used for vp */ 1625 for (vp = 0; vp < SUBPORT_NUM_VP; vp++) { 1626 if (_sc_subport_port_l3idx_map[unit][vp] == l3_idx) { 1627 break; 1628 } 1629 } 1630 if (vp == SUBPORT_NUM_VP) { 1631 return BCM_E_NOT_FOUND; 1632 } 1633 } 1634 1635 /* Get the base group VP */ 1636 if (SOC_IS_SC_CQ(unit)) { 1637 vp_base = _sc_subport_group_vp_base[unit][vp]; 1638 } else { 1639 /* Get the base group VP */ 1640 vp_base = vp & ~(0x7); 1641 } 1642 1643 /* Get the group's next-hop index */ 1644 if (SOC_IS_TR_VL(unit)) { 1645 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp); 1646 BCM_IF_ERROR_RETURN(rv); 1647 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 1648 /* Get the group's OVID from the group's egress next-hop entry */ 1649 rv = soc_mem_read(unit, EGR_L3_NEXT_HOPm, 1650 MEM_BLOCK_ALL, nh_index, &egr_nh); 1651 BCM_IF_ERROR_RETURN(rv); 1652 ovid = soc_mem_field32_get(unit, EGR_L3_NEXT_HOPm, &egr_nh, OVIDf); 1653 } else if (SOC_IS_SC_CQ(unit)) { 1654 int idx = vp_base / 8; 1655 nh_index = _sc_subport_group_index[unit][idx]; 1656 ovid = _sc_subport_group_ovid[unit][idx]; 1657 } 1658 1659 if (nh_index == -1) { 1660 return BCM_E_INTERNAL; 1661 } 1662 1663 /* Get the egress port class */ 1664 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1665 nh_index, &ing_nh)); 1666 if (!soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) { 1667 port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf); 1668 rv = bcm_esw_port_class_get(unit, port, bcmPortClassVlanTranslateEgress, 1669 &port_class); 1670 BCM_IF_ERROR_RETURN(rv); 1671 } 1672 1673 /* Find the egress vlan translate entry */ 1674 sal_memset(&egr_vent, 0, sizeof(egr_vent)); 1675 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, VALIDf, 1); 1676 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, OVIDf, ovid); 1677 1678 if (SOC_IS_TR_VL(unit)) { 1679 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp); 1680 } else if (SOC_IS_SC_CQ(unit)) { 1681 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, IVIDf, vp); 1682 } 1683 soc_EGR_VLAN_XLATEm_field32_set(unit, &egr_vent, PORT_GROUP_IDf, port_class); 1684 1685 MEM_LOCK(unit, EGR_VLAN_XLATEm); 1686 rv = soc_mem_search(unit, EGR_VLAN_XLATEm, MEM_BLOCK_ALL, &index, 1687 &egr_vent, &egr_vent, 0); 1688 if (rv < 0) { 1689 MEM_UNLOCK(unit, EGR_VLAN_XLATEm); 1690 return rv; 1691 } 1692 1693 /* Set the config data to be returned */ 1694 BCM_GPORT_SUBPORT_GROUP_SET(config->group, vp_base); 1695 config->pkt_vlan = soc_EGR_VLAN_XLATEm_field32_get(unit, &egr_vent, NEW_OTAG_VPTAGf); 1696 if (SOC_IS_SC_CQ(unit)) { 1697 config->int_pri = (vp & (~nh_index)); 1698 } else { 1699 config->int_pri = vp & 0x7; 1700 } 1701 return BCM_E_NONE; 1702 } 1703 1704 /* 1705 * Function: 1706 * bcm_subport_port_get 1707 * Purpose: 1708 * Get a subport 1709 * Parameters: 1710 * unit - (IN) Device Number 1711 * port - (IN) GPORT (generic port) identifier 1712 * config - (OUT) Subport config information 1713 * Returns: 1714 * BCM_E_XXX 1715 */ 1716 int 1717 bcm_tr_subport_port_get(int unit, bcm_gport_t port, 1718 bcm_subport_config_t *config) 1719 { 1720 int l3_idx, is_modid_local; 1721 bcm_module_t modid; 1722 1723 _TR_SUBPORT_CHECK_INIT(unit); 1724 1725 if (config == NULL) { 1726 return BCM_E_PARAM; 1727 } 1728 1729 modid = (BCM_GPORT_SUBPORT_PORT_GET(port) >> 12) & SOC_MODID_MAX(unit); 1730 BCM_IF_ERROR_RETURN( 1731 _bcm_esw_modid_is_local(unit, modid, &is_modid_local)); 1732 1733 if (TRUE != is_modid_local) { 1734 return BCM_E_PORT; 1735 } 1736 1737 l3_idx = BCM_GPORT_SUBPORT_PORT_GET(port) & 0xfff; 1738 if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 1739 return (BCM_E_PARAM); 1740 } 1741 1742 return _bcm_tr_subport_port_get(unit, l3_idx, config); 1743 } 1744 1745 /* 1746 * Function: 1747 * bcm_subport_port_traverse 1748 * Purpose: 1749 * Traverse all valid subports and call the 1750 * supplied callback routine. 1751 * Parameters: 1752 * unit - Device Number 1753 * cb - User callback function, called once per subport. 1754 * user_data - cookie 1755 * Returns: 1756 * BCM_E_XXX 1757 */ 1758 int 1759 bcm_tr_subport_port_traverse(int unit, 1760 bcm_subport_port_traverse_cb cb, 1761 void *user_data) 1762 { 1763 int rv, vp, l3_idx; 1764 bcm_subport_config_t config; 1765 bcm_gport_t gport; 1766 bcm_module_t my_modid; 1767 1768 _TR_SUBPORT_CHECK_INIT(unit); 1769 1770 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 1771 1772 for (vp = 0; vp < SUBPORT_NUM_VP; vp++) { 1773 l3_idx = _BCM_SUBPORT_ID_GET(unit, vp); 1774 if (l3_idx != 0xffff) { 1775 rv = _bcm_tr_subport_port_get(unit, l3_idx, &config); 1776 BCM_IF_ERROR_RETURN(rv); 1777 1778 BCM_GPORT_SUBPORT_PORT_SET(gport, ((my_modid << 12) | l3_idx)); 1779 /* coverity[dead_error_begin] */ 1780 rv = cb(unit, gport, &config, user_data); 1781 /* coverity[dead_error_begin] */ 1782 #ifdef BCM_CB_ABORT_ON_ERR 1783 if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) { 1784 return rv; 1785 } 1786 #endif 1787 } 1788 } 1789 return BCM_E_NONE; 1790 } 1791 1792 /* 1793 * Function: 1794 * _bcm_tr_subport_group_resolve 1795 * Purpose: 1796 * Get the modid, port, trunk values for a subport group GPORT 1797 * Returns: 1798 * BCM_E_XXX 1799 */ 1800 int 1801 _bcm_tr_subport_group_resolve(int unit, bcm_gport_t gport, 1802 bcm_module_t *modid, bcm_port_t *port, 1803 bcm_trunk_t *trunk_id, int *id) 1804 { 1805 int rv = BCM_E_NONE; 1806 ing_l3_next_hop_entry_t ing_nh; 1807 ing_dvp_table_entry_t dvp; 1808 int nh_index, vp_base; 1809 1810 _TR_SUBPORT_CHECK_INIT(unit); 1811 1812 vp_base = BCM_GPORT_SUBPORT_GROUP_GET(gport); 1813 if (vp_base == -1) { 1814 return BCM_E_PARAM; 1815 } 1816 1817 if (SOC_IS_TR_VL(unit)) { 1818 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp); 1819 BCM_IF_ERROR_RETURN(rv); 1820 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 1821 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1822 nh_index, &ing_nh)); 1823 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) { 1824 /* Entry type is not GPON DVP */ 1825 return BCM_E_NOT_FOUND; 1826 } 1827 } else if (SOC_IS_SC_CQ(unit)) { 1828 if (_BCM_GROUP_USED_GET(unit, (vp_base/8)) == 0) { 1829 return BCM_E_NOT_FOUND; 1830 } 1831 nh_index = _sc_subport_group_index[unit][vp_base/8]; 1832 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1833 nh_index, &ing_nh)); 1834 } 1835 1836 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) { 1837 *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf); 1838 } else { 1839 *modid = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, MODULE_IDf); 1840 *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf); 1841 } 1842 *id = vp_base; 1843 return rv; 1844 } 1845 1846 /* 1847 * Function: 1848 * _bcm_tr_subport_port_resolve 1849 * Purpose: 1850 * Get the modid, port, trunk values for a subport port GPORT 1851 * Returns: 1852 * BCM_E_XXX 1853 */ 1854 int 1855 _bcm_tr_subport_port_resolve(int unit, bcm_gport_t gport, 1856 bcm_module_t *modid, bcm_port_t *port, 1857 bcm_trunk_t *trunk_id, int *id) 1858 { 1859 int rv = BCM_E_NONE, l3_idx; 1860 ing_l3_next_hop_entry_t ing_nh; 1861 egr_l3_intf_entry_t l3_intf; 1862 ing_dvp_table_entry_t dvp; 1863 int nh_index, vp, vp_base, is_modid_local; 1864 1865 _TR_SUBPORT_CHECK_INIT(unit); 1866 1867 *id = BCM_GPORT_SUBPORT_PORT_GET(gport); 1868 *modid = (*id >> 12) & SOC_MODID_MAX(unit); 1869 1870 BCM_IF_ERROR_RETURN( 1871 _bcm_esw_modid_is_local(unit, *modid, &is_modid_local)); 1872 1873 if (TRUE != is_modid_local) { 1874 return (BCM_E_PORT); 1875 } 1876 1877 l3_idx = BCM_GPORT_SUBPORT_PORT_GET(gport) & 0xfff; 1878 if (l3_idx >= BCM_XGS3_L3_IF_TBL_SIZE(unit)) { 1879 return (BCM_E_PARAM); 1880 } 1881 rv = soc_mem_read(unit, EGR_L3_INTFm, MEM_BLOCK_ALL, l3_idx, &l3_intf); 1882 BCM_IF_ERROR_RETURN(rv); 1883 1884 1885 if (SOC_IS_TR_VL(unit)) { 1886 vp = soc_mem_field32_get(unit, EGR_L3_INTFm, &l3_intf, IVIDf); 1887 vp_base = vp & ~(0x7); 1888 rv = READ_ING_DVP_TABLEm(unit, MEM_BLOCK_ALL, vp_base, &dvp); 1889 BCM_IF_ERROR_RETURN(rv); 1890 nh_index = soc_ING_DVP_TABLEm_field32_get(unit, &dvp, NEXT_HOP_INDEXf); 1891 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1892 nh_index, &ing_nh)); 1893 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, ENTRY_TYPEf) != 0x3) { 1894 /* Entry type is not GPON DVP */ 1895 return BCM_E_NOT_FOUND; 1896 } 1897 } else if (SOC_IS_SC_CQ(unit)) { 1898 /* IVIDf in Scorpion can not be used for vp */ 1899 1900 for (vp = 0; vp < SUBPORT_NUM_VP; vp++) { 1901 if (l3_idx == _BCM_SUBPORT_ID_GET(unit, vp)) { 1902 break; 1903 } 1904 } 1905 if (vp == SUBPORT_NUM_VP) { 1906 return BCM_E_NOT_FOUND; 1907 } 1908 vp_base = vp & ~(0x7); 1909 nh_index = _sc_subport_group_index[unit][vp_base/8]; 1910 BCM_IF_ERROR_RETURN (soc_mem_read(unit, ING_L3_NEXT_HOPm, MEM_BLOCK_ANY, 1911 nh_index, &ing_nh)); 1912 } 1913 1914 if (soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, Tf)) { 1915 *trunk_id = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, TGIDf); 1916 } else { 1917 *port = soc_ING_L3_NEXT_HOPm_field32_get(unit, &ing_nh, PORT_NUMf); 1918 } 1919 return rv; 1920 } 1921 1922 /* 1923 * Function: 1924 * bcm_tr_subport_learn_set 1925 * Purpose: 1926 * Set the CML bits for a subport group. 1927 * Returns: 1928 * BCM_E_XXX 1929 */ 1930 int 1931 bcm_tr_subport_learn_set(int unit, bcm_gport_t group, uint32 flags) 1932 { 1933 int vp_base, cml = 0, rv = BCM_E_NONE; 1934 source_vp_entry_t svp; 1935 1936 _TR_SUBPORT_CHECK_INIT(unit); 1937 1938 cml = 0; 1939 if (!(flags & BCM_PORT_LEARN_FWD)) { 1940 cml |= (1 << 0); 1941 } 1942 if (flags & BCM_PORT_LEARN_CPU) { 1943 cml |= (1 << 1); 1944 } 1945 if (flags & BCM_PORT_LEARN_PENDING) { 1946 cml |= (1 << 2); 1947 } 1948 if (flags & BCM_PORT_LEARN_ARL) { 1949 cml |= (1 << 3); 1950 } 1951 1952 vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 1953 if (vp_base == -1) { 1954 return BCM_E_PARAM; 1955 } 1956 1957 if (!_BCM_GROUP_USED_GET(unit, vp_base / 8)) { 1958 return BCM_E_NOT_FOUND; 1959 } 1960 MEM_LOCK(unit, SOURCE_VPm); 1961 rv = READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp); 1962 if (soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf) != 0x3) { 1963 MEM_UNLOCK(unit, SOURCE_VPm); 1964 return BCM_E_INTERNAL; 1965 } 1966 soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_MOVEf, cml); 1967 soc_SOURCE_VPm_field32_set(unit, &svp, CML_FLAGS_NEWf, cml); 1968 rv = WRITE_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp); 1969 MEM_UNLOCK(unit, SOURCE_VPm); 1970 return rv; 1971 } 1972 1973 /* 1974 * Function: 1975 * bcm_tr_subport_learn_get 1976 * Purpose: 1977 * Get the CML bits for a subport group. 1978 * Returns: 1979 * BCM_E_XXX 1980 */ 1981 int 1982 bcm_tr_subport_learn_get(int unit, bcm_gport_t group, uint32 *flags) 1983 { 1984 int vp_base, cml; 1985 source_vp_entry_t svp; 1986 1987 _TR_SUBPORT_CHECK_INIT(unit); 1988 1989 vp_base = BCM_GPORT_SUBPORT_GROUP_GET(group); 1990 if (vp_base == -1) { 1991 return BCM_E_PARAM; 1992 } 1993 1994 if (!_BCM_GROUP_USED_GET(unit, vp_base / 8)) { 1995 return BCM_E_NOT_FOUND; 1996 } 1997 BCM_IF_ERROR_RETURN 1998 (READ_SOURCE_VPm(unit, MEM_BLOCK_ALL, vp_base, &svp)); 1999 if (soc_SOURCE_VPm_field32_get(unit, &svp, ENTRY_TYPEf) != 0x3) { 2000 return BCM_E_INTERNAL; 2001 } 2002 cml = soc_SOURCE_VPm_field32_get(unit, &svp, CML_FLAGS_NEWf); 2003 2004 *flags = 0; 2005 if (!(cml & (1 << 0))) { 2006 *flags |= BCM_PORT_LEARN_FWD; 2007 } 2008 if (cml & (1 << 1)) { 2009 *flags |= BCM_PORT_LEARN_CPU; 2010 } 2011 if (cml & (1 << 2)) { 2012 *flags |= BCM_PORT_LEARN_PENDING; 2013 } 2014 if (cml & (1 << 3)) { 2015 *flags |= BCM_PORT_LEARN_ARL; 2016 } 2017 2018 return BCM_E_NONE; 2019 } 2020 2021 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP 2022 /* 2023 * Function: 2024 * _bcm_tr_subport_sw_dump 2025 * Purpose: 2026 * Print Subport module s/w state 2027 * Returns: 2028 * void 2029 */ 2030 void 2031 _bcm_tr_subport_sw_dump(int unit) 2032 { 2033 int idx, sub_prt; 2034 2035 if(BCM_ESW_SUBPORT_DRV(unit) == NULL) { 2036 LOG_CLI((BSL_META_U(unit, 2037 "\nSubport DRV function is not initialized\n"))); 2038 return; 2039 } 2040 LOG_CLI((BSL_META_U(unit, 2041 "Subport Groups:\n"))); 2042 for(idx = 0; idx < SUBPORT_NUM_GROUP; idx++) { 2043 if(_BCM_GROUP_USED_GET(unit, idx)) { 2044 LOG_CLI((BSL_META_U(unit, 2045 "%d "), idx)); 2046 } 2047 } 2048 2049 LOG_CLI((BSL_META_U(unit, 2050 "\n----\n"))); 2051 2052 LOG_CLI((BSL_META_U(unit, 2053 "Subport IDs used:\n"))); 2054 for(idx = 0; idx < SUBPORT_NUM_VP; idx++) { 2055 if((sub_prt = _BCM_SUBPORT_ID_GET(unit, idx)) != 0xffff) { 2056 LOG_CLI((BSL_META_U(unit, 2057 "Subport ID=%d, VP=%d \n"), sub_prt, idx)); 2058 } 2059 } 2060 } 2061 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */ 2062 2063 #else /* INCLUDE_L3 && BCM_TRX_SUPPORT */ 2064 int bcm_esw_triumph_subport_not_empty; 2065 #endif /* INCLUDE_L3 && BCM_TRX_SUPPORT */