stg.c (46052B)
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: stg.c 8 * Purpose: Spanning tree group support 9 * 10 * Multiple spanning trees (MST) is supported in 11 * BCM5690, etc. STGs are created and VLANs may be added to each STG. 12 * 13 * Per-VLAN spanning tree (PVST) is supported in BCM5632. This module 14 * supports PVST on BCM5632 by having 4k virtual STGs and allowing only 15 * a single VLAN per STG. Before the application can create a second 16 * STG, it must remove all but one VLAN from the default STG. 17 */ 18 19 #include <shared/bsl.h> 20 21 #include <shared/bitop.h> 22 23 #include <sal/core/libc.h> 24 25 #include <soc/drv.h> 26 #include <soc/scache.h> 27 #include <soc/ptable.h> 28 29 #include <bcm/error.h> 30 #include <bcm/stg.h> 31 32 #include <bcm_int/common/lock.h> 33 #include <bcm_int/control.h> 34 #include <bcm_int/esw/mbcm.h> 35 #include <bcm_int/esw/stg.h> 36 #ifdef BCM_WARM_BOOT_SUPPORT 37 #include <bcm_int/esw/switch.h> 38 #endif /* BCM_WARM_BOOT_SUPPORT */ 39 40 #include <bcm_int/esw_dispatch.h> 41 #if defined(BCM_KATANA2_SUPPORT) 42 #include <bcm_int/esw/katana2.h> 43 #endif 44 #ifdef BCM_TRIDENT2PLUS_SUPPORT 45 #include <bcm_int/esw/trident2plus.h> 46 #endif 47 48 /* 49 * The STG info structure is protected by BCM_LOCK. 50 * The hardware PTABLE and hardware STG table are protected by 51 * memory locks in the lower level. 52 */ 53 54 typedef struct bcm_stg_info_s { 55 int init; /* TRUE if STG module has been initialized */ 56 soc_mem_t stg_mem; /* STG table memory, INVALIDm if none */ 57 bcm_stg_t stg_min; /* STG table min index */ 58 bcm_stg_t stg_max; /* STG table max index */ 59 bcm_stg_t stg_defl; /* Default STG */ 60 SHR_BITDCL *stg_bitmap; /* Bitmap of allocated STGs */ 61 int stg_count; /* Number STGs allocated */ 62 63 /* 64 * STG map - keep a linked list of VLANs in each STG. 65 */ 66 bcm_vlan_t *vlan_first; /* Indexed by STG (also links free list) */ 67 bcm_vlan_t *vlan_next; /* Indexed by VLAN ID */ 68 } bcm_stg_info_t; 69 70 static bcm_stg_info_t stg_info[BCM_MAX_NUM_UNITS]; 71 72 #define CHECK_INIT(unit, si) do { \ 73 if (!SOC_UNIT_VALID(unit)) return BCM_E_UNIT; \ 74 if (si->init == 0) return BCM_E_INIT; \ 75 if (si->init < 0) return si->init; \ 76 } while (0); 77 78 79 #define CHECK_STG(si, stg) \ 80 if ((stg) < 0 || (stg) > si->stg_max) \ 81 return BCM_E_BADID 82 83 /* 84 * Allocation bitmap macros 85 */ 86 #define STG_BITMAP_TST(si, stg) SHR_BITGET(si->stg_bitmap, stg) 87 #define STG_BITMAP_SET(si, stg) SHR_BITSET(si->stg_bitmap, stg) 88 #define STG_BITMAP_CLR(si, stg) SHR_BITCLR(si->stg_bitmap, stg) 89 90 /* 91 * STG-to-VLAN Reverse Map 92 * 93 * The Spanning Tree Group map is a data structure that forms one 94 * linked list per spanning tree group to keep track of all the VLANs 95 * in each Spanning Tree Group. Otherwise, to answer the question 96 * 'what VLANs are in STG x' would require searching all 4k entries of 97 * the hardware VLAN table. 98 * 99 * vlan_first[stg_num] is the number of the first VLAN in STG stg_num. 100 * 101 * vlan_next[vlan_id] has one entry per VLAN ID and contains the number 102 * of the next VLAN in the STG that contains vlan_id. 103 */ 104 105 /* 106 * Function: 107 * _bcm_vlan_vfi_index_get(internal) 108 * Purpose: 109 * Transform vlan/vpn to vlan/vfi index 110 */ 111 STATIC uint32 112 _bcm_stg_vlan_vfi_get(int vlan_vpn) 113 { 114 uint32 vlan_vfi = -1; 115 116 #ifdef BCM_TRIDENT2PLUS_SUPPORT 117 if (_BCM_VPN_VFI_IS_SET(vlan_vpn)) { 118 _BCM_VPN_GET(vlan_vfi, _BCM_VPN_TYPE_VFI, vlan_vpn); 119 vlan_vfi += BCM_VLAN_COUNT; 120 } else 121 #endif 122 { 123 vlan_vfi = vlan_vpn; 124 } 125 126 return vlan_vfi; 127 } 128 129 /* 130 * Function: 131 * _bcm_stg_vlan_vpn_get(internal) 132 * Purpose: 133 * Transform vlan/vfi index to vlan/vpn 134 */ 135 STATIC uint32 136 _bcm_stg_vlan_vpn_get(int vlan_vfi) 137 { 138 uint32 vlan_vpn = -1; 139 140 #ifdef BCM_TRIDENT2PLUS_SUPPORT 141 if (vlan_vfi > BCM_VLAN_MAX) { 142 vlan_vpn = vlan_vfi - BCM_VLAN_COUNT; 143 _BCM_VPN_SET(vlan_vpn, _BCM_VPN_TYPE_VFI, vlan_vpn); 144 } else 145 #endif 146 { 147 vlan_vpn = vlan_vfi; 148 } 149 150 return vlan_vpn; 151 } 152 153 /* 154 * Function: 155 * _bcm_stg_vlan_vfi_count_get(internal) 156 * Purpose: 157 * Get vlan and vfi count 158 */ 159 STATIC uint32 160 _bcm_stg_vlan_vfi_count_get(int unit) 161 { 162 int count = BCM_VLAN_COUNT; 163 164 #ifdef BCM_TRIDENT2PLUS_SUPPORT 165 if (soc_feature(unit, soc_feature_vlan_vfi_membership)) { 166 count += soc_mem_index_count(unit, VFIm); 167 } 168 #endif 169 170 return count; 171 } 172 173 #ifdef BROADCOM_DEBUG 174 175 /* 176 * Function: 177 * _bcm_stg_map_check (internal) 178 * Purpose: 179 * Return TRUE if STG contains VLAN 180 */ 181 int 182 _bcm_stg_map_check(int unit, bcm_stg_t stg, bcm_vlan_t vid) 183 { 184 bcm_stg_info_t *si = &stg_info[unit]; 185 bcm_vlan_t v = si->vlan_first[stg]; 186 int vlan_vfi = _bcm_stg_vlan_vfi_get(vid); 187 int vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 188 189 while (v != vlan_vfi_count) { 190 if (v == vlan_vfi) { 191 return TRUE; 192 } else { 193 v = si->vlan_next[v]; 194 } 195 } 196 197 return FALSE; 198 } 199 200 #endif /* BROADCOM_DEBUG */ 201 202 /* 203 * Function: 204 * _bcm_stg_map_add (internal) 205 * Purpose: 206 * Add VLAN to STG linked list 207 */ 208 209 STATIC void 210 _bcm_stg_map_add(int unit, bcm_stg_t stg, bcm_vlan_t vid) 211 { 212 bcm_stg_info_t *si = &stg_info[unit]; 213 int vlan_vfi = _bcm_stg_vlan_vfi_get(vid); 214 215 si->vlan_next[vlan_vfi] = si->vlan_first[stg]; 216 si->vlan_first[stg] = vlan_vfi; 217 } 218 219 /* 220 * Function: 221 * _bcm_stg_map_delete (internal) 222 * Purpose: 223 * Remove VLAN from STG linked list; return boolean TRUE if found 224 */ 225 226 STATIC void 227 _bcm_stg_map_delete(int unit, bcm_stg_t stg, bcm_vlan_t vid) 228 { 229 bcm_stg_info_t *si = &stg_info[unit]; 230 bcm_vlan_t *vp; 231 int vlan_vfi = _bcm_stg_vlan_vfi_get(vid); 232 int vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 233 234 vp = &si->vlan_first[stg]; 235 while (*vp != vlan_vfi_count) { 236 if (*vp == vlan_vfi) { 237 *vp = si->vlan_next[*vp]; 238 } else { 239 vp = &si->vlan_next[*vp]; 240 } 241 } 242 } 243 244 #if defined (BCM_EASY_RELOAD_SUPPORT) 245 /* 246 * Function: 247 * _bcm_stg_map_get (internal) 248 * Purpose: 249 * Given a VLAN with vid, return the STG 250 */ 251 252 STATIC bcm_stg_t 253 _bcm_stg_map_get(int unit, bcm_vlan_t vid) 254 { 255 bcm_stg_t stg = BCM_STG_DEFAULT; 256 bcm_stg_info_t *si = &stg_info[unit]; 257 bcm_vlan_t *vp; 258 int vlan_vfi = _bcm_stg_vlan_vfi_get(vid); 259 int vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 260 261 for (stg = si->stg_min; stg <= si->stg_max; stg++) { 262 vp = &si->vlan_first[stg]; 263 while (*vp != vlan_vfi_count) { 264 if (*vp == vlan_vfi) { 265 return stg; 266 } else { 267 vp = &si->vlan_next[*vp]; 268 } 269 } 270 } 271 return BCM_STG_DEFAULT; 272 } 273 #endif 274 275 /* 276 * Function: 277 * _bcm_stg_pvp_translate (internal) 278 * Purpose: 279 * Translate from hardware PVP_xxx state to BCM_STG_STP_xxx state 280 * Parameters: 281 * unit - (IN) Bcm device number. 282 * pvp_state - (IN) HW STP state encoding. 283 * bcm_state - (OUT) API STP state. 284 * Return: 285 * BCM_E_XXX 286 */ 287 288 int 289 _bcm_stg_pvp_translate(int unit, int pvp_state, int *bcm_state) 290 { 291 COMPILER_REFERENCE(unit); 292 293 if (NULL == bcm_state) { 294 return (BCM_E_PARAM); 295 } 296 297 switch (pvp_state) { 298 case PVP_STP_FORWARDING: 299 *bcm_state = BCM_STG_STP_FORWARD; 300 break; 301 case PVP_STP_BLOCKING: 302 *bcm_state = BCM_STG_STP_BLOCK; 303 break; 304 case PVP_STP_LEARNING: 305 *bcm_state = BCM_STG_STP_LEARN; 306 break; 307 case PVP_STP_DISABLED: 308 *bcm_state = BCM_STG_STP_DISABLE; 309 break; 310 default: 311 return (BCM_E_INTERNAL); 312 } 313 return (BCM_E_NONE); 314 } 315 316 /* 317 * Function: 318 * _bcm_stg_stp_translate (internal) 319 * Purpose: 320 * Translate from BCM_STG_STP_xxx state to hardware PVP_xxx state 321 * Parameters: 322 * unit - (IN) Bcm device number. 323 * bcm_state - (IN) API STP state. 324 * pvp_state - (OUT) HW STP state encoding. 325 * Return: 326 * BCM_E_XXX 327 */ 328 329 int 330 _bcm_stg_stp_translate(int unit, int bcm_state, int *pvp_state) 331 { 332 COMPILER_REFERENCE(unit); 333 334 if (NULL == pvp_state) { 335 return (BCM_E_PARAM); 336 } 337 338 switch (bcm_state) { 339 case BCM_STG_STP_FORWARD: 340 *pvp_state = PVP_STP_FORWARDING; 341 break; 342 case BCM_STG_STP_LISTEN: 343 case BCM_STG_STP_BLOCK: 344 *pvp_state = PVP_STP_BLOCKING; 345 break; 346 case BCM_STG_STP_LEARN: 347 *pvp_state = PVP_STP_LEARNING; 348 break; 349 case BCM_STG_STP_DISABLE: 350 *pvp_state = PVP_STP_DISABLED; 351 break; 352 default: 353 return (BCM_E_PARAM); 354 } 355 return (BCM_E_NONE); 356 } 357 358 /* 359 * Function: 360 * _bcm_stg_vid_compar 361 * Purpose: 362 * Internal utility routine for sorting on VLAN ID. 363 */ 364 365 STATIC int 366 _bcm_stg_vid_compar(void *a, void *b) 367 { 368 uint16 a16, b16; 369 370 a16 = *(uint16 *)a; 371 b16 = *(uint16 *)b; 372 373 if (a16 < b16) { 374 return -1; 375 } 376 377 if (a16 > b16) { 378 return 1; 379 } 380 381 return 0; 382 } 383 384 /* 385 * Function: 386 * bcm_stg_vlan_list 387 * Purpose: 388 * Return a list of VLANs in a specified STG. 389 * Parameters: 390 * unit - StrataSwitch PCI device unit number 391 * stg - STG ID to list 392 * list - Place where pointer to return array will be stored, 393 * which will be NULL if there are zero VLANs returned. 394 * count - Place where number of entries in array will be stored, 395 * which will be 0 if there are zero VLANs returned. 396 * Returns: 397 * BCM_E_XXX 398 * Notes: 399 * The caller is responsible for freeing the memory that is 400 * returned, using bcm_stg_vlan_list_destroy(). 401 */ 402 403 int 404 bcm_esw_stg_vlan_list(int unit, bcm_stg_t stg, bcm_vlan_t **list, int *count) 405 { 406 bcm_stg_info_t *si = &stg_info[unit]; 407 bcm_vlan_t v; 408 int n; 409 int vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 410 411 CHECK_INIT(unit, si); 412 CHECK_STG(si, stg); 413 414 BCM_LOCK(unit); 415 if (!STG_BITMAP_TST(si, stg)) { 416 BCM_UNLOCK(unit); 417 return BCM_E_NOT_FOUND; 418 } 419 420 *list = NULL; 421 *count = 0; 422 423 /* Traverse list once just to get an allocation count */ 424 if (si->stg_mem == INVALIDm) { /* Strata1 */ 425 (*count) = 4096; 426 } else { 427 v = si->vlan_first[stg]; 428 429 while (v != vlan_vfi_count) { 430 (*count)++; 431 v = si->vlan_next[v]; 432 } 433 434 if (*count == 0) { 435 BCM_UNLOCK(unit); 436 return BCM_E_NONE; /* Return empty list */ 437 } 438 } 439 440 *list = sal_alloc(*count * sizeof (bcm_vlan_t), "bcm_stg_vlan_list"); 441 if (*list == NULL) { 442 BCM_UNLOCK(unit); 443 return BCM_E_MEMORY; 444 } 445 446 /* Traverse list a second time to record the VLANs */ 447 if (si->stg_mem == INVALIDm) { /* Strata1 */ 448 for (n = 0; n < 4096; n++) { 449 (*list)[n] = n; 450 } 451 } else { 452 v = si->vlan_first[stg]; 453 n = 0; 454 455 while (v != vlan_vfi_count) { 456 (*list)[n++] = _bcm_stg_vlan_vpn_get(v); 457 v = si->vlan_next[v]; 458 } 459 } 460 461 BCM_UNLOCK(unit); 462 463 _shr_sort(*list, *count, sizeof (bcm_vlan_t), _bcm_stg_vid_compar); 464 465 return BCM_E_NONE; 466 } 467 468 /* 469 * Function: 470 * bcm_stg_vlan_list_destroy 471 * Purpose: 472 * Destroy a list returned by bcm_stg_vlan_list. 473 * Parameters: 474 * unit - StrataSwitch PCI device unit number 475 * list - Pointer to VLAN array to be destroyed. 476 * count - Number of entries in array. 477 * Returns: 478 * BCM_E_XXX 479 */ 480 481 int 482 bcm_esw_stg_vlan_list_destroy(int unit, bcm_vlan_t *list, int count) 483 { 484 COMPILER_REFERENCE(unit); 485 COMPILER_REFERENCE(count); 486 487 if (list != NULL) { 488 sal_free(list); 489 } 490 491 return BCM_E_NONE; 492 } 493 494 /* 495 * Function: 496 * bcm_stg_default_get 497 * Purpose: 498 * Returns the default STG for the chip, usually 0 or 1 depending 499 * on the architecture. 500 * Parameters: 501 * unit - StrataSwitch PCI device unit number. 502 * stg_ptr - (OUT) STG ID for default. 503 * Returns: 504 * BCM_E_XXX 505 */ 506 507 int 508 bcm_esw_stg_default_get(int unit, bcm_stg_t *stg_ptr) 509 { 510 bcm_stg_info_t *si = &stg_info[unit]; 511 512 CHECK_INIT(unit, si); 513 514 *stg_ptr = si->stg_defl; 515 516 return BCM_E_NONE; 517 } 518 519 /* 520 * Function: 521 * bcm_stg_default_set 522 * Purpose: 523 * Changes the default STG for the chip. 524 * Parameters: 525 * unit - StrataSwitch PCI device unit number. 526 * stg - STG ID to become default. 527 * Returns: 528 * BCM_E_XXX 529 * Notes: 530 * The specified STG must already exist. 531 */ 532 533 int 534 bcm_esw_stg_default_set(int unit, bcm_stg_t stg) 535 { 536 bcm_stg_info_t *si = &stg_info[unit]; 537 538 CHECK_INIT(unit, si); 539 CHECK_STG(si, stg); 540 541 BCM_LOCK(unit); 542 543 if (!STG_BITMAP_TST(si, stg)) { 544 BCM_UNLOCK(unit); 545 return BCM_E_NOT_FOUND; 546 } 547 548 si->stg_defl = stg; 549 550 #ifdef BCM_WARM_BOOT_SUPPORT 551 SOC_CONTROL_LOCK(unit); 552 SOC_CONTROL(unit)->scache_dirty = 1; 553 SOC_CONTROL_UNLOCK(unit); 554 #endif 555 556 BCM_UNLOCK(unit); 557 558 return BCM_E_NONE; 559 } 560 561 /* Function: 562 * _bcm_stg_mstp_vlan_update 563 * Purpose: 564 * For systems with MSTP mask, update the mask info for the VLAN. 565 */ 566 STATIC int 567 _bcm_stg_mstp_vlan_update(int unit, bcm_stg_t stg, bcm_vlan_t vid) 568 { 569 int stp_state; 570 bcm_port_t port; 571 bcm_pbmp_t stp_pbmp; 572 573 BCM_PBMP_CLEAR(stp_pbmp); 574 BCM_PBMP_ASSIGN(stp_pbmp, PBMP_E_ALL(unit)); 575 576 #ifdef BCM_KATANA2_SUPPORT 577 if (soc_feature(unit, soc_feature_linkphy_coe) || 578 soc_feature(unit, soc_feature_subtag_coe)) { 579 _bcm_kt2_subport_pbmp_update (unit, &stp_pbmp); 580 } 581 #endif 582 583 584 PBMP_ITER(stp_pbmp, port) { 585 BCM_IF_ERROR_RETURN 586 (bcm_esw_stg_stp_get(unit, stg, port, &stp_state)); 587 } 588 589 return BCM_E_NONE; 590 } 591 592 /* 593 * Function: 594 * _bcm_stg_vlan_add 595 * Purpose: 596 * Main part of bcm_stg_vlan_add; assumes locks already done. 597 */ 598 599 STATIC int 600 _bcm_stg_vlan_add(int unit, bcm_stg_t stg, bcm_vlan_t vid) 601 { 602 bcm_stg_info_t *si = &stg_info[unit]; 603 bcm_stg_t stg_cur; 604 605 /* STG must already exist */ 606 if (!STG_BITMAP_TST(si, stg)) { 607 return BCM_E_NOT_FOUND; 608 } 609 610 if (SOC_IS_RELOADING(unit)) { 611 #if defined (BCM_EASY_RELOAD_SUPPORT) 612 stg_cur = _bcm_stg_map_get(unit, vid); 613 #endif 614 } else { 615 BCM_IF_ERROR_RETURN 616 (mbcm_driver[unit]->mbcm_vlan_stg_get(unit, vid, &stg_cur)); 617 } 618 619 /* 620 * If this is being called from bcm_vlan_create(), the map will not 621 * contain the VLAN but this will not hurt. 622 */ 623 624 if (si->stg_mem != INVALIDm) { /* !Strata1 */ 625 _bcm_stg_map_delete(unit, stg_cur, vid); 626 } 627 628 BCM_IF_ERROR_RETURN 629 (mbcm_driver[unit]->mbcm_vlan_stg_set(unit, vid, stg)); 630 631 if (si->stg_mem != INVALIDm) { /* !Strata1 */ 632 _bcm_stg_map_add(unit, stg, vid); 633 } 634 635 if (soc_feature(unit, soc_feature_mstp_mask)) { 636 BCM_IF_ERROR_RETURN 637 (_bcm_stg_mstp_vlan_update(unit, stg, vid)); 638 } 639 640 return BCM_E_NONE; 641 } 642 643 /* 644 * Function: 645 * bcm_stg_vlan_add 646 * Purpose: 647 * Add a VLAN to a spanning tree group. 648 * Parameters: 649 * unit - StrataSwitch PCI device unit number 650 * stg - STG ID to use 651 * vid - VLAN id to be added to STG 652 * Returns: 653 * BCM_E_XXX 654 * Notes: 655 * Spanning tree group ID must have already been created. 656 * The VLAN is removed from the STG it is currently in. 657 */ 658 659 int 660 bcm_esw_stg_vlan_add(int unit, bcm_stg_t stg, bcm_vlan_t vid) 661 { 662 bcm_stg_info_t *si = &stg_info[unit]; 663 int rv; 664 665 CHECK_INIT(unit, si); 666 CHECK_STG(si, stg); 667 668 /* VLAN/VFI check */ 669 #ifdef BCM_TRIDENT2PLUS_SUPPORT 670 if (soc_feature(unit, soc_feature_vlan_vfi_membership) && 671 _BCM_VPN_VFI_IS_SET(vid) && SOC_MEM_IS_VALID(unit, VFIm)) { 672 bcm_vpn_t vpn_min = 0; 673 int num_vfi = soc_mem_index_count(unit, VFIm); 674 675 _BCM_VPN_SET(vpn_min, _BCM_VPN_TYPE_VFI, 0); 676 if ((vid > (vpn_min+num_vfi-1)) || (vid < vpn_min)) { 677 return (BCM_E_PARAM); 678 } 679 } else 680 #endif 681 { 682 VLAN_CHK_ID(unit, vid); 683 } 684 685 BCM_LOCK(unit); 686 rv = _bcm_stg_vlan_add(unit, stg, vid); 687 BCM_UNLOCK(unit); 688 689 return rv; 690 } 691 692 /* 693 * Function: 694 * _bcm_stg_vlan_remove 695 * Purpose: 696 * Main part of bcm_stg_vlan_remove; assumes lock already done. 697 * Returns: 698 * BCM_E_XXX 699 */ 700 701 STATIC int 702 _bcm_stg_vlan_remove(int unit, bcm_stg_t stg, bcm_vlan_t vid, int destroy) 703 { 704 bcm_stg_info_t *si = &stg_info[unit]; 705 int stg_cur; 706 707 /* STG must already exist */ 708 709 if (!STG_BITMAP_TST(si, stg)) { 710 return BCM_E_NOT_FOUND; 711 } 712 713 BCM_IF_ERROR_RETURN 714 (mbcm_driver[unit]->mbcm_vlan_stg_get(unit, vid, &stg_cur)); 715 716 if (stg != stg_cur) { 717 return BCM_E_NOT_FOUND; /* Not found in specified STG */ 718 } 719 720 BCM_IF_ERROR_RETURN 721 (mbcm_driver[unit]->mbcm_vlan_stg_set(unit, vid, si->stg_defl)); 722 723 if (si->stg_mem != INVALIDm) { /* !Strata1 */ 724 _bcm_stg_map_delete(unit, stg, vid); 725 } 726 727 if (!destroy) { 728 _bcm_stg_map_add(unit, si->stg_defl, vid); 729 } 730 731 if (soc_feature(unit, soc_feature_mstp_mask)) { 732 BCM_IF_ERROR_RETURN 733 (_bcm_stg_mstp_vlan_update(unit, si->stg_defl, vid)); 734 } 735 736 return BCM_E_NONE; 737 } 738 739 /* 740 * Function: 741 * _bcm_stg_vlan_destroy 742 * Purpose: 743 * Remove a VLAN from a spanning tree group. 744 * The VLAN is NOT placed in the default spanning tree group. 745 * Intended for use when the VLAN is destroyed. 746 * Parameters: 747 * unit - StrataSwitch PCI device unit number 748 * stg - STG ID to use 749 * vid - VLAN id to be removed from STG 750 * Returns: 751 * BCM_E_XXX 752 */ 753 754 int 755 _bcm_stg_vlan_destroy(int unit, bcm_stg_t stg, bcm_vlan_t vid) 756 { 757 bcm_stg_info_t *si = &stg_info[unit]; 758 int rv; 759 760 CHECK_INIT(unit, si); 761 CHECK_STG(si, stg); 762 763 /* VLAN/VFI check */ 764 #ifdef BCM_TRIDENT2PLUS_SUPPORT 765 if (_BCM_VPN_VFI_IS_SET(vid) && SOC_MEM_IS_VALID(unit, VFIm)) { 766 bcm_vpn_t vpn_min = 0; 767 int num_vfi = soc_mem_index_count(unit, VFIm); 768 769 _BCM_VPN_SET(vpn_min, _BCM_VPN_TYPE_VFI, 0); 770 if ((vid > (vpn_min+num_vfi-1)) || (vid < vpn_min)) { 771 return (BCM_E_PARAM); 772 } 773 } else 774 #endif 775 { 776 VLAN_CHK_ID(unit, vid); 777 } 778 779 BCM_LOCK(unit); 780 781 rv = _bcm_stg_vlan_remove(unit, stg, vid, TRUE); 782 783 BCM_UNLOCK(unit); 784 785 return rv; 786 } 787 788 /* 789 * Function: 790 * bcm_stg_vlan_remove 791 * Purpose: 792 * Remove a VLAN from a spanning tree group. 793 * The VLAN is placed in the default spanning tree group. 794 * Parameters: 795 * unit - StrataSwitch PCI device unit number 796 * stg - STG ID to use 797 * vid - VLAN id to be removed from STG 798 * Returns: 799 * BCM_E_XXX 800 */ 801 802 int 803 bcm_esw_stg_vlan_remove(int unit, bcm_stg_t stg, bcm_vlan_t vid) 804 { 805 bcm_stg_info_t *si = &stg_info[unit]; 806 int rv; 807 808 CHECK_INIT(unit, si); 809 CHECK_STG(si, stg); 810 811 /* VLAN/VFI check */ 812 #ifdef BCM_TRIDENT2PLUS_SUPPORT 813 if (soc_feature(unit, soc_feature_vlan_vfi_membership) && 814 _BCM_VPN_VFI_IS_SET(vid) && SOC_MEM_IS_VALID(unit, VFIm)) { 815 bcm_vpn_t vpn_min = 0; 816 int num_vfi = soc_mem_index_count(unit, VFIm); 817 818 _BCM_VPN_SET(vpn_min, _BCM_VPN_TYPE_VFI, 0); 819 if ((vid > (vpn_min+num_vfi-1)) || (vid < vpn_min)) { 820 return (BCM_E_PARAM); 821 } 822 } else 823 #endif 824 { 825 VLAN_CHK_ID(unit, vid); 826 } 827 828 BCM_LOCK(unit); 829 rv = _bcm_stg_vlan_remove(unit, stg, vid, FALSE); 830 BCM_UNLOCK(unit); 831 832 return rv; 833 } 834 835 /* 836 * Function: 837 * bcm_stg_vlan_remove_all 838 * Purpose: 839 * Remove all VLAN from a spanning tree group. 840 * The VLANs are placed in the default spanning tree group. 841 * Parameters: 842 * unit - StrataSwitch PCI device unit number 843 * stg - STG ID to clear 844 * Returns: 845 * BCM_E_XXX 846 */ 847 848 int 849 bcm_esw_stg_vlan_remove_all(int unit, bcm_stg_t stg) 850 { 851 bcm_stg_info_t *si = &stg_info[unit]; 852 int rv = BCM_E_NONE; 853 bcm_vlan_t vid, vlan_vpn; 854 int vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 855 856 CHECK_INIT(unit, si); 857 CHECK_STG(si, stg); 858 859 BCM_LOCK(unit); 860 861 if (stg == si->stg_defl) { /* Null operation */ 862 BCM_UNLOCK(unit); 863 return BCM_E_NONE; 864 } 865 866 if (!STG_BITMAP_TST(si, stg)) { /* STG must already exist */ 867 BCM_UNLOCK(unit); 868 return BCM_E_NOT_FOUND; 869 } 870 871 while ((vid = si->vlan_first[stg]) != vlan_vfi_count) { 872 vlan_vpn = _bcm_stg_vlan_vpn_get(vid); 873 874 if ((rv = _bcm_stg_vlan_remove(unit, stg, vlan_vpn, FALSE)) < 0) { 875 BCM_UNLOCK(unit); 876 return rv; 877 } 878 879 if ((rv = _bcm_stg_vlan_add(unit, si->stg_defl, vlan_vpn)) < 0) { 880 BCM_UNLOCK(unit); 881 return rv; 882 } 883 } 884 885 BCM_UNLOCK(unit); 886 887 return rv; 888 } 889 890 #ifdef BCM_WARM_BOOT_SUPPORT 891 892 #define BCM_WB_VERSION_1_0 SOC_SCACHE_VERSION(1,0) 893 #define BCM_WB_DEFAULT_VERSION BCM_WB_VERSION_1_0 894 895 /* 896 * Function: 897 * _bcm_esw_stg_sync 898 * Purpose: 899 * Record STG module persisitent info for Level 2 Warm Boot 900 * Parameters: 901 * unit - StrataSwitch unit number. 902 * Returns: 903 * BCM_E_XXX 904 */ 905 906 int 907 _bcm_esw_stg_sync(int unit) 908 { 909 bcm_stg_info_t *si = &stg_info[unit]; 910 int rv = BCM_E_NONE; 911 int alloc_size; 912 soc_scache_handle_t scache_handle; 913 uint8 *stg_scache; 914 915 CHECK_INIT(unit, si); 916 917 alloc_size = SHR_BITALLOCSIZE(si->stg_max + 1); 918 alloc_size += sizeof(si->stg_defl); 919 SOC_SCACHE_HANDLE_SET(scache_handle, 920 unit, BCM_MODULE_STG, 0); 921 BCM_IF_ERROR_RETURN 922 (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 923 alloc_size, 924 &stg_scache, BCM_WB_DEFAULT_VERSION, NULL)); 925 926 /* Save bitmap of defined STGs*/ 927 sal_memcpy(stg_scache, si->stg_bitmap, 928 SHR_BITALLOCSIZE(si->stg_max + 1)); 929 /* Save default STG */ 930 sal_memcpy(stg_scache + SHR_BITALLOCSIZE(si->stg_max + 1), 931 &(si->stg_defl), sizeof(si->stg_defl)); 932 933 return rv; 934 } 935 936 /* 937 * Function: 938 * _bcm_stg_reload (internal) 939 * Description: 940 * Reload the STG structures from the current hardware configuration. 941 * Parameters: 942 * unit - StrataSwitch PCI device unit number (driver internal). 943 * Returns: 944 * BCM_E_XXX 945 */ 946 947 STATIC int 948 _bcm_stg_reload(int unit) 949 { 950 bcm_stg_info_t *si = &stg_info[unit]; 951 bcm_stg_t stg; 952 int vid, rv, alloc_size; 953 soc_scache_handle_t scache_handle; 954 uint8 *stg_scache; 955 bcm_stg_t stg_defl; 956 int vlan_vpn = 0; 957 int vlan_vfi_count; 958 959 /* 960 * Go through the VLAN table to find out which STG is created, 961 * and which VLANs belong to a particular STG. 962 */ 963 964 if (si->stg_mem == INVALIDm) { /* Strata1 */ 965 STG_BITMAP_SET(si, BCM_STG_DEFAULT); 966 si->stg_count++; 967 } else { 968 alloc_size = SHR_BITALLOCSIZE(si->stg_max + 1); 969 alloc_size += sizeof(si->stg_defl); 970 SOC_SCACHE_HANDLE_SET(scache_handle, 971 unit, BCM_MODULE_STG, 0); 972 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE, 973 alloc_size, 974 &stg_scache, BCM_WB_DEFAULT_VERSION, NULL); 975 976 if (BCM_SUCCESS(rv)) { 977 /* Get the saved bitmap of defined STGs*/ 978 sal_memcpy(si->stg_bitmap, stg_scache, 979 SHR_BITALLOCSIZE(si->stg_max + 1)); 980 sal_memcpy(&stg_defl, 981 stg_scache + SHR_BITALLOCSIZE(si->stg_max + 1), 982 sizeof(stg_defl)); 983 984 if (STG_BITMAP_TST(si, stg_defl)) { 985 /* If saved default STG exists, change the SW default 986 * to match */ 987 si->stg_defl = stg_defl; 988 } 989 990 /* Count the STGs to prepare for VLAN recovery below */ 991 for (stg = si->stg_min; stg <= si->stg_max; stg++) { 992 if (STG_BITMAP_TST(si, stg)) { 993 si->stg_count++; 994 } 995 } 996 } else if (BCM_E_NOT_FOUND != rv) { 997 return rv; 998 } else { 999 /* 1000 * For level 1 Warm Boot 1001 * XGS switches have a special STG 0 entry that is used 1002 * only for tagged packets with invalid VLAN. 1003 * STG is marked valid so the bcm_stg_stp_set/get APIs can be used 1004 * to manage entry 0, but this is generally for internal purposes. 1005 */ 1006 1007 if (SOC_IS_XGS_SWITCH(unit)) { 1008 STG_BITMAP_SET(si, 0); 1009 } 1010 } 1011 1012 vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 1013 for (vid = 1; vid < vlan_vfi_count; vid++) { 1014 vlan_vpn = _bcm_stg_vlan_vpn_get(vid); 1015 1016 if (mbcm_driver[unit]->mbcm_vlan_stg_get(unit, vlan_vpn, &stg) != 0) { 1017 continue; 1018 } 1019 1020 if ((stg < si->stg_min) || (stg > si->stg_max)) { 1021 /* Out of range */ 1022 continue; 1023 } 1024 1025 if (!STG_BITMAP_TST(si, stg)) { 1026 STG_BITMAP_SET(si, stg); 1027 si->stg_count++; 1028 } 1029 1030 /* Add the VLAN to this STG's VLAN list */ 1031 _bcm_stg_map_add(unit, stg, vlan_vpn); 1032 } 1033 } 1034 1035 si->init = 1; /* > 0 */ 1036 1037 return BCM_E_NONE; 1038 } 1039 #endif /* BCM_WARM_BOOT_SUPPORT */ 1040 1041 /* 1042 * Function: 1043 * bcm_stg_init 1044 * Description: 1045 * Initialize the STG module according to Initial System Configuration. 1046 * Parameters: 1047 * unit - StrataSwitch PCI device unit number (driver internal). 1048 * Returns: 1049 * BCM_E_XXX 1050 */ 1051 1052 int 1053 bcm_esw_stg_init(int unit) 1054 { 1055 bcm_stg_info_t *si = &stg_info[unit]; 1056 int alloc_size, idx; 1057 int vlan_vfi_count; 1058 1059 if (!SOC_UNIT_VALID(unit)) { 1060 return BCM_E_UNIT; 1061 } 1062 1063 if (SOC_IS_SHADOW(unit)) { 1064 si->init = BCM_E_UNAVAIL; 1065 return BCM_E_NONE; 1066 } 1067 1068 if (SOC_IS_XGS12_FABRIC(unit)) { 1069 si->init = BCM_E_UNAVAIL; 1070 return BCM_E_NONE; 1071 } 1072 1073 if (soc_feature(unit, soc_feature_stg_xgs)) { 1074 si->stg_mem = STG_TABm; 1075 } else { 1076 si->stg_mem = INVALIDm; 1077 } 1078 1079 /* 1080 * Strata 2 and XGS switches have a special STG 0 entry that is used 1081 * only for tagged packets with invalid VLAN. 1082 */ 1083 1084 si->stg_min = 1; 1085 1086 if (si->stg_mem == INVALIDm) { 1087 si->stg_max = 1; 1088 } else { 1089 si->stg_max = soc_mem_index_max(unit, si->stg_mem); 1090 } 1091 1092 #ifdef BCM_WARM_BOOT_SUPPORT 1093 if (!SOC_WARM_BOOT(unit)) { 1094 int rv; 1095 soc_scache_handle_t scache_handle; 1096 uint8 *stg_scache; 1097 1098 alloc_size = SHR_BITALLOCSIZE(si->stg_max + 1); 1099 alloc_size += sizeof(si->stg_defl); 1100 1101 SOC_SCACHE_HANDLE_SET(scache_handle, 1102 unit, BCM_MODULE_STG, 0); 1103 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 1104 TRUE, 1105 alloc_size, 1106 &stg_scache, BCM_WB_DEFAULT_VERSION, NULL); 1107 if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) { 1108 return rv; 1109 } 1110 } 1111 #endif /* BCM_WARM_BOOT_SUPPORT */ 1112 1113 alloc_size = SHR_BITALLOCSIZE(si->stg_max + 1); 1114 if (si->stg_bitmap == NULL) { 1115 si->stg_bitmap = sal_alloc(alloc_size, "STG-bitmap"); 1116 } 1117 1118 if (si->vlan_first == NULL) { 1119 si->vlan_first = sal_alloc( 1120 (si->stg_max + 1) * sizeof (bcm_vlan_t), "STG-vfirst"); 1121 } 1122 1123 vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 1124 if (si->vlan_next == NULL) { 1125 si->vlan_next = sal_alloc( 1126 vlan_vfi_count * sizeof(bcm_vlan_t), "STG-vnext"); 1127 } 1128 1129 if (si->stg_bitmap == NULL || 1130 si->vlan_first == NULL || 1131 si->vlan_next == NULL) { 1132 return BCM_E_MEMORY; 1133 } 1134 1135 sal_memset(si->stg_bitmap, 0, alloc_size); 1136 for (idx = 0; idx < (si->stg_max + 1); idx++) { 1137 si->vlan_first[idx] = vlan_vfi_count; 1138 } 1139 for (idx = 0; idx < vlan_vfi_count; idx++) { 1140 si->vlan_next[idx] = vlan_vfi_count; 1141 } 1142 1143 si->stg_count = 0; 1144 1145 /* 1146 * For practical ease of use, the initial default STG is always 1 1147 * since that ID is valid on all chips. 1148 */ 1149 1150 si->stg_defl = BCM_STG_DEFAULT; 1151 1152 si->init = 1; /* > 0 */ 1153 1154 /* 1155 * If reloading, recover software structures from hardware 1156 * configuration. 1157 */ 1158 1159 #ifdef BCM_WARM_BOOT_SUPPORT 1160 if (SOC_WARM_BOOT(unit)) { 1161 return _bcm_stg_reload(unit); 1162 } 1163 #endif /* BCM_WARM_BOOT_SUPPORT */ 1164 1165 /* 1166 * XGS switches have a special STG 0 entry that is used 1167 * only for tagged packets with invalid VLAN. XGS hardware does not 1168 * automatically initialize it to all 1s. 1169 * STG is marked valid so the bcm_stg_stp_set/get APIs can be used 1170 * to manage entry 0, but this is generally for internal purposes. 1171 */ 1172 1173 if (SOC_IS_XGS_SWITCH(unit)) 1174 { 1175 BCM_IF_ERROR_RETURN(mbcm_driver[unit]->mbcm_stg_stp_init(unit, 0)); 1176 STG_BITMAP_SET(si, 0); 1177 } 1178 1179 /* 1180 * Create default STG and add all VLANs to it. Calling this routine 1181 * is safe because it does not reference other BCM driver modules. 1182 */ 1183 1184 BCM_IF_ERROR_RETURN(bcm_esw_stg_create_id(unit, si->stg_defl)); 1185 1186 _bcm_stg_map_add(unit, si->stg_defl, BCM_VLAN_DEFAULT); 1187 1188 return BCM_E_NONE; 1189 } 1190 1191 int _bcm_esw_stg_destroy_all(int unit) 1192 { 1193 bcm_stg_info_t *si = &stg_info[unit]; 1194 bcm_stg_t stg; 1195 1196 CHECK_INIT(unit, si); 1197 BCM_LOCK(unit); 1198 1199 for (stg = si->stg_min; stg <= si->stg_max; stg++) 1200 { 1201 if (STG_BITMAP_TST(si, stg)) 1202 { 1203 bcm_esw_stg_destroy(unit, stg); 1204 } 1205 } 1206 1207 BCM_UNLOCK(unit); 1208 1209 return BCM_E_NONE; 1210 } 1211 1212 /* 1213 * Function: 1214 * bcm_stg_clear 1215 * Description: 1216 * Destroy all STGs 1217 * Parameters: 1218 * unit - StrataSwitch PCI device unit number (driver internal). 1219 * Returns: 1220 * BCM_E_XXX 1221 */ 1222 1223 int 1224 bcm_esw_stg_clear(int unit) 1225 { 1226 _bcm_esw_stg_destroy_all(unit); 1227 1228 return bcm_esw_stg_init(unit); 1229 } 1230 1231 int bcm_esw_stg_detach(int unit) 1232 { 1233 bcm_stg_info_t *si = &stg_info[unit]; 1234 int rv; 1235 1236 if ((si->init == 0) || (si->init < 0)) { 1237 return BCM_E_NONE; 1238 } 1239 1240 BCM_LOCK(unit); 1241 1242 rv = _bcm_esw_stg_destroy_all(unit); 1243 1244 if (BCM_SUCCESS(rv)) 1245 { 1246 sal_free(si->vlan_next); 1247 sal_free(si->vlan_first); 1248 sal_free(si->stg_bitmap); 1249 1250 si->vlan_next = NULL; 1251 si->vlan_first = NULL; 1252 si->stg_bitmap = NULL; 1253 } 1254 1255 BCM_UNLOCK(unit); 1256 si->init = 0; 1257 1258 return rv; 1259 } 1260 1261 /* 1262 * Function: 1263 * bcm_stg_create_id 1264 * Description: 1265 * Create a STG, using a specified ID. 1266 * Parameters: 1267 * unit - StrataSwitch PCI device unit number 1268 * stg - STG to create 1269 * Returns: 1270 * BCM_E_XXX 1271 * Notes: 1272 * In the new STG, all ports are in the DISABLED state. 1273 */ 1274 1275 int 1276 bcm_esw_stg_create_id(int unit, bcm_stg_t stg) 1277 { 1278 bcm_stg_info_t *si = &stg_info[unit]; 1279 int rv = BCM_E_NONE; 1280 1281 CHECK_INIT(unit, si); 1282 CHECK_STG(si, stg); 1283 1284 BCM_LOCK(unit); 1285 1286 if (STG_BITMAP_TST(si, stg)) { 1287 BCM_UNLOCK(unit); 1288 return BCM_E_EXISTS; 1289 } 1290 1291 /* Write an entry with all ports DISABLED */ 1292 1293 if ((rv = mbcm_driver[unit]->mbcm_stg_stp_init(unit, stg)) < 0) { 1294 BCM_UNLOCK(unit); 1295 return rv; 1296 } 1297 1298 STG_BITMAP_SET(si, stg); 1299 si->stg_count++; 1300 1301 #ifdef BCM_WARM_BOOT_SUPPORT 1302 SOC_CONTROL_LOCK(unit); 1303 SOC_CONTROL(unit)->scache_dirty = 1; 1304 SOC_CONTROL_UNLOCK(unit); 1305 #endif 1306 1307 BCM_UNLOCK(unit); 1308 1309 return rv; 1310 } 1311 1312 /* 1313 * Function: 1314 * bcm_stg_create 1315 * Description: 1316 * Create a STG, picking an unused ID and returning it. 1317 * Parameters: 1318 * unit - StrataSwitch PCI device unit number 1319 * stg_ptr - (OUT) the STG ID. 1320 * Returns: 1321 * BCM_E_XXX 1322 */ 1323 1324 int 1325 bcm_esw_stg_create(int unit, bcm_stg_t *stg_ptr) 1326 { 1327 bcm_stg_info_t *si = &stg_info[unit]; 1328 bcm_stg_t stg; 1329 int rv; 1330 1331 CHECK_INIT(unit, si); 1332 1333 BCM_LOCK(unit); 1334 1335 for (stg = si->stg_min; stg <= si->stg_max; stg++) { 1336 if (!STG_BITMAP_TST(si, stg)) { 1337 break; 1338 } 1339 } 1340 1341 if (stg > si->stg_max) { 1342 BCM_UNLOCK(unit); 1343 return BCM_E_FULL; 1344 } 1345 1346 rv = bcm_esw_stg_create_id(unit, stg); 1347 1348 BCM_UNLOCK(unit); 1349 1350 *stg_ptr = stg; 1351 1352 return rv; 1353 } 1354 1355 /* 1356 * Function: 1357 * bcm_stg_destroy 1358 * Description: 1359 * Destroy an STG. 1360 * Parameters: 1361 * unit - StrataSwitch PCI device unit number (driver internal). 1362 * stg - The STG ID to be destroyed. 1363 * Returns: 1364 * BCM_E_XXX 1365 * Notes: 1366 * The default STG may not be destroyed. 1367 */ 1368 1369 int 1370 bcm_esw_stg_destroy(int unit, bcm_stg_t stg) 1371 { 1372 bcm_stg_info_t *si = &stg_info[unit]; 1373 int rv; 1374 1375 CHECK_INIT(unit, si); 1376 CHECK_STG(si, stg); 1377 1378 BCM_LOCK(unit); 1379 1380 if (stg == si->stg_defl) { 1381 BCM_UNLOCK(unit); 1382 return BCM_E_NOT_FOUND; 1383 } 1384 1385 if (stg < si->stg_min) { 1386 /* Do not destroy STG 0 */ 1387 BCM_UNLOCK(unit); 1388 return BCM_E_BADID; 1389 } 1390 1391 /* The next call already checks if STG exists */ 1392 1393 rv = bcm_esw_stg_vlan_remove_all(unit, stg); 1394 1395 if (rv < 0) { 1396 BCM_UNLOCK(unit); 1397 return rv; 1398 } 1399 1400 STG_BITMAP_CLR(si, stg); 1401 si->stg_count--; 1402 1403 #ifdef BCM_WARM_BOOT_SUPPORT 1404 SOC_CONTROL_LOCK(unit); 1405 SOC_CONTROL(unit)->scache_dirty = 1; 1406 SOC_CONTROL_UNLOCK(unit); 1407 #endif 1408 1409 BCM_UNLOCK(unit); 1410 1411 return BCM_E_NONE; 1412 } 1413 1414 /* 1415 * Function: 1416 * bcm_stg_list 1417 * Purpose: 1418 * Return a list of defined STGs 1419 * Parameters: 1420 * unit - StrataSwitch PCI device unit number 1421 * list - Place where pointer to return array will be stored, 1422 * which will be NULL if there are zero STGs returned. 1423 * count - Place where number of entries in array will be stored, 1424 * which will be 0 if there are zero STGs returned. 1425 * Returns: 1426 * BCM_E_XXX 1427 * Notes: 1428 * The caller is responsible for freeing the memory that is 1429 * returned, using bcm_stg_list_destroy(). 1430 */ 1431 1432 int 1433 bcm_esw_stg_list(int unit, bcm_stg_t **list, int *count) 1434 { 1435 bcm_stg_info_t *si = &stg_info[unit]; 1436 bcm_stg_t stg; 1437 int n; 1438 1439 CHECK_INIT(unit, si); 1440 1441 BCM_LOCK(unit); 1442 1443 if (si->stg_count == 0) { 1444 BCM_UNLOCK(unit); 1445 *count = 0; 1446 *list = NULL; 1447 return BCM_E_NONE; /* Empty list */ 1448 } 1449 1450 *count = si->stg_count; 1451 *list = sal_alloc(si->stg_count * sizeof (bcm_stg_t), "bcm_stg_list"); 1452 1453 if (*list == NULL) { 1454 BCM_UNLOCK(unit); 1455 return BCM_E_MEMORY; 1456 } 1457 1458 n = 0; 1459 for (stg = si->stg_min; stg <= si->stg_max; stg++) { 1460 if (STG_BITMAP_TST(si, stg)) { 1461 assert(n < *count); 1462 (*list)[n++] = stg; 1463 } 1464 } 1465 1466 BCM_UNLOCK(unit); 1467 1468 return BCM_E_NONE; 1469 } 1470 1471 /* 1472 * Function: 1473 * bcm_stg_list_destroy 1474 * Purpose: 1475 * Destroy a list returned by bcm_stg_list. 1476 * Parameters: 1477 * unit - StrataSwitch PCI device unit number 1478 * list - Place where pointer to return array will be stored, 1479 * which will be NULL if there are zero STGs returned. 1480 * count - Place where number of entries in array will be stored, 1481 * which will be 0 if there are zero STGs returned. 1482 * Returns: 1483 * BCM_E_NONE 1484 */ 1485 1486 int 1487 bcm_esw_stg_list_destroy(int unit, bcm_stg_t *list, int count) 1488 { 1489 COMPILER_REFERENCE(unit); 1490 COMPILER_REFERENCE(count); 1491 1492 if (list != NULL) { 1493 sal_free(list); 1494 } 1495 1496 return BCM_E_NONE; 1497 } 1498 1499 /* Function: 1500 * _bcm_stg_mstp_stp_update 1501 * Purpose: 1502 * For systems with MSTP mask, update for an STP state change. 1503 */ 1504 STATIC int 1505 _bcm_stg_mstp_stp_update(int unit, bcm_stg_t stg, bcm_port_t port, 1506 int stp_state) 1507 { 1508 bcm_stg_info_t *si = &stg_info[unit]; 1509 bcm_vlan_t v = si->vlan_first[stg]; 1510 int vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 1511 1512 while (v != vlan_vfi_count) { 1513 v = si->vlan_next[v]; 1514 } 1515 1516 return BCM_E_NONE; 1517 } 1518 1519 /* 1520 * Function: 1521 * bcm_stg_stp_set 1522 * Purpose: 1523 * Set the Spanning tree state for a port in specified STG. 1524 * Parameters: 1525 * unit - StrataSwitch PCI device unit number. 1526 * stg - STG ID. 1527 * port - StrataSwitch port number. 1528 * stp_state - Spanning Tree State of port. 1529 * Returns: 1530 * BCM_E_XXX 1531 */ 1532 1533 int 1534 bcm_esw_stg_stp_set(int unit, bcm_stg_t stg, bcm_port_t port, int stp_state) 1535 { 1536 bcm_stg_info_t *si = &stg_info[unit]; 1537 int local_port; 1538 int rv = BCM_E_NONE; 1539 int hw_stp_state; 1540 1541 if (SOC_IS_XGS12_FABRIC(unit)) { 1542 return BCM_E_NONE; 1543 } 1544 1545 #ifdef BCM_SHADOW_SUPPORT 1546 /* No STG STP support in shadow device */ 1547 if (SOC_IS_SHADOW(unit)) { 1548 return BCM_E_NONE; 1549 } 1550 #endif /* BCM_SHADOW_SUPPORT */ 1551 1552 CHECK_INIT(unit, si); 1553 CHECK_STG(si, stg); 1554 1555 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &local_port)); 1556 1557 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_KATANA_SUPPORT) 1558 if ((SOC_IS_ENDURO(unit) || SOC_IS_KATANAX(unit)) 1559 && IS_LB_PORT(unit, local_port)) { 1560 } else 1561 #endif 1562 #ifdef BCM_KATANA2_SUPPORT 1563 if ((soc_feature(unit, soc_feature_linkphy_coe) && 1564 BCM_PBMP_MEMBER (SOC_INFO(unit).linkphy_pp_port_pbm, local_port)) || 1565 (soc_feature(unit, soc_feature_subtag_coe) && 1566 BCM_PBMP_MEMBER (SOC_INFO(unit).subtag_pp_port_pbm, local_port)) || 1567 (soc_feature(unit, soc_feature_general_cascade) && 1568 BCM_PBMP_MEMBER (SOC_INFO(unit).general_pp_port_pbm, local_port))) { 1569 } else 1570 #endif 1571 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 1572 if (soc_feature(unit, soc_feature_vlan_vfi_membership) && 1573 !BCM_PORT_IS_LOCAL_PHYSICAL(port)) { 1574 } else 1575 #endif 1576 if (!IS_PORT(unit, local_port)) { 1577 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 1578 if (!SOC_IS_TRIDENT2PLUS(unit) || !IS_CPU_PORT(unit, local_port)) 1579 #endif 1580 return BCM_E_PORT; 1581 } 1582 1583 /* Verify passed stp state. */ 1584 BCM_IF_ERROR_RETURN(_bcm_stg_stp_translate(unit, stp_state, &hw_stp_state)); 1585 1586 BCM_LOCK(unit); 1587 1588 if (!STG_BITMAP_TST(si, stg)) { 1589 rv = BCM_E_NOT_FOUND; 1590 goto cleanup; 1591 } 1592 1593 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(INCLUDE_L3) 1594 if (!BCM_PORT_IS_LOCAL_PHYSICAL(port) && 1595 soc_feature(unit, soc_feature_vlan_vfi_membership)) { 1596 int vp_group_found = 0; 1597 1598 if (BCM_GPORT_IS_VP_GROUP(port)) { 1599 if (bcm_td2p_ing_vp_group_unmanaged_get(unit)) { 1600 rv = bcm_td2p_vp_group_stp_state_set(unit, 1601 stg, port, FALSE, hw_stp_state); 1602 if (rv < 0) { 1603 goto cleanup; 1604 } 1605 1606 vp_group_found++; 1607 } 1608 1609 if (bcm_td2p_egr_vp_group_unmanaged_get(unit)) { 1610 rv = bcm_td2p_vp_group_stp_state_set( 1611 unit, stg, port, TRUE, hw_stp_state); 1612 if (rv < 0) { 1613 goto cleanup; 1614 } 1615 1616 vp_group_found++; 1617 } 1618 } else { 1619 uint32 filter_flags; 1620 1621 rv = bcm_esw_port_vlan_member_get(unit, port, &filter_flags); 1622 if (rv < 0) { 1623 goto cleanup; 1624 } 1625 1626 if (!(filter_flags & BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP) 1627 && (filter_flags & BCM_PORT_VLAN_MEMBER_INGRESS)) { 1628 rv = bcm_td2p_vp_group_stg_move(unit, 1629 stg, port, hw_stp_state, FALSE); 1630 if (rv < 0) { 1631 goto cleanup; 1632 } 1633 1634 vp_group_found++; 1635 } 1636 1637 if (!(filter_flags & BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP) 1638 && (filter_flags & BCM_PORT_VLAN_MEMBER_EGRESS)) { 1639 rv = bcm_td2p_vp_group_stg_move(unit, 1640 stg, port, hw_stp_state, TRUE); 1641 if (rv < 0) { 1642 goto cleanup; 1643 } 1644 1645 vp_group_found++; 1646 } 1647 } 1648 1649 if (!vp_group_found) { 1650 rv = BCM_E_NOT_FOUND; 1651 goto cleanup; 1652 } 1653 } else 1654 #endif 1655 { 1656 rv = mbcm_driver[unit]->mbcm_stg_stp_set(unit, stg, local_port, stp_state); 1657 } 1658 1659 if (rv >= 0 && soc_feature(unit, soc_feature_mstp_mask) && 1660 IS_E_PORT(unit, local_port)) { 1661 rv = _bcm_stg_mstp_stp_update(unit, stg, local_port, stp_state); 1662 } 1663 1664 cleanup: 1665 BCM_UNLOCK(unit); 1666 1667 return rv; 1668 } 1669 1670 /* 1671 * Function: 1672 * bcm_stg_stp_get 1673 * Purpose: 1674 * Get the Spanning tree state for a port in specified STG. 1675 * Parameters: 1676 * unit - StrataSwitch unit number. 1677 * stg - STG ID. 1678 * port - StrataSwitch port number. 1679 * stp_state - (Out) Pointer to where Spanning Tree State is stored. 1680 * Returns: 1681 * BCM_E_NONE 1682 * BCM_E_INTERNAL 1683 */ 1684 1685 int 1686 bcm_esw_stg_stp_get(int unit, bcm_stg_t stg, bcm_port_t port, int *stp_state) 1687 { 1688 bcm_stg_info_t *si = &stg_info[unit]; 1689 int rv = BCM_E_NONE; 1690 int local_port; 1691 1692 if (SOC_IS_XGS12_FABRIC(unit)) { 1693 *stp_state = BCM_STG_STP_FORWARD; 1694 return BCM_E_NONE; 1695 } 1696 1697 CHECK_INIT(unit, si); 1698 CHECK_STG(si, stg); 1699 1700 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, port, &local_port)); 1701 1702 #if defined(BCM_ENDURO_SUPPORT) || defined(BCM_KATANA_SUPPORT) 1703 if ((SOC_IS_ENDURO(unit) || SOC_IS_KATANAX(unit)) 1704 && IS_LB_PORT(unit, local_port)) { 1705 } else 1706 #endif 1707 #ifdef BCM_KATANA2_SUPPORT 1708 if ((soc_feature(unit, soc_feature_linkphy_coe) && 1709 BCM_PBMP_MEMBER (SOC_INFO(unit).linkphy_pp_port_pbm, local_port)) || 1710 (soc_feature(unit, soc_feature_subtag_coe) && 1711 BCM_PBMP_MEMBER (SOC_INFO(unit).subtag_pp_port_pbm, local_port))) { 1712 } else 1713 #endif 1714 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 1715 if (soc_feature(unit, soc_feature_vlan_vfi_membership) && 1716 !BCM_PORT_IS_LOCAL_PHYSICAL(port)) { 1717 } else 1718 #endif 1719 if (!IS_PORT(unit, local_port)) { 1720 #if defined(BCM_TRIDENT2PLUS_SUPPORT) 1721 if (!SOC_IS_TRIDENT2PLUS(unit) || !IS_CPU_PORT(unit, local_port)) 1722 #endif 1723 return BCM_E_PORT; 1724 } 1725 1726 BCM_LOCK(unit); 1727 1728 if (!STG_BITMAP_TST(si, stg)) { 1729 rv = BCM_E_NOT_FOUND; 1730 goto cleanup; 1731 } 1732 1733 #if defined(BCM_TRIDENT2PLUS_SUPPORT) && defined(INCLUDE_L3) 1734 if (!BCM_PORT_IS_LOCAL_PHYSICAL(port) && 1735 soc_feature(unit, soc_feature_vlan_vfi_membership)) { 1736 int egress; 1737 int hw_stp_state = PVP_STP_FORWARDING; 1738 1739 if (BCM_GPORT_IS_VP_GROUP(port)) { 1740 if (bcm_td2p_ing_vp_group_unmanaged_get(unit)) { 1741 egress = FALSE; 1742 } else if (bcm_td2p_egr_vp_group_unmanaged_get(unit)) { 1743 egress = TRUE; 1744 } else { 1745 rv = BCM_E_NOT_FOUND; 1746 goto cleanup; 1747 } 1748 } else { 1749 uint32 filter_flags; 1750 1751 rv = bcm_esw_port_vlan_member_get(unit, port, &filter_flags); 1752 if (rv < 0) { 1753 goto cleanup; 1754 } 1755 1756 if (!(filter_flags & BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP) 1757 && (filter_flags & BCM_PORT_VLAN_MEMBER_INGRESS)) { 1758 egress = FALSE; 1759 } else if (!(filter_flags & BCM_PORT_VLAN_MEMBER_VP_VLAN_MEMBERSHIP) 1760 && (filter_flags & BCM_PORT_VLAN_MEMBER_EGRESS)) { 1761 egress = TRUE; 1762 } else { 1763 rv = BCM_E_NOT_FOUND; 1764 goto cleanup; 1765 } 1766 } 1767 1768 rv = bcm_td2p_vp_group_stp_state_get(unit, stg, port, egress, &hw_stp_state); 1769 if (rv < 0) { 1770 goto cleanup; 1771 } 1772 1773 /* Translate from hardware PVP_xxx state to BCM_STG_STP_xxx state. */ 1774 rv = _bcm_stg_pvp_translate(unit, hw_stp_state, stp_state); 1775 } else 1776 #endif 1777 { 1778 rv = mbcm_driver[unit]->mbcm_stg_stp_get(unit, stg, local_port, stp_state); 1779 } 1780 1781 cleanup: 1782 BCM_UNLOCK(unit); 1783 1784 return rv; 1785 } 1786 1787 /* 1788 * Function: 1789 * bcm_stg_count_get 1790 * Purpose: 1791 * Get the maximum number of STG groups the chip supports 1792 * Parameters: 1793 * unit - StrataSwitch unit number. 1794 * max_stg - max number of STG groups supported by this chip 1795 * Returns: 1796 * BCM_E_xxx 1797 */ 1798 1799 int 1800 bcm_esw_stg_count_get(int unit, int *max_stg) 1801 { 1802 bcm_stg_info_t *si = &stg_info[unit]; 1803 1804 CHECK_INIT(unit, si); 1805 1806 *max_stg = si->stg_max; 1807 1808 return BCM_E_NONE; 1809 } 1810 1811 #ifndef BCM_SW_STATE_DUMP_DISABLE 1812 /* 1813 * Function: 1814 * _bcm_stg_sw_dump 1815 * Purpose: 1816 * Displays STG software structure information. 1817 * Parameters: 1818 * unit - Device unit number 1819 * Returns: 1820 * None 1821 */ 1822 void 1823 _bcm_stg_sw_dump(int unit) 1824 { 1825 int i, count; 1826 bcm_stg_info_t *si = &stg_info[unit]; 1827 int vlan_count = 0; 1828 bcm_vlan_t v; 1829 int vlan_vfi_count = _bcm_stg_vlan_vfi_count_get(unit); 1830 1831 LOG_CLI((BSL_META_U(unit, 1832 "\nSW Information STG - Unit %d\n"), unit)); 1833 LOG_CLI((BSL_META_U(unit, 1834 " Init : %4d\n"), si->init)); 1835 LOG_CLI((BSL_META_U(unit, 1836 " Memory : %d(%4d-%4d)\n"), 1837 si->stg_mem, si->stg_min, si->stg_max)); 1838 LOG_CLI((BSL_META_U(unit, 1839 " Default STG: %4d\n"), si->stg_defl)); 1840 LOG_CLI((BSL_META_U(unit, 1841 " Count : %4d\n"), si->stg_count)); 1842 1843 if (si->stg_max >= BCM_VLAN_COUNT) { 1844 LOG_CLI((BSL_META_U(unit, 1845 "More STGs than VLANs!\n"))); 1846 si->stg_max = BCM_VLAN_COUNT - 1; 1847 } 1848 1849 /* Print STG list sorted */ 1850 count = 0; 1851 for (i = si->stg_min; i < si->stg_max; i++) { 1852 if (0 == STG_BITMAP_TST(si, i)){ 1853 continue; 1854 } 1855 LOG_CLI((BSL_META_U(unit, 1856 " STG %4d: "), i)); 1857 count++; 1858 vlan_count = 0; 1859 v = si->vlan_first[i]; 1860 1861 while (v != vlan_vfi_count) { 1862 if ((vlan_count > 0) && (!(vlan_count % 10))) { 1863 LOG_CLI((BSL_META_U(unit, 1864 "\n "))); 1865 } 1866 LOG_CLI((BSL_META_U(unit, 1867 " %4d"), _bcm_stg_vlan_vpn_get(v))); 1868 vlan_count++; 1869 v = si->vlan_next[v]; 1870 } 1871 LOG_CLI((BSL_META_U(unit, 1872 "\n"))); 1873 if (si->stg_count == count) { 1874 break; 1875 } 1876 } 1877 1878 return; 1879 } 1880 #endif /* BCM_SW_STATE_DUMP_DISABLE */