openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 */